• 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.content.pm.PackageManager.FEATURE_PC;
19 import static android.os.Trace.TRACE_TAG_APP;
20 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
21 import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
22 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
23 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
24 
25 import static com.android.launcher3.AbstractFloatingView.TYPE_ALL;
26 import static com.android.launcher3.AbstractFloatingView.TYPE_REBIND_SAFE;
27 import static com.android.launcher3.Utilities.isRunningInTestHarness;
28 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_OPEN;
29 import static com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_DRAGGING;
30 import static com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_FULLSCREEN;
31 import static com.android.launcher3.taskbar.TaskbarManager.FLAG_HIDE_NAVBAR_WINDOW;
32 import static com.android.launcher3.testing.shared.ResourceUtils.getBoolByName;
33 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE;
34 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING;
35 
36 import android.animation.AnimatorSet;
37 import android.animation.ValueAnimator;
38 import android.app.ActivityOptions;
39 import android.content.ActivityNotFoundException;
40 import android.content.Context;
41 import android.content.Intent;
42 import android.content.pm.ActivityInfo.Config;
43 import android.content.pm.LauncherApps;
44 import android.content.res.Resources;
45 import android.graphics.PixelFormat;
46 import android.graphics.Rect;
47 import android.hardware.display.DisplayManager;
48 import android.os.Process;
49 import android.os.SystemProperties;
50 import android.os.Trace;
51 import android.provider.Settings;
52 import android.util.Log;
53 import android.view.Display;
54 import android.view.Gravity;
55 import android.view.RoundedCorner;
56 import android.view.View;
57 import android.view.WindowManager;
58 import android.widget.FrameLayout;
59 import android.widget.Toast;
60 
61 import androidx.annotation.NonNull;
62 import androidx.annotation.Nullable;
63 import androidx.annotation.VisibleForTesting;
64 
65 import com.android.launcher3.AbstractFloatingView;
66 import com.android.launcher3.BubbleTextView;
67 import com.android.launcher3.DeviceProfile;
68 import com.android.launcher3.LauncherSettings.Favorites;
69 import com.android.launcher3.R;
70 import com.android.launcher3.anim.AnimatorPlaybackController;
71 import com.android.launcher3.config.FeatureFlags;
72 import com.android.launcher3.dot.DotInfo;
73 import com.android.launcher3.folder.Folder;
74 import com.android.launcher3.folder.FolderIcon;
75 import com.android.launcher3.logger.LauncherAtom;
76 import com.android.launcher3.logging.StatsLogManager;
77 import com.android.launcher3.model.data.AppInfo;
78 import com.android.launcher3.model.data.FolderInfo;
79 import com.android.launcher3.model.data.ItemInfo;
80 import com.android.launcher3.model.data.WorkspaceItemInfo;
81 import com.android.launcher3.popup.PopupContainerWithArrow;
82 import com.android.launcher3.popup.PopupDataProvider;
83 import com.android.launcher3.taskbar.TaskbarAutohideSuspendController.AutohideSuspendFlag;
84 import com.android.launcher3.taskbar.TaskbarTranslationController.TransitionCallback;
85 import com.android.launcher3.taskbar.allapps.TaskbarAllAppsController;
86 import com.android.launcher3.taskbar.overlay.TaskbarOverlayController;
87 import com.android.launcher3.testing.TestLogging;
88 import com.android.launcher3.testing.shared.TestProtocol;
89 import com.android.launcher3.touch.ItemClickHandler;
90 import com.android.launcher3.touch.ItemClickHandler.ItemClickProxy;
91 import com.android.launcher3.util.ComponentKey;
92 import com.android.launcher3.util.DisplayController;
93 import com.android.launcher3.util.NavigationMode;
94 import com.android.launcher3.util.PackageManagerHelper;
95 import com.android.launcher3.util.SettingsCache;
96 import com.android.launcher3.util.SplitConfigurationOptions.SplitSelectSource;
97 import com.android.launcher3.util.TraceHelper;
98 import com.android.launcher3.util.ViewCache;
99 import com.android.launcher3.views.ActivityContext;
100 import com.android.quickstep.views.RecentsView;
101 import com.android.quickstep.views.TaskView;
102 import com.android.systemui.shared.recents.model.Task;
103 import com.android.systemui.shared.rotation.RotationButtonController;
104 import com.android.systemui.shared.system.ActivityManagerWrapper;
105 import com.android.systemui.unfold.updates.RotationChangeProvider;
106 import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider;
107 
108 import java.io.PrintWriter;
109 
110 /**
111  * The {@link ActivityContext} with which we inflate Taskbar-related Views. This allows UI elements
112  * that are used by both Launcher and Taskbar (such as Folder) to reference a generic
113  * ActivityContext and BaseDragLayer instead of the Launcher activity and its DragLayer.
114  */
115 public class TaskbarActivityContext extends BaseTaskbarContext {
116 
117     private static final String IME_DRAWS_IME_NAV_BAR_RES_NAME = "config_imeDrawsImeNavBar";
118 
119     private static final boolean ENABLE_THREE_BUTTON_TASKBAR =
120             SystemProperties.getBoolean("persist.debug.taskbar_three_button", false);
121     private static final String TAG = "TaskbarActivityContext";
122 
123     private static final String WINDOW_TITLE = "Taskbar";
124 
125     private final TaskbarDragLayer mDragLayer;
126     private final TaskbarControllers mControllers;
127 
128     private final WindowManager mWindowManager;
129     private final @Nullable RoundedCorner mLeftCorner, mRightCorner;
130     private DeviceProfile mDeviceProfile;
131     private WindowManager.LayoutParams mWindowLayoutParams;
132     private boolean mIsFullscreen;
133     // The size we should return to when we call setTaskbarWindowFullscreen(false)
134     private int mLastRequestedNonFullscreenHeight;
135 
136     private NavigationMode mNavMode;
137     private final boolean mImeDrawsImeNavBar;
138     private final ViewCache mViewCache = new ViewCache();
139 
140     private final boolean mIsSafeModeEnabled;
141     private final boolean mIsUserSetupComplete;
142     private final boolean mIsNavBarForceVisible;
143     private final boolean mIsNavBarKidsMode;
144 
145     private boolean mIsDestroyed = false;
146     // The flag to know if the window is excluded from magnification region computation.
147     private boolean mIsExcludeFromMagnificationRegion = false;
148     private boolean mBindingItems = false;
149     private boolean mAddedWindow = false;
150 
151     // The bounds of the taskbar items relative to TaskbarDragLayer
152     private final Rect mTransientTaskbarBounds = new Rect();
153 
154     private final TaskbarShortcutMenuAccessibilityDelegate mAccessibilityDelegate;
155 
TaskbarActivityContext(Context windowContext, DeviceProfile launcherDp, TaskbarNavButtonController buttonController, ScopedUnfoldTransitionProgressProvider unfoldTransitionProgressProvider)156     public TaskbarActivityContext(Context windowContext, DeviceProfile launcherDp,
157             TaskbarNavButtonController buttonController, ScopedUnfoldTransitionProgressProvider
158             unfoldTransitionProgressProvider) {
159         super(windowContext);
160         final Resources resources = getResources();
161 
162         matchDeviceProfile(launcherDp, getResources());
163 
164         mNavMode = DisplayController.getNavigationMode(windowContext);
165         mImeDrawsImeNavBar = getBoolByName(IME_DRAWS_IME_NAV_BAR_RES_NAME, resources, false);
166         mIsSafeModeEnabled = TraceHelper.allowIpcs("isSafeMode",
167                 () -> getPackageManager().isSafeMode());
168         SettingsCache settingsCache = SettingsCache.INSTANCE.get(this);
169         mIsUserSetupComplete = settingsCache.getValue(
170                 Settings.Secure.getUriFor(Settings.Secure.USER_SETUP_COMPLETE), 0);
171         mIsNavBarForceVisible = settingsCache.getValue(
172                 Settings.Secure.getUriFor(Settings.Secure.NAV_BAR_KIDS_MODE), 0);
173         // TODO(b/244231596) For shared Taskbar window, update this value in init() instead so
174         //  to get correct value when recreating the taskbar
175         mIsNavBarKidsMode = settingsCache.getValue(
176                 Settings.Secure.getUriFor(Settings.Secure.NAV_BAR_KIDS_MODE), 0);
177 
178         // Get display and corners first, as views might use them in constructor.
179         Display display = windowContext.getDisplay();
180         Context c = display.getDisplayId() == Display.DEFAULT_DISPLAY
181                 ? windowContext.getApplicationContext()
182                 : windowContext.getApplicationContext().createDisplayContext(display);
183         mWindowManager = c.getSystemService(WindowManager.class);
184         mLeftCorner = display.getRoundedCorner(RoundedCorner.POSITION_BOTTOM_LEFT);
185         mRightCorner = display.getRoundedCorner(RoundedCorner.POSITION_BOTTOM_RIGHT);
186 
187         // Inflate views.
188         int taskbarLayout = DisplayController.isTransientTaskbar(this)
189                 ? R.layout.transient_taskbar
190                 : R.layout.taskbar;
191         mDragLayer = (TaskbarDragLayer) mLayoutInflater.inflate(taskbarLayout, null, false);
192         TaskbarView taskbarView = mDragLayer.findViewById(R.id.taskbar_view);
193         TaskbarScrimView taskbarScrimView = mDragLayer.findViewById(R.id.taskbar_scrim);
194         FrameLayout navButtonsView = mDragLayer.findViewById(R.id.navbuttons_view);
195         StashedHandleView stashedHandleView = mDragLayer.findViewById(R.id.stashed_handle);
196 
197         mAccessibilityDelegate = new TaskbarShortcutMenuAccessibilityDelegate(this);
198 
199         final boolean isDesktopMode = getPackageManager().hasSystemFeature(FEATURE_PC);
200 
201         // Construct controllers.
202         mControllers = new TaskbarControllers(this,
203                 new TaskbarDragController(this),
204                 buttonController,
205                 isDesktopMode
206                         ? new DesktopNavbarButtonsViewController(this, navButtonsView)
207                         : new NavbarButtonsViewController(this, navButtonsView),
208                 new RotationButtonController(this,
209                         c.getColor(R.color.taskbar_nav_icon_light_color),
210                         c.getColor(R.color.taskbar_nav_icon_dark_color),
211                         R.drawable.ic_sysbar_rotate_button_ccw_start_0,
212                         R.drawable.ic_sysbar_rotate_button_ccw_start_90,
213                         R.drawable.ic_sysbar_rotate_button_cw_start_0,
214                         R.drawable.ic_sysbar_rotate_button_cw_start_90,
215                         () -> getDisplay().getRotation()),
216                 new TaskbarDragLayerController(this, mDragLayer),
217                 new TaskbarViewController(this, taskbarView),
218                 new TaskbarScrimViewController(this, taskbarScrimView),
219                 new TaskbarUnfoldAnimationController(this, unfoldTransitionProgressProvider,
220                     mWindowManager,
221                     new RotationChangeProvider(c.getSystemService(DisplayManager.class), this,
222                         getMainThreadHandler())),
223                 new TaskbarKeyguardController(this),
224                 new StashedHandleViewController(this, stashedHandleView),
225                 new TaskbarStashController(this),
226                 new TaskbarEduController(this),
227                 new TaskbarAutohideSuspendController(this),
228                 new TaskbarPopupController(this),
229                 new TaskbarForceVisibleImmersiveController(this),
230                 new TaskbarOverlayController(this, launcherDp),
231                 new TaskbarAllAppsController(),
232                 new TaskbarInsetsController(this),
233                 new VoiceInteractionWindowController(this),
234                 new TaskbarTranslationController(this),
235                 new TaskbarSpringOnStashController(this),
236                 isDesktopMode
237                         ? new DesktopTaskbarRecentAppsController(this)
238                         : TaskbarRecentAppsController.DEFAULT,
239                 new TaskbarEduTooltipController(this),
240                 new KeyboardQuickSwitchController());
241     }
242 
init(@onNull TaskbarSharedState sharedState)243     public void init(@NonNull TaskbarSharedState sharedState) {
244         mLastRequestedNonFullscreenHeight = getDefaultTaskbarWindowHeight();
245         mWindowLayoutParams =
246                 createDefaultWindowLayoutParams(TYPE_NAVIGATION_BAR_PANEL, WINDOW_TITLE);
247 
248         // Initialize controllers after all are constructed.
249         mControllers.init(sharedState);
250         updateSysuiStateFlags(sharedState.sysuiStateFlags, true /* fromInit */);
251         disableNavBarElements(sharedState.disableNavBarDisplayId, sharedState.disableNavBarState1,
252                 sharedState.disableNavBarState2, false /* animate */);
253         onSystemBarAttributesChanged(sharedState.systemBarAttrsDisplayId,
254                 sharedState.systemBarAttrsBehavior);
255         onNavButtonsDarkIntensityChanged(sharedState.navButtonsDarkIntensity);
256 
257 
258         if (!mAddedWindow) {
259             mWindowManager.addView(mDragLayer, mWindowLayoutParams);
260             mAddedWindow = true;
261         } else {
262             mWindowManager.updateViewLayout(mDragLayer, mWindowLayoutParams);
263         }
264     }
265 
266     /**
267      * Show Taskbar upon receiving broadcast
268      */
showTaskbarFromBroadcast()269     public void showTaskbarFromBroadcast() {
270         mControllers.taskbarStashController.showTaskbarFromBroadcast();
271     }
272 
273     @Override
getDeviceProfile()274     public DeviceProfile getDeviceProfile() {
275         return mDeviceProfile;
276     }
277 
278     /** Updates {@link DeviceProfile} instances for any Taskbar windows. */
updateDeviceProfile(DeviceProfile launcherDp, NavigationMode navMode)279     public void updateDeviceProfile(DeviceProfile launcherDp, NavigationMode navMode) {
280         mNavMode = navMode;
281         mControllers.taskbarOverlayController.updateLauncherDeviceProfile(launcherDp);
282         matchDeviceProfile(launcherDp, getResources());
283 
284         AbstractFloatingView.closeAllOpenViewsExcept(this, false, TYPE_REBIND_SAFE);
285         // Reapply fullscreen to take potential new screen size into account.
286         setTaskbarWindowFullscreen(mIsFullscreen);
287 
288         dispatchDeviceProfileChanged();
289     }
290 
291     @Override
dispatchDeviceProfileChanged()292     public void dispatchDeviceProfileChanged() {
293         super.dispatchDeviceProfileChanged();
294         Trace.instantForTrack(TRACE_TAG_APP, "TaskbarActivityContext#DeviceProfileChanged",
295                 getDeviceProfile().toSmallString());
296     }
297 
298     /**
299      * Copy the original DeviceProfile, match the number of hotseat icons and qsb width and update
300      * the icon size
301      */
matchDeviceProfile(DeviceProfile originDeviceProfile, Resources resources)302     private void matchDeviceProfile(DeviceProfile originDeviceProfile, Resources resources) {
303         mDeviceProfile = originDeviceProfile.toBuilder(this)
304                 .withDimensionsOverride(deviceProfile -> {
305                     // Taskbar should match the number of icons of hotseat
306                     deviceProfile.numShownHotseatIcons = originDeviceProfile.numShownHotseatIcons;
307                     // Same QSB width to have a smooth animation
308                     deviceProfile.hotseatQsbWidth = originDeviceProfile.hotseatQsbWidth;
309 
310                     // Update icon size
311                     deviceProfile.iconSizePx = deviceProfile.taskbarIconSize;
312                     deviceProfile.updateIconSize(1f, resources);
313                 }).build();
314     }
315 
316     /**
317      * Returns the View bounds of transient taskbar.
318      */
getTransientTaskbarBounds()319     public Rect getTransientTaskbarBounds() {
320         return mTransientTaskbarBounds;
321     }
322 
323     @Override
getStatsLogManager()324     public StatsLogManager getStatsLogManager() {
325         // Used to mock, can't mock a default interface method directly
326         return super.getStatsLogManager();
327     }
328 
329     /**
330      * Creates LayoutParams for adding a view directly to WindowManager as a new window.
331      * @param type The window type to pass to the created WindowManager.LayoutParams.
332      * @param title The window title to pass to the created WindowManager.LayoutParams.
333      */
createDefaultWindowLayoutParams(int type, String title)334     public WindowManager.LayoutParams createDefaultWindowLayoutParams(int type, String title) {
335         DeviceProfile deviceProfile = getDeviceProfile();
336         // Taskbar is on the logical bottom of the screen
337         boolean isVerticalBarLayout = TaskbarManager.isPhoneMode(deviceProfile) &&
338                 deviceProfile.isLandscape;
339 
340         int windowFlags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
341                 | WindowManager.LayoutParams.FLAG_SLIPPERY
342                 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
343         if (DisplayController.isTransientTaskbar(this) && !isRunningInTestHarness()) {
344             windowFlags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
345                     | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
346         }
347         WindowManager.LayoutParams windowLayoutParams = new WindowManager.LayoutParams(
348                 isVerticalBarLayout ? mLastRequestedNonFullscreenHeight : MATCH_PARENT,
349                 isVerticalBarLayout ? MATCH_PARENT : mLastRequestedNonFullscreenHeight,
350                 type,
351                 windowFlags,
352                 PixelFormat.TRANSLUCENT);
353         windowLayoutParams.setTitle(title);
354         windowLayoutParams.packageName = getPackageName();
355         windowLayoutParams.gravity = !isVerticalBarLayout ?
356                 Gravity.BOTTOM :
357                 Gravity.END; // TODO(b/230394142): seascape
358 
359         windowLayoutParams.setFitInsetsTypes(0);
360         windowLayoutParams.receiveInsetsIgnoringZOrder = true;
361         windowLayoutParams.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
362         windowLayoutParams.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
363         windowLayoutParams.privateFlags =
364                 WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
365         windowLayoutParams.accessibilityTitle = getString(
366                 TaskbarManager.isPhoneMode(mDeviceProfile)
367                         ? R.string.taskbar_phone_a11y_title
368                         : R.string.taskbar_a11y_title);
369         return windowLayoutParams;
370     }
371 
onConfigurationChanged(@onfig int configChanges)372     public void onConfigurationChanged(@Config int configChanges) {
373         mControllers.onConfigurationChanged(configChanges);
374         if (!mIsUserSetupComplete) {
375             setTaskbarWindowHeight(getSetupWindowHeight());
376         }
377     }
378 
isThreeButtonNav()379     public boolean isThreeButtonNav() {
380         return mNavMode == NavigationMode.THREE_BUTTONS;
381     }
382 
isGestureNav()383     public boolean isGestureNav() {
384         return mNavMode == NavigationMode.NO_BUTTON;
385     }
386 
imeDrawsImeNavBar()387     public boolean imeDrawsImeNavBar() {
388         return mImeDrawsImeNavBar;
389     }
390 
getLeftCornerRadius()391     public int getLeftCornerRadius() {
392         return mLeftCorner == null ? 0 : mLeftCorner.getRadius();
393     }
394 
getRightCornerRadius()395     public int getRightCornerRadius() {
396         return mRightCorner == null ? 0 : mRightCorner.getRadius();
397     }
398 
getWindowLayoutParams()399     public WindowManager.LayoutParams getWindowLayoutParams() {
400         return mWindowLayoutParams;
401     }
402 
403     @Override
getDragLayer()404     public TaskbarDragLayer getDragLayer() {
405         return mDragLayer;
406     }
407 
408     @Override
getFolderBoundingBox()409     public Rect getFolderBoundingBox() {
410         return mControllers.taskbarDragLayerController.getFolderBoundingBox();
411     }
412 
413     @Override
getDragController()414     public TaskbarDragController getDragController() {
415         return mControllers.taskbarDragController;
416     }
417 
418     @Override
getViewCache()419     public ViewCache getViewCache() {
420         return mViewCache;
421     }
422 
423     @Override
getItemOnClickListener()424     public View.OnClickListener getItemOnClickListener() {
425         return this::onTaskbarIconClicked;
426     }
427 
428     /**
429      * Change from hotseat/predicted hotseat to taskbar container.
430      */
431     @Override
applyOverwritesToLogItem(LauncherAtom.ItemInfo.Builder itemInfoBuilder)432     public void applyOverwritesToLogItem(LauncherAtom.ItemInfo.Builder itemInfoBuilder) {
433         if (!itemInfoBuilder.hasContainerInfo()) {
434             return;
435         }
436         LauncherAtom.ContainerInfo oldContainer = itemInfoBuilder.getContainerInfo();
437 
438         LauncherAtom.TaskBarContainer.Builder taskbarBuilder =
439                 LauncherAtom.TaskBarContainer.newBuilder();
440         if (mControllers.uiController.isInOverview()) {
441             taskbarBuilder.setTaskSwitcherContainer(
442                     LauncherAtom.TaskSwitcherContainer.newBuilder());
443         }
444 
445         if (oldContainer.hasPredictedHotseatContainer()) {
446             LauncherAtom.PredictedHotseatContainer predictedHotseat =
447                     oldContainer.getPredictedHotseatContainer();
448 
449             if (predictedHotseat.hasIndex()) {
450                 taskbarBuilder.setIndex(predictedHotseat.getIndex());
451             }
452             if (predictedHotseat.hasCardinality()) {
453                 taskbarBuilder.setCardinality(predictedHotseat.getCardinality());
454             }
455 
456             itemInfoBuilder.setContainerInfo(LauncherAtom.ContainerInfo.newBuilder()
457                     .setTaskBarContainer(taskbarBuilder));
458         } else if (oldContainer.hasHotseat()) {
459             LauncherAtom.HotseatContainer hotseat = oldContainer.getHotseat();
460 
461             if (hotseat.hasIndex()) {
462                 taskbarBuilder.setIndex(hotseat.getIndex());
463             }
464 
465             itemInfoBuilder.setContainerInfo(LauncherAtom.ContainerInfo.newBuilder()
466                     .setTaskBarContainer(taskbarBuilder));
467         } else if (oldContainer.hasFolder() && oldContainer.getFolder().hasHotseat()) {
468             LauncherAtom.FolderContainer.Builder folderBuilder = oldContainer.getFolder()
469                     .toBuilder();
470             LauncherAtom.HotseatContainer hotseat = folderBuilder.getHotseat();
471 
472             if (hotseat.hasIndex()) {
473                 taskbarBuilder.setIndex(hotseat.getIndex());
474             }
475 
476             folderBuilder.setTaskbar(taskbarBuilder);
477             folderBuilder.clearHotseat();
478             itemInfoBuilder.setContainerInfo(LauncherAtom.ContainerInfo.newBuilder()
479                     .setFolder(folderBuilder));
480         } else if (oldContainer.hasAllAppsContainer()) {
481             itemInfoBuilder.setContainerInfo(LauncherAtom.ContainerInfo.newBuilder()
482                     .setAllAppsContainer(oldContainer.getAllAppsContainer().toBuilder()
483                             .setTaskbarContainer(taskbarBuilder)));
484         } else if (oldContainer.hasPredictionContainer()) {
485             itemInfoBuilder.setContainerInfo(LauncherAtom.ContainerInfo.newBuilder()
486                     .setPredictionContainer(oldContainer.getPredictionContainer().toBuilder()
487                             .setTaskbarContainer(taskbarBuilder)));
488         }
489     }
490 
491     @Override
getDotInfoForItem(ItemInfo info)492     public DotInfo getDotInfoForItem(ItemInfo info) {
493         return getPopupDataProvider().getDotInfoForItem(info);
494     }
495 
496     @NonNull
497     @Override
getPopupDataProvider()498     public PopupDataProvider getPopupDataProvider() {
499         return mControllers.taskbarPopupController.getPopupDataProvider();
500     }
501 
502     @Override
getAccessibilityDelegate()503     public View.AccessibilityDelegate getAccessibilityDelegate() {
504         return mAccessibilityDelegate;
505     }
506 
507     @Override
isBindingItems()508     public boolean isBindingItems() {
509         return mBindingItems;
510     }
511 
setBindingItems(boolean bindingItems)512     public void setBindingItems(boolean bindingItems) {
513         mBindingItems = bindingItems;
514     }
515 
516     @Override
onDragStart()517     public void onDragStart() {
518         setTaskbarWindowFullscreen(true);
519     }
520 
521     @Override
onDragEnd()522     public void onDragEnd() {
523         onDragEndOrViewRemoved();
524     }
525 
526     @Override
onPopupVisibilityChanged(boolean isVisible)527     public void onPopupVisibilityChanged(boolean isVisible) {
528         setTaskbarWindowFocusable(isVisible);
529     }
530 
531     @Override
onSplitScreenMenuButtonClicked()532     public void onSplitScreenMenuButtonClicked() {
533         PopupContainerWithArrow popup = PopupContainerWithArrow.getOpen(this);
534         if (popup != null) {
535             popup.addOnCloseCallback(() -> {
536                 mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(true);
537             });
538         }
539     }
540 
541     /**
542      * Sets a new data-source for this taskbar instance
543      */
setUIController(@onNull TaskbarUIController uiController)544     public void setUIController(@NonNull TaskbarUIController uiController) {
545         mControllers.uiController.onDestroy();
546         mControllers.uiController = uiController;
547         mControllers.uiController.init(mControllers);
548     }
549 
550     /**
551      * Sets the flag indicating setup UI is visible
552      */
setSetupUIVisible(boolean isVisible)553     public void setSetupUIVisible(boolean isVisible) {
554         mControllers.taskbarStashController.setSetupUIVisible(isVisible);
555     }
556 
557     /**
558      * Called when this instance of taskbar is no longer needed
559      */
onDestroy()560     public void onDestroy() {
561         mIsDestroyed = true;
562         setUIController(TaskbarUIController.DEFAULT);
563         mControllers.onDestroy();
564         if (!FLAG_HIDE_NAVBAR_WINDOW) {
565             mWindowManager.removeViewImmediate(mDragLayer);
566             mAddedWindow = false;
567         }
568     }
569 
isDestroyed()570     public boolean isDestroyed() {
571         return mIsDestroyed;
572     }
573 
updateSysuiStateFlags(int systemUiStateFlags, boolean fromInit)574     public void updateSysuiStateFlags(int systemUiStateFlags, boolean fromInit) {
575         mControllers.navbarButtonsViewController.updateStateForSysuiFlags(systemUiStateFlags,
576                 fromInit);
577         boolean isShadeVisible = (systemUiStateFlags & SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE) != 0;
578         onNotificationShadeExpandChanged(isShadeVisible, fromInit);
579         mControllers.taskbarViewController.setRecentsButtonDisabled(
580                 mControllers.navbarButtonsViewController.isRecentsDisabled()
581                         || isNavBarKidsModeActive());
582         mControllers.stashedHandleViewController.setIsHomeButtonDisabled(
583                 mControllers.navbarButtonsViewController.isHomeDisabled());
584         mControllers.stashedHandleViewController.updateStateForSysuiFlags(systemUiStateFlags);
585         mControllers.taskbarKeyguardController.updateStateForSysuiFlags(systemUiStateFlags);
586         mControllers.taskbarStashController.updateStateForSysuiFlags(
587                 systemUiStateFlags, fromInit || !isUserSetupComplete());
588         mControllers.taskbarScrimViewController.updateStateForSysuiFlags(systemUiStateFlags,
589                 fromInit);
590         mControllers.navButtonController.updateSysuiFlags(systemUiStateFlags);
591         mControllers.taskbarForceVisibleImmersiveController.updateSysuiFlags(systemUiStateFlags);
592         mControllers.voiceInteractionWindowController.setIsVoiceInteractionWindowVisible(
593                 (systemUiStateFlags & SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING) != 0, fromInit);
594 
595         mControllers.uiController.updateStateForSysuiFlags(systemUiStateFlags, fromInit);
596     }
597 
598     /**
599      * Hides the taskbar icons and background when the notication shade is expanded.
600      */
onNotificationShadeExpandChanged(boolean isExpanded, boolean skipAnim)601     private void onNotificationShadeExpandChanged(boolean isExpanded, boolean skipAnim) {
602         float alpha = isExpanded ? 0 : 1;
603         AnimatorSet anim = new AnimatorSet();
604         anim.play(mControllers.taskbarViewController.getTaskbarIconAlpha().get(
605                 TaskbarViewController.ALPHA_INDEX_NOTIFICATION_EXPANDED).animateToValue(alpha));
606         anim.play(mControllers.taskbarDragLayerController.getNotificationShadeBgTaskbar()
607                 .animateToValue(alpha));
608         anim.start();
609         if (skipAnim) {
610             anim.end();
611         }
612     }
613 
onRotationProposal(int rotation, boolean isValid)614     public void onRotationProposal(int rotation, boolean isValid) {
615         mControllers.rotationButtonController.onRotationProposal(rotation, isValid);
616     }
617 
disableNavBarElements(int displayId, int state1, int state2, boolean animate)618     public void disableNavBarElements(int displayId, int state1, int state2, boolean animate) {
619         if (displayId != getDisplayId()) {
620             return;
621         }
622         mControllers.rotationButtonController.onDisable2FlagChanged(state2);
623     }
624 
onSystemBarAttributesChanged(int displayId, int behavior)625     public void onSystemBarAttributesChanged(int displayId, int behavior) {
626         mControllers.rotationButtonController.onBehaviorChanged(displayId, behavior);
627     }
628 
onNavButtonsDarkIntensityChanged(float darkIntensity)629     public void onNavButtonsDarkIntensityChanged(float darkIntensity) {
630         mControllers.navbarButtonsViewController.getTaskbarNavButtonDarkIntensity()
631                 .updateValue(darkIntensity);
632     }
633 
634     /**
635      * Called to update a {@link AutohideSuspendFlag} with a new value.
636      */
setAutohideSuspendFlag(@utohideSuspendFlag int flag, boolean newValue)637     public void setAutohideSuspendFlag(@AutohideSuspendFlag int flag, boolean newValue) {
638         mControllers.taskbarAutohideSuspendController.updateFlag(flag, newValue);
639     }
640 
641     /**
642      * Updates the TaskbarContainer to MATCH_PARENT vs original Taskbar size.
643      */
setTaskbarWindowFullscreen(boolean fullscreen)644     public void setTaskbarWindowFullscreen(boolean fullscreen) {
645         setAutohideSuspendFlag(FLAG_AUTOHIDE_SUSPEND_FULLSCREEN, fullscreen);
646         mIsFullscreen = fullscreen;
647         setTaskbarWindowHeight(fullscreen ? MATCH_PARENT : mLastRequestedNonFullscreenHeight);
648     }
649 
650     /**
651      * Called when drag ends or when a view is removed from the DragLayer.
652      */
onDragEndOrViewRemoved()653     void onDragEndOrViewRemoved() {
654         boolean isDragInProgress = mControllers.taskbarDragController.isSystemDragInProgress();
655 
656         if (!isDragInProgress && !AbstractFloatingView.hasOpenView(this, TYPE_ALL)) {
657             // Reverts Taskbar window to its original size
658             setTaskbarWindowFullscreen(false);
659         }
660 
661         setAutohideSuspendFlag(FLAG_AUTOHIDE_SUSPEND_DRAGGING, isDragInProgress);
662     }
663 
isTaskbarWindowFullscreen()664     public boolean isTaskbarWindowFullscreen() {
665         return mIsFullscreen;
666     }
667 
668     /**
669      * Notify system to inset the rounded corner frame based on the task bar insets.
670      */
updateInsetRoundedCornerFrame(boolean shouldInsetsRoundedCorner)671     public void updateInsetRoundedCornerFrame(boolean shouldInsetsRoundedCorner) {
672         if (!mDragLayer.isAttachedToWindow()
673                 || mWindowLayoutParams.insetsRoundedCornerFrame == shouldInsetsRoundedCorner) {
674             return;
675         }
676         mWindowLayoutParams.insetsRoundedCornerFrame = shouldInsetsRoundedCorner;
677         mWindowManager.updateViewLayout(mDragLayer, mWindowLayoutParams);
678     }
679 
680     /**
681      * Updates the TaskbarContainer height (pass {@link #getDefaultTaskbarWindowHeight()} to reset).
682      */
setTaskbarWindowHeight(int height)683     public void setTaskbarWindowHeight(int height) {
684         if (mWindowLayoutParams.height == height || mIsDestroyed) {
685             return;
686         }
687         if (height == MATCH_PARENT) {
688             height = mDeviceProfile.heightPx;
689         } else {
690             mLastRequestedNonFullscreenHeight = height;
691             if (mIsFullscreen) {
692                 // We still need to be fullscreen, so defer any change to our height until we call
693                 // setTaskbarWindowFullscreen(false). For example, this could happen when dragging
694                 // from the gesture region, as the drag will cancel the gesture and reset launcher's
695                 // state, which in turn normally would reset the taskbar window height as well.
696                 return;
697             }
698         }
699         mWindowLayoutParams.height = height;
700         mControllers.taskbarInsetsController.onTaskbarWindowHeightOrInsetsChanged();
701         mWindowManager.updateViewLayout(mDragLayer, mWindowLayoutParams);
702     }
703 
704     /**
705      * Returns the default height of the window, including the static corner radii above taskbar.
706      */
getDefaultTaskbarWindowHeight()707     public int getDefaultTaskbarWindowHeight() {
708         Resources resources = getResources();
709 
710         if (FLAG_HIDE_NAVBAR_WINDOW && mDeviceProfile.isPhone) {
711             return isThreeButtonNav() ?
712                     resources.getDimensionPixelSize(R.dimen.taskbar_size) :
713                     resources.getDimensionPixelSize(R.dimen.taskbar_stashed_size);
714         }
715 
716         if (!isUserSetupComplete()) {
717             return getSetupWindowHeight();
718         }
719 
720         if (DisplayController.isTransientTaskbar(this)) {
721             return mDeviceProfile.taskbarHeight
722                     + (2 * mDeviceProfile.taskbarBottomMargin)
723                     + resources.getDimensionPixelSize(R.dimen.transient_taskbar_shadow_blur);
724         }
725 
726         return mDeviceProfile.taskbarHeight
727                 + Math.max(getLeftCornerRadius(), getRightCornerRadius());
728     }
729 
getSetupWindowHeight()730     public int getSetupWindowHeight() {
731         return getResources().getDimensionPixelSize(R.dimen.taskbar_suw_frame);
732     }
733 
734     /**
735      * Either adds or removes {@link WindowManager.LayoutParams#FLAG_NOT_FOCUSABLE} on the taskbar
736      * window.
737      */
setTaskbarWindowFocusable(boolean focusable)738     public void setTaskbarWindowFocusable(boolean focusable) {
739         if (focusable) {
740             mWindowLayoutParams.flags &= ~FLAG_NOT_FOCUSABLE;
741         } else {
742             mWindowLayoutParams.flags |= FLAG_NOT_FOCUSABLE;
743         }
744         mWindowManager.updateViewLayout(mDragLayer, mWindowLayoutParams);
745     }
746 
747     /**
748      * Either adds or removes {@link WindowManager.LayoutParams#FLAG_NOT_FOCUSABLE} on the taskbar
749      * window. If we're now focusable, also move nav buttons to a separate window above IME.
750      */
setTaskbarWindowFocusableForIme(boolean focusable)751     public void setTaskbarWindowFocusableForIme(boolean focusable) {
752         if (focusable) {
753             mControllers.navbarButtonsViewController.moveNavButtonsToNewWindow();
754         } else {
755             mControllers.navbarButtonsViewController.moveNavButtonsBackToTaskbarWindow();
756         }
757         setTaskbarWindowFocusable(focusable);
758     }
759 
760     /** Adds the given view to WindowManager with the provided LayoutParams (creates new window). */
addWindowView(View view, WindowManager.LayoutParams windowLayoutParams)761     public void addWindowView(View view, WindowManager.LayoutParams windowLayoutParams) {
762         if (!view.isAttachedToWindow()) {
763             mWindowManager.addView(view, windowLayoutParams);
764         }
765     }
766 
767     /** Removes the given view from WindowManager. See {@link #addWindowView}. */
removeWindowView(View view)768     public void removeWindowView(View view) {
769         if (view.isAttachedToWindow()) {
770             mWindowManager.removeViewImmediate(view);
771         }
772     }
773 
774     @Override
startSplitSelection(SplitSelectSource splitSelectSource)775     public void startSplitSelection(SplitSelectSource splitSelectSource) {
776         mControllers.uiController.startSplitSelection(splitSelectSource);
777     }
778 
onTaskbarIconClicked(View view)779     protected void onTaskbarIconClicked(View view) {
780         Object tag = view.getTag();
781         if (tag instanceof Task) {
782             Task task = (Task) tag;
783             ActivityManagerWrapper.getInstance().startActivityFromRecents(task.key,
784                     ActivityOptions.makeBasic());
785             mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(true);
786         } else if (tag instanceof FolderInfo) {
787             FolderIcon folderIcon = (FolderIcon) view;
788             Folder folder = folderIcon.getFolder();
789 
790             folder.setOnFolderStateChangedListener(newState -> {
791                 if (newState == Folder.STATE_OPEN) {
792                     setTaskbarWindowFocusableForIme(true);
793                 } else if (newState == Folder.STATE_CLOSED) {
794                     // Defer by a frame to ensure we're no longer fullscreen and thus won't jump.
795                     getDragLayer().post(() -> setTaskbarWindowFocusableForIme(false));
796                     folder.setOnFolderStateChangedListener(null);
797                 }
798             });
799 
800             setTaskbarWindowFullscreen(true);
801 
802             getDragLayer().post(() -> {
803                 folder.animateOpen();
804                 getStatsLogManager().logger().withItemInfo(folder.mInfo).log(LAUNCHER_FOLDER_OPEN);
805 
806                 folder.iterateOverItems((itemInfo, itemView) -> {
807                     mControllers.taskbarViewController
808                             .setClickAndLongClickListenersForIcon(itemView);
809                     // To play haptic when dragging, like other Taskbar items do.
810                     itemView.setHapticFeedbackEnabled(true);
811                     return false;
812                 });
813             });
814         } else if (tag instanceof WorkspaceItemInfo) {
815             // Tapping a launchable icon on Taskbar
816             WorkspaceItemInfo info = (WorkspaceItemInfo) tag;
817             if (!info.isDisabled() || !ItemClickHandler.handleDisabledItemClicked(info, this)) {
818                 TaskbarUIController taskbarUIController = mControllers.uiController;
819                 RecentsView recents = taskbarUIController.getRecentsView();
820                 if (recents != null && recents.isSplitSelectionActive()) {
821                     // If we are selecting a second app for split, launch the split tasks
822                     taskbarUIController.triggerSecondAppForSplit(info, info.intent, view);
823                 } else {
824                     // Else launch the selected task
825                     Intent intent = new Intent(info.getIntent())
826                             .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
827                     try {
828                         if (mIsSafeModeEnabled && !PackageManagerHelper.isSystemApp(this, intent)) {
829                             Toast.makeText(this, R.string.safemode_shortcut_error,
830                                     Toast.LENGTH_SHORT).show();
831                         } else if (info.isPromise()) {
832                             TestLogging.recordEvent(
833                                     TestProtocol.SEQUENCE_MAIN, "start: taskbarPromiseIcon");
834                             intent = new PackageManagerHelper(this)
835                                     .getMarketIntent(info.getTargetPackage())
836                                     .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
837                             startActivity(intent);
838 
839                         } else if (info.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
840                             TestLogging.recordEvent(
841                                     TestProtocol.SEQUENCE_MAIN, "start: taskbarDeepShortcut");
842                             String id = info.getDeepShortcutId();
843                             String packageName = intent.getPackage();
844                             getSystemService(LauncherApps.class)
845                                     .startShortcut(packageName, id, null, null, info.user);
846                         } else {
847                             launchFromTaskbarPreservingSplitIfVisible(recents, info);
848                         }
849 
850                     } catch (NullPointerException
851                             | ActivityNotFoundException
852                             | SecurityException e) {
853                         Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT)
854                                 .show();
855                         Log.e(TAG, "Unable to launch. tag=" + info + " intent=" + intent, e);
856                         return;
857                     }
858 
859                 }
860                 mControllers.uiController.onTaskbarIconLaunched(info);
861                 mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(true);
862             }
863         } else if (tag instanceof AppInfo) {
864             // Tapping an item in AllApps
865             AppInfo info = (AppInfo) tag;
866             TaskbarUIController taskbarUIController = mControllers.uiController;
867             RecentsView recents = taskbarUIController.getRecentsView();
868             if (recents != null
869                     && taskbarUIController.getRecentsView().isSplitSelectionActive()) {
870                 // If we are selecting a second app for split, launch the split tasks
871                 taskbarUIController.triggerSecondAppForSplit(info, info.intent, view);
872             } else {
873                 launchFromTaskbarPreservingSplitIfVisible(recents, info);
874             }
875             mControllers.uiController.onTaskbarIconLaunched(info);
876             mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(true);
877         } else if (tag instanceof ItemClickProxy) {
878             ((ItemClickProxy) tag).onItemClicked(view);
879         } else {
880             Log.e(TAG, "Unknown type clicked: " + tag);
881         }
882 
883         AbstractFloatingView.closeAllOpenViews(this);
884     }
885 
886     /**
887      * Run when the user taps a Taskbar icon while in Overview. If the tapped app is currently
888      * visible to the user in Overview, or is part of a visible split pair, we expand the TaskView
889      * as if the user tapped on it (preserving the split pair). Otherwise, launch it normally
890      * (potentially breaking a split pair).
891      */
launchFromTaskbarPreservingSplitIfVisible(@ullable RecentsView recents, ItemInfo info)892     private void launchFromTaskbarPreservingSplitIfVisible(@Nullable RecentsView recents,
893             ItemInfo info) {
894         if (recents == null) {
895             return;
896         }
897         ComponentKey componentToBeLaunched = new ComponentKey(info.getTargetComponent(), info.user);
898         recents.getSplitSelectController().findLastActiveTaskAndRunCallback(
899                 componentToBeLaunched,
900                 foundTask -> {
901                     if (foundTask != null) {
902                         TaskView foundTaskView =
903                                 recents.getTaskViewByTaskId(foundTask.key.id);
904                         if (foundTaskView != null
905                                 && foundTaskView.isVisibleToUser()) {
906                             TestLogging.recordEvent(
907                                     TestProtocol.SEQUENCE_MAIN, "start: taskbarAppIcon");
908                             foundTaskView.launchTasks();
909                             return;
910                         }
911                     }
912                     startItemInfoActivity(info);
913                 });
914     }
915 
startItemInfoActivity(ItemInfo info)916     private void startItemInfoActivity(ItemInfo info) {
917         Intent intent = new Intent(info.getIntent())
918                 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
919         try {
920             TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "start: taskbarAppIcon");
921             if (info.user.equals(Process.myUserHandle())) {
922                 // TODO(b/216683257): Use startActivityForResult for search results that require it.
923                 startActivity(intent);
924             } else {
925                 getSystemService(LauncherApps.class).startMainActivity(
926                         intent.getComponent(), info.user, intent.getSourceBounds(), null);
927             }
928         } catch (NullPointerException | ActivityNotFoundException | SecurityException e) {
929             Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT)
930                     .show();
931             Log.e(TAG, "Unable to launch. tag=" + info + " intent=" + intent, e);
932         }
933     }
934 
935     /**
936      * Called when we detect a long press in the nav region before passing the gesture slop.
937      * @return Whether taskbar handled the long press, and thus should cancel the gesture.
938      */
onLongPressToUnstashTaskbar()939     public boolean onLongPressToUnstashTaskbar() {
940         return mControllers.taskbarStashController.onLongPressToUnstashTaskbar();
941     }
942 
943     /**
944      * Called when we want to unstash taskbar when user performs swipes up gesture.
945      */
onSwipeToUnstashTaskbar()946     public void onSwipeToUnstashTaskbar() {
947         mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(false);
948         mControllers.taskbarEduTooltipController.hide();
949     }
950 
951     /** Returns {@code true} if taskbar All Apps is open. */
isTaskbarAllAppsOpen()952     public boolean isTaskbarAllAppsOpen() {
953         return mControllers.taskbarAllAppsController.isOpen();
954     }
955 
956     /**
957      * Called to start the taskbar translation spring to its settled translation (0).
958      */
startTranslationSpring()959     public void startTranslationSpring() {
960         mControllers.taskbarTranslationController.startSpring();
961     }
962 
963     /**
964      * Returns a callback to help monitor the swipe gesture.
965      */
getTranslationCallbacks()966     public TransitionCallback getTranslationCallbacks() {
967         return mControllers.taskbarTranslationController.getTransitionCallback();
968     }
969 
970     /**
971      * Called when a transient Autohide flag suspend status changes.
972      */
onTransientAutohideSuspendFlagChanged(boolean isSuspended)973     public void onTransientAutohideSuspendFlagChanged(boolean isSuspended) {
974         mControllers.taskbarStashController.updateTaskbarTimeout(isSuspended);
975     }
976 
977     /**
978      * Called when we detect a motion down or up/cancel in the nav region while stashed.
979      * @param animateForward Whether to animate towards the unstashed hint state or back to stashed.
980      */
startTaskbarUnstashHint(boolean animateForward)981     public void startTaskbarUnstashHint(boolean animateForward) {
982         mControllers.taskbarStashController.startUnstashHint(animateForward);
983     }
984 
985     /**
986      * Enables manual taskbar stashing. This method should only be used for tests that need to
987      * stash/unstash the taskbar.
988      */
989     @VisibleForTesting
enableManualStashingDuringTests(boolean enableManualStashing)990     public void enableManualStashingDuringTests(boolean enableManualStashing) {
991         mControllers.taskbarStashController.enableManualStashingDuringTests(enableManualStashing);
992     }
993 
994     /**
995      * Enables the auto timeout for taskbar stashing. This method should only be used for taskbar
996      * testing.
997      */
998     @VisibleForTesting
enableBlockingTimeoutDuringTests(boolean enableBlockingTimeout)999     public void enableBlockingTimeoutDuringTests(boolean enableBlockingTimeout) {
1000         mControllers.taskbarStashController.enableBlockingTimeoutDuringTests(enableBlockingTimeout);
1001     }
1002 
1003     /**
1004      * Unstashes the Taskbar if it is stashed. This method should only be used to unstash the
1005      * taskbar at the end of a test.
1006      */
1007     @VisibleForTesting
unstashTaskbarIfStashed()1008     public void unstashTaskbarIfStashed() {
1009         if (DisplayController.isTransientTaskbar(this)) {
1010             mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(false);
1011         } else {
1012             mControllers.taskbarStashController.onLongPressToUnstashTaskbar();
1013         }
1014     }
1015 
isUserSetupComplete()1016     protected boolean isUserSetupComplete() {
1017         return mIsUserSetupComplete;
1018     }
1019 
isNavBarKidsModeActive()1020     public boolean isNavBarKidsModeActive() {
1021         return mIsNavBarKidsMode && isThreeButtonNav();
1022     }
1023 
isNavBarForceVisible()1024     protected boolean isNavBarForceVisible() {
1025         return mIsNavBarForceVisible;
1026     }
1027 
1028     /**
1029      * Displays a single frame of the Launcher start from SUW animation.
1030      *
1031      * This animation is a combination of the Launcher resume animation, which animates the hotseat
1032      * icons into position, the Taskbar unstash to hotseat animation, which animates the Taskbar
1033      * stash bar into the hotseat icons, and an override to prevent showing the Taskbar all apps
1034      * button.
1035      *
1036      * This should be used to run a Taskbar unstash to hotseat animation whose progress matches a
1037      * swipe progress.
1038      *
1039      * @param duration a placeholder duration to be used to ensure all full-length
1040      *                 sub-animations are properly coordinated. This duration should not actually
1041      *                 be used since this animation tracks a swipe progress.
1042      */
createLauncherStartFromSuwAnim(int duration)1043     protected AnimatorPlaybackController createLauncherStartFromSuwAnim(int duration) {
1044         AnimatorSet fullAnimation = new AnimatorSet();
1045         fullAnimation.setDuration(duration);
1046 
1047         TaskbarUIController uiController = mControllers.uiController;
1048         if (uiController instanceof LauncherTaskbarUIController) {
1049             ((LauncherTaskbarUIController) uiController).addLauncherResumeAnimation(
1050                     fullAnimation, duration);
1051         }
1052         mControllers.taskbarStashController.addUnstashToHotseatAnimation(fullAnimation, duration);
1053 
1054         View allAppsButton = mControllers.taskbarViewController.getAllAppsButtonView();
1055         if (allAppsButton != null && !FeatureFlags.ENABLE_ALL_APPS_BUTTON_IN_HOTSEAT.get()) {
1056             ValueAnimator alphaOverride = ValueAnimator.ofFloat(0, 1);
1057             alphaOverride.setDuration(duration);
1058             alphaOverride.addUpdateListener(a -> {
1059                 // Override the alpha updates in the icon alignment animation.
1060                 allAppsButton.setAlpha(0);
1061             });
1062             fullAnimation.play(alphaOverride);
1063         }
1064 
1065         return AnimatorPlaybackController.wrap(fullAnimation, duration);
1066     }
1067 
1068     /**
1069      * Called when we determine the touchable region.
1070      *
1071      * @param exclude {@code true} then the magnification region computation will omit the window.
1072      */
excludeFromMagnificationRegion(boolean exclude)1073     public void excludeFromMagnificationRegion(boolean exclude) {
1074         if (mIsExcludeFromMagnificationRegion == exclude) {
1075             return;
1076         }
1077 
1078         mIsExcludeFromMagnificationRegion = exclude;
1079         if (exclude) {
1080             mWindowLayoutParams.privateFlags |=
1081                     WindowManager.LayoutParams.PRIVATE_FLAG_EXCLUDE_FROM_SCREEN_MAGNIFICATION;
1082         } else {
1083             mWindowLayoutParams.privateFlags &=
1084                     ~WindowManager.LayoutParams.PRIVATE_FLAG_EXCLUDE_FROM_SCREEN_MAGNIFICATION;
1085         }
1086         mWindowManager.updateViewLayout(mDragLayer, mWindowLayoutParams);
1087     }
1088 
notifyUpdateLayoutParams()1089     void notifyUpdateLayoutParams() {
1090         if (mDragLayer.isAttachedToWindow()) {
1091             mWindowManager.updateViewLayout(mDragLayer, mWindowLayoutParams);
1092         }
1093     }
1094 
showPopupMenuForIcon(BubbleTextView btv)1095     public void showPopupMenuForIcon(BubbleTextView btv) {
1096         setTaskbarWindowFullscreen(true);
1097         btv.post(() -> mControllers.taskbarPopupController.showForIcon(btv));
1098     }
1099 
isInApp()1100     public boolean isInApp() {
1101         return mControllers.taskbarStashController.isInApp();
1102     }
1103 
dumpLogs(String prefix, PrintWriter pw)1104     protected void dumpLogs(String prefix, PrintWriter pw) {
1105         pw.println(prefix + "TaskbarActivityContext:");
1106 
1107         pw.println(String.format(
1108                 "%s\tmNavMode=%s", prefix, mNavMode));
1109         pw.println(String.format(
1110                 "%s\tmImeDrawsImeNavBar=%b", prefix, mImeDrawsImeNavBar));
1111         pw.println(String.format(
1112                 "%s\tmIsUserSetupComplete=%b", prefix, mIsUserSetupComplete));
1113         pw.println(String.format(
1114                 "%s\tmWindowLayoutParams.height=%dpx", prefix, mWindowLayoutParams.height));
1115         pw.println(String.format(
1116                 "%s\tmBindInProgress=%b", prefix, mBindingItems));
1117         mControllers.dumpLogs(prefix + "\t", pw);
1118         mDeviceProfile.dump(this, prefix, pw);
1119     }
1120 
1121     @VisibleForTesting
getTaskbarAllAppsTopPadding()1122     public int getTaskbarAllAppsTopPadding() {
1123         return mControllers.taskbarAllAppsController.getTaskbarAllAppsTopPadding();
1124     }
1125 }
1126