1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.systemui.accessibility; 18 19 import static android.view.WindowManager.ScreenshotSource.SCREENSHOT_ACCESSIBILITY_ACTIONS; 20 21 import static com.android.internal.accessibility.common.ShortcutConstants.CHOOSER_PACKAGE_NAME; 22 23 import android.accessibilityservice.AccessibilityService; 24 import android.app.PendingIntent; 25 import android.app.RemoteAction; 26 import android.content.BroadcastReceiver; 27 import android.content.Context; 28 import android.content.Intent; 29 import android.content.IntentFilter; 30 import android.content.res.Configuration; 31 import android.graphics.drawable.Icon; 32 import android.hardware.input.InputManager; 33 import android.os.Handler; 34 import android.os.Looper; 35 import android.os.PowerManager; 36 import android.os.RemoteException; 37 import android.os.SystemClock; 38 import android.util.Log; 39 import android.view.IWindowManager; 40 import android.view.InputDevice; 41 import android.view.KeyCharacterMap; 42 import android.view.KeyEvent; 43 import android.view.WindowManagerGlobal; 44 import android.view.accessibility.AccessibilityManager; 45 46 import com.android.internal.R; 47 import com.android.internal.accessibility.dialog.AccessibilityButtonChooserActivity; 48 import com.android.internal.accessibility.util.AccessibilityUtils; 49 import com.android.internal.annotations.VisibleForTesting; 50 import com.android.internal.util.ScreenshotHelper; 51 import com.android.systemui.CoreStartable; 52 import com.android.systemui.dagger.SysUISingleton; 53 import com.android.systemui.recents.Recents; 54 import com.android.systemui.settings.DisplayTracker; 55 import com.android.systemui.settings.UserTracker; 56 import com.android.systemui.shade.ShadeController; 57 import com.android.systemui.shade.ShadeViewController; 58 import com.android.systemui.statusbar.CommandQueue; 59 import com.android.systemui.statusbar.NotificationShadeWindowController; 60 import com.android.systemui.statusbar.phone.CentralSurfaces; 61 import com.android.systemui.statusbar.phone.StatusBarWindowCallback; 62 import com.android.systemui.util.Assert; 63 64 import dagger.Lazy; 65 66 import java.util.Locale; 67 import java.util.Optional; 68 69 import javax.inject.Inject; 70 71 /** 72 * Class to register system actions with accessibility framework. 73 */ 74 @SysUISingleton 75 public class SystemActions implements CoreStartable { 76 private static final String TAG = "SystemActions"; 77 78 /** 79 * Action ID to go back. 80 */ 81 private static final int SYSTEM_ACTION_ID_BACK = AccessibilityService.GLOBAL_ACTION_BACK; // = 1 82 83 /** 84 * Action ID to go home. 85 */ 86 private static final int SYSTEM_ACTION_ID_HOME = AccessibilityService.GLOBAL_ACTION_HOME; // = 2 87 88 /** 89 * Action ID to toggle showing the overview of recent apps. Will fail on platforms that don't 90 * show recent apps. 91 */ 92 private static final int SYSTEM_ACTION_ID_RECENTS = 93 AccessibilityService.GLOBAL_ACTION_RECENTS; // = 3 94 95 /** 96 * Action ID to open the notifications. 97 */ 98 private static final int SYSTEM_ACTION_ID_NOTIFICATIONS = 99 AccessibilityService.GLOBAL_ACTION_NOTIFICATIONS; // = 4 100 101 /** 102 * Action ID to open the quick settings. 103 */ 104 private static final int SYSTEM_ACTION_ID_QUICK_SETTINGS = 105 AccessibilityService.GLOBAL_ACTION_QUICK_SETTINGS; // = 5 106 107 /** 108 * Action ID to open the power long-press dialog. 109 */ 110 private static final int SYSTEM_ACTION_ID_POWER_DIALOG = 111 AccessibilityService.GLOBAL_ACTION_POWER_DIALOG; // = 6 112 113 /** 114 * Action ID to lock the screen 115 */ 116 private static final int SYSTEM_ACTION_ID_LOCK_SCREEN = 117 AccessibilityService.GLOBAL_ACTION_LOCK_SCREEN; // = 8 118 119 /** 120 * Action ID to take a screenshot 121 */ 122 private static final int SYSTEM_ACTION_ID_TAKE_SCREENSHOT = 123 AccessibilityService.GLOBAL_ACTION_TAKE_SCREENSHOT; // = 9 124 125 /** 126 * Action ID to send the KEYCODE_HEADSETHOOK KeyEvent, which is used to answer/hang up calls and 127 * play/stop media 128 */ 129 private static final int SYSTEM_ACTION_ID_KEYCODE_HEADSETHOOK = 130 AccessibilityService.GLOBAL_ACTION_KEYCODE_HEADSETHOOK; // = 10 131 132 /** 133 * Action ID to trigger the accessibility button 134 */ 135 public static final int SYSTEM_ACTION_ID_ACCESSIBILITY_BUTTON = 136 AccessibilityService.GLOBAL_ACTION_ACCESSIBILITY_BUTTON; // 11 137 138 /** 139 * Action ID to show accessibility button's menu of services 140 */ 141 public static final int SYSTEM_ACTION_ID_ACCESSIBILITY_BUTTON_CHOOSER = 142 AccessibilityService.GLOBAL_ACTION_ACCESSIBILITY_BUTTON_CHOOSER; // 12 143 144 public static final int SYSTEM_ACTION_ID_ACCESSIBILITY_SHORTCUT = 145 AccessibilityService.GLOBAL_ACTION_ACCESSIBILITY_SHORTCUT; // 13 146 147 public static final int SYSTEM_ACTION_ID_ACCESSIBILITY_DISMISS_NOTIFICATION_SHADE = 148 AccessibilityService.GLOBAL_ACTION_DISMISS_NOTIFICATION_SHADE; // 15 149 150 /** 151 * Action ID to trigger the dpad up button 152 */ 153 private static final int SYSTEM_ACTION_ID_DPAD_UP = 154 AccessibilityService.GLOBAL_ACTION_DPAD_UP; // 16 155 156 /** 157 * Action ID to trigger the dpad down button 158 */ 159 private static final int SYSTEM_ACTION_ID_DPAD_DOWN = 160 AccessibilityService.GLOBAL_ACTION_DPAD_DOWN; // 17 161 162 /** 163 * Action ID to trigger the dpad left button 164 */ 165 private static final int SYSTEM_ACTION_ID_DPAD_LEFT = 166 AccessibilityService.GLOBAL_ACTION_DPAD_LEFT; // 18 167 168 /** 169 * Action ID to trigger the dpad right button 170 */ 171 private static final int SYSTEM_ACTION_ID_DPAD_RIGHT = 172 AccessibilityService.GLOBAL_ACTION_DPAD_RIGHT; // 19 173 174 /** 175 * Action ID to trigger dpad center keyevent 176 */ 177 private static final int SYSTEM_ACTION_ID_DPAD_CENTER = 178 AccessibilityService.GLOBAL_ACTION_DPAD_CENTER; // 20 179 180 private static final String PERMISSION_SELF = "com.android.systemui.permission.SELF"; 181 182 private final SystemActionsBroadcastReceiver mReceiver; 183 private final Context mContext; 184 private final UserTracker mUserTracker; 185 private final Optional<Recents> mRecentsOptional; 186 private final DisplayTracker mDisplayTracker; 187 private Locale mLocale; 188 private final AccessibilityManager mA11yManager; 189 private final Lazy<Optional<CentralSurfaces>> mCentralSurfacesOptionalLazy; 190 private final NotificationShadeWindowController mNotificationShadeController; 191 private final ShadeController mShadeController; 192 private final Lazy<ShadeViewController> mShadeViewController; 193 private final StatusBarWindowCallback mNotificationShadeCallback; 194 private boolean mDismissNotificationShadeActionRegistered; 195 196 @Inject SystemActions(Context context, UserTracker userTracker, NotificationShadeWindowController notificationShadeController, ShadeController shadeController, Lazy<ShadeViewController> shadeViewController, Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy, Optional<Recents> recentsOptional, DisplayTracker displayTracker)197 public SystemActions(Context context, 198 UserTracker userTracker, 199 NotificationShadeWindowController notificationShadeController, 200 ShadeController shadeController, 201 Lazy<ShadeViewController> shadeViewController, 202 Lazy<Optional<CentralSurfaces>> centralSurfacesOptionalLazy, 203 Optional<Recents> recentsOptional, 204 DisplayTracker displayTracker) { 205 mContext = context; 206 mUserTracker = userTracker; 207 mShadeController = shadeController; 208 mShadeViewController = shadeViewController; 209 mRecentsOptional = recentsOptional; 210 mDisplayTracker = displayTracker; 211 mReceiver = new SystemActionsBroadcastReceiver(); 212 mLocale = mContext.getResources().getConfiguration().getLocales().get(0); 213 mA11yManager = (AccessibilityManager) mContext.getSystemService( 214 Context.ACCESSIBILITY_SERVICE); 215 mNotificationShadeController = notificationShadeController; 216 // Saving in instance variable since to prevent GC since 217 // NotificationShadeWindowController.registerCallback() only keeps weak references. 218 mNotificationShadeCallback = 219 (keyguardShowing, keyguardOccluded, keyguardGoingAway, bouncerShowing, mDozing, 220 panelExpanded, isDreaming) -> 221 registerOrUnregisterDismissNotificationShadeAction(); 222 mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy; 223 } 224 225 @Override start()226 public void start() { 227 mNotificationShadeController.registerCallback(mNotificationShadeCallback); 228 mContext.registerReceiverForAllUsers( 229 mReceiver, 230 mReceiver.createIntentFilter(), 231 PERMISSION_SELF, 232 null, 233 Context.RECEIVER_EXPORTED); 234 registerActions(); 235 } 236 237 @Override onConfigurationChanged(Configuration newConfig)238 public void onConfigurationChanged(Configuration newConfig) { 239 final Locale locale = mContext.getResources().getConfiguration().getLocales().get(0); 240 if (!locale.equals(mLocale)) { 241 mLocale = locale; 242 registerActions(); 243 } 244 } 245 registerActions()246 private void registerActions() { 247 RemoteAction actionBack = createRemoteAction( 248 R.string.accessibility_system_action_back_label, 249 SystemActionsBroadcastReceiver.INTENT_ACTION_BACK); 250 251 RemoteAction actionHome = createRemoteAction( 252 R.string.accessibility_system_action_home_label, 253 SystemActionsBroadcastReceiver.INTENT_ACTION_HOME); 254 255 RemoteAction actionRecents = createRemoteAction( 256 R.string.accessibility_system_action_recents_label, 257 SystemActionsBroadcastReceiver.INTENT_ACTION_RECENTS); 258 259 RemoteAction actionNotifications = createRemoteAction( 260 R.string.accessibility_system_action_notifications_label, 261 SystemActionsBroadcastReceiver.INTENT_ACTION_NOTIFICATIONS); 262 263 RemoteAction actionQuickSettings = createRemoteAction( 264 R.string.accessibility_system_action_quick_settings_label, 265 SystemActionsBroadcastReceiver.INTENT_ACTION_QUICK_SETTINGS); 266 267 RemoteAction actionPowerDialog = createRemoteAction( 268 R.string.accessibility_system_action_power_dialog_label, 269 SystemActionsBroadcastReceiver.INTENT_ACTION_POWER_DIALOG); 270 271 RemoteAction actionLockScreen = createRemoteAction( 272 R.string.accessibility_system_action_lock_screen_label, 273 SystemActionsBroadcastReceiver.INTENT_ACTION_LOCK_SCREEN); 274 275 RemoteAction actionTakeScreenshot = createRemoteAction( 276 R.string.accessibility_system_action_screenshot_label, 277 SystemActionsBroadcastReceiver.INTENT_ACTION_TAKE_SCREENSHOT); 278 279 RemoteAction actionHeadsetHook = createRemoteAction( 280 R.string.accessibility_system_action_headset_hook_label, 281 SystemActionsBroadcastReceiver.INTENT_ACTION_HEADSET_HOOK); 282 283 RemoteAction actionAccessibilityShortcut = createRemoteAction( 284 R.string.accessibility_system_action_hardware_a11y_shortcut_label, 285 SystemActionsBroadcastReceiver.INTENT_ACTION_ACCESSIBILITY_SHORTCUT); 286 287 RemoteAction actionDpadUp = createRemoteAction( 288 R.string.accessibility_system_action_dpad_up_label, 289 SystemActionsBroadcastReceiver.INTENT_ACTION_DPAD_UP); 290 291 RemoteAction actionDpadDown = createRemoteAction( 292 R.string.accessibility_system_action_dpad_down_label, 293 SystemActionsBroadcastReceiver.INTENT_ACTION_DPAD_DOWN); 294 295 RemoteAction actionDpadLeft = createRemoteAction( 296 R.string.accessibility_system_action_dpad_left_label, 297 SystemActionsBroadcastReceiver.INTENT_ACTION_DPAD_LEFT); 298 299 RemoteAction actionDpadRight = createRemoteAction( 300 R.string.accessibility_system_action_dpad_right_label, 301 SystemActionsBroadcastReceiver.INTENT_ACTION_DPAD_RIGHT); 302 303 RemoteAction actionDpadCenter = createRemoteAction( 304 R.string.accessibility_system_action_dpad_center_label, 305 SystemActionsBroadcastReceiver.INTENT_ACTION_DPAD_CENTER); 306 307 mA11yManager.registerSystemAction(actionBack, SYSTEM_ACTION_ID_BACK); 308 mA11yManager.registerSystemAction(actionHome, SYSTEM_ACTION_ID_HOME); 309 mA11yManager.registerSystemAction(actionRecents, SYSTEM_ACTION_ID_RECENTS); 310 if (mCentralSurfacesOptionalLazy.get().isPresent()) { 311 // These two actions require the CentralSurfaces instance. 312 mA11yManager.registerSystemAction(actionNotifications, SYSTEM_ACTION_ID_NOTIFICATIONS); 313 mA11yManager.registerSystemAction(actionQuickSettings, SYSTEM_ACTION_ID_QUICK_SETTINGS); 314 } 315 mA11yManager.registerSystemAction(actionPowerDialog, SYSTEM_ACTION_ID_POWER_DIALOG); 316 mA11yManager.registerSystemAction(actionLockScreen, SYSTEM_ACTION_ID_LOCK_SCREEN); 317 mA11yManager.registerSystemAction(actionTakeScreenshot, SYSTEM_ACTION_ID_TAKE_SCREENSHOT); 318 mA11yManager.registerSystemAction(actionHeadsetHook, SYSTEM_ACTION_ID_KEYCODE_HEADSETHOOK); 319 mA11yManager.registerSystemAction( 320 actionAccessibilityShortcut, SYSTEM_ACTION_ID_ACCESSIBILITY_SHORTCUT); 321 mA11yManager.registerSystemAction(actionDpadUp, SYSTEM_ACTION_ID_DPAD_UP); 322 mA11yManager.registerSystemAction(actionDpadDown, SYSTEM_ACTION_ID_DPAD_DOWN); 323 mA11yManager.registerSystemAction(actionDpadLeft, SYSTEM_ACTION_ID_DPAD_LEFT); 324 mA11yManager.registerSystemAction(actionDpadRight, SYSTEM_ACTION_ID_DPAD_RIGHT); 325 mA11yManager.registerSystemAction(actionDpadCenter, SYSTEM_ACTION_ID_DPAD_CENTER); 326 registerOrUnregisterDismissNotificationShadeAction(); 327 } 328 registerOrUnregisterDismissNotificationShadeAction()329 private void registerOrUnregisterDismissNotificationShadeAction() { 330 Assert.isMainThread(); 331 332 // Saving state in instance variable since this callback is called quite often to avoid 333 // binder calls 334 final Optional<CentralSurfaces> centralSurfacesOptional = 335 mCentralSurfacesOptionalLazy.get(); 336 if (centralSurfacesOptional.isPresent() 337 && mShadeViewController.get().isPanelExpanded() 338 && !centralSurfacesOptional.get().isKeyguardShowing()) { 339 if (!mDismissNotificationShadeActionRegistered) { 340 mA11yManager.registerSystemAction( 341 createRemoteAction( 342 R.string.accessibility_system_action_dismiss_notification_shade, 343 SystemActionsBroadcastReceiver 344 .INTENT_ACTION_ACCESSIBILITY_DISMISS_NOTIFICATION_SHADE), 345 SYSTEM_ACTION_ID_ACCESSIBILITY_DISMISS_NOTIFICATION_SHADE); 346 mDismissNotificationShadeActionRegistered = true; 347 } 348 } else { 349 if (mDismissNotificationShadeActionRegistered) { 350 mA11yManager.unregisterSystemAction( 351 SYSTEM_ACTION_ID_ACCESSIBILITY_DISMISS_NOTIFICATION_SHADE); 352 mDismissNotificationShadeActionRegistered = false; 353 } 354 } 355 } 356 357 /** 358 * Register a system action. 359 * 360 * @param actionId the action ID to register. 361 */ register(int actionId)362 public void register(int actionId) { 363 int labelId; 364 String intent; 365 switch (actionId) { 366 case SYSTEM_ACTION_ID_BACK: 367 labelId = R.string.accessibility_system_action_back_label; 368 intent = SystemActionsBroadcastReceiver.INTENT_ACTION_BACK; 369 break; 370 case SYSTEM_ACTION_ID_HOME: 371 labelId = R.string.accessibility_system_action_home_label; 372 intent = SystemActionsBroadcastReceiver.INTENT_ACTION_HOME; 373 break; 374 case SYSTEM_ACTION_ID_RECENTS: 375 labelId = R.string.accessibility_system_action_recents_label; 376 intent = SystemActionsBroadcastReceiver.INTENT_ACTION_RECENTS; 377 break; 378 case SYSTEM_ACTION_ID_NOTIFICATIONS: 379 labelId = R.string.accessibility_system_action_notifications_label; 380 intent = SystemActionsBroadcastReceiver.INTENT_ACTION_NOTIFICATIONS; 381 break; 382 case SYSTEM_ACTION_ID_QUICK_SETTINGS: 383 labelId = R.string.accessibility_system_action_quick_settings_label; 384 intent = SystemActionsBroadcastReceiver.INTENT_ACTION_QUICK_SETTINGS; 385 break; 386 case SYSTEM_ACTION_ID_POWER_DIALOG: 387 labelId = R.string.accessibility_system_action_power_dialog_label; 388 intent = SystemActionsBroadcastReceiver.INTENT_ACTION_POWER_DIALOG; 389 break; 390 case SYSTEM_ACTION_ID_LOCK_SCREEN: 391 labelId = R.string.accessibility_system_action_lock_screen_label; 392 intent = SystemActionsBroadcastReceiver.INTENT_ACTION_LOCK_SCREEN; 393 break; 394 case SYSTEM_ACTION_ID_TAKE_SCREENSHOT: 395 labelId = R.string.accessibility_system_action_screenshot_label; 396 intent = SystemActionsBroadcastReceiver.INTENT_ACTION_TAKE_SCREENSHOT; 397 break; 398 case SYSTEM_ACTION_ID_KEYCODE_HEADSETHOOK: 399 labelId = R.string.accessibility_system_action_headset_hook_label; 400 intent = SystemActionsBroadcastReceiver.INTENT_ACTION_HEADSET_HOOK; 401 break; 402 case SYSTEM_ACTION_ID_ACCESSIBILITY_BUTTON: 403 labelId = R.string.accessibility_system_action_on_screen_a11y_shortcut_label; 404 intent = SystemActionsBroadcastReceiver.INTENT_ACTION_ACCESSIBILITY_BUTTON; 405 break; 406 case SYSTEM_ACTION_ID_ACCESSIBILITY_BUTTON_CHOOSER: 407 labelId = 408 R.string.accessibility_system_action_on_screen_a11y_shortcut_chooser_label; 409 intent = SystemActionsBroadcastReceiver.INTENT_ACTION_ACCESSIBILITY_BUTTON_CHOOSER; 410 break; 411 case SYSTEM_ACTION_ID_ACCESSIBILITY_SHORTCUT: 412 labelId = R.string.accessibility_system_action_hardware_a11y_shortcut_label; 413 intent = SystemActionsBroadcastReceiver.INTENT_ACTION_ACCESSIBILITY_SHORTCUT; 414 break; 415 case SYSTEM_ACTION_ID_ACCESSIBILITY_DISMISS_NOTIFICATION_SHADE: 416 labelId = R.string.accessibility_system_action_dismiss_notification_shade; 417 intent = SystemActionsBroadcastReceiver 418 .INTENT_ACTION_ACCESSIBILITY_DISMISS_NOTIFICATION_SHADE; 419 break; 420 case SYSTEM_ACTION_ID_DPAD_UP: 421 labelId = R.string.accessibility_system_action_dpad_up_label; 422 intent = SystemActionsBroadcastReceiver.INTENT_ACTION_DPAD_UP; 423 break; 424 case SYSTEM_ACTION_ID_DPAD_DOWN: 425 labelId = R.string.accessibility_system_action_dpad_down_label; 426 intent = SystemActionsBroadcastReceiver.INTENT_ACTION_DPAD_DOWN; 427 break; 428 case SYSTEM_ACTION_ID_DPAD_LEFT: 429 labelId = R.string.accessibility_system_action_dpad_left_label; 430 intent = SystemActionsBroadcastReceiver.INTENT_ACTION_DPAD_LEFT; 431 break; 432 case SYSTEM_ACTION_ID_DPAD_RIGHT: 433 labelId = R.string.accessibility_system_action_dpad_right_label; 434 intent = SystemActionsBroadcastReceiver.INTENT_ACTION_DPAD_RIGHT; 435 break; 436 case SYSTEM_ACTION_ID_DPAD_CENTER: 437 labelId = R.string.accessibility_system_action_dpad_center_label; 438 intent = SystemActionsBroadcastReceiver.INTENT_ACTION_DPAD_CENTER; 439 break; 440 default: 441 return; 442 } 443 mA11yManager.registerSystemAction(createRemoteAction(labelId, intent), actionId); 444 } 445 createRemoteAction(int labelId, String intent)446 private RemoteAction createRemoteAction(int labelId, String intent) { 447 // TODO(b/148087487): update the icon used below to a valid one 448 return new RemoteAction( 449 Icon.createWithResource(mContext, R.drawable.ic_info), 450 mContext.getString(labelId), 451 mContext.getString(labelId), 452 mReceiver.createPendingIntent(mContext, intent)); 453 } 454 455 /** 456 * Unregister a system action. 457 * 458 * @param actionId the action ID to unregister. 459 */ unregister(int actionId)460 public void unregister(int actionId) { 461 mA11yManager.unregisterSystemAction(actionId); 462 } 463 handleBack()464 private void handleBack() { 465 sendDownAndUpKeyEvents(KeyEvent.KEYCODE_BACK); 466 } 467 handleHome()468 private void handleHome() { 469 sendDownAndUpKeyEvents(KeyEvent.KEYCODE_HOME); 470 } 471 sendDownAndUpKeyEvents(int keyCode)472 private void sendDownAndUpKeyEvents(int keyCode) { 473 final long downTime = SystemClock.uptimeMillis(); 474 sendKeyEventIdentityCleared(keyCode, KeyEvent.ACTION_DOWN, downTime, downTime); 475 sendKeyEventIdentityCleared( 476 keyCode, KeyEvent.ACTION_UP, downTime, SystemClock.uptimeMillis()); 477 } 478 sendKeyEventIdentityCleared(int keyCode, int action, long downTime, long time)479 private void sendKeyEventIdentityCleared(int keyCode, int action, long downTime, long time) { 480 KeyEvent event = KeyEvent.obtain(downTime, time, action, keyCode, 0, 0, 481 KeyCharacterMap.VIRTUAL_KEYBOARD, 0, KeyEvent.FLAG_FROM_SYSTEM, 482 InputDevice.SOURCE_KEYBOARD, null); 483 mContext.getSystemService(InputManager.class) 484 .injectInputEvent(event, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC); 485 event.recycle(); 486 } 487 handleRecents()488 private void handleRecents() { 489 mRecentsOptional.ifPresent(Recents::toggleRecentApps); 490 } 491 handleNotifications()492 private void handleNotifications() { 493 mShadeController.animateExpandShade(); 494 } 495 handleQuickSettings()496 private void handleQuickSettings() { 497 mShadeController.animateExpandQs(); 498 } 499 handlePowerDialog()500 private void handlePowerDialog() { 501 IWindowManager windowManager = WindowManagerGlobal.getWindowManagerService(); 502 503 try { 504 windowManager.showGlobalActions(); 505 } catch (RemoteException e) { 506 Log.e(TAG, "failed to display power dialog."); 507 } 508 } 509 handleLockScreen()510 private void handleLockScreen() { 511 IWindowManager windowManager = WindowManagerGlobal.getWindowManagerService(); 512 513 mContext.getSystemService(PowerManager.class).goToSleep(SystemClock.uptimeMillis(), 514 PowerManager.GO_TO_SLEEP_REASON_ACCESSIBILITY, 0); 515 try { 516 windowManager.lockNow(null); 517 } catch (RemoteException e) { 518 Log.e(TAG, "failed to lock screen."); 519 } 520 } 521 handleTakeScreenshot()522 private void handleTakeScreenshot() { 523 ScreenshotHelper screenshotHelper = new ScreenshotHelper(mContext); 524 screenshotHelper.takeScreenshot( 525 SCREENSHOT_ACCESSIBILITY_ACTIONS, new Handler(Looper.getMainLooper()), null); 526 } 527 528 @VisibleForTesting handleHeadsetHook()529 void handleHeadsetHook() { 530 if (!AccessibilityUtils.interceptHeadsetHookForActiveCall(mContext)) { 531 sendDownAndUpKeyEvents(KeyEvent.KEYCODE_HEADSETHOOK); 532 } 533 } 534 handleAccessibilityButton()535 private void handleAccessibilityButton() { 536 AccessibilityManager.getInstance(mContext).notifyAccessibilityButtonClicked( 537 mDisplayTracker.getDefaultDisplayId()); 538 } 539 handleAccessibilityButtonChooser()540 private void handleAccessibilityButtonChooser() { 541 final Intent intent = new Intent(AccessibilityManager.ACTION_CHOOSE_ACCESSIBILITY_BUTTON); 542 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); 543 final String chooserClassName = AccessibilityButtonChooserActivity.class.getName(); 544 intent.setClassName(CHOOSER_PACKAGE_NAME, chooserClassName); 545 mContext.startActivityAsUser(intent, mUserTracker.getUserHandle()); 546 } 547 handleAccessibilityShortcut()548 private void handleAccessibilityShortcut() { 549 mA11yManager.performAccessibilityShortcut(); 550 } 551 handleAccessibilityDismissNotificationShade()552 private void handleAccessibilityDismissNotificationShade() { 553 mShadeController.animateCollapseShade(CommandQueue.FLAG_EXCLUDE_NONE); 554 } 555 handleDpadUp()556 private void handleDpadUp() { 557 sendDownAndUpKeyEvents(KeyEvent.KEYCODE_DPAD_UP); 558 } 559 handleDpadDown()560 private void handleDpadDown() { 561 sendDownAndUpKeyEvents(KeyEvent.KEYCODE_DPAD_DOWN); 562 } 563 handleDpadLeft()564 private void handleDpadLeft() { 565 sendDownAndUpKeyEvents(KeyEvent.KEYCODE_DPAD_LEFT); 566 } 567 handleDpadRight()568 private void handleDpadRight() { 569 sendDownAndUpKeyEvents(KeyEvent.KEYCODE_DPAD_RIGHT); 570 } 571 handleDpadCenter()572 private void handleDpadCenter() { 573 sendDownAndUpKeyEvents(KeyEvent.KEYCODE_DPAD_CENTER); 574 } 575 576 private class SystemActionsBroadcastReceiver extends BroadcastReceiver { 577 private static final String INTENT_ACTION_BACK = "SYSTEM_ACTION_BACK"; 578 private static final String INTENT_ACTION_HOME = "SYSTEM_ACTION_HOME"; 579 private static final String INTENT_ACTION_RECENTS = "SYSTEM_ACTION_RECENTS"; 580 private static final String INTENT_ACTION_NOTIFICATIONS = "SYSTEM_ACTION_NOTIFICATIONS"; 581 private static final String INTENT_ACTION_QUICK_SETTINGS = "SYSTEM_ACTION_QUICK_SETTINGS"; 582 private static final String INTENT_ACTION_POWER_DIALOG = "SYSTEM_ACTION_POWER_DIALOG"; 583 private static final String INTENT_ACTION_LOCK_SCREEN = "SYSTEM_ACTION_LOCK_SCREEN"; 584 private static final String INTENT_ACTION_TAKE_SCREENSHOT = "SYSTEM_ACTION_TAKE_SCREENSHOT"; 585 private static final String INTENT_ACTION_HEADSET_HOOK = "SYSTEM_ACTION_HEADSET_HOOK"; 586 private static final String INTENT_ACTION_ACCESSIBILITY_BUTTON = 587 "SYSTEM_ACTION_ACCESSIBILITY_BUTTON"; 588 private static final String INTENT_ACTION_ACCESSIBILITY_BUTTON_CHOOSER = 589 "SYSTEM_ACTION_ACCESSIBILITY_BUTTON_MENU"; 590 private static final String INTENT_ACTION_ACCESSIBILITY_SHORTCUT = 591 "SYSTEM_ACTION_ACCESSIBILITY_SHORTCUT"; 592 private static final String INTENT_ACTION_ACCESSIBILITY_DISMISS_NOTIFICATION_SHADE = 593 "SYSTEM_ACTION_ACCESSIBILITY_DISMISS_NOTIFICATION_SHADE"; 594 private static final String INTENT_ACTION_DPAD_UP = "SYSTEM_ACTION_DPAD_UP"; 595 private static final String INTENT_ACTION_DPAD_DOWN = "SYSTEM_ACTION_DPAD_DOWN"; 596 private static final String INTENT_ACTION_DPAD_LEFT = "SYSTEM_ACTION_DPAD_LEFT"; 597 private static final String INTENT_ACTION_DPAD_RIGHT = "SYSTEM_ACTION_DPAD_RIGHT"; 598 private static final String INTENT_ACTION_DPAD_CENTER = "SYSTEM_ACTION_DPAD_CENTER"; 599 createPendingIntent(Context context, String intentAction)600 private PendingIntent createPendingIntent(Context context, String intentAction) { 601 switch (intentAction) { 602 case INTENT_ACTION_BACK: 603 case INTENT_ACTION_HOME: 604 case INTENT_ACTION_RECENTS: 605 case INTENT_ACTION_NOTIFICATIONS: 606 case INTENT_ACTION_QUICK_SETTINGS: 607 case INTENT_ACTION_POWER_DIALOG: 608 case INTENT_ACTION_LOCK_SCREEN: 609 case INTENT_ACTION_TAKE_SCREENSHOT: 610 case INTENT_ACTION_HEADSET_HOOK: 611 case INTENT_ACTION_ACCESSIBILITY_BUTTON: 612 case INTENT_ACTION_ACCESSIBILITY_BUTTON_CHOOSER: 613 case INTENT_ACTION_ACCESSIBILITY_SHORTCUT: 614 case INTENT_ACTION_ACCESSIBILITY_DISMISS_NOTIFICATION_SHADE: 615 case INTENT_ACTION_DPAD_UP: 616 case INTENT_ACTION_DPAD_DOWN: 617 case INTENT_ACTION_DPAD_LEFT: 618 case INTENT_ACTION_DPAD_RIGHT: 619 case INTENT_ACTION_DPAD_CENTER: { 620 Intent intent = new Intent(intentAction); 621 intent.setPackage(context.getPackageName()); 622 intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); 623 return PendingIntent.getBroadcast(context, 0, intent, 624 PendingIntent.FLAG_IMMUTABLE); 625 } 626 default: 627 break; 628 } 629 return null; 630 } 631 createIntentFilter()632 private IntentFilter createIntentFilter() { 633 IntentFilter intentFilter = new IntentFilter(); 634 intentFilter.addAction(INTENT_ACTION_BACK); 635 intentFilter.addAction(INTENT_ACTION_HOME); 636 intentFilter.addAction(INTENT_ACTION_RECENTS); 637 intentFilter.addAction(INTENT_ACTION_NOTIFICATIONS); 638 intentFilter.addAction(INTENT_ACTION_QUICK_SETTINGS); 639 intentFilter.addAction(INTENT_ACTION_POWER_DIALOG); 640 intentFilter.addAction(INTENT_ACTION_LOCK_SCREEN); 641 intentFilter.addAction(INTENT_ACTION_TAKE_SCREENSHOT); 642 intentFilter.addAction(INTENT_ACTION_HEADSET_HOOK); 643 intentFilter.addAction(INTENT_ACTION_ACCESSIBILITY_BUTTON); 644 intentFilter.addAction(INTENT_ACTION_ACCESSIBILITY_BUTTON_CHOOSER); 645 intentFilter.addAction(INTENT_ACTION_ACCESSIBILITY_SHORTCUT); 646 intentFilter.addAction(INTENT_ACTION_ACCESSIBILITY_DISMISS_NOTIFICATION_SHADE); 647 intentFilter.addAction(INTENT_ACTION_DPAD_UP); 648 intentFilter.addAction(INTENT_ACTION_DPAD_DOWN); 649 intentFilter.addAction(INTENT_ACTION_DPAD_LEFT); 650 intentFilter.addAction(INTENT_ACTION_DPAD_RIGHT); 651 intentFilter.addAction(INTENT_ACTION_DPAD_CENTER); 652 return intentFilter; 653 } 654 655 @Override onReceive(Context context, Intent intent)656 public void onReceive(Context context, Intent intent) { 657 String intentAction = intent.getAction(); 658 switch (intentAction) { 659 case INTENT_ACTION_BACK: { 660 handleBack(); 661 break; 662 } 663 case INTENT_ACTION_HOME: { 664 handleHome(); 665 break; 666 } 667 case INTENT_ACTION_RECENTS: { 668 handleRecents(); 669 break; 670 } 671 case INTENT_ACTION_NOTIFICATIONS: { 672 handleNotifications(); 673 break; 674 } 675 case INTENT_ACTION_QUICK_SETTINGS: { 676 handleQuickSettings(); 677 break; 678 } 679 case INTENT_ACTION_POWER_DIALOG: { 680 handlePowerDialog(); 681 break; 682 } 683 case INTENT_ACTION_LOCK_SCREEN: { 684 handleLockScreen(); 685 break; 686 } 687 case INTENT_ACTION_TAKE_SCREENSHOT: { 688 handleTakeScreenshot(); 689 break; 690 } 691 case INTENT_ACTION_HEADSET_HOOK: { 692 handleHeadsetHook(); 693 break; 694 } 695 case INTENT_ACTION_ACCESSIBILITY_BUTTON: { 696 handleAccessibilityButton(); 697 break; 698 } 699 case INTENT_ACTION_ACCESSIBILITY_BUTTON_CHOOSER: { 700 handleAccessibilityButtonChooser(); 701 break; 702 } 703 case INTENT_ACTION_ACCESSIBILITY_SHORTCUT: { 704 handleAccessibilityShortcut(); 705 break; 706 } 707 case INTENT_ACTION_ACCESSIBILITY_DISMISS_NOTIFICATION_SHADE: { 708 handleAccessibilityDismissNotificationShade(); 709 break; 710 } 711 case INTENT_ACTION_DPAD_UP: { 712 handleDpadUp(); 713 break; 714 } 715 case INTENT_ACTION_DPAD_DOWN: { 716 handleDpadDown(); 717 break; 718 } 719 case INTENT_ACTION_DPAD_LEFT: { 720 handleDpadLeft(); 721 break; 722 } 723 case INTENT_ACTION_DPAD_RIGHT: { 724 handleDpadRight(); 725 break; 726 } 727 case INTENT_ACTION_DPAD_CENTER: { 728 handleDpadCenter(); 729 break; 730 } 731 default: 732 break; 733 } 734 } 735 } 736 } 737