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