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 com.android.systemui.flags.Flags.ONE_WAY_HAPTICS_API_MIGRATION;
20 import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_AWAKE;
21 import static com.android.systemui.keyguard.WakefulnessLifecycle.WAKEFULNESS_WAKING;
22 
23 import android.annotation.Nullable;
24 import android.app.StatusBarManager;
25 import android.content.ComponentName;
26 import android.content.Context;
27 import android.content.Intent;
28 import android.content.res.Resources;
29 import android.os.Bundle;
30 import android.os.PowerManager;
31 import android.os.SystemClock;
32 import android.os.VibrationAttributes;
33 import android.os.VibrationEffect;
34 import android.os.Vibrator;
35 import android.util.Log;
36 import android.util.Slog;
37 import android.view.HapticFeedbackConstants;
38 import android.view.KeyEvent;
39 import android.view.WindowInsets;
40 import android.view.WindowInsets.Type.InsetsType;
41 import android.view.WindowInsetsController.Appearance;
42 import android.view.WindowInsetsController.Behavior;
43 
44 import androidx.annotation.VisibleForTesting;
45 
46 import com.android.internal.logging.MetricsLogger;
47 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
48 import com.android.internal.statusbar.LetterboxDetails;
49 import com.android.internal.view.AppearanceRegion;
50 import com.android.keyguard.KeyguardUpdateMonitor;
51 import com.android.systemui.R;
52 import com.android.systemui.assist.AssistManager;
53 import com.android.systemui.camera.CameraIntents;
54 import com.android.systemui.dagger.qualifiers.DisplayId;
55 import com.android.systemui.dagger.qualifiers.Main;
56 import com.android.systemui.flags.FeatureFlags;
57 import com.android.systemui.keyguard.WakefulnessLifecycle;
58 import com.android.systemui.plugins.ActivityStarter;
59 import com.android.systemui.qs.QSHost;
60 import com.android.systemui.qs.QSPanelController;
61 import com.android.systemui.settings.UserTracker;
62 import com.android.systemui.shade.CameraLauncher;
63 import com.android.systemui.shade.QuickSettingsController;
64 import com.android.systemui.shade.ShadeController;
65 import com.android.systemui.shade.ShadeViewController;
66 import com.android.systemui.statusbar.CommandQueue;
67 import com.android.systemui.statusbar.VibratorHelper;
68 import com.android.systemui.statusbar.disableflags.DisableFlagsLogger;
69 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
70 import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent;
71 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
72 import com.android.systemui.statusbar.policy.HeadsUpManager;
73 import com.android.systemui.statusbar.policy.KeyguardStateController;
74 import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
75 
76 import dagger.Lazy;
77 
78 import java.util.Optional;
79 
80 import javax.inject.Inject;
81 
82 /** */
83 @CentralSurfacesComponent.CentralSurfacesScope
84 public class CentralSurfacesCommandQueueCallbacks implements CommandQueue.Callbacks {
85     private final CentralSurfaces mCentralSurfaces;
86     private final Context mContext;
87     private final com.android.systemui.shade.ShadeController mShadeController;
88     private final CommandQueue mCommandQueue;
89     private final ShadeViewController mShadeViewController;
90     private final RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler;
91     private final MetricsLogger mMetricsLogger;
92     private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
93     private final KeyguardStateController mKeyguardStateController;
94     private final HeadsUpManager mHeadsUpManager;
95     private final WakefulnessLifecycle mWakefulnessLifecycle;
96     private final DeviceProvisionedController mDeviceProvisionedController;
97     private final StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
98     private final AssistManager mAssistManager;
99     private final DozeServiceHost mDozeServiceHost;
100     private final NotificationStackScrollLayoutController mNotificationStackScrollLayoutController;
101     private final StatusBarHideIconsForBouncerManager mStatusBarHideIconsForBouncerManager;
102     private final PowerManager mPowerManager;
103     private final VibratorHelper mVibratorHelper;
104     private final Optional<Vibrator> mVibratorOptional;
105     private final DisableFlagsLogger mDisableFlagsLogger;
106     private final int mDisplayId;
107     private final UserTracker mUserTracker;
108     private final boolean mVibrateOnOpening;
109     private final VibrationEffect mCameraLaunchGestureVibrationEffect;
110     private final SystemBarAttributesListener mSystemBarAttributesListener;
111     private final ActivityStarter mActivityStarter;
112     private final Lazy<CameraLauncher> mCameraLauncherLazy;
113     private final QuickSettingsController mQsController;
114     private final QSHost mQSHost;
115     private final FeatureFlags mFeatureFlags;
116 
117     private static final VibrationAttributes HARDWARE_FEEDBACK_VIBRATION_ATTRIBUTES =
118             VibrationAttributes.createForUsage(VibrationAttributes.USAGE_HARDWARE_FEEDBACK);
119 
120     private int mDisabled1;
121     private int mDisabled2;
122 
123     @Inject
CentralSurfacesCommandQueueCallbacks( CentralSurfaces centralSurfaces, QuickSettingsController quickSettingsController, Context context, @Main Resources resources, ShadeController shadeController, CommandQueue commandQueue, ShadeViewController shadeViewController, 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, VibratorHelper vibratorHelper, Optional<Vibrator> vibratorOptional, DisableFlagsLogger disableFlagsLogger, @DisplayId int displayId, SystemBarAttributesListener systemBarAttributesListener, Lazy<CameraLauncher> cameraLauncherLazy, UserTracker userTracker, QSHost qsHost, ActivityStarter activityStarter, FeatureFlags featureFlags)124     CentralSurfacesCommandQueueCallbacks(
125             CentralSurfaces centralSurfaces,
126             QuickSettingsController quickSettingsController,
127             Context context,
128             @Main Resources resources,
129             ShadeController shadeController,
130             CommandQueue commandQueue,
131             ShadeViewController shadeViewController,
132             RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler,
133             MetricsLogger metricsLogger,
134             KeyguardUpdateMonitor keyguardUpdateMonitor,
135             KeyguardStateController keyguardStateController,
136             HeadsUpManager headsUpManager,
137             WakefulnessLifecycle wakefulnessLifecycle,
138             DeviceProvisionedController deviceProvisionedController,
139             StatusBarKeyguardViewManager statusBarKeyguardViewManager,
140             AssistManager assistManager,
141             DozeServiceHost dozeServiceHost,
142             NotificationStackScrollLayoutController notificationStackScrollLayoutController,
143             StatusBarHideIconsForBouncerManager statusBarHideIconsForBouncerManager,
144             PowerManager powerManager,
145             VibratorHelper vibratorHelper,
146             Optional<Vibrator> vibratorOptional,
147             DisableFlagsLogger disableFlagsLogger,
148             @DisplayId int displayId,
149             SystemBarAttributesListener systemBarAttributesListener,
150             Lazy<CameraLauncher> cameraLauncherLazy,
151             UserTracker userTracker,
152             QSHost qsHost,
153             ActivityStarter activityStarter,
154             FeatureFlags featureFlags) {
155         mCentralSurfaces = centralSurfaces;
156         mQsController = quickSettingsController;
157         mContext = context;
158         mShadeController = shadeController;
159         mCommandQueue = commandQueue;
160         mShadeViewController = shadeViewController;
161         mRemoteInputQuickSettingsDisabler = remoteInputQuickSettingsDisabler;
162         mMetricsLogger = metricsLogger;
163         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
164         mKeyguardStateController = keyguardStateController;
165         mHeadsUpManager = headsUpManager;
166         mWakefulnessLifecycle = wakefulnessLifecycle;
167         mDeviceProvisionedController = deviceProvisionedController;
168         mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
169         mAssistManager = assistManager;
170         mDozeServiceHost = dozeServiceHost;
171         mNotificationStackScrollLayoutController = notificationStackScrollLayoutController;
172         mStatusBarHideIconsForBouncerManager = statusBarHideIconsForBouncerManager;
173         mPowerManager = powerManager;
174         mVibratorHelper = vibratorHelper;
175         mVibratorOptional = vibratorOptional;
176         mDisableFlagsLogger = disableFlagsLogger;
177         mDisplayId = displayId;
178         mCameraLauncherLazy = cameraLauncherLazy;
179         mUserTracker = userTracker;
180         mQSHost = qsHost;
181         mFeatureFlags = featureFlags;
182 
183         mVibrateOnOpening = resources.getBoolean(R.bool.config_vibrateOnIconAnimation);
184         mCameraLaunchGestureVibrationEffect = getCameraGestureVibrationEffect(
185                 mVibratorOptional, resources);
186         mSystemBarAttributesListener = systemBarAttributesListener;
187         mActivityStarter = activityStarter;
188     }
189 
190     @Override
abortTransient(int displayId, @InsetsType int types)191     public void abortTransient(int displayId, @InsetsType int types) {
192         if (displayId != mDisplayId) {
193             return;
194         }
195         if ((types & WindowInsets.Type.statusBars()) == 0) {
196             return;
197         }
198         mCentralSurfaces.clearTransient();
199     }
200 
201     @Override
addQsTile(ComponentName tile)202     public void addQsTile(ComponentName tile) {
203         mQSHost.addTile(tile);
204     }
205 
206     @Override
remQsTile(ComponentName tile)207     public void remQsTile(ComponentName tile) {
208         mQSHost.removeTileByUser(tile);
209     }
210 
211     @Override
clickTile(ComponentName tile)212     public void clickTile(ComponentName tile) {
213         // Can't inject this because it changes with the QS fragment
214         QSPanelController qsPanelController = mCentralSurfaces.getQSPanelController();
215         if (qsPanelController != null) {
216             qsPanelController.clickTile(tile);
217         }
218     }
219 
220     @Override
animateCollapsePanels(int flags, boolean force)221     public void animateCollapsePanels(int flags, boolean force) {
222         mShadeController.animateCollapseShade(flags, force, false /* delayed */,
223                 1.0f /* speedUpFactor */);
224     }
225 
226     @Override
animateExpandNotificationsPanel()227     public void animateExpandNotificationsPanel() {
228         if (CentralSurfaces.SPEW) {
229             Log.d(CentralSurfaces.TAG,
230                     "animateExpand: mExpandedVisible=" + mShadeController.isExpandedVisible());
231         }
232         mShadeController.animateExpandShade();
233     }
234 
235     @Override
animateExpandSettingsPanel(@ullable String subPanel)236     public void animateExpandSettingsPanel(@Nullable String subPanel) {
237         if (CentralSurfaces.SPEW) {
238             Log.d(CentralSurfaces.TAG,
239                     "animateExpand: mExpandedVisible=" + mShadeController.isExpandedVisible());
240         }
241         mShadeController.animateExpandQs();
242     }
243 
244     @Override
appTransitionCancelled(int displayId)245     public void appTransitionCancelled(int displayId) {
246     }
247 
248     @Override
appTransitionFinished(int displayId)249     public void appTransitionFinished(int displayId) {
250     }
251 
252     @Override
dismissKeyboardShortcutsMenu()253     public void dismissKeyboardShortcutsMenu() {
254         mCentralSurfaces.resendMessage(CentralSurfaces.MSG_DISMISS_KEYBOARD_SHORTCUTS_MENU);
255     }
256     /**
257      * State is one or more of the DISABLE constants from StatusBarManager.
258      *
259      * @deprecated If you need to react to changes in disable flags, listen to
260      * {@link com.android.systemui.statusbar.disableflags.data.repository.DisableFlagsRepository}
261      * instead.
262      */
263     @Override
264     @Deprecated
disable(int displayId, int state1, int state2, boolean animate)265     public void disable(int displayId, int state1, int state2, boolean animate) {
266         if (displayId != mDisplayId) {
267             return;
268         }
269 
270         final int old1 = mDisabled1;
271         final int diff1 = state1 ^ old1;
272         mDisabled1 = state1;
273 
274         state2 = mRemoteInputQuickSettingsDisabler.adjustDisableFlags(state2);
275         final int old2 = mDisabled2;
276         final int diff2 = state2 ^ old2;
277         mDisabled2 = state2;
278 
279         if ((diff1 & StatusBarManager.DISABLE_EXPAND) != 0) {
280             if ((state1 & StatusBarManager.DISABLE_EXPAND) != 0) {
281                 mShadeController.animateCollapseShade();
282             }
283         }
284 
285         if ((diff1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) {
286             if ((state1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) {
287                 mHeadsUpManager.releaseAllImmediately();
288             }
289         }
290 
291         if ((diff2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) != 0) {
292             if ((state2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) != 0) {
293                 mShadeController.animateCollapseShade();
294             }
295         }
296 
297         mShadeViewController.disableHeader(state1, state2, animate);
298     }
299 
300     /**
301      * Called for system navigation gestures. First action opens the panel, second opens
302      * settings. Down action closes the entire panel.
303      */
304     @Override
handleSystemKey(KeyEvent key)305     public void handleSystemKey(KeyEvent key) {
306         if (CentralSurfaces.SPEW) {
307             Log.d(CentralSurfaces.TAG, "handleNavigationKey: " + key);
308         }
309         if (!mCommandQueue.panelsEnabled() || !mKeyguardUpdateMonitor.isDeviceInteractive()
310                 || mKeyguardStateController.isShowing() && !mKeyguardStateController.isOccluded()) {
311             return;
312         }
313 
314         // Panels are not available in setup
315         if (!mDeviceProvisionedController.isCurrentUserSetup()) return;
316 
317         if (KeyEvent.KEYCODE_SYSTEM_NAVIGATION_UP == key.getKeyCode()) {
318             mMetricsLogger.action(MetricsEvent.ACTION_SYSTEM_NAVIGATION_KEY_UP);
319             mShadeViewController.collapse(
320                     false /* delayed */, 1.0f /* speedUpFactor */);
321         } else if (KeyEvent.KEYCODE_SYSTEM_NAVIGATION_DOWN == key.getKeyCode()) {
322             mMetricsLogger.action(MetricsEvent.ACTION_SYSTEM_NAVIGATION_KEY_DOWN);
323             if (mShadeViewController.isFullyCollapsed()) {
324                 if (mVibrateOnOpening) {
325                     vibrateOnNavigationKeyDown();
326                 }
327                 mShadeViewController.expand(true /* animate */);
328                 mNotificationStackScrollLayoutController.setWillExpand(true);
329                 mHeadsUpManager.unpinAll(true /* userUnpinned */);
330                 mMetricsLogger.count("panel_open", 1);
331             } else if (!mQsController.getExpanded()
332                     && !mShadeViewController.isExpandingOrCollapsing()) {
333                 mQsController.flingQs(0 /* velocity */,
334                         ShadeViewController.FLING_EXPAND);
335                 mMetricsLogger.count("panel_open_qs", 1);
336             }
337         }
338 
339     }
340 
341     @Override
onCameraLaunchGestureDetected(int source)342     public void onCameraLaunchGestureDetected(int source) {
343         mCentralSurfaces.setLastCameraLaunchSource(source);
344         if (mCentralSurfaces.isGoingToSleep()) {
345             if (CentralSurfaces.DEBUG_CAMERA_LIFT) {
346                 Slog.d(CentralSurfaces.TAG, "Finish going to sleep before launching camera");
347             }
348             mCentralSurfaces.setLaunchCameraOnFinishedGoingToSleep(true);
349             return;
350         }
351         if (!mCameraLauncherLazy.get().canCameraGestureBeLaunched(
352                 mShadeViewController.getBarState())) {
353             if (CentralSurfaces.DEBUG_CAMERA_LIFT) {
354                 Slog.d(CentralSurfaces.TAG, "Can't launch camera right now");
355             }
356             return;
357         }
358         if (!mCentralSurfaces.isDeviceInteractive()) {
359             mPowerManager.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_CAMERA_LAUNCH,
360                     "com.android.systemui:CAMERA_GESTURE");
361         }
362         vibrateForCameraGesture();
363 
364         if (source == StatusBarManager.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP) {
365             Log.v(CentralSurfaces.TAG, "Camera launch");
366             mKeyguardUpdateMonitor.onCameraLaunched();
367         }
368 
369         if (!mKeyguardStateController.isShowing()) {
370             final Intent cameraIntent = CameraIntents.getInsecureCameraIntent(mContext);
371             cameraIntent.putExtra(CameraIntents.EXTRA_LAUNCH_SOURCE, source);
372             mActivityStarter.startActivityDismissingKeyguard(cameraIntent,
373                     false /* onlyProvisioned */, true /* dismissShade */,
374                     true /* disallowEnterPictureInPictureWhileLaunching */, null /* callback */, 0,
375                     null /* animationController */, mUserTracker.getUserHandle());
376         } else {
377             if (!mCentralSurfaces.isDeviceInteractive()) {
378                 // Avoid flickering of the scrim when we instant launch the camera and the bouncer
379                 // comes on.
380                 mCentralSurfaces.acquireGestureWakeLock(
381                         CentralSurfaces.LAUNCH_TRANSITION_TIMEOUT_MS + 1000L);
382             }
383             if (isWakingUpOrAwake()) {
384                 if (CentralSurfaces.DEBUG_CAMERA_LIFT) {
385                     Slog.d(CentralSurfaces.TAG, "Launching camera");
386                 }
387                 if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
388                     mStatusBarKeyguardViewManager.reset(true /* hide */);
389                 }
390                 mCameraLauncherLazy.get().launchCamera(source,
391                         mShadeViewController.isFullyCollapsed());
392                 mCentralSurfaces.updateScrimController();
393             } else {
394                 // We need to defer the camera launch until the screen comes on, since otherwise
395                 // we will dismiss us too early since we are waiting on an activity to be drawn and
396                 // incorrectly get notified because of the screen on event (which resumes and pauses
397                 // some activities)
398                 if (CentralSurfaces.DEBUG_CAMERA_LIFT) {
399                     Slog.d(CentralSurfaces.TAG, "Deferring until screen turns on");
400                 }
401                 mCentralSurfaces.setLaunchCameraOnFinishedWaking(true);
402             }
403         }
404     }
405 
406     @Override
onEmergencyActionLaunchGestureDetected()407     public void onEmergencyActionLaunchGestureDetected() {
408         Intent emergencyIntent = mCentralSurfaces.getEmergencyActionIntent();
409 
410         if (emergencyIntent == null) {
411             Log.wtf(CentralSurfaces.TAG, "Couldn't find an app to process the emergency intent.");
412             return;
413         }
414 
415         if (isGoingToSleep()) {
416             mCentralSurfaces.setLaunchEmergencyActionOnFinishedGoingToSleep(true);
417             return;
418         }
419 
420         if (!mCentralSurfaces.isDeviceInteractive()) {
421             mPowerManager.wakeUp(SystemClock.uptimeMillis(),
422                     PowerManager.WAKE_REASON_GESTURE,
423                     "com.android.systemui:EMERGENCY_GESTURE");
424         }
425         // TODO(b/169087248) Possibly add haptics here for emergency action. Currently disabled for
426         // app-side haptic experimentation.
427 
428         if (!mKeyguardStateController.isShowing()) {
429             mActivityStarter.startActivityDismissingKeyguard(emergencyIntent,
430                     false /* onlyProvisioned */, true /* dismissShade */,
431                     true /* disallowEnterPictureInPictureWhileLaunching */, null /* callback */, 0,
432                     null /* animationController */, mUserTracker.getUserHandle());
433             return;
434         }
435 
436         if (!mCentralSurfaces.isDeviceInteractive()) {
437             // Avoid flickering of the scrim when we instant launch the camera and the bouncer
438             // comes on.
439             mCentralSurfaces.acquireGestureWakeLock(
440                     CentralSurfaces.LAUNCH_TRANSITION_TIMEOUT_MS + 1000L);
441         }
442 
443         if (isWakingUpOrAwake()) {
444             if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
445                 mStatusBarKeyguardViewManager.reset(true /* hide */);
446             }
447             mContext.startActivityAsUser(emergencyIntent, mUserTracker.getUserHandle());
448             return;
449         }
450         // We need to defer the emergency action launch until the screen comes on, since otherwise
451         // we will dismiss us too early since we are waiting on an activity to be drawn and
452         // incorrectly get notified because of the screen on event (which resumes and pauses
453         // some activities)
454         mCentralSurfaces.setLaunchEmergencyActionOnFinishedWaking(true);
455     }
456 
457     @Override
onRecentsAnimationStateChanged(boolean running)458     public void onRecentsAnimationStateChanged(boolean running) {
459         mCentralSurfaces.setInteracting(StatusBarManager.WINDOW_NAVIGATION_BAR, running);
460     }
461 
462 
463     @Override
onSystemBarAttributesChanged(int displayId, @Appearance int appearance, AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme, @Behavior int behavior, @InsetsType int requestedVisibleTypes, String packageName, LetterboxDetails[] letterboxDetails)464     public void onSystemBarAttributesChanged(int displayId, @Appearance int appearance,
465             AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme,
466             @Behavior int behavior, @InsetsType int requestedVisibleTypes, String packageName,
467             LetterboxDetails[] letterboxDetails) {
468         if (displayId != mDisplayId) {
469             return;
470         }
471         // SystemBarAttributesListener should __always__ be the top-level listener for system bar
472         // attributes changed.
473         mSystemBarAttributesListener.onSystemBarAttributesChanged(
474                 displayId,
475                 appearance,
476                 appearanceRegions,
477                 navbarColorManagedByIme,
478                 behavior,
479                 requestedVisibleTypes,
480                 packageName,
481                 letterboxDetails
482         );
483     }
484 
485     @Override
showTransient(int displayId, @InsetsType int types, boolean isGestureOnSystemBar)486     public void showTransient(int displayId, @InsetsType int types, boolean isGestureOnSystemBar) {
487         if (displayId != mDisplayId) {
488             return;
489         }
490         if ((types & WindowInsets.Type.statusBars()) == 0) {
491             return;
492         }
493         mCentralSurfaces.showTransientUnchecked();
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
showPinningEnterExitToast(boolean entering)513     public void showPinningEnterExitToast(boolean entering) {
514         mCentralSurfaces.showPinningEnterExitToast(entering);
515     }
516 
517     @Override
showPinningEscapeToast()518     public void showPinningEscapeToast() {
519         mCentralSurfaces.showPinningEscapeToast();
520     }
521 
522     @Override
showScreenPinningRequest(int taskId)523     public void showScreenPinningRequest(int taskId) {
524         if (mKeyguardStateController.isShowing()) {
525             // Don't allow apps to trigger this from keyguard.
526             return;
527         }
528         // Show screen pinning request, since this comes from an app, show 'no thanks', button.
529         mCentralSurfaces.showScreenPinningRequest(taskId, true);
530     }
531 
532     @Override
showWirelessChargingAnimation(int batteryLevel)533     public void showWirelessChargingAnimation(int batteryLevel) {
534         mCentralSurfaces.showWirelessChargingAnimation(batteryLevel);
535     }
536 
537     @Override
startAssist(Bundle args)538     public void startAssist(Bundle args) {
539         mAssistManager.startAssist(args);
540     }
541 
542     @Override
suppressAmbientDisplay(boolean suppressed)543     public void suppressAmbientDisplay(boolean suppressed) {
544         mDozeServiceHost.setAlwaysOnSuppressed(suppressed);
545     }
546 
547     @Override
togglePanel()548     public void togglePanel() {
549         if (mShadeViewController.isPanelExpanded()) {
550             mShadeController.animateCollapseShade();
551         } else {
552             mShadeController.animateExpandShade();
553         }
554     }
555 
isGoingToSleep()556     private boolean isGoingToSleep() {
557         return mWakefulnessLifecycle.getWakefulness()
558                 == WakefulnessLifecycle.WAKEFULNESS_GOING_TO_SLEEP;
559     }
560 
isWakingUpOrAwake()561     private boolean isWakingUpOrAwake() {
562         return mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_AWAKE
563                 || mWakefulnessLifecycle.getWakefulness() == WAKEFULNESS_WAKING;
564     }
565 
vibrateForCameraGesture()566     private void vibrateForCameraGesture() {
567         mVibratorOptional.ifPresent(
568                 v -> v.vibrate(mCameraLaunchGestureVibrationEffect,
569                         HARDWARE_FEEDBACK_VIBRATION_ATTRIBUTES));
570     }
571 
getCameraGestureVibrationEffect( Optional<Vibrator> vibratorOptional, Resources resources)572     private static VibrationEffect getCameraGestureVibrationEffect(
573             Optional<Vibrator> vibratorOptional, Resources resources) {
574         if (vibratorOptional.isPresent() && vibratorOptional.get().areAllPrimitivesSupported(
575                 VibrationEffect.Composition.PRIMITIVE_QUICK_RISE,
576                 VibrationEffect.Composition.PRIMITIVE_CLICK)) {
577             return VibrationEffect.startComposition()
578                     .addPrimitive(VibrationEffect.Composition.PRIMITIVE_QUICK_RISE)
579                     .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1, 50)
580                     .compose();
581         }
582         if (vibratorOptional.isPresent() && vibratorOptional.get().hasAmplitudeControl()) {
583             // Make sure to pass -1 for repeat so VibratorManagerService doesn't stop us when going
584             // to sleep.
585             return VibrationEffect.createWaveform(
586                     CentralSurfaces.CAMERA_LAUNCH_GESTURE_VIBRATION_TIMINGS,
587                     CentralSurfaces.CAMERA_LAUNCH_GESTURE_VIBRATION_AMPLITUDES,
588                     /* repeat= */ -1);
589         }
590 
591         int[] pattern = resources.getIntArray(R.array.config_cameraLaunchGestureVibePattern);
592         long[] timings = new long[pattern.length];
593         for (int i = 0; i < pattern.length; i++) {
594             timings[i] = pattern[i];
595         }
596         return VibrationEffect.createWaveform(timings, /* repeat= */ -1);
597     }
598 
599     @VisibleForTesting
vibrateOnNavigationKeyDown()600     void vibrateOnNavigationKeyDown() {
601         if (mFeatureFlags.isEnabled(ONE_WAY_HAPTICS_API_MIGRATION)) {
602             mShadeViewController.performHapticFeedback(
603                     HapticFeedbackConstants.GESTURE_START
604             );
605         } else {
606             mVibratorHelper.vibrate(VibrationEffect.EFFECT_TICK);
607         }
608     }
609 }
610