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