• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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 package com.android.launcher3.uioverrides;
17 
18 import static android.app.ActivityTaskManager.INVALID_TASK_ID;
19 import static android.os.Trace.TRACE_TAG_APP;
20 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_OPTIMIZE_MEASURE;
21 import static android.view.accessibility.AccessibilityEvent.TYPE_VIEW_FOCUSED;
22 import static android.window.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY;
23 
24 import static com.android.app.animation.Interpolators.EMPHASIZED;
25 import static com.android.internal.jank.Cuj.CUJ_LAUNCHER_LAUNCH_APP_PAIR_FROM_WORKSPACE;
26 import static com.android.launcher3.Flags.enableExpressiveDismissTaskMotion;
27 import static com.android.launcher3.Flags.enableUnfoldStateAnimation;
28 import static com.android.launcher3.LauncherConstants.SavedInstanceKeys.PENDING_SPLIT_SELECT_INFO;
29 import static com.android.launcher3.LauncherConstants.SavedInstanceKeys.RUNTIME_STATE;
30 import static com.android.launcher3.LauncherSettings.Animation.DEFAULT_NO_ICON;
31 import static com.android.launcher3.LauncherSettings.Animation.VIEW_BACKGROUND;
32 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT;
33 import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
34 import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT;
35 import static com.android.launcher3.LauncherState.ALL_APPS;
36 import static com.android.launcher3.LauncherState.NORMAL;
37 import static com.android.launcher3.LauncherState.NO_OFFSET;
38 import static com.android.launcher3.LauncherState.OVERVIEW;
39 import static com.android.launcher3.LauncherState.OVERVIEW_MODAL_TASK;
40 import static com.android.launcher3.LauncherState.OVERVIEW_SPLIT_SELECT;
41 import static com.android.launcher3.Utilities.isRtl;
42 import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent;
43 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_LAUNCH_TAP;
44 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SPLIT_SELECTION_EXIT_HOME;
45 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SPLIT_SELECTION_EXIT_INTERRUPTED;
46 import static com.android.launcher3.popup.QuickstepSystemShortcut.getSplitSelectShortcutByPosition;
47 import static com.android.launcher3.popup.SystemShortcut.APP_INFO;
48 import static com.android.launcher3.popup.SystemShortcut.BUBBLE_SHORTCUT;
49 import static com.android.launcher3.popup.SystemShortcut.DONT_SUGGEST_APP;
50 import static com.android.launcher3.popup.SystemShortcut.INSTALL;
51 import static com.android.launcher3.popup.SystemShortcut.PRIVATE_PROFILE_INSTALL;
52 import static com.android.launcher3.popup.SystemShortcut.UNINSTALL_APP;
53 import static com.android.launcher3.popup.SystemShortcut.WIDGETS;
54 import static com.android.launcher3.taskbar.LauncherTaskbarUIController.ALL_APPS_PAGE_PROGRESS_INDEX;
55 import static com.android.launcher3.taskbar.LauncherTaskbarUIController.MINUS_ONE_PAGE_PROGRESS_INDEX;
56 import static com.android.launcher3.taskbar.LauncherTaskbarUIController.WIDGETS_PAGE_PROGRESS_INDEX;
57 import static com.android.launcher3.testing.shared.TestProtocol.HINT_STATE_ORDINAL;
58 import static com.android.launcher3.testing.shared.TestProtocol.HINT_STATE_TWO_BUTTON_ORDINAL;
59 import static com.android.launcher3.testing.shared.TestProtocol.OVERVIEW_STATE_ORDINAL;
60 import static com.android.launcher3.testing.shared.TestProtocol.QUICK_SWITCH_STATE_ORDINAL;
61 import static com.android.launcher3.util.DisplayController.CHANGE_ACTIVE_SCREEN;
62 import static com.android.launcher3.util.DisplayController.CHANGE_NAVIGATION_MODE;
63 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
64 import static com.android.quickstep.util.AnimUtils.completeRunnableListCallback;
65 import static com.android.quickstep.util.SplitAnimationTimings.TABLET_HOME_TO_SPLIT;
66 import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_HOME_KEY;
67 
68 import android.animation.Animator;
69 import android.animation.AnimatorListenerAdapter;
70 import android.animation.AnimatorSet;
71 import android.app.ActivityOptions;
72 import android.content.Context;
73 import android.content.Intent;
74 import android.content.IntentSender;
75 import android.content.pm.ShortcutInfo;
76 import android.content.res.Configuration;
77 import android.graphics.Rect;
78 import android.graphics.RectF;
79 import android.hardware.display.DisplayManager;
80 import android.media.permission.SafeCloseable;
81 import android.os.Build;
82 import android.os.Bundle;
83 import android.os.IRemoteCallback;
84 import android.os.SystemProperties;
85 import android.os.Trace;
86 import android.os.UserHandle;
87 import android.text.TextUtils;
88 import android.util.AttributeSet;
89 import android.view.Display;
90 import android.view.HapticFeedbackConstants;
91 import android.view.KeyEvent;
92 import android.view.View;
93 import android.widget.AnalogClock;
94 import android.widget.TextClock;
95 import android.window.BackEvent;
96 import android.window.OnBackAnimationCallback;
97 import android.window.OnBackInvokedDispatcher;
98 import android.window.RemoteTransition;
99 import android.window.SplashScreen;
100 
101 import androidx.annotation.BinderThread;
102 import androidx.annotation.NonNull;
103 import androidx.annotation.Nullable;
104 import androidx.annotation.RequiresApi;
105 
106 import com.android.app.viewcapture.ViewCaptureFactory;
107 import com.android.launcher3.AbstractFloatingView;
108 import com.android.launcher3.DeviceProfile;
109 import com.android.launcher3.Flags;
110 import com.android.launcher3.InvariantDeviceProfile;
111 import com.android.launcher3.Launcher;
112 import com.android.launcher3.LauncherSettings.Favorites;
113 import com.android.launcher3.LauncherState;
114 import com.android.launcher3.QuickstepAccessibilityDelegate;
115 import com.android.launcher3.QuickstepTransitionManager;
116 import com.android.launcher3.R;
117 import com.android.launcher3.Utilities;
118 import com.android.launcher3.Workspace;
119 import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
120 import com.android.launcher3.allapps.AllAppsRecyclerView;
121 import com.android.launcher3.anim.AnimatorPlaybackController;
122 import com.android.launcher3.anim.PendingAnimation;
123 import com.android.launcher3.apppairs.AppPairIcon;
124 import com.android.launcher3.appprediction.PredictionRowView;
125 import com.android.launcher3.config.FeatureFlags;
126 import com.android.launcher3.desktop.DesktopRecentsTransitionController;
127 import com.android.launcher3.hybridhotseat.HotseatPredictionController;
128 import com.android.launcher3.logging.InstanceId;
129 import com.android.launcher3.logging.StatsLogManager;
130 import com.android.launcher3.logging.StatsLogManager.StatsLogger;
131 import com.android.launcher3.model.BgDataModel.FixedContainerItems;
132 import com.android.launcher3.model.WellbeingModel;
133 import com.android.launcher3.model.data.ItemInfo;
134 import com.android.launcher3.popup.SystemShortcut;
135 import com.android.launcher3.proxy.ProxyActivityStarter;
136 import com.android.launcher3.statehandlers.DepthController;
137 import com.android.launcher3.statehandlers.DesktopVisibilityController;
138 import com.android.launcher3.statemanager.StateManager.AtomicAnimationFactory;
139 import com.android.launcher3.statemanager.StateManager.StateHandler;
140 import com.android.launcher3.taskbar.LauncherTaskbarUIController;
141 import com.android.launcher3.taskbar.TaskbarManager;
142 import com.android.launcher3.taskbar.TaskbarUIController;
143 import com.android.launcher3.testing.TestLogging;
144 import com.android.launcher3.testing.shared.TestProtocol;
145 import com.android.launcher3.uioverrides.states.QuickstepAtomicAnimationFactory;
146 import com.android.launcher3.uioverrides.touchcontrollers.NavBarToHomeTouchController;
147 import com.android.launcher3.uioverrides.touchcontrollers.NoButtonNavbarToOverviewTouchController;
148 import com.android.launcher3.uioverrides.touchcontrollers.NoButtonQuickSwitchTouchController;
149 import com.android.launcher3.uioverrides.touchcontrollers.PortraitStatesTouchController;
150 import com.android.launcher3.uioverrides.touchcontrollers.QuickSwitchTouchController;
151 import com.android.launcher3.uioverrides.touchcontrollers.StatusBarTouchController;
152 import com.android.launcher3.uioverrides.touchcontrollers.TaskViewDismissTouchController;
153 import com.android.launcher3.uioverrides.touchcontrollers.TaskViewLaunchTouchController;
154 import com.android.launcher3.uioverrides.touchcontrollers.TaskViewRecentsTouchContext;
155 import com.android.launcher3.uioverrides.touchcontrollers.TaskViewTouchControllerDeprecated;
156 import com.android.launcher3.uioverrides.touchcontrollers.TransposedQuickSwitchTouchController;
157 import com.android.launcher3.uioverrides.touchcontrollers.TwoButtonNavbarTouchController;
158 import com.android.launcher3.util.ActivityOptionsWrapper;
159 import com.android.launcher3.util.DisplayController;
160 import com.android.launcher3.util.IntSet;
161 import com.android.launcher3.util.NavigationMode;
162 import com.android.launcher3.util.ObjectWrapper;
163 import com.android.launcher3.util.PendingRequestArgs;
164 import com.android.launcher3.util.PendingSplitSelectInfo;
165 import com.android.launcher3.util.RunnableList;
166 import com.android.launcher3.util.SplitConfigurationOptions;
167 import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
168 import com.android.launcher3.util.SplitConfigurationOptions.SplitSelectSource;
169 import com.android.launcher3.util.StableViewInfo;
170 import com.android.launcher3.util.StartActivityParams;
171 import com.android.launcher3.util.TouchController;
172 import com.android.launcher3.views.FloatingIconView;
173 import com.android.quickstep.OverviewCommandHelper;
174 import com.android.quickstep.OverviewComponentObserver;
175 import com.android.quickstep.OverviewComponentObserver.OverviewChangeListener;
176 import com.android.quickstep.RecentsModel;
177 import com.android.quickstep.SystemUiProxy;
178 import com.android.quickstep.TaskUtils;
179 import com.android.quickstep.TouchInteractionService.TISBinder;
180 import com.android.quickstep.util.ActiveGestureProtoLogProxy;
181 import com.android.quickstep.util.AsyncClockEventDelegate;
182 import com.android.quickstep.util.LauncherUnfoldAnimationController;
183 import com.android.quickstep.util.QuickstepOnboardingPrefs;
184 import com.android.quickstep.util.SplitSelectStateController;
185 import com.android.quickstep.util.SplitTask;
186 import com.android.quickstep.util.SplitToWorkspaceController;
187 import com.android.quickstep.util.SplitWithKeyboardShortcutController;
188 import com.android.quickstep.util.TISBindHelper;
189 import com.android.quickstep.util.unfold.LauncherUnfoldTransitionController;
190 import com.android.quickstep.util.unfold.ProxyUnfoldTransitionProvider;
191 import com.android.quickstep.views.FloatingTaskView;
192 import com.android.quickstep.views.OverviewActionsView;
193 import com.android.quickstep.views.RecentsView;
194 import com.android.quickstep.views.RecentsViewContainer;
195 import com.android.quickstep.views.TaskView;
196 import com.android.systemui.animation.back.FlingOnBackAnimationCallback;
197 import com.android.systemui.shared.recents.model.Task;
198 import com.android.systemui.shared.system.ActivityManagerWrapper;
199 import com.android.systemui.unfold.RemoteUnfoldSharedComponent;
200 import com.android.systemui.unfold.UnfoldTransitionFactory;
201 import com.android.systemui.unfold.UnfoldTransitionProgressProvider;
202 import com.android.systemui.unfold.config.ResourceUnfoldTransitionConfig;
203 import com.android.systemui.unfold.config.UnfoldTransitionConfig;
204 import com.android.systemui.unfold.dagger.UnfoldMain;
205 import com.android.systemui.unfold.progress.RemoteUnfoldTransitionReceiver;
206 import com.android.systemui.unfold.updates.RotationChangeProvider;
207 import com.android.wm.shell.shared.bubbles.BubbleAnythingFlagHelper;
208 import com.android.wm.shell.shared.bubbles.BubbleBarLocation;
209 import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
210 
211 import kotlin.Unit;
212 
213 import java.io.FileDescriptor;
214 import java.io.PrintWriter;
215 import java.util.ArrayList;
216 import java.util.Arrays;
217 import java.util.Collections;
218 import java.util.List;
219 import java.util.Objects;
220 import java.util.Optional;
221 import java.util.function.BiConsumer;
222 import java.util.function.Predicate;
223 import java.util.stream.Stream;
224 
225 public class QuickstepLauncher extends Launcher implements RecentsViewContainer,
226         SystemShortcut.BubbleActivityStarter {
227     private static final boolean TRACE_LAYOUTS =
228             SystemProperties.getBoolean("persist.debug.trace_layouts", false);
229     private static final String TRACE_RELAYOUT_CLASS =
230             SystemProperties.get("persist.debug.trace_request_layout_class", null);
231 
232     protected static final String RING_APPEAR_ANIMATION_PREFIX = "RingAppearAnimation\t";
233 
234     private FixedContainerItems mAllAppsPredictions;
235     private HotseatPredictionController mHotseatPredictionController;
236     private DepthController mDepthController;
237     private QuickstepTransitionManager mAppTransitionManager;
238 
239     private OverviewActionsView<?> mActionsView;
240     private TISBindHelper mTISBindHelper;
241     private @Nullable LauncherTaskbarUIController mTaskbarUIController;
242     // Will be updated when dragging from taskbar.
243     private @Nullable UnfoldTransitionProgressProvider mUnfoldTransitionProgressProvider;
244     private @Nullable LauncherUnfoldAnimationController mLauncherUnfoldAnimationController;
245 
246     private SplitSelectStateController mSplitSelectStateController;
247     private SplitWithKeyboardShortcutController mSplitWithKeyboardShortcutController;
248     private SplitToWorkspaceController mSplitToWorkspaceController;
249     private BubbleBarLocation mBubbleBarLocation;
250 
251     /**
252      * If Launcher restarted while in the middle of an Overview split select, it needs this data to
253      * recover. In all other cases this will remain null.
254      */
255     private PendingSplitSelectInfo mPendingSplitSelectInfo = null;
256 
257     @Nullable
258     private DesktopRecentsTransitionController mDesktopRecentsTransitionController;
259 
260     private SafeCloseable mViewCapture;
261 
262     private boolean mEnableWidgetDepth;
263 
264     private boolean mIsPredictiveBackToHomeInProgress;
265 
266     private boolean mCanShowAllAppsEducationView;
267 
268     private boolean mIsOverlayVisible;
269 
270     private final OverviewChangeListener mOverviewChangeListener = this::onOverviewTargetChanged;
271 
272     private final TaskViewRecentsTouchContext mTaskViewRecentsTouchContext =
273             new TaskViewRecentsTouchContext() {
274                 @Override
275                 public boolean isRecentsInteractive() {
276                     return isInState(OVERVIEW) || isInState(OVERVIEW_MODAL_TASK);
277                 }
278 
279                 @Override
280                 public boolean isRecentsModal() {
281                     return isInState(OVERVIEW_MODAL_TASK);
282                 }
283 
284                 @Override
285                 public void onUserControlledAnimationCreated(
286                         AnimatorPlaybackController animController) {
287                     getStateManager().setCurrentUserControlledAnimation(animController);
288                 }
289             };
290 
getLauncher(Context context)291     public static QuickstepLauncher getLauncher(Context context) {
292         return fromContext(context);
293     }
294 
295     @Override
setupViews()296     protected void setupViews() {
297         getAppWidgetHolder().setOnViewCreationCallback(new QuickstepInteractionHandler(this));
298         super.setupViews();
299 
300         mActionsView = findViewById(R.id.overview_actions_view);
301         RecentsView<?,?> overviewPanel = getOverviewPanel();
302         SystemUiProxy systemUiProxy = SystemUiProxy.INSTANCE.get(this);
303         mSplitSelectStateController =
304                 new SplitSelectStateController(this, getStateManager(),
305                         getDepthController(), getStatsLogManager(),
306                         systemUiProxy, RecentsModel.INSTANCE.get(this),
307                         () -> onStateBack());
308         if (DesktopModeStatus.canEnterDesktopMode(this)) {
309             mDesktopRecentsTransitionController = new DesktopRecentsTransitionController(
310                     getStateManager(), systemUiProxy, getIApplicationThread(),
311                     getDepthController());
312         }
313         overviewPanel.init(mActionsView, mSplitSelectStateController,
314                 mDesktopRecentsTransitionController);
315         mSplitWithKeyboardShortcutController = new SplitWithKeyboardShortcutController(
316                 this, mSplitSelectStateController);
317         mSplitToWorkspaceController = new SplitToWorkspaceController(this,
318                 mSplitSelectStateController);
319         mActionsView.updateDimension(getDeviceProfile(), overviewPanel.getLastComputedTaskSize());
320         mActionsView.updateVerticalMargin(DisplayController.getNavigationMode(this));
321 
322         mAppTransitionManager = buildAppTransitionManager();
323         mAppTransitionManager.registerRemoteAnimations();
324         mAppTransitionManager.registerRemoteTransitions();
325 
326         mTISBindHelper = new TISBindHelper(this, this::onTISConnected);
327         mDepthController = new DepthController(this);
328         if (DesktopModeStatus.canEnterDesktopModeOrShowAppHandle(this)) {
329             mSplitSelectStateController.initSplitFromDesktopController(this);
330         }
331         mHotseatPredictionController = new HotseatPredictionController(this);
332 
333         mEnableWidgetDepth = SystemProperties.getBoolean("ro.launcher.depth.widget", true);
334         getWorkspace().addOverlayCallback(progress ->
335                 onTaskbarInAppDisplayProgressUpdate(progress, MINUS_ONE_PAGE_PROGRESS_INDEX));
336         addBackAnimationCallback(mSplitSelectStateController.getSplitBackHandler());
337     }
338 
339     @Override
logAppLaunch(StatsLogManager statsLogManager, ItemInfo info, InstanceId instanceId)340     public void logAppLaunch(StatsLogManager statsLogManager, ItemInfo info,
341             InstanceId instanceId) {
342         // If the app launch is from any of the surfaces in AllApps then add the InstanceId from
343         // LiveSearchManager to recreate the AllApps session on the server side.
344         if (mAllAppsSessionLogId != null && ALL_APPS.equals(
345                 getStateManager().getCurrentStableState())) {
346             instanceId = mAllAppsSessionLogId;
347         }
348 
349         StatsLogger logger = statsLogManager.logger().withItemInfo(info).withInstanceId(instanceId);
350 
351         if (mAllAppsPredictions != null
352                 && (info.itemType == ITEM_TYPE_APPLICATION
353                 || info.itemType == ITEM_TYPE_DEEP_SHORTCUT)) {
354             int count = mAllAppsPredictions.items.size();
355             for (int i = 0; i < count; i++) {
356                 ItemInfo targetInfo = mAllAppsPredictions.items.get(i);
357                 if (targetInfo.itemType == info.itemType
358                         && targetInfo.user.equals(info.user)
359                         && Objects.equals(targetInfo.getIntent(), info.getIntent())) {
360                     logger.withRank(i);
361                     break;
362                 }
363 
364             }
365         }
366         logger.log(LAUNCHER_APP_LAUNCH_TAP);
367 
368         mHotseatPredictionController.logLaunchedAppRankingInfo(info, instanceId);
369     }
370 
371     @Override
completeAddShortcut(Intent data, int container, int screenId, int cellX, int cellY, PendingRequestArgs args)372     protected void completeAddShortcut(Intent data, int container, int screenId, int cellX,
373             int cellY, PendingRequestArgs args) {
374         if (container == CONTAINER_HOTSEAT) {
375             mHotseatPredictionController.onDeferredDrop(cellX, cellY);
376         }
377         super.completeAddShortcut(data, container, screenId, cellX, cellY, args);
378     }
379 
380     @Override
createAccessibilityDelegate()381     protected LauncherAccessibilityDelegate createAccessibilityDelegate() {
382         return new QuickstepAccessibilityDelegate(this);
383     }
384 
385     /**
386      * Returns Prediction controller for hybrid hotseat
387      */
getHotseatPredictionController()388     public HotseatPredictionController getHotseatPredictionController() {
389         return mHotseatPredictionController;
390     }
391 
392     @Override
enableHotseatEdu(boolean enable)393     public void enableHotseatEdu(boolean enable) {
394         super.enableHotseatEdu(enable);
395         mHotseatPredictionController.enableHotseatEdu(enable);
396     }
397 
398     /**
399      * Builds the {@link QuickstepTransitionManager} instance to use for managing transitions.
400      */
buildAppTransitionManager()401     protected QuickstepTransitionManager buildAppTransitionManager() {
402         return new QuickstepTransitionManager(this);
403     }
404 
405     @Override
onConfigurationChanged(Configuration newConfig)406     public void onConfigurationChanged(Configuration newConfig) {
407         super.onConfigurationChanged(newConfig);
408         onStateOrResumeChanging(false /* inTransition */);
409     }
410 
411     @Override
startActivitySafely(View v, Intent intent, ItemInfo item)412     public RunnableList startActivitySafely(View v, Intent intent, ItemInfo item) {
413         // Only pause is taskbar controller is not present until the transition (if it exists) ends
414         mHotseatPredictionController.setPauseUIUpdate(getTaskbarUIController() == null);
415         PredictionRowView<?> predictionRowView =
416                 getAppsView().getFloatingHeaderView().findFixedRowByType(PredictionRowView.class);
417         // Pause the prediction row updates until the transition (if it exists) ends.
418         predictionRowView.setPredictionUiUpdatePaused(true);
419         RunnableList result = super.startActivitySafely(v, intent, item);
420         if (result == null) {
421             mHotseatPredictionController.setPauseUIUpdate(false);
422             predictionRowView.setPredictionUiUpdatePaused(false);
423         } else {
424             result.add(() -> {
425                 mHotseatPredictionController.setPauseUIUpdate(false);
426                 predictionRowView.setPredictionUiUpdatePaused(false);
427             });
428         }
429         return result;
430     }
431 
432     @Override
startBinding()433     public void startBinding() {
434         super.startBinding();
435         mHotseatPredictionController.verifyUIUpdateNotPaused();
436     }
437 
438     @Override
onActivityFlagsChanged(int changeBits)439     protected void onActivityFlagsChanged(int changeBits) {
440         if ((changeBits & ACTIVITY_STATE_STARTED) != 0) {
441             mDepthController.setActivityStarted(isStarted());
442         }
443 
444         if ((changeBits & ACTIVITY_STATE_RESUMED) != 0) {
445             if (!FeatureFlags.enableHomeTransitionListener() && mTaskbarUIController != null) {
446                 mTaskbarUIController.onLauncherVisibilityChanged(hasBeenResumed());
447             }
448         }
449 
450         super.onActivityFlagsChanged(changeBits);
451         if ((changeBits & (ACTIVITY_STATE_DEFERRED_RESUMED | ACTIVITY_STATE_STARTED
452                 | ACTIVITY_STATE_USER_ACTIVE | ACTIVITY_STATE_TRANSITION_ACTIVE)) != 0) {
453             onStateOrResumeChanging((getActivityFlags() & ACTIVITY_STATE_TRANSITION_ACTIVE) == 0);
454         }
455     }
456 
457     @Override
showAllAppsFromIntent(boolean alreadyOnHome)458     protected void showAllAppsFromIntent(boolean alreadyOnHome) {
459         TaskUtils.closeSystemWindowsAsync(CLOSE_SYSTEM_WINDOWS_REASON_HOME_KEY);
460         super.showAllAppsFromIntent(alreadyOnHome);
461     }
462 
onItemClicked(View view)463     protected void onItemClicked(View view) {
464         if (!mSplitToWorkspaceController.handleSecondAppSelectionForSplit(view)) {
465             super.getItemOnClickListener().onClick(view);
466         }
467     }
468 
469     @Override
getItemOnClickListener()470     public View.OnClickListener getItemOnClickListener() {
471         return this::onItemClicked;
472     }
473 
474     @Override
getSupportedShortcuts()475     public Stream<SystemShortcut.Factory> getSupportedShortcuts() {
476         // Order matters as it affects order of appearance in popup container
477         List<SystemShortcut.Factory> shortcuts = new ArrayList(Arrays.asList(
478                 APP_INFO, WellbeingModel.SHORTCUT_FACTORY, mHotseatPredictionController));
479 
480         shortcuts.addAll(getSplitShortcuts());
481         shortcuts.add(WIDGETS);
482         shortcuts.add(INSTALL);
483         if (Flags.enablePrivateSpaceInstallShortcut()) {
484             shortcuts.add(PRIVATE_PROFILE_INSTALL);
485         }
486         if (Flags.enableShortcutDontSuggestApp()) {
487             shortcuts.add(DONT_SUGGEST_APP);
488         }
489         if (Flags.enablePrivateSpace()) {
490             shortcuts.add(UNINSTALL_APP);
491         }
492         if (BubbleAnythingFlagHelper.enableCreateAnyBubble()) {
493             shortcuts.add(BUBBLE_SHORTCUT);
494         }
495         return shortcuts.stream();
496     }
497 
getSplitShortcuts()498     private List<SystemShortcut.Factory<QuickstepLauncher>> getSplitShortcuts() {
499         if (!mDeviceProfile.isTablet || mSplitSelectStateController.isSplitSelectActive()) {
500             return Collections.emptyList();
501         }
502         RecentsView recentsView = getOverviewPanel();
503         // TODO(b/266482558): Pull it out of PagedOrentationHandler for split from workspace.
504         List<SplitPositionOption> positions =
505                 recentsView.getPagedOrientationHandler().getSplitPositionOptions(
506                         mDeviceProfile);
507         List<SystemShortcut.Factory<QuickstepLauncher>> splitShortcuts = new ArrayList<>();
508         for (SplitPositionOption position : positions) {
509             splitShortcuts.add(getSplitSelectShortcutByPosition(position));
510         }
511         return splitShortcuts;
512     }
513 
514     /**
515      * Recents logic that triggers when launcher state changes or launcher activity stops/resumes.
516      */
onStateOrResumeChanging(boolean inTransition)517     private void onStateOrResumeChanging(boolean inTransition) {
518         LauncherState state = getStateManager().getState();
519         boolean started = ((getActivityFlags() & ACTIVITY_STATE_STARTED)) != 0;
520         if (started) {
521             DeviceProfile profile = getDeviceProfile();
522             boolean visible = (state == NORMAL || state == OVERVIEW)
523                     && isUserActive()
524                     && !profile.isVerticalBarLayout()
525                     && !mIsOverlayVisible;
526             SystemUiProxy.INSTANCE.get(this)
527                     .setLauncherKeepClearAreaHeight(visible, profile.hotseatBarSizePx);
528         }
529         if (state == NORMAL && !inTransition) {
530             ((RecentsView) getOverviewPanel()).setSwipeDownShouldLaunchApp(false);
531         }
532     }
533 
534     @Override
onOverlayVisibilityChanged(boolean visible)535     public void onOverlayVisibilityChanged(boolean visible) {
536         super.onOverlayVisibilityChanged(visible);
537         mIsOverlayVisible = visible;
538     }
539 
540     @Override
bindExtraContainerItems(FixedContainerItems item)541     public void bindExtraContainerItems(FixedContainerItems item) {
542         if (item.containerId == Favorites.CONTAINER_PREDICTION) {
543             mAllAppsPredictions = item;
544             PredictionRowView<?> predictionRowView =
545                     getAppsView().getFloatingHeaderView().findFixedRowByType(
546                             PredictionRowView.class);
547             predictionRowView.setPredictedApps(item.items);
548         } else if (item.containerId == Favorites.CONTAINER_HOTSEAT_PREDICTION) {
549             mHotseatPredictionController.setPredictedItems(item);
550         } else if (item.containerId == Favorites.CONTAINER_WIDGETS_PREDICTION) {
551             getWidgetPickerDataProvider().setWidgetRecommendations(item.items);
552         }
553     }
554 
555     @Override
bindWorkspaceComponentsRemoved(Predicate<ItemInfo> matcher)556     public void bindWorkspaceComponentsRemoved(Predicate<ItemInfo> matcher) {
557         super.bindWorkspaceComponentsRemoved(matcher);
558         mHotseatPredictionController.onModelItemsRemoved(matcher);
559     }
560 
561     @Override
onDestroy()562     public void onDestroy() {
563         if (mAppTransitionManager != null) {
564             mAppTransitionManager.onActivityDestroyed();
565         }
566         mAppTransitionManager = null;
567         mIsPredictiveBackToHomeInProgress = false;
568 
569         if (mUnfoldTransitionProgressProvider != null) {
570             SystemUiProxy.INSTANCE.get(this).setUnfoldAnimationListener(null);
571             mUnfoldTransitionProgressProvider.destroy();
572         }
573 
574         OverviewComponentObserver.INSTANCE.get(this)
575                 .removeOverviewChangeListener(mOverviewChangeListener);
576         mTISBindHelper.onDestroy();
577 
578         if (mLauncherUnfoldAnimationController != null) {
579             mLauncherUnfoldAnimationController.onDestroy();
580         }
581 
582         if (mSplitSelectStateController != null) {
583             mSplitSelectStateController.onDestroy();
584         }
585 
586         RecentsView recentsView = getOverviewPanel();
587         if (recentsView != null) {
588             recentsView.destroy();
589         }
590 
591         super.onDestroy();
592         mHotseatPredictionController.destroy();
593         if (mViewCapture != null) mViewCapture.close();
594         removeBackAnimationCallback(mSplitSelectStateController.getSplitBackHandler());
595     }
596 
597     @Override
onStateSetEnd(LauncherState state)598     public void onStateSetEnd(LauncherState state) {
599         super.onStateSetEnd(state);
600         handlePendingActivityRequest();
601 
602         switch (state.ordinal) {
603             case HINT_STATE_ORDINAL: {
604                 Workspace<?> workspace = getWorkspace();
605                 getStateManager().goToState(NORMAL);
606                 if (workspace.getNextPage() != Workspace.DEFAULT_PAGE) {
607                     workspace.post(workspace::moveToDefaultScreen);
608                 }
609                 break;
610             }
611             case HINT_STATE_TWO_BUTTON_ORDINAL: {
612                 getStateManager().goToState(OVERVIEW);
613                 getDragLayer().performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
614                 break;
615             }
616             case OVERVIEW_STATE_ORDINAL: {
617                 RecentsView rv = getOverviewPanel();
618                 sendCustomAccessibilityEvent(
619                         rv.getPageAt(rv.getCurrentPage()), TYPE_VIEW_FOCUSED, null);
620                 break;
621             }
622             case QUICK_SWITCH_STATE_ORDINAL: {
623                 RecentsView rv = getOverviewPanel();
624                 TaskView currentPageTask = rv.getCurrentPageTaskView();
625                 TaskView fallbackTask = rv.getFirstTaskView();
626                 if (currentPageTask != null || fallbackTask != null) {
627                     TaskView taskToLaunch = currentPageTask;
628                     if (currentPageTask == null) {
629                         taskToLaunch = fallbackTask;
630                         ActiveGestureProtoLogProxy.logQuickSwitchFromHomeFallback(
631                                 rv.getCurrentPage());
632                     }
633                     taskToLaunch.launchWithoutAnimation(success -> {
634                         if (!success) {
635                             getStateManager().goToState(OVERVIEW);
636                         } else {
637                             getStateManager().moveToRestState();
638                         }
639                         return Unit.INSTANCE;
640                     });
641                 } else {
642                     ActiveGestureProtoLogProxy.logQuickSwitchFromHomeFailed(rv.getCurrentPage());
643                     getStateManager().goToState(NORMAL);
644                 }
645                 break;
646             }
647 
648         }
649     }
650 
651     @Override
createTouchControllers()652     public TouchController[] createTouchControllers() {
653         NavigationMode mode = DisplayController.getNavigationMode(this);
654 
655         ArrayList<TouchController> list = new ArrayList<>();
656         list.add(getDragController());
657         BiConsumer<AnimatorSet, Long> splitAnimator = (animatorSet, duration) ->
658                 animatorSet.play(mSplitSelectStateController.getSplitAnimationController()
659                         .createPlaceholderDismissAnim(this, LAUNCHER_SPLIT_SELECTION_EXIT_HOME,
660                                 duration));
661         switch (mode) {
662             case NO_BUTTON:
663                 list.add(new NoButtonQuickSwitchTouchController(this));
664                 list.add(new NavBarToHomeTouchController(this, splitAnimator));
665                 list.add(new NoButtonNavbarToOverviewTouchController(this, splitAnimator));
666                 break;
667             case TWO_BUTTONS:
668                 list.add(new TwoButtonNavbarTouchController(this));
669                 list.add(getDeviceProfile().isVerticalBarLayout()
670                         ? new TransposedQuickSwitchTouchController(this)
671                         : new QuickSwitchTouchController(this));
672                 list.add(new PortraitStatesTouchController(this));
673                 break;
674             case THREE_BUTTONS:
675                 list.add(new NoButtonQuickSwitchTouchController(this));
676                 list.add(new NavBarToHomeTouchController(this, splitAnimator));
677                 list.add(new NoButtonNavbarToOverviewTouchController(this, splitAnimator));
678                 list.add(new PortraitStatesTouchController(this));
679                 break;
680             default:
681                 list.add(new PortraitStatesTouchController(this));
682                 break;
683         }
684 
685         if (!getDeviceProfile().isMultiWindowMode) {
686             list.add(new StatusBarTouchController(this));
687         }
688 
689         if (enableExpressiveDismissTaskMotion()) {
690             list.add(new TaskViewLaunchTouchController<>(this, mTaskViewRecentsTouchContext));
691             list.add(new TaskViewDismissTouchController<>(this, mTaskViewRecentsTouchContext));
692         } else {
693             list.add(new TaskViewTouchControllerDeprecated<>(this, mTaskViewRecentsTouchContext));
694         }
695         return list.toArray(new TouchController[list.size()]);
696     }
697 
698     @Override
createAtomicAnimationFactory()699     public AtomicAnimationFactory createAtomicAnimationFactory() {
700         return new QuickstepAtomicAnimationFactory(this);
701     }
702 
703     @Override
onCreate(Bundle savedInstanceState)704     protected void onCreate(Bundle savedInstanceState) {
705         super.onCreate(savedInstanceState);
706         if (savedInstanceState != null) {
707             mPendingSplitSelectInfo = ObjectWrapper.unwrap(
708                     savedInstanceState.getIBinder(PENDING_SPLIT_SELECT_INFO));
709         }
710         addMultiWindowModeChangedListener(mDepthController);
711         initUnfoldTransitionProgressProvider();
712         mViewCapture = ViewCaptureFactory.getInstance(this).startCapture(getWindow());
713         getWindow().addPrivateFlags(PRIVATE_FLAG_OPTIMIZE_MEASURE);
714         QuickstepOnboardingPrefs.setup(this);
715         View.setTraceLayoutSteps(TRACE_LAYOUTS);
716         View.setTracedRequestLayoutClassClass(TRACE_RELAYOUT_CLASS);
717         OverviewComponentObserver.INSTANCE.get(this)
718                 .addOverviewChangeListener(mOverviewChangeListener);
719     }
720 
721     @Override
initDeviceProfile(InvariantDeviceProfile idp)722     protected boolean initDeviceProfile(InvariantDeviceProfile idp) {
723         final boolean ret = super.initDeviceProfile(idp);
724         mDeviceProfile.isPredictiveBackSwipe =
725                 getApplicationInfo().isOnBackInvokedCallbackEnabled();
726         if (ret) {
727             SystemUiProxy.INSTANCE.get(this).setLauncherAppIconSize(mDeviceProfile.iconSizePx);
728         }
729         return ret;
730     }
731 
732     @Override
startSplitSelection(SplitSelectSource splitSelectSource)733     public void startSplitSelection(SplitSelectSource splitSelectSource) {
734         RecentsView recentsView = getOverviewPanel();
735         // Check if there is already an instance of this app running, if so, initiate the split
736         // using that.
737         mSplitSelectStateController.findLastActiveTasksAndRunCallback(
738                 Collections.singletonList(splitSelectSource.getItemInfo().getComponentKey()),
739                 false /* findExactPairMatch */,
740                 foundTasks -> {
741                     @Nullable Task foundTask = foundTasks[0];
742                     boolean taskWasFound = foundTask != null;
743                     splitSelectSource.alreadyRunningTaskId = taskWasFound
744                             ? foundTask.key.id
745                             : INVALID_TASK_ID;
746                     startSplitToHome(splitSelectSource);
747                 }
748         );
749     }
750 
751     /** TODO(b/266482558) Migrate into SplitSelectStateController or someplace split specific. */
startSplitToHome(SplitSelectSource source)752     private void startSplitToHome(SplitSelectSource source) {
753         AbstractFloatingView.closeAllOpenViews(this);
754         int splitPlaceholderSize = getResources().getDimensionPixelSize(
755                 R.dimen.split_placeholder_size);
756         int splitPlaceholderInset = getResources().getDimensionPixelSize(
757                 R.dimen.split_placeholder_inset);
758         Rect tempRect = new Rect();
759 
760         mSplitSelectStateController.setInitialTaskSelect(source.intent,
761                 source.position.stagePosition, source.getItemInfo(), source.splitEvent,
762                 source.alreadyRunningTaskId);
763 
764         RecentsView recentsView = getOverviewPanel();
765         recentsView.getPagedOrientationHandler().getInitialSplitPlaceholderBounds(
766                 splitPlaceholderSize, splitPlaceholderInset, getDeviceProfile(),
767                 mSplitSelectStateController.getActiveSplitStagePosition(), tempRect);
768 
769         PendingAnimation anim = new PendingAnimation(TABLET_HOME_TO_SPLIT.getDuration());
770         RectF startingTaskRect = new RectF();
771         final FloatingTaskView floatingTaskView = FloatingTaskView.getFloatingTaskView(this,
772                 source.getView(), null /* thumbnail */, source.getDrawable(), startingTaskRect);
773         floatingTaskView.setAlpha(1);
774         floatingTaskView.addStagingAnimation(anim, startingTaskRect, tempRect,
775                 false /* fadeWithThumbnail */, true /* isStagedTask */);
776         floatingTaskView.setOnClickListener(view ->
777                 mSplitSelectStateController.getSplitAnimationController().
778                         playAnimPlaceholderToFullscreen(this, view, Optional.empty()));
779         floatingTaskView.setContentDescription(source.getItemInfo().contentDescription);
780 
781         mSplitSelectStateController.setFirstFloatingTaskView(floatingTaskView);
782         anim.addListener(new AnimatorListenerAdapter() {
783             @Override
784             public void onAnimationCancel(Animator animation) {
785                 getDragLayer().removeView(floatingTaskView);
786                 mSplitSelectStateController.getSplitAnimationController()
787                         .removeSplitInstructionsView(QuickstepLauncher.this);
788                 mSplitSelectStateController.resetState();
789             }
790         });
791         anim.add(mSplitSelectStateController.getSplitAnimationController()
792                 .getShowSplitInstructionsAnim(this).buildAnim());
793         anim.buildAnim().start();
794     }
795 
796     @Override
isSplitSelectionActive()797     public boolean isSplitSelectionActive() {
798         if (mSplitSelectStateController == null) {
799             return false;
800         }
801         return mSplitSelectStateController.isSplitSelectActive();
802     }
803 
areBothSplitAppsConfirmed()804     public boolean areBothSplitAppsConfirmed() {
805         return mSplitSelectStateController.isBothSplitAppsConfirmed();
806     }
807 
808     @Override
onStateTransitionCompletedAfterSwipeToHome(LauncherState finalState)809     public void onStateTransitionCompletedAfterSwipeToHome(LauncherState finalState) {
810         if (mTaskbarUIController != null) {
811             mTaskbarUIController.onStateTransitionCompletedAfterSwipeToHome(finalState);
812         }
813     }
814 
815     @Override
onResume()816     protected void onResume() {
817         super.onResume();
818 
819         if (mLauncherUnfoldAnimationController != null) {
820             mLauncherUnfoldAnimationController.onResume();
821         }
822 
823         if (mTaskbarUIController != null && FeatureFlags.enableHomeTransitionListener()) {
824             mTaskbarUIController.onLauncherResume();
825         }
826     }
827 
828     @Override
onPause()829     protected void onPause() {
830         if (mLauncherUnfoldAnimationController != null) {
831             mLauncherUnfoldAnimationController.onPause();
832         }
833 
834         super.onPause();
835 
836         // If Launcher pauses before both split apps are selected, exit split screen.
837         if (!mSplitSelectStateController.isBothSplitAppsConfirmed() &&
838                 !mSplitSelectStateController.isLaunchingFirstAppFullscreen()) {
839             mSplitSelectStateController
840                     .logExitReason(LAUNCHER_SPLIT_SELECTION_EXIT_INTERRUPTED);
841             mSplitSelectStateController.getSplitAnimationController()
842                     .playPlaceholderDismissAnim(this, LAUNCHER_SPLIT_SELECTION_EXIT_INTERRUPTED);
843         }
844 
845         if (mTaskbarUIController != null && FeatureFlags.enableHomeTransitionListener()) {
846             mTaskbarUIController.onLauncherPause();
847         }
848     }
849 
850     @Override
onStop()851     protected void onStop() {
852         super.onStop();
853         if (mTaskbarUIController != null && FeatureFlags.enableHomeTransitionListener()) {
854             mTaskbarUIController.onLauncherStop();
855         }
856     }
857 
858     @Override
onNewIntent(Intent intent)859     protected void onNewIntent(Intent intent) {
860         super.onNewIntent(intent);
861         OverviewCommandHelper overviewCommandHelper = mTISBindHelper.getOverviewCommandHelper();
862         if (overviewCommandHelper != null) {
863             overviewCommandHelper.clearPendingCommands();
864         }
865     }
866 
getAppTransitionManager()867     public QuickstepTransitionManager getAppTransitionManager() {
868         return mAppTransitionManager;
869     }
870 
871     @Override
onEnterAnimationComplete()872     public void onEnterAnimationComplete() {
873         super.onEnterAnimationComplete();
874         // After the transition to home, enable the high-res thumbnail loader if it wasn't enabled
875         // as a part of quickstep, so that high-res thumbnails can load the next time we enter
876         // overview
877         RecentsModel.INSTANCE.get(this).getThumbnailCache()
878                 .getHighResLoadingState().setVisible(true);
879     }
880 
881     @Override
handleGestureContract(Intent intent)882     protected void handleGestureContract(Intent intent) {
883         if (FeatureFlags.SEPARATE_RECENTS_ACTIVITY.get()) {
884             super.handleGestureContract(intent);
885         }
886     }
887 
888     @Override
onTrimMemory(int level)889     public void onTrimMemory(int level) {
890         super.onTrimMemory(level);
891         RecentsModel.INSTANCE.get(this).onTrimMemory(level);
892     }
893 
894     @Override
onUiChangedWhileSleeping()895     public void onUiChangedWhileSleeping() {
896         // Remove the snapshot because the content view may have obvious changes.
897         UI_HELPER_EXECUTOR.execute(
898                 () -> ActivityManagerWrapper.getInstance().invalidateHomeTaskSnapshot(this));
899     }
900 
901     @Override
onAllAppsTransition(float progress)902     public void onAllAppsTransition(float progress) {
903         super.onAllAppsTransition(progress);
904         onTaskbarInAppDisplayProgressUpdate(progress, ALL_APPS_PAGE_PROGRESS_INDEX);
905     }
906 
907     @Override
onWidgetsTransition(float progress)908     public void onWidgetsTransition(float progress) {
909         super.onWidgetsTransition(progress);
910         onTaskbarInAppDisplayProgressUpdate(progress, WIDGETS_PAGE_PROGRESS_INDEX);
911         if (mEnableWidgetDepth) {
912             getDepthController().widgetDepth.setValue(Utilities.mapToRange(
913                     progress, 0f, 1f, 0f, getDeviceProfile().bottomSheetDepth, EMPHASIZED));
914         }
915     }
916 
917     @Override
dispatchKeyEvent(KeyEvent event)918     public boolean dispatchKeyEvent(KeyEvent event) {
919         return tryHandleBackKey(event) || super.dispatchKeyEvent(event);
920     }
921 
922     // TODO (b/267248420) Once the recents input consumer has been removed, there is no need to
923     //  handle the back key specially.
tryHandleBackKey(KeyEvent event)924     private boolean tryHandleBackKey(KeyEvent event) {
925         // Unlike normal activity, recents can receive input event from InputConsumer, so the input
926         // event won't go through ViewRootImpl#InputStage#onProcess.
927         // So when receive back key, try to do the same check thing in
928         // ViewRootImpl#NativePreImeInputStage#onProcess
929         if (event.getKeyCode() != KeyEvent.KEYCODE_BACK
930                 || event.getAction() != KeyEvent.ACTION_UP || event.isCanceled()) {
931             return false;
932         }
933 
934         getOnBackAnimationCallback().onBackInvoked();
935         return true;
936     }
937 
938     @Override
registerBackDispatcher()939     protected void registerBackDispatcher() {
940         getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
941                 OnBackInvokedDispatcher.PRIORITY_DEFAULT,
942                 new FlingOnBackAnimationCallback() {
943 
944                     @Nullable OnBackAnimationCallback mActiveOnBackAnimationCallback;
945 
946                     @Override
947                     public void onBackStartedCompat(@NonNull BackEvent backEvent) {
948                         if (mActiveOnBackAnimationCallback != null) {
949                             mActiveOnBackAnimationCallback.onBackCancelled();
950                         }
951                         mActiveOnBackAnimationCallback = getOnBackAnimationCallback();
952                         mActiveOnBackAnimationCallback.onBackStarted(backEvent);
953                     }
954 
955                     @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
956                     @Override
957                     public void onBackInvokedCompat() {
958                         // Recreate mActiveOnBackAnimationCallback if necessary to avoid NPE
959                         // because:
960                         // 1. b/260636433: In 3-button-navigation mode, onBackStarted() is not
961                         // called on ACTION_DOWN before onBackInvoked() is called in ACTION_UP.
962                         // 2. Launcher#onBackPressed() will call onBackInvoked() without calling
963                         // onBackInvoked() beforehand.
964                         if (mActiveOnBackAnimationCallback == null) {
965                             mActiveOnBackAnimationCallback = getOnBackAnimationCallback();
966                         }
967                         mActiveOnBackAnimationCallback.onBackInvoked();
968                         mActiveOnBackAnimationCallback = null;
969                         TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "onBackInvoked");
970                     }
971 
972                     @Override
973                     public void onBackProgressedCompat(@NonNull BackEvent backEvent) {
974                         if (!FeatureFlags.IS_STUDIO_BUILD
975                                 && mActiveOnBackAnimationCallback == null) {
976                             return;
977                         }
978                         mActiveOnBackAnimationCallback.onBackProgressed(backEvent);
979                     }
980 
981                     @Override
982                     public void onBackCancelledCompat() {
983                         if (!FeatureFlags.IS_STUDIO_BUILD
984                                 && mActiveOnBackAnimationCallback == null) {
985                             return;
986                         }
987                         mActiveOnBackAnimationCallback.onBackCancelled();
988                         mActiveOnBackAnimationCallback = null;
989                     }
990                 });
991     }
992 
onTaskbarInAppDisplayProgressUpdate(float progress, int flag)993     private void onTaskbarInAppDisplayProgressUpdate(float progress, int flag) {
994         TaskbarManager taskbarManager = mTISBindHelper.getTaskbarManager();
995         if (taskbarManager == null
996                 || taskbarManager.getCurrentActivityContext() == null
997                 || mTaskbarUIController == null) {
998             return;
999         }
1000         mTaskbarUIController.onTaskbarInAppDisplayProgressUpdate(progress, flag);
1001     }
1002 
1003     @Override
startIntentSenderForResult(IntentSender intent, int requestCode, Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags, Bundle options)1004     public void startIntentSenderForResult(IntentSender intent, int requestCode,
1005             Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags, Bundle options) {
1006         if (requestCode != -1) {
1007             mPendingActivityRequestCode = requestCode;
1008             StartActivityParams params = new StartActivityParams(this, requestCode);
1009             params.intentSender = intent;
1010             params.fillInIntent = fillInIntent;
1011             params.flagsMask = flagsMask;
1012             params.flagsValues = flagsValues;
1013             params.extraFlags = extraFlags;
1014             params.options = options;
1015             startActivity(ProxyActivityStarter.getLaunchIntent(this, params));
1016         } else {
1017             super.startIntentSenderForResult(intent, requestCode, fillInIntent, flagsMask,
1018                     flagsValues, extraFlags, options);
1019         }
1020     }
1021 
1022     @Override
startActivityForResult(Intent intent, int requestCode, Bundle options)1023     public void startActivityForResult(Intent intent, int requestCode, Bundle options) {
1024         if (requestCode != -1) {
1025             mPendingActivityRequestCode = requestCode;
1026             StartActivityParams params = new StartActivityParams(this, requestCode);
1027             params.intent = intent;
1028             params.options = options;
1029             startActivity(ProxyActivityStarter.getLaunchIntent(this, params));
1030         } else {
1031             super.startActivityForResult(intent, requestCode, options);
1032         }
1033     }
1034 
1035     @Override
setResumed()1036     public void setResumed() {
1037         DesktopVisibilityController desktopVisibilityController =
1038                 DesktopVisibilityController.INSTANCE.get(this);
1039         if (!ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY.isTrue()
1040                 && desktopVisibilityController.isInDesktopModeAndNotInOverview(getDisplayId())
1041                 && !desktopVisibilityController.isRecentsGestureInProgress()) {
1042             // Return early to skip setting activity to appear as resumed
1043             // TODO: b/333533253 - Remove after flag rollout
1044             return;
1045         }
1046         super.setResumed();
1047     }
1048 
1049     @Override
onDeferredResumed()1050     protected void onDeferredResumed() {
1051         super.onDeferredResumed();
1052         handlePendingActivityRequest();
1053     }
1054 
handlePendingActivityRequest()1055     private void handlePendingActivityRequest() {
1056         if (mPendingActivityRequestCode != -1 && isInState(NORMAL)
1057                 && ((getActivityFlags() & ACTIVITY_STATE_DEFERRED_RESUMED) != 0)) {
1058             // Remove any active ProxyActivityStarter task and send RESULT_CANCELED to Launcher.
1059             onActivityResult(mPendingActivityRequestCode, RESULT_CANCELED, null);
1060             // ProxyActivityStarter is started with clear task to reset the task after which it
1061             // removes the task itself.
1062             startActivity(ProxyActivityStarter.getLaunchIntent(this, null));
1063         }
1064     }
1065 
onOverviewTargetChanged(boolean isHomeAndOverviewSame)1066     private void onOverviewTargetChanged(boolean isHomeAndOverviewSame) {
1067         QuickstepTransitionManager transitionManager = getAppTransitionManager();
1068         if (transitionManager != null) {
1069             transitionManager.onOverviewTargetChange();
1070         }
1071     }
1072 
onTISConnected(TISBinder binder)1073     private void onTISConnected(TISBinder binder) {
1074         TaskbarManager taskbarManager = mTISBindHelper.getTaskbarManager();
1075         if (taskbarManager != null) {
1076             taskbarManager.setActivity(this);
1077         }
1078         mTISBindHelper.setPredictiveBackToHomeInProgress(mIsPredictiveBackToHomeInProgress);
1079     }
1080 
1081     @Override
runOnBindToTouchInteractionService(Runnable r)1082     public void runOnBindToTouchInteractionService(Runnable r) {
1083         mTISBindHelper.runOnBindToTouchInteractionService(r);
1084     }
1085 
initUnfoldTransitionProgressProvider()1086     private void initUnfoldTransitionProgressProvider() {
1087         if (!enableUnfoldStateAnimation()) {
1088             final UnfoldTransitionConfig config = new ResourceUnfoldTransitionConfig();
1089             if (config.isEnabled()) {
1090                 initRemotelyCalculatedUnfoldAnimation(config);
1091             }
1092         } else {
1093             ProxyUnfoldTransitionProvider provider =
1094                     SystemUiProxy.INSTANCE.get(this).getUnfoldTransitionProvider();
1095             if (provider != null) {
1096                 new LauncherUnfoldTransitionController(this, provider);
1097             }
1098         }
1099     }
1100 
1101     /** Receives animation progress from sysui process. */
initRemotelyCalculatedUnfoldAnimation(UnfoldTransitionConfig config)1102     private void initRemotelyCalculatedUnfoldAnimation(UnfoldTransitionConfig config) {
1103         RemoteUnfoldSharedComponent unfoldComponent =
1104                 UnfoldTransitionFactory.createRemoteUnfoldSharedComponent(
1105                         /* context= */ this,
1106                         config,
1107                         getMainExecutor(),
1108                         getMainThreadHandler(),
1109                         /* backgroundExecutor= */ UI_HELPER_EXECUTOR,
1110                         /* bgHandler= */ UI_HELPER_EXECUTOR.getHandler(),
1111                         /* tracingTagPrefix= */ "launcher",
1112                         getSystemService(DisplayManager.class)
1113                 );
1114 
1115         final RemoteUnfoldTransitionReceiver remoteUnfoldTransitionProgressProvider =
1116                 unfoldComponent.getRemoteTransitionProgress().orElseThrow(
1117                         () -> new IllegalStateException(
1118                                 "Trying to create getRemoteTransitionProgress when the transition "
1119                                         + "is disabled"));
1120         mUnfoldTransitionProgressProvider = remoteUnfoldTransitionProgressProvider;
1121 
1122         SystemUiProxy.INSTANCE.get(this).setUnfoldAnimationListener(
1123                 remoteUnfoldTransitionProgressProvider);
1124 
1125         initUnfoldAnimationController(mUnfoldTransitionProgressProvider,
1126                 unfoldComponent.getRotationChangeProvider());
1127     }
1128 
initUnfoldAnimationController(UnfoldTransitionProgressProvider progressProvider, @UnfoldMain RotationChangeProvider rotationChangeProvider)1129     private void initUnfoldAnimationController(UnfoldTransitionProgressProvider progressProvider,
1130             @UnfoldMain RotationChangeProvider rotationChangeProvider) {
1131         mLauncherUnfoldAnimationController = new LauncherUnfoldAnimationController(
1132                 /* launcher= */ this,
1133                 getWindowManager(),
1134                 progressProvider,
1135                 rotationChangeProvider
1136         );
1137     }
1138 
1139     @Override
setTaskbarUIController(@ullable TaskbarUIController taskbarUIController)1140     public void setTaskbarUIController(@Nullable TaskbarUIController taskbarUIController) {
1141         mTaskbarUIController = (LauncherTaskbarUIController) taskbarUIController;
1142     }
1143 
1144     @Override
getTaskbarUIController()1145     public @Nullable LauncherTaskbarUIController getTaskbarUIController() {
1146         return mTaskbarUIController;
1147     }
1148 
1149     /** Provides the translation X for the hotseat item. */
getHotseatItemTranslationX(ItemInfo itemInfo)1150     public int getHotseatItemTranslationX(ItemInfo itemInfo) {
1151         int translationX = 0;
1152         if (isBubbleBarEnabled() && mBubbleBarLocation != null) {
1153             boolean isBubblesOnLeft = mBubbleBarLocation.isOnLeft(isRtl(getResources()));
1154             translationX += mDeviceProfile
1155                     .getHotseatTranslationXForNavBar(this, isBubblesOnLeft);
1156         }
1157         if (isBubbleBarEnabled()
1158                 && mDeviceProfile.shouldAdjustHotseatForBubbleBar(asContext(), hasBubbles())) {
1159             translationX += (int) mDeviceProfile
1160                     .getHotseatAdjustedTranslation(asContext(), itemInfo.cellX);
1161         }
1162         return translationX;
1163     }
1164 
getSplitToWorkspaceController()1165     public SplitToWorkspaceController getSplitToWorkspaceController() {
1166         return mSplitToWorkspaceController;
1167     }
1168 
1169     @Override
handleSplitAnimationGoingToHome(StatsLogManager.EventEnum splitDismissReason)1170     protected void handleSplitAnimationGoingToHome(StatsLogManager.EventEnum splitDismissReason) {
1171         super.handleSplitAnimationGoingToHome(splitDismissReason);
1172         mSplitSelectStateController.getSplitAnimationController()
1173                 .playPlaceholderDismissAnim(this, splitDismissReason);
1174     }
1175 
1176     @Override
dismissSplitSelection(StatsLogManager.LauncherEvent splitDismissEvent)1177     public void dismissSplitSelection(StatsLogManager.LauncherEvent splitDismissEvent) {
1178         super.dismissSplitSelection(splitDismissEvent);
1179         mSplitSelectStateController.getSplitAnimationController()
1180                 .playPlaceholderDismissAnim(this, splitDismissEvent);
1181     }
1182 
1183     @Override
getActionsView()1184     public OverviewActionsView<?> getActionsView() {
1185         return mActionsView;
1186     }
1187 
1188     @Override
closeOpenViews(boolean animate)1189     protected void closeOpenViews(boolean animate) {
1190         super.closeOpenViews(animate);
1191         TaskUtils.closeSystemWindowsAsync(CLOSE_SYSTEM_WINDOWS_REASON_HOME_KEY);
1192     }
1193 
1194     @Override
collectStateHandlers(List<StateHandler<LauncherState>> out)1195     public void collectStateHandlers(List<StateHandler<LauncherState>> out) {
1196         super.collectStateHandlers(out);
1197         out.add(getDepthController());
1198         out.add(new RecentsViewStateController(this));
1199     }
1200 
getDepthController()1201     public DepthController getDepthController() {
1202         return mDepthController;
1203     }
1204 
1205     @Nullable
getUnfoldTransitionProgressProvider()1206     public UnfoldTransitionProgressProvider getUnfoldTransitionProgressProvider() {
1207         return mUnfoldTransitionProgressProvider;
1208     }
1209 
1210     @Override
supportsAdaptiveIconAnimation(View clickedView)1211     public boolean supportsAdaptiveIconAnimation(View clickedView) {
1212         return true;
1213     }
1214 
1215     @Override
getNormalOverviewScaleAndOffset()1216     public float[] getNormalOverviewScaleAndOffset() {
1217         return DisplayController.getNavigationMode(this).hasGestures
1218                 ? new float[] {1, 1} : new float[] {1.1f, NO_OFFSET};
1219     }
1220 
1221     @Override
finishBindingItems(IntSet pagesBoundFirst)1222     public void finishBindingItems(IntSet pagesBoundFirst) {
1223         super.finishBindingItems(pagesBoundFirst);
1224         // Instantiate and initialize WellbeingModel now that its loading won't interfere with
1225         // populating workspace.
1226         // TODO: Find a better place for this
1227         WellbeingModel.INSTANCE.get(this);
1228 
1229         if (mLauncherUnfoldAnimationController != null) {
1230             // This is needed in case items are rebound while the unfold animation is in progress.
1231             mLauncherUnfoldAnimationController.updateRegisteredViewsIfNeeded();
1232         }
1233     }
1234 
1235     @NonNull
1236     @Override
getActivityLaunchOptions(View v, @Nullable ItemInfo item)1237     public ActivityOptionsWrapper getActivityLaunchOptions(View v, @Nullable ItemInfo item) {
1238         ActivityOptionsWrapper activityOptions = mAppTransitionManager.getActivityLaunchOptions(
1239                 v, item != null ? item : (ItemInfo) v.getTag());
1240         if (mLastTouchUpTime > 0) {
1241             activityOptions.options.setSourceInfo(ActivityOptions.SourceInfo.TYPE_LAUNCHER,
1242                     mLastTouchUpTime);
1243         }
1244         if (item != null && (item.animationType == DEFAULT_NO_ICON
1245                 || item.animationType == VIEW_BACKGROUND)) {
1246             activityOptions.options.setSplashScreenStyle(
1247                     SplashScreen.SPLASH_SCREEN_STYLE_SOLID_COLOR);
1248         } else {
1249             activityOptions.options.setSplashScreenStyle(SplashScreen.SPLASH_SCREEN_STYLE_ICON);
1250         }
1251         activityOptions.options.setLaunchDisplayId(
1252                 (v != null && v.getDisplay() != null) ? v.getDisplay().getDisplayId()
1253                         : Display.DEFAULT_DISPLAY);
1254         activityOptions.options.setPendingIntentBackgroundActivityStartMode(
1255                 ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
1256         return activityOptions;
1257     }
1258 
1259     @Override
makeDefaultActivityOptions(int splashScreenStyle)1260     public ActivityOptionsWrapper makeDefaultActivityOptions(int splashScreenStyle) {
1261         RunnableList callbacks = new RunnableList();
1262         ActivityOptions options = ActivityOptions.makeCustomAnimation(this, 0, 0);
1263         options.setSplashScreenStyle(splashScreenStyle);
1264         options.setPendingIntentBackgroundActivityStartMode(
1265                 ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
1266 
1267         IRemoteCallback endCallback = completeRunnableListCallback(callbacks, this);
1268         options.setOnAnimationAbortListener(endCallback);
1269         options.setOnAnimationFinishedListener(endCallback);
1270         return new ActivityOptionsWrapper(options, callbacks);
1271     }
1272 
1273     @Override
1274     @BinderThread
enterStageSplitFromRunningApp(boolean leftOrTop)1275     public void enterStageSplitFromRunningApp(boolean leftOrTop) {
1276         mSplitWithKeyboardShortcutController.enterStageSplit(leftOrTop);
1277     }
1278 
1279     @Override
onDisplayInfoChanged(Context context, DisplayController.Info info, int flags)1280     public void onDisplayInfoChanged(Context context, DisplayController.Info info, int flags) {
1281         super.onDisplayInfoChanged(context, info, flags);
1282         // When changing screens, force moving to rest state similar to StatefulActivity.onStop, as
1283         // StatefulActivity isn't called consistently.
1284         if ((flags & CHANGE_ACTIVE_SCREEN) != 0) {
1285             // Do not animate moving to rest state, as it can clash with Launcher#onIdpChanged
1286             // where reapplyUi calls StateManager's reapplyState during the state change animation,
1287             // and cancel the state change unexpectedly. The screen will be off during screen
1288             // transition, hiding the unanimated transition.
1289             getStateManager().moveToRestState(/* isAnimated = */false);
1290         }
1291 
1292         if ((flags & CHANGE_NAVIGATION_MODE) != 0) {
1293             getDragLayer().recreateControllers();
1294             if (mActionsView != null) {
1295                 mActionsView.updateVerticalMargin(info.getNavigationMode());
1296             }
1297         }
1298     }
1299 
1300     @Override
onSaveInstanceState(Bundle outState)1301     protected void onSaveInstanceState(Bundle outState) {
1302         super.onSaveInstanceState(outState);
1303 
1304         // If Launcher shuts downs during split select, we save some extra data in the recovery
1305         // bundle to allow graceful recovery. The normal LauncherState restore mechanism doesn't
1306         // work in this case because restoring straight to OverviewSplitSelect without staging data,
1307         // or before the tasks themselves have loaded into Overview, causes a crash. So we tell
1308         // Launcher to first restore into Overview state, wait for the relevant tasks and icons to
1309         // load in, and then proceed to OverviewSplitSelect.
1310         if (isInState(OVERVIEW_SPLIT_SELECT)) {
1311             // Launcher will restart in Overview and then transition to OverviewSplitSelect.
1312             outState.putIBinder(PENDING_SPLIT_SELECT_INFO, ObjectWrapper.wrap(
1313                     new PendingSplitSelectInfo(
1314                             mSplitSelectStateController.getInitialTaskId(),
1315                             mSplitSelectStateController.getActiveSplitStagePosition(),
1316                             mSplitSelectStateController.getSplitEvent())
1317             ));
1318             outState.putInt(RUNTIME_STATE, OVERVIEW.ordinal);
1319         }
1320     }
1321 
1322     /**
1323      * When Launcher restarts, it sometimes needs to recover to a split selection state.
1324      * This function checks if such a recovery is needed.
1325      * @return a boolean representing whether the launcher is waiting to recover to
1326      * OverviewSplitSelect state.
1327      */
hasPendingSplitSelectInfo()1328     public boolean hasPendingSplitSelectInfo() {
1329         return mPendingSplitSelectInfo != null;
1330     }
1331 
1332     /**
1333      * See {@link #hasPendingSplitSelectInfo()}
1334      */
getPendingSplitSelectInfo()1335     public @Nullable PendingSplitSelectInfo getPendingSplitSelectInfo() {
1336         return mPendingSplitSelectInfo;
1337     }
1338 
1339     /**
1340      * When the launcher has successfully recovered to OverviewSplitSelect state, this function
1341      * deletes the recovery data, returning it to a null state.
1342      */
finishSplitSelectRecovery()1343     public void finishSplitSelectRecovery() {
1344         mPendingSplitSelectInfo = null;
1345     }
1346 
1347     /**
1348      * Sets flag whether a predictive back-to-home animation is in progress
1349      */
setPredictiveBackToHomeInProgress(boolean isInProgress)1350     public void setPredictiveBackToHomeInProgress(boolean isInProgress) {
1351         mIsPredictiveBackToHomeInProgress = isInProgress;
1352         mTISBindHelper.setPredictiveBackToHomeInProgress(isInProgress);
1353     }
1354 
getPredictiveBackToHomeInProgress()1355     public boolean getPredictiveBackToHomeInProgress() {
1356         return mIsPredictiveBackToHomeInProgress;
1357     }
1358 
1359     @Override
areDesktopTasksVisible()1360     public boolean areDesktopTasksVisible() {
1361         return DesktopVisibilityController.INSTANCE.get(this)
1362                 .isInDesktopModeAndNotInOverview(getDisplayId());
1363     }
1364 
1365     @Override
dispatchDeviceProfileChanged()1366     public void dispatchDeviceProfileChanged() {
1367         super.dispatchDeviceProfileChanged();
1368         Trace.instantForTrack(TRACE_TAG_APP, "QuickstepLauncher#DeviceProfileChanged",
1369                 getDeviceProfile().toSmallString());
1370         SystemUiProxy.INSTANCE.get(this).setLauncherAppIconSize(mDeviceProfile.iconSizePx);
1371         TaskbarManager taskbarManager = mTISBindHelper.getTaskbarManager();
1372         if (taskbarManager != null) {
1373             taskbarManager.debugPrimaryTaskbar("QuickstepLauncher#onDeviceProfileChanged",
1374                     true);
1375         }
1376     }
1377 
1378     /**
1379      * Launches the given {@link SplitTask} in splitscreen.
1380      */
launchSplitTasks( @onNull SplitTask splitTask, @Nullable RemoteTransition remoteTransition)1381     public void launchSplitTasks(
1382             @NonNull SplitTask splitTask, @Nullable RemoteTransition remoteTransition) {
1383         mSplitSelectStateController.launchExistingSplitPair(null /* launchingTaskView */,
1384                 splitTask.getTopLeftTask().key.id,
1385                 splitTask.getBottomRightTask().key.id,
1386                 SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT,
1387                 /* callback= */ success -> mSplitSelectStateController.resetState(),
1388                 /* freezeTaskList= */ false,
1389                 splitTask.getSplitBounds().snapPosition,
1390                 remoteTransition);
1391     }
1392 
1393     /**
1394      * Launches two apps as an app pair.
1395      */
launchAppPair(AppPairIcon appPairIcon)1396     public void launchAppPair(AppPairIcon appPairIcon) {
1397         // Potentially show the Taskbar education once the app pair launch finishes
1398         mSplitSelectStateController.getAppPairsController().launchAppPair(appPairIcon,
1399                 CUJ_LAUNCHER_LAUNCH_APP_PAIR_FROM_WORKSPACE,
1400                 (success) -> {
1401                     if (success && mTaskbarUIController != null) {
1402                         mTaskbarUIController.showEduOnAppLaunch();
1403                     }
1404                 });
1405     }
1406 
canStartHomeSafely()1407     public boolean canStartHomeSafely() {
1408         OverviewCommandHelper overviewCommandHelper = mTISBindHelper.getOverviewCommandHelper();
1409         return overviewCommandHelper == null || overviewCommandHelper.canStartHomeSafely();
1410     }
1411 
1412     @Override
isBubbleBarEnabled()1413     public boolean isBubbleBarEnabled() {
1414         return (mTaskbarUIController != null && mTaskbarUIController.isBubbleBarEnabled());
1415     }
1416 
1417     @Override
hasBubbles()1418     public boolean hasBubbles() {
1419         return (mTaskbarUIController != null && mTaskbarUIController.hasBubbles());
1420     }
1421 
1422     @Override
handleIncorrectSplitTargetSelection()1423     public boolean handleIncorrectSplitTargetSelection() {
1424         if (!mSplitSelectStateController.isSplitSelectActive()) {
1425             return false;
1426         }
1427         mSplitSelectStateController.getSplitInstructionsView().goBoing();
1428         return true;
1429     }
1430 
1431     @Override
showShortcutBubble(ShortcutInfo info)1432     public void showShortcutBubble(ShortcutInfo info) {
1433         if (info == null) return;
1434         SystemUiProxy.INSTANCE.get(this).showShortcutBubble(info);
1435     }
1436 
1437     @Override
showAppBubble(Intent intent, UserHandle user)1438     public void showAppBubble(Intent intent, UserHandle user) {
1439         if (intent == null || intent.getPackage() == null) return;
1440         SystemUiProxy.INSTANCE.get(this).showAppBubble(intent, user);
1441     }
1442 
1443     /** Sets the location of the bubble bar */
setBubbleBarLocation(BubbleBarLocation bubbleBarLocation)1444     public void setBubbleBarLocation(BubbleBarLocation bubbleBarLocation) {
1445         mBubbleBarLocation = bubbleBarLocation;
1446     }
1447 
1448     /**
1449      * Similar to {@link #getFirstHomeElementForAppClose} but also matches all apps if its visible
1450      */
1451     @Nullable
getFirstVisibleElementForAppClose( @ullable StableViewInfo svi, String packageName, UserHandle user)1452     public View getFirstVisibleElementForAppClose(
1453             @Nullable StableViewInfo svi, String packageName, UserHandle user) {
1454         if (isInState(LauncherState.ALL_APPS)) {
1455             AllAppsRecyclerView activeRecyclerView = getAppsView().getActiveRecyclerView();
1456             View v = null;
1457             if (svi != null) {
1458                 // Preferred item match
1459                 v = activeRecyclerView.findViewByPredicate(view ->
1460                         view.isAggregatedVisible()
1461                                 && view.getTag() instanceof ItemInfo info && svi.matches(info));
1462             }
1463             if (v == null) {
1464                 // Package user match
1465                 v = activeRecyclerView.findViewByPredicate(view ->
1466                         view.isAggregatedVisible() && view.getTag() instanceof ItemInfo info
1467                                 && info.itemType == ITEM_TYPE_APPLICATION
1468                                 && info.user.equals(user)
1469                                 && TextUtils.equals(info.getTargetPackage(), packageName));
1470             }
1471 
1472             if (v != null && activeRecyclerView.computeVerticalScrollOffset() > 0) {
1473                 RectF locationBounds = new RectF();
1474                 FloatingIconView.getLocationBoundsForView(this, v, false, locationBounds,
1475                         new Rect());
1476                 if (locationBounds.top < getAppsView().getHeaderBottom()) {
1477                     // Icon is covered by scrim, return null to play fallback animation.
1478                     return null;
1479                 }
1480             }
1481             return v;
1482         }
1483 
1484         return getFirstHomeElementForAppClose(svi, packageName, user);
1485     }
1486 
1487     @Override
dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args)1488     public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
1489         super.dump(prefix, fd, writer, args);
1490         if (mDepthController != null) {
1491             mDepthController.dump(prefix, writer);
1492         }
1493         RecentsView recentsView = getOverviewPanel();
1494         writer.println("\nQuickstepLauncher:");
1495         writer.println(prefix + "\tmOrientationState: " + (recentsView == null ? "recentsNull" :
1496                 recentsView.getPagedViewOrientedState()));
1497         if (recentsView != null) {
1498             recentsView.getSplitSelectController().dump(prefix, writer);
1499         }
1500         if (mAppTransitionManager != null) {
1501             mAppTransitionManager.dump(prefix + "\t" + RING_APPEAR_ANIMATION_PREFIX, writer);
1502         }
1503         if (mHotseatPredictionController != null) {
1504             mHotseatPredictionController.dump(prefix, writer);
1505         }
1506         PredictionRowView<?> predictionRowView =
1507                 getAppsView().getFloatingHeaderView().findFixedRowByType(
1508                         PredictionRowView.class);
1509         predictionRowView.dump(prefix, writer);
1510     }
1511 
1512     @Override
onCreateView(View parent, String name, Context context, AttributeSet attrs)1513     public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
1514         switch (name) {
1515             case "TextClock", "android.widget.TextClock" -> {
1516                 TextClock tc = new TextClock(context, attrs);
1517                 tc.setClockEventDelegate(AsyncClockEventDelegate.INSTANCE.get(this));
1518                 return tc;
1519             }
1520             case "AnalogClock", "android.widget.AnalogClock" -> {
1521                 AnalogClock ac = new AnalogClock(context, attrs);
1522                 ac.setClockEventDelegate(AsyncClockEventDelegate.INSTANCE.get(this));
1523                 return ac;
1524             }
1525         }
1526         return super.onCreateView(parent, name, context, attrs);
1527     }
1528 
1529     @Override
isRecentsViewVisible()1530     public boolean isRecentsViewVisible() {
1531         return getStateManager().getState().isRecentsViewVisible;
1532     }
1533 
isCanShowAllAppsEducationView()1534     public boolean isCanShowAllAppsEducationView() {
1535         return mCanShowAllAppsEducationView;
1536     }
1537 
setCanShowAllAppsEducationView(boolean canShowAllAppsEducationView)1538     public void setCanShowAllAppsEducationView(boolean canShowAllAppsEducationView) {
1539         mCanShowAllAppsEducationView = canShowAllAppsEducationView;
1540     }
1541 
1542     @Override
returnToHomescreen()1543     public void returnToHomescreen() {
1544         getStateManager().goToState(LauncherState.NORMAL);
1545     }
1546 }
1547