Add DISMISS_NOTIFICATION_SHADE action for a11y

As discussed in b/159334261, although the current a11y use-cases for
closing the notification shade are already handled, it makes sense to
add an explicit global action for accessibility services to close the
notification shade (especially given there is one for opening the shade
already).

Added dependency to SystemActions, which required me to change add
SystemActions to SystemUIGoogleBinder (topic). I also added to
CarSystemUIBinder since SystemActions was also in their xml. I don't
know if I need to add to others (eg. Arc), please advise.

Bug: 159334261
Bug: 159105552
Test: With the shade opened, as a11y service send
      GLOBAL_ACTION_DISMISS_NOTIFICATION_SHADE and verify shade is
      closed.
Change-Id: If52a1763170d5a5efd6b4756794206fd8bfb18a0
This commit is contained in:
Bernardo Rufino
2021-01-11 12:34:18 +00:00
parent d620cd52cf
commit 2c458b7cf6
6 changed files with 79 additions and 12 deletions

View File

@@ -3015,6 +3015,7 @@ package android.accessibilityservice {
field public static final int GLOBAL_ACTION_ACCESSIBILITY_BUTTON_CHOOSER = 12; // 0xc
field public static final int GLOBAL_ACTION_ACCESSIBILITY_SHORTCUT = 13; // 0xd
field public static final int GLOBAL_ACTION_BACK = 1; // 0x1
field public static final int GLOBAL_ACTION_DISMISS_NOTIFICATION_SHADE = 15; // 0xf
field public static final int GLOBAL_ACTION_HOME = 2; // 0x2
field public static final int GLOBAL_ACTION_KEYCODE_HEADSETHOOK = 10; // 0xa
field public static final int GLOBAL_ACTION_LOCK_SCREEN = 8; // 0x8

View File

@@ -555,6 +555,11 @@ public abstract class AccessibilityService extends Service {
*/
public static final int GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS = 14;
/**
* Action to dismiss the notification shade
*/
public static final int GLOBAL_ACTION_DISMISS_NOTIFICATION_SHADE = 15;
private static final String LOG_TAG = "AccessibilityService";
/**

View File

@@ -5519,6 +5519,8 @@
<string name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label">On-screen Accessibility Shortcut Chooser</string>
<!-- Label for triggering hardware accessibility shortcut action [CHAR LIMIT=NONE] -->
<string name="accessibility_system_action_hardware_a11y_shortcut_label">Accessibility Shortcut</string>
<!-- Label for dismissing the notification shade [CHAR LIMIT=NONE] -->
<string name="accessibility_system_action_dismiss_notification_shade">Dismiss Notification Shade</string>
<!-- Accessibility description of caption view -->
<string name="accessibility_freeform_caption">Caption bar of <xliff:g id="app_name">%1$s</xliff:g>.</string>

View File

@@ -3964,6 +3964,7 @@
<java-symbol type="string" name="accessibility_system_action_on_screen_a11y_shortcut_label" />
<java-symbol type="string" name="accessibility_system_action_on_screen_a11y_shortcut_chooser_label" />
<java-symbol type="string" name="accessibility_system_action_hardware_a11y_shortcut_label" />
<java-symbol type="string" name="accessibility_system_action_dismiss_notification_shade" />
<java-symbol type="string" name="accessibility_freeform_caption" />

View File

@@ -53,12 +53,18 @@ import com.android.systemui.Dependency;
import com.android.systemui.SystemUI;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.recents.Recents;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationShadeWindowController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarWindowCallback;
import com.android.systemui.util.Assert;
import java.util.Locale;
import javax.inject.Inject;
import dagger.Lazy;
/**
* Class to register system actions with accessibility framework.
*/
@@ -128,23 +134,39 @@ public class SystemActions extends SystemUI {
public static final int SYSTEM_ACTION_ID_ACCESSIBILITY_SHORTCUT =
AccessibilityService.GLOBAL_ACTION_ACCESSIBILITY_SHORTCUT; // 13
public static final int SYSTEM_ACTION_ID_ACCESSIBILITY_DISMISS_NOTIFICATION_SHADE =
AccessibilityService.GLOBAL_ACTION_DISMISS_NOTIFICATION_SHADE; // 15
private static final String PERMISSION_SELF = "com.android.systemui.permission.SELF";
private SystemActionsBroadcastReceiver mReceiver;
private final SystemActionsBroadcastReceiver mReceiver;
private Locale mLocale;
private AccessibilityManager mA11yManager;
private final AccessibilityManager mA11yManager;
private final Lazy<StatusBar> mStatusBar;
private final NotificationShadeWindowController mNotificationShadeController;
private final StatusBarWindowCallback mNotificationShadeCallback;
private boolean mDismissNotificationShadeActionRegistered;
@Inject
public SystemActions(Context context) {
public SystemActions(Context context,
NotificationShadeWindowController notificationShadeController,
Lazy<StatusBar> statusBar) {
super(context);
mReceiver = new SystemActionsBroadcastReceiver();
mLocale = mContext.getResources().getConfiguration().getLocales().get(0);
mA11yManager = (AccessibilityManager) mContext.getSystemService(
Context.ACCESSIBILITY_SERVICE);
mNotificationShadeController = notificationShadeController;
// Saving in instance variable since to prevent GC since
// NotificationShadeWindowController.registerCallback() only keeps weak references.
mNotificationShadeCallback = (keyguardShowing, keyguardOccluded, bouncerShowing) ->
registerOrUnregisterDismissNotificationShadeAction();
mStatusBar = statusBar;
}
@Override
public void start() {
mNotificationShadeController.registerCallback(mNotificationShadeCallback);
mContext.registerReceiverForAllUsers(
mReceiver,
mReceiver.createIntentFilter(),
@@ -210,6 +232,32 @@ public class SystemActions extends SystemUI {
mA11yManager.registerSystemAction(actionTakeScreenshot, SYSTEM_ACTION_ID_TAKE_SCREENSHOT);
mA11yManager.registerSystemAction(
actionAccessibilityShortcut, SYSTEM_ACTION_ID_ACCESSIBILITY_SHORTCUT);
registerOrUnregisterDismissNotificationShadeAction();
}
private void registerOrUnregisterDismissNotificationShadeAction() {
Assert.isMainThread();
// Saving state in instance variable since this callback is called quite often to avoid
// binder calls
StatusBar statusBar = mStatusBar.get();
if (statusBar.isPanelExpanded() && !statusBar.isKeyguardShowing()) {
if (!mDismissNotificationShadeActionRegistered) {
mA11yManager.registerSystemAction(
createRemoteAction(
R.string.accessibility_system_action_dismiss_notification_shade,
SystemActionsBroadcastReceiver
.INTENT_ACTION_ACCESSIBILITY_DISMISS_NOTIFICATION_SHADE),
SYSTEM_ACTION_ID_ACCESSIBILITY_DISMISS_NOTIFICATION_SHADE);
mDismissNotificationShadeActionRegistered = true;
}
} else {
if (mDismissNotificationShadeActionRegistered) {
mA11yManager.unregisterSystemAction(
SYSTEM_ACTION_ID_ACCESSIBILITY_DISMISS_NOTIFICATION_SHADE);
mDismissNotificationShadeActionRegistered = false;
}
}
}
/**
@@ -261,10 +309,15 @@ public class SystemActions extends SystemUI {
R.string.accessibility_system_action_on_screen_a11y_shortcut_chooser_label;
intent = SystemActionsBroadcastReceiver.INTENT_ACTION_ACCESSIBILITY_BUTTON_CHOOSER;
break;
case SYSTEM_ACTION_ID_ACCESSIBILITY_SHORTCUT:
case SYSTEM_ACTION_ID_ACCESSIBILITY_SHORTCUT:
labelId = R.string.accessibility_system_action_hardware_a11y_shortcut_label;
intent = SystemActionsBroadcastReceiver.INTENT_ACTION_ACCESSIBILITY_SHORTCUT;
break;
case SYSTEM_ACTION_ID_ACCESSIBILITY_DISMISS_NOTIFICATION_SHADE:
labelId = R.string.accessibility_system_action_dismiss_notification_shade;
intent = SystemActionsBroadcastReceiver
.INTENT_ACTION_ACCESSIBILITY_DISMISS_NOTIFICATION_SHADE;
break;
default:
return;
}
@@ -369,6 +422,10 @@ public class SystemActions extends SystemUI {
mA11yManager.performAccessibilityShortcut();
}
private void handleAccessibilityDismissNotificationShade() {
mStatusBar.get().animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE, false /* force */);
}
private class SystemActionsBroadcastReceiver extends BroadcastReceiver {
private static final String INTENT_ACTION_BACK = "SYSTEM_ACTION_BACK";
private static final String INTENT_ACTION_HOME = "SYSTEM_ACTION_HOME";
@@ -384,6 +441,8 @@ public class SystemActions extends SystemUI {
"SYSTEM_ACTION_ACCESSIBILITY_BUTTON_MENU";
private static final String INTENT_ACTION_ACCESSIBILITY_SHORTCUT =
"SYSTEM_ACTION_ACCESSIBILITY_SHORTCUT";
private static final String INTENT_ACTION_ACCESSIBILITY_DISMISS_NOTIFICATION_SHADE =
"SYSTEM_ACTION_ACCESSIBILITY_DISMISS_NOTIFICATION_SHADE";
private PendingIntent createPendingIntent(Context context, String intentAction) {
switch (intentAction) {
@@ -397,7 +456,8 @@ public class SystemActions extends SystemUI {
case INTENT_ACTION_TAKE_SCREENSHOT:
case INTENT_ACTION_ACCESSIBILITY_BUTTON:
case INTENT_ACTION_ACCESSIBILITY_BUTTON_CHOOSER:
case INTENT_ACTION_ACCESSIBILITY_SHORTCUT: {
case INTENT_ACTION_ACCESSIBILITY_SHORTCUT:
case INTENT_ACTION_ACCESSIBILITY_DISMISS_NOTIFICATION_SHADE: {
Intent intent = new Intent(intentAction);
intent.setPackage(context.getPackageName());
return PendingIntent.getBroadcast(context, 0, intent,
@@ -422,6 +482,7 @@ public class SystemActions extends SystemUI {
intentFilter.addAction(INTENT_ACTION_ACCESSIBILITY_BUTTON);
intentFilter.addAction(INTENT_ACTION_ACCESSIBILITY_BUTTON_CHOOSER);
intentFilter.addAction(INTENT_ACTION_ACCESSIBILITY_SHORTCUT);
intentFilter.addAction(INTENT_ACTION_ACCESSIBILITY_DISMISS_NOTIFICATION_SHADE);
return intentFilter;
}
@@ -473,6 +534,10 @@ public class SystemActions extends SystemUI {
handleAccessibilityShortcut();
break;
}
case INTENT_ACTION_ACCESSIBILITY_DISMISS_NOTIFICATION_SHADE: {
handleAccessibilityDismissNotificationShade();
break;
}
default:
break;
}

View File

@@ -334,13 +334,6 @@ public class DependencyProvider {
return WindowManagerWrapper.getInstance();
}
/** */
@Provides
@SysUISingleton
public SystemActions providesSystemActions(Context context) {
return new SystemActions(context);
}
/** */
@Provides
@SysUISingleton