summaryrefslogtreecommitdiff
path: root/android/view/accessibility/ThrottlingAccessibilityEventSender.java
diff options
context:
space:
mode:
Diffstat (limited to 'android/view/accessibility/ThrottlingAccessibilityEventSender.java')
-rw-r--r--android/view/accessibility/ThrottlingAccessibilityEventSender.java248
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 + ")";
- }
-
-}