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