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