• 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.systemui.navigationbar.buttons;
18 
19 import static com.android.systemui.animation.Interpolators.LINEAR;
20 
21 import android.animation.Animator;
22 import android.animation.AnimatorListenerAdapter;
23 import android.animation.ValueAnimator;
24 import android.view.View;
25 import android.view.View.AccessibilityDelegate;
26 
27 import com.android.systemui.Dependency;
28 import com.android.systemui.assist.AssistManager;
29 
30 import java.util.ArrayList;
31 
32 /**
33  * Dispatches common view calls to multiple views.  This is used to handle
34  * multiples of the same nav bar icon appearing.
35  */
36 public class ButtonDispatcher {
37     private static final int FADE_DURATION_IN = 150;
38     private static final int FADE_DURATION_OUT = 250;
39 
40     private final ArrayList<View> mViews = new ArrayList<>();
41 
42     private final int mId;
43 
44     private View.OnClickListener mClickListener;
45     private View.OnTouchListener mTouchListener;
46     private View.OnLongClickListener mLongClickListener;
47     private View.OnHoverListener mOnHoverListener;
48     private Boolean mLongClickable;
49     private Float mAlpha;
50     private Float mDarkIntensity;
51     private Integer mVisibility = View.VISIBLE;
52     private Boolean mDelayTouchFeedback;
53     private KeyButtonDrawable mImageDrawable;
54     private View mCurrentView;
55     private boolean mVertical;
56     private ValueAnimator mFadeAnimator;
57     private AccessibilityDelegate mAccessibilityDelegate;
58 
59     private final ValueAnimator.AnimatorUpdateListener mAlphaListener = animation ->
60             setAlpha(
61                     (float) animation.getAnimatedValue(),
62                     false /* animate */,
63                     false /* cancelAnimator */);
64 
65     private final AnimatorListenerAdapter mFadeListener = new AnimatorListenerAdapter() {
66         @Override
67         public void onAnimationEnd(Animator animation) {
68             mFadeAnimator = null;
69             setVisibility(getAlpha() == 1 ? View.VISIBLE : View.INVISIBLE);
70         }
71     };
72 
ButtonDispatcher(int id)73     public ButtonDispatcher(int id) {
74         mId = id;
75     }
76 
clear()77     public void clear() {
78         mViews.clear();
79     }
80 
addView(View view)81     public void addView(View view) {
82         mViews.add(view);
83         view.setOnClickListener(mClickListener);
84         view.setOnTouchListener(mTouchListener);
85         view.setOnLongClickListener(mLongClickListener);
86         view.setOnHoverListener(mOnHoverListener);
87         if (mLongClickable != null) {
88             view.setLongClickable(mLongClickable);
89         }
90         if (mAlpha != null) {
91             view.setAlpha(mAlpha);
92         }
93         if (mVisibility != null) {
94             view.setVisibility(mVisibility);
95         }
96         if (mAccessibilityDelegate != null) {
97             view.setAccessibilityDelegate(mAccessibilityDelegate);
98         }
99         if (view instanceof ButtonInterface) {
100             final ButtonInterface button = (ButtonInterface) view;
101             if (mDarkIntensity != null) {
102                 button.setDarkIntensity(mDarkIntensity);
103             }
104             if (mImageDrawable != null) {
105                 button.setImageDrawable(mImageDrawable);
106             }
107             if (mDelayTouchFeedback != null) {
108                 button.setDelayTouchFeedback(mDelayTouchFeedback);
109             }
110             button.setVertical(mVertical);
111         }
112     }
113 
getId()114     public int getId() {
115         return mId;
116     }
117 
getVisibility()118     public int getVisibility() {
119         return mVisibility != null ? mVisibility : View.VISIBLE;
120     }
121 
isVisible()122     public boolean isVisible() {
123         return getVisibility() == View.VISIBLE;
124     }
125 
getAlpha()126     public float getAlpha() {
127         return mAlpha != null ? mAlpha : 1;
128     }
129 
getImageDrawable()130     public KeyButtonDrawable getImageDrawable() {
131         return mImageDrawable;
132     }
133 
setImageDrawable(KeyButtonDrawable drawable)134     public void setImageDrawable(KeyButtonDrawable drawable) {
135         mImageDrawable = drawable;
136         final int N = mViews.size();
137         for (int i = 0; i < N; i++) {
138             if (mViews.get(i) instanceof ButtonInterface) {
139                 ((ButtonInterface) mViews.get(i)).setImageDrawable(mImageDrawable);
140             }
141         }
142         if (mImageDrawable != null) {
143             mImageDrawable.setCallback(mCurrentView);
144         }
145     }
146 
setVisibility(int visibility)147     public void setVisibility(int visibility) {
148         if (mVisibility == visibility) return;
149         if (mFadeAnimator != null) {
150             mFadeAnimator.cancel();
151         }
152 
153         mVisibility = visibility;
154         final int N = mViews.size();
155         for (int i = 0; i < N; i++) {
156             mViews.get(i).setVisibility(mVisibility);
157         }
158     }
159 
abortCurrentGesture()160     public void abortCurrentGesture() {
161         // This seems to be an instantaneous thing, so not going to persist it.
162         final int N = mViews.size();
163         for (int i = 0; i < N; i++) {
164             if (mViews.get(i) instanceof ButtonInterface) {
165                 ((ButtonInterface) mViews.get(i)).abortCurrentGesture();
166             }
167         }
168     }
169 
setAlpha(float alpha)170     public void setAlpha(float alpha) {
171         setAlpha(alpha, false /* animate */);
172     }
173 
setAlpha(float alpha, boolean animate)174     public void setAlpha(float alpha, boolean animate) {
175         setAlpha(alpha, animate, true /* cancelAnimator */);
176     }
177 
setAlpha(float alpha, boolean animate, long duration)178     public void setAlpha(float alpha, boolean animate, long duration) {
179         setAlpha(alpha, animate, duration, true /* cancelAnimator */);
180     }
181 
setAlpha(float alpha, boolean animate, boolean cancelAnimator)182     public void setAlpha(float alpha, boolean animate, boolean cancelAnimator) {
183         setAlpha(
184                 alpha,
185                 animate,
186                 (getAlpha() < alpha) ? FADE_DURATION_IN : FADE_DURATION_OUT,
187                 cancelAnimator);
188     }
189 
setAlpha(float alpha, boolean animate, long duration, boolean cancelAnimator)190     public void setAlpha(float alpha, boolean animate, long duration, boolean cancelAnimator) {
191         if (mFadeAnimator != null && (cancelAnimator || animate)) {
192             mFadeAnimator.cancel();
193         }
194         if (animate) {
195             setVisibility(View.VISIBLE);
196             mFadeAnimator = ValueAnimator.ofFloat(getAlpha(), alpha);
197             mFadeAnimator.setDuration(duration);
198             mFadeAnimator.setInterpolator(LINEAR);
199             mFadeAnimator.addListener(mFadeListener);
200             mFadeAnimator.addUpdateListener(mAlphaListener);
201             mFadeAnimator.start();
202         } else {
203             // Discretize the alpha updates to prevent too frequent updates when there is a long
204             // alpha animation
205             int prevAlpha = (int) (getAlpha() * 255);
206             int nextAlpha = (int) (alpha * 255);
207             if (prevAlpha != nextAlpha) {
208                 mAlpha = nextAlpha / 255f;
209                 final int N = mViews.size();
210                 for (int i = 0; i < N; i++) {
211                     mViews.get(i).setAlpha(mAlpha);
212                 }
213             }
214         }
215     }
216 
setDarkIntensity(float darkIntensity)217     public void setDarkIntensity(float darkIntensity) {
218         mDarkIntensity = darkIntensity;
219         final int N = mViews.size();
220         for (int i = 0; i < N; i++) {
221             if (mViews.get(i) instanceof ButtonInterface) {
222                 ((ButtonInterface) mViews.get(i)).setDarkIntensity(darkIntensity);
223             }
224         }
225     }
226 
setDelayTouchFeedback(boolean delay)227     public void setDelayTouchFeedback(boolean delay) {
228         mDelayTouchFeedback = delay;
229         final int N = mViews.size();
230         for (int i = 0; i < N; i++) {
231             if (mViews.get(i) instanceof ButtonInterface) {
232                 ((ButtonInterface) mViews.get(i)).setDelayTouchFeedback(delay);
233             }
234         }
235     }
236 
setOnClickListener(View.OnClickListener clickListener)237     public void setOnClickListener(View.OnClickListener clickListener) {
238         mClickListener = clickListener;
239         final int N = mViews.size();
240         for (int i = 0; i < N; i++) {
241             mViews.get(i).setOnClickListener(mClickListener);
242         }
243     }
244 
setOnTouchListener(View.OnTouchListener touchListener)245     public void setOnTouchListener(View.OnTouchListener touchListener) {
246         mTouchListener = touchListener;
247         final int N = mViews.size();
248         for (int i = 0; i < N; i++) {
249             mViews.get(i).setOnTouchListener(mTouchListener);
250         }
251     }
252 
setLongClickable(boolean isLongClickable)253     public void setLongClickable(boolean isLongClickable) {
254         mLongClickable = isLongClickable;
255         final int N = mViews.size();
256         for (int i = 0; i < N; i++) {
257             mViews.get(i).setLongClickable(mLongClickable);
258         }
259     }
260 
setOnLongClickListener(View.OnLongClickListener longClickListener)261     public void setOnLongClickListener(View.OnLongClickListener longClickListener) {
262         mLongClickListener = longClickListener;
263         final int N = mViews.size();
264         for (int i = 0; i < N; i++) {
265             mViews.get(i).setOnLongClickListener(mLongClickListener);
266         }
267     }
268 
setOnHoverListener(View.OnHoverListener hoverListener)269     public void setOnHoverListener(View.OnHoverListener hoverListener) {
270         mOnHoverListener = hoverListener;
271         final int N = mViews.size();
272         for (int i = 0; i < N; i++) {
273             mViews.get(i).setOnHoverListener(mOnHoverListener);
274         }
275     }
276 
setAccessibilityDelegate(AccessibilityDelegate delegate)277     public void setAccessibilityDelegate(AccessibilityDelegate delegate) {
278         mAccessibilityDelegate = delegate;
279         final int N = mViews.size();
280         for (int i = 0; i < N; i++) {
281             mViews.get(i).setAccessibilityDelegate(delegate);
282         }
283     }
284 
setClickable(boolean clickable)285     public void setClickable(boolean clickable) {
286         abortCurrentGesture();
287         final int N = mViews.size();
288         for (int i = 0; i < N; i++) {
289             mViews.get(i).setClickable(clickable);
290         }
291     }
292 
setTranslation(int x, int y, int z)293     public void setTranslation(int x, int y, int z) {
294         final int N = mViews.size();
295         for (int i = 0; i < N; i++) {
296             final View view = mViews.get(i);
297             view.setTranslationX(x);
298             view.setTranslationY(y);
299             view.setTranslationZ(z);
300         }
301     }
302 
getViews()303     public ArrayList<View> getViews() {
304         return mViews;
305     }
306 
getCurrentView()307     public View getCurrentView() {
308         return mCurrentView;
309     }
310 
setCurrentView(View currentView)311     public void setCurrentView(View currentView) {
312         mCurrentView = currentView.findViewById(mId);
313         if (mImageDrawable != null) {
314             mImageDrawable.setCallback(mCurrentView);
315         }
316         if (mCurrentView != null) {
317             mCurrentView.setTranslationX(0);
318             mCurrentView.setTranslationY(0);
319             mCurrentView.setTranslationZ(0);
320         }
321     }
322 
setVertical(boolean vertical)323     public void setVertical(boolean vertical) {
324         mVertical = vertical;
325         final int N = mViews.size();
326         for (int i = 0; i < N; i++) {
327             final View view = mViews.get(i);
328             if (view instanceof ButtonInterface) {
329                 ((ButtonInterface) view).setVertical(vertical);
330             }
331         }
332     }
333 
334     /**
335      * Executes when button is detached from window.
336      */
onDestroy()337     public void onDestroy() {
338     }
339 }
340