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 android.animation.AnimatorSet; 19 import android.content.pm.ActivityInfo.Config; 20 21 import androidx.annotation.NonNull; 22 import androidx.annotation.Nullable; 23 import androidx.annotation.VisibleForTesting; 24 25 import com.android.launcher3.anim.AnimatedFloat; 26 import com.android.launcher3.taskbar.allapps.TaskbarAllAppsController; 27 import com.android.launcher3.taskbar.bubbles.BubbleControllers; 28 import com.android.launcher3.taskbar.growth.NudgeController; 29 import com.android.launcher3.taskbar.overlay.TaskbarOverlayController; 30 import com.android.systemui.shared.rotation.RotationButtonController; 31 import com.android.wm.shell.shared.bubbles.BubbleBarLocation; 32 33 import java.io.PrintWriter; 34 import java.util.ArrayList; 35 import java.util.List; 36 import java.util.Optional; 37 38 /** 39 * Hosts various taskbar controllers to facilitate passing between one another. 40 */ 41 public class TaskbarControllers { 42 43 public final TaskbarActivityContext taskbarActivityContext; 44 45 public final TaskbarDragController taskbarDragController; 46 public final TaskbarNavButtonController navButtonController; 47 public final NavbarButtonsViewController navbarButtonsViewController; 48 public final RotationButtonController rotationButtonController; 49 public final TaskbarDragLayerController taskbarDragLayerController; 50 public final TaskbarScrimViewController taskbarScrimViewController; 51 public final TaskbarViewController taskbarViewController; 52 public final TaskbarUnfoldAnimationController taskbarUnfoldAnimationController; 53 public final TaskbarKeyguardController taskbarKeyguardController; 54 public final StashedHandleViewController stashedHandleViewController; 55 public final TaskbarStashController taskbarStashController; 56 public final TaskbarAutohideSuspendController taskbarAutohideSuspendController; 57 public final TaskbarPopupController taskbarPopupController; 58 public final TaskbarForceVisibleImmersiveController taskbarForceVisibleImmersiveController; 59 public final TaskbarAllAppsController taskbarAllAppsController; 60 public final TaskbarInsetsController taskbarInsetsController; 61 public final VoiceInteractionWindowController voiceInteractionWindowController; 62 public final TaskbarRecentAppsController taskbarRecentAppsController; 63 public final TaskbarTranslationController taskbarTranslationController; 64 public final TaskbarSpringOnStashController taskbarSpringOnStashController; 65 public final TaskbarOverlayController taskbarOverlayController; 66 public final TaskbarEduTooltipController taskbarEduTooltipController; 67 public final KeyboardQuickSwitchController keyboardQuickSwitchController; 68 public final TaskbarPinningController taskbarPinningController; 69 public final Optional<BubbleControllers> bubbleControllers; 70 public final TaskbarDesktopModeController taskbarDesktopModeController; 71 public final NudgeController nudgeController; 72 73 @Nullable private LoggableTaskbarController[] mControllersToLog = null; 74 @Nullable private BackgroundRendererController[] mBackgroundRendererControllers = null; 75 76 /** Do not store this controller, as it may change at runtime. */ 77 @NonNull public TaskbarUIController uiController = TaskbarUIController.DEFAULT; 78 79 private boolean mAreAllControllersInitialized; 80 private final List<Runnable> mPostInitCallbacks = new ArrayList<>(); 81 82 @Nullable private TaskbarSharedState mSharedState = null; 83 84 // Roundness property for round corner above taskbar . 85 private final AnimatedFloat mCornerRoundness = new AnimatedFloat(this::updateCornerRoundness); 86 87 /** 88 * Want to add a new controller? Don't forget to: 89 * * Call init 90 * * Call onDestroy 91 * * Add to mControllersToLog 92 * * Add tests by adding this controller to TaskbarBaseTestCase.kt and extending that class 93 */ TaskbarControllers(TaskbarActivityContext taskbarActivityContext, TaskbarDragController taskbarDragController, TaskbarNavButtonController navButtonController, NavbarButtonsViewController navbarButtonsViewController, RotationButtonController rotationButtonController, TaskbarDragLayerController taskbarDragLayerController, TaskbarViewController taskbarViewController, TaskbarScrimViewController taskbarScrimViewController, TaskbarUnfoldAnimationController taskbarUnfoldAnimationController, TaskbarKeyguardController taskbarKeyguardController, StashedHandleViewController stashedHandleViewController, TaskbarStashController taskbarStashController, TaskbarAutohideSuspendController taskbarAutoHideSuspendController, TaskbarPopupController taskbarPopupController, TaskbarForceVisibleImmersiveController taskbarForceVisibleImmersiveController, TaskbarOverlayController taskbarOverlayController, TaskbarAllAppsController taskbarAllAppsController, TaskbarInsetsController taskbarInsetsController, VoiceInteractionWindowController voiceInteractionWindowController, TaskbarTranslationController taskbarTranslationController, TaskbarSpringOnStashController taskbarSpringOnStashController, TaskbarRecentAppsController taskbarRecentAppsController, TaskbarEduTooltipController taskbarEduTooltipController, KeyboardQuickSwitchController keyboardQuickSwitchController, TaskbarPinningController taskbarPinningController, Optional<BubbleControllers> bubbleControllers, TaskbarDesktopModeController taskbarDesktopModeController, NudgeController nudgeController)94 public TaskbarControllers(TaskbarActivityContext taskbarActivityContext, 95 TaskbarDragController taskbarDragController, 96 TaskbarNavButtonController navButtonController, 97 NavbarButtonsViewController navbarButtonsViewController, 98 RotationButtonController rotationButtonController, 99 TaskbarDragLayerController taskbarDragLayerController, 100 TaskbarViewController taskbarViewController, 101 TaskbarScrimViewController taskbarScrimViewController, 102 TaskbarUnfoldAnimationController taskbarUnfoldAnimationController, 103 TaskbarKeyguardController taskbarKeyguardController, 104 StashedHandleViewController stashedHandleViewController, 105 TaskbarStashController taskbarStashController, 106 TaskbarAutohideSuspendController taskbarAutoHideSuspendController, 107 TaskbarPopupController taskbarPopupController, 108 TaskbarForceVisibleImmersiveController taskbarForceVisibleImmersiveController, 109 TaskbarOverlayController taskbarOverlayController, 110 TaskbarAllAppsController taskbarAllAppsController, 111 TaskbarInsetsController taskbarInsetsController, 112 VoiceInteractionWindowController voiceInteractionWindowController, 113 TaskbarTranslationController taskbarTranslationController, 114 TaskbarSpringOnStashController taskbarSpringOnStashController, 115 TaskbarRecentAppsController taskbarRecentAppsController, 116 TaskbarEduTooltipController taskbarEduTooltipController, 117 KeyboardQuickSwitchController keyboardQuickSwitchController, 118 TaskbarPinningController taskbarPinningController, 119 Optional<BubbleControllers> bubbleControllers, 120 TaskbarDesktopModeController taskbarDesktopModeController, 121 NudgeController nudgeController) { 122 this.taskbarActivityContext = taskbarActivityContext; 123 this.taskbarDragController = taskbarDragController; 124 this.navButtonController = navButtonController; 125 this.navbarButtonsViewController = navbarButtonsViewController; 126 this.rotationButtonController = rotationButtonController; 127 this.taskbarDragLayerController = taskbarDragLayerController; 128 this.taskbarViewController = taskbarViewController; 129 this.taskbarScrimViewController = taskbarScrimViewController; 130 this.taskbarUnfoldAnimationController = taskbarUnfoldAnimationController; 131 this.taskbarKeyguardController = taskbarKeyguardController; 132 this.stashedHandleViewController = stashedHandleViewController; 133 this.taskbarStashController = taskbarStashController; 134 this.taskbarAutohideSuspendController = taskbarAutoHideSuspendController; 135 this.taskbarPopupController = taskbarPopupController; 136 this.taskbarForceVisibleImmersiveController = taskbarForceVisibleImmersiveController; 137 this.taskbarOverlayController = taskbarOverlayController; 138 this.taskbarAllAppsController = taskbarAllAppsController; 139 this.taskbarInsetsController = taskbarInsetsController; 140 this.voiceInteractionWindowController = voiceInteractionWindowController; 141 this.taskbarTranslationController = taskbarTranslationController; 142 this.taskbarSpringOnStashController = taskbarSpringOnStashController; 143 this.taskbarRecentAppsController = taskbarRecentAppsController; 144 this.taskbarEduTooltipController = taskbarEduTooltipController; 145 this.keyboardQuickSwitchController = keyboardQuickSwitchController; 146 this.taskbarPinningController = taskbarPinningController; 147 this.bubbleControllers = bubbleControllers; 148 this.taskbarDesktopModeController = taskbarDesktopModeController; 149 this.nudgeController = nudgeController; 150 } 151 152 /** 153 * Initializes all controllers. Note that controllers can now reference each other through this 154 * TaskbarControllers instance, but should be careful to only access things that were created 155 * in constructors for now, as some controllers may still be waiting for init(). 156 */ init(@onNull TaskbarSharedState sharedState, AnimatorSet startAnimation)157 public void init(@NonNull TaskbarSharedState sharedState, AnimatorSet startAnimation) { 158 mAreAllControllersInitialized = false; 159 mSharedState = sharedState; 160 161 taskbarDragController.init(this); 162 navbarButtonsViewController.init(this); 163 rotationButtonController.init(); 164 taskbarDragLayerController.init(this, startAnimation); 165 taskbarViewController.init(this, startAnimation); 166 taskbarScrimViewController.init(this); 167 taskbarUnfoldAnimationController.init(this); 168 taskbarKeyguardController.init(navbarButtonsViewController); 169 taskbarSpringOnStashController.init(this); 170 stashedHandleViewController.init(this); 171 taskbarStashController.init(this, sharedState.setupUIVisible, mSharedState); 172 taskbarPopupController.init(this); 173 taskbarForceVisibleImmersiveController.init(this); 174 taskbarOverlayController.init(this); 175 taskbarAllAppsController.init(this, sharedState.allAppsVisible); 176 navButtonController.init(this); 177 bubbleControllers.ifPresent(controllers -> controllers.init(sharedState, this)); 178 taskbarInsetsController.init(this); 179 voiceInteractionWindowController.init(this); 180 taskbarRecentAppsController.init(this); 181 taskbarTranslationController.init(this); 182 taskbarEduTooltipController.init(this); 183 keyboardQuickSwitchController.init(this); 184 taskbarPinningController.init(this, mSharedState); 185 taskbarDesktopModeController.init(this, mSharedState); 186 nudgeController.init(this); 187 188 mControllersToLog = new LoggableTaskbarController[] { 189 taskbarDragController, navButtonController, navbarButtonsViewController, 190 taskbarDragLayerController, taskbarScrimViewController, taskbarViewController, 191 taskbarUnfoldAnimationController, taskbarKeyguardController, 192 stashedHandleViewController, taskbarStashController, 193 taskbarAutohideSuspendController, taskbarPopupController, taskbarInsetsController, 194 voiceInteractionWindowController, taskbarRecentAppsController, 195 taskbarTranslationController, taskbarEduTooltipController, 196 keyboardQuickSwitchController, taskbarPinningController, 197 nudgeController 198 }; 199 mBackgroundRendererControllers = new BackgroundRendererController[] { 200 taskbarDragLayerController, taskbarScrimViewController, 201 voiceInteractionWindowController 202 }; 203 204 // TODO(b/401061748): get primary status from 205 // TaskbarDesktopModeController/DesktopVisibilityController. 206 if (taskbarDesktopModeController.isInDesktopModeAndNotInOverview( 207 taskbarActivityContext.getDisplayId()) 208 || !taskbarActivityContext.isPrimaryDisplay()) { 209 mCornerRoundness.value = taskbarDesktopModeController.getTaskbarCornerRoundness( 210 mSharedState.showCornerRadiusInDesktopMode); 211 } else { 212 mCornerRoundness.value = TaskbarBackgroundRenderer.MAX_ROUNDNESS; 213 } 214 updateCornerRoundness(); 215 onPostInit(); 216 } 217 218 @VisibleForTesting onPostInit()219 public void onPostInit() { 220 mAreAllControllersInitialized = true; 221 for (Runnable postInitCallback : mPostInitCallbacks) { 222 postInitCallback.run(); 223 } 224 mPostInitCallbacks.clear(); 225 } 226 227 /** 228 * Sets the ui controller. 229 */ setUiController(@onNull TaskbarUIController newUiController)230 public void setUiController(@NonNull TaskbarUIController newUiController) { 231 uiController.onDestroy(); 232 uiController = newUiController; 233 uiController.init(this); 234 uiController.updateStateForSysuiFlags(mSharedState.sysuiStateFlags); 235 // if bubble controllers are present configure the UI controller 236 bubbleControllers.ifPresentOrElse(bubbleControllers -> { 237 BubbleBarLocation location = 238 bubbleControllers.bubbleBarViewController.getBubbleBarLocation(); 239 boolean hiddenForBubbles = 240 bubbleControllers.bubbleBarViewController.isHiddenForNoBubbles(); 241 if (!hiddenForBubbles) { 242 uiController.adjustHotseatForBubbleBar(/* isBubbleBarVisible= */ true); 243 } 244 uiController.onBubbleBarLocationUpdated(location); 245 }, () -> uiController.onBubbleBarLocationUpdated(null)); 246 // Notify that the ui controller has changed 247 navbarButtonsViewController.onUiControllerChanged(); 248 } 249 250 @Nullable getSharedState()251 public TaskbarSharedState getSharedState() { 252 // This should only be null if called before init() and after destroy(). 253 return mSharedState; 254 } 255 onConfigurationChanged(@onfig int configChanges)256 public void onConfigurationChanged(@Config int configChanges) { 257 navbarButtonsViewController.onConfigurationChanged(configChanges); 258 taskbarDragLayerController.onConfigurationChanged(); 259 keyboardQuickSwitchController.onConfigurationChanged(configChanges); 260 } 261 262 /** 263 * Cleans up all controllers. 264 */ onDestroy()265 public void onDestroy() { 266 mAreAllControllersInitialized = false; 267 mSharedState = null; 268 269 taskbarDragController.onDestroy(); 270 navbarButtonsViewController.onDestroy(); 271 uiController.onDestroy(); 272 rotationButtonController.onDestroy(); 273 taskbarDragLayerController.onDestroy(); 274 taskbarUnfoldAnimationController.onDestroy(); 275 taskbarViewController.onDestroy(); 276 stashedHandleViewController.onDestroy(); 277 taskbarAutohideSuspendController.onDestroy(); 278 taskbarPopupController.onDestroy(); 279 taskbarForceVisibleImmersiveController.onDestroy(); 280 taskbarOverlayController.onDestroy(); 281 taskbarAllAppsController.onDestroy(); 282 navButtonController.onDestroy(); 283 taskbarInsetsController.onDestroy(); 284 voiceInteractionWindowController.onDestroy(); 285 taskbarRecentAppsController.onDestroy(); 286 keyboardQuickSwitchController.onDestroy(); 287 taskbarStashController.onDestroy(); 288 bubbleControllers.ifPresent(controllers -> controllers.onDestroy()); 289 taskbarDesktopModeController.onDestroy(); 290 mControllersToLog = null; 291 mBackgroundRendererControllers = null; 292 } 293 294 /** 295 * If all controllers are already initialized, runs the given callback immediately. Otherwise, 296 * queues it to run after calling init() on all controllers. This should likely be used in any 297 * case where one controller is telling another controller to do something inside init(). 298 */ runAfterInit(Runnable callback)299 public void runAfterInit(Runnable callback) { 300 if (mAreAllControllersInitialized) { 301 callback.run(); 302 } else { 303 mPostInitCallbacks.add(callback); 304 } 305 } 306 dumpLogs(String prefix, PrintWriter pw)307 protected void dumpLogs(String prefix, PrintWriter pw) { 308 pw.println(prefix + "TaskbarControllers:"); 309 310 if (mControllersToLog == null) { 311 pw.println(String.format( 312 "%s\t%s", prefix, "All taskbar controllers have already been destroyed.")); 313 return; 314 } 315 316 pw.println(String.format( 317 "%s\tmAreAllControllersInitialized=%b", prefix, mAreAllControllersInitialized)); 318 for (LoggableTaskbarController controller : mControllersToLog) { 319 controller.dumpLogs(prefix + "\t", pw); 320 } 321 uiController.dumpLogs(prefix + "\t", pw); 322 rotationButtonController.dumpLogs(prefix + "\t", pw); 323 if (bubbleControllers.isPresent()) { 324 bubbleControllers.get().dump(pw); 325 } else { 326 pw.println(String.format("%s\t%s", prefix, "Bubble controllers are empty.")); 327 } 328 } 329 330 /** 331 * Returns a float property that animates roundness of the round corner above Taskbar. 332 */ getTaskbarCornerRoundness()333 public AnimatedFloat getTaskbarCornerRoundness() { 334 return mCornerRoundness; 335 } 336 updateCornerRoundness()337 private void updateCornerRoundness() { 338 if (mBackgroundRendererControllers == null) { 339 return; 340 } 341 342 for (BackgroundRendererController controller : mBackgroundRendererControllers) { 343 controller.setCornerRoundness(mCornerRoundness.value); 344 } 345 } 346 347 @VisibleForTesting getTaskbarActivityContext()348 TaskbarActivityContext getTaskbarActivityContext() { 349 // Used to mock 350 return taskbarActivityContext; 351 } 352 353 public interface LoggableTaskbarController { dumpLogs(String prefix, PrintWriter pw)354 void dumpLogs(String prefix, PrintWriter pw); 355 } 356 357 protected interface BackgroundRendererController { 358 /** 359 * Sets the roundness of the round corner above Taskbar. 360 * @param cornerRoundness 0 has no round corner, 1 has complete round corner. 361 */ setCornerRoundness(float cornerRoundness)362 void setCornerRoundness(float cornerRoundness); 363 } 364 } 365