From c9699994aa11b34b55b6321f19e8421fbcc84919 Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Mon, 20 May 2013 09:28:08 -0700 Subject: [PATCH 1/4] Fix off-by-1 error in timing If deferred action msg was delivered promptly it would end up looking like it too needed to be deferred and then nothing would end up getting done. bug:9014777 Change-Id: I243df70463ebb9333efd6df510f71f9d8d9bdf91 --- services/java/com/android/server/wifi/WifiController.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/java/com/android/server/wifi/WifiController.java b/services/java/com/android/server/wifi/WifiController.java index 10f7f5a9dcde2..8e2bdaad41c4a 100644 --- a/services/java/com/android/server/wifi/WifiController.java +++ b/services/java/com/android/server/wifi/WifiController.java @@ -426,7 +426,7 @@ class WifiController extends StateMachine { private boolean doDeferEnable(Message msg) { long delaySoFar = SystemClock.elapsedRealtime() - mDisabledTimestamp; - if (delaySoFar > mReEnableDelayMillis) { + if (delaySoFar >= mReEnableDelayMillis) { return false; } @@ -550,7 +550,7 @@ class WifiController extends StateMachine { private boolean doDeferEnable(Message msg) { long delaySoFar = SystemClock.elapsedRealtime() - mDisabledTimestamp; - if (delaySoFar > mReEnableDelayMillis) { + if (delaySoFar >= mReEnableDelayMillis) { return false; } From 1b64daf1acc8ba2967f280d2d7980544b80851d6 Mon Sep 17 00:00:00 2001 From: Svetoslav Ganov Date: Fri, 17 May 2013 18:06:31 -0700 Subject: [PATCH 2/4] Taking into account data change for AbsListView when prefetching node infos. We are prefetching accessibility node infos to minimize the number of IPC calls when an accessibility service introspects the screen. It is however, possible that the view we are prefetching is a child of an AbsListView whose adapter changed its data but the AbsListView still did not perform a layout pass to sync its children with the new adapter state. This may lead to an exeption when trying to query for the state of a child's position. If the data of the adapter is changed and the layout pass still not performed, we return null for the AbsLIstView's children. When the layout pass completes we already notify the accessibliity layer so it will be able to refetch the children of the AbsListView. bug:8433433 Change-Id: I56313c721aef3848b15fad50027d068ba1d291f7 --- core/java/android/view/View.java | 38 +++++++++++++++++++++++ core/java/android/widget/AbsListView.java | 12 +++++++ 2 files changed, 50 insertions(+) diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 0cd7c6e1c6683..4e8005fafaa12 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -4928,6 +4928,17 @@ public class View implements Drawable.Callback, KeyEvent.Callback, * @see AccessibilityNodeInfo */ public AccessibilityNodeInfo createAccessibilityNodeInfo() { + if (mAccessibilityDelegate != null) { + return mAccessibilityDelegate.createAccessibilityNodeInfo(this); + } else { + return createAccessibilityNodeInfoInternal(); + } + } + + /** + * @see #createAccessibilityNodeInfo() + */ + AccessibilityNodeInfo createAccessibilityNodeInfoInternal() { AccessibilityNodeProvider provider = getAccessibilityNodeProvider(); if (provider != null) { return provider.createAccessibilityNodeInfo(View.NO_ID); @@ -18690,6 +18701,33 @@ public class View implements Drawable.Callback, KeyEvent.Callback, public AccessibilityNodeProvider getAccessibilityNodeProvider(View host) { return null; } + + /** + * Returns an {@link AccessibilityNodeInfo} representing the host view from the + * point of view of an {@link android.accessibilityservice.AccessibilityService}. + * This method is responsible for obtaining an accessibility node info from a + * pool of reusable instances and calling + * {@link #onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo)} on the host + * view to initialize the former. + *

+ * Note: The client is responsible for recycling the obtained + * instance by calling {@link AccessibilityNodeInfo#recycle()} to minimize object + * creation. + *

+ *

+ * The default implementation behaves as + * {@link View#createAccessibilityNodeInfo() View#createAccessibilityNodeInfo()} for + * the case of no accessibility delegate been set. + *

+ * @return A populated {@link AccessibilityNodeInfo}. + * + * @see AccessibilityNodeInfo + * + * @hide + */ + public AccessibilityNodeInfo createAccessibilityNodeInfo(View host) { + return host.createAccessibilityNodeInfoInternal(); + } } private class MatchIdPredicate implements Predicate { diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index 5a40368d59353..bf662924b7f31 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -2212,6 +2212,18 @@ public abstract class AbsListView extends AdapterView implements Te } class ListItemAccessibilityDelegate extends AccessibilityDelegate { + @Override + public AccessibilityNodeInfo createAccessibilityNodeInfo(View host) { + // If the data changed the children are invalid since the data model changed. + // Hence, we pretend they do not exist. After a layout the children will sync + // with the model at which point we notify that the accessibility state changed, + // so a service will be able to re-fetch the views. + if (mDataChanged) { + return null; + } + return super.createAccessibilityNodeInfo(host); + } + @Override public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) { super.onInitializeAccessibilityNodeInfo(host, info); From b11ef589c1d250982db8e6fd6d067bee8c5c88ee Mon Sep 17 00:00:00 2001 From: Robert Greenwalt Date: Mon, 20 May 2013 11:49:46 -0700 Subject: [PATCH 3/4] Add a time margin for deferred enable. We were getting delayed message delivered 1 ms before we expected. bug:9014777 Change-Id: I70e681ff6b4155d31097b43529478b39c816e70b --- services/java/com/android/server/wifi/WifiController.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/services/java/com/android/server/wifi/WifiController.java b/services/java/com/android/server/wifi/WifiController.java index 8e2bdaad41c4a..228fabf67a046 100644 --- a/services/java/com/android/server/wifi/WifiController.java +++ b/services/java/com/android/server/wifi/WifiController.java @@ -78,6 +78,10 @@ class WifiController extends StateMachine { */ private static final long DEFAULT_REENABLE_DELAY_MS = 500; + // finding that delayed messages can sometimes be delivered earlier than expected + // probably rounding errors.. add a margin to prevent problems + private static final long DEFER_MARGIN_MS = 5; + NetworkInfo mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0, "WIFI", ""); private static final String ACTION_DEVICE_IDLE = @@ -437,7 +441,7 @@ class WifiController extends StateMachine { Message deferredMsg = obtainMessage(CMD_DEFERRED_TOGGLE); deferredMsg.obj = Message.obtain(msg); deferredMsg.arg1 = ++mDeferredEnableSerialNumber; - sendMessageDelayed(deferredMsg, mReEnableDelayMillis - delaySoFar); + sendMessageDelayed(deferredMsg, mReEnableDelayMillis - delaySoFar + DEFER_MARGIN_MS); return true; } @@ -561,7 +565,7 @@ class WifiController extends StateMachine { Message deferredMsg = obtainMessage(CMD_DEFERRED_TOGGLE); deferredMsg.obj = Message.obtain(msg); deferredMsg.arg1 = ++mDeferredEnableSerialNumber; - sendMessageDelayed(deferredMsg, mReEnableDelayMillis - delaySoFar); + sendMessageDelayed(deferredMsg, mReEnableDelayMillis - delaySoFar + DEFER_MARGIN_MS); return true; } From 962dac14425317f6232bf2beddc6e453efb59a02 Mon Sep 17 00:00:00 2001 From: Svetoslav Ganov Date: Fri, 17 May 2013 19:12:38 -0700 Subject: [PATCH 4/4] Do not report the fake UI automation service to clients. For UI test automation purposes we register a fake accessibility service and suspend all other services. When the UI automation serivce is unregistered we restore the suspended ones. Since the UI automation serivce is fake and incomplete, for example it has not resolve info, it should not be reported to clients as being installed or enabled. bug:8871034 Change-Id: I66792cd028159c1652d3c8a2982164821282ab24 --- .../AccessibilityManagerService.java | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java index 2b5544ba0be96..2f8250fbf1a23 100644 --- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -95,6 +95,7 @@ import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -405,7 +406,17 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { synchronized (mLock) { final int resolvedUserId = mSecurityPolicy .resolveCallingUserIdEnforcingPermissionsLocked(userId); - return getUserStateLocked(resolvedUserId).mInstalledServices; + // The automation service is a fake one and should not be reported + // to clients as being installed - it really is not. + UserState userState = getUserStateLocked(resolvedUserId); + if (userState.mUiAutomationService != null) { + List installedServices = + new ArrayList(); + installedServices.addAll(userState.mInstalledServices); + installedServices.remove(userState.mUiAutomationService); + return installedServices; + } + return userState.mInstalledServices; } } @@ -415,9 +426,18 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub { synchronized (mLock) { final int resolvedUserId = mSecurityPolicy .resolveCallingUserIdEnforcingPermissionsLocked(userId); + + // The automation service is a fake one and should not be reported + // to clients as being enabled. The automation service is always the + // only active one, if it exists. + UserState userState = getUserStateLocked(resolvedUserId); + if (userState.mUiAutomationService != null) { + return Collections.emptyList(); + } + result = mEnabledServicesForFeedbackTempList; result.clear(); - List services = getUserStateLocked(resolvedUserId).mBoundServices; + List services = userState.mBoundServices; while (feedbackType != 0) { final int feedbackTypeBit = (1 << Integer.numberOfTrailingZeros(feedbackType)); feedbackType &= ~feedbackTypeBit;