1 /*
2  * Copyright (C) 2017 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.recents;
18 
19 import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
20 import static android.view.Display.DEFAULT_DISPLAY;
21 import static android.view.MotionEvent.ACTION_CANCEL;
22 import static android.view.MotionEvent.ACTION_DOWN;
23 import static android.view.MotionEvent.ACTION_UP;
24 import static android.view.WindowManager.ScreenshotSource.SCREENSHOT_OVERVIEW;
25 import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_3BUTTON;
26 
27 import static com.android.internal.accessibility.common.ShortcutConstants.CHOOSER_PACKAGE_NAME;
28 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_RECENT_TASKS;
29 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_ONE_HANDED;
30 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_PIP;
31 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_SHELL_TRANSITIONS;
32 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_SPLIT_SCREEN;
33 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_STARTING_WINDOW;
34 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SMARTSPACE_TRANSITION_CONTROLLER;
35 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SUPPORTS_WINDOW_CORNERS;
36 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY;
37 import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_WINDOW_CORNER_RADIUS;
38 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING;
39 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DEVICE_DOZING;
40 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING;
41 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED;
42 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_TRACING_ENABLED;
43 
44 import android.annotation.FloatRange;
45 import android.app.ActivityTaskManager;
46 import android.content.BroadcastReceiver;
47 import android.content.ComponentName;
48 import android.content.Context;
49 import android.content.Intent;
50 import android.content.IntentFilter;
51 import android.content.ServiceConnection;
52 import android.graphics.Bitmap;
53 import android.graphics.Insets;
54 import android.graphics.Rect;
55 import android.graphics.Region;
56 import android.hardware.input.InputManager;
57 import android.os.Binder;
58 import android.os.Bundle;
59 import android.os.Handler;
60 import android.os.IBinder;
61 import android.os.Looper;
62 import android.os.PatternMatcher;
63 import android.os.RemoteException;
64 import android.os.SystemClock;
65 import android.os.UserHandle;
66 import android.util.Log;
67 import android.view.InputDevice;
68 import android.view.KeyCharacterMap;
69 import android.view.KeyEvent;
70 import android.view.MotionEvent;
71 import android.view.Surface;
72 import android.view.accessibility.AccessibilityManager;
73 import android.view.inputmethod.InputMethodManager;
74 
75 import androidx.annotation.NonNull;
76 
77 import com.android.internal.accessibility.dialog.AccessibilityButtonChooserActivity;
78 import com.android.internal.annotations.VisibleForTesting;
79 import com.android.internal.logging.UiEventLogger;
80 import com.android.internal.policy.ScreenDecorationsUtils;
81 import com.android.internal.util.ScreenshotHelper;
82 import com.android.systemui.Dumpable;
83 import com.android.systemui.broadcast.BroadcastDispatcher;
84 import com.android.systemui.dagger.SysUISingleton;
85 import com.android.systemui.dump.DumpManager;
86 import com.android.systemui.keyguard.ScreenLifecycle;
87 import com.android.systemui.model.SysUiState;
88 import com.android.systemui.navigationbar.NavigationBar;
89 import com.android.systemui.navigationbar.NavigationBarController;
90 import com.android.systemui.navigationbar.NavigationBarView;
91 import com.android.systemui.navigationbar.NavigationModeController;
92 import com.android.systemui.navigationbar.buttons.KeyButtonView;
93 import com.android.systemui.recents.OverviewProxyService.OverviewProxyListener;
94 import com.android.systemui.settings.CurrentUserTracker;
95 import com.android.systemui.shared.recents.IOverviewProxy;
96 import com.android.systemui.shared.recents.ISystemUiProxy;
97 import com.android.systemui.shared.recents.model.Task;
98 import com.android.systemui.shared.system.ActivityManagerWrapper;
99 import com.android.systemui.shared.system.QuickStepContract;
100 import com.android.systemui.shared.system.smartspace.SmartspaceTransitionController;
101 import com.android.systemui.statusbar.CommandQueue;
102 import com.android.systemui.statusbar.NotificationShadeWindowController;
103 import com.android.systemui.statusbar.phone.NotificationPanelViewController;
104 import com.android.systemui.statusbar.phone.StatusBar;
105 import com.android.systemui.statusbar.phone.StatusBarWindowCallback;
106 import com.android.systemui.statusbar.policy.CallbackController;
107 import com.android.wm.shell.legacysplitscreen.LegacySplitScreen;
108 import com.android.wm.shell.onehanded.OneHanded;
109 import com.android.wm.shell.pip.Pip;
110 import com.android.wm.shell.pip.PipAnimationController;
111 import com.android.wm.shell.recents.RecentTasks;
112 import com.android.wm.shell.splitscreen.SplitScreen;
113 import com.android.wm.shell.startingsurface.StartingSurface;
114 import com.android.wm.shell.transition.ShellTransitions;
115 
116 import java.io.FileDescriptor;
117 import java.io.PrintWriter;
118 import java.util.ArrayList;
119 import java.util.List;
120 import java.util.Optional;
121 import java.util.function.BiConsumer;
122 import java.util.function.Supplier;
123 
124 import javax.inject.Inject;
125 
126 import dagger.Lazy;
127 
128 
129 /**
130  * Class to send information from overview to launcher with a binder.
131  */
132 @SysUISingleton
133 public class OverviewProxyService extends CurrentUserTracker implements
134         CallbackController<OverviewProxyListener>, NavigationModeController.ModeChangedListener,
135         Dumpable {
136 
137     private static final String ACTION_QUICKSTEP = "android.intent.action.QUICKSTEP_SERVICE";
138 
139     public static final String TAG_OPS = "OverviewProxyService";
140     private static final long BACKOFF_MILLIS = 1000;
141     private static final long DEFERRED_CALLBACK_MILLIS = 5000;
142 
143     // Max backoff caps at 5 mins
144     private static final long MAX_BACKOFF_MILLIS = 10 * 60 * 1000;
145 
146     private final Context mContext;
147     private final Optional<Pip> mPipOptional;
148     private final Lazy<Optional<StatusBar>> mStatusBarOptionalLazy;
149     private final Optional<LegacySplitScreen> mLegacySplitScreenOptional;
150     private final Optional<SplitScreen> mSplitScreenOptional;
151     private SysUiState mSysUiState;
152     private final Handler mHandler;
153     private final Lazy<NavigationBarController> mNavBarControllerLazy;
154     private final NotificationShadeWindowController mStatusBarWinController;
155     private final Runnable mConnectionRunnable = this::internalConnectToCurrentUser;
156     private final ComponentName mRecentsComponentName;
157     private final List<OverviewProxyListener> mConnectionCallbacks = new ArrayList<>();
158     private final Intent mQuickStepIntent;
159     private final ScreenshotHelper mScreenshotHelper;
160     private final Optional<OneHanded> mOneHandedOptional;
161     private final CommandQueue mCommandQueue;
162     private final ShellTransitions mShellTransitions;
163     private final Optional<StartingSurface> mStartingSurface;
164     private final SmartspaceTransitionController mSmartspaceTransitionController;
165     private final Optional<RecentTasks> mRecentTasks;
166     private final UiEventLogger mUiEventLogger;
167 
168     private Region mActiveNavBarRegion;
169 
170     private IOverviewProxy mOverviewProxy;
171     private int mConnectionBackoffAttempts;
172     private boolean mBound;
173     private boolean mIsEnabled;
174     private int mCurrentBoundedUserId = -1;
175     private float mNavBarButtonAlpha;
176     private boolean mInputFocusTransferStarted;
177     private float mInputFocusTransferStartY;
178     private long mInputFocusTransferStartMillis;
179     private float mWindowCornerRadius;
180     private boolean mSupportsRoundedCornersOnWindows;
181     private int mNavBarMode = NAV_BAR_MODE_3BUTTON;
182 
183     @VisibleForTesting
184     public ISystemUiProxy mSysUiProxy = new ISystemUiProxy.Stub() {
185         @Override
186         public void startScreenPinning(int taskId) {
187             verifyCallerAndClearCallingIdentityPostMain("startScreenPinning", () ->
188                     mStatusBarOptionalLazy.get().ifPresent(
189                             statusBar -> statusBar.showScreenPinningRequest(taskId,
190                                     false /* allowCancel */)));
191         }
192 
193         @Override
194         public void stopScreenPinning() {
195             verifyCallerAndClearCallingIdentityPostMain("stopScreenPinning", () -> {
196                 try {
197                     ActivityTaskManager.getService().stopSystemLockTaskMode();
198                 } catch (RemoteException e) {
199                     Log.e(TAG_OPS, "Failed to stop screen pinning");
200                 }
201             });
202         }
203 
204         // TODO: change the method signature to use (boolean inputFocusTransferStarted)
205         @Override
206         public void onStatusBarMotionEvent(MotionEvent event) {
207             verifyCallerAndClearCallingIdentity("onStatusBarMotionEvent", () -> {
208                 // TODO move this logic to message queue
209                 mStatusBarOptionalLazy.get().ifPresent(statusBar -> {
210                     if (event.getActionMasked() == ACTION_DOWN) {
211                         statusBar.getPanelController().startExpandLatencyTracking();
212                     }
213                     mHandler.post(() -> {
214                         int action = event.getActionMasked();
215                         if (action == ACTION_DOWN) {
216                             mInputFocusTransferStarted = true;
217                             mInputFocusTransferStartY = event.getY();
218                             mInputFocusTransferStartMillis = event.getEventTime();
219                             statusBar.onInputFocusTransfer(
220                                     mInputFocusTransferStarted, false /* cancel */,
221                                     0 /* velocity */);
222                         }
223                         if (action == ACTION_UP || action == ACTION_CANCEL) {
224                             mInputFocusTransferStarted = false;
225                             float velocity = (event.getY() - mInputFocusTransferStartY)
226                                     / (event.getEventTime() - mInputFocusTransferStartMillis);
227                             statusBar.onInputFocusTransfer(mInputFocusTransferStarted,
228                                     action == ACTION_CANCEL,
229                                     velocity);
230                         }
231                         event.recycle();
232                     });
233                 });
234             });
235         }
236 
237         @Override
238         public void onBackPressed() throws RemoteException {
239             verifyCallerAndClearCallingIdentityPostMain("onBackPressed", () -> {
240                 sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_BACK);
241                 sendEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_BACK);
242 
243                 notifyBackAction(true, -1, -1, true, false);
244             });
245         }
246 
247         @Override
248         public void onImeSwitcherPressed() throws RemoteException {
249             // TODO(b/204901476) We're intentionally using DEFAULT_DISPLAY for now since
250             // Launcher/Taskbar isn't display aware.
251             mContext.getSystemService(InputMethodManager.class)
252                     .showInputMethodPickerFromSystem(true /* showAuxiliarySubtypes */,
253                             DEFAULT_DISPLAY);
254             mUiEventLogger.log(KeyButtonView.NavBarButtonEvent.NAVBAR_IME_SWITCHER_BUTTON_TAP);
255         }
256 
257         @Override
258         public void setHomeRotationEnabled(boolean enabled) {
259             verifyCallerAndClearCallingIdentityPostMain("setHomeRotationEnabled", () ->
260                     mHandler.post(() -> notifyHomeRotationEnabled(enabled)));
261         }
262 
263         @Override
264         public void notifyTaskbarStatus(boolean visible, boolean stashed) {
265             verifyCallerAndClearCallingIdentityPostMain("notifyTaskbarStatus", () ->
266                     onTaskbarStatusUpdated(visible, stashed));
267         }
268 
269         @Override
270         public void notifyTaskbarAutohideSuspend(boolean suspend) {
271             verifyCallerAndClearCallingIdentityPostMain("notifyTaskbarAutohideSuspend", () ->
272                     onTaskbarAutohideSuspend(suspend));
273         }
274 
275         private boolean sendEvent(int action, int code) {
276             long when = SystemClock.uptimeMillis();
277             final KeyEvent ev = new KeyEvent(when, when, action, code, 0 /* repeat */,
278                     0 /* metaState */, KeyCharacterMap.VIRTUAL_KEYBOARD, 0 /* scancode */,
279                     KeyEvent.FLAG_FROM_SYSTEM | KeyEvent.FLAG_VIRTUAL_HARD_KEY,
280                     InputDevice.SOURCE_KEYBOARD);
281 
282             ev.setDisplayId(mContext.getDisplay().getDisplayId());
283             return InputManager.getInstance()
284                     .injectInputEvent(ev, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC);
285         }
286 
287         @Override
288         public void onOverviewShown(boolean fromHome) {
289             verifyCallerAndClearCallingIdentityPostMain("onOverviewShown", () -> {
290                 for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
291                     mConnectionCallbacks.get(i).onOverviewShown(fromHome);
292                 }
293             });
294         }
295 
296         @Override
297         public Rect getNonMinimizedSplitScreenSecondaryBounds() {
298             return verifyCallerAndClearCallingIdentity(
299                     "getNonMinimizedSplitScreenSecondaryBounds",
300                     () -> mLegacySplitScreenOptional.map(splitScreen ->
301                             splitScreen
302                                     .getDividerView()
303                                     .getNonMinimizedSplitScreenSecondaryBounds())
304                             .orElse(null)
305             );
306         }
307 
308         @Override
309         public void setNavBarButtonAlpha(float alpha, boolean animate) {
310             verifyCallerAndClearCallingIdentityPostMain("setNavBarButtonAlpha", () ->
311                     notifyNavBarButtonAlphaChanged(alpha, animate));
312         }
313 
314         @Override
315         public void onAssistantProgress(@FloatRange(from = 0.0, to = 1.0) float progress) {
316             verifyCallerAndClearCallingIdentityPostMain("onAssistantProgress", () ->
317                     notifyAssistantProgress(progress));
318         }
319 
320         @Override
321         public void onAssistantGestureCompletion(float velocity) {
322             verifyCallerAndClearCallingIdentityPostMain("onAssistantGestureCompletion", () ->
323                     notifyAssistantGestureCompletion(velocity));
324         }
325 
326         @Override
327         public void startAssistant(Bundle bundle) {
328             verifyCallerAndClearCallingIdentityPostMain("startAssistant", () ->
329                     notifyStartAssistant(bundle));
330         }
331 
332         @Override
333         public void notifyAccessibilityButtonClicked(int displayId) {
334             verifyCallerAndClearCallingIdentity("notifyAccessibilityButtonClicked", () ->
335                     AccessibilityManager.getInstance(mContext)
336                             .notifyAccessibilityButtonClicked(displayId));
337         }
338 
339         @Override
340         public void notifyAccessibilityButtonLongClicked() {
341             verifyCallerAndClearCallingIdentity("notifyAccessibilityButtonLongClicked",
342                     () -> {
343                         final Intent intent =
344                                 new Intent(AccessibilityManager.ACTION_CHOOSE_ACCESSIBILITY_BUTTON);
345                         final String chooserClassName = AccessibilityButtonChooserActivity
346                                 .class.getName();
347                         intent.setClassName(CHOOSER_PACKAGE_NAME, chooserClassName);
348                         intent.addFlags(
349                                 Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
350                         mContext.startActivityAsUser(intent, UserHandle.CURRENT);
351                     });
352         }
353 
354         @Override
355         public void handleImageAsScreenshot(Bitmap screenImage, Rect locationInScreen,
356                                             Insets visibleInsets, int taskId) {
357             // Deprecated
358         }
359 
360         @Override
361         public void setSplitScreenMinimized(boolean minimized) {
362             mLegacySplitScreenOptional.ifPresent(
363                     splitScreen -> splitScreen.setMinimized(minimized));
364         }
365 
366         @Override
367         public void notifySwipeToHomeFinished() {
368             verifyCallerAndClearCallingIdentity("notifySwipeToHomeFinished", () ->
369                     mPipOptional.ifPresent(
370                             pip -> pip.setPinnedStackAnimationType(
371                                     PipAnimationController.ANIM_TYPE_ALPHA)));
372         }
373 
374         @Override
375         public void notifySwipeUpGestureStarted() {
376             verifyCallerAndClearCallingIdentityPostMain("notifySwipeUpGestureStarted", () ->
377                     notifySwipeUpGestureStartedInternal());
378         }
379 
380         @Override
381         public void notifyPrioritizedRotation(@Surface.Rotation int rotation) {
382             verifyCallerAndClearCallingIdentityPostMain("notifyPrioritizedRotation", () ->
383                     notifyPrioritizedRotationInternal(rotation));
384         }
385 
386         @Override
387         public void handleImageBundleAsScreenshot(Bundle screenImageBundle, Rect locationInScreen,
388                 Insets visibleInsets, Task.TaskKey task) {
389             mScreenshotHelper.provideScreenshot(
390                     screenImageBundle,
391                     locationInScreen,
392                     visibleInsets,
393                     task.id,
394                     task.userId,
395                     task.sourceComponent,
396                     SCREENSHOT_OVERVIEW,
397                     mHandler,
398                     null);
399         }
400 
401         @Override
402         public void expandNotificationPanel() {
403             verifyCallerAndClearCallingIdentity("expandNotificationPanel",
404                     () -> mCommandQueue.handleSystemKey(KeyEvent.KEYCODE_SYSTEM_NAVIGATION_DOWN));
405         }
406 
407         private boolean verifyCaller(String reason) {
408             final int callerId = Binder.getCallingUserHandle().getIdentifier();
409             if (callerId != mCurrentBoundedUserId) {
410                 Log.w(TAG_OPS, "Launcher called sysui with invalid user: " + callerId + ", reason: "
411                         + reason);
412                 return false;
413             }
414             return true;
415         }
416 
417         private <T> T verifyCallerAndClearCallingIdentity(String reason, Supplier<T> supplier) {
418             if (!verifyCaller(reason)) {
419                 return null;
420             }
421             final long token = Binder.clearCallingIdentity();
422             try {
423                 return supplier.get();
424             } finally {
425                 Binder.restoreCallingIdentity(token);
426             }
427         }
428 
429         private void verifyCallerAndClearCallingIdentity(String reason, Runnable runnable) {
430             verifyCallerAndClearCallingIdentity(reason, () -> {
431                 runnable.run();
432                 return null;
433             });
434         }
435 
436         private void verifyCallerAndClearCallingIdentityPostMain(String reason, Runnable runnable) {
437             verifyCallerAndClearCallingIdentity(reason, () -> mHandler.post(runnable));
438         }
439     };
440 
441     private final Runnable mDeferredConnectionCallback = () -> {
442         Log.w(TAG_OPS, "Binder supposed established connection but actual connection to service "
443             + "timed out, trying again");
444         retryConnectionWithBackoff();
445     };
446 
447     private final BroadcastReceiver mLauncherStateChangedReceiver = new BroadcastReceiver() {
448         @Override
449         public void onReceive(Context context, Intent intent) {
450             updateEnabledState();
451 
452             // Reconnect immediately, instead of waiting for resume to arrive.
453             startConnectionToCurrentUser();
454         }
455     };
456 
457     private final ServiceConnection mOverviewServiceConnection = new ServiceConnection() {
458         @Override
459         public void onServiceConnected(ComponentName name, IBinder service) {
460             if (SysUiState.DEBUG) {
461                 Log.d(TAG_OPS, "Overview proxy service connected");
462             }
463             mConnectionBackoffAttempts = 0;
464             mHandler.removeCallbacks(mDeferredConnectionCallback);
465             try {
466                 service.linkToDeath(mOverviewServiceDeathRcpt, 0);
467             } catch (RemoteException e) {
468                 // Failed to link to death (process may have died between binding and connecting),
469                 // just unbind the service for now and retry again
470                 Log.e(TAG_OPS, "Lost connection to launcher service", e);
471                 disconnectFromLauncherService();
472                 retryConnectionWithBackoff();
473                 return;
474             }
475 
476             mCurrentBoundedUserId = getCurrentUserId();
477             mOverviewProxy = IOverviewProxy.Stub.asInterface(service);
478 
479             Bundle params = new Bundle();
480             params.putBinder(KEY_EXTRA_SYSUI_PROXY, mSysUiProxy.asBinder());
481             params.putFloat(KEY_EXTRA_WINDOW_CORNER_RADIUS, mWindowCornerRadius);
482             params.putBoolean(KEY_EXTRA_SUPPORTS_WINDOW_CORNERS, mSupportsRoundedCornersOnWindows);
483 
484             mPipOptional.ifPresent((pip) -> params.putBinder(
485                     KEY_EXTRA_SHELL_PIP,
486                     pip.createExternalInterface().asBinder()));
487             mSplitScreenOptional.ifPresent((splitscreen) -> params.putBinder(
488                     KEY_EXTRA_SHELL_SPLIT_SCREEN,
489                     splitscreen.createExternalInterface().asBinder()));
490             mOneHandedOptional.ifPresent((onehanded) -> params.putBinder(
491                     KEY_EXTRA_SHELL_ONE_HANDED,
492                     onehanded.createExternalInterface().asBinder()));
493             params.putBinder(KEY_EXTRA_SHELL_SHELL_TRANSITIONS,
494                     mShellTransitions.createExternalInterface().asBinder());
495             mStartingSurface.ifPresent((startingwindow) -> params.putBinder(
496                     KEY_EXTRA_SHELL_STARTING_WINDOW,
497                     startingwindow.createExternalInterface().asBinder()));
498             params.putBinder(
499                     KEY_EXTRA_SMARTSPACE_TRANSITION_CONTROLLER,
500                     mSmartspaceTransitionController.createExternalInterface().asBinder());
501             mRecentTasks.ifPresent(recentTasks -> params.putBinder(
502                     KEY_EXTRA_RECENT_TASKS,
503                     recentTasks.createExternalInterface().asBinder()));
504 
505             try {
506                 mOverviewProxy.onInitialize(params);
507             } catch (RemoteException e) {
508                 mCurrentBoundedUserId = -1;
509                 Log.e(TAG_OPS, "Failed to call onInitialize()", e);
510             }
511             dispatchNavButtonBounds();
512 
513             // Force-update the systemui state flags
514             updateSystemUiStateFlags();
515             notifySystemUiStateFlags(mSysUiState.getFlags());
516 
517             notifyConnectionChanged();
518         }
519 
520         @Override
521         public void onNullBinding(ComponentName name) {
522             Log.w(TAG_OPS, "Null binding of '" + name + "', try reconnecting");
523             mCurrentBoundedUserId = -1;
524             retryConnectionWithBackoff();
525         }
526 
527         @Override
528         public void onBindingDied(ComponentName name) {
529             Log.w(TAG_OPS, "Binding died of '" + name + "', try reconnecting");
530             mCurrentBoundedUserId = -1;
531             retryConnectionWithBackoff();
532         }
533 
534         @Override
535         public void onServiceDisconnected(ComponentName name) {
536             Log.w(TAG_OPS, "Service disconnected");
537             // Do nothing
538             mCurrentBoundedUserId = -1;
539         }
540     };
541 
542     private final StatusBarWindowCallback mStatusBarWindowCallback = this::onStatusBarStateChanged;
543     private final BiConsumer<Rect, Rect> mSplitScreenBoundsChangeListener =
544             this::notifySplitScreenBoundsChanged;
545 
546     // This is the death handler for the binder from the launcher service
547     private final IBinder.DeathRecipient mOverviewServiceDeathRcpt
548             = this::cleanupAfterDeath;
549 
550     @SuppressWarnings("OptionalUsedAsFieldOrParameterType")
551     @Inject
OverviewProxyService(Context context, CommandQueue commandQueue, Lazy<NavigationBarController> navBarControllerLazy, Lazy<Optional<StatusBar>> statusBarOptionalLazy, NavigationModeController navModeController, NotificationShadeWindowController statusBarWinController, SysUiState sysUiState, Optional<Pip> pipOptional, Optional<LegacySplitScreen> legacySplitScreenOptional, Optional<SplitScreen> splitScreenOptional, Optional<OneHanded> oneHandedOptional, Optional<RecentTasks> recentTasks, Optional<StartingSurface> startingSurface, BroadcastDispatcher broadcastDispatcher, ShellTransitions shellTransitions, ScreenLifecycle screenLifecycle, SmartspaceTransitionController smartspaceTransitionController, UiEventLogger uiEventLogger, DumpManager dumpManager)552     public OverviewProxyService(Context context, CommandQueue commandQueue,
553             Lazy<NavigationBarController> navBarControllerLazy,
554             Lazy<Optional<StatusBar>> statusBarOptionalLazy,
555             NavigationModeController navModeController,
556             NotificationShadeWindowController statusBarWinController, SysUiState sysUiState,
557             Optional<Pip> pipOptional,
558             Optional<LegacySplitScreen> legacySplitScreenOptional,
559             Optional<SplitScreen> splitScreenOptional,
560             Optional<OneHanded> oneHandedOptional,
561             Optional<RecentTasks> recentTasks,
562             Optional<StartingSurface> startingSurface,
563             BroadcastDispatcher broadcastDispatcher,
564             ShellTransitions shellTransitions,
565             ScreenLifecycle screenLifecycle,
566             SmartspaceTransitionController smartspaceTransitionController,
567             UiEventLogger uiEventLogger,
568             DumpManager dumpManager) {
569         super(broadcastDispatcher);
570         mContext = context;
571         mPipOptional = pipOptional;
572         mStatusBarOptionalLazy = statusBarOptionalLazy;
573         mHandler = new Handler();
574         mNavBarControllerLazy = navBarControllerLazy;
575         mStatusBarWinController = statusBarWinController;
576         mConnectionBackoffAttempts = 0;
577         mRecentsComponentName = ComponentName.unflattenFromString(context.getString(
578                 com.android.internal.R.string.config_recentsComponentName));
579         mQuickStepIntent = new Intent(ACTION_QUICKSTEP)
580                 .setPackage(mRecentsComponentName.getPackageName());
581         mWindowCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(mContext);
582         mSupportsRoundedCornersOnWindows = ScreenDecorationsUtils
583                 .supportsRoundedCornersOnWindows(mContext.getResources());
584         mSysUiState = sysUiState;
585         mSysUiState.addCallback(this::notifySystemUiStateFlags);
586         mOneHandedOptional = oneHandedOptional;
587         mShellTransitions = shellTransitions;
588         mRecentTasks = recentTasks;
589         mUiEventLogger = uiEventLogger;
590 
591         // Assumes device always starts with back button until launcher tells it that it does not
592         mNavBarButtonAlpha = 1.0f;
593 
594         dumpManager.registerDumpable(getClass().getSimpleName(), this);
595 
596         // Listen for nav bar mode changes
597         mNavBarMode = navModeController.addListener(this);
598 
599         // Listen for launcher package changes
600         IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
601         filter.addDataScheme("package");
602         filter.addDataSchemeSpecificPart(mRecentsComponentName.getPackageName(),
603                 PatternMatcher.PATTERN_LITERAL);
604         filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
605         mContext.registerReceiver(mLauncherStateChangedReceiver, filter);
606 
607         // Listen for status bar state changes
608         statusBarWinController.registerCallback(mStatusBarWindowCallback);
609         mScreenshotHelper = new ScreenshotHelper(context);
610 
611         // Listen for tracing state changes
612         commandQueue.addCallback(new CommandQueue.Callbacks() {
613             @Override
614             public void onTracingStateChanged(boolean enabled) {
615                 mSysUiState.setFlag(SYSUI_STATE_TRACING_ENABLED, enabled)
616                         .commitUpdate(mContext.getDisplayId());
617             }
618         });
619         mCommandQueue = commandQueue;
620 
621         mSplitScreenOptional = splitScreenOptional;
622         legacySplitScreenOptional.ifPresent(splitScreen ->
623                 splitScreen.registerBoundsChangeListener(mSplitScreenBoundsChangeListener));
624         mLegacySplitScreenOptional = legacySplitScreenOptional;
625 
626         // Listen for user setup
627         startTracking();
628 
629         screenLifecycle.addObserver(new ScreenLifecycle.Observer() {
630             @Override
631             public void onScreenTurnedOn() {
632                 notifyScreenTurnedOn();
633             }
634         });
635 
636         // Connect to the service
637         updateEnabledState();
638         startConnectionToCurrentUser();
639         mStartingSurface = startingSurface;
640         mSmartspaceTransitionController = smartspaceTransitionController;
641     }
642 
643     @Override
onUserSwitched(int newUserId)644     public void onUserSwitched(int newUserId) {
645         mConnectionBackoffAttempts = 0;
646         internalConnectToCurrentUser();
647     }
648 
notifyBackAction(boolean completed, int downX, int downY, boolean isButton, boolean gestureSwipeLeft)649     public void notifyBackAction(boolean completed, int downX, int downY, boolean isButton,
650             boolean gestureSwipeLeft) {
651         try {
652             if (mOverviewProxy != null) {
653                 mOverviewProxy.onBackAction(completed, downX, downY, isButton, gestureSwipeLeft);
654             }
655         } catch (RemoteException e) {
656             Log.e(TAG_OPS, "Failed to notify back action", e);
657         }
658     }
659 
updateSystemUiStateFlags()660     private void updateSystemUiStateFlags() {
661         final NavigationBar navBarFragment =
662                 mNavBarControllerLazy.get().getDefaultNavigationBar();
663         final NavigationBarView navBarView =
664                 mNavBarControllerLazy.get().getNavigationBarView(mContext.getDisplayId());
665         final NotificationPanelViewController panelController =
666                 mStatusBarOptionalLazy.get().get().getPanelController();
667         if (SysUiState.DEBUG) {
668             Log.d(TAG_OPS, "Updating sysui state flags: navBarFragment=" + navBarFragment
669                     + " navBarView=" + navBarView + " panelController=" + panelController);
670         }
671 
672         if (navBarFragment != null) {
673             navBarFragment.updateSystemUiStateFlags(-1);
674         }
675         if (navBarView != null) {
676             navBarView.updateDisabledSystemUiStateFlags();
677         }
678         if (panelController != null) {
679             panelController.updateSystemUiStateFlags();
680         }
681         if (mStatusBarWinController != null) {
682             mStatusBarWinController.notifyStateChangedCallbacks();
683         }
684     }
685 
notifySystemUiStateFlags(int flags)686     private void notifySystemUiStateFlags(int flags) {
687         if (SysUiState.DEBUG) {
688             Log.d(TAG_OPS, "Notifying sysui state change to overview service: proxy="
689                     + mOverviewProxy + " flags=" + flags);
690         }
691         try {
692             if (mOverviewProxy != null) {
693                 mOverviewProxy.onSystemUiStateChanged(flags);
694             }
695         } catch (RemoteException e) {
696             Log.e(TAG_OPS, "Failed to notify sysui state change", e);
697         }
698     }
699 
onStatusBarStateChanged(boolean keyguardShowing, boolean keyguardOccluded, boolean bouncerShowing, boolean isDozing)700     private void onStatusBarStateChanged(boolean keyguardShowing, boolean keyguardOccluded,
701             boolean bouncerShowing, boolean isDozing) {
702         mSysUiState.setFlag(SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING,
703                         keyguardShowing && !keyguardOccluded)
704                 .setFlag(SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED,
705                         keyguardShowing && keyguardOccluded)
706                 .setFlag(SYSUI_STATE_BOUNCER_SHOWING, bouncerShowing)
707                 .setFlag(SYSUI_STATE_DEVICE_DOZING, isDozing)
708                 .commitUpdate(mContext.getDisplayId());
709     }
710 
711     /**
712      * Sets the navbar region which can receive touch inputs
713      */
onActiveNavBarRegionChanges(Region activeRegion)714     public void onActiveNavBarRegionChanges(Region activeRegion) {
715         mActiveNavBarRegion = activeRegion;
716         dispatchNavButtonBounds();
717     }
718 
dispatchNavButtonBounds()719     private void dispatchNavButtonBounds() {
720         if (mOverviewProxy != null && mActiveNavBarRegion != null) {
721             try {
722                 mOverviewProxy.onActiveNavBarRegionChanges(mActiveNavBarRegion);
723             } catch (RemoteException e) {
724                 Log.e(TAG_OPS, "Failed to call onActiveNavBarRegionChanges()", e);
725             }
726         }
727     }
728 
cleanupAfterDeath()729     public void cleanupAfterDeath() {
730         if (mInputFocusTransferStarted) {
731             mHandler.post(() -> {
732                 mStatusBarOptionalLazy.get().ifPresent(statusBar -> {
733                     mInputFocusTransferStarted = false;
734                     statusBar.onInputFocusTransfer(false, true /* cancel */, 0 /* velocity */);
735                 });
736             });
737         }
738         startConnectionToCurrentUser();
739 
740         // Clean up the minimized state if launcher dies
741         mLegacySplitScreenOptional.ifPresent(
742                 splitScreen -> splitScreen.setMinimized(false));
743     }
744 
startConnectionToCurrentUser()745     public void startConnectionToCurrentUser() {
746         if (mHandler.getLooper() != Looper.myLooper()) {
747             mHandler.post(mConnectionRunnable);
748         } else {
749             internalConnectToCurrentUser();
750         }
751     }
752 
internalConnectToCurrentUser()753     private void internalConnectToCurrentUser() {
754         disconnectFromLauncherService();
755 
756         // If user has not setup yet or already connected, do not try to connect
757         if (!isEnabled()) {
758             Log.v(TAG_OPS, "Cannot attempt connection, is enabled " + isEnabled());
759             return;
760         }
761         mHandler.removeCallbacks(mConnectionRunnable);
762         Intent launcherServiceIntent = new Intent(ACTION_QUICKSTEP)
763                 .setPackage(mRecentsComponentName.getPackageName());
764         try {
765             mBound = mContext.bindServiceAsUser(launcherServiceIntent,
766                     mOverviewServiceConnection,
767                     Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
768                     UserHandle.of(getCurrentUserId()));
769         } catch (SecurityException e) {
770             Log.e(TAG_OPS, "Unable to bind because of security error", e);
771         }
772         if (mBound) {
773             // Ensure that connection has been established even if it thinks it is bound
774             mHandler.postDelayed(mDeferredConnectionCallback, DEFERRED_CALLBACK_MILLIS);
775         } else {
776             // Retry after exponential backoff timeout
777             retryConnectionWithBackoff();
778         }
779     }
780 
retryConnectionWithBackoff()781     private void retryConnectionWithBackoff() {
782         if (mHandler.hasCallbacks(mConnectionRunnable)) {
783             return;
784         }
785         final long timeoutMs = (long) Math.min(
786                 Math.scalb(BACKOFF_MILLIS, mConnectionBackoffAttempts), MAX_BACKOFF_MILLIS);
787         mHandler.postDelayed(mConnectionRunnable, timeoutMs);
788         mConnectionBackoffAttempts++;
789         Log.w(TAG_OPS, "Failed to connect on attempt " + mConnectionBackoffAttempts
790                 + " will try again in " + timeoutMs + "ms");
791     }
792 
793     @Override
addCallback(@onNull OverviewProxyListener listener)794     public void addCallback(@NonNull OverviewProxyListener listener) {
795         if (!mConnectionCallbacks.contains(listener)) {
796             mConnectionCallbacks.add(listener);
797         }
798         listener.onConnectionChanged(mOverviewProxy != null);
799         listener.onNavBarButtonAlphaChanged(mNavBarButtonAlpha, false);
800     }
801 
802     @Override
removeCallback(@onNull OverviewProxyListener listener)803     public void removeCallback(@NonNull OverviewProxyListener listener) {
804         mConnectionCallbacks.remove(listener);
805     }
806 
shouldShowSwipeUpUI()807     public boolean shouldShowSwipeUpUI() {
808         return isEnabled() && !QuickStepContract.isLegacyMode(mNavBarMode);
809     }
810 
isEnabled()811     public boolean isEnabled() {
812         return mIsEnabled;
813     }
814 
getProxy()815     public IOverviewProxy getProxy() {
816         return mOverviewProxy;
817     }
818 
disconnectFromLauncherService()819     private void disconnectFromLauncherService() {
820         if (mBound) {
821             // Always unbind the service (ie. if called through onNullBinding or onBindingDied)
822             mContext.unbindService(mOverviewServiceConnection);
823             mBound = false;
824         }
825 
826         if (mOverviewProxy != null) {
827             mOverviewProxy.asBinder().unlinkToDeath(mOverviewServiceDeathRcpt, 0);
828             mOverviewProxy = null;
829             notifyNavBarButtonAlphaChanged(1f, false /* animate */);
830             notifyConnectionChanged();
831         }
832     }
833 
notifyNavBarButtonAlphaChanged(float alpha, boolean animate)834     private void notifyNavBarButtonAlphaChanged(float alpha, boolean animate) {
835         for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
836             mConnectionCallbacks.get(i).onNavBarButtonAlphaChanged(alpha, animate);
837         }
838     }
839 
notifyHomeRotationEnabled(boolean enabled)840     private void notifyHomeRotationEnabled(boolean enabled) {
841         for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
842             mConnectionCallbacks.get(i).onHomeRotationEnabled(enabled);
843         }
844     }
845 
onTaskbarStatusUpdated(boolean visible, boolean stashed)846     private void onTaskbarStatusUpdated(boolean visible, boolean stashed) {
847         for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
848             mConnectionCallbacks.get(i).onTaskbarStatusUpdated(visible, stashed);
849         }
850     }
851 
onTaskbarAutohideSuspend(boolean suspend)852     private void onTaskbarAutohideSuspend(boolean suspend) {
853         for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
854             mConnectionCallbacks.get(i).onTaskbarAutohideSuspend(suspend);
855         }
856     }
857 
notifyConnectionChanged()858     private void notifyConnectionChanged() {
859         for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
860             mConnectionCallbacks.get(i).onConnectionChanged(mOverviewProxy != null);
861         }
862     }
863 
notifyQuickStepStarted()864     public void notifyQuickStepStarted() {
865         for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
866             mConnectionCallbacks.get(i).onQuickStepStarted();
867         }
868     }
869 
notifyPrioritizedRotationInternal(@urface.Rotation int rotation)870     private void notifyPrioritizedRotationInternal(@Surface.Rotation int rotation) {
871         for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
872             mConnectionCallbacks.get(i).onPrioritizedRotation(rotation);
873         }
874     }
875 
notifyQuickScrubStarted()876     public void notifyQuickScrubStarted() {
877         for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
878             mConnectionCallbacks.get(i).onQuickScrubStarted();
879         }
880     }
881 
notifyAssistantProgress(@loatRangefrom = 0.0, to = 1.0) float progress)882     private void notifyAssistantProgress(@FloatRange(from = 0.0, to = 1.0) float progress) {
883         for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
884             mConnectionCallbacks.get(i).onAssistantProgress(progress);
885         }
886     }
887 
notifyAssistantGestureCompletion(float velocity)888     private void notifyAssistantGestureCompletion(float velocity) {
889         for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
890             mConnectionCallbacks.get(i).onAssistantGestureCompletion(velocity);
891         }
892     }
893 
notifyStartAssistant(Bundle bundle)894     private void notifyStartAssistant(Bundle bundle) {
895         for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
896             mConnectionCallbacks.get(i).startAssistant(bundle);
897         }
898     }
899 
notifySwipeUpGestureStartedInternal()900     private void notifySwipeUpGestureStartedInternal() {
901         for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
902             mConnectionCallbacks.get(i).onSwipeUpGestureStarted();
903         }
904     }
905 
notifyAssistantVisibilityChanged(float visibility)906     public void notifyAssistantVisibilityChanged(float visibility) {
907         try {
908             if (mOverviewProxy != null) {
909                 mOverviewProxy.onAssistantVisibilityChanged(visibility);
910             } else {
911                 Log.e(TAG_OPS, "Failed to get overview proxy for assistant visibility.");
912             }
913         } catch (RemoteException e) {
914             Log.e(TAG_OPS, "Failed to call notifyAssistantVisibilityChanged()", e);
915         }
916     }
917 
918     /**
919      * Notifies the Launcher of split screen size changes
920      *
921      * @param secondaryWindowBounds Bounds of the secondary window including the insets
922      * @param secondaryWindowInsets stable insets received by the secondary window
923      */
notifySplitScreenBoundsChanged( Rect secondaryWindowBounds, Rect secondaryWindowInsets)924     public void notifySplitScreenBoundsChanged(
925             Rect secondaryWindowBounds, Rect secondaryWindowInsets) {
926         try {
927             if (mOverviewProxy != null) {
928                 mOverviewProxy.onSplitScreenSecondaryBoundsChanged(
929                         secondaryWindowBounds, secondaryWindowInsets);
930             } else {
931                 Log.e(TAG_OPS, "Failed to get overview proxy for split screen bounds.");
932             }
933         } catch (RemoteException e) {
934             Log.e(TAG_OPS, "Failed to call onSplitScreenSecondaryBoundsChanged()", e);
935         }
936     }
937 
938     /**
939      * Notifies the Launcher that screen turned on and ready to use
940      */
notifyScreenTurnedOn()941     public void notifyScreenTurnedOn() {
942         try {
943             if (mOverviewProxy != null) {
944                 mOverviewProxy.onScreenTurnedOn();
945             } else {
946                 Log.e(TAG_OPS, "Failed to get overview proxy for screen turned on event.");
947             }
948         } catch (RemoteException e) {
949             Log.e(TAG_OPS, "Failed to call notifyScreenTurnedOn()", e);
950         }
951     }
952 
notifyToggleRecentApps()953     void notifyToggleRecentApps() {
954         for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
955             mConnectionCallbacks.get(i).onToggleRecentApps();
956         }
957     }
958 
disable(int displayId, int state1, int state2, boolean animate)959     public void disable(int displayId, int state1, int state2, boolean animate) {
960         try {
961             if (mOverviewProxy != null) {
962                 mOverviewProxy.disable(displayId, state1, state2, animate);
963             } else {
964                 Log.e(TAG_OPS, "Failed to get overview proxy for disable flags.");
965             }
966         } catch (RemoteException e) {
967             Log.e(TAG_OPS, "Failed to call disable()", e);
968         }
969     }
970 
onRotationProposal(int rotation, boolean isValid)971     public void onRotationProposal(int rotation, boolean isValid) {
972         try {
973             if (mOverviewProxy != null) {
974                 mOverviewProxy.onRotationProposal(rotation, isValid);
975             } else {
976                 Log.e(TAG_OPS, "Failed to get overview proxy for proposing rotation.");
977             }
978         } catch (RemoteException e) {
979             Log.e(TAG_OPS, "Failed to call onRotationProposal()", e);
980         }
981     }
982 
onSystemBarAttributesChanged(int displayId, int behavior)983     public void onSystemBarAttributesChanged(int displayId, int behavior) {
984         try {
985             if (mOverviewProxy != null) {
986                 mOverviewProxy.onSystemBarAttributesChanged(displayId, behavior);
987             } else {
988                 Log.e(TAG_OPS, "Failed to get overview proxy for system bar attr change.");
989             }
990         } catch (RemoteException e) {
991             Log.e(TAG_OPS, "Failed to call onSystemBarAttributesChanged()", e);
992         }
993     }
994 
onNavButtonsDarkIntensityChanged(float darkIntensity)995     public void onNavButtonsDarkIntensityChanged(float darkIntensity) {
996         try {
997             if (mOverviewProxy != null) {
998                 mOverviewProxy.onNavButtonsDarkIntensityChanged(darkIntensity);
999             } else {
1000                 Log.e(TAG_OPS, "Failed to get overview proxy to update nav buttons dark intensity");
1001             }
1002         } catch (RemoteException e) {
1003             Log.e(TAG_OPS, "Failed to call onNavButtonsDarkIntensityChanged()", e);
1004         }
1005     }
1006 
updateEnabledState()1007     private void updateEnabledState() {
1008         final int currentUser = ActivityManagerWrapper.getInstance().getCurrentUserId();
1009         mIsEnabled = mContext.getPackageManager().resolveServiceAsUser(mQuickStepIntent,
1010                 MATCH_SYSTEM_ONLY, currentUser) != null;
1011     }
1012 
1013     @Override
onNavigationModeChanged(int mode)1014     public void onNavigationModeChanged(int mode) {
1015         mNavBarMode = mode;
1016     }
1017 
1018     @Override
dump(FileDescriptor fd, PrintWriter pw, String[] args)1019     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
1020         pw.println(TAG_OPS + " state:");
1021         pw.print("  isConnected="); pw.println(mOverviewProxy != null);
1022         pw.print("  mIsEnabled="); pw.println(isEnabled());
1023         pw.print("  mRecentsComponentName="); pw.println(mRecentsComponentName);
1024         pw.print("  mQuickStepIntent="); pw.println(mQuickStepIntent);
1025         pw.print("  mBound="); pw.println(mBound);
1026         pw.print("  mCurrentBoundedUserId="); pw.println(mCurrentBoundedUserId);
1027         pw.print("  mConnectionBackoffAttempts="); pw.println(mConnectionBackoffAttempts);
1028         pw.print("  mInputFocusTransferStarted="); pw.println(mInputFocusTransferStarted);
1029         pw.print("  mInputFocusTransferStartY="); pw.println(mInputFocusTransferStartY);
1030         pw.print("  mInputFocusTransferStartMillis="); pw.println(mInputFocusTransferStartMillis);
1031         pw.print("  mWindowCornerRadius="); pw.println(mWindowCornerRadius);
1032         pw.print("  mSupportsRoundedCornersOnWindows="); pw.println(mSupportsRoundedCornersOnWindows);
1033         pw.print("  mNavBarButtonAlpha="); pw.println(mNavBarButtonAlpha);
1034         pw.print("  mActiveNavBarRegion="); pw.println(mActiveNavBarRegion);
1035         pw.print("  mNavBarMode="); pw.println(mNavBarMode);
1036         mSysUiState.dump(fd, pw, args);
1037     }
1038 
1039     public interface OverviewProxyListener {
onConnectionChanged(boolean isConnected)1040         default void onConnectionChanged(boolean isConnected) {}
onQuickStepStarted()1041         default void onQuickStepStarted() {}
onSwipeUpGestureStarted()1042         default void onSwipeUpGestureStarted() {}
onPrioritizedRotation(@urface.Rotation int rotation)1043         default void onPrioritizedRotation(@Surface.Rotation int rotation) {}
onOverviewShown(boolean fromHome)1044         default void onOverviewShown(boolean fromHome) {}
onQuickScrubStarted()1045         default void onQuickScrubStarted() {}
1046         /** Notify the recents app (overview) is started by 3-button navigation. */
onToggleRecentApps()1047         default void onToggleRecentApps() {}
1048         /** Notify changes in the nav bar button alpha */
onNavBarButtonAlphaChanged(float alpha, boolean animate)1049         default void onNavBarButtonAlphaChanged(float alpha, boolean animate) {}
onHomeRotationEnabled(boolean enabled)1050         default void onHomeRotationEnabled(boolean enabled) {}
onTaskbarStatusUpdated(boolean visible, boolean stashed)1051         default void onTaskbarStatusUpdated(boolean visible, boolean stashed) {}
onTaskbarAutohideSuspend(boolean suspend)1052         default void onTaskbarAutohideSuspend(boolean suspend) {}
onSystemUiStateChanged(int sysuiStateFlags)1053         default void onSystemUiStateChanged(int sysuiStateFlags) {}
onAssistantProgress(@loatRangefrom = 0.0, to = 1.0) float progress)1054         default void onAssistantProgress(@FloatRange(from = 0.0, to = 1.0) float progress) {}
onAssistantGestureCompletion(float velocity)1055         default void onAssistantGestureCompletion(float velocity) {}
startAssistant(Bundle bundle)1056         default void startAssistant(Bundle bundle) {}
1057     }
1058 }
1059