Merge "[DO NOT MERGE] Avoid sending content changed a11y events from wrong views" into pi-dev
This commit is contained in:
@@ -11791,6 +11791,14 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
View getSelfOrParentImportantForA11y() {
|
||||
if (isImportantForAccessibility()) return this;
|
||||
ViewParent parent = getParentForAccessibility();
|
||||
if (parent instanceof View) return (View) parent;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the children of this View relevant for accessibility to the given list
|
||||
* as output. Since some Views are not important for accessibility the added
|
||||
@@ -15006,10 +15014,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
||||
public void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha) {
|
||||
ensureTransformationInfo();
|
||||
if (mTransformationInfo.mAlpha != alpha) {
|
||||
// Report visibility changes, which can affect children, to accessibility
|
||||
if ((alpha == 0) ^ (mTransformationInfo.mAlpha == 0)) {
|
||||
notifySubtreeAccessibilityStateChangedIfNeeded();
|
||||
}
|
||||
float oldAlpha = mTransformationInfo.mAlpha;
|
||||
mTransformationInfo.mAlpha = alpha;
|
||||
if (onSetAlpha((int) (alpha * 255))) {
|
||||
mPrivateFlags |= PFLAG_ALPHA_SET;
|
||||
@@ -15021,6 +15026,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
||||
invalidateViewProperty(true, false);
|
||||
mRenderNode.setAlpha(getFinalAlpha());
|
||||
}
|
||||
// Report visibility changes, which can affect children, to accessibility
|
||||
if ((alpha == 0) ^ (oldAlpha == 0)) {
|
||||
notifySubtreeAccessibilityStateChangedIfNeeded();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8305,6 +8305,12 @@ public final class ViewRootImpl implements ViewParent,
|
||||
|
||||
public View mSource;
|
||||
public long mLastEventTimeMillis;
|
||||
/**
|
||||
* Override for {@link AccessibilityEvent#originStackTrace} to provide the stack trace
|
||||
* of the original {@link #runOrPost} call instead of one for sending the delayed event
|
||||
* from a looper.
|
||||
*/
|
||||
public StackTraceElement[] mOrigin;
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
@@ -8322,6 +8328,7 @@ public final class ViewRootImpl implements ViewParent,
|
||||
AccessibilityEvent event = AccessibilityEvent.obtain();
|
||||
event.setEventType(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
|
||||
event.setContentChangeTypes(mChangeTypes);
|
||||
if (AccessibilityEvent.DEBUG_ORIGIN) event.originStackTrace = mOrigin;
|
||||
source.sendAccessibilityEventUnchecked(event);
|
||||
} else {
|
||||
mLastEventTimeMillis = 0;
|
||||
@@ -8329,6 +8336,7 @@ public final class ViewRootImpl implements ViewParent,
|
||||
// In any case reset to initial state.
|
||||
source.resetSubtreeAccessibilityStateChanged();
|
||||
mChangeTypes = 0;
|
||||
if (AccessibilityEvent.DEBUG_ORIGIN) mOrigin = null;
|
||||
}
|
||||
|
||||
public void runOrPost(View source, int changeType) {
|
||||
@@ -8352,12 +8360,18 @@ public final class ViewRootImpl implements ViewParent,
|
||||
// If there is no common predecessor, then mSource points to
|
||||
// a removed view, hence in this case always prefer the source.
|
||||
View predecessor = getCommonPredecessor(mSource, source);
|
||||
if (predecessor != null) {
|
||||
predecessor = predecessor.getSelfOrParentImportantForA11y();
|
||||
}
|
||||
mSource = (predecessor != null) ? predecessor : source;
|
||||
mChangeTypes |= changeType;
|
||||
return;
|
||||
}
|
||||
mSource = source;
|
||||
mChangeTypes = changeType;
|
||||
if (AccessibilityEvent.DEBUG_ORIGIN) {
|
||||
mOrigin = Thread.currentThread().getStackTrace();
|
||||
}
|
||||
final long timeSinceLastMillis = SystemClock.uptimeMillis() - mLastEventTimeMillis;
|
||||
final long minEventIntevalMillis =
|
||||
ViewConfiguration.getSendRecurringAccessibilityEventsInterval();
|
||||
|
||||
@@ -388,6 +388,8 @@ import java.util.List;
|
||||
*/
|
||||
public final class AccessibilityEvent extends AccessibilityRecord implements Parcelable {
|
||||
private static final boolean DEBUG = false;
|
||||
/** @hide */
|
||||
public static final boolean DEBUG_ORIGIN = false;
|
||||
|
||||
/**
|
||||
* Invalid selection/focus position.
|
||||
@@ -748,7 +750,7 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
|
||||
|
||||
private static final int MAX_POOL_SIZE = 10;
|
||||
private static final SynchronizedPool<AccessibilityEvent> sPool =
|
||||
new SynchronizedPool<AccessibilityEvent>(MAX_POOL_SIZE);
|
||||
new SynchronizedPool<>(MAX_POOL_SIZE);
|
||||
|
||||
private @EventType int mEventType;
|
||||
private CharSequence mPackageName;
|
||||
@@ -758,6 +760,17 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
|
||||
int mContentChangeTypes;
|
||||
int mWindowChangeTypes;
|
||||
|
||||
/**
|
||||
* The stack trace describing where this event originated from on the app side.
|
||||
* Only populated if {@link #DEBUG_ORIGIN} is enabled
|
||||
* Can be inspected(e.g. printed) from an
|
||||
* {@link android.accessibilityservice.AccessibilityService} to trace where particular events
|
||||
* are being dispatched from.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public StackTraceElement[] originStackTrace = null;
|
||||
|
||||
private ArrayList<AccessibilityRecord> mRecords;
|
||||
|
||||
/*
|
||||
@@ -780,6 +793,7 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
|
||||
mWindowChangeTypes = event.mWindowChangeTypes;
|
||||
mEventTime = event.mEventTime;
|
||||
mPackageName = event.mPackageName;
|
||||
if (DEBUG_ORIGIN) originStackTrace = event.originStackTrace;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1104,7 +1118,9 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
|
||||
*/
|
||||
public static AccessibilityEvent obtain() {
|
||||
AccessibilityEvent event = sPool.acquire();
|
||||
return (event != null) ? event : new AccessibilityEvent();
|
||||
if (event == null) event = new AccessibilityEvent();
|
||||
if (DEBUG_ORIGIN) event.originStackTrace = Thread.currentThread().getStackTrace();
|
||||
return event;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1142,6 +1158,7 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
|
||||
record.recycle();
|
||||
}
|
||||
}
|
||||
if (DEBUG_ORIGIN) originStackTrace = null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1164,7 +1181,7 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
|
||||
// Read the records.
|
||||
final int recordCount = parcel.readInt();
|
||||
if (recordCount > 0) {
|
||||
mRecords = new ArrayList<AccessibilityRecord>(recordCount);
|
||||
mRecords = new ArrayList<>(recordCount);
|
||||
for (int i = 0; i < recordCount; i++) {
|
||||
AccessibilityRecord record = AccessibilityRecord.obtain();
|
||||
readAccessibilityRecordFromParcel(record, parcel);
|
||||
@@ -1172,6 +1189,17 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
|
||||
mRecords.add(record);
|
||||
}
|
||||
}
|
||||
|
||||
if (DEBUG_ORIGIN) {
|
||||
originStackTrace = new StackTraceElement[parcel.readInt()];
|
||||
for (int i = 0; i < originStackTrace.length; i++) {
|
||||
originStackTrace[i] = new StackTraceElement(
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readString(),
|
||||
parcel.readInt());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1227,6 +1255,17 @@ public final class AccessibilityEvent extends AccessibilityRecord implements Par
|
||||
AccessibilityRecord record = mRecords.get(i);
|
||||
writeAccessibilityRecordToParcel(record, parcel, flags);
|
||||
}
|
||||
|
||||
if (DEBUG_ORIGIN) {
|
||||
if (originStackTrace == null) originStackTrace = Thread.currentThread().getStackTrace();
|
||||
parcel.writeInt(originStackTrace.length);
|
||||
for (StackTraceElement element : originStackTrace) {
|
||||
parcel.writeString(element.getClassName());
|
||||
parcel.writeString(element.getMethodName());
|
||||
parcel.writeString(element.getFileName());
|
||||
parcel.writeInt(element.getLineNumber());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -326,12 +326,14 @@ public final class AccessibilityInteractionClient
|
||||
accessibilityWindowId, accessibilityNodeId);
|
||||
if (cachedInfo != null) {
|
||||
if (DEBUG) {
|
||||
Log.i(LOG_TAG, "Node cache hit");
|
||||
Log.i(LOG_TAG, "Node cache hit for "
|
||||
+ idToString(accessibilityWindowId, accessibilityNodeId));
|
||||
}
|
||||
return cachedInfo;
|
||||
}
|
||||
if (DEBUG) {
|
||||
Log.i(LOG_TAG, "Node cache miss");
|
||||
Log.i(LOG_TAG, "Node cache miss for "
|
||||
+ idToString(accessibilityWindowId, accessibilityNodeId));
|
||||
}
|
||||
}
|
||||
final int interactionId = mInteractionIdCounter.getAndIncrement();
|
||||
@@ -368,6 +370,11 @@ public final class AccessibilityInteractionClient
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String idToString(int accessibilityWindowId, long accessibilityNodeId) {
|
||||
return accessibilityWindowId + "/"
|
||||
+ AccessibilityNodeInfo.idToString(accessibilityNodeId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds an {@link AccessibilityNodeInfo} by View id. The search is performed in
|
||||
* the window whose id is specified and starts from the node whose accessibility
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package android.view.accessibility;
|
||||
|
||||
import static android.accessibilityservice.AccessibilityServiceInfo.FLAG_ENABLE_ACCESSIBILITY_VOLUME;
|
||||
|
||||
import android.Manifest;
|
||||
import android.accessibilityservice.AccessibilityServiceInfo;
|
||||
import android.accessibilityservice.AccessibilityServiceInfo.FeedbackType;
|
||||
@@ -44,6 +46,7 @@ import android.util.SparseArray;
|
||||
import android.view.IWindow;
|
||||
import android.view.View;
|
||||
import android.view.accessibility.AccessibilityEvent.EventType;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
import com.android.internal.util.IntPair;
|
||||
|
||||
@@ -51,8 +54,6 @@ import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static android.accessibilityservice.AccessibilityServiceInfo.FLAG_ENABLE_ACCESSIBILITY_VOLUME;
|
||||
|
||||
/**
|
||||
* System level service that serves as an event dispatch for {@link AccessibilityEvent}s,
|
||||
* and provides facilities for querying the accessibility state of the system.
|
||||
|
||||
@@ -3874,6 +3874,24 @@ public class AccessibilityNodeInfo implements Parcelable {
|
||||
| FLAG_PREFETCH_DESCENDANTS | FLAG_PREFETCH_SIBLINGS, null);
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public static String idToString(long accessibilityId) {
|
||||
int accessibilityViewId = getAccessibilityViewId(accessibilityId);
|
||||
int virtualDescendantId = getVirtualDescendantId(accessibilityId);
|
||||
return virtualDescendantId == AccessibilityNodeProvider.HOST_VIEW_ID
|
||||
? idItemToString(accessibilityViewId)
|
||||
: idItemToString(accessibilityViewId) + ":" + idItemToString(virtualDescendantId);
|
||||
}
|
||||
|
||||
private static String idItemToString(int item) {
|
||||
switch (item) {
|
||||
case ROOT_ITEM_ID: return "ROOT";
|
||||
case UNDEFINED_ITEM_ID: return "UNDEFINED";
|
||||
case AccessibilityNodeProvider.HOST_VIEW_ID: return "HOST";
|
||||
default: return "" + item;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A class defining an action that can be performed on an {@link AccessibilityNodeInfo}.
|
||||
* Each action has a unique id that is mandatory and optional data.
|
||||
|
||||
Reference in New Issue
Block a user