• 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 android.content.Context;
22 import android.graphics.Canvas;
23 import android.graphics.RectF;
24 import android.media.permission.SafeCloseable;
25 import android.util.AttributeSet;
26 import android.util.FloatProperty;
27 import android.view.KeyEvent;
28 import android.view.MotionEvent;
29 import android.view.View;
30 import android.view.ViewTreeObserver;
31 
32 import androidx.annotation.NonNull;
33 import androidx.annotation.Nullable;
34 
35 import com.android.app.viewcapture.SettingsAwareViewCapture;
36 import com.android.launcher3.AbstractFloatingView;
37 import com.android.launcher3.testing.TestLogging;
38 import com.android.launcher3.testing.shared.TestProtocol;
39 import com.android.launcher3.util.MultiPropertyFactory;
40 import com.android.launcher3.util.MultiPropertyFactory.MultiProperty;
41 import com.android.launcher3.views.BaseDragLayer;
42 
43 /**
44  * Top-level ViewGroup that hosts the TaskbarView as well as Views created by it such as Folder.
45  */
46 public class TaskbarDragLayer extends BaseDragLayer<TaskbarActivityContext> {
47 
48     private static final int INDEX_ALL_OTHER_STATES = 0;
49     private static final int INDEX_STASH_ANIM = 1;
50     private static final int INDEX_COUNT = 2;
51 
52     private static final FloatProperty<TaskbarDragLayer> BG_ALPHA =
53             new FloatProperty<>("taskbarBgAlpha") {
54                 @Override
55                 public void setValue(TaskbarDragLayer dragLayer, float alpha) {
56                     dragLayer.mBackgroundRenderer.getPaint().setAlpha((int) (alpha * 255));
57                     dragLayer.invalidate();
58                 }
59 
60                 @Override
61                 public Float get(TaskbarDragLayer dragLayer) {
62                     return dragLayer.mBackgroundRenderer.getPaint().getAlpha() / 255f;
63                 }
64             };
65 
66 
67     private final TaskbarBackgroundRenderer mBackgroundRenderer;
68     private final ViewTreeObserver.OnComputeInternalInsetsListener mTaskbarInsetsComputer =
69             this::onComputeTaskbarInsets;
70 
71     // Initialized in init.
72     private TaskbarDragLayerController.TaskbarDragLayerCallbacks mControllerCallbacks;
73     private SafeCloseable mViewCaptureCloseable;
74 
75     private float mTaskbarBackgroundOffset;
76 
77     private final MultiPropertyFactory<TaskbarDragLayer> mTaskbarBackgroundAlpha;
78 
TaskbarDragLayer(@onNull Context context)79     public TaskbarDragLayer(@NonNull Context context) {
80         this(context, null);
81     }
82 
TaskbarDragLayer(@onNull Context context, @Nullable AttributeSet attrs)83     public TaskbarDragLayer(@NonNull Context context, @Nullable AttributeSet attrs) {
84         this(context, attrs, 0);
85     }
86 
TaskbarDragLayer(@onNull Context context, @Nullable AttributeSet attrs, int defStyleAttr)87     public TaskbarDragLayer(@NonNull Context context, @Nullable AttributeSet attrs,
88             int defStyleAttr) {
89         this(context, attrs, defStyleAttr, 0);
90     }
91 
TaskbarDragLayer(@onNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes)92     public TaskbarDragLayer(@NonNull Context context, @Nullable AttributeSet attrs,
93             int defStyleAttr, int defStyleRes) {
94         super(context, attrs, 1 /* alphaChannelCount */);
95         mBackgroundRenderer = new TaskbarBackgroundRenderer(mActivity);
96 
97         mTaskbarBackgroundAlpha = new MultiPropertyFactory<>(this, BG_ALPHA, INDEX_COUNT,
98                 (a, b) -> a * b, 1f);
99         mTaskbarBackgroundAlpha.get(INDEX_ALL_OTHER_STATES).setValue(0);
100         mTaskbarBackgroundAlpha.get(INDEX_STASH_ANIM).setValue(1);
101     }
102 
init(TaskbarDragLayerController.TaskbarDragLayerCallbacks callbacks)103     public void init(TaskbarDragLayerController.TaskbarDragLayerCallbacks callbacks) {
104         mControllerCallbacks = callbacks;
105         mBackgroundRenderer.updateStashedHandleWidth(mActivity.getDeviceProfile(), getResources());
106         recreateControllers();
107     }
108 
109     @Override
recreateControllers()110     public void recreateControllers() {
111         mControllers = mControllerCallbacks.getTouchControllers();
112     }
113 
onComputeTaskbarInsets(ViewTreeObserver.InternalInsetsInfo insetsInfo)114     private void onComputeTaskbarInsets(ViewTreeObserver.InternalInsetsInfo insetsInfo) {
115         if (mControllerCallbacks != null) {
116             mControllerCallbacks.updateInsetsTouchability(insetsInfo);
117         }
118     }
119 
onDestroy(boolean forceDestroy)120     protected void onDestroy(boolean forceDestroy) {
121         if (forceDestroy) {
122             getViewTreeObserver().removeOnComputeInternalInsetsListener(mTaskbarInsetsComputer);
123         }
124     }
125 
onDestroy()126     protected void onDestroy() {
127         onDestroy(!TaskbarManager.FLAG_HIDE_NAVBAR_WINDOW);
128     }
129 
130     @Override
onAttachedToWindow()131     protected void onAttachedToWindow() {
132         super.onAttachedToWindow();
133         getViewTreeObserver().addOnComputeInternalInsetsListener(mTaskbarInsetsComputer);
134         mViewCaptureCloseable = SettingsAwareViewCapture.getInstance(getContext())
135                 .startCapture(getRootView(), ".Taskbar");
136     }
137 
138     @Override
onDetachedFromWindow()139     protected void onDetachedFromWindow() {
140         super.onDetachedFromWindow();
141         mViewCaptureCloseable.close();
142         onDestroy(true);
143     }
144 
145     @Override
canFindActiveController()146     protected boolean canFindActiveController() {
147         // Unlike super class, we want to be able to find controllers when touches occur in the
148         // gesture area. For example, this allows Folder to close itself when touching the Taskbar.
149         return true;
150     }
151 
152     @Override
onViewRemoved(View child)153     public void onViewRemoved(View child) {
154         super.onViewRemoved(child);
155         if (mControllerCallbacks != null) {
156             mControllerCallbacks.onDragLayerViewRemoved();
157         }
158     }
159 
160     @Override
dispatchDraw(Canvas canvas)161     protected void dispatchDraw(Canvas canvas) {
162         float backgroundHeight = mControllerCallbacks.getTaskbarBackgroundHeight()
163                 * (1f - mTaskbarBackgroundOffset);
164         mBackgroundRenderer.setBackgroundHeight(backgroundHeight);
165         mBackgroundRenderer.draw(canvas);
166         super.dispatchDraw(canvas);
167     }
168 
getBackgroundRendererAlpha()169     protected MultiProperty getBackgroundRendererAlpha() {
170         return mTaskbarBackgroundAlpha.get(INDEX_ALL_OTHER_STATES);
171     }
172 
getBackgroundRendererAlphaForStash()173     protected MultiProperty getBackgroundRendererAlphaForStash() {
174         return mTaskbarBackgroundAlpha.get(INDEX_STASH_ANIM);
175     }
176 
177     /**
178      * Sets the translation of the background color behind all the Taskbar contents.
179      * @param offset 0 is fully onscreen, 1 is fully offscreen.
180      */
setTaskbarBackgroundOffset(float offset)181     protected void setTaskbarBackgroundOffset(float offset) {
182         mTaskbarBackgroundOffset = offset;
183         invalidate();
184     }
185 
186     /**
187      * Sets the roundness of the round corner above Taskbar.
188      * @param cornerRoundness 0 has no round corner, 1 has complete round corner.
189      */
setCornerRoundness(float cornerRoundness)190     protected void setCornerRoundness(float cornerRoundness) {
191         mBackgroundRenderer.setCornerRoundness(cornerRoundness);
192         invalidate();
193     }
194 
195     /*
196      * Sets the translation of the background during the swipe up gesture.
197      */
setBackgroundTranslationYForSwipe(float translationY)198     protected void setBackgroundTranslationYForSwipe(float translationY) {
199         mBackgroundRenderer.setTranslationYForSwipe(translationY);
200         invalidate();
201     }
202 
203     /*
204      * Sets the translation of the background during the spring on stash animation.
205      */
setBackgroundTranslationYForStash(float translationY)206     protected void setBackgroundTranslationYForStash(float translationY) {
207         mBackgroundRenderer.setTranslationYForStash(translationY);
208         invalidate();
209     }
210 
211     /** Returns the bounds in DragLayer coordinates of where the transient background was drawn. */
getLastDrawnTransientRect()212     protected RectF getLastDrawnTransientRect() {
213         return mBackgroundRenderer.getLastDrawnTransientRect();
214     }
215 
216     @Override
dispatchTouchEvent(MotionEvent ev)217     public boolean dispatchTouchEvent(MotionEvent ev) {
218         TestLogging.recordMotionEvent(TestProtocol.SEQUENCE_MAIN, "Touch event", ev);
219         return super.dispatchTouchEvent(ev);
220     }
221 
222     /** Called while Taskbar window is focusable, e.g. when pressing back while a folder is open */
223     @Override
dispatchKeyEvent(KeyEvent event)224     public boolean dispatchKeyEvent(KeyEvent event) {
225         if (event.getAction() == ACTION_UP && event.getKeyCode() == KEYCODE_BACK) {
226             AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(mActivity);
227             if (topView != null && topView.canHandleBack()) {
228                 topView.onBackInvoked();
229                 // Handled by the floating view.
230                 return true;
231             }
232         }
233         return super.dispatchKeyEvent(event);
234     }
235 
236     /**
237      * Sets the width percentage to inset the transient taskbar's background from the left and from
238      * the right.
239      */
setBackgroundHorizontalInsets(float insetPercentage)240     public void setBackgroundHorizontalInsets(float insetPercentage) {
241         mBackgroundRenderer.setBackgroundHorizontalInsets(insetPercentage);
242         invalidate();
243     }
244 }
245