1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5  * except in compliance with the License. You may obtain a copy of the License at
6  *
7  *      http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software distributed under the
10  * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
11  * KIND, either express or implied. See the License for the specific language governing
12  * permissions and limitations under the License.
13  */
14 
15 package com.android.systemui.statusbar.phone;
16 
17 import static com.android.systemui.Interpolators.LINEAR;
18 
19 import android.animation.Animator;
20 import android.animation.AnimatorListenerAdapter;
21 import android.animation.ValueAnimator;
22 import android.view.View;
23 import android.view.View.AccessibilityDelegate;
24 
25 import com.android.systemui.Dependency;
26 import com.android.systemui.assist.AssistManager;
27 import com.android.systemui.statusbar.policy.KeyButtonDrawable;
28 
29 import java.util.ArrayList;
30 
31 /**
32  * Dispatches common view calls to multiple views.  This is used to handle
33  * multiples of the same nav bar icon appearing.
34  */
35 public class ButtonDispatcher {
36     private static final int FADE_DURATION_IN = 150;
37     private static final int FADE_DURATION_OUT = 250;
38 
39     private final ArrayList<View> mViews = new ArrayList<>();
40 
41     private final int mId;
42     private final AssistManager mAssistManager;
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         mAssistManager = Dependency.get(AssistManager.class);
76     }
77 
clear()78     void clear() {
79         mViews.clear();
80     }
81 
addView(View view)82     void addView(View view) {
83         mViews.add(view);
84         view.setOnClickListener(mClickListener);
85         view.setOnTouchListener(mTouchListener);
86         view.setOnLongClickListener(mLongClickListener);
87         view.setOnHoverListener(mOnHoverListener);
88         if (mLongClickable != null) {
89             view.setLongClickable(mLongClickable);
90         }
91         if (mAlpha != null) {
92             view.setAlpha(mAlpha);
93         }
94         if (mVisibility != null) {
95             view.setVisibility(mVisibility);
96         }
97         if (mAccessibilityDelegate != null) {
98             view.setAccessibilityDelegate(mAccessibilityDelegate);
99         }
100         if (view instanceof ButtonInterface) {
101             final ButtonInterface button = (ButtonInterface) view;
102             if (mDarkIntensity != null) {
103                 button.setDarkIntensity(mDarkIntensity);
104             }
105             if (mImageDrawable != null) {
106                 button.setImageDrawable(mImageDrawable);
107             }
108             if (mDelayTouchFeedback != null) {
109                 button.setDelayTouchFeedback(mDelayTouchFeedback);
110             }
111             button.setVertical(mVertical);
112         }
113     }
114 
getId()115     public int getId() {
116         return mId;
117     }
118 
getVisibility()119     public int getVisibility() {
120         return mVisibility != null ? mVisibility : View.VISIBLE;
121     }
122 
isVisible()123     public boolean isVisible() {
124         return getVisibility() == View.VISIBLE;
125     }
126 
getAlpha()127     public float getAlpha() {
128         return mAlpha != null ? mAlpha : 1;
129     }
130 
getImageDrawable()131     public KeyButtonDrawable getImageDrawable() {
132         return mImageDrawable;
133     }
134 
setImageDrawable(KeyButtonDrawable drawable)135     public void setImageDrawable(KeyButtonDrawable drawable) {
136         mImageDrawable = drawable;
137         final int N = mViews.size();
138         for (int i = 0; i < N; i++) {
139             if (mViews.get(i) instanceof ButtonInterface) {
140                 ((ButtonInterface) mViews.get(i)).setImageDrawable(mImageDrawable);
141             }
142         }
143         if (mImageDrawable != null) {
144             mImageDrawable.setCallback(mCurrentView);
145         }
146     }
147 
setVisibility(int visibility)148     public void setVisibility(int visibility) {
149         if (mVisibility == visibility) return;
150         if (mFadeAnimator != null) {
151             mFadeAnimator.cancel();
152         }
153 
154         mVisibility = visibility;
155         final int N = mViews.size();
156         for (int i = 0; i < N; i++) {
157             mViews.get(i).setVisibility(mVisibility);
158         }
159     }
160 
abortCurrentGesture()161     public void abortCurrentGesture() {
162         // This seems to be an instantaneous thing, so not going to persist it.
163         final int N = mViews.size();
164         for (int i = 0; i < N; i++) {
165             if (mViews.get(i) instanceof ButtonInterface) {
166                 ((ButtonInterface) mViews.get(i)).abortCurrentGesture();
167             }
168         }
169     }
170 
setAlpha(float alpha)171     public void setAlpha(float alpha) {
172         setAlpha(alpha, false /* animate */);
173     }
174 
setAlpha(float alpha, boolean animate)175     public void setAlpha(float alpha, boolean animate) {
176         setAlpha(alpha, animate, true /* cancelAnimator */);
177     }
178 
setAlpha(float alpha, boolean animate, long duration)179     public void setAlpha(float alpha, boolean animate, long duration) {
180         setAlpha(alpha, animate, duration, true /* cancelAnimator */);
181     }
182 
setAlpha(float alpha, boolean animate, boolean cancelAnimator)183     public void setAlpha(float alpha, boolean animate, boolean cancelAnimator) {
184         setAlpha(
185                 alpha,
186                 animate,
187                 (getAlpha() < alpha) ? FADE_DURATION_IN : FADE_DURATION_OUT,
188                 cancelAnimator);
189     }
190 
setAlpha(float alpha, boolean animate, long duration, boolean cancelAnimator)191     public void setAlpha(float alpha, boolean animate, long duration, boolean cancelAnimator) {
192         if (mFadeAnimator != null && (cancelAnimator || animate)) {
193             mFadeAnimator.cancel();
194         }
195         if (animate) {
196             setVisibility(View.VISIBLE);
197             mFadeAnimator = ValueAnimator.ofFloat(getAlpha(), alpha);
198             mFadeAnimator.setStartDelay(
199                     mAssistManager.getAssistHandleShowAndGoRemainingDurationMs());
200             mFadeAnimator.setDuration(duration);
201             mFadeAnimator.setInterpolator(LINEAR);
202             mFadeAnimator.addListener(mFadeListener);
203             mFadeAnimator.addUpdateListener(mAlphaListener);
204             mFadeAnimator.start();
205         } else {
206             mAlpha = alpha;
207             final int N = mViews.size();
208             for (int i = 0; i < N; i++) {
209                 mViews.get(i).setAlpha(alpha);
210             }
211         }
212     }
213 
setDarkIntensity(float darkIntensity)214     public void setDarkIntensity(float darkIntensity) {
215         mDarkIntensity = darkIntensity;
216         final int N = mViews.size();
217         for (int i = 0; i < N; i++) {
218             if (mViews.get(i) instanceof ButtonInterface) {
219                 ((ButtonInterface) mViews.get(i)).setDarkIntensity(darkIntensity);
220             }
221         }
222     }
223 
setDelayTouchFeedback(boolean delay)224     public void setDelayTouchFeedback(boolean delay) {
225         mDelayTouchFeedback = delay;
226         final int N = mViews.size();
227         for (int i = 0; i < N; i++) {
228             if (mViews.get(i) instanceof ButtonInterface) {
229                 ((ButtonInterface) mViews.get(i)).setDelayTouchFeedback(delay);
230             }
231         }
232     }
233 
setOnClickListener(View.OnClickListener clickListener)234     public void setOnClickListener(View.OnClickListener clickListener) {
235         mClickListener = clickListener;
236         final int N = mViews.size();
237         for (int i = 0; i < N; i++) {
238             mViews.get(i).setOnClickListener(mClickListener);
239         }
240     }
241 
setOnTouchListener(View.OnTouchListener touchListener)242     public void setOnTouchListener(View.OnTouchListener touchListener) {
243         mTouchListener = touchListener;
244         final int N = mViews.size();
245         for (int i = 0; i < N; i++) {
246             mViews.get(i).setOnTouchListener(mTouchListener);
247         }
248     }
249 
setLongClickable(boolean isLongClickable)250     public void setLongClickable(boolean isLongClickable) {
251         mLongClickable = isLongClickable;
252         final int N = mViews.size();
253         for (int i = 0; i < N; i++) {
254             mViews.get(i).setLongClickable(mLongClickable);
255         }
256     }
257 
setOnLongClickListener(View.OnLongClickListener longClickListener)258     public void setOnLongClickListener(View.OnLongClickListener longClickListener) {
259         mLongClickListener = longClickListener;
260         final int N = mViews.size();
261         for (int i = 0; i < N; i++) {
262             mViews.get(i).setOnLongClickListener(mLongClickListener);
263         }
264     }
265 
setOnHoverListener(View.OnHoverListener hoverListener)266     public void setOnHoverListener(View.OnHoverListener hoverListener) {
267         mOnHoverListener = hoverListener;
268         final int N = mViews.size();
269         for (int i = 0; i < N; i++) {
270             mViews.get(i).setOnHoverListener(mOnHoverListener);
271         }
272     }
273 
setAccessibilityDelegate(AccessibilityDelegate delegate)274     public void setAccessibilityDelegate(AccessibilityDelegate delegate) {
275         mAccessibilityDelegate = delegate;
276         final int N = mViews.size();
277         for (int i = 0; i < N; i++) {
278             mViews.get(i).setAccessibilityDelegate(delegate);
279         }
280     }
281 
setClickable(boolean clickable)282     public void setClickable(boolean clickable) {
283         abortCurrentGesture();
284         final int N = mViews.size();
285         for (int i = 0; i < N; i++) {
286             mViews.get(i).setClickable(clickable);
287         }
288     }
289 
setTranslation(int x, int y, int z)290     public void setTranslation(int x, int y, int z) {
291         final int N = mViews.size();
292         for (int i = 0; i < N; i++) {
293             final View view = mViews.get(i);
294             view.setTranslationX(x);
295             view.setTranslationY(y);
296             view.setTranslationZ(z);
297         }
298     }
299 
getViews()300     public ArrayList<View> getViews() {
301         return mViews;
302     }
303 
getCurrentView()304     public View getCurrentView() {
305         return mCurrentView;
306     }
307 
setCurrentView(View currentView)308     public void setCurrentView(View currentView) {
309         mCurrentView = currentView.findViewById(mId);
310         if (mImageDrawable != null) {
311             mImageDrawable.setCallback(mCurrentView);
312         }
313         if (mCurrentView != null) {
314             mCurrentView.setTranslationX(0);
315             mCurrentView.setTranslationY(0);
316             mCurrentView.setTranslationZ(0);
317         }
318     }
319 
setVertical(boolean vertical)320     public void setVertical(boolean vertical) {
321         mVertical = vertical;
322         final int N = mViews.size();
323         for (int i = 0; i < N; i++) {
324             final View view = mViews.get(i);
325             if (view instanceof ButtonInterface) {
326                 ((ButtonInterface) view).setVertical(vertical);
327             }
328         }
329     }
330 
331     /**
332      * Executes when button is detached from window.
333      */
onDestroy()334     protected void onDestroy() {
335     }
336 }
337