Merge "Fixing bugs exposed when moving accessibility CTS tests to UiAutomation." into jb-mr2-dev
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index 40f45b7..7e21db3 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -378,6 +378,23 @@
     /**
      * Creates a new instance.
      *
+     * @param isAutomation Whether this is a test automation service.
+     *
+     * @hide
+     */
+    public AccessibilityServiceInfo(boolean isAutomation) {
+        // Automation service can do anything.
+        if (isAutomation) {
+            mCapabilities |= CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT
+                    | CAPABILITY_CAN_REQUEST_TOUCH_EXPLORATION
+                    | CAPABILITY_CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY
+                    | CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS;
+        }
+    }
+
+    /**
+     * Creates a new instance.
+     *
      * @param resolveInfo The service resolve info.
      * @param context Context for accessing resources.
      * @throws XmlPullParserException If a XML parsing error occurs.
diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java
index 05b79c1..498fa42 100644
--- a/core/java/android/app/UiAutomation.java
+++ b/core/java/android/app/UiAutomation.java
@@ -443,18 +443,25 @@
      */
     public AccessibilityEvent executeAndWaitForEvent(Runnable command,
             AccessibilityEventFilter filter, long timeoutMillis) throws TimeoutException {
+        // Acquire the lock and prepare for receiving events.
         synchronized (mLock) {
             throwIfNotConnectedLocked();
-
             mEventQueue.clear();
             // Prepare to wait for an event.
             mWaitingForEventDelivery = true;
+        }
 
-            // We will ignore events from previous interactions.
-            final long executionStartTimeMillis = SystemClock.uptimeMillis();
+        // Note: We have to release the lock since calling out with this lock held
+        // can bite. We will correctly filter out events from other interactions,
+        // so starting to collect events before running the action is just fine.
 
-            // Execute the command.
-            command.run();
+        // We will ignore events from previous interactions.
+        final long executionStartTimeMillis = SystemClock.uptimeMillis();
+        // Execute the command *without* the lock being held.
+        command.run();
+
+        // Acquire the lock and wait for the event.
+        synchronized (mLock) {
             try {
                 // Wait for the event.
                 final long startTimeMillis = SystemClock.uptimeMillis();
@@ -463,7 +470,7 @@
                     while (!mEventQueue.isEmpty()) {
                         AccessibilityEvent event = mEventQueue.remove(0);
                         // Ignore events from previous interactions.
-                        if (event.getEventTime() <= executionStartTimeMillis) {
+                        if (event.getEventTime() < executionStartTimeMillis) {
                             continue;
                         }
                         if (filter.accept(event)) {
diff --git a/core/java/android/app/UiAutomationConnection.java b/core/java/android/app/UiAutomationConnection.java
index 97c7ff3..5bc17fa 100644
--- a/core/java/android/app/UiAutomationConnection.java
+++ b/core/java/android/app/UiAutomationConnection.java
@@ -158,7 +158,7 @@
     private void registerUiTestAutomationServiceLocked(IAccessibilityServiceClient client) {
         IAccessibilityManager manager = IAccessibilityManager.Stub.asInterface(
                 ServiceManager.getService(Context.ACCESSIBILITY_SERVICE));
-        AccessibilityServiceInfo info = new AccessibilityServiceInfo();
+        AccessibilityServiceInfo info = new AccessibilityServiceInfo(true);
         info.eventTypes = AccessibilityEvent.TYPES_ALL_MASK;
         info.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC;
         info.flags |= AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfoCache.java b/core/java/android/view/accessibility/AccessibilityNodeInfoCache.java
index 14954be..28518aa 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfoCache.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfoCache.java
@@ -83,6 +83,7 @@
                 } break;
                 case AccessibilityEvent.TYPE_VIEW_FOCUSED:
                 case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED:
+                case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED:
                 case AccessibilityEvent.TYPE_VIEW_SELECTED:
                 case AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED:
                 case AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED: {
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 1246051..9e3f87f 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -8042,7 +8042,7 @@
             info.setEditable(true);
         }
 
-        if (TextUtils.isEmpty(getContentDescription()) && !TextUtils.isEmpty(mText)) {
+        if (!TextUtils.isEmpty(mText)) {
             info.addAction(AccessibilityNodeInfo.ACTION_NEXT_AT_MOVEMENT_GRANULARITY);
             info.addAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY);
             info.setMovementGranularities(AccessibilityNodeInfo.MOVEMENT_GRANULARITY_CHARACTER
@@ -8051,6 +8051,7 @@
                     | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PARAGRAPH
                     | AccessibilityNodeInfo.MOVEMENT_GRANULARITY_PAGE);
         }
+
         if (isFocused()) {
             if (canSelectText()) {
                 info.addAction(AccessibilityNodeInfo.ACTION_SET_SELECTION);
@@ -8655,13 +8656,10 @@
      */
     @Override
     public CharSequence getIterableTextForAccessibility() {
-        if (!TextUtils.isEmpty(mText)) {
-            if (!(mText instanceof Spannable)) {
-                setText(mText, BufferType.SPANNABLE);
-            }
-            return mText;
+        if (!(mText instanceof Spannable)) {
+            setText(mText, BufferType.SPANNABLE);
         }
-        return super.getIterableTextForAccessibility();
+        return mText;
     }
 
     /**
@@ -8697,13 +8695,7 @@
      */
     @Override
     public int getAccessibilitySelectionStart() {
-        if (TextUtils.isEmpty(getContentDescription())) {
-            final int selectionStart = getSelectionStart();
-            if (selectionStart >= 0) {
-                return selectionStart;
-            }
-        }
-        return ACCESSIBILITY_CURSOR_POSITION_UNDEFINED;
+        return getSelectionStart();
     }
 
     /**
@@ -8718,13 +8710,7 @@
      */
     @Override
     public int getAccessibilitySelectionEnd() {
-        if (TextUtils.isEmpty(getContentDescription())) {
-            final int selectionEnd = getSelectionEnd();
-            if (selectionEnd >= 0) {
-                return selectionEnd;
-            }
-        }
-        return ACCESSIBILITY_CURSOR_POSITION_UNDEFINED;
+        return getSelectionEnd();
     }
 
     /**
diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
index 2f64908..64dfd67 100644
--- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -542,7 +542,8 @@
         return -1;
     }
 
-    public void registerUiTestAutomationService(IBinder owner, IAccessibilityServiceClient serviceClient,
+    public void registerUiTestAutomationService(IBinder owner,
+            IAccessibilityServiceClient serviceClient,
             AccessibilityServiceInfo accessibilityServiceInfo) {
         mSecurityPolicy.enforceCallingPermission(Manifest.permission.RETRIEVE_WINDOW_CONTENT,
                 FUNCTION_REGISTER_UI_TEST_AUTOMATION_SERVICE);
@@ -1732,14 +1733,12 @@
                 mFetchFlags &= ~AccessibilityNodeInfo.FLAG_REPORT_VIEW_IDS;
             }
 
-            if (mResolveInfo != null) {
-                mRequestTouchExplorationMode = (info.flags
-                        & AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE) != 0;
-                mRequestEnhancedWebAccessibility = (info.flags
-                        & AccessibilityServiceInfo.FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY) != 0;
-                mRequestFilterKeyEvents = (info.flags
-                        & AccessibilityServiceInfo.FLAG_REQUEST_FILTER_KEY_EVENTS)  != 0;
-            }
+            mRequestTouchExplorationMode = (info.flags
+                    & AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE) != 0;
+            mRequestEnhancedWebAccessibility = (info.flags
+                    & AccessibilityServiceInfo.FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY) != 0;
+            mRequestFilterKeyEvents = (info.flags
+                    & AccessibilityServiceInfo.FLAG_REQUEST_FILTER_KEY_EVENTS)  != 0;
         }
 
         /**