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.config.FeatureFlags.ENABLE_OVERVIEW_ACTIONS;
20 import static com.android.launcher3.config.FeatureFlags.ENABLE_OVERVIEW_SHARE;
21 import static com.android.quickstep.SysUINavigationMode.removeShelfFromOverview;
22 
23 import android.content.Context;
24 import android.content.res.Configuration;
25 import android.graphics.Rect;
26 import android.util.AttributeSet;
27 import android.view.View;
28 import android.view.View.OnClickListener;
29 import android.widget.FrameLayout;
30 
31 import androidx.annotation.IntDef;
32 import androidx.annotation.Nullable;
33 
34 import com.android.launcher3.Insettable;
35 import com.android.launcher3.R;
36 import com.android.launcher3.util.MultiValueAlpha;
37 import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
38 import com.android.quickstep.SysUINavigationMode;
39 import com.android.quickstep.SysUINavigationMode.Mode;
40 import com.android.quickstep.TaskOverlayFactory.OverlayUICallbacks;
41 import com.android.quickstep.util.LayoutUtils;
42 
43 import java.lang.annotation.Retention;
44 import java.lang.annotation.RetentionPolicy;
45 
46 /**
47  * View for showing action buttons in Overview
48  */
49 public class OverviewActionsView<T extends OverlayUICallbacks> extends FrameLayout
50         implements OnClickListener, Insettable {
51 
52     private final Rect mInsets = new Rect();
53 
54     @IntDef(flag = true, value = {
55             HIDDEN_UNSUPPORTED_NAVIGATION,
56             HIDDEN_DISABLED_FEATURE,
57             HIDDEN_NON_ZERO_ROTATION,
58             HIDDEN_NO_TASKS,
59             HIDDEN_GESTURE_RUNNING,
60             HIDDEN_NO_RECENTS})
61     @Retention(RetentionPolicy.SOURCE)
62     public @interface ActionsHiddenFlags { }
63 
64     public static final int HIDDEN_UNSUPPORTED_NAVIGATION = 1 << 0;
65     public static final int HIDDEN_DISABLED_FEATURE = 1 << 1;
66     public static final int HIDDEN_NON_ZERO_ROTATION = 1 << 2;
67     public static final int HIDDEN_NO_TASKS = 1 << 3;
68     public static final int HIDDEN_GESTURE_RUNNING = 1 << 4;
69     public static final int HIDDEN_NO_RECENTS = 1 << 5;
70 
71     @IntDef(flag = true, value = {
72             DISABLED_SCROLLING,
73             DISABLED_ROTATED})
74     @Retention(RetentionPolicy.SOURCE)
75     public @interface ActionsDisabledFlags { }
76 
77     public static final int DISABLED_SCROLLING = 1 << 0;
78     public static final int DISABLED_ROTATED = 1 << 1;
79 
80     private static final int INDEX_CONTENT_ALPHA = 0;
81     private static final int INDEX_VISIBILITY_ALPHA = 1;
82     private static final int INDEX_FULLSCREEN_ALPHA = 2;
83     private static final int INDEX_HIDDEN_FLAGS_ALPHA = 3;
84 
85     private final MultiValueAlpha mMultiValueAlpha;
86 
87     @ActionsHiddenFlags
88     private int mHiddenFlags;
89 
90     @ActionsDisabledFlags
91     protected int mDisabledFlags;
92 
93     protected T mCallbacks;
94 
OverviewActionsView(Context context)95     public OverviewActionsView(Context context) {
96         this(context, null);
97     }
98 
OverviewActionsView(Context context, @Nullable AttributeSet attrs)99     public OverviewActionsView(Context context, @Nullable AttributeSet attrs) {
100         this(context, attrs, 0);
101     }
102 
OverviewActionsView(Context context, @Nullable AttributeSet attrs, int defStyleAttr)103     public OverviewActionsView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
104         super(context, attrs, defStyleAttr, 0);
105         mMultiValueAlpha = new MultiValueAlpha(this, 4);
106     }
107 
108     @Override
onFinishInflate()109     protected void onFinishInflate() {
110         super.onFinishInflate();
111         View share = findViewById(R.id.action_share);
112         share.setOnClickListener(this);
113         findViewById(R.id.action_screenshot).setOnClickListener(this);
114         if (ENABLE_OVERVIEW_SHARE.get()) {
115             share.setVisibility(VISIBLE);
116             findViewById(R.id.share_space).setVisibility(VISIBLE);
117         }
118     }
119 
120     /**
121      * Set listener for callbacks on action button taps.
122      *
123      * @param callbacks for callbacks, or {@code null} to clear the listener.
124      */
setCallbacks(T callbacks)125     public void setCallbacks(T callbacks) {
126         mCallbacks = callbacks;
127     }
128 
129     @Override
onClick(View view)130     public void onClick(View view) {
131         if (mCallbacks == null) {
132             return;
133         }
134         int id = view.getId();
135         if (id == R.id.action_share) {
136             mCallbacks.onShare();
137         } else if (id == R.id.action_screenshot) {
138             mCallbacks.onScreenshot();
139         }
140     }
141 
142     @Override
onAttachedToWindow()143     protected void onAttachedToWindow() {
144         super.onAttachedToWindow();
145         updateHiddenFlags(HIDDEN_DISABLED_FEATURE, !ENABLE_OVERVIEW_ACTIONS.get());
146         updateHiddenFlags(HIDDEN_UNSUPPORTED_NAVIGATION, !removeShelfFromOverview(getContext()));
147     }
148 
149     @Override
onConfigurationChanged(Configuration newConfig)150     protected void onConfigurationChanged(Configuration newConfig) {
151         super.onConfigurationChanged(newConfig);
152         updateVerticalMargin(SysUINavigationMode.getMode(getContext()));
153     }
154 
155     @Override
setInsets(Rect insets)156     public void setInsets(Rect insets) {
157         mInsets.set(insets);
158         updateVerticalMargin(SysUINavigationMode.getMode(getContext()));
159     }
160 
updateHiddenFlags(@ctionsHiddenFlags int visibilityFlags, boolean enable)161     public void updateHiddenFlags(@ActionsHiddenFlags int visibilityFlags, boolean enable) {
162         if (enable) {
163             mHiddenFlags |= visibilityFlags;
164         } else {
165             mHiddenFlags &= ~visibilityFlags;
166         }
167         boolean isHidden = mHiddenFlags != 0;
168         mMultiValueAlpha.getProperty(INDEX_HIDDEN_FLAGS_ALPHA).setValue(isHidden ? 0 : 1);
169         setVisibility(isHidden ? INVISIBLE : VISIBLE);
170     }
171 
172     /**
173      * Updates the proper disabled flag to indicate whether OverviewActionsView should be enabled.
174      * Ignores DISABLED_ROTATED flag for determining enabled. Flag is used to enable/disable
175      * buttons individually, currently done for select button in subclass.
176      *
177      * @param disabledFlags The flag to update.
178      * @param enable        Whether to enable the disable flag: True will cause view to be disabled.
179      */
updateDisabledFlags(@ctionsDisabledFlags int disabledFlags, boolean enable)180     public void updateDisabledFlags(@ActionsDisabledFlags int disabledFlags, boolean enable) {
181         if (enable) {
182             mDisabledFlags |= disabledFlags;
183         } else {
184             mDisabledFlags &= ~disabledFlags;
185         }
186         //
187         boolean isEnabled = (mDisabledFlags & ~DISABLED_ROTATED) == 0;
188         LayoutUtils.setViewEnabled(this, isEnabled);
189     }
190 
getContentAlpha()191     public AlphaProperty getContentAlpha() {
192         return mMultiValueAlpha.getProperty(INDEX_CONTENT_ALPHA);
193     }
194 
getVisibilityAlpha()195     public AlphaProperty getVisibilityAlpha() {
196         return mMultiValueAlpha.getProperty(INDEX_VISIBILITY_ALPHA);
197     }
198 
getFullscreenAlpha()199     public AlphaProperty getFullscreenAlpha() {
200         return mMultiValueAlpha.getProperty(INDEX_FULLSCREEN_ALPHA);
201     }
202 
203     /** Updates vertical margins for different navigation mode or configuration changes. */
updateVerticalMargin(Mode mode)204     public void updateVerticalMargin(Mode mode) {
205         int bottomMargin;
206         int orientation = getResources().getConfiguration().orientation;
207         if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
208             bottomMargin = 0;
209         } else if (mode == Mode.THREE_BUTTONS) {
210             bottomMargin = getResources()
211                     .getDimensionPixelSize(R.dimen.overview_actions_bottom_margin_three_button);
212         } else {
213             bottomMargin = getResources()
214                     .getDimensionPixelSize(R.dimen.overview_actions_bottom_margin_gesture);
215         }
216         bottomMargin += mInsets.bottom;
217         LayoutParams params = (LayoutParams) getLayoutParams();
218         params.setMargins(
219                 params.leftMargin, params.topMargin, params.rightMargin, bottomMargin);
220     }
221 }
222