Merge "Accessibility services cannot obtain the source of an event coming from a root namespace descendant."
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index d193d6e..31740ef 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -12093,6 +12093,39 @@
     }
 
     /**
+     * Finds a view by its unuque and stable accessibility id.
+     *
+     * @param accessibilityId The searched accessibility id.
+     * @return The found view.
+     */
+    final View findViewByAccessibilityId(int accessibilityId) {
+        if (accessibilityId < 0) {
+            return null;
+        }
+        return findViewByAccessibilityIdTraversal(accessibilityId);
+    }
+
+    /**
+     * Performs the traversal to find a view by its unuque and stable accessibility id.
+     *
+     * <strong>Note:</strong>This method does not stop at the root namespace
+     * boundary since the user can touch the screen at an arbitrary location
+     * potentially crossing the root namespace bounday which will send an
+     * accessibility event to accessibility services and they should be able
+     * to obtain the event source. Also accessibility ids are guaranteed to be
+     * unique in the window.
+     *
+     * @param accessibilityId The accessibility id.
+     * @return The found view.
+     */
+    View findViewByAccessibilityIdTraversal(int accessibilityId) {
+        if (getAccessibilityViewId() == accessibilityId) {
+            return this;
+        }
+        return null;
+    }
+
+    /**
      * Look for a child view with the given tag.  If this view has the given
      * tag, return this view.
      *
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index fb0d80a..5b4a6f8 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -821,6 +821,24 @@
         }
     }
 
+    @Override
+    View findViewByAccessibilityIdTraversal(int accessibilityId) {
+        View foundView = super.findViewByAccessibilityIdTraversal(accessibilityId);
+        if (foundView != null) {
+            return foundView;
+        }
+        final int childrenCount = mChildrenCount;
+        final View[] children = mChildren;
+        for (int i = 0; i < childrenCount; i++) {
+            View child = children[i];
+            foundView = child.findViewByAccessibilityIdTraversal(accessibilityId);
+            if (foundView != null) {
+                return foundView;
+            }
+        }
+        return null;
+    }
+
     /**
      * {@inheritDoc}
      */
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 9cb4e5e..a9a0347d 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -74,7 +74,6 @@
 import android.widget.Scroller;
 
 import com.android.internal.policy.PolicyManager;
-import com.android.internal.util.Predicate;
 import com.android.internal.view.BaseSurfaceHolder;
 import com.android.internal.view.IInputMethodCallback;
 import com.android.internal.view.IInputMethodSession;
@@ -4462,9 +4461,6 @@
     final class AccessibilityInteractionController {
         private static final int POOL_SIZE = 5;
 
-        private FindByAccessibilitytIdPredicate mFindByAccessibilityIdPredicate =
-            new FindByAccessibilitytIdPredicate();
-
         private ArrayList<AccessibilityNodeInfo> mTempAccessibilityNodeInfoList =
             new ArrayList<AccessibilityNodeInfo>();
 
@@ -4551,11 +4547,8 @@
 
             AccessibilityNodeInfo info = null;
             try {
-                FindByAccessibilitytIdPredicate predicate = mFindByAccessibilityIdPredicate;
-                predicate.init(accessibilityId);
-                View root = ViewRootImpl.this.mView;
-                View target = root.findViewByPredicate(predicate);
-                if (target != null && target.getVisibility() == View.VISIBLE) {
+                View target = findViewByAccessibilityId(accessibilityId);
+                if (target != null) {
                     info = target.createAccessibilityNodeInfo();
                 }
             } finally {
@@ -4794,25 +4787,12 @@
             if (root == null) {
                 return null;
             }
-            mFindByAccessibilityIdPredicate.init(accessibilityId);
-            View foundView = root.findViewByPredicate(mFindByAccessibilityIdPredicate);
-            if (foundView == null || foundView.getVisibility() != View.VISIBLE) {
+            View foundView = root.findViewByAccessibilityId(accessibilityId);
+            if (foundView != null && foundView.getVisibility() != View.VISIBLE) {
                 return null;
             }
             return foundView;
         }
-
-        private final class FindByAccessibilitytIdPredicate implements Predicate<View> {
-            public int mSearchedId;
-
-            public void init(int searchedId) {
-                mSearchedId = searchedId;
-            }
-
-            public boolean apply(View view) {
-                return (view.getAccessibilityViewId() == mSearchedId);
-            }
-        }
     }
 
     private class SendWindowContentChangedAccessibilityEvent implements Runnable {
diff --git a/core/java/android/widget/AnalogClock.java b/core/java/android/widget/AnalogClock.java
index 84ebec3..63a0870 100644
--- a/core/java/android/widget/AnalogClock.java
+++ b/core/java/android/widget/AnalogClock.java
@@ -25,6 +25,7 @@
 import android.graphics.Canvas;
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
+import android.text.format.DateUtils;
 import android.text.format.Time;
 import android.util.AttributeSet;
 import android.view.View;
@@ -228,6 +229,8 @@
         mMinutes = minute + second / 60.0f;
         mHour = hour + mMinutes / 60.0f;
         mChanged = true;
+
+        updateContentDescription(mCalendar);
     }
 
     private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
@@ -243,4 +246,11 @@
             invalidate();
         }
     };
+
+    private void updateContentDescription(Time time) {
+        final int flags = DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_24HOUR;
+        String contentDescription = DateUtils.formatDateTime(mContext,
+                time.toMillis(false), flags);
+        setContentDescription(contentDescription);
+    }
 }
diff --git a/core/java/android/widget/TimePicker.java b/core/java/android/widget/TimePicker.java
index 7444d46..f52e773 100644
--- a/core/java/android/widget/TimePicker.java
+++ b/core/java/android/widget/TimePicker.java
@@ -237,9 +237,7 @@
         }
 
         // set the content descriptions
-        if (AccessibilityManager.getInstance(mContext).isEnabled()) {
-            setContentDescriptions();
-        }
+        setContentDescriptions();
     }
 
     @Override