• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.launcher3.taskbar;
17 
18 import static android.window.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY;
19 
20 import static com.android.launcher3.Flags.syncAppLaunchWithTaskbarStash;
21 import static com.android.launcher3.QuickstepTransitionManager.TASKBAR_TO_APP_DURATION;
22 import static com.android.launcher3.QuickstepTransitionManager.TRANSIENT_TASKBAR_TRANSITION_DURATION;
23 import static com.android.launcher3.QuickstepTransitionManager.getTaskbarToHomeDuration;
24 import static com.android.launcher3.statemanager.BaseState.FLAG_NON_INTERACTIVE;
25 import static com.android.launcher3.taskbar.TaskbarEduTooltipControllerKt.TOOLTIP_STEP_FEATURES;
26 import static com.android.launcher3.taskbar.TaskbarLauncherStateController.FLAG_VISIBLE;
27 import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IGNORE_IN_APP;
28 
29 import android.animation.Animator;
30 import android.animation.AnimatorSet;
31 import android.window.RemoteTransition;
32 
33 import androidx.annotation.NonNull;
34 import androidx.annotation.Nullable;
35 
36 import com.android.launcher3.DeviceProfile;
37 import com.android.launcher3.Flags;
38 import com.android.launcher3.Hotseat;
39 import com.android.launcher3.LauncherState;
40 import com.android.launcher3.Utilities;
41 import com.android.launcher3.anim.AnimatedFloat;
42 import com.android.launcher3.logging.InstanceId;
43 import com.android.launcher3.logging.InstanceIdSequence;
44 import com.android.launcher3.model.data.ItemInfo;
45 import com.android.launcher3.taskbar.bubbles.BubbleBarController;
46 import com.android.launcher3.taskbar.bubbles.BubbleControllers;
47 import com.android.launcher3.uioverrides.QuickstepLauncher;
48 import com.android.launcher3.util.DisplayController;
49 import com.android.launcher3.util.MultiPropertyFactory;
50 import com.android.launcher3.util.OnboardingPrefs;
51 import com.android.quickstep.GestureState;
52 import com.android.quickstep.HomeVisibilityState;
53 import com.android.quickstep.LauncherActivityInterface;
54 import com.android.quickstep.RecentsAnimationCallbacks;
55 import com.android.quickstep.SystemUiProxy;
56 import com.android.quickstep.fallback.window.RecentsDisplayModel;
57 import com.android.quickstep.fallback.window.RecentsWindowFlags;
58 import com.android.quickstep.util.SplitTask;
59 import com.android.quickstep.views.RecentsView;
60 import com.android.quickstep.views.RecentsViewContainer;
61 import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags;
62 import com.android.wm.shell.shared.bubbles.BubbleBarLocation;
63 import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
64 
65 import java.io.PrintWriter;
66 import java.util.Arrays;
67 
68 /**
69  * A data source which integrates with a Launcher instance
70  */
71 public class LauncherTaskbarUIController extends TaskbarUIController {
72 
73     private static final String TAG = "TaskbarUIController";
74 
75     public static final int MINUS_ONE_PAGE_PROGRESS_INDEX = 0;
76     public static final int ALL_APPS_PAGE_PROGRESS_INDEX = 1;
77     public static final int WIDGETS_PAGE_PROGRESS_INDEX = 2;
78     public static final int SYSUI_SURFACE_PROGRESS_INDEX = 3;
79     public static final int LAUNCHER_PAUSE_PROGRESS_INDEX = 4;
80 
81     public static final int DISPLAY_PROGRESS_COUNT = 5;
82 
83     private final AnimatedFloat mTaskbarInAppDisplayProgress = new AnimatedFloat(
84             this::onInAppDisplayProgressChanged);
85     private final MultiPropertyFactory<AnimatedFloat> mTaskbarInAppDisplayProgressMultiProp =
86             new MultiPropertyFactory<>(mTaskbarInAppDisplayProgress,
87                     AnimatedFloat.VALUE, DISPLAY_PROGRESS_COUNT, Float::max);
88     private final AnimatedFloat mLauncherPauseProgress = new AnimatedFloat(
89             this::onLauncherPauseProgressUpdate);
90 
91     private final QuickstepLauncher mLauncher;
92     private final HomeVisibilityState mHomeState;
93 
94     private final DeviceProfile.OnDeviceProfileChangeListener mOnDeviceProfileChangeListener =
95             dp -> {
96                 onStashedInAppChanged(dp);
97                 postAdjustHotseatForBubbleBar();
98                 if (mControllers != null && mControllers.taskbarViewController != null) {
99                     mControllers.taskbarViewController.onRotationChanged(dp);
100                 }
101             };
102     private final HomeVisibilityState.VisibilityChangeListener  mVisibilityChangeListener =
103             this::onLauncherVisibilityChanged;
104 
105     // Initialized in init.
106     private final TaskbarLauncherStateController
107             mTaskbarLauncherStateController = new TaskbarLauncherStateController();
108     // When overview-in-a-window is enabled, that window is the container, else it is mLauncher.
109     private RecentsViewContainer mRecentsViewContainer;
110 
LauncherTaskbarUIController(QuickstepLauncher launcher)111     public LauncherTaskbarUIController(QuickstepLauncher launcher) {
112         mLauncher = launcher;
113         mHomeState =  SystemUiProxy.INSTANCE.get(mLauncher).getHomeVisibilityState();
114     }
115 
116     @Override
init(TaskbarControllers taskbarControllers)117     protected void init(TaskbarControllers taskbarControllers) {
118         super.init(taskbarControllers);
119 
120         mTaskbarLauncherStateController.init(mControllers, mLauncher,
121                 mControllers.getSharedState().sysuiStateFlags);
122         final TaskbarActivityContext taskbarContext = mControllers.taskbarActivityContext;
123         if (RecentsWindowFlags.getEnableOverviewInWindow()) {
124             mRecentsViewContainer = RecentsDisplayModel.getINSTANCE()
125                     .get(taskbarContext).getRecentsWindowManager(taskbarContext.getDisplayId());
126         }
127         if (mRecentsViewContainer == null) {
128             mRecentsViewContainer = mLauncher;
129         }
130         mLauncher.setTaskbarUIController(this);
131         if (mRecentsViewContainer != mLauncher) {
132             mRecentsViewContainer.setTaskbarUIController(this);
133         }
134 
135         mHomeState.addListener(mVisibilityChangeListener);
136         onLauncherVisibilityChanged(
137                 Flags.useActivityOverlay()
138                         ? mHomeState.isHomeVisible() : mLauncher.hasBeenResumed(),
139                 true /* fromInit */);
140 
141         onStashedInAppChanged(mLauncher.getDeviceProfile());
142         mLauncher.addOnDeviceProfileChangeListener(mOnDeviceProfileChangeListener);
143 
144         // Restore the in-app display progress from before Taskbar was recreated.
145         float[] prevProgresses = mControllers.getSharedState().inAppDisplayProgressMultiPropValues;
146         // Make a copy of the previous progress to set since updating the multiprop will update
147         // the property which also calls onInAppDisplayProgressChanged() which writes the current
148         // values into the shared state
149         prevProgresses = Arrays.copyOf(prevProgresses, prevProgresses.length);
150         for (int i = 0; i < prevProgresses.length; i++) {
151             mTaskbarInAppDisplayProgressMultiProp.get(i).setValue(prevProgresses[i]);
152         }
153     }
154 
155     @Override
onDestroy()156     protected void onDestroy() {
157         onLauncherVisibilityChanged(false /* isVisible */, true /* fromInitOrDestroy */);
158         mLauncher.removeOnDeviceProfileChangeListener(mOnDeviceProfileChangeListener);
159         super.onDestroy();
160         mTaskbarLauncherStateController.onDestroy();
161 
162         mLauncher.setTaskbarUIController(null);
163         if (mRecentsViewContainer != mLauncher) {
164             mRecentsViewContainer.setTaskbarUIController(null);
165         }
166         mHomeState.removeListener(mVisibilityChangeListener);
167     }
168 
onInAppDisplayProgressChanged()169     private void onInAppDisplayProgressChanged() {
170         if (mControllers != null) {
171             // Update our shared state so we can restore it if taskbar gets recreated.
172             for (int i = 0; i < DISPLAY_PROGRESS_COUNT; i++) {
173                 mControllers.getSharedState().inAppDisplayProgressMultiPropValues[i] =
174                         mTaskbarInAppDisplayProgressMultiProp.get(i).getValue();
175             }
176             // Ensure nav buttons react to our latest state if necessary.
177             mControllers.navbarButtonsViewController.updateNavButtonTranslationY();
178         }
179     }
180 
181     @Override
isTaskbarTouchable()182     protected boolean isTaskbarTouchable() {
183         // Touching down during animation to Hotseat will end the transition and allow the touch to
184         // go through to the Hotseat directly.
185         return !isAnimatingToHotseat();
186     }
187 
setShouldDelayLauncherStateAnim(boolean shouldDelayLauncherStateAnim)188     public void setShouldDelayLauncherStateAnim(boolean shouldDelayLauncherStateAnim) {
189         mTaskbarLauncherStateController.setShouldDelayLauncherStateAnim(
190                 shouldDelayLauncherStateAnim);
191     }
192 
193     @Override
stashHotseat(boolean stash)194     public void stashHotseat(boolean stash) {
195         mTaskbarLauncherStateController.stashHotseat(stash);
196     }
197 
198     @Override
unStashHotseatInstantly()199     public void unStashHotseatInstantly() {
200         mTaskbarLauncherStateController.unStashHotseatInstantly();
201     }
202 
203     /**
204      * Adds the Launcher resume animator to the given animator set.
205      *
206      * This should be used to run a Launcher resume animation whose progress matches a
207      * swipe progress.
208      *
209      * @param placeholderDuration a placeholder duration to be used to ensure all full-length
210      *                            sub-animations are properly coordinated. This duration should not
211      *                            actually be used since this animation tracks a swipe progress.
212      */
addLauncherVisibilityChangedAnimation(AnimatorSet animation, int placeholderDuration)213     protected void addLauncherVisibilityChangedAnimation(AnimatorSet animation,
214             int placeholderDuration) {
215         animation.play(onLauncherVisibilityChanged(
216                 /* isResumed= */ true,
217                 /* fromInit= */ false,
218                 /* startAnimation= */ false,
219                 placeholderDuration));
220     }
221 
222     /**
223      * Should be called from onResume() and onPause(), and animates the Taskbar accordingly.
224      */
225     @Override
onLauncherVisibilityChanged(boolean isVisible)226     public void onLauncherVisibilityChanged(boolean isVisible) {
227         if (DesktopModeStatus.enterDesktopByDefaultOnFreeformDisplay(mLauncher)
228                 && mControllers.taskbarActivityContext.isPrimaryDisplay()) {
229             DisplayController.INSTANCE.get(mLauncher).notifyConfigChange();
230         }
231 
232         onLauncherVisibilityChanged(isVisible, false /* fromInit */);
233     }
234 
onLauncherVisibilityChanged(boolean isVisible, boolean fromInitOrDestroy)235     private void onLauncherVisibilityChanged(boolean isVisible, boolean fromInitOrDestroy) {
236         if (mControllers == null) {
237             return;
238         }
239         onLauncherVisibilityChanged(
240                 isVisible,
241                 fromInitOrDestroy,
242                 /* startAnimation= */ true,
243                 getTaskbarAnimationDuration(isVisible));
244     }
245 
getTaskbarAnimationDuration(boolean isVisible)246     private int getTaskbarAnimationDuration(boolean isVisible) {
247         // fast animation duration since we will not be playing workspace reveal animation.
248         boolean shouldOverrideToFastAnimation = !isHotseatIconOnTopWhenAligned();
249         if (!Flags.predictiveBackToHomePolish()) {
250             shouldOverrideToFastAnimation |= mLauncher.getPredictiveBackToHomeInProgress();
251         }
252 
253         boolean isPinned = mControllers.taskbarActivityContext.isPinnedTaskbar();
254         if (isVisible || isPinned) {
255             return getTaskbarToHomeDuration(shouldOverrideToFastAnimation, isPinned);
256         } else {
257             return (mControllers.taskbarActivityContext.isTransientTaskbar())
258                     ? TRANSIENT_TASKBAR_TRANSITION_DURATION : TASKBAR_TO_APP_DURATION;
259         }
260     }
261 
262     @Nullable
onLauncherVisibilityChanged( boolean isVisible, boolean fromInitOrDestroy, boolean startAnimation, int duration)263     private Animator onLauncherVisibilityChanged(
264             boolean isVisible, boolean fromInitOrDestroy, boolean startAnimation, int duration) {
265         // Launcher is resumed during the swipe-to-overview gesture under shell-transitions, so
266         // avoid updating taskbar state in that situation (when it's non-interactive -- or
267         // "background") to avoid premature animations.
268         LauncherState state = mTaskbarLauncherStateController.getLauncherState();
269         boolean nonInteractiveState = state.hasFlag(FLAG_NON_INTERACTIVE)
270                 && !state.isTaskbarAlignedWithHotseat(mLauncher);
271         if (isVisible && (nonInteractiveState || mSkipLauncherVisibilityChange)) {
272             return null;
273         }
274 
275         if (!ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY.isTrue()
276                 && mControllers.taskbarDesktopModeController
277                     .isInDesktopModeAndNotInOverview(mLauncher.getDisplayId())) {
278             // TODO: b/333533253 - Remove after flag rollout
279             isVisible = false;
280         }
281 
282         mTaskbarLauncherStateController.updateStateForFlag(FLAG_VISIBLE, isVisible);
283         if (fromInitOrDestroy) {
284             duration = 0;
285         }
286         return mTaskbarLauncherStateController.applyState(duration, startAnimation);
287     }
288 
289     @Override
onStateTransitionCompletedAfterSwipeToHome(LauncherState state)290     public void onStateTransitionCompletedAfterSwipeToHome(LauncherState state) {
291         mTaskbarLauncherStateController.onStateTransitionCompletedAfterSwipeToHome(state);
292     }
293 
294     @Override
refreshResumedState()295     public void refreshResumedState() {
296         onLauncherVisibilityChanged(Flags.useActivityOverlay()
297                 ? mHomeState.isHomeVisible() : mLauncher.hasBeenResumed());
298     }
299 
300     @Override
adjustHotseatForBubbleBar(boolean isBubbleBarVisible)301     public void adjustHotseatForBubbleBar(boolean isBubbleBarVisible) {
302         if (mLauncher.getHotseat() != null) {
303             mLauncher.getHotseat().adjustForBubbleBar(isBubbleBarVisible);
304         }
305     }
306 
postAdjustHotseatForBubbleBar()307     private void postAdjustHotseatForBubbleBar() {
308         Hotseat hotseat = mLauncher.getHotseat();
309         if (hotseat == null || !isBubbleBarVisible()) return;
310         hotseat.post(() -> {
311             if (mControllers == null) return;
312             adjustHotseatForBubbleBar(isBubbleBarVisible());
313         });
314     }
315 
isBubbleBarVisible()316     private boolean isBubbleBarVisible() {
317         BubbleControllers bubbleControllers = mControllers.bubbleControllers.orElse(null);
318         return bubbleControllers != null
319                 && bubbleControllers.bubbleBarViewController.isBubbleBarVisible();
320     }
321 
322     /**
323      * Create Taskbar animation when going from an app to Launcher as part of recents transition.
324      * {@inheritDoc}
325      */
326     @Override
getParallelAnimationToGestureEndTarget( GestureState.GestureEndTarget gestureEndTarget, long duration, RecentsAnimationCallbacks callbacks)327     public Animator getParallelAnimationToGestureEndTarget(
328             GestureState.GestureEndTarget gestureEndTarget, long duration,
329             RecentsAnimationCallbacks callbacks) {
330         return mTaskbarLauncherStateController.createAnimToLauncher(
331                 LauncherActivityInterface.INSTANCE.stateFromGestureEndTarget(gestureEndTarget),
332                 callbacks,
333                 duration);
334     }
335 
336     /**
337      * Create Taskbar animation to be played alongside the Launcher app launch animation.
338      */
createAnimToApp()339     public @Nullable Animator createAnimToApp() {
340         if (!syncAppLaunchWithTaskbarStash()) {
341             return null;
342         }
343         TaskbarStashController stashController = mControllers.taskbarStashController;
344         stashController.updateStateForFlag(TaskbarStashController.FLAG_IN_APP, true);
345         return stashController.createApplyStateAnimator(stashController.getStashDuration());
346     }
347 
348     /**
349      * Temporarily ignore FLAG_IN_APP for app launches to prevent premature taskbar stashing.
350      * This is needed because taskbar gets a signal to stash before we actually start the
351      * app launch animation.
352      */
setIgnoreInAppFlagForSync(boolean enabled)353     public void setIgnoreInAppFlagForSync(boolean enabled) {
354         if (syncAppLaunchWithTaskbarStash()) {
355             mControllers.taskbarStashController.updateStateForFlag(FLAG_IGNORE_IN_APP, enabled);
356         }
357     }
358 
updateTaskbarLauncherStateGoingHome()359     public void updateTaskbarLauncherStateGoingHome() {
360         mTaskbarLauncherStateController.updateStateForFlag(FLAG_VISIBLE, true);
361         mTaskbarLauncherStateController.applyState();
362     }
363 
isDraggingItem()364     public boolean isDraggingItem() {
365         boolean bubblesDragging = false;
366         if (mControllers.bubbleControllers.isPresent()) {
367             bubblesDragging =
368                     mControllers.bubbleControllers.get().bubbleDragController.isDragging();
369         }
370         return mControllers.taskbarDragController.isDragging() || bubblesDragging;
371     }
372 
373     @Override
onStashedInAppChanged()374     protected void onStashedInAppChanged() {
375         onStashedInAppChanged(mLauncher.getDeviceProfile());
376     }
377 
onStashedInAppChanged(DeviceProfile deviceProfile)378     private void onStashedInAppChanged(DeviceProfile deviceProfile) {
379         boolean taskbarStashedInApps = mControllers.taskbarStashController.isStashedInApp();
380         deviceProfile.isTaskbarPresentInApps = !taskbarStashedInApps;
381     }
382 
383     /**
384      * Starts a Taskbar EDU flow, if the user should see one upon launching an application.
385      */
showEduOnAppLaunch()386     public void showEduOnAppLaunch() {
387         if (!shouldShowEduOnAppLaunch()) {
388             // Called in case the edu finishes and search edu is still pending
389             mControllers.taskbarEduTooltipController.maybeShowSearchEdu();
390             return;
391         }
392 
393         // Persistent features EDU tooltip.
394         if (!mControllers.taskbarActivityContext.isTransientTaskbar()) {
395             mControllers.taskbarEduTooltipController.maybeShowFeaturesEdu();
396             return;
397         }
398 
399         // Transient swipe EDU tooltip.
400         mControllers.taskbarEduTooltipController.maybeShowSwipeEdu();
401     }
402 
403     /** Will make the next onRecentsAnimationFinished() animation a no-op. */
setSkipNextRecentsAnimEnd()404     public void setSkipNextRecentsAnimEnd() {
405         mTaskbarLauncherStateController.setSkipNextRecentsAnimEnd();
406     }
407 
408     /**
409      * Returns {@code true} if a Taskbar education should be shown on application launch.
410      */
shouldShowEduOnAppLaunch()411     public boolean shouldShowEduOnAppLaunch() {
412         if (Utilities.isRunningInTestHarness()) {
413             return false;
414         }
415 
416         // Persistent features EDU tooltip.
417         if (!mControllers.taskbarActivityContext.isTransientTaskbar()) {
418             return !OnboardingPrefs.TASKBAR_EDU_TOOLTIP_STEP.hasReachedMax(mLauncher);
419         }
420 
421         // Transient swipe EDU tooltip.
422         return mControllers.taskbarEduTooltipController.getTooltipStep() < TOOLTIP_STEP_FEATURES;
423     }
424 
425     @Override
onTaskbarIconLaunched(ItemInfo item)426     public void onTaskbarIconLaunched(ItemInfo item) {
427         super.onTaskbarIconLaunched(item);
428         InstanceId instanceId = new InstanceIdSequence().newInstanceId();
429         mLauncher.logAppLaunch(mControllers.taskbarActivityContext.getStatsLogManager(), item,
430                 instanceId);
431     }
432 
433     /**
434      * Animates Taskbar elements during a transition to a Launcher state that should use in-app
435      * layouts.
436      *
437      * @param progress [0, 1]
438      *                 0 => use home layout
439      *                 1 => use in-app layout
440      */
onTaskbarInAppDisplayProgressUpdate(float progress, int progressIndex)441     public void onTaskbarInAppDisplayProgressUpdate(float progress, int progressIndex) {
442         mTaskbarInAppDisplayProgressMultiProp.get(progressIndex).setValue(progress);
443         if (mControllers == null) {
444             // This method can be called before init() is called.
445             return;
446         }
447         if (mControllers.uiController.isIconAlignedWithHotseat()) {
448             if (!mTaskbarLauncherStateController.isAnimatingToLauncher()) {
449                 // Only animate the nav buttons while home and not animating home, otherwise let
450                 // the TaskbarViewController handle it.
451                 mControllers.navbarButtonsViewController
452                         .getTaskbarNavButtonTranslationYForInAppDisplay()
453                         .updateValue(mLauncher.getDeviceProfile().getTaskbarOffsetY()
454                                 * mTaskbarInAppDisplayProgress.value);
455                 mControllers.navbarButtonsViewController
456                         .getOnTaskbarBackgroundNavButtonColorOverride().updateValue(progress);
457             }
458             if (isBubbleBarEnabled()) {
459                 mControllers.bubbleControllers.ifPresent(
460                         c -> c.bubbleStashController.setInAppDisplayOverrideProgress(
461                                 mTaskbarInAppDisplayProgress.value));
462             }
463         }
464     }
465 
466     /** Returns true iff any in-app display progress > 0. */
shouldUseInAppLayout()467     public boolean shouldUseInAppLayout() {
468         return mTaskbarInAppDisplayProgress.value > 0;
469     }
470 
isBubbleBarEnabled()471     public boolean isBubbleBarEnabled() {
472         return BubbleBarController.isBubbleBarEnabled();
473     }
474 
475     /** Whether the bubble bar has any bubbles. */
hasBubbles()476     public boolean hasBubbles() {
477         if (mControllers == null) {
478             return false;
479         }
480         if (mControllers.bubbleControllers.isEmpty()) {
481             return false;
482         }
483         return mControllers.bubbleControllers.get().bubbleBarViewController.hasBubbles();
484     }
485 
486     @Override
onExpandPip()487     public void onExpandPip() {
488         super.onExpandPip();
489         mTaskbarLauncherStateController.updateStateForFlag(FLAG_VISIBLE, false);
490         mTaskbarLauncherStateController.applyState();
491     }
492 
493     @Override
updateStateForSysuiFlags(@ystemUiStateFlags long sysuiFlags)494     public void updateStateForSysuiFlags(@SystemUiStateFlags long sysuiFlags) {
495         mTaskbarLauncherStateController.updateStateForSysuiFlags(sysuiFlags);
496     }
497 
498     @Override
isIconAlignedWithHotseat()499     public boolean isIconAlignedWithHotseat() {
500         return mTaskbarLauncherStateController.isIconAlignedWithHotseat();
501     }
502 
503     @Override
isHotseatIconOnTopWhenAligned()504     public boolean isHotseatIconOnTopWhenAligned() {
505         return mTaskbarLauncherStateController.isInHotseatOnTopStates()
506                 && mTaskbarInAppDisplayProgressMultiProp.get(MINUS_ONE_PAGE_PROGRESS_INDEX)
507                     .getValue() == 0;
508     }
509 
510     @Override
isAnimatingToHotseat()511     public boolean isAnimatingToHotseat() {
512         return mTaskbarLauncherStateController.isAnimatingToLauncher()
513                 && isIconAlignedWithHotseat();
514     }
515 
516     @Override
endAnimationToHotseat()517     public void endAnimationToHotseat() {
518         mTaskbarLauncherStateController.resetIconAlignment();
519     }
520 
521     @Override
isInOverviewUi()522     protected boolean isInOverviewUi() {
523         return mTaskbarLauncherStateController.isInOverviewUi();
524     }
525 
526     @Override
toggleAllApps(boolean focusSearch)527     protected void toggleAllApps(boolean focusSearch) {
528         boolean canToggleHomeAllApps = mLauncher.isResumed()
529                 && !mTaskbarLauncherStateController.isInOverviewUi()
530                 && !mLauncher.areDesktopTasksVisible();
531         if (canToggleHomeAllApps) {
532             mLauncher.toggleAllApps(focusSearch);
533             return;
534         }
535         super.toggleAllApps(focusSearch);
536     }
537 
538     @Override
getRecentsView()539     public RecentsView getRecentsView() {
540         return mRecentsViewContainer.getOverviewPanel();
541     }
542 
543     @Override
launchSplitTasks( @onNull SplitTask splitTask, @Nullable RemoteTransition remoteTransition)544     public void launchSplitTasks(
545             @NonNull SplitTask splitTask, @Nullable RemoteTransition remoteTransition) {
546         mLauncher.launchSplitTasks(splitTask, remoteTransition);
547     }
548 
549     @Override
onIconLayoutBoundsChanged()550     protected void onIconLayoutBoundsChanged() {
551         mTaskbarLauncherStateController.resetIconAlignment();
552     }
553 
554     @Override
dumpLogs(String prefix, PrintWriter pw)555     public void dumpLogs(String prefix, PrintWriter pw) {
556         super.dumpLogs(prefix, pw);
557 
558         pw.println(String.format("%s\tTaskbar in-app display progress: %.2f", prefix,
559                 mTaskbarInAppDisplayProgress.value));
560         mTaskbarInAppDisplayProgressMultiProp.dump(
561                 prefix + "\t\t",
562                 pw,
563                 "mTaskbarInAppDisplayProgressMultiProp",
564                 "MINUS_ONE_PAGE_PROGRESS_INDEX",
565                 "ALL_APPS_PAGE_PROGRESS_INDEX",
566                 "WIDGETS_PAGE_PROGRESS_INDEX",
567                 "SYSUI_SURFACE_PROGRESS_INDEX",
568                 "LAUNCHER_PAUSE_PROGRESS_INDEX");
569         pw.println(String.format("%s\tmRecentsWindowContainer=%s", prefix, mRecentsViewContainer));
570 
571         mTaskbarLauncherStateController.dumpLogs(prefix + "\t", pw);
572     }
573 
574     @Override
getTaskbarUIControllerName()575     protected String getTaskbarUIControllerName() {
576         return "LauncherTaskbarUIController";
577     }
578 
579     @Override
onBubbleBarLocationAnimated(BubbleBarLocation location)580     public void onBubbleBarLocationAnimated(BubbleBarLocation location) {
581         mTaskbarLauncherStateController.onBubbleBarLocationChanged(location, /* animate = */ true);
582         mLauncher.setBubbleBarLocation(location);
583     }
584 
585     @Override
onBubbleBarLocationUpdated(BubbleBarLocation location)586     public void onBubbleBarLocationUpdated(BubbleBarLocation location) {
587         mTaskbarLauncherStateController.onBubbleBarLocationChanged(location, /* animate = */ false);
588         mLauncher.setBubbleBarLocation(location);
589     }
590 
591     @Override
onSwipeToUnstashTaskbar()592     public void onSwipeToUnstashTaskbar() {
593         // Once taskbar is unstashed, the user cannot return back to the overlay. We can
594         // clear it here to set the expected state once the user goes home.
595         if (mLauncher.getWorkspace().isOverlayShown()) {
596             mLauncher.getWorkspace().onOverlayScrollChanged(0);
597         }
598     }
599 
600     /**
601      * Called when Launcher Activity resumed while staying at home.
602      * <p>
603      * Shift nav buttons up to at-home position.
604      */
onLauncherResume()605     public void onLauncherResume() {
606         mLauncherPauseProgress.animateToValue(0.0f).start();
607     }
608 
609     /**
610      * Called when Launcher Activity paused while staying at home.
611      * <p>
612      * To avoid UI clash between taskbar & bottom sheet, shift nav buttons down to in-app position.
613      */
onLauncherPause()614     public void onLauncherPause() {
615         mLauncherPauseProgress.animateToValue(1.0f).start();
616     }
617 
618     /**
619      * On launcher stop, avoid animating taskbar & overriding pre-existing animations.
620      */
onLauncherStop()621     public void onLauncherStop() {
622         mLauncherPauseProgress.cancelAnimation();
623         mLauncherPauseProgress.updateValue(0.0f);
624     }
625 
onLauncherPauseProgressUpdate()626     private void onLauncherPauseProgressUpdate() {
627         // If we are not aligned with hotseat, setting this will clobber the 3 button nav position.
628         // So in that case, treat the progress as 0 instead.
629         float pauseProgress = isIconAlignedWithHotseat() ? mLauncherPauseProgress.value : 0;
630         onTaskbarInAppDisplayProgressUpdate(pauseProgress, LAUNCHER_PAUSE_PROGRESS_INDEX);
631     }
632 
633 
634 }
635