From 428e3979599203f4451fe7637a6a0593c46cd809 Mon Sep 17 00:00:00 2001 From: Phil Weaver Date: Thu, 18 Jan 2018 12:50:05 -0800 Subject: [PATCH] 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 --- core/java/android/view/View.java | 41 +++++++++++++------ .../systemui/qs/customize/QSCustomizer.java | 4 -- .../phone/NotificationPanelView.java | 37 +++++++---------- 3 files changed, 44 insertions(+), 38 deletions(-) diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index cf26b2bce04aa..713b6cd88763e 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -7308,6 +7308,10 @@ public class View implements Drawable.Callback, KeyEvent.Callback, 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 @@ public class View implements Drawable.Callback, KeyEvent.Callback, return mode == IMPORTANT_FOR_ACCESSIBILITY_YES || isActionableForAccessibility() || hasListenersForAccessibility() || getAccessibilityNodeProvider() != null || getAccessibilityLiveRegion() != ACCESSIBILITY_LIVE_REGION_NONE - || (mAccessibilityPaneTitle != null); + || isAccessibilityPane(); } /** @@ -11729,18 +11733,26 @@ public class View implements Drawable.Callback, KeyEvent.Callback, // 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 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } 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 5a3081cd6664b..3847040271e23 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 @@ public class QSCustomizer extends LinearLayout implements OnMenuItemClickListene 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 @@ public class QSCustomizer extends LinearLayout implements OnMenuItemClickListene 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 52d005cb152ab..0e8fcbabf2aea 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.View; 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 @@ public class NotificationPanelView extends PanelView implements } }; private final PowerManager mPowerManager; + private final AccessibilityManager mAccessibilityManager; private KeyguardAffordanceHelper mAffordanceHelper; private KeyguardUserSwitcher mKeyguardUserSwitcher; @@ -249,6 +250,8 @@ public class NotificationPanelView extends PanelView implements setWillNotDraw(!DEBUG); mFalsingManager = FalsingManager.getInstance(context); mPowerManager = context.getSystemService(PowerManager.class); + mAccessibilityManager = context.getSystemService(AccessibilityManager.class); + setAccessibilityPaneTitle(determineAccessibilityPaneTitle()); } public void setStatusBar(StatusBar bar) { @@ -660,16 +663,6 @@ public class NotificationPanelView extends PanelView implements super.flingToHeight(vel, expand, target, collapseSpeedUpFactor, expandBecauseOfFalsing); } - @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)) { @@ -1300,10 +1293,6 @@ public class NotificationPanelView extends PanelView implements setQsExpanded(true); } else if (height <= mQsMinExpansionHeight && mQsExpanded) { setQsExpanded(false); - if (mLastAnnouncementWasQuickSettings && !mTracking && !isCollapsing()) { - announceForAccessibility(getKeyguardOrLockScreenString()); - mLastAnnouncementWasQuickSettings = false; - } } mQsExpansionHeight = height; updateQsExpansion(); @@ -1329,13 +1318,10 @@ public class NotificationPanelView extends PanelView implements 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 @@ public class NotificationPanelView extends PanelView implements 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 @@ public class NotificationPanelView extends PanelView implements requestScrollerTopPaddingUpdate(false /* animate */); requestPanelHeightUpdate(); } + if (mAccessibilityManager.isEnabled()) { + setAccessibilityPaneTitle(determineAccessibilityPaneTitle()); + } } @Override