Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2c458b7c authored by Bernardo Rufino's avatar Bernardo Rufino
Browse files

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
parent d620cd52
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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
+5 −0
Original line number Diff line number Diff line
@@ -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";

    /**
+2 −0
Original line number Diff line number Diff line
@@ -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>

+1 −0
Original line number Diff line number Diff line
@@ -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" />

+70 −5
Original line number Diff line number Diff line
@@ -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;
            }
        }
    }

    /**
@@ -265,6 +313,11 @@ public class SystemActions extends SystemUI {
                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;
            }
Loading