diff options
Diffstat (limited to 'android/view/accessibility/ThrottlingAccessibilityEventSender.java')
-rw-r--r-- | android/view/accessibility/ThrottlingAccessibilityEventSender.java | 248 |
1 files changed, 0 insertions, 248 deletions
diff --git a/android/view/accessibility/ThrottlingAccessibilityEventSender.java b/android/view/accessibility/ThrottlingAccessibilityEventSender.java deleted file mode 100644 index 66fa3010..00000000 --- a/android/view/accessibility/ThrottlingAccessibilityEventSender.java +++ /dev/null @@ -1,248 +0,0 @@ -/* - * Copyright (C) 2017 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.view.accessibility; - - -import android.annotation.NonNull; -import android.annotation.Nullable; -import android.os.Handler; -import android.os.Looper; -import android.os.SystemClock; -import android.util.Log; -import android.view.View; -import android.view.ViewConfiguration; -import android.view.ViewRootImpl; -import android.view.ViewRootImpl.CalledFromWrongThreadException; - -/** - * A throttling {@link AccessibilityEvent} sender that relies on its currently associated - * 'source' view's {@link View#postDelayed delayed execution} to delay and possibly - * {@link #tryMerge merge} together any events that come in less than - * {@link ViewConfiguration#getSendRecurringAccessibilityEventsInterval - * the configured amount of milliseconds} apart. - * - * The suggested usage is to create a singleton extending this class, holding any state specific to - * the particular event type that the subclass represents, and have an 'entrypoint' method that - * delegates to {@link #scheduleFor(View)}. - * For example: - * - * {@code - * public void post(View view, String text, int resId) { - * mText = text; - * mId = resId; - * scheduleFor(view); - * } - * } - * - * @see #scheduleFor(View) - * @see #tryMerge(View, View) - * @see #performSendEvent(View) - * @hide - */ -public abstract class ThrottlingAccessibilityEventSender { - - private static final boolean DEBUG = false; - private static final String LOG_TAG = "ThrottlingA11ySender"; - - View mSource; - private long mLastSendTimeMillis = Long.MIN_VALUE; - private boolean mIsPending = false; - - private final Runnable mWorker = () -> { - View source = mSource; - if (DEBUG) Log.d(LOG_TAG, thisClass() + ".run(mSource = " + source + ")"); - - if (!checkAndResetIsPending() || source == null) { - resetStateInternal(); - return; - } - - // Accessibility may be turned off while we were waiting - if (isAccessibilityEnabled(source)) { - mLastSendTimeMillis = SystemClock.uptimeMillis(); - performSendEvent(source); - } - resetStateInternal(); - }; - - /** - * Populate and send an {@link AccessibilityEvent} using the given {@code source} view, as well - * as any extra data from this instance's state. - * - * Send the event via {@link View#sendAccessibilityEventUnchecked(AccessibilityEvent)} or - * {@link View#sendAccessibilityEvent(int)} on the provided {@code source} view to allow for - * overrides of those methods on {@link View} subclasses to take effect, and/or make sure that - * an {@link View#getAccessibilityDelegate() accessibility delegate} is not ignored if any. - */ - protected abstract void performSendEvent(@NonNull View source); - - /** - * Perform optional cleanup after {@link #performSendEvent} - * - * @param source the view this event was associated with - */ - protected abstract void resetState(@Nullable View source); - - /** - * Attempt to merge the pending events for source views {@code oldSource} and {@code newSource} - * into one, with source set to the resulting {@link View} - * - * A result of {@code null} means merger is not possible, resulting in the currently pending - * event being flushed before proceeding. - */ - protected @Nullable View tryMerge(@NonNull View oldSource, @NonNull View newSource) { - return null; - } - - /** - * Schedules a {@link #performSendEvent} with the source {@link View} set to given - * {@code source} - * - * If an event is already scheduled a {@link #tryMerge merge} will be attempted. - * If merging is not possible (as indicated by the null result from {@link #tryMerge}), - * the currently scheduled event will be {@link #sendNow sent immediately} and the new one - * will be scheduled afterwards. - */ - protected final void scheduleFor(@NonNull View source) { - if (DEBUG) Log.d(LOG_TAG, thisClass() + ".scheduleFor(source = " + source + ")"); - - Handler uiHandler = source.getHandler(); - if (uiHandler == null || uiHandler.getLooper() != Looper.myLooper()) { - CalledFromWrongThreadException e = new CalledFromWrongThreadException( - "Expected to be called from main thread but was called from " - + Thread.currentThread()); - // TODO: Throw the exception - Log.e(LOG_TAG, "Accessibility content change on non-UI thread. Future Android " - + "versions will throw an exception.", e); - } - - if (!isAccessibilityEnabled(source)) return; - - if (mIsPending) { - View merged = tryMerge(mSource, source); - if (merged != null) { - setSource(merged); - return; - } else { - sendNow(); - } - } - - setSource(source); - - final long timeSinceLastMillis = SystemClock.uptimeMillis() - mLastSendTimeMillis; - final long minEventIntervalMillis = - ViewConfiguration.getSendRecurringAccessibilityEventsInterval(); - if (timeSinceLastMillis >= minEventIntervalMillis) { - sendNow(); - } else { - mSource.postDelayed(mWorker, minEventIntervalMillis - timeSinceLastMillis); - } - } - - static boolean isAccessibilityEnabled(@NonNull View contextProvider) { - return AccessibilityManager.getInstance(contextProvider.getContext()).isEnabled(); - } - - protected final void sendNow(View source) { - setSource(source); - sendNow(); - } - - private void sendNow() { - mSource.removeCallbacks(mWorker); - mWorker.run(); - } - - /** - * Flush the event if one is pending - */ - public void sendNowIfPending() { - if (mIsPending) sendNow(); - } - - /** - * Cancel the event if one is pending and is for the given view - */ - public final void cancelIfPendingFor(@NonNull View source) { - if (isPendingFor(source)) cancelIfPending(this); - } - - /** - * @return whether an event is currently pending for the given source view - */ - protected final boolean isPendingFor(@Nullable View source) { - return mIsPending && mSource == source; - } - - /** - * Cancel the event if one is not null and pending - */ - public static void cancelIfPending(@Nullable ThrottlingAccessibilityEventSender sender) { - if (sender == null || !sender.checkAndResetIsPending()) return; - sender.mSource.removeCallbacks(sender.mWorker); - sender.resetStateInternal(); - } - - void resetStateInternal() { - if (DEBUG) Log.d(LOG_TAG, thisClass() + ".resetStateInternal()"); - - resetState(mSource); - setSource(null); - } - - boolean checkAndResetIsPending() { - if (mIsPending) { - mIsPending = false; - return true; - } else { - return false; - } - } - - private void setSource(@Nullable View source) { - if (DEBUG) Log.d(LOG_TAG, thisClass() + ".setSource(" + source + ")"); - - if (source == null && mIsPending) { - Log.e(LOG_TAG, "mSource nullified while callback still pending: " + this); - return; - } - - if (source != null && !mIsPending) { - // At most one can be pending at any given time - View oldSource = mSource; - if (oldSource != null) { - ViewRootImpl viewRootImpl = oldSource.getViewRootImpl(); - if (viewRootImpl != null) { - viewRootImpl.flushPendingAccessibilityEvents(); - } - } - mIsPending = true; - } - mSource = source; - } - - String thisClass() { - return getClass().getSimpleName(); - } - - @Override - public String toString() { - return thisClass() + "(" + mSource + ")"; - } - -} |