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 com.android.launcher3.taskbar.TaskbarPinningController.PINNING_PERSISTENT;
19 import static com.android.launcher3.taskbar.TaskbarPinningController.PINNING_TRANSIENT;
20 
21 import android.content.res.Resources;
22 import android.graphics.Canvas;
23 import android.graphics.Point;
24 import android.graphics.Rect;
25 import android.os.SystemProperties;
26 import android.view.ViewTreeObserver;
27 
28 import com.android.launcher3.DeviceProfile;
29 import com.android.launcher3.R;
30 import com.android.launcher3.anim.AnimatedFloat;
31 import com.android.launcher3.util.DimensionUtils;
32 import com.android.launcher3.util.DisplayController;
33 import com.android.launcher3.util.MultiPropertyFactory.MultiProperty;
34 import com.android.launcher3.util.TouchController;
35 
36 import java.io.PrintWriter;
37 
38 /**
39  * Handles properties/data collection, then passes the results to TaskbarDragLayer to render.
40  */
41 public class TaskbarDragLayerController implements TaskbarControllers.LoggableTaskbarController,
42         TaskbarControllers.BackgroundRendererController {
43 
44     private static final boolean DEBUG = SystemProperties.getBoolean(
45             "persist.debug.draw_taskbar_debug_ui", false);
46 
47     private final TaskbarActivityContext mActivity;
48     private final TaskbarDragLayer mTaskbarDragLayer;
49     private final int mFolderMargin;
50 
51     // Alpha properties for taskbar background.
52     private final AnimatedFloat mBgTaskbar = new AnimatedFloat(this::updateBackgroundAlpha);
53     private final AnimatedFloat mBgNavbar = new AnimatedFloat(this::updateBackgroundAlpha);
54     private final AnimatedFloat mKeyguardBgTaskbar = new AnimatedFloat(this::updateBackgroundAlpha);
55     private final AnimatedFloat mNotificationShadeBgTaskbar = new AnimatedFloat(
56             this::updateBackgroundAlpha);
57     private final AnimatedFloat mImeBgTaskbar = new AnimatedFloat(this::updateBackgroundAlpha);
58     private final AnimatedFloat mAssistantBgTaskbar = new AnimatedFloat(
59             this::updateBackgroundAlpha);
60     // Used to hide our background color when someone else (e.g. ScrimView) is handling it.
61     private final AnimatedFloat mBgOverride = new AnimatedFloat(this::updateBackgroundAlpha);
62 
63     // Translation property for taskbar background.
64     private final AnimatedFloat mBgOffset = new AnimatedFloat(this::updateBackgroundOffset);
65 
66     // Used to fade in/out the entirety of the taskbar, for a smooth transition before/after sysui
67     // changes the inset visibility.
68     private final AnimatedFloat mTaskbarAlpha = new AnimatedFloat(this::updateTaskbarAlpha);
69 
70     private final AnimatedFloat mTaskbarBackgroundProgress = new AnimatedFloat(
71             this::updateTaskbarBackgroundProgress);
72 
73     // Initialized in init.
74     private TaskbarControllers mControllers;
75     private TaskbarStashViaTouchController mTaskbarStashViaTouchController;
76     private AnimatedFloat mOnBackgroundNavButtonColorIntensity;
77 
78     private MultiProperty mBackgroundRendererAlpha;
79     private float mLastSetBackgroundAlpha;
80 
TaskbarDragLayerController(TaskbarActivityContext activity, TaskbarDragLayer taskbarDragLayer)81     public TaskbarDragLayerController(TaskbarActivityContext activity,
82             TaskbarDragLayer taskbarDragLayer) {
83         mActivity = activity;
84         mTaskbarDragLayer = taskbarDragLayer;
85         mBackgroundRendererAlpha = mTaskbarDragLayer.getBackgroundRendererAlpha();
86         final Resources resources = mTaskbarDragLayer.getResources();
87         mFolderMargin = resources.getDimensionPixelSize(R.dimen.taskbar_folder_margin);
88     }
89 
init(TaskbarControllers controllers)90     public void init(TaskbarControllers controllers) {
91         mControllers = controllers;
92         mTaskbarStashViaTouchController = new TaskbarStashViaTouchController(mControllers);
93         mTaskbarDragLayer.init(new TaskbarDragLayerCallbacks());
94 
95         mOnBackgroundNavButtonColorIntensity = mControllers.navbarButtonsViewController
96                 .getOnTaskbarBackgroundNavButtonColorOverride();
97 
98         mTaskbarBackgroundProgress.updateValue(DisplayController.isTransientTaskbar(mActivity)
99                 ? PINNING_TRANSIENT
100                 : PINNING_PERSISTENT);
101 
102         mBgTaskbar.value = 1;
103         mKeyguardBgTaskbar.value = 1;
104         mNotificationShadeBgTaskbar.value = 1;
105         mImeBgTaskbar.value = 1;
106         mAssistantBgTaskbar.value = 1;
107         mBgOverride.value = 1;
108         updateBackgroundAlpha();
109 
110         mTaskbarAlpha.value = 1;
111         updateTaskbarAlpha();
112     }
113 
onDestroy()114     public void onDestroy() {
115         mTaskbarDragLayer.onDestroy();
116     }
117 
118     /**
119      * @return Bounds (in TaskbarDragLayer coordinates) where an opened Folder can display.
120      */
getFolderBoundingBox()121     public Rect getFolderBoundingBox() {
122         Rect boundingBox = new Rect(0, 0, mTaskbarDragLayer.getWidth(),
123                 mTaskbarDragLayer.getHeight() - mActivity.getDeviceProfile().taskbarHeight
124                         - mActivity.getDeviceProfile().taskbarBottomMargin);
125         boundingBox.inset(mFolderMargin, mFolderMargin);
126         return boundingBox;
127     }
128 
getTaskbarBackgroundAlpha()129     public AnimatedFloat getTaskbarBackgroundAlpha() {
130         return mBgTaskbar;
131     }
132 
getNavbarBackgroundAlpha()133     public AnimatedFloat getNavbarBackgroundAlpha() {
134         return mBgNavbar;
135     }
136 
getKeyguardBgTaskbar()137     public AnimatedFloat getKeyguardBgTaskbar() {
138         return mKeyguardBgTaskbar;
139     }
140 
getNotificationShadeBgTaskbar()141     public AnimatedFloat getNotificationShadeBgTaskbar() {
142         return mNotificationShadeBgTaskbar;
143     }
144 
getImeBgTaskbar()145     public AnimatedFloat getImeBgTaskbar() {
146         return mImeBgTaskbar;
147     }
148 
getAssistantBgTaskbar()149     public AnimatedFloat getAssistantBgTaskbar() {
150         return mAssistantBgTaskbar;
151     }
152 
getTaskbarBackgroundOffset()153     public AnimatedFloat getTaskbarBackgroundOffset() {
154         return mBgOffset;
155     }
156 
157     // AnimatedFloat is for animating between pinned and transient taskbar
getTaskbarBackgroundProgress()158     public AnimatedFloat getTaskbarBackgroundProgress() {
159         return mTaskbarBackgroundProgress;
160     }
161 
getTaskbarAlpha()162     public AnimatedFloat getTaskbarAlpha() {
163         return mTaskbarAlpha;
164     }
165 
166     /**
167      * Make updates when configuration changes.
168      */
onConfigurationChanged()169     public void onConfigurationChanged() {
170         mTaskbarStashViaTouchController.updateGestureHeight();
171     }
172 
updateBackgroundAlpha()173     private void updateBackgroundAlpha() {
174         final float bgNavbar = mBgNavbar.value;
175         final float bgTaskbar = mBgTaskbar.value * mKeyguardBgTaskbar.value
176                 * mNotificationShadeBgTaskbar.value * mImeBgTaskbar.value
177                 * mAssistantBgTaskbar.value;
178         mLastSetBackgroundAlpha = mBgOverride.value * Math.max(bgNavbar, bgTaskbar);
179         mBackgroundRendererAlpha.setValue(mLastSetBackgroundAlpha);
180 
181         updateOnBackgroundNavButtonColorIntensity();
182     }
183 
getBackgroundRendererAlphaForStash()184     public MultiProperty getBackgroundRendererAlphaForStash() {
185         return mTaskbarDragLayer.getBackgroundRendererAlphaForStash();
186     }
187 
188     /**
189      * Sets the translation of the background during the swipe up gesture.
190      */
setTranslationYForSwipe(float transY)191     public void setTranslationYForSwipe(float transY) {
192         mTaskbarDragLayer.setBackgroundTranslationYForSwipe(transY);
193     }
194 
195     /**
196      * Sets the translation of the background during the spring on stash animation.
197      */
setTranslationYForStash(float transY)198     public void setTranslationYForStash(float transY) {
199         mTaskbarDragLayer.setBackgroundTranslationYForStash(transY);
200     }
201 
updateBackgroundOffset()202     private void updateBackgroundOffset() {
203         mTaskbarDragLayer.setTaskbarBackgroundOffset(mBgOffset.value);
204         updateOnBackgroundNavButtonColorIntensity();
205     }
206 
updateTaskbarBackgroundProgress()207     private void updateTaskbarBackgroundProgress() {
208         mTaskbarDragLayer.setTaskbarBackgroundProgress(mTaskbarBackgroundProgress.value);
209     }
210 
updateTaskbarAlpha()211     private void updateTaskbarAlpha() {
212         mTaskbarDragLayer.setAlpha(mTaskbarAlpha.value);
213     }
214 
215     @Override
setCornerRoundness(float cornerRoundness)216     public void setCornerRoundness(float cornerRoundness) {
217         mTaskbarDragLayer.setCornerRoundness(cornerRoundness);
218     }
219 
220     /**
221      * Set if another controller is temporarily handling background drawing. In this case we
222      * override our background alpha to be {@code 0}.
223      */
setIsBackgroundDrawnElsewhere(boolean isBackgroundDrawnElsewhere)224     public void setIsBackgroundDrawnElsewhere(boolean isBackgroundDrawnElsewhere) {
225         mBgOverride.updateValue(isBackgroundDrawnElsewhere ? 0 : 1);
226     }
227 
updateOnBackgroundNavButtonColorIntensity()228     private void updateOnBackgroundNavButtonColorIntensity() {
229         mOnBackgroundNavButtonColorIntensity.updateValue(
230                 mLastSetBackgroundAlpha * (1 - mBgOffset.value));
231     }
232 
233     /**
234      * Sets the width percentage to inset the transient taskbar's background from the left and from
235      * the right.
236      */
setBackgroundHorizontalInsets(float insetPercentage)237     public void setBackgroundHorizontalInsets(float insetPercentage) {
238         mTaskbarDragLayer.setBackgroundHorizontalInsets(insetPercentage);
239 
240     }
241 
242     @Override
dumpLogs(String prefix, PrintWriter pw)243     public void dumpLogs(String prefix, PrintWriter pw) {
244         pw.println(prefix + "TaskbarDragLayerController:");
245 
246         pw.println(prefix + "\tmBgOffset=" + mBgOffset.value);
247         pw.println(prefix + "\tmTaskbarAlpha=" + mTaskbarAlpha.value);
248         pw.println(prefix + "\tmFolderMargin=" + mFolderMargin);
249         pw.println(prefix + "\tmLastSetBackgroundAlpha=" + mLastSetBackgroundAlpha);
250         pw.println(prefix + "\t\tmBgOverride=" + mBgOverride.value);
251         pw.println(prefix + "\t\tmBgNavbar=" + mBgNavbar.value);
252         pw.println(prefix + "\t\tmBgTaskbar=" + mBgTaskbar.value);
253         pw.println(prefix + "\t\tmKeyguardBgTaskbar=" + mKeyguardBgTaskbar.value);
254         pw.println(prefix + "\t\tmNotificationShadeBgTaskbar=" + mNotificationShadeBgTaskbar.value);
255         pw.println(prefix + "\t\tmImeBgTaskbar=" + mImeBgTaskbar.value);
256         pw.println(prefix + "\t\tmAssistantBgTaskbar=" + mAssistantBgTaskbar.value);
257     }
258 
259     /**
260      * Callbacks for {@link TaskbarDragLayer} to interact with its controller.
261      */
262     public class TaskbarDragLayerCallbacks {
263 
264         /**
265          * Called to update the touchable insets.
266          * @see ViewTreeObserver.InternalInsetsInfo#setTouchableInsets(int)
267          */
updateInsetsTouchability(ViewTreeObserver.InternalInsetsInfo insetsInfo)268         public void updateInsetsTouchability(ViewTreeObserver.InternalInsetsInfo insetsInfo) {
269             mControllers.taskbarInsetsController.updateInsetsTouchability(insetsInfo);
270         }
271 
272         /**
273          * Called when an IME inset is changed.
274          */
onImeInsetChanged()275         public void onImeInsetChanged() {
276             mControllers.taskbarStashController.onImeInsetChanged();
277         }
278 
279         /**
280          * Called when a child is removed from TaskbarDragLayer.
281          */
onDragLayerViewRemoved()282         public void onDragLayerViewRemoved() {
283             mActivity.onDragEndOrViewRemoved();
284         }
285 
286         /**
287          * Returns how tall the background should be drawn at the bottom of the screen.
288          */
getTaskbarBackgroundHeight()289         public int getTaskbarBackgroundHeight() {
290             DeviceProfile deviceProfile = mActivity.getDeviceProfile();
291             if (mActivity.isPhoneMode()) {
292                 Resources resources = mActivity.getResources();
293                 Point taskbarDimensions = DimensionUtils.getTaskbarPhoneDimensions(deviceProfile,
294                         resources, true /* isPhoneMode */);
295                 return taskbarDimensions.y == -1 ?
296                         deviceProfile.getDisplayInfo().currentSize.y :
297                         taskbarDimensions.y;
298             } else {
299                 return deviceProfile.taskbarHeight;
300             }
301         }
302 
303         /**
304          * Returns touch controllers.
305          */
getTouchControllers()306         public TouchController[] getTouchControllers() {
307             return new TouchController[] {
308                     mActivity.getDragController(),
309                     mControllers.taskbarForceVisibleImmersiveController,
310                     mControllers.navbarButtonsViewController.getTouchController(),
311                     mTaskbarStashViaTouchController,
312             };
313         }
314 
315         /**
316          * Draws debug UI on top of everything in TaskbarDragLayer.
317          */
drawDebugUi(Canvas canvas)318         public void drawDebugUi(Canvas canvas) {
319             if (!DEBUG) {
320                 return;
321             }
322             mControllers.taskbarInsetsController.drawDebugTouchableRegionBounds(canvas);
323         }
324     }
325 }
326