• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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 
17 package com.android.quickstep.views;
18 
19 import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL;
20 import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_SHARE;
21 
22 import android.content.Context;
23 import android.content.res.Configuration;
24 import android.graphics.Rect;
25 import android.util.AttributeSet;
26 import android.view.View;
27 import android.view.View.OnClickListener;
28 import android.widget.FrameLayout;
29 
30 import androidx.annotation.IntDef;
31 import androidx.annotation.Nullable;
32 
33 import com.android.launcher3.DeviceProfile;
34 import com.android.launcher3.Insettable;
35 import com.android.launcher3.R;
36 import com.android.launcher3.Utilities;
37 import com.android.launcher3.util.MultiValueAlpha;
38 import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
39 import com.android.quickstep.SysUINavigationMode;
40 import com.android.quickstep.SysUINavigationMode.Mode;
41 import com.android.quickstep.TaskOverlayFactory.OverlayUICallbacks;
42 import com.android.quickstep.util.LayoutUtils;
43 
44 import java.lang.annotation.Retention;
45 import java.lang.annotation.RetentionPolicy;
46 
47 /**
48  * View for showing action buttons in Overview
49  */
50 public class OverviewActionsView<T extends OverlayUICallbacks> extends FrameLayout
51         implements OnClickListener, Insettable {
52 
53     private final Rect mInsets = new Rect();
54 
55     @IntDef(flag = true, value = {
56             HIDDEN_NON_ZERO_ROTATION,
57             HIDDEN_NO_TASKS,
58             HIDDEN_NO_RECENTS})
59     @Retention(RetentionPolicy.SOURCE)
60     public @interface ActionsHiddenFlags { }
61 
62     public static final int HIDDEN_NON_ZERO_ROTATION = 1 << 0;
63     public static final int HIDDEN_NO_TASKS = 1 << 1;
64     public static final int HIDDEN_NO_RECENTS = 1 << 2;
65 
66     @IntDef(flag = true, value = {
67             DISABLED_SCROLLING,
68             DISABLED_ROTATED,
69             DISABLED_NO_THUMBNAIL})
70     @Retention(RetentionPolicy.SOURCE)
71     public @interface ActionsDisabledFlags { }
72 
73     public static final int DISABLED_SCROLLING = 1 << 0;
74     public static final int DISABLED_ROTATED = 1 << 1;
75     public static final int DISABLED_NO_THUMBNAIL = 1 << 2;
76 
77     private static final int INDEX_CONTENT_ALPHA = 0;
78     private static final int INDEX_VISIBILITY_ALPHA = 1;
79     private static final int INDEX_FULLSCREEN_ALPHA = 2;
80     private static final int INDEX_HIDDEN_FLAGS_ALPHA = 3;
81     private static final int INDEX_SCROLL_ALPHA = 4;
82 
83     private final MultiValueAlpha mMultiValueAlpha;
84 
85     @ActionsHiddenFlags
86     private int mHiddenFlags;
87 
88     @ActionsDisabledFlags
89     protected int mDisabledFlags;
90 
91     protected T mCallbacks;
92 
93     private float mModalness;
94     private float mModalTransformY;
95 
96     protected DeviceProfile mDp;
97 
OverviewActionsView(Context context)98     public OverviewActionsView(Context context) {
99         this(context, null);
100     }
101 
OverviewActionsView(Context context, @Nullable AttributeSet attrs)102     public OverviewActionsView(Context context, @Nullable AttributeSet attrs) {
103         this(context, attrs, 0);
104     }
105 
OverviewActionsView(Context context, @Nullable AttributeSet attrs, int defStyleAttr)106     public OverviewActionsView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
107         super(context, attrs, defStyleAttr, 0);
108         mMultiValueAlpha = new MultiValueAlpha(this, 5);
109         mMultiValueAlpha.setUpdateVisibility(true);
110     }
111 
112     @Override
onFinishInflate()113     protected void onFinishInflate() {
114         super.onFinishInflate();
115         View share = findViewById(R.id.action_share);
116         share.setOnClickListener(this);
117         findViewById(R.id.action_screenshot).setOnClickListener(this);
118         if (ENABLE_OVERVIEW_SHARE.get()) {
119             share.setVisibility(VISIBLE);
120             findViewById(R.id.oav_three_button_space).setVisibility(VISIBLE);
121         }
122     }
123 
124     /**
125      * Set listener for callbacks on action button taps.
126      *
127      * @param callbacks for callbacks, or {@code null} to clear the listener.
128      */
setCallbacks(T callbacks)129     public void setCallbacks(T callbacks) {
130         mCallbacks = callbacks;
131     }
132 
133     @Override
onClick(View view)134     public void onClick(View view) {
135         if (mCallbacks == null) {
136             return;
137         }
138         int id = view.getId();
139         if (id == R.id.action_share) {
140             mCallbacks.onShare();
141         } else if (id == R.id.action_screenshot) {
142             mCallbacks.onScreenshot();
143         }
144     }
145 
146     @Override
onConfigurationChanged(Configuration newConfig)147     protected void onConfigurationChanged(Configuration newConfig) {
148         super.onConfigurationChanged(newConfig);
149         updateVerticalMargin(SysUINavigationMode.getMode(getContext()));
150     }
151 
152     @Override
setInsets(Rect insets)153     public void setInsets(Rect insets) {
154         mInsets.set(insets);
155         updateVerticalMargin(SysUINavigationMode.getMode(getContext()));
156         updateHorizontalPadding();
157     }
158 
updateHiddenFlags(@ctionsHiddenFlags int visibilityFlags, boolean enable)159     public void updateHiddenFlags(@ActionsHiddenFlags int visibilityFlags, boolean enable) {
160         if (enable) {
161             mHiddenFlags |= visibilityFlags;
162         } else {
163             mHiddenFlags &= ~visibilityFlags;
164         }
165         boolean isHidden = mHiddenFlags != 0;
166         mMultiValueAlpha.getProperty(INDEX_HIDDEN_FLAGS_ALPHA).setValue(isHidden ? 0 : 1);
167     }
168 
169     /**
170      * Updates the proper disabled flag to indicate whether OverviewActionsView should be enabled.
171      * Ignores DISABLED_ROTATED flag for determining enabled. Flag is used to enable/disable
172      * buttons individually, currently done for select button in subclass.
173      *
174      * @param disabledFlags The flag to update.
175      * @param enable        Whether to enable the disable flag: True will cause view to be disabled.
176      */
updateDisabledFlags(@ctionsDisabledFlags int disabledFlags, boolean enable)177     public void updateDisabledFlags(@ActionsDisabledFlags int disabledFlags, boolean enable) {
178         if (enable) {
179             mDisabledFlags |= disabledFlags;
180         } else {
181             mDisabledFlags &= ~disabledFlags;
182         }
183         //
184         boolean isEnabled = (mDisabledFlags & ~DISABLED_ROTATED) == 0;
185         LayoutUtils.setViewEnabled(this, isEnabled);
186     }
187 
getContentAlpha()188     public AlphaProperty getContentAlpha() {
189         return mMultiValueAlpha.getProperty(INDEX_CONTENT_ALPHA);
190     }
191 
getVisibilityAlpha()192     public AlphaProperty getVisibilityAlpha() {
193         return mMultiValueAlpha.getProperty(INDEX_VISIBILITY_ALPHA);
194     }
195 
getFullscreenAlpha()196     public AlphaProperty getFullscreenAlpha() {
197         return mMultiValueAlpha.getProperty(INDEX_FULLSCREEN_ALPHA);
198     }
199 
getScrollAlpha()200     public AlphaProperty getScrollAlpha() {
201         return mMultiValueAlpha.getProperty(INDEX_SCROLL_ALPHA);
202     }
203 
updateHorizontalPadding()204     private void updateHorizontalPadding() {
205         setPadding(mInsets.left, 0, mInsets.right, 0);
206     }
207 
208     /** Updates vertical margins for different navigation mode or configuration changes. */
updateVerticalMargin(Mode mode)209     public void updateVerticalMargin(Mode mode) {
210         if (mDp == null) {
211             return;
212         }
213         LayoutParams actionParams = (LayoutParams) findViewById(
214                 R.id.action_buttons).getLayoutParams();
215         actionParams.setMargins(
216                 actionParams.leftMargin, getOverviewActionsTopMarginPx(mode, mDp),
217                 actionParams.rightMargin, getOverviewActionsBottomMarginPx(mode, mDp));
218     }
219 
220     /**
221      * Set the device profile for this view to draw with.
222      */
setDp(DeviceProfile dp)223     public void setDp(DeviceProfile dp) {
224         mDp = dp;
225         updateVerticalMargin(SysUINavigationMode.getMode(getContext()));
226         requestLayout();
227     }
228 
229     /**
230      * The current task is fully modal (modalness = 1) when it is shown on its own in a modal
231      * way. Modalness 0 means the task is shown in context with all the other tasks.
232      */
setTaskModalness(float modalness)233     public void setTaskModalness(float modalness) {
234         mModalness = modalness;
235         applyTranslationY();
236     }
237 
setModalTransformY(float modalTransformY)238     public void setModalTransformY(float modalTransformY) {
239         mModalTransformY = modalTransformY;
240         applyTranslationY();
241     }
242 
applyTranslationY()243     private void applyTranslationY() {
244         setTranslationY(getModalTrans(mModalTransformY));
245     }
246 
getModalTrans(float endTranslation)247     private float getModalTrans(float endTranslation) {
248         float progress = ACCEL_DEACCEL.getInterpolation(mModalness);
249         return Utilities.mapRange(progress, 0, endTranslation);
250     }
251 
252     /** Get the top margin associated with the action buttons in Overview. */
getOverviewActionsTopMarginPx( SysUINavigationMode.Mode mode, DeviceProfile dp)253     public static int getOverviewActionsTopMarginPx(
254             SysUINavigationMode.Mode mode, DeviceProfile dp) {
255         // In vertical bar, use the smaller task margin for the top regardless of mode
256         if (dp.isVerticalBarLayout()) {
257             return dp.overviewTaskMarginPx;
258         }
259 
260         if (mode == SysUINavigationMode.Mode.THREE_BUTTONS) {
261             return dp.overviewActionsMarginThreeButtonPx;
262         }
263 
264         return dp.overviewActionsMarginGesturePx;
265     }
266 
267     /** Get the bottom margin associated with the action buttons in Overview. */
getOverviewActionsBottomMarginPx( SysUINavigationMode.Mode mode, DeviceProfile dp)268     public static int getOverviewActionsBottomMarginPx(
269             SysUINavigationMode.Mode mode, DeviceProfile dp) {
270         int inset = dp.getInsets().bottom;
271 
272         if (dp.isVerticalBarLayout()) {
273             return inset;
274         }
275 
276         if (mode == SysUINavigationMode.Mode.THREE_BUTTONS) {
277             return dp.overviewActionsMarginThreeButtonPx + inset;
278         }
279 
280         return dp.overviewActionsMarginGesturePx + inset;
281     }
282 }
283