Migrate notification shade to use the a11y panes

The new pane API is intended to manage things that
look like windows but aren't formal windows. The
notification shade and quick settings are a great
example of this. I've replaced explicit requests
for announcements with code that just keeps the
pane title up to date. The correct events are then
dispatched automatically.

Bug: 62231686
Test: I've verified that the correct events are
dispatched using the TestBack experimental
accessibility service. I've also run TalkBack with
the events. TalkBack has an issue with the new API
(b/73126910), so it will be slightly too verbose
until they check the change type.

Change-Id: I8ba130e20b09c69fff65c59af9f08aa6abd2b016
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index cf26b2b..713b6cd 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -7308,6 +7308,10 @@
         return mAccessibilityPaneTitle;
     }
 
+    private boolean isAccessibilityPane() {
+        return !TextUtils.isEmpty(mAccessibilityPaneTitle);
+    }
+
     /**
      * Sends an accessibility event of the given type. If accessibility is
      * not enabled this method has no effect. The default implementation calls
@@ -11632,7 +11636,7 @@
         return mode == IMPORTANT_FOR_ACCESSIBILITY_YES || isActionableForAccessibility()
                 || hasListenersForAccessibility() || getAccessibilityNodeProvider() != null
                 || getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE
-                || (mAccessibilityPaneTitle != null);
+                || isAccessibilityPane();
     }
 
     /**
@@ -11729,18 +11733,26 @@
 
         // Changes to views with a pane title count as window state changes, as the pane title
         // marks them as significant parts of the UI.
-        if (!TextUtils.isEmpty(getAccessibilityPaneTitle())) {
-            final AccessibilityEvent event = AccessibilityEvent.obtain();
-            event.setEventType(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
-            event.setContentChangeTypes(changeType);
-            onPopulateAccessibilityEvent(event);
-            if (mParent != null) {
-                try {
-                    mParent.requestSendAccessibilityEvent(this, event);
-                } catch (AbstractMethodError e) {
-                    Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName()
-                            + " does not fully implement ViewParent", e);
+        if ((changeType != AccessibilityEvent.CONTENT_CHANGE_TYPE_SUBTREE)
+                && isAccessibilityPane()) {
+            // If the pane isn't visible, content changed events are sufficient unless we're
+            // reporting that the view just disappeared
+            if ((getVisibility() == VISIBLE)
+                    || (changeType == AccessibilityEvent.CONTENT_CHANGE_TYPE_PANE_DISAPPEARED)) {
+                final AccessibilityEvent event = AccessibilityEvent.obtain();
+                event.setEventType(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
+                event.setContentChangeTypes(changeType);
+                event.setSource(this);
+                onPopulateAccessibilityEvent(event);
+                if (mParent != null) {
+                    try {
+                        mParent.requestSendAccessibilityEvent(this, event);
+                    } catch (AbstractMethodError e) {
+                        Log.e(VIEW_LOG_TAG, mParent.getClass().getSimpleName()
+                                + " does not fully implement ViewParent", e);
+                    }
                 }
+                return;
             }
         }
 
@@ -14030,6 +14042,11 @@
         }
 
         if (accessibilityEnabled) {
+            // If we're an accessibility pane and the visibility changed, we already have sent
+            // a state change, so we really don't need to report other changes.
+            if (isAccessibilityPane()) {
+                changed &= ~VISIBILITY_MASK;
+            }
             if ((changed & FOCUSABLE) != 0 || (changed & VISIBILITY_MASK) != 0
                     || (changed & CLICKABLE) != 0 || (changed & LONG_CLICKABLE) != 0
                     || (changed & CONTEXT_CLICKABLE) != 0) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
index 5a3081c..3847040 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
@@ -171,8 +171,6 @@
             queryTiles();
             mNotifQsContainer.setCustomizerAnimating(true);
             mNotifQsContainer.setCustomizerShowing(true);
-            announceForAccessibility(mContext.getString(
-                    R.string.accessibility_desc_quick_settings_edit));
             Dependency.get(KeyguardMonitor.class).addCallback(mKeyguardCallback);
             updateNavColors();
         }
@@ -213,8 +211,6 @@
             mClipper.animateCircularClip(mX, mY, false, mCollapseAnimationListener);
             mNotifQsContainer.setCustomizerAnimating(true);
             mNotifQsContainer.setCustomizerShowing(false);
-            announceForAccessibility(mContext.getString(
-                    R.string.accessibility_desc_quick_settings));
             Dependency.get(KeyguardMonitor.class).removeCallback(mKeyguardCallback);
             updateNavColors();
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 52d005c..0e8fcba 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -45,7 +45,7 @@
 import android.view.ViewGroup;
 import android.view.ViewTreeObserver;
 import android.view.WindowInsets;
-import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
 import android.widget.FrameLayout;
 
 import com.android.internal.logging.MetricsLogger;
@@ -111,6 +111,7 @@
                 }
             };
     private final PowerManager mPowerManager;
+    private final AccessibilityManager mAccessibilityManager;
 
     private KeyguardAffordanceHelper mAffordanceHelper;
     private KeyguardUserSwitcher mKeyguardUserSwitcher;
@@ -249,6 +250,8 @@
         setWillNotDraw(!DEBUG);
         mFalsingManager = FalsingManager.getInstance(context);
         mPowerManager = context.getSystemService(PowerManager.class);
+        mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
+        setAccessibilityPaneTitle(determineAccessibilityPaneTitle());
     }
 
     public void setStatusBar(StatusBar bar) {
@@ -661,16 +664,6 @@
     }
 
     @Override
-    public boolean dispatchPopulateAccessibilityEventInternal(AccessibilityEvent event) {
-        if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
-            event.getText().add(getKeyguardOrLockScreenString());
-            mLastAnnouncementWasQuickSettings = false;
-            return true;
-        }
-        return super.dispatchPopulateAccessibilityEventInternal(event);
-    }
-
-    @Override
     public boolean onInterceptTouchEvent(MotionEvent event) {
         if (mBlockTouches || mQsFullyExpanded && mQs.onInterceptTouchEvent(event)) {
             return false;
@@ -1300,10 +1293,6 @@
             setQsExpanded(true);
         } else if (height <= mQsMinExpansionHeight && mQsExpanded) {
             setQsExpanded(false);
-            if (mLastAnnouncementWasQuickSettings && !mTracking && !isCollapsing()) {
-                announceForAccessibility(getKeyguardOrLockScreenString());
-                mLastAnnouncementWasQuickSettings = false;
-            }
         }
         mQsExpansionHeight = height;
         updateQsExpansion();
@@ -1329,13 +1318,10 @@
             updateClock(mClockPositionResult.clockAlpha, mClockPositionResult.clockScale);
         }
 
-        // Upon initialisation when we are not layouted yet we don't want to announce that we are
-        // fully expanded, hence the != 0.0f check.
-        if (height != 0.0f && mQsFullyExpanded && !mLastAnnouncementWasQuickSettings) {
-            announceForAccessibility(getContext().getString(
-                    R.string.accessibility_desc_quick_settings));
-            mLastAnnouncementWasQuickSettings = true;
+        if (mAccessibilityManager.isEnabled()) {
+            setAccessibilityPaneTitle(determineAccessibilityPaneTitle());
         }
+
         if (mQsFullyExpanded && mFalsingManager.shouldEnforceBouncer()) {
             mStatusBar.executeRunnableDismissingKeyguard(null, null /* cancelAction */,
                     false /* dismissShade */, true /* afterKeyguardGone */, false /* deferred */);
@@ -1350,9 +1336,13 @@
         mQs.setQsExpansion(getQsExpansionFraction(), getHeaderTranslation());
     }
 
-    private String getKeyguardOrLockScreenString() {
+    private String determineAccessibilityPaneTitle() {
         if (mQs != null && mQs.isCustomizing()) {
             return getContext().getString(R.string.accessibility_desc_quick_settings_edit);
+        } else if (mQsExpansionHeight != 0.0f && mQsFullyExpanded) {
+            // Upon initialisation when we are not layouted yet we don't want to announce that we
+            // are fully expanded, hence the != 0.0f check.
+            return getContext().getString(R.string.accessibility_desc_quick_settings);
         } else if (mStatusBarState == StatusBarState.KEYGUARD) {
             return getContext().getString(R.string.accessibility_desc_lock_screen);
         } else {
@@ -1880,6 +1870,9 @@
             requestScrollerTopPaddingUpdate(false /* animate */);
             requestPanelHeightUpdate();
         }
+        if (mAccessibilityManager.isEnabled()) {
+            setAccessibilityPaneTitle(determineAccessibilityPaneTitle());
+        }
     }
 
     @Override