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