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