1 /* 2 * Copyright (C) 2021 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.statusbar.phone; 18 19 import static android.service.quickaccesswallet.Flags.launchWalletOptionOnPowerDoubleTap; 20 import static android.service.quickaccesswallet.Flags.launchWalletViaSysuiCallbacks; 21 22 import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE; 23 import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_WAKING; 24 25 import android.annotation.Nullable; 26 import android.app.StatusBarManager; 27 import android.content.ComponentName; 28 import android.content.Context; 29 import android.content.Intent; 30 import android.content.res.Resources; 31 import android.os.Bundle; 32 import android.os.PowerManager; 33 import android.os.SystemClock; 34 import android.os.VibrationAttributes; 35 import android.os.VibrationEffect; 36 import android.os.Vibrator; 37 import android.util.Log; 38 import android.util.Slog; 39 import android.view.HapticFeedbackConstants; 40 import android.view.KeyEvent; 41 42 import androidx.annotation.VisibleForTesting; 43 44 import com.android.internal.logging.MetricsLogger; 45 import com.android.internal.logging.nano.MetricsProto.MetricsEvent; 46 import com.android.keyguard.KeyguardUpdateMonitor; 47 import com.android.systemui.assist.AssistManager; 48 import com.android.systemui.camera.CameraIntents; 49 import com.android.systemui.dagger.SysUISingleton; 50 import com.android.systemui.dagger.qualifiers.DisplayId; 51 import com.android.systemui.dagger.qualifiers.Main; 52 import com.android.systemui.emergency.EmergencyGesture; 53 import com.android.systemui.emergency.EmergencyGestureModule.EmergencyGestureIntentFactory; 54 import com.android.systemui.keyguard.WakefulnessLifecycle; 55 import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor; 56 import com.android.systemui.plugins.ActivityStarter; 57 import com.android.systemui.qs.QSHost; 58 import com.android.systemui.qs.QSPanelController; 59 import com.android.systemui.qs.flags.QsInCompose; 60 import com.android.systemui.recents.ScreenPinningRequest; 61 import com.android.systemui.res.R; 62 import com.android.systemui.scene.shared.flag.SceneContainerFlag; 63 import com.android.systemui.settings.UserTracker; 64 import com.android.systemui.shade.CameraLauncher; 65 import com.android.systemui.shade.QuickSettingsController; 66 import com.android.systemui.shade.ShadeController; 67 import com.android.systemui.shade.ShadeHeaderController; 68 import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor; 69 import com.android.systemui.shade.domain.interactor.ShadeInteractor; 70 import com.android.systemui.statusbar.CommandQueue; 71 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController; 72 import com.android.systemui.statusbar.policy.DeviceProvisionedController; 73 import com.android.systemui.statusbar.notification.headsup.HeadsUpManager; 74 import com.android.systemui.statusbar.policy.KeyguardStateController; 75 import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler; 76 import com.android.systemui.wallet.controller.QuickAccessWalletController; 77 78 import dagger.Lazy; 79 80 import java.util.Arrays; 81 import java.util.Optional; 82 83 import javax.inject.Inject; 84 85 /** */ 86 @SysUISingleton 87 public class CentralSurfacesCommandQueueCallbacks implements CommandQueue.Callbacks { 88 private final CentralSurfaces mCentralSurfaces; 89 private final Context mContext; 90 private final ScreenPinningRequest mScreenPinningRequest; 91 private final com.android.systemui.shade.ShadeController mShadeController; 92 private final CommandQueue mCommandQueue; 93 private final PanelExpansionInteractor mPanelExpansionInteractor; 94 private final Lazy<ShadeInteractor> mShadeInteractorLazy; 95 private final ShadeHeaderController mShadeHeaderController; 96 private final RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler; 97 private final MetricsLogger mMetricsLogger; 98 private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; 99 private final KeyguardStateController mKeyguardStateController; 100 private final HeadsUpManager mHeadsUpManager; 101 private final WakefulnessLifecycle mWakefulnessLifecycle; 102 private final DeviceProvisionedController mDeviceProvisionedController; 103 private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; 104 private final AssistManager mAssistManager; 105 private final DozeServiceHost mDozeServiceHost; 106 private final NotificationStackScrollLayoutController mNotificationStackScrollLayoutController; 107 private final StatusBarHideIconsForBouncerManager mStatusBarHideIconsForBouncerManager; 108 private final PowerManager mPowerManager; 109 private final Optional<Vibrator> mVibratorOptional; 110 private final int mDisplayId; 111 private final UserTracker mUserTracker; 112 private final boolean mVibrateOnOpening; 113 private final VibrationEffect mCameraLaunchGestureVibrationEffect; 114 private final ActivityStarter mActivityStarter; 115 private final Lazy<CameraLauncher> mCameraLauncherLazy; 116 private final QuickSettingsController mQsController; 117 private final QSHost mQSHost; 118 private final KeyguardInteractor mKeyguardInteractor; 119 private static final VibrationAttributes HARDWARE_FEEDBACK_VIBRATION_ATTRIBUTES = 120 VibrationAttributes.createForUsage(VibrationAttributes.USAGE_HARDWARE_FEEDBACK); 121 122 private int mDisabled1; 123 private int mDisabled2; 124 125 private final EmergencyGestureIntentFactory mEmergencyGestureIntentFactory; 126 private QuickAccessWalletController mWalletController; 127 128 enum PowerButtonLaunchGestureTarget { 129 LAUNCH_CAMERA_ON_GESTURE, LAUNCH_WALLET_ON_GESTURE 130 } 131 132 @Inject CentralSurfacesCommandQueueCallbacks( CentralSurfaces centralSurfaces, QuickSettingsController quickSettingsController, Context context, @Main Resources resources, ScreenPinningRequest screenPinningRequest, ShadeController shadeController, CommandQueue commandQueue, PanelExpansionInteractor panelExpansionInteractor, Lazy<ShadeInteractor> shadeInteractorLazy, ShadeHeaderController shadeHeaderController, RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler, MetricsLogger metricsLogger, KeyguardUpdateMonitor keyguardUpdateMonitor, KeyguardStateController keyguardStateController, HeadsUpManager headsUpManager, WakefulnessLifecycle wakefulnessLifecycle, DeviceProvisionedController deviceProvisionedController, StatusBarKeyguardViewManager statusBarKeyguardViewManager, AssistManager assistManager, DozeServiceHost dozeServiceHost, NotificationStackScrollLayoutController notificationStackScrollLayoutController, StatusBarHideIconsForBouncerManager statusBarHideIconsForBouncerManager, PowerManager powerManager, Optional<Vibrator> vibratorOptional, @DisplayId int displayId, Lazy<CameraLauncher> cameraLauncherLazy, UserTracker userTracker, QSHost qsHost, ActivityStarter activityStarter, KeyguardInteractor keyguardInteractor, EmergencyGestureIntentFactory emergencyGestureIntentFactory, QuickAccessWalletController walletController)133 CentralSurfacesCommandQueueCallbacks( 134 CentralSurfaces centralSurfaces, 135 QuickSettingsController quickSettingsController, 136 Context context, 137 @Main Resources resources, 138 ScreenPinningRequest screenPinningRequest, 139 ShadeController shadeController, 140 CommandQueue commandQueue, 141 PanelExpansionInteractor panelExpansionInteractor, 142 Lazy<ShadeInteractor> shadeInteractorLazy, 143 ShadeHeaderController shadeHeaderController, 144 RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler, 145 MetricsLogger metricsLogger, 146 KeyguardUpdateMonitor keyguardUpdateMonitor, 147 KeyguardStateController keyguardStateController, 148 HeadsUpManager headsUpManager, 149 WakefulnessLifecycle wakefulnessLifecycle, 150 DeviceProvisionedController deviceProvisionedController, 151 StatusBarKeyguardViewManager statusBarKeyguardViewManager, 152 AssistManager assistManager, 153 DozeServiceHost dozeServiceHost, 154 NotificationStackScrollLayoutController notificationStackScrollLayoutController, 155 StatusBarHideIconsForBouncerManager statusBarHideIconsForBouncerManager, 156 PowerManager powerManager, 157 Optional<Vibrator> vibratorOptional, 158 @DisplayId int displayId, 159 Lazy<CameraLauncher> cameraLauncherLazy, 160 UserTracker userTracker, 161 QSHost qsHost, 162 ActivityStarter activityStarter, 163 KeyguardInteractor keyguardInteractor, 164 EmergencyGestureIntentFactory emergencyGestureIntentFactory, 165 QuickAccessWalletController walletController) { 166 mCentralSurfaces = centralSurfaces; 167 mQsController = quickSettingsController; 168 mContext = context; 169 mScreenPinningRequest = screenPinningRequest; 170 mShadeController = shadeController; 171 mCommandQueue = commandQueue; 172 mPanelExpansionInteractor = panelExpansionInteractor; 173 mShadeInteractorLazy = shadeInteractorLazy; 174 mShadeHeaderController = shadeHeaderController; 175 mRemoteInputQuickSettingsDisabler = remoteInputQuickSettingsDisabler; 176 mMetricsLogger = metricsLogger; 177 mKeyguardUpdateMonitor = keyguardUpdateMonitor; 178 mKeyguardStateController = keyguardStateController; 179 mHeadsUpManager = headsUpManager; 180 mWakefulnessLifecycle = wakefulnessLifecycle; 181 mDeviceProvisionedController = deviceProvisionedController; 182 mStatusBarKeyguardViewManager = statusBarKeyguardViewManager; 183 mAssistManager = assistManager; 184 mDozeServiceHost = dozeServiceHost; 185 mNotificationStackScrollLayoutController = notificationStackScrollLayoutController; 186 mStatusBarHideIconsForBouncerManager = statusBarHideIconsForBouncerManager; 187 mPowerManager = powerManager; 188 mVibratorOptional = vibratorOptional; 189 mDisplayId = displayId; 190 mCameraLauncherLazy = cameraLauncherLazy; 191 mUserTracker = userTracker; 192 mQSHost = qsHost; 193 mKeyguardInteractor = keyguardInteractor; 194 mVibrateOnOpening = resources.getBoolean(R.bool.config_vibrateOnIconAnimation); 195 mCameraLaunchGestureVibrationEffect = getCameraGestureVibrationEffect( 196 mVibratorOptional, resources); 197 mActivityStarter = activityStarter; 198 mEmergencyGestureIntentFactory = emergencyGestureIntentFactory; 199 mWalletController = walletController; 200 } 201 202 @Override addQsTile(ComponentName tile)203 public void addQsTile(ComponentName tile) { 204 mQSHost.addTile(tile); 205 } 206 207 @Override addQsTileToFrontOrEnd(ComponentName tile, boolean end)208 public void addQsTileToFrontOrEnd(ComponentName tile, boolean end) { 209 mQSHost.addTile(tile, end); 210 } 211 212 @Override remQsTile(ComponentName tile)213 public void remQsTile(ComponentName tile) { 214 mQSHost.removeTileByUser(tile); 215 } 216 217 @Override setQsTiles(String[] tiles)218 public void setQsTiles(String[] tiles) { 219 mQSHost.changeTilesByUser(mQSHost.getSpecs(), Arrays.stream(tiles).toList()); 220 } 221 222 @Override clickTile(ComponentName tile)223 public void clickTile(ComponentName tile) { 224 if (QsInCompose.isEnabled()) { 225 if (tile != null) { 226 mQSHost.clickTile(tile); 227 } 228 } else { 229 // Can't inject this because it changes with the QS fragment 230 QSPanelController qsPanelController = mCentralSurfaces.getQSPanelController(); 231 if (qsPanelController != null) { 232 qsPanelController.clickTile(tile); 233 } 234 } 235 } 236 237 @Override animateCollapsePanels(int flags, boolean force)238 public void animateCollapsePanels(int flags, boolean force) { 239 mShadeController.animateCollapseShade(flags, force, false /* delayed */, 240 1.0f /* speedUpFactor */); 241 } 242 243 @Override animateExpandNotificationsPanel()244 public void animateExpandNotificationsPanel() { 245 if (CentralSurfaces.SPEW) { 246 Log.d(CentralSurfaces.TAG, 247 "animateExpand: mExpandedVisible=" + mShadeController.isExpandedVisible()); 248 } 249 mShadeController.animateExpandShade(); 250 } 251 252 @Override animateExpandSettingsPanel(@ullable String subPanel)253 public void animateExpandSettingsPanel(@Nullable String subPanel) { 254 if (CentralSurfaces.SPEW) { 255 Log.d(CentralSurfaces.TAG, 256 "animateExpand: mExpandedVisible=" + mShadeController.isExpandedVisible()); 257 } 258 mShadeController.animateExpandQs(); 259 } 260 261 @Override appTransitionCancelled(int displayId)262 public void appTransitionCancelled(int displayId) { 263 } 264 265 @Override appTransitionFinished(int displayId)266 public void appTransitionFinished(int displayId) { 267 } 268 269 @Override dismissKeyboardShortcutsMenu()270 public void dismissKeyboardShortcutsMenu() { 271 mCentralSurfaces.resendMessage(CentralSurfaces.MSG_DISMISS_KEYBOARD_SHORTCUTS_MENU); 272 } 273 /** 274 * State is one or more of the DISABLE constants from StatusBarManager. 275 * 276 * @deprecated If you need to react to changes in disable flags, listen to 277 * {@link com.android.systemui.statusbar.disableflags.data.repository.DisableFlagsRepository} 278 * instead. 279 */ 280 @Override 281 @Deprecated disable(int displayId, int state1, int state2, boolean animate)282 public void disable(int displayId, int state1, int state2, boolean animate) { 283 if (displayId != mDisplayId) { 284 return; 285 } 286 287 final int old1 = mDisabled1; 288 final int diff1 = state1 ^ old1; 289 mDisabled1 = state1; 290 291 state2 = mRemoteInputQuickSettingsDisabler.adjustDisableFlags(state2); 292 final int old2 = mDisabled2; 293 final int diff2 = state2 ^ old2; 294 mDisabled2 = state2; 295 296 if ((diff1 & StatusBarManager.DISABLE_EXPAND) != 0) { 297 if ((state1 & StatusBarManager.DISABLE_EXPAND) != 0) { 298 mShadeController.animateCollapseShade(); 299 } 300 } 301 302 if ((diff1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) { 303 if ((state1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) { 304 mHeadsUpManager.releaseAllImmediately(); 305 } 306 } 307 308 if ((diff2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) != 0) { 309 if ((state2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) != 0) { 310 mShadeController.animateCollapseShade(); 311 } 312 } 313 314 if (!SceneContainerFlag.isEnabled()) { 315 mShadeHeaderController.disable(state1, state2, animate); 316 } 317 } 318 319 /** 320 * Called for system navigation gestures. First action opens the panel, second opens 321 * settings. Down action closes the entire panel. 322 */ 323 @Override handleSystemKey(KeyEvent key)324 public void handleSystemKey(KeyEvent key) { 325 if (CentralSurfaces.SPEW) { 326 Log.d(CentralSurfaces.TAG, "handleNavigationKey: " + key); 327 } 328 if (!mCommandQueue.panelsEnabled() || !mKeyguardUpdateMonitor.isDeviceInteractive() 329 || mKeyguardStateController.isShowing() && !mKeyguardStateController.isOccluded()) { 330 return; 331 } 332 333 // Panels are not available in setup 334 if (!mDeviceProvisionedController.isCurrentUserSetup()) return; 335 336 if (KeyEvent.KEYCODE_SYSTEM_NAVIGATION_UP == key.getKeyCode()) { 337 mMetricsLogger.action(MetricsEvent.ACTION_SYSTEM_NAVIGATION_KEY_UP); 338 mShadeController.animateCollapseShade(); 339 } else if (KeyEvent.KEYCODE_SYSTEM_NAVIGATION_DOWN == key.getKeyCode()) { 340 mMetricsLogger.action(MetricsEvent.ACTION_SYSTEM_NAVIGATION_KEY_DOWN); 341 if (mPanelExpansionInteractor.isFullyCollapsed()) { 342 if (mVibrateOnOpening) { 343 vibrateOnNavigationKeyDown(); 344 } 345 mShadeController.animateExpandShade(); 346 mNotificationStackScrollLayoutController.setWillExpand(true); 347 mHeadsUpManager.unpinAll(true /* userUnpinned */); 348 mMetricsLogger.count("panel_open", 1); 349 } else if (!mQsController.getExpanded() 350 && !mShadeController.isExpandingOrCollapsing()) { 351 mShadeController.animateExpandQs(); 352 mMetricsLogger.count("panel_open_qs", 1); 353 } 354 } 355 356 } 357 358 @Override onCameraLaunchGestureDetected(int source)359 public void onCameraLaunchGestureDetected(int source) { 360 if (launchWalletOptionOnPowerDoubleTap() && launchWalletViaSysuiCallbacks()) { 361 onPowerButtonLaunchGestureTriggered( 362 PowerButtonLaunchGestureTarget.LAUNCH_CAMERA_ON_GESTURE, source); 363 return; 364 } 365 366 mCentralSurfaces.setLastCameraLaunchSource(source); 367 if (mCentralSurfaces.isGoingToSleep()) { 368 if (CentralSurfaces.DEBUG_POWER_BUTTON_GESTURE) { 369 Slog.d(CentralSurfaces.TAG, "Finish going to sleep before launching camera"); 370 } 371 mCentralSurfaces.setLaunchCameraOnFinishedGoingToSleep(true); 372 return; 373 } 374 if (!mCameraLauncherLazy.get().canCameraGestureBeLaunched( 375 mPanelExpansionInteractor.getBarState())) { 376 if (CentralSurfaces.DEBUG_POWER_BUTTON_GESTURE) { 377 Slog.d(CentralSurfaces.TAG, "Can't launch camera right now"); 378 } 379 return; 380 } 381 mKeyguardInteractor.onCameraLaunchDetected(source); 382 383 if (!mCentralSurfaces.isDeviceInteractive()) { 384 mPowerManager.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_CAMERA_LAUNCH, 385 "com.android.systemui:CAMERA_GESTURE"); 386 } 387 vibrateForCameraGesture(); 388 389 if (source == StatusBarManager.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP) { 390 Log.v(CentralSurfaces.TAG, "Camera launch"); 391 mKeyguardUpdateMonitor.onCameraLaunched(); 392 } 393 394 if (!mKeyguardStateController.isShowing()) { 395 final Intent cameraIntent = CameraIntents.getInsecureCameraIntent(mContext, mUserTracker.getUserId()); 396 cameraIntent.putExtra(CameraIntents.EXTRA_LAUNCH_SOURCE, source); 397 mActivityStarter.startActivityDismissingKeyguard(cameraIntent, 398 false /* onlyProvisioned */, true /* dismissShade */, 399 true /* disallowEnterPictureInPictureWhileLaunching */, null /* callback */, 0, 400 null /* animationController */, mUserTracker.getUserHandle()); 401 } else { 402 if (!mCentralSurfaces.isDeviceInteractive()) { 403 // Avoid flickering of the scrim when we instant launch the camera and the bouncer 404 // comes on. 405 mCentralSurfaces.acquireGestureWakeLock( 406 CentralSurfaces.LAUNCH_TRANSITION_TIMEOUT_MS + 1000L); 407 } 408 if (isWakingUpOrAwake()) { 409 if (CentralSurfaces.DEBUG_POWER_BUTTON_GESTURE) { 410 Slog.d(CentralSurfaces.TAG, "Launching camera"); 411 } 412 if (mStatusBarKeyguardViewManager.isBouncerShowing()) { 413 mStatusBarKeyguardViewManager.reset(true /* hide */); 414 } 415 mCentralSurfaces.startLaunchTransitionTimeout(); 416 mCameraLauncherLazy.get().launchCamera(source, 417 mPanelExpansionInteractor.isFullyCollapsed()); 418 mCentralSurfaces.updateScrimController(); 419 } else { 420 // We need to defer the camera launch until the screen comes on, since otherwise 421 // we will dismiss us too early since we are waiting on an activity to be drawn and 422 // incorrectly get notified because of the screen on event (which resumes and pauses 423 // some activities) 424 if (CentralSurfaces.DEBUG_POWER_BUTTON_GESTURE) { 425 Slog.d(CentralSurfaces.TAG, "Deferring until screen turns on"); 426 } 427 mCentralSurfaces.setLaunchCameraOnFinishedWaking(true); 428 } 429 } 430 } 431 432 @Override onWalletLaunchGestureDetected()433 public void onWalletLaunchGestureDetected() { 434 onPowerButtonLaunchGestureTriggered( 435 PowerButtonLaunchGestureTarget.LAUNCH_WALLET_ON_GESTURE, 436 /* cameraLaunchSource=*/ -1); 437 } 438 439 @Override onEmergencyActionLaunchGestureDetected()440 public void onEmergencyActionLaunchGestureDetected() { 441 Intent emergencyIntent = mEmergencyGestureIntentFactory.invoke( 442 EmergencyGesture.ACTION_LAUNCH_EMERGENCY); 443 444 if (emergencyIntent == null) { 445 Log.wtf(CentralSurfaces.TAG, "Couldn't find an app to process the emergency intent."); 446 return; 447 } 448 449 if (isGoingToSleep()) { 450 mCentralSurfaces.setLaunchEmergencyActionOnFinishedGoingToSleep(true); 451 return; 452 } 453 454 if (!mCentralSurfaces.isDeviceInteractive()) { 455 mPowerManager.wakeUp(SystemClock.uptimeMillis(), 456 PowerManager.WAKE_REASON_GESTURE, 457 "com.android.systemui:EMERGENCY_GESTURE"); 458 } 459 // TODO(b/169087248) Possibly add haptics here for emergency action. Currently disabled for 460 // app-side haptic experimentation. 461 462 if (!mKeyguardStateController.isShowing()) { 463 mActivityStarter.startActivityDismissingKeyguard(emergencyIntent, 464 false /* onlyProvisioned */, true /* dismissShade */, 465 true /* disallowEnterPictureInPictureWhileLaunching */, null /* callback */, 0, 466 null /* animationController */, mUserTracker.getUserHandle()); 467 return; 468 } 469 470 if (!mCentralSurfaces.isDeviceInteractive()) { 471 // Avoid flickering of the scrim when we instant launch the camera and the bouncer 472 // comes on. 473 mCentralSurfaces.acquireGestureWakeLock( 474 CentralSurfaces.LAUNCH_TRANSITION_TIMEOUT_MS + 1000L); 475 } 476 477 if (isWakingUpOrAwake()) { 478 if (mStatusBarKeyguardViewManager.isBouncerShowing()) { 479 mStatusBarKeyguardViewManager.reset(true /* hide */); 480 } 481 mContext.startActivityAsUser(emergencyIntent, mUserTracker.getUserHandle()); 482 return; 483 } 484 // We need to defer the emergency action launch until the screen comes on, since otherwise 485 // we will dismiss us too early since we are waiting on an activity to be drawn and 486 // incorrectly get notified because of the screen on event (which resumes and pauses 487 // some activities) 488 mCentralSurfaces.setLaunchEmergencyActionOnFinishedWaking(true); 489 } 490 491 @Override onRecentsAnimationStateChanged(boolean running)492 public void onRecentsAnimationStateChanged(boolean running) { 493 mCentralSurfaces.setInteracting(StatusBarManager.WINDOW_NAVIGATION_BAR, running); 494 } 495 496 @Override toggleKeyboardShortcutsMenu(int deviceId)497 public void toggleKeyboardShortcutsMenu(int deviceId) { 498 mCentralSurfaces.resendMessage(new CentralSurfaces.KeyboardShortcutsMessage(deviceId)); 499 } 500 501 @Override setTopAppHidesStatusBar(boolean topAppHidesStatusBar)502 public void setTopAppHidesStatusBar(boolean topAppHidesStatusBar) { 503 mStatusBarHideIconsForBouncerManager 504 .setTopAppHidesStatusBarAndTriggerUpdate(topAppHidesStatusBar); 505 } 506 507 @Override showAssistDisclosure()508 public void showAssistDisclosure() { 509 mAssistManager.showDisclosure(); 510 } 511 512 @Override showScreenPinningRequest(int taskId)513 public void showScreenPinningRequest(int taskId) { 514 if (mKeyguardStateController.isShowing()) { 515 // Don't allow apps to trigger this from keyguard. 516 return; 517 } 518 // Show screen pinning request, since this comes from an app, show 'no thanks', button. 519 mScreenPinningRequest.showPrompt(taskId, true); 520 } 521 522 @Override showWirelessChargingAnimation(int batteryLevel)523 public void showWirelessChargingAnimation(int batteryLevel) { 524 mCentralSurfaces.showWirelessChargingAnimation(batteryLevel); 525 } 526 527 @Override startAssist(Bundle args)528 public void startAssist(Bundle args) { 529 mAssistManager.startAssist(args); 530 } 531 532 @Override suppressAmbientDisplay(boolean suppressed)533 public void suppressAmbientDisplay(boolean suppressed) { 534 mDozeServiceHost.setAlwaysOnSuppressed(suppressed); 535 } 536 537 @Override toggleNotificationsPanel()538 public void toggleNotificationsPanel() { 539 if (mShadeInteractorLazy.get().isAnyExpanded().getValue()) { 540 mShadeController.animateCollapseShade(); 541 } else { 542 mShadeController.animateExpandShade(); 543 } 544 } 545 546 @Override toggleQuickSettingsPanel()547 public void toggleQuickSettingsPanel() { 548 if (mShadeInteractorLazy.get().isQsExpanded().getValue()) { 549 mShadeController.animateCollapseShade(); 550 } else { 551 mShadeController.animateExpandQs(); 552 } 553 } 554 isGoingToSleep()555 private boolean isGoingToSleep() { 556 return mWakefulnessLifecycle.getWakefulness() 557 == WakefulnessLifecycle.WAKEFULNESS_GOING_TO_SLEEP; 558 } 559 isWakingUpOrAwake()560 private boolean isWakingUpOrAwake() { 561 return mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_AWAKE 562 || mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_WAKING; 563 } 564 vibrateForCameraGesture()565 private void vibrateForCameraGesture() { 566 mVibratorOptional.ifPresent( 567 v -> v.vibrate(mCameraLaunchGestureVibrationEffect, 568 HARDWARE_FEEDBACK_VIBRATION_ATTRIBUTES)); 569 } 570 getCameraGestureVibrationEffect( Optional<Vibrator> vibratorOptional, Resources resources)571 private static VibrationEffect getCameraGestureVibrationEffect( 572 Optional<Vibrator> vibratorOptional, Resources resources) { 573 if (vibratorOptional.isPresent() && vibratorOptional.get().areAllPrimitivesSupported( 574 VibrationEffect.Composition.PRIMITIVE_QUICK_RISE, 575 VibrationEffect.Composition.PRIMITIVE_CLICK)) { 576 return VibrationEffect.startComposition() 577 .addPrimitive(VibrationEffect.Composition.PRIMITIVE_QUICK_RISE) 578 .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1, 50) 579 .compose(); 580 } 581 if (vibratorOptional.isPresent() && vibratorOptional.get().hasAmplitudeControl()) { 582 // Make sure to pass -1 for repeat so VibratorManagerService doesn't stop us when going 583 // to sleep. 584 return VibrationEffect.createWaveform( 585 CentralSurfaces.CAMERA_LAUNCH_GESTURE_VIBRATION_TIMINGS, 586 CentralSurfaces.CAMERA_LAUNCH_GESTURE_VIBRATION_AMPLITUDES, 587 /* repeat= */ -1); 588 } 589 590 int[] pattern = resources.getIntArray(R.array.config_cameraLaunchGestureVibePattern); 591 long[] timings = new long[pattern.length]; 592 for (int i = 0; i < pattern.length; i++) { 593 timings[i] = pattern[i]; 594 } 595 return VibrationEffect.createWaveform(timings, /* repeat= */ -1); 596 } 597 598 @VisibleForTesting vibrateOnNavigationKeyDown()599 void vibrateOnNavigationKeyDown() { 600 mShadeController.performHapticFeedback( 601 HapticFeedbackConstants.GESTURE_START 602 ); 603 } 604 onPowerButtonLaunchGestureTriggered(PowerButtonLaunchGestureTarget target, int cameraLaunchSource)605 private void onPowerButtonLaunchGestureTriggered(PowerButtonLaunchGestureTarget target, 606 int cameraLaunchSource) { 607 if (!launchWalletOptionOnPowerDoubleTap() || !launchWalletViaSysuiCallbacks()) { 608 return; 609 } 610 611 if (target == PowerButtonLaunchGestureTarget.LAUNCH_CAMERA_ON_GESTURE) { 612 mCentralSurfaces.setLastCameraLaunchSource(cameraLaunchSource); 613 } 614 615 if (mCentralSurfaces.isGoingToSleep()) { 616 setLaunchAppOnFinishedGoingToSleep(target); 617 return; 618 } 619 620 if (!canAppBeLaunched(PowerButtonLaunchGestureTarget.LAUNCH_CAMERA_ON_GESTURE)) { 621 if (CentralSurfaces.DEBUG_POWER_BUTTON_GESTURE) { 622 Slog.d(CentralSurfaces.TAG, "Can't launch app via power button gesture right " 623 + "now"); 624 } 625 return; 626 } 627 628 if (target == PowerButtonLaunchGestureTarget.LAUNCH_CAMERA_ON_GESTURE) { 629 mKeyguardInteractor.onCameraLaunchDetected(cameraLaunchSource); 630 } 631 632 wakeUpFromAppLaunch(target); 633 vibrateForCameraGesture(); 634 635 if (target == PowerButtonLaunchGestureTarget.LAUNCH_CAMERA_ON_GESTURE && 636 cameraLaunchSource == StatusBarManager.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP) { 637 Slog.v(CentralSurfaces.TAG, "Camera launch"); 638 mKeyguardUpdateMonitor.onCameraLaunched(); 639 } 640 641 if (!mKeyguardStateController.isShowing()) { 642 switch (target) { 643 case LAUNCH_CAMERA_ON_GESTURE: 644 startInsecureCameraIntent(cameraLaunchSource); 645 break; 646 case LAUNCH_WALLET_ON_GESTURE: 647 mWalletController.startGestureUiIntent(mActivityStarter, 648 /* animationController=*/ null); 649 break; 650 } 651 } else { 652 if (!mCentralSurfaces.isDeviceInteractive()) { 653 // Avoid flickering of the scrim when we instant launch and the bouncer 654 // comes on. 655 mCentralSurfaces.acquireGestureWakeLock( 656 CentralSurfaces.LAUNCH_TRANSITION_TIMEOUT_MS + 1000L); 657 } 658 if (isWakingUpOrAwake()) { 659 if (CentralSurfaces.DEBUG_POWER_BUTTON_GESTURE) { 660 Slog.d(CentralSurfaces.TAG, "Launching app via double power button " 661 + "gesture"); 662 } 663 if (mStatusBarKeyguardViewManager.isBouncerShowing()) { 664 mStatusBarKeyguardViewManager.reset(true /* hide */); 665 } 666 mCentralSurfaces.startLaunchTransitionTimeout(); 667 switch (target) { 668 case LAUNCH_CAMERA_ON_GESTURE: 669 mCameraLauncherLazy.get().launchCamera(cameraLaunchSource, 670 mPanelExpansionInteractor.isFullyCollapsed()); 671 break; 672 case LAUNCH_WALLET_ON_GESTURE: 673 mWalletController.startGestureUiIntent(mActivityStarter, 674 /* animationController=*/ null); 675 break; 676 } 677 mCentralSurfaces.updateScrimController(); 678 } else { 679 // We need to defer the app launch until the screen comes on, since otherwise 680 // we will dismiss us too early since we are waiting on an activity to be drawn and 681 // incorrectly get notified because of the screen on event (which resumes and pauses 682 // some activities) 683 if (CentralSurfaces.DEBUG_POWER_BUTTON_GESTURE) { 684 Slog.d(CentralSurfaces.TAG, "Deferring until screen turns on"); 685 } 686 setLaunchAppOnFinishedWaking(target); 687 } 688 } 689 } 690 setLaunchAppOnFinishedGoingToSleep(PowerButtonLaunchGestureTarget target)691 private void setLaunchAppOnFinishedGoingToSleep(PowerButtonLaunchGestureTarget target) { 692 if (CentralSurfaces.DEBUG_POWER_BUTTON_GESTURE) { 693 Slog.d(CentralSurfaces.TAG, 694 "Finish going to sleep before LAUNCHING"); 695 } 696 switch (target) { 697 case LAUNCH_CAMERA_ON_GESTURE: 698 Slog.d(CentralSurfaces.TAG, "setLaunchCameraOnFinishedGoingToSleep"); 699 mCentralSurfaces.setLaunchCameraOnFinishedGoingToSleep(true); 700 break; 701 case LAUNCH_WALLET_ON_GESTURE: 702 Slog.d(CentralSurfaces.TAG, "setLaunchWalletOnFinishedGoingToSleep"); 703 mCentralSurfaces.setLaunchWalletOnFinishedGoingToSleep(true); 704 break; 705 706 } 707 } 708 canAppBeLaunched(PowerButtonLaunchGestureTarget target)709 private boolean canAppBeLaunched(PowerButtonLaunchGestureTarget target) { 710 if (target == PowerButtonLaunchGestureTarget.LAUNCH_CAMERA_ON_GESTURE && 711 !mCameraLauncherLazy.get().canCameraGestureBeLaunched( 712 mPanelExpansionInteractor.getBarState())) { 713 if (CentralSurfaces.DEBUG_POWER_BUTTON_GESTURE) { 714 Slog.d(CentralSurfaces.TAG, "Can't launch camera right now"); 715 } 716 return false; 717 } 718 return true; 719 } 720 startInsecureCameraIntent(int source)721 private void startInsecureCameraIntent(int source) { 722 final Intent cameraIntent = CameraIntents.getInsecureCameraIntent(mContext, 723 mUserTracker.getUserId()); 724 cameraIntent.putExtra(CameraIntents.EXTRA_LAUNCH_SOURCE, source); 725 mActivityStarter.startActivityDismissingKeyguard(cameraIntent, 726 /* onlyProvisioned=*/ false, /* dismissShade=*/ true, 727 /* disallowEnterPictureInPictureWhileLaunching=*/ true, 728 /* callback=*/ null, /*flags=*/ 0,/* animationController=*/ null, 729 mUserTracker.getUserHandle()); 730 } 731 setLaunchAppOnFinishedWaking(PowerButtonLaunchGestureTarget target)732 private void setLaunchAppOnFinishedWaking(PowerButtonLaunchGestureTarget target) { 733 switch (target) { 734 case LAUNCH_CAMERA_ON_GESTURE: 735 mCentralSurfaces.setLaunchCameraOnFinishedWaking(true); 736 break; 737 case LAUNCH_WALLET_ON_GESTURE: 738 mCentralSurfaces.setLaunchWalletOnFinishedWaking(true); 739 break; 740 } 741 } 742 wakeUpFromAppLaunch(PowerButtonLaunchGestureTarget appLaunch)743 private void wakeUpFromAppLaunch(PowerButtonLaunchGestureTarget appLaunch) { 744 if (!mCentralSurfaces.isDeviceInteractive()) { 745 int reason = appLaunch == PowerButtonLaunchGestureTarget.LAUNCH_CAMERA_ON_GESTURE ? 746 PowerManager.WAKE_REASON_CAMERA_LAUNCH : PowerManager.WAKE_REASON_GESTURE; 747 String details = appLaunch == PowerButtonLaunchGestureTarget.LAUNCH_CAMERA_ON_GESTURE ? 748 "com.android.systemui:CAMERA_GESTURE" : "com.android.systemui:WALLET_GESTURE"; 749 mPowerManager.wakeUp(SystemClock.uptimeMillis(), reason, details); 750 } 751 } 752 } 753