Merge "[DO NOT MERGE] Avoid sending content changed a11y events from wrong views" into pi-dev

This commit is contained in:
Eugene Susla
2018-04-10 20:18:09 +00:00
committed by Android (Google) Code Review
6 changed files with 99 additions and 11 deletions

View File

@@ -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();
}
}
}

View File

@@ -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();

View File

@@ -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());
}
}
}
/**

View File

@@ -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

View File

@@ -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.

View File

@@ -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.