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.os.Trace.TRACE_TAG_APP;
19 import static android.view.Display.DEFAULT_DISPLAY;
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;
24 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
25 import static android.window.SplashScreen.SPLASH_SCREEN_STYLE_UNDEFINED;
26 
27 import static com.android.launcher3.AbstractFloatingView.TYPE_ALL;
28 import static com.android.launcher3.AbstractFloatingView.TYPE_REBIND_SAFE;
29 import static com.android.launcher3.AbstractFloatingView.TYPE_TASKBAR_OVERLAY_PROXY;
30 import static com.android.launcher3.Flags.enableCursorHoverStates;
31 import static com.android.launcher3.Utilities.calculateTextHeight;
32 import static com.android.launcher3.Utilities.isRunningInTestHarness;
33 import static com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_NAVBAR_UNIFICATION;
34 import static com.android.launcher3.config.FeatureFlags.enableTaskbarNoRecreate;
35 import static com.android.launcher3.config.FeatureFlags.enableTaskbarPinning;
36 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_OPEN;
37 import static com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_DRAGGING;
38 import static com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_FULLSCREEN;
39 import static com.android.launcher3.testing.shared.ResourceUtils.getBoolByName;
40 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
41 import static com.android.quickstep.util.AnimUtils.completeRunnableListCallback;
42 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE;
43 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING;
44 import static com.android.wm.shell.Flags.enableTinyTaskbar;
45 
46 import android.animation.AnimatorSet;
47 import android.animation.ValueAnimator;
48 import android.app.ActivityOptions;
49 import android.content.ActivityNotFoundException;
50 import android.content.Context;
51 import android.content.Intent;
52 import android.content.pm.ActivityInfo.Config;
53 import android.content.pm.LauncherApps;
54 import android.content.res.Resources;
55 import android.graphics.PixelFormat;
56 import android.graphics.Rect;
57 import android.hardware.display.DisplayManager;
58 import android.os.IRemoteCallback;
59 import android.os.Process;
60 import android.os.Trace;
61 import android.provider.Settings;
62 import android.util.Log;
63 import android.view.Display;
64 import android.view.Gravity;
65 import android.view.Surface;
66 import android.view.View;
67 import android.view.WindowInsets;
68 import android.view.WindowManager;
69 import android.widget.Toast;
70 
71 import androidx.annotation.NonNull;
72 import androidx.annotation.Nullable;
73 import androidx.annotation.VisibleForTesting;
74 import androidx.core.graphics.Insets;
75 import androidx.core.view.WindowInsetsCompat;
76 
77 import com.android.launcher3.AbstractFloatingView;
78 import com.android.launcher3.BubbleTextView;
79 import com.android.launcher3.DeviceProfile;
80 import com.android.launcher3.LauncherPrefs;
81 import com.android.launcher3.LauncherSettings.Favorites;
82 import com.android.launcher3.R;
83 import com.android.launcher3.anim.AnimatorPlaybackController;
84 import com.android.launcher3.apppairs.AppPairIcon;
85 import com.android.launcher3.config.FeatureFlags;
86 import com.android.launcher3.dot.DotInfo;
87 import com.android.launcher3.folder.Folder;
88 import com.android.launcher3.folder.FolderIcon;
89 import com.android.launcher3.logger.LauncherAtom;
90 import com.android.launcher3.logging.StatsLogManager;
91 import com.android.launcher3.model.data.AppInfo;
92 import com.android.launcher3.model.data.AppPairInfo;
93 import com.android.launcher3.model.data.FolderInfo;
94 import com.android.launcher3.model.data.ItemInfo;
95 import com.android.launcher3.model.data.WorkspaceItemInfo;
96 import com.android.launcher3.popup.PopupContainerWithArrow;
97 import com.android.launcher3.popup.PopupDataProvider;
98 import com.android.launcher3.taskbar.TaskbarAutohideSuspendController.AutohideSuspendFlag;
99 import com.android.launcher3.taskbar.TaskbarTranslationController.TransitionCallback;
100 import com.android.launcher3.taskbar.allapps.TaskbarAllAppsController;
101 import com.android.launcher3.taskbar.bubbles.BubbleBarController;
102 import com.android.launcher3.taskbar.bubbles.BubbleBarPinController;
103 import com.android.launcher3.taskbar.bubbles.BubbleBarView;
104 import com.android.launcher3.taskbar.bubbles.BubbleBarViewController;
105 import com.android.launcher3.taskbar.bubbles.BubbleControllers;
106 import com.android.launcher3.taskbar.bubbles.BubbleDismissController;
107 import com.android.launcher3.taskbar.bubbles.BubbleDragController;
108 import com.android.launcher3.taskbar.bubbles.BubblePinController;
109 import com.android.launcher3.taskbar.bubbles.BubbleStashController;
110 import com.android.launcher3.taskbar.bubbles.BubbleStashedHandleViewController;
111 import com.android.launcher3.taskbar.navbutton.NearestTouchFrame;
112 import com.android.launcher3.taskbar.overlay.TaskbarOverlayController;
113 import com.android.launcher3.testing.TestLogging;
114 import com.android.launcher3.testing.shared.TestProtocol;
115 import com.android.launcher3.touch.ItemClickHandler;
116 import com.android.launcher3.touch.ItemClickHandler.ItemClickProxy;
117 import com.android.launcher3.util.ActivityOptionsWrapper;
118 import com.android.launcher3.util.ApiWrapper;
119 import com.android.launcher3.util.ComponentKey;
120 import com.android.launcher3.util.DisplayController;
121 import com.android.launcher3.util.Executors;
122 import com.android.launcher3.util.NavigationMode;
123 import com.android.launcher3.util.PackageManagerHelper;
124 import com.android.launcher3.util.RunnableList;
125 import com.android.launcher3.util.SettingsCache;
126 import com.android.launcher3.util.SplitConfigurationOptions.SplitSelectSource;
127 import com.android.launcher3.util.TraceHelper;
128 import com.android.launcher3.util.VibratorWrapper;
129 import com.android.launcher3.util.ViewCache;
130 import com.android.launcher3.views.ActivityContext;
131 import com.android.quickstep.LauncherActivityInterface;
132 import com.android.quickstep.NavHandle;
133 import com.android.quickstep.RecentsModel;
134 import com.android.quickstep.views.RecentsView;
135 import com.android.quickstep.views.TaskView;
136 import com.android.systemui.shared.recents.model.Task;
137 import com.android.systemui.shared.rotation.RotationButtonController;
138 import com.android.systemui.shared.system.ActivityManagerWrapper;
139 import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags;
140 import com.android.systemui.unfold.updates.RotationChangeProvider;
141 import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider;
142 
143 import java.io.PrintWriter;
144 import java.util.Collections;
145 import java.util.List;
146 import java.util.Optional;
147 import java.util.function.Consumer;
148 
149 /**
150  * The {@link ActivityContext} with which we inflate Taskbar-related Views. This allows UI elements
151  * that are used by both Launcher and Taskbar (such as Folder) to reference a generic
152  * ActivityContext and BaseDragLayer instead of the Launcher activity and its DragLayer.
153  */
154 public class TaskbarActivityContext extends BaseTaskbarContext {
155 
156     private static final String IME_DRAWS_IME_NAV_BAR_RES_NAME = "config_imeDrawsImeNavBar";
157 
158     private static final String TAG = "TaskbarActivityContext";
159 
160     private static final String WINDOW_TITLE = "Taskbar";
161 
162     private final @Nullable Context mNavigationBarPanelContext;
163 
164     private final TaskbarDragLayer mDragLayer;
165     private final TaskbarControllers mControllers;
166 
167     private final WindowManager mWindowManager;
168     private DeviceProfile mDeviceProfile;
169     private WindowManager.LayoutParams mWindowLayoutParams;
170     private boolean mIsFullscreen;
171     // The size we should return to when we call setTaskbarWindowFullscreen(false)
172     private int mLastRequestedNonFullscreenSize;
173 
174     private NavigationMode mNavMode;
175     private boolean mImeDrawsImeNavBar;
176     private final ViewCache mViewCache = new ViewCache();
177 
178     private final boolean mIsSafeModeEnabled;
179     private final boolean mIsUserSetupComplete;
180     private final boolean mIsNavBarForceVisible;
181     private final boolean mIsNavBarKidsMode;
182 
183     private boolean mIsDestroyed = false;
184     // The flag to know if the window is excluded from magnification region computation.
185     private boolean mIsExcludeFromMagnificationRegion = false;
186     private boolean mBindingItems = false;
187     private boolean mAddedWindow = false;
188 
189     // The bounds of the taskbar items relative to TaskbarDragLayer
190     private final Rect mTransientTaskbarBounds = new Rect();
191 
192     private final TaskbarShortcutMenuAccessibilityDelegate mAccessibilityDelegate;
193 
194     private DeviceProfile mTransientTaskbarDeviceProfile;
195 
196     private DeviceProfile mPersistentTaskbarDeviceProfile;
197 
198     private final LauncherPrefs mLauncherPrefs;
199 
TaskbarActivityContext(Context windowContext, @Nullable Context navigationBarPanelContext, DeviceProfile launcherDp, TaskbarNavButtonController buttonController, ScopedUnfoldTransitionProgressProvider unfoldTransitionProgressProvider)200     public TaskbarActivityContext(Context windowContext,
201             @Nullable Context navigationBarPanelContext, DeviceProfile launcherDp,
202             TaskbarNavButtonController buttonController, ScopedUnfoldTransitionProgressProvider
203             unfoldTransitionProgressProvider) {
204         super(windowContext);
205 
206         mNavigationBarPanelContext = navigationBarPanelContext;
207         applyDeviceProfile(launcherDp);
208         final Resources resources = getResources();
209 
210         mImeDrawsImeNavBar = getBoolByName(IME_DRAWS_IME_NAV_BAR_RES_NAME, resources, false);
211         mIsSafeModeEnabled = TraceHelper.allowIpcs("isSafeMode",
212                 () -> getPackageManager().isSafeMode());
213 
214         // TODO(b/244231596) For shared Taskbar window, update this value in applyDeviceProfile()
215         //  instead so to get correct value when recreating the taskbar
216         SettingsCache settingsCache = SettingsCache.INSTANCE.get(this);
217         mIsUserSetupComplete = settingsCache.getValue(
218                 Settings.Secure.getUriFor(Settings.Secure.USER_SETUP_COMPLETE), 0);
219         mIsNavBarKidsMode = settingsCache.getValue(
220                 Settings.Secure.getUriFor(Settings.Secure.NAV_BAR_KIDS_MODE), 0);
221         mIsNavBarForceVisible = mIsNavBarKidsMode;
222 
223         // Get display and corners first, as views might use them in constructor.
224         Display display = windowContext.getDisplay();
225         Context c = getApplicationContext();
226         mWindowManager = c.getSystemService(WindowManager.class);
227 
228         // Inflate views.
229         int taskbarLayout = DisplayController.isTransientTaskbar(this) && !isPhoneMode()
230                 ? R.layout.transient_taskbar
231                 : R.layout.taskbar;
232         mDragLayer = (TaskbarDragLayer) mLayoutInflater.inflate(taskbarLayout, null, false);
233         TaskbarView taskbarView = mDragLayer.findViewById(R.id.taskbar_view);
234         TaskbarScrimView taskbarScrimView = mDragLayer.findViewById(R.id.taskbar_scrim);
235         NearestTouchFrame navButtonsView = mDragLayer.findViewById(R.id.navbuttons_view);
236         StashedHandleView stashedHandleView = mDragLayer.findViewById(R.id.stashed_handle);
237         BubbleBarView bubbleBarView = mDragLayer.findViewById(R.id.taskbar_bubbles);
238         StashedHandleView bubbleHandleView = mDragLayer.findViewById(R.id.stashed_bubble_handle);
239 
240         mAccessibilityDelegate = new TaskbarShortcutMenuAccessibilityDelegate(this);
241 
242         // If Bubble bar is present, TaskbarControllers depends on it so build it first.
243         Optional<BubbleControllers> bubbleControllersOptional = Optional.empty();
244         BubbleBarController.onTaskbarRecreated();
245         if (BubbleBarController.isBubbleBarEnabled() && bubbleBarView != null) {
246             bubbleControllersOptional = Optional.of(new BubbleControllers(
247                     new BubbleBarController(this, bubbleBarView),
248                     new BubbleBarViewController(this, bubbleBarView),
249                     new BubbleStashController(this),
250                     new BubbleStashedHandleViewController(this, bubbleHandleView),
251                     new BubbleDragController(this),
252                     new BubbleDismissController(this, mDragLayer),
253                     new BubbleBarPinController(this, mDragLayer,
254                             () -> DisplayController.INSTANCE.get(this).getInfo().currentSize),
255                     new BubblePinController(this, mDragLayer,
256                             () -> DisplayController.INSTANCE.get(this).getInfo().currentSize)
257             ));
258         }
259 
260         // Construct controllers.
261         RotationButtonController rotationButtonController = new RotationButtonController(this,
262                 c.getColor(R.color.floating_rotation_button_light_color),
263                 c.getColor(R.color.floating_rotation_button_dark_color),
264                 R.drawable.ic_sysbar_rotate_button_ccw_start_0,
265                 R.drawable.ic_sysbar_rotate_button_ccw_start_90,
266                 R.drawable.ic_sysbar_rotate_button_cw_start_0,
267                 R.drawable.ic_sysbar_rotate_button_cw_start_90,
268                 () -> getDisplay().getRotation());
269         rotationButtonController.setBgExecutor(Executors.UI_HELPER_EXECUTOR);
270 
271         mControllers = new TaskbarControllers(this,
272                 new TaskbarDragController(this),
273                 buttonController,
274                 new NavbarButtonsViewController(this, mNavigationBarPanelContext, navButtonsView),
275                 rotationButtonController,
276                 new TaskbarDragLayerController(this, mDragLayer),
277                 new TaskbarViewController(this, taskbarView),
278                 new TaskbarScrimViewController(this, taskbarScrimView),
279                 new TaskbarUnfoldAnimationController(this, unfoldTransitionProgressProvider,
280                         mWindowManager,
281                         new RotationChangeProvider(c.getSystemService(DisplayManager.class), this,
282                                 UI_HELPER_EXECUTOR.getHandler(), getMainThreadHandler())),
283                 new TaskbarKeyguardController(this),
284                 new StashedHandleViewController(this, stashedHandleView),
285                 new TaskbarStashController(this),
286                 new TaskbarAutohideSuspendController(this),
287                 new TaskbarPopupController(this),
288                 new TaskbarForceVisibleImmersiveController(this),
289                 new TaskbarOverlayController(this, launcherDp),
290                 new TaskbarAllAppsController(),
291                 new TaskbarInsetsController(this),
292                 new VoiceInteractionWindowController(this),
293                 new TaskbarTranslationController(this),
294                 new TaskbarSpringOnStashController(this),
295                 new TaskbarRecentAppsController(
296                         RecentsModel.INSTANCE.get(this),
297                         LauncherActivityInterface.INSTANCE::getDesktopVisibilityController),
298                 TaskbarEduTooltipController.newInstance(this),
299                 new KeyboardQuickSwitchController(),
300                 new TaskbarPinningController(this, () ->
301                         DisplayController.INSTANCE.get(this).getInfo().isInDesktopMode()),
302                 bubbleControllersOptional);
303 
304         mLauncherPrefs = LauncherPrefs.get(this);
305     }
306 
307     /** Updates {@link DeviceProfile} instances for any Taskbar windows. */
updateDeviceProfile(DeviceProfile launcherDp)308     public void updateDeviceProfile(DeviceProfile launcherDp) {
309         applyDeviceProfile(launcherDp);
310 
311         mControllers.taskbarOverlayController.updateLauncherDeviceProfile(launcherDp);
312         AbstractFloatingView.closeAllOpenViewsExcept(this, false, TYPE_REBIND_SAFE);
313         // Reapply fullscreen to take potential new screen size into account.
314         setTaskbarWindowFullscreen(mIsFullscreen);
315 
316         dispatchDeviceProfileChanged();
317     }
318 
319     /**
320      * Copy the original DeviceProfile, match the number of hotseat icons and qsb width and update
321      * the icon size
322      */
applyDeviceProfile(DeviceProfile originDeviceProfile)323     private void applyDeviceProfile(DeviceProfile originDeviceProfile) {
324         Consumer<DeviceProfile> overrideProvider = deviceProfile -> {
325             // Taskbar should match the number of icons of hotseat
326             deviceProfile.numShownHotseatIcons = originDeviceProfile.numShownHotseatIcons;
327             // Same QSB width to have a smooth animation
328             deviceProfile.hotseatQsbWidth = originDeviceProfile.hotseatQsbWidth;
329 
330             // Update icon size
331             deviceProfile.iconSizePx = deviceProfile.taskbarIconSize;
332             deviceProfile.updateIconSize(1f, this);
333         };
334         mDeviceProfile = originDeviceProfile.toBuilder(this)
335                 .withDimensionsOverride(overrideProvider).build();
336 
337         if (DisplayController.isTransientTaskbar(this)) {
338             mTransientTaskbarDeviceProfile = mDeviceProfile;
339             mPersistentTaskbarDeviceProfile = mDeviceProfile
340                     .toBuilder(this)
341                     .withDimensionsOverride(overrideProvider)
342                     .setIsTransientTaskbar(false)
343                     .build();
344         } else {
345             mPersistentTaskbarDeviceProfile = mDeviceProfile;
346             mTransientTaskbarDeviceProfile = mDeviceProfile
347                     .toBuilder(this)
348                     .withDimensionsOverride(overrideProvider)
349                     .setIsTransientTaskbar(true)
350                     .build();
351         }
352         mNavMode = DisplayController.getNavigationMode(this);
353     }
354 
355     /** Called when the visibility of the bubble bar changed. */
bubbleBarVisibilityChanged(boolean isVisible)356     public void bubbleBarVisibilityChanged(boolean isVisible) {
357         mControllers.uiController.adjustHotseatForBubbleBar(isVisible);
358         mControllers.taskbarViewController.resetIconAlignmentController();
359     }
360 
init(@onNull TaskbarSharedState sharedState)361     public void init(@NonNull TaskbarSharedState sharedState) {
362         mImeDrawsImeNavBar = getBoolByName(IME_DRAWS_IME_NAV_BAR_RES_NAME, getResources(), false);
363         mLastRequestedNonFullscreenSize = getDefaultTaskbarWindowSize();
364         mWindowLayoutParams = createAllWindowParams();
365 
366         // Initialize controllers after all are constructed.
367         mControllers.init(sharedState);
368         // This may not be necessary and can be reverted once we move towards recreating all
369         // controllers without re-creating the window
370         mControllers.rotationButtonController.onNavigationModeChanged(mNavMode.resValue);
371         updateSysuiStateFlags(sharedState.sysuiStateFlags, true /* fromInit */);
372         disableNavBarElements(sharedState.disableNavBarDisplayId, sharedState.disableNavBarState1,
373                 sharedState.disableNavBarState2, false /* animate */);
374         onSystemBarAttributesChanged(sharedState.systemBarAttrsDisplayId,
375                 sharedState.systemBarAttrsBehavior);
376         onNavButtonsDarkIntensityChanged(sharedState.navButtonsDarkIntensity);
377         onNavigationBarLumaSamplingEnabled(sharedState.mLumaSamplingDisplayId,
378                 sharedState.mIsLumaSamplingEnabled);
379 
380         if (ENABLE_TASKBAR_NAVBAR_UNIFICATION) {
381             // W/ the flag not set this entire class gets re-created, which resets the value of
382             // mIsDestroyed. We re-use the class for small-screen, so we explicitly have to mark
383             // this class as non-destroyed
384             mIsDestroyed = false;
385         }
386 
387         if (!enableTaskbarNoRecreate() && !mAddedWindow) {
388             mWindowManager.addView(mDragLayer, mWindowLayoutParams);
389             mAddedWindow = true;
390         } else {
391             notifyUpdateLayoutParams();
392         }
393     }
394 
395     /**
396      * @return {@code true} if the device profile isn't a large screen profile and we are using a
397      * single window for taskbar and navbar.
398      */
isPhoneMode()399     public boolean isPhoneMode() {
400         return ENABLE_TASKBAR_NAVBAR_UNIFICATION
401                 && mDeviceProfile.isPhone
402                 && !mDeviceProfile.isTaskbarPresent;
403     }
404 
405     /**
406      * @return {@code true} if {@link #isPhoneMode()} is true and we're using 3 button-nav
407      */
isPhoneButtonNavMode()408     public boolean isPhoneButtonNavMode() {
409         return isPhoneMode() && isThreeButtonNav();
410     }
411 
412     /**
413      * @return {@code true} if {@link #isPhoneMode()} is true and we're using gesture nav
414      */
isPhoneGestureNavMode()415     public boolean isPhoneGestureNavMode() {
416         return isPhoneMode() && !isThreeButtonNav();
417     }
418 
419     /** Returns {@code true} iff a tiny version of taskbar is shown on phone. */
isTinyTaskbar()420     public boolean isTinyTaskbar() {
421         return enableTinyTaskbar() && mDeviceProfile.isPhone && mDeviceProfile.isTaskbarPresent;
422     }
423 
424     /**
425      * Returns if software keyboard is docked or input toolbar is placed at the taskbar area
426      */
isImeDocked()427     public boolean isImeDocked() {
428         View dragLayer = getDragLayer();
429         WindowInsets insets = dragLayer.getRootWindowInsets();
430         if (insets == null) {
431             return false;
432         }
433 
434         WindowInsetsCompat insetsCompat =
435                 WindowInsetsCompat.toWindowInsetsCompat(insets, dragLayer.getRootView());
436 
437         if (insetsCompat.isVisible(WindowInsetsCompat.Type.ime())) {
438             Insets imeInsets = insetsCompat.getInsets(WindowInsetsCompat.Type.ime());
439             return imeInsets.bottom >= getResources().getDimensionPixelSize(
440                     R.dimen.floating_ime_inset_height);
441         } else {
442             return false;
443         }
444     }
445 
446     /**
447      * Show Taskbar upon receiving broadcast
448      */
showTaskbarFromBroadcast()449     public void showTaskbarFromBroadcast() {
450         mControllers.taskbarStashController.showTaskbarFromBroadcast();
451     }
452 
453     /** Toggles Taskbar All Apps overlay. */
toggleAllApps()454     public void toggleAllApps() {
455         mControllers.taskbarAllAppsController.toggle();
456     }
457 
458     /** Toggles Taskbar All Apps overlay with keyboard ready for search. */
toggleAllAppsSearch()459     public void toggleAllAppsSearch() {
460         mControllers.taskbarAllAppsController.toggleSearch();
461     }
462 
463     @Override
getDeviceProfile()464     public DeviceProfile getDeviceProfile() {
465         return mDeviceProfile;
466     }
467 
468     @Override
dispatchDeviceProfileChanged()469     public void dispatchDeviceProfileChanged() {
470         super.dispatchDeviceProfileChanged();
471         Trace.instantForTrack(TRACE_TAG_APP, "TaskbarActivityContext#DeviceProfileChanged",
472                 getDeviceProfile().toSmallString());
473     }
474 
475     @NonNull
getLauncherPrefs()476     public LauncherPrefs getLauncherPrefs() {
477         return mLauncherPrefs;
478     }
479 
480     /**
481      * Returns the View bounds of transient taskbar.
482      */
getTransientTaskbarBounds()483     public Rect getTransientTaskbarBounds() {
484         return mTransientTaskbarBounds;
485     }
486 
getCurrentTaskbarWidth()487     protected float getCurrentTaskbarWidth() {
488         return mControllers.taskbarViewController.getCurrentVisualTaskbarWidth();
489     }
490 
491     @Override
getStatsLogManager()492     public StatsLogManager getStatsLogManager() {
493         // Used to mock, can't mock a default interface method directly
494         return super.getStatsLogManager();
495     }
496 
497     /**
498      * Creates LayoutParams for adding a view directly to WindowManager as a new window.
499      *
500      * @param type  The window type to pass to the created WindowManager.LayoutParams.
501      * @param title The window title to pass to the created WindowManager.LayoutParams.
502      */
createDefaultWindowLayoutParams(int type, String title)503     public WindowManager.LayoutParams createDefaultWindowLayoutParams(int type, String title) {
504         int windowFlags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
505                 | WindowManager.LayoutParams.FLAG_SLIPPERY
506                 | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
507         if (DisplayController.isTransientTaskbar(this) && !isRunningInTestHarness()) {
508             windowFlags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
509                     | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
510         }
511         WindowManager.LayoutParams windowLayoutParams = new WindowManager.LayoutParams(
512                 MATCH_PARENT,
513                 mLastRequestedNonFullscreenSize,
514                 type,
515                 windowFlags,
516                 PixelFormat.TRANSLUCENT);
517         windowLayoutParams.setTitle(title);
518         windowLayoutParams.packageName = getPackageName();
519         windowLayoutParams.gravity = Gravity.BOTTOM;
520         windowLayoutParams.setFitInsetsTypes(0);
521         windowLayoutParams.receiveInsetsIgnoringZOrder = true;
522         windowLayoutParams.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
523         windowLayoutParams.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
524         windowLayoutParams.privateFlags =
525                 WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
526         windowLayoutParams.accessibilityTitle = getString(
527                 isPhoneMode() ? R.string.taskbar_phone_a11y_title : R.string.taskbar_a11y_title);
528 
529         return windowLayoutParams;
530     }
531 
532     /**
533      * Creates {@link WindowManager.LayoutParams} for Taskbar, and also sets LP.paramsForRotation
534      * for taskbar
535      */
createAllWindowParams()536     private WindowManager.LayoutParams createAllWindowParams() {
537         final int windowType =
538                 ENABLE_TASKBAR_NAVBAR_UNIFICATION ? TYPE_NAVIGATION_BAR : TYPE_NAVIGATION_BAR_PANEL;
539         WindowManager.LayoutParams windowLayoutParams =
540                 createDefaultWindowLayoutParams(windowType, TaskbarActivityContext.WINDOW_TITLE);
541 
542         windowLayoutParams.paramsForRotation = new WindowManager.LayoutParams[4];
543         for (int rot = Surface.ROTATION_0; rot <= Surface.ROTATION_270; rot++) {
544             WindowManager.LayoutParams lp =
545                     createDefaultWindowLayoutParams(windowType,
546                             TaskbarActivityContext.WINDOW_TITLE);
547             if (isPhoneButtonNavMode()) {
548                 populatePhoneButtonNavModeWindowLayoutParams(rot, lp);
549             }
550             windowLayoutParams.paramsForRotation[rot] = lp;
551         }
552 
553         // Override with current layout params
554         WindowManager.LayoutParams currentParams =
555                 windowLayoutParams.paramsForRotation[getDisplay().getRotation()];
556         windowLayoutParams.width = currentParams.width;
557         windowLayoutParams.height = currentParams.height;
558         windowLayoutParams.gravity = currentParams.gravity;
559 
560         return windowLayoutParams;
561     }
562 
563     /**
564      * Update {@link WindowManager.LayoutParams} with values specific to phone and 3 button
565      * navigation users
566      */
populatePhoneButtonNavModeWindowLayoutParams(int rot, WindowManager.LayoutParams lp)567     private void populatePhoneButtonNavModeWindowLayoutParams(int rot,
568             WindowManager.LayoutParams lp) {
569         lp.width = WindowManager.LayoutParams.MATCH_PARENT;
570         lp.height = WindowManager.LayoutParams.MATCH_PARENT;
571         lp.gravity = Gravity.BOTTOM;
572 
573         // Override with per-rotation specific values
574         switch (rot) {
575             case Surface.ROTATION_0, Surface.ROTATION_180 -> {
576                 lp.height = mLastRequestedNonFullscreenSize;
577             }
578             case Surface.ROTATION_90 -> {
579                 lp.width = mLastRequestedNonFullscreenSize;
580                 lp.gravity = Gravity.END;
581             }
582             case Surface.ROTATION_270 -> {
583                 lp.width = mLastRequestedNonFullscreenSize;
584                 lp.gravity = Gravity.START;
585             }
586         }
587     }
588 
onConfigurationChanged(@onfig int configChanges)589     public void onConfigurationChanged(@Config int configChanges) {
590         mControllers.onConfigurationChanged(configChanges);
591         if (!mIsUserSetupComplete) {
592             setTaskbarWindowSize(getSetupWindowSize());
593         }
594     }
595 
isThreeButtonNav()596     public boolean isThreeButtonNav() {
597         return mNavMode == NavigationMode.THREE_BUTTONS;
598     }
599 
isGestureNav()600     public boolean isGestureNav() {
601         return mNavMode == NavigationMode.NO_BUTTON;
602     }
603 
imeDrawsImeNavBar()604     public boolean imeDrawsImeNavBar() {
605         return mImeDrawsImeNavBar;
606     }
607 
getCornerRadius()608     public int getCornerRadius() {
609         return isPhoneMode() ? 0 : getResources().getDimensionPixelSize(
610                 R.dimen.persistent_taskbar_corner_radius);
611     }
612 
getWindowLayoutParams()613     public WindowManager.LayoutParams getWindowLayoutParams() {
614         return mWindowLayoutParams;
615     }
616 
617     @Override
getDragLayer()618     public TaskbarDragLayer getDragLayer() {
619         return mDragLayer;
620     }
621 
622     @Override
getFolderBoundingBox()623     public Rect getFolderBoundingBox() {
624         return mControllers.taskbarDragLayerController.getFolderBoundingBox();
625     }
626 
627     @Override
getDragController()628     public TaskbarDragController getDragController() {
629         return mControllers.taskbarDragController;
630     }
631 
632     @Nullable
getBubbleControllers()633     public BubbleControllers getBubbleControllers() {
634         return mControllers.bubbleControllers.orElse(null);
635     }
636 
637     @NonNull
getNavHandle()638     public NavHandle getNavHandle() {
639         return mControllers.stashedHandleViewController;
640     }
641 
642     @Override
getViewCache()643     public ViewCache getViewCache() {
644         return mViewCache;
645     }
646 
647     @Override
getItemOnClickListener()648     public View.OnClickListener getItemOnClickListener() {
649         return this::onTaskbarIconClicked;
650     }
651 
652     /**
653      * Change from hotseat/predicted hotseat to taskbar container.
654      */
655     @Override
applyOverwritesToLogItem(LauncherAtom.ItemInfo.Builder itemInfoBuilder)656     public void applyOverwritesToLogItem(LauncherAtom.ItemInfo.Builder itemInfoBuilder) {
657         if (!itemInfoBuilder.hasContainerInfo()) {
658             return;
659         }
660         LauncherAtom.ContainerInfo oldContainer = itemInfoBuilder.getContainerInfo();
661 
662         LauncherAtom.TaskBarContainer.Builder taskbarBuilder =
663                 LauncherAtom.TaskBarContainer.newBuilder();
664         if (mControllers.uiController.isInOverviewUi()) {
665             taskbarBuilder.setTaskSwitcherContainer(
666                     LauncherAtom.TaskSwitcherContainer.newBuilder());
667         }
668 
669         if (oldContainer.hasPredictedHotseatContainer()) {
670             LauncherAtom.PredictedHotseatContainer predictedHotseat =
671                     oldContainer.getPredictedHotseatContainer();
672 
673             if (predictedHotseat.hasIndex()) {
674                 taskbarBuilder.setIndex(predictedHotseat.getIndex());
675             }
676             if (predictedHotseat.hasCardinality()) {
677                 taskbarBuilder.setCardinality(predictedHotseat.getCardinality());
678             }
679 
680             itemInfoBuilder.setContainerInfo(LauncherAtom.ContainerInfo.newBuilder()
681                     .setTaskBarContainer(taskbarBuilder));
682         } else if (oldContainer.hasHotseat()) {
683             LauncherAtom.HotseatContainer hotseat = oldContainer.getHotseat();
684 
685             if (hotseat.hasIndex()) {
686                 taskbarBuilder.setIndex(hotseat.getIndex());
687             }
688 
689             itemInfoBuilder.setContainerInfo(LauncherAtom.ContainerInfo.newBuilder()
690                     .setTaskBarContainer(taskbarBuilder));
691         } else if (oldContainer.hasFolder() && oldContainer.getFolder().hasHotseat()) {
692             LauncherAtom.FolderContainer.Builder folderBuilder = oldContainer.getFolder()
693                     .toBuilder();
694             LauncherAtom.HotseatContainer hotseat = folderBuilder.getHotseat();
695 
696             if (hotseat.hasIndex()) {
697                 taskbarBuilder.setIndex(hotseat.getIndex());
698             }
699 
700             folderBuilder.setTaskbar(taskbarBuilder);
701             folderBuilder.clearHotseat();
702             itemInfoBuilder.setContainerInfo(LauncherAtom.ContainerInfo.newBuilder()
703                     .setFolder(folderBuilder));
704         } else if (oldContainer.hasAllAppsContainer()) {
705             itemInfoBuilder.setContainerInfo(LauncherAtom.ContainerInfo.newBuilder()
706                     .setAllAppsContainer(oldContainer.getAllAppsContainer().toBuilder()
707                             .setTaskbarContainer(taskbarBuilder)));
708         } else if (oldContainer.hasPredictionContainer()) {
709             itemInfoBuilder.setContainerInfo(LauncherAtom.ContainerInfo.newBuilder()
710                     .setPredictionContainer(oldContainer.getPredictionContainer().toBuilder()
711                             .setTaskbarContainer(taskbarBuilder)));
712         }
713     }
714 
715     @Override
getDotInfoForItem(ItemInfo info)716     public DotInfo getDotInfoForItem(ItemInfo info) {
717         return getPopupDataProvider().getDotInfoForItem(info);
718     }
719 
720     @NonNull
721     @Override
getPopupDataProvider()722     public PopupDataProvider getPopupDataProvider() {
723         return mControllers.taskbarPopupController.getPopupDataProvider();
724     }
725 
726     @Override
getAccessibilityDelegate()727     public View.AccessibilityDelegate getAccessibilityDelegate() {
728         return mAccessibilityDelegate;
729     }
730 
731     @Override
isBindingItems()732     public boolean isBindingItems() {
733         return mBindingItems;
734     }
735 
setBindingItems(boolean bindingItems)736     public void setBindingItems(boolean bindingItems) {
737         mBindingItems = bindingItems;
738     }
739 
740     @Override
onDragStart()741     public void onDragStart() {
742         setTaskbarWindowFullscreen(true);
743     }
744 
745     @Override
onDragEnd()746     public void onDragEnd() {
747         onDragEndOrViewRemoved();
748     }
749 
750     @Override
onPopupVisibilityChanged(boolean isVisible)751     public void onPopupVisibilityChanged(boolean isVisible) {
752         setTaskbarWindowFocusable(isVisible);
753     }
754 
755     @Override
onSplitScreenMenuButtonClicked()756     public void onSplitScreenMenuButtonClicked() {
757         PopupContainerWithArrow popup = PopupContainerWithArrow.getOpen(this);
758         if (popup != null) {
759             popup.addOnCloseCallback(() -> {
760                 mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(true);
761             });
762         }
763     }
764 
765     @Override
makeDefaultActivityOptions(int splashScreenStyle)766     public ActivityOptionsWrapper makeDefaultActivityOptions(int splashScreenStyle) {
767         RunnableList callbacks = new RunnableList();
768         ActivityOptions options = ActivityOptions.makeCustomAnimation(this, 0, 0);
769         options.setSplashScreenStyle(splashScreenStyle);
770         options.setPendingIntentBackgroundActivityStartMode(
771                 ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
772         IRemoteCallback endCallback = completeRunnableListCallback(callbacks);
773         options.setOnAnimationAbortListener(endCallback);
774         options.setOnAnimationFinishedListener(endCallback);
775 
776         return new ActivityOptionsWrapper(options, callbacks);
777     }
778 
779     @Override
getActivityLaunchOptions(View v, @Nullable ItemInfo item)780     public ActivityOptionsWrapper getActivityLaunchOptions(View v, @Nullable ItemInfo item) {
781         return makeDefaultActivityOptions(SPLASH_SCREEN_STYLE_UNDEFINED);
782     }
783 
784     /**
785      * Sets a new data-source for this taskbar instance
786      */
setUIController(@onNull TaskbarUIController uiController)787     public void setUIController(@NonNull TaskbarUIController uiController) {
788         mControllers.setUiController(uiController);
789     }
790 
791     /**
792      * Sets the flag indicating setup UI is visible
793      */
setSetupUIVisible(boolean isVisible)794     public void setSetupUIVisible(boolean isVisible) {
795         mControllers.taskbarStashController.setSetupUIVisible(isVisible);
796     }
797 
798     /**
799      * Called when this instance of taskbar is no longer needed
800      */
onDestroy()801     public void onDestroy() {
802         mIsDestroyed = true;
803         setUIController(TaskbarUIController.DEFAULT);
804         mControllers.onDestroy();
805         if (!enableTaskbarNoRecreate() && !ENABLE_TASKBAR_NAVBAR_UNIFICATION) {
806             mWindowManager.removeViewImmediate(mDragLayer);
807             mAddedWindow = false;
808         }
809     }
810 
isDestroyed()811     public boolean isDestroyed() {
812         return mIsDestroyed;
813     }
814 
updateSysuiStateFlags(@ystemUiStateFlags long systemUiStateFlags, boolean fromInit)815     public void updateSysuiStateFlags(@SystemUiStateFlags long systemUiStateFlags,
816             boolean fromInit) {
817         mControllers.navbarButtonsViewController.updateStateForSysuiFlags(systemUiStateFlags,
818                 fromInit);
819         boolean isShadeVisible = (systemUiStateFlags & SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE) != 0;
820         onNotificationShadeExpandChanged(isShadeVisible, fromInit);
821         mControllers.taskbarViewController.setRecentsButtonDisabled(
822                 mControllers.navbarButtonsViewController.isRecentsDisabled()
823                         || isNavBarKidsModeActive());
824         mControllers.stashedHandleViewController.setIsHomeButtonDisabled(
825                 mControllers.navbarButtonsViewController.isHomeDisabled());
826         mControllers.stashedHandleViewController.updateStateForSysuiFlags(systemUiStateFlags);
827         mControllers.taskbarKeyguardController.updateStateForSysuiFlags(systemUiStateFlags);
828         mControllers.taskbarStashController.updateStateForSysuiFlags(
829                 systemUiStateFlags, fromInit || !isUserSetupComplete());
830         mControllers.taskbarScrimViewController.updateStateForSysuiFlags(systemUiStateFlags,
831                 fromInit);
832         mControllers.navButtonController.updateSysuiFlags(systemUiStateFlags);
833         mControllers.taskbarForceVisibleImmersiveController.updateSysuiFlags(systemUiStateFlags);
834         mControllers.voiceInteractionWindowController.setIsVoiceInteractionWindowVisible(
835                 (systemUiStateFlags & SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING) != 0, fromInit);
836         mControllers.uiController.updateStateForSysuiFlags(systemUiStateFlags);
837         mControllers.bubbleControllers.ifPresent(controllers -> {
838             controllers.bubbleBarController.updateStateForSysuiFlags(systemUiStateFlags);
839             controllers.bubbleStashedHandleViewController.setIsHomeButtonDisabled(
840                     mControllers.navbarButtonsViewController.isHomeDisabled());
841         });
842     }
843 
844     /**
845      * Hides the taskbar icons and background when the notication shade is expanded.
846      */
onNotificationShadeExpandChanged(boolean isExpanded, boolean skipAnim)847     private void onNotificationShadeExpandChanged(boolean isExpanded, boolean skipAnim) {
848         float alpha = isExpanded ? 0 : 1;
849         AnimatorSet anim = new AnimatorSet();
850         anim.play(mControllers.taskbarViewController.getTaskbarIconAlpha().get(
851                 TaskbarViewController.ALPHA_INDEX_NOTIFICATION_EXPANDED).animateToValue(alpha));
852         anim.play(mControllers.taskbarDragLayerController.getNotificationShadeBgTaskbar()
853                 .animateToValue(alpha));
854         anim.start();
855         if (skipAnim) {
856             anim.end();
857         }
858     }
859 
onRotationProposal(int rotation, boolean isValid)860     public void onRotationProposal(int rotation, boolean isValid) {
861         mControllers.rotationButtonController.onRotationProposal(rotation, isValid);
862     }
863 
disableNavBarElements(int displayId, int state1, int state2, boolean animate)864     public void disableNavBarElements(int displayId, int state1, int state2, boolean animate) {
865         if (displayId != getDisplayId()) {
866             return;
867         }
868         mControllers.rotationButtonController.onDisable2FlagChanged(state2);
869     }
870 
onSystemBarAttributesChanged(int displayId, int behavior)871     public void onSystemBarAttributesChanged(int displayId, int behavior) {
872         mControllers.rotationButtonController.onBehaviorChanged(displayId, behavior);
873     }
874 
onNavButtonsDarkIntensityChanged(float darkIntensity)875     public void onNavButtonsDarkIntensityChanged(float darkIntensity) {
876         mControllers.navbarButtonsViewController.getTaskbarNavButtonDarkIntensity()
877                 .updateValue(darkIntensity);
878     }
879 
onNavigationBarLumaSamplingEnabled(int displayId, boolean enable)880     public void onNavigationBarLumaSamplingEnabled(int displayId, boolean enable) {
881         mControllers.stashedHandleViewController.onNavigationBarLumaSamplingEnabled(displayId,
882                 enable);
883     }
884 
885     /**
886      * Called to update a {@link AutohideSuspendFlag} with a new value.
887      */
setAutohideSuspendFlag(@utohideSuspendFlag int flag, boolean newValue)888     public void setAutohideSuspendFlag(@AutohideSuspendFlag int flag, boolean newValue) {
889         mControllers.taskbarAutohideSuspendController.updateFlag(flag, newValue);
890     }
891 
892     /**
893      * Updates the TaskbarContainer to MATCH_PARENT vs original Taskbar size.
894      */
setTaskbarWindowFullscreen(boolean fullscreen)895     public void setTaskbarWindowFullscreen(boolean fullscreen) {
896         setAutohideSuspendFlag(FLAG_AUTOHIDE_SUSPEND_FULLSCREEN, fullscreen);
897         mIsFullscreen = fullscreen;
898         setTaskbarWindowSize(fullscreen ? MATCH_PARENT : mLastRequestedNonFullscreenSize);
899     }
900 
901     /**
902      * Called when drag ends or when a view is removed from the DragLayer.
903      */
onDragEndOrViewRemoved()904     void onDragEndOrViewRemoved() {
905         boolean isDragInProgress = mControllers.taskbarDragController.isSystemDragInProgress();
906 
907         // Overlay AFVs are in a separate window and do not require Taskbar to be fullscreen.
908         if (!isDragInProgress
909                 && !AbstractFloatingView.hasOpenView(
910                 this, TYPE_ALL & ~TYPE_TASKBAR_OVERLAY_PROXY)) {
911             // Reverts Taskbar window to its original size
912             setTaskbarWindowFullscreen(false);
913         }
914 
915         setAutohideSuspendFlag(FLAG_AUTOHIDE_SUSPEND_DRAGGING, isDragInProgress);
916     }
917 
isTaskbarWindowFullscreen()918     public boolean isTaskbarWindowFullscreen() {
919         return mIsFullscreen;
920     }
921 
922     /**
923      * Updates the TaskbarContainer size (pass {@link #getDefaultTaskbarWindowSize()} to reset).
924      */
setTaskbarWindowSize(int size)925     public void setTaskbarWindowSize(int size) {
926         // In landscape phone button nav mode, we should set the task bar width instead of height
927         // because this is the only case in which the nav bar is not on the display bottom.
928         boolean landscapePhoneButtonNav = isPhoneButtonNavMode() && mDeviceProfile.isLandscape;
929         if ((landscapePhoneButtonNav ? mWindowLayoutParams.width : mWindowLayoutParams.height)
930                 == size || mIsDestroyed) {
931             return;
932         }
933         if (size == MATCH_PARENT) {
934             size = mDeviceProfile.heightPx;
935         } else {
936             mLastRequestedNonFullscreenSize = size;
937             if (mIsFullscreen) {
938                 // We still need to be fullscreen, so defer any change to our height until we call
939                 // setTaskbarWindowFullscreen(false). For example, this could happen when dragging
940                 // from the gesture region, as the drag will cancel the gesture and reset launcher's
941                 // state, which in turn normally would reset the taskbar window height as well.
942                 return;
943             }
944         }
945         if (landscapePhoneButtonNav) {
946             mWindowLayoutParams.width = size;
947             for (int rot = Surface.ROTATION_0; rot <= Surface.ROTATION_270; rot++) {
948                 mWindowLayoutParams.paramsForRotation[rot].width = size;
949             }
950         } else {
951             mWindowLayoutParams.height = size;
952             for (int rot = Surface.ROTATION_0; rot <= Surface.ROTATION_270; rot++) {
953                 mWindowLayoutParams.paramsForRotation[rot].height = size;
954             }
955         }
956         mControllers.runAfterInit(
957                 mControllers.taskbarInsetsController
958                         ::onTaskbarOrBubblebarWindowHeightOrInsetsChanged);
959         notifyUpdateLayoutParams();
960     }
961 
962     /**
963      * Returns the default size (in most cases height, but in 3-button phone mode, width) of the
964      * window, including the static corner radii above taskbar.
965      */
getDefaultTaskbarWindowSize()966     public int getDefaultTaskbarWindowSize() {
967         Resources resources = getResources();
968 
969         if (isPhoneMode()) {
970             return isThreeButtonNav() ?
971                     resources.getDimensionPixelSize(R.dimen.taskbar_phone_size) :
972                     resources.getDimensionPixelSize(R.dimen.taskbar_stashed_size);
973         }
974 
975         if (!isUserSetupComplete()) {
976             return getSetupWindowSize();
977         }
978 
979         boolean shouldTreatAsTransient = DisplayController.isTransientTaskbar(this)
980                 || (enableTaskbarPinning() && !isThreeButtonNav());
981 
982         int extraHeightForTaskbarTooltips = enableCursorHoverStates()
983                 ? resources.getDimensionPixelSize(R.dimen.arrow_toast_arrow_height)
984                 + (resources.getDimensionPixelSize(R.dimen.taskbar_tooltip_vertical_padding) * 2)
985                 + calculateTextHeight(
986                 resources.getDimensionPixelSize(R.dimen.arrow_toast_text_size))
987                 : 0;
988 
989         // Return transient taskbar window height when pinning feature is enabled, so taskbar view
990         // does not get cut off during pinning animation.
991         if (shouldTreatAsTransient) {
992             DeviceProfile transientTaskbarDp = mDeviceProfile.toBuilder(this)
993                     .setIsTransientTaskbar(true).build();
994 
995             return transientTaskbarDp.taskbarHeight
996                     + (2 * transientTaskbarDp.taskbarBottomMargin)
997                     + Math.max(extraHeightForTaskbarTooltips, resources.getDimensionPixelSize(
998                     R.dimen.transient_taskbar_shadow_blur));
999         }
1000 
1001 
1002         return mDeviceProfile.taskbarHeight
1003                 + getCornerRadius()
1004                 + extraHeightForTaskbarTooltips;
1005     }
1006 
getSetupWindowSize()1007     public int getSetupWindowSize() {
1008         return getResources().getDimensionPixelSize(R.dimen.taskbar_suw_frame);
1009     }
1010 
getTransientTaskbarDeviceProfile()1011     public DeviceProfile getTransientTaskbarDeviceProfile() {
1012         return mTransientTaskbarDeviceProfile;
1013     }
1014 
getPersistentTaskbarDeviceProfile()1015     public DeviceProfile getPersistentTaskbarDeviceProfile() {
1016         return mPersistentTaskbarDeviceProfile;
1017     }
1018 
1019     /**
1020      * Either adds or removes {@link WindowManager.LayoutParams#FLAG_NOT_FOCUSABLE} on the taskbar
1021      * window.
1022      */
setTaskbarWindowFocusable(boolean focusable)1023     public void setTaskbarWindowFocusable(boolean focusable) {
1024         if (focusable) {
1025             mWindowLayoutParams.flags &= ~FLAG_NOT_FOCUSABLE;
1026         } else {
1027             mWindowLayoutParams.flags |= FLAG_NOT_FOCUSABLE;
1028         }
1029         notifyUpdateLayoutParams();
1030     }
1031 
1032     /**
1033      * Applies forcibly show flag to taskbar window iff transient taskbar is unstashed.
1034      */
applyForciblyShownFlagWhileTransientTaskbarUnstashed(boolean shouldForceShow)1035     public void applyForciblyShownFlagWhileTransientTaskbarUnstashed(boolean shouldForceShow) {
1036         if (!DisplayController.isTransientTaskbar(this)) {
1037             return;
1038         }
1039         if (shouldForceShow) {
1040             mWindowLayoutParams.forciblyShownTypes |= WindowInsets.Type.navigationBars();
1041         } else {
1042             mWindowLayoutParams.forciblyShownTypes &= ~WindowInsets.Type.navigationBars();
1043         }
1044         notifyUpdateLayoutParams();
1045     }
1046 
1047     /**
1048      * Either adds or removes {@link WindowManager.LayoutParams#FLAG_NOT_FOCUSABLE} on the taskbar
1049      * window. If we're now focusable, also move nav buttons to a separate window above IME.
1050      */
setTaskbarWindowFocusableForIme(boolean focusable)1051     public void setTaskbarWindowFocusableForIme(boolean focusable) {
1052         if (focusable) {
1053             mControllers.navbarButtonsViewController.moveNavButtonsToNewWindow();
1054         } else {
1055             mControllers.navbarButtonsViewController.moveNavButtonsBackToTaskbarWindow();
1056         }
1057         setTaskbarWindowFocusable(focusable);
1058     }
1059 
1060     /** Adds the given view to WindowManager with the provided LayoutParams (creates new window). */
addWindowView(View view, WindowManager.LayoutParams windowLayoutParams)1061     public void addWindowView(View view, WindowManager.LayoutParams windowLayoutParams) {
1062         if (!view.isAttachedToWindow()) {
1063             mWindowManager.addView(view, windowLayoutParams);
1064         }
1065     }
1066 
1067     /** Removes the given view from WindowManager. See {@link #addWindowView}. */
removeWindowView(View view)1068     public void removeWindowView(View view) {
1069         if (view.isAttachedToWindow()) {
1070             mWindowManager.removeViewImmediate(view);
1071         }
1072     }
1073 
1074     @Override
startSplitSelection(SplitSelectSource splitSelectSource)1075     public void startSplitSelection(SplitSelectSource splitSelectSource) {
1076         mControllers.uiController.startSplitSelection(splitSelectSource);
1077     }
1078 
onTaskbarIconClicked(View view)1079     protected void onTaskbarIconClicked(View view) {
1080         TaskbarUIController taskbarUIController = mControllers.uiController;
1081         RecentsView recents = taskbarUIController.getRecentsView();
1082         boolean shouldCloseAllOpenViews = true;
1083         Object tag = view.getTag();
1084         if (tag instanceof Task) {
1085             Task task = (Task) tag;
1086             ActivityManagerWrapper.getInstance().startActivityFromRecents(task.key,
1087                     ActivityOptions.makeBasic());
1088             mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(true);
1089         } else if (tag instanceof FolderInfo) {
1090             // Tapping an expandable folder icon on Taskbar
1091             shouldCloseAllOpenViews = false;
1092             expandFolder((FolderIcon) view);
1093         } else if (tag instanceof AppPairInfo api) {
1094             // Tapping an app pair icon on Taskbar
1095             if (recents != null && recents.isSplitSelectionActive()) {
1096                 Toast.makeText(this, "Unable to split with an app pair. Select another app.",
1097                         Toast.LENGTH_SHORT).show();
1098             } else {
1099                 // Else launch the selected app pair
1100                 launchFromTaskbar(recents, view, api.getContents());
1101                 mControllers.uiController.onTaskbarIconLaunched(api);
1102                 mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(true);
1103             }
1104         } else if (tag instanceof WorkspaceItemInfo) {
1105             // Tapping a launchable icon on Taskbar
1106             WorkspaceItemInfo info = (WorkspaceItemInfo) tag;
1107             if (!info.isDisabled() || !ItemClickHandler.handleDisabledItemClicked(info, this)) {
1108                 if (recents != null && recents.isSplitSelectionActive()) {
1109                     // If we are selecting a second app for split, launch the split tasks
1110                     taskbarUIController.triggerSecondAppForSplit(info, info.intent, view);
1111                 } else {
1112                     // Else launch the selected task
1113                     Intent intent = new Intent(info.getIntent())
1114                             .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
1115                     try {
1116                         if (mIsSafeModeEnabled && !PackageManagerHelper.isSystemApp(this, intent)) {
1117                             Toast.makeText(this, R.string.safemode_shortcut_error,
1118                                     Toast.LENGTH_SHORT).show();
1119                         } else if (info.isPromise()) {
1120                             TestLogging.recordEvent(
1121                                     TestProtocol.SEQUENCE_MAIN, "start: taskbarPromiseIcon");
1122                             intent = ApiWrapper.INSTANCE.get(this).getAppMarketActivityIntent(
1123                                     info.getTargetPackage(), Process.myUserHandle());
1124                             startActivity(intent);
1125 
1126                         } else if (info.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
1127                             TestLogging.recordEvent(
1128                                     TestProtocol.SEQUENCE_MAIN, "start: taskbarDeepShortcut");
1129                             String id = info.getDeepShortcutId();
1130                             String packageName = intent.getPackage();
1131                             getSystemService(LauncherApps.class)
1132                                     .startShortcut(packageName, id, null, null, info.user);
1133                         } else {
1134                             launchFromTaskbar(recents, view, Collections.singletonList(info));
1135                         }
1136 
1137                     } catch (NullPointerException
1138                              | ActivityNotFoundException
1139                              | SecurityException e) {
1140                         Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT)
1141                                 .show();
1142                         Log.e(TAG, "Unable to launch. tag=" + info + " intent=" + intent, e);
1143                         return;
1144                     }
1145                 }
1146 
1147                 // If the app was launched from a folder, stash the taskbar after it closes
1148                 Folder f = Folder.getOpen(this);
1149                 if (f != null && f.getInfo().id == info.container) {
1150                     f.addOnFolderStateChangedListener(new Folder.OnFolderStateChangedListener() {
1151                         @Override
1152                         public void onFolderStateChanged(int newState) {
1153                             if (newState == Folder.STATE_CLOSED) {
1154                                 f.removeOnFolderStateChangedListener(this);
1155                                 mControllers.taskbarStashController
1156                                         .updateAndAnimateTransientTaskbar(true);
1157                             }
1158                         }
1159                     });
1160                 }
1161                 mControllers.uiController.onTaskbarIconLaunched(info);
1162                 mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(true);
1163             }
1164         } else if (tag instanceof AppInfo) {
1165             // Tapping an item in AllApps
1166             AppInfo info = (AppInfo) tag;
1167             if (recents != null
1168                     && taskbarUIController.getRecentsView().isSplitSelectionActive()) {
1169                 // If we are selecting a second app for split, launch the split tasks
1170                 taskbarUIController.triggerSecondAppForSplit(info, info.intent, view);
1171             } else {
1172                 launchFromTaskbar(recents, view, Collections.singletonList(info));
1173             }
1174             mControllers.uiController.onTaskbarIconLaunched(info);
1175             mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(true);
1176         } else if (tag instanceof ItemClickProxy) {
1177             ((ItemClickProxy) tag).onItemClicked(view);
1178         } else {
1179             Log.e(TAG, "Unknown type clicked: " + tag);
1180         }
1181 
1182         if (shouldCloseAllOpenViews) {
1183             AbstractFloatingView.closeAllOpenViews(this);
1184         }
1185     }
1186 
1187     /**
1188      * Runs when the user taps a Taskbar icon in TaskbarActivityContext (Overview or inside an app),
1189      * and calls the appropriate method to animate and launch.
1190      */
launchFromTaskbar(@ullable RecentsView recents, @Nullable View launchingIconView, List<? extends ItemInfo> itemInfos)1191     private void launchFromTaskbar(@Nullable RecentsView recents, @Nullable View launchingIconView,
1192             List<? extends ItemInfo> itemInfos) {
1193         if (isInApp()) {
1194             launchFromInAppTaskbar(recents, launchingIconView, itemInfos);
1195         } else {
1196             launchFromOverviewTaskbar(recents, launchingIconView, itemInfos);
1197         }
1198     }
1199 
1200     /**
1201      * Runs when the user taps a Taskbar icon while inside an app.
1202      */
launchFromInAppTaskbar(@ullable RecentsView recents, @Nullable View launchingIconView, List<? extends ItemInfo> itemInfos)1203     private void launchFromInAppTaskbar(@Nullable RecentsView recents,
1204             @Nullable View launchingIconView, List<? extends ItemInfo> itemInfos) {
1205         if (recents == null) {
1206             return;
1207         }
1208 
1209         boolean tappedAppPair = itemInfos.size() == 2;
1210 
1211         if (tappedAppPair) {
1212             // If the icon is an app pair, the logic gets a bit complicated because we play
1213             // different animations depending on which app (or app pair) is currently running on
1214             // screen, so delegate logic to appPairsController.
1215             recents.getSplitSelectController().getAppPairsController()
1216                     .handleAppPairLaunchInApp((AppPairIcon) launchingIconView, itemInfos);
1217         } else {
1218             // Tapped a single app, nothing complicated here.
1219             startItemInfoActivity(itemInfos.get(0), null /*foundTask*/);
1220         }
1221     }
1222 
1223     /**
1224      * Run when the user taps a Taskbar icon while in Overview. If the tapped app is currently
1225      * visible to the user in Overview, or is part of a visible split pair, we expand the TaskView
1226      * as if the user tapped on it (preserving the split pair). Otherwise, launch it normally
1227      * (potentially breaking a split pair).
1228      */
launchFromOverviewTaskbar(@ullable RecentsView recents, @Nullable View launchingIconView, List<? extends ItemInfo> itemInfos)1229     private void launchFromOverviewTaskbar(@Nullable RecentsView recents,
1230             @Nullable View launchingIconView, List<? extends ItemInfo> itemInfos) {
1231         if (recents == null) {
1232             return;
1233         }
1234 
1235         boolean isLaunchingAppPair = itemInfos.size() == 2;
1236         // Convert the list of ItemInfo instances to a list of ComponentKeys
1237         List<ComponentKey> componentKeys =
1238                 itemInfos.stream().map(ItemInfo::getComponentKey).toList();
1239         recents.getSplitSelectController().findLastActiveTasksAndRunCallback(
1240                 componentKeys,
1241                 isLaunchingAppPair,
1242                 foundTasks -> {
1243                     @Nullable Task foundTask = foundTasks[0];
1244                     if (foundTask != null) {
1245                         TaskView foundTaskView = recents.getTaskViewByTaskId(foundTask.key.id);
1246                         if (foundTaskView != null
1247                                 && foundTaskView.isVisibleToUser()) {
1248                             TestLogging.recordEvent(
1249                                     TestProtocol.SEQUENCE_MAIN, "start: taskbarAppIcon");
1250                             foundTaskView.launchTasks();
1251                             return;
1252                         }
1253                     }
1254 
1255                     if (isLaunchingAppPair) {
1256                         // Finish recents animation if it's running before launching to ensure
1257                         // we get both leashes for the animation
1258                         mControllers.uiController.setSkipNextRecentsAnimEnd();
1259                         recents.switchToScreenshot(() ->
1260                                 recents.finishRecentsAnimation(true /*toRecents*/,
1261                                         false /*shouldPip*/,
1262                                         () -> recents
1263                                                 .getSplitSelectController()
1264                                                 .getAppPairsController()
1265                                                 .launchAppPair((AppPairIcon) launchingIconView,
1266                                                         -1 /*cuj*/)));
1267                     } else {
1268                         startItemInfoActivity(itemInfos.get(0), foundTask);
1269                     }
1270                 }
1271         );
1272     }
1273 
1274     /**
1275      * Starts an activity with the information provided by the "info" param. However, if
1276      * taskInRecents is present, it will prioritize re-launching an existing instance via
1277      * {@link ActivityManagerWrapper#startActivityFromRecents(int, ActivityOptions)}
1278      */
startItemInfoActivity(ItemInfo info, @Nullable Task taskInRecents)1279     private void startItemInfoActivity(ItemInfo info, @Nullable Task taskInRecents) {
1280         Intent intent = new Intent(info.getIntent())
1281                 .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
1282         try {
1283             TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "start: taskbarAppIcon");
1284             if (info.user.equals(Process.myUserHandle())) {
1285                 // TODO(b/216683257): Use startActivityForResult for search results that require it.
1286                 if (taskInRecents != null) {
1287                     // Re launch instance from recents
1288                     ActivityOptionsWrapper opts = getActivityLaunchOptions(null, info);
1289                     opts.options.setLaunchDisplayId(
1290                             getDisplay() == null ? DEFAULT_DISPLAY : getDisplay().getDisplayId());
1291                     if (ActivityManagerWrapper.getInstance()
1292                             .startActivityFromRecents(taskInRecents.key, opts.options)) {
1293                         mControllers.uiController.getRecentsView()
1294                                 .addSideTaskLaunchCallback(opts.onEndCallback);
1295                         return;
1296                     }
1297                 }
1298 
1299                 startActivity(intent);
1300             } else {
1301                 getSystemService(LauncherApps.class).startMainActivity(
1302                         intent.getComponent(), info.user, intent.getSourceBounds(), null);
1303             }
1304         } catch (NullPointerException | ActivityNotFoundException | SecurityException e) {
1305             Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT)
1306                     .show();
1307             Log.e(TAG, "Unable to launch. tag=" + info + " intent=" + intent, e);
1308         }
1309     }
1310 
1311     /** Expands a folder icon when it is clicked */
expandFolder(FolderIcon folderIcon)1312     private void expandFolder(FolderIcon folderIcon) {
1313         Folder folder = folderIcon.getFolder();
1314 
1315         folder.setPriorityOnFolderStateChangedListener(
1316                 new Folder.OnFolderStateChangedListener() {
1317                     @Override
1318                     public void onFolderStateChanged(int newState) {
1319                         if (newState == Folder.STATE_OPEN) {
1320                             setTaskbarWindowFocusableForIme(true);
1321                         } else if (newState == Folder.STATE_CLOSED) {
1322                             // Defer by a frame to ensure we're no longer fullscreen and thus
1323                             // won't jump.
1324                             getDragLayer().post(() -> setTaskbarWindowFocusableForIme(false));
1325                             folder.setPriorityOnFolderStateChangedListener(null);
1326                         }
1327                     }
1328                 });
1329 
1330         setTaskbarWindowFullscreen(true);
1331 
1332         getDragLayer().post(() -> {
1333             folder.animateOpen();
1334             getStatsLogManager().logger().withItemInfo(folder.mInfo).log(LAUNCHER_FOLDER_OPEN);
1335 
1336             folder.iterateOverItems((itemInfo, itemView) -> {
1337                 mControllers.taskbarViewController
1338                         .setClickAndLongClickListenersForIcon(itemView);
1339                 // To play haptic when dragging, like other Taskbar items do.
1340                 itemView.setHapticFeedbackEnabled(true);
1341                 return false;
1342             });
1343         });
1344     }
1345 
1346     /**
1347      * Returns whether the taskbar is currently visually stashed.
1348      */
isTaskbarStashed()1349     public boolean isTaskbarStashed() {
1350         return mControllers.taskbarStashController.isStashed();
1351     }
1352 
1353     /**
1354      * Called when we want to unstash taskbar when user performs swipes up gesture.
1355      */
onSwipeToUnstashTaskbar()1356     public void onSwipeToUnstashTaskbar() {
1357         boolean wasStashed = mControllers.taskbarStashController.isStashed();
1358         mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(/* stash= */ false);
1359         boolean isStashed = mControllers.taskbarStashController.isStashed();
1360         if (isStashed != wasStashed) {
1361             VibratorWrapper.INSTANCE.get(this).vibrateForTaskbarUnstash();
1362         }
1363         mControllers.taskbarEduTooltipController.hide();
1364     }
1365 
1366     /**
1367      * Called when we want to open bubblebar when user performs swipes up gesture.
1368      */
onSwipeToOpenBubblebar()1369     public void onSwipeToOpenBubblebar() {
1370         mControllers.bubbleControllers.ifPresent(controllers -> {
1371             controllers.bubbleStashController.showBubbleBar(/* expandBubbles= */ true);
1372         });
1373     }
1374 
1375     /** Returns {@code true} if Taskbar All Apps is open. */
isTaskbarAllAppsOpen()1376     public boolean isTaskbarAllAppsOpen() {
1377         return mControllers.taskbarAllAppsController.isOpen();
1378     }
1379 
1380     /** Toggles the Taskbar's stash state. */
toggleTaskbarStash()1381     public void toggleTaskbarStash() {
1382         mControllers.taskbarStashController.toggleTaskbarStash();
1383     }
1384 
1385     /**
1386      * Plays the taskbar background alpha animation if one is not currently playing.
1387      */
playTaskbarBackgroundAlphaAnimation()1388     public void playTaskbarBackgroundAlphaAnimation() {
1389         mControllers.taskbarStashController.playTaskbarBackgroundAlphaAnimation();
1390     }
1391 
1392     /**
1393      * Called to start the taskbar translation spring to its settled translation (0).
1394      */
startTranslationSpring()1395     public void startTranslationSpring() {
1396         mControllers.taskbarTranslationController.startSpring();
1397     }
1398 
1399     /**
1400      * Returns a callback to help monitor the swipe gesture.
1401      */
getTranslationCallbacks()1402     public TransitionCallback getTranslationCallbacks() {
1403         return mControllers.taskbarTranslationController.getTransitionCallback();
1404     }
1405 
1406     /**
1407      * Called when a transient Autohide flag suspend status changes.
1408      */
onTransientAutohideSuspendFlagChanged(boolean isSuspended)1409     public void onTransientAutohideSuspendFlagChanged(boolean isSuspended) {
1410         mControllers.taskbarStashController.updateTaskbarTimeout(isSuspended);
1411     }
1412 
1413     /**
1414      * Called when we detect a motion down or up/cancel in the nav region while stashed.
1415      *
1416      * @param animateForward Whether to animate towards the unstashed hint state or back to stashed.
1417      */
startTaskbarUnstashHint(boolean animateForward)1418     public void startTaskbarUnstashHint(boolean animateForward) {
1419         mControllers.taskbarStashController.startUnstashHint(animateForward);
1420     }
1421 
1422     /**
1423      * Enables the auto timeout for taskbar stashing. This method should only be used for taskbar
1424      * testing.
1425      */
1426     @VisibleForTesting
enableBlockingTimeoutDuringTests(boolean enableBlockingTimeout)1427     public void enableBlockingTimeoutDuringTests(boolean enableBlockingTimeout) {
1428         mControllers.taskbarStashController.enableBlockingTimeoutDuringTests(enableBlockingTimeout);
1429     }
1430 
1431     /**
1432      * Unstashes the Taskbar if it is stashed.
1433      */
1434     @VisibleForTesting
unstashTaskbarIfStashed()1435     public void unstashTaskbarIfStashed() {
1436         if (DisplayController.isTransientTaskbar(this)) {
1437             mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(false);
1438         }
1439     }
1440 
1441     /** Unstashes the Bubble Bar if it is stashed. */
1442     @VisibleForTesting
unstashBubbleBarIfStashed()1443     public void unstashBubbleBarIfStashed() {
1444         mControllers.bubbleControllers.ifPresent(bubbleControllers -> {
1445             if (bubbleControllers.bubbleStashController.isStashed()) {
1446                 bubbleControllers.bubbleStashController.showBubbleBar(false);
1447             }
1448         });
1449     }
1450 
isUserSetupComplete()1451     public boolean isUserSetupComplete() {
1452         return mIsUserSetupComplete;
1453     }
1454 
isNavBarKidsModeActive()1455     public boolean isNavBarKidsModeActive() {
1456         return mIsNavBarKidsMode && isThreeButtonNav();
1457     }
1458 
isNavBarForceVisible()1459     protected boolean isNavBarForceVisible() {
1460         return mIsNavBarForceVisible;
1461     }
1462 
1463     /**
1464      * Displays a single frame of the Launcher start from SUW animation.
1465      *
1466      * This animation is a combination of the Launcher resume animation, which animates the hotseat
1467      * icons into position, the Taskbar unstash to hotseat animation, which animates the Taskbar
1468      * stash bar into the hotseat icons, and an override to prevent showing the Taskbar all apps
1469      * button.
1470      *
1471      * This should be used to run a Taskbar unstash to hotseat animation whose progress matches a
1472      * swipe progress.
1473      *
1474      * @param duration a placeholder duration to be used to ensure all full-length
1475      *                 sub-animations are properly coordinated. This duration should not actually
1476      *                 be used since this animation tracks a swipe progress.
1477      */
createLauncherStartFromSuwAnim(int duration)1478     protected AnimatorPlaybackController createLauncherStartFromSuwAnim(int duration) {
1479         AnimatorSet fullAnimation = new AnimatorSet();
1480         fullAnimation.setDuration(duration);
1481 
1482         TaskbarUIController uiController = mControllers.uiController;
1483         if (uiController instanceof LauncherTaskbarUIController) {
1484             ((LauncherTaskbarUIController) uiController).addLauncherVisibilityChangedAnimation(
1485                     fullAnimation, duration);
1486         }
1487         mControllers.taskbarStashController.addUnstashToHotseatAnimationFromSuw(fullAnimation,
1488                 duration);
1489 
1490         View allAppsButton = mControllers.taskbarViewController.getAllAppsButtonView();
1491         if (allAppsButton != null && !FeatureFlags.ENABLE_ALL_APPS_BUTTON_IN_HOTSEAT.get()) {
1492             ValueAnimator alphaOverride = ValueAnimator.ofFloat(0, 1);
1493             alphaOverride.setDuration(duration);
1494             alphaOverride.addUpdateListener(a -> {
1495                 // Override the alpha updates in the icon alignment animation.
1496                 allAppsButton.setAlpha(0);
1497             });
1498             fullAnimation.play(alphaOverride);
1499         }
1500 
1501         return AnimatorPlaybackController.wrap(fullAnimation, duration);
1502     }
1503 
1504     /**
1505      * Called when we determine the touchable region.
1506      *
1507      * @param exclude {@code true} then the magnification region computation will omit the window.
1508      */
excludeFromMagnificationRegion(boolean exclude)1509     public void excludeFromMagnificationRegion(boolean exclude) {
1510         if (mIsExcludeFromMagnificationRegion == exclude) {
1511             return;
1512         }
1513 
1514         mIsExcludeFromMagnificationRegion = exclude;
1515         if (exclude) {
1516             mWindowLayoutParams.privateFlags |=
1517                     WindowManager.LayoutParams.PRIVATE_FLAG_EXCLUDE_FROM_SCREEN_MAGNIFICATION;
1518         } else {
1519             mWindowLayoutParams.privateFlags &=
1520                     ~WindowManager.LayoutParams.PRIVATE_FLAG_EXCLUDE_FROM_SCREEN_MAGNIFICATION;
1521         }
1522         notifyUpdateLayoutParams();
1523     }
1524 
notifyUpdateLayoutParams()1525     void notifyUpdateLayoutParams() {
1526         if (mDragLayer.isAttachedToWindow()) {
1527             if (enableTaskbarNoRecreate()) {
1528                 mWindowManager.updateViewLayout(mDragLayer.getRootView(), mWindowLayoutParams);
1529             } else {
1530                 mWindowManager.updateViewLayout(mDragLayer, mWindowLayoutParams);
1531             }
1532         }
1533     }
1534 
showPopupMenuForIcon(BubbleTextView btv)1535     public void showPopupMenuForIcon(BubbleTextView btv) {
1536         setTaskbarWindowFullscreen(true);
1537         btv.post(() -> mControllers.taskbarPopupController.showForIcon(btv));
1538     }
1539 
launchKeyboardFocusedTask()1540     public void launchKeyboardFocusedTask() {
1541         mControllers.uiController.launchKeyboardFocusedTask();
1542     }
1543 
isInApp()1544     public boolean isInApp() {
1545         return mControllers.taskbarStashController.isInApp();
1546     }
1547 
isInStashedLauncherState()1548     public boolean isInStashedLauncherState() {
1549         return mControllers.taskbarStashController.isInStashedLauncherState();
1550     }
1551 
dumpLogs(String prefix, PrintWriter pw)1552     protected void dumpLogs(String prefix, PrintWriter pw) {
1553         pw.println(prefix + "TaskbarActivityContext:");
1554 
1555         pw.println(String.format(
1556                 "%s\tmNavMode=%s", prefix, mNavMode));
1557         pw.println(String.format(
1558                 "%s\tmImeDrawsImeNavBar=%b", prefix, mImeDrawsImeNavBar));
1559         pw.println(String.format(
1560                 "%s\tmIsUserSetupComplete=%b", prefix, mIsUserSetupComplete));
1561         pw.println(String.format(
1562                 "%s\tmWindowLayoutParams.height=%dpx", prefix, mWindowLayoutParams.height));
1563         pw.println(String.format(
1564                 "%s\tmBindInProgress=%b", prefix, mBindingItems));
1565         mControllers.dumpLogs(prefix + "\t", pw);
1566         mDeviceProfile.dump(this, prefix, pw);
1567     }
1568 
1569     @VisibleForTesting
getTaskbarAllAppsTopPadding()1570     public int getTaskbarAllAppsTopPadding() {
1571         return mControllers.taskbarAllAppsController.getTaskbarAllAppsTopPadding();
1572     }
1573 
1574     @VisibleForTesting
getTaskbarAllAppsScroll()1575     public int getTaskbarAllAppsScroll() {
1576         return mControllers.taskbarAllAppsController.getTaskbarAllAppsScroll();
1577     }
1578 
1579     @VisibleForTesting
getStashedTaskbarScale()1580     public float getStashedTaskbarScale() {
1581         return mControllers.stashedHandleViewController.getStashedHandleHintScale().value;
1582     }
1583 
1584     /** Closes the KeyboardQuickSwitchView without an animation if open. */
closeKeyboardQuickSwitchView()1585     public void closeKeyboardQuickSwitchView() {
1586         mControllers.keyboardQuickSwitchController.closeQuickSwitchView(false);
1587     }
1588 
canToggleHomeAllApps()1589     boolean canToggleHomeAllApps() {
1590         return mControllers.uiController.canToggleHomeAllApps();
1591     }
1592 
1593     @VisibleForTesting
getControllers()1594     public TaskbarControllers getControllers() {
1595         return mControllers;
1596     }
1597 }
1598