• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.view.KeyEvent.ACTION_UP;
19 import static android.view.KeyEvent.KEYCODE_BACK;
20 
21 import static com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_NAVBAR_UNIFICATION;
22 
23 import android.content.Context;
24 import android.graphics.Canvas;
25 import android.graphics.RectF;
26 import android.media.permission.SafeCloseable;
27 import android.util.AttributeSet;
28 import android.util.FloatProperty;
29 import android.view.KeyEvent;
30 import android.view.MotionEvent;
31 import android.view.View;
32 import android.view.ViewTreeObserver;
33 import android.view.WindowInsets;
34 
35 import androidx.annotation.NonNull;
36 import androidx.annotation.Nullable;
37 import androidx.core.graphics.Insets;
38 import androidx.core.view.WindowInsetsCompat;
39 
40 import com.android.app.viewcapture.ViewCaptureFactory;
41 import com.android.launcher3.AbstractFloatingView;
42 import com.android.launcher3.testing.TestLogging;
43 import com.android.launcher3.testing.shared.TestProtocol;
44 import com.android.launcher3.util.MultiPropertyFactory;
45 import com.android.launcher3.util.MultiPropertyFactory.MultiProperty;
46 import com.android.launcher3.views.BaseDragLayer;
47 
48 /**
49  * Top-level ViewGroup that hosts the TaskbarView as well as Views created by it such as Folder.
50  */
51 public class TaskbarDragLayer extends BaseDragLayer<TaskbarActivityContext> {
52 
53     private static final int INDEX_ALL_OTHER_STATES = 0;
54     private static final int INDEX_STASH_ANIM = 1;
55     private static final int INDEX_COUNT = 2;
56 
57     private static final FloatProperty<TaskbarDragLayer> BG_ALPHA =
58             new FloatProperty<>("taskbarBgAlpha") {
59                 @Override
60                 public void setValue(TaskbarDragLayer dragLayer, float alpha) {
61                     dragLayer.mBackgroundRenderer.getPaint().setAlpha((int) (alpha * 255));
62                     dragLayer.invalidate();
63                 }
64 
65                 @Override
66                 public Float get(TaskbarDragLayer dragLayer) {
67                     return dragLayer.mBackgroundRenderer.getPaint().getAlpha() / 255f;
68                 }
69             };
70 
71 
72     private final TaskbarBackgroundRenderer mBackgroundRenderer;
73     private final ViewTreeObserver.OnComputeInternalInsetsListener mTaskbarInsetsComputer =
74             this::onComputeTaskbarInsets;
75 
76     // Initialized in init.
77     private TaskbarDragLayerController.TaskbarDragLayerCallbacks mControllerCallbacks;
78     private SafeCloseable mViewCaptureCloseable;
79 
80     private float mTaskbarBackgroundOffset;
81     private float mTaskbarBackgroundProgress;
82     private boolean mIsAnimatingTaskbarPinning = false;
83 
84     private final MultiPropertyFactory<TaskbarDragLayer> mTaskbarBackgroundAlpha;
85 
TaskbarDragLayer(@onNull Context context)86     public TaskbarDragLayer(@NonNull Context context) {
87         this(context, null);
88     }
89 
TaskbarDragLayer(@onNull Context context, @Nullable AttributeSet attrs)90     public TaskbarDragLayer(@NonNull Context context, @Nullable AttributeSet attrs) {
91         this(context, attrs, 0);
92     }
93 
TaskbarDragLayer(@onNull Context context, @Nullable AttributeSet attrs, int defStyleAttr)94     public TaskbarDragLayer(@NonNull Context context, @Nullable AttributeSet attrs,
95             int defStyleAttr) {
96         this(context, attrs, defStyleAttr, 0);
97     }
98 
TaskbarDragLayer(@onNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes)99     public TaskbarDragLayer(@NonNull Context context, @Nullable AttributeSet attrs,
100             int defStyleAttr, int defStyleRes) {
101         super(context, attrs, 1 /* alphaChannelCount */);
102         mBackgroundRenderer = new TaskbarBackgroundRenderer(mContainer);
103 
104         mTaskbarBackgroundAlpha = new MultiPropertyFactory<>(this, BG_ALPHA, INDEX_COUNT,
105                 (a, b) -> a * b, 1f);
106         mTaskbarBackgroundAlpha.get(INDEX_ALL_OTHER_STATES).setValue(0);
107     }
108 
init(TaskbarDragLayerController.TaskbarDragLayerCallbacks callbacks)109     public void init(TaskbarDragLayerController.TaskbarDragLayerCallbacks callbacks) {
110         mControllerCallbacks = callbacks;
111         mBackgroundRenderer.updateStashedHandleWidth(mContainer, getResources());
112         recreateControllers();
113     }
114 
115     @Override
onApplyWindowInsets(WindowInsets insets)116     public WindowInsets onApplyWindowInsets(WindowInsets insets) {
117         if (insets != null) {
118             WindowInsetsCompat insetsCompat = WindowInsetsCompat.toWindowInsetsCompat(insets, this);
119             Insets imeInsets = insetsCompat.getInsets(WindowInsetsCompat.Type.ime());
120             if (imeInsets != null) {
121                 mControllerCallbacks.onImeInsetChanged();
122             }
123         }
124         return insets;
125     }
126 
127     @Override
recreateControllers()128     public void recreateControllers() {
129         mControllers = mControllerCallbacks.getTouchControllers();
130     }
131 
onComputeTaskbarInsets(ViewTreeObserver.InternalInsetsInfo insetsInfo)132     private void onComputeTaskbarInsets(ViewTreeObserver.InternalInsetsInfo insetsInfo) {
133         if (mControllerCallbacks != null) {
134             mControllerCallbacks.updateInsetsTouchability(insetsInfo);
135         }
136     }
137 
onDestroy(boolean forceDestroy)138     protected void onDestroy(boolean forceDestroy) {
139         if (forceDestroy) {
140             getViewTreeObserver().removeOnComputeInternalInsetsListener(mTaskbarInsetsComputer);
141         }
142     }
143 
onDestroy()144     protected void onDestroy() {
145         onDestroy(!ENABLE_TASKBAR_NAVBAR_UNIFICATION);
146     }
147 
148     @Override
onAttachedToWindow()149     protected void onAttachedToWindow() {
150         super.onAttachedToWindow();
151         getViewTreeObserver().addOnComputeInternalInsetsListener(mTaskbarInsetsComputer);
152         mViewCaptureCloseable = ViewCaptureFactory.getInstance(getContext())
153                 .startCapture(getRootView(), ".Taskbar");
154     }
155 
156     @Override
onDetachedFromWindow()157     protected void onDetachedFromWindow() {
158         super.onDetachedFromWindow();
159         mViewCaptureCloseable.close();
160         onDestroy(true);
161     }
162 
163     @Override
isEventWithinSystemGestureRegion(MotionEvent ev)164     protected boolean isEventWithinSystemGestureRegion(MotionEvent ev) {
165         final float x = ev.getX();
166         final float y = ev.getY();
167 
168         return x >= mSystemGestureRegion.left && x < getWidth() - mSystemGestureRegion.right
169                 && y >= mSystemGestureRegion.top;
170     }
171 
172     @Override
canFindActiveController()173     protected boolean canFindActiveController() {
174         // Unlike super class, we want to be able to find controllers when touches occur in the
175         // gesture area. For example, this allows Folder to close itself when touching the Taskbar.
176         return true;
177     }
178 
179     @Override
onViewRemoved(View child)180     public void onViewRemoved(View child) {
181         super.onViewRemoved(child);
182         if (mControllerCallbacks != null) {
183             mControllerCallbacks.onDragLayerViewRemoved();
184         }
185     }
186 
187     @Override
dispatchDraw(Canvas canvas)188     protected void dispatchDraw(Canvas canvas) {
189         if (mContainer.isDestroyed()) return;
190         float backgroundHeight = mControllerCallbacks.getTaskbarBackgroundHeight()
191                 * (1f - mTaskbarBackgroundOffset);
192         mBackgroundRenderer.setBackgroundHeight(backgroundHeight);
193         mBackgroundRenderer.setBackgroundProgress(mTaskbarBackgroundProgress);
194         mBackgroundRenderer.draw(canvas);
195         super.dispatchDraw(canvas);
196         mControllerCallbacks.drawDebugUi(canvas);
197     }
198 
199     /**
200      * Sets animation boolean when taskbar pinning animation starts or stops.
201      */
setAnimatingTaskbarPinning(boolean animatingTaskbarPinning)202     public void setAnimatingTaskbarPinning(boolean animatingTaskbarPinning) {
203         mIsAnimatingTaskbarPinning = animatingTaskbarPinning;
204         mBackgroundRenderer.setAnimatingPinning(mIsAnimatingTaskbarPinning);
205     }
206 
getBackgroundRendererAlpha()207     protected MultiProperty getBackgroundRendererAlpha() {
208         return mTaskbarBackgroundAlpha.get(INDEX_ALL_OTHER_STATES);
209     }
210 
getBackgroundRendererAlphaForStash()211     protected MultiProperty getBackgroundRendererAlphaForStash() {
212         return mTaskbarBackgroundAlpha.get(INDEX_STASH_ANIM);
213     }
214 
215     /**
216      * Sets the value for taskbar background switching between persistent and transient backgrounds.
217      * @param progress 0 is transient background, 1 is persistent background.
218      */
setTaskbarBackgroundProgress(float progress)219     protected void setTaskbarBackgroundProgress(float progress) {
220         mTaskbarBackgroundProgress = progress;
221         invalidate();
222     }
223 
224     /**
225      * Sets the translation of the background color behind all the Taskbar contents.
226      * @param offset 0 is fully onscreen, 1 is fully offscreen.
227      */
setTaskbarBackgroundOffset(float offset)228     protected void setTaskbarBackgroundOffset(float offset) {
229         mTaskbarBackgroundOffset = offset;
230         invalidate();
231     }
232 
233     /**
234      * Sets the roundness of the round corner above Taskbar.
235      * @param cornerRoundness 0 has no round corner, 1 has complete round corner.
236      */
setCornerRoundness(float cornerRoundness)237     protected void setCornerRoundness(float cornerRoundness) {
238         mBackgroundRenderer.setCornerRoundness(cornerRoundness);
239         invalidate();
240     }
241 
242     /*
243      * Sets the translation of the background during the swipe up gesture.
244      */
setBackgroundTranslationYForSwipe(float translationY)245     protected void setBackgroundTranslationYForSwipe(float translationY) {
246         mBackgroundRenderer.setTranslationYForSwipe(translationY);
247         invalidate();
248     }
249 
250     /*
251      * Sets the translation of the background during the spring on stash animation.
252      */
setBackgroundTranslationYForStash(float translationY)253     protected void setBackgroundTranslationYForStash(float translationY) {
254         mBackgroundRenderer.setTranslationYForStash(translationY);
255         invalidate();
256     }
257 
setBackgroundTranslationXForBubbleBar(float translationX)258     protected void setBackgroundTranslationXForBubbleBar(float translationX) {
259         mBackgroundRenderer.setTranslationXForBubbleBar(translationX);
260         invalidate();
261     }
262 
263     /** Returns the bounds in DragLayer coordinates of where the transient background was drawn. */
getLastDrawnTransientRect()264     protected RectF getLastDrawnTransientRect() {
265         return mBackgroundRenderer.getLastDrawnTransientRect();
266     }
267 
268     @Override
dispatchTouchEvent(MotionEvent ev)269     public boolean dispatchTouchEvent(MotionEvent ev) {
270         TestLogging.recordMotionEvent(TestProtocol.SEQUENCE_MAIN, "Touch event", ev);
271         mControllerCallbacks.onDispatchTouchEvent(ev);
272         return super.dispatchTouchEvent(ev);
273     }
274 
275     /** Called while Taskbar window is focusable, e.g. when pressing back while a folder is open */
276     @Override
dispatchKeyEvent(KeyEvent event)277     public boolean dispatchKeyEvent(KeyEvent event) {
278         if (event.getAction() == ACTION_UP && event.getKeyCode() == KEYCODE_BACK) {
279             AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(mContainer);
280             if (topView != null && topView.canHandleBack()) {
281                 topView.onBackInvoked();
282                 // Handled by the floating view.
283                 return true;
284             }
285         }
286         return super.dispatchKeyEvent(event);
287     }
288 
289     /**
290      * Sets animation boolean when only animating persistent taskbar.
291      */
setIsAnimatingPersistentTaskbarBackground(boolean animatingPersistentTaskbarBg)292     public void setIsAnimatingPersistentTaskbarBackground(boolean animatingPersistentTaskbarBg) {
293         mBackgroundRenderer.setAnimatingPersistentTaskbar(animatingPersistentTaskbarBg);
294     }
295 
296     /**
297      * Sets animation boolean when only animating transient taskbar.
298      */
setIsAnimatingTransientTaskbarBackground(boolean animatingTransientTaskbarBg)299     public void setIsAnimatingTransientTaskbarBackground(boolean animatingTransientTaskbarBg) {
300         mBackgroundRenderer.setAnimatingTransientTaskbar(animatingTransientTaskbarBg);
301     }
302 
303 
304     /**
305      * Sets the width percentage to inset the transient taskbar's background from the left and from
306      * the right.
307      */
setBackgroundHorizontalInsets(float insetPercentage)308     public void setBackgroundHorizontalInsets(float insetPercentage) {
309         mBackgroundRenderer.setBackgroundHorizontalInsets(insetPercentage);
310         invalidate();
311     }
312 }
313