• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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