Always propagate AccessibilityCache events

Bug: b/32642665
Test: Steps:
	- Retrieve root AccessibilityNodeInfo
	- Change text on its child TextView
	- Wait for a few seconds to let the AccessibilityEvent propagate to
    the AccessibilityCache
	- Get the child AccessibilityNodeInfo from the root, corresponding to
    that TextView, and ensure that it's updated to reflect the text
    change
Change-Id: Icbdb91803b646fa06aaf11996d350f6f65c1e809
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index b311c21..3e5cc54 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -1531,8 +1531,9 @@
             mCaller.sendMessage(message);
         }
 
-        public void onAccessibilityEvent(AccessibilityEvent event) {
-            Message message = mCaller.obtainMessageO(DO_ON_ACCESSIBILITY_EVENT, event);
+        public void onAccessibilityEvent(AccessibilityEvent event, boolean serviceWantsEvent) {
+            Message message = mCaller.obtainMessageBO(
+                    DO_ON_ACCESSIBILITY_EVENT, serviceWantsEvent, event);
             mCaller.sendMessage(message);
         }
 
@@ -1581,9 +1582,14 @@
             switch (message.what) {
                 case DO_ON_ACCESSIBILITY_EVENT: {
                     AccessibilityEvent event = (AccessibilityEvent) message.obj;
+                    boolean serviceWantsEvent = message.arg1 != 0;
                     if (event != null) {
+                        // Send the event to AccessibilityCache via AccessibilityInteractionClient
                         AccessibilityInteractionClient.getInstance().onAccessibilityEvent(event);
-                        mCallback.onAccessibilityEvent(event);
+                        if (serviceWantsEvent) {
+                            // Send the event to AccessibilityService
+                            mCallback.onAccessibilityEvent(event);
+                        }
                         // Make sure the event is recycled.
                         try {
                             event.recycle();
diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl
index ef05d6f..da16a65 100644
--- a/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl
+++ b/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl
@@ -31,7 +31,7 @@
 
     void init(in IAccessibilityServiceConnection connection, int connectionId, IBinder windowToken);
 
-    void onAccessibilityEvent(in AccessibilityEvent event);
+    void onAccessibilityEvent(in AccessibilityEvent event, in boolean serviceWantsEvent);
 
     void onInterrupt();
 
diff --git a/core/java/android/view/accessibility/AccessibilityCache.java b/core/java/android/view/accessibility/AccessibilityCache.java
index ee5bbe8..9bc4bc7 100644
--- a/core/java/android/view/accessibility/AccessibilityCache.java
+++ b/core/java/android/view/accessibility/AccessibilityCache.java
@@ -42,6 +42,26 @@
 
     private static final boolean CHECK_INTEGRITY = "eng".equals(Build.TYPE);
 
+    /**
+     * {@link AccessibilityEvent} types that are critical for the cache to stay up to date
+     *
+     * When adding new event types in {@link #onAccessibilityEvent}, please add it here also, to
+     * make sure that the events are delivered to cache regardless of
+     * {@link android.accessibilityservice.AccessibilityServiceInfo#eventTypes}
+     */
+    public static final int CACHE_CRITICAL_EVENTS_MASK =
+            AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED
+                    | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED
+                    | AccessibilityEvent.TYPE_VIEW_FOCUSED
+                    | AccessibilityEvent.TYPE_VIEW_SELECTED
+                    | AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED
+                    | AccessibilityEvent.TYPE_VIEW_CLICKED
+                    | AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED
+                    | AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED
+                    | AccessibilityEvent.TYPE_VIEW_SCROLLED
+                    | AccessibilityEvent.TYPE_WINDOWS_CHANGED
+                    | AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED;
+
     private final Object mLock = new Object();
 
     private final AccessibilityNodeRefresher mAccessibilityNodeRefresher;
@@ -100,6 +120,9 @@
      * Notifies the cache that the something in the UI changed. As a result
      * the cache will either refresh some nodes or evict some nodes.
      *
+     * Note: any event that ends up affecting the cache should also be present in
+     * {@link #CACHE_CRITICAL_EVENTS_MASK}
+     *
      * @param event An event.
      */
     public void onAccessibilityEvent(AccessibilityEvent event) {
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 386fbc9..dafa3f6 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -78,10 +78,10 @@
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
 import android.view.MagnificationSpec;
-import android.view.MotionEvent;
 import android.view.WindowInfo;
 import android.view.WindowManager;
 import android.view.WindowManagerInternal;
+import android.view.accessibility.AccessibilityCache;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityInteractionClient;
 import android.view.accessibility.AccessibilityManager;
@@ -1151,8 +1151,11 @@
                 Service service = state.mBoundServices.get(i);
 
                 if (service.mIsDefault == isDefault) {
-                    if (canDispatchEventToServiceLocked(service, event)) {
-                        service.notifyAccessibilityEvent(event);
+                    if (doesServiceWantEventLocked(service, event)) {
+                        service.notifyAccessibilityEvent(event, true);
+                    } else if ((AccessibilityCache.CACHE_CRITICAL_EVENTS_MASK
+                            & event.getEventType()) != 0) {
+                        service.notifyAccessibilityEvent(event, false);
                     }
                 }
             }
@@ -1201,7 +1204,7 @@
      * @param event The event.
      * @return True if the listener should be notified, false otherwise.
      */
-    private boolean canDispatchEventToServiceLocked(Service service, AccessibilityEvent event) {
+    private boolean doesServiceWantEventLocked(Service service, AccessibilityEvent event) {
 
         if (!service.canReceiveEventsLocked()) {
             return false;
@@ -2285,7 +2288,8 @@
             public void handleMessage(Message message) {
                 final int eventType =  message.what;
                 AccessibilityEvent event = (AccessibilityEvent) message.obj;
-                notifyAccessibilityEventInternal(eventType, event);
+                boolean serviceWantsEvent = message.arg1 != 0;
+                notifyAccessibilityEventInternal(eventType, event, serviceWantsEvent);
             }
         };
 
@@ -3200,8 +3204,11 @@
          * Performs a notification for an {@link AccessibilityEvent}.
          *
          * @param event The event.
+         * @param serviceWantsEvent whether the event should be received by
+         *  {@link AccessibilityService#onAccessibilityEvent} (true),
+         *  as opposed to just {@link AccessibilityInteractionClient#onAccessibilityEvent} (false)
          */
-        public void notifyAccessibilityEvent(AccessibilityEvent event) {
+        public void notifyAccessibilityEvent(AccessibilityEvent event, boolean serviceWantsEvent) {
             synchronized (mLock) {
                 final int eventType = event.getEventType();
                 // Make a copy since during dispatch it is possible the event to
@@ -3223,6 +3230,7 @@
                     // Send all messages, bypassing mPendingEvents
                     message = mEventDispatchHandler.obtainMessage(eventType, newEvent);
                 }
+                message.arg1 = serviceWantsEvent ? 1 : 0;
 
                 mEventDispatchHandler.sendMessageDelayed(message, mNotificationTimeout);
             }
@@ -3233,7 +3241,10 @@
          *
          * @param eventType The type of the event to dispatch.
          */
-        private void notifyAccessibilityEventInternal(int eventType, AccessibilityEvent event) {
+        private void notifyAccessibilityEventInternal(
+                int eventType,
+                AccessibilityEvent event,
+                boolean serviceWantsEvent) {
             IAccessibilityServiceClient listener;
 
             synchronized (mLock) {
@@ -3280,7 +3291,7 @@
             }
 
             try {
-                listener.onAccessibilityEvent(event);
+                listener.onAccessibilityEvent(event, serviceWantsEvent);
                 if (DEBUG) {
                     Slog.i(LOG_TAG, "Event " + event + " sent to " + listener);
                 }