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
15package com.android.systemui.statusbar.phone;
16
17import static com.android.systemui.Interpolators.ALPHA_IN;
18import static com.android.systemui.Interpolators.ALPHA_OUT;
19
20import android.animation.Animator;
21import android.animation.AnimatorListenerAdapter;
22import android.animation.ValueAnimator;
23import android.view.View;
24
25import android.view.View.AccessibilityDelegate;
26import com.android.systemui.plugins.statusbar.phone.NavBarButtonProvider.ButtonInterface;
27import com.android.systemui.statusbar.policy.KeyButtonDrawable;
28
29import 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 */
35public class ButtonDispatcher {
36    private final static int FADE_DURATION_IN = 150;
37    private final static int FADE_DURATION_OUT = 100;
38
39    private final ArrayList<View> mViews = new ArrayList<>();
40
41    private final int mId;
42
43    private View.OnClickListener mClickListener;
44    private View.OnTouchListener mTouchListener;
45    private View.OnLongClickListener mLongClickListener;
46    private View.OnHoverListener mOnHoverListener;
47    private Boolean mLongClickable;
48    private Float mAlpha;
49    private Float mDarkIntensity;
50    private Integer mVisibility = -1;
51    private Boolean mDelayTouchFeedback;
52    private KeyButtonDrawable mImageDrawable;
53    private View mCurrentView;
54    private boolean mVertical;
55    private ValueAnimator mFadeAnimator;
56    private AccessibilityDelegate mAccessibilityDelegate;
57
58    private final ValueAnimator.AnimatorUpdateListener mAlphaListener = animation ->
59            setAlpha((float) animation.getAnimatedValue());
60
61    private final AnimatorListenerAdapter mFadeListener = new AnimatorListenerAdapter() {
62        @Override
63        public void onAnimationEnd(Animator animation) {
64            setVisibility(getAlpha() == 1 ? View.VISIBLE : View.INVISIBLE);
65        }
66    };
67
68    public ButtonDispatcher(int id) {
69        mId = id;
70    }
71
72    void clear() {
73        mViews.clear();
74    }
75
76    void addView(View view) {
77        mViews.add(view);
78        view.setOnClickListener(mClickListener);
79        view.setOnTouchListener(mTouchListener);
80        view.setOnLongClickListener(mLongClickListener);
81        view.setOnHoverListener(mOnHoverListener);
82        if (mLongClickable != null) {
83            view.setLongClickable(mLongClickable);
84        }
85        if (mAlpha != null) {
86            view.setAlpha(mAlpha);
87        }
88        if (mVisibility != null && mVisibility != -1) {
89            view.setVisibility(mVisibility);
90        }
91        if (mAccessibilityDelegate != null) {
92            view.setAccessibilityDelegate(mAccessibilityDelegate);
93        }
94        if (view instanceof ButtonInterface) {
95            final ButtonInterface button = (ButtonInterface) view;
96            if (mDarkIntensity != null) {
97                button.setDarkIntensity(mDarkIntensity);
98            }
99            if (mImageDrawable != null) {
100                button.setImageDrawable(mImageDrawable);
101            }
102            if (mDelayTouchFeedback != null) {
103                button.setDelayTouchFeedback(mDelayTouchFeedback);
104            }
105            button.setVertical(mVertical);
106        }
107    }
108
109    public int getId() {
110        return mId;
111    }
112
113    public int getVisibility() {
114        return mVisibility != null ? mVisibility : View.VISIBLE;
115    }
116
117    public boolean isVisible() {
118        return getVisibility() == View.VISIBLE;
119    }
120
121    public float getAlpha() {
122        return mAlpha != null ? mAlpha : 1;
123    }
124
125    public KeyButtonDrawable getImageDrawable() {
126        return mImageDrawable;
127    }
128
129    public void setImageDrawable(KeyButtonDrawable drawable) {
130        mImageDrawable = drawable;
131        final int N = mViews.size();
132        for (int i = 0; i < N; i++) {
133            if (mViews.get(i) instanceof ButtonInterface) {
134                ((ButtonInterface) mViews.get(i)).setImageDrawable(mImageDrawable);
135            }
136        }
137    }
138
139    public void setVisibility(int visibility) {
140        if (mVisibility == visibility) return;
141        mVisibility = visibility;
142        final int N = mViews.size();
143        for (int i = 0; i < N; i++) {
144            mViews.get(i).setVisibility(mVisibility);
145        }
146    }
147
148    public void abortCurrentGesture() {
149        // This seems to be an instantaneous thing, so not going to persist it.
150        final int N = mViews.size();
151        for (int i = 0; i < N; i++) {
152            if (mViews.get(i) instanceof ButtonInterface) {
153                ((ButtonInterface) mViews.get(i)).abortCurrentGesture();
154            }
155        }
156    }
157
158    public void setAlpha(float alpha) {
159        setAlpha(alpha, false /* animate */);
160    }
161
162    public void setAlpha(float alpha, boolean animate) {
163        if (animate) {
164            if (mFadeAnimator != null) {
165                mFadeAnimator.cancel();
166            }
167            mFadeAnimator = ValueAnimator.ofFloat(getAlpha(), alpha);
168            mFadeAnimator.setDuration(getAlpha() < alpha? FADE_DURATION_IN : FADE_DURATION_OUT);
169            mFadeAnimator.setInterpolator(getAlpha() < alpha ? ALPHA_IN : ALPHA_OUT);
170            mFadeAnimator.addListener(mFadeListener);
171            mFadeAnimator.addUpdateListener(mAlphaListener);
172            mFadeAnimator.start();
173            setVisibility(View.VISIBLE);
174        } else {
175            mAlpha = alpha;
176            final int N = mViews.size();
177            for (int i = 0; i < N; i++) {
178                mViews.get(i).setAlpha(alpha);
179            }
180        }
181    }
182
183    public void setDarkIntensity(float darkIntensity) {
184        mDarkIntensity = darkIntensity;
185        final int N = mViews.size();
186        for (int i = 0; i < N; i++) {
187            if (mViews.get(i) instanceof ButtonInterface) {
188                ((ButtonInterface) mViews.get(i)).setDarkIntensity(darkIntensity);
189            }
190        }
191    }
192
193    public void setDelayTouchFeedback(boolean delay) {
194        mDelayTouchFeedback = delay;
195        final int N = mViews.size();
196        for (int i = 0; i < N; i++) {
197            if (mViews.get(i) instanceof ButtonInterface) {
198                ((ButtonInterface) mViews.get(i)).setDelayTouchFeedback(delay);
199            }
200        }
201    }
202
203    public void setOnClickListener(View.OnClickListener clickListener) {
204        mClickListener = clickListener;
205        final int N = mViews.size();
206        for (int i = 0; i < N; i++) {
207            mViews.get(i).setOnClickListener(mClickListener);
208        }
209    }
210
211    public void setOnTouchListener(View.OnTouchListener touchListener) {
212        mTouchListener = touchListener;
213        final int N = mViews.size();
214        for (int i = 0; i < N; i++) {
215            mViews.get(i).setOnTouchListener(mTouchListener);
216        }
217    }
218
219    public void setLongClickable(boolean isLongClickable) {
220        mLongClickable = isLongClickable;
221        final int N = mViews.size();
222        for (int i = 0; i < N; i++) {
223            mViews.get(i).setLongClickable(mLongClickable);
224        }
225    }
226
227    public void setOnLongClickListener(View.OnLongClickListener longClickListener) {
228        mLongClickListener = longClickListener;
229        final int N = mViews.size();
230        for (int i = 0; i < N; i++) {
231            mViews.get(i).setOnLongClickListener(mLongClickListener);
232        }
233    }
234
235    public void setOnHoverListener(View.OnHoverListener hoverListener) {
236        mOnHoverListener = hoverListener;
237        final int N = mViews.size();
238        for (int i = 0; i < N; i++) {
239            mViews.get(i).setOnHoverListener(mOnHoverListener);
240        }
241    }
242
243    public void setAccessibilityDelegate(AccessibilityDelegate delegate) {
244        mAccessibilityDelegate = delegate;
245        final int N = mViews.size();
246        for (int i = 0; i < N; i++) {
247            mViews.get(i).setAccessibilityDelegate(delegate);
248        }
249    }
250
251    public void setClickable(boolean clickable) {
252        abortCurrentGesture();
253        final int N = mViews.size();
254        for (int i = 0; i < N; i++) {
255            mViews.get(i).setClickable(clickable);
256        }
257    }
258
259    public ArrayList<View> getViews() {
260        return mViews;
261    }
262
263    public View getCurrentView() {
264        return mCurrentView;
265    }
266
267    public void setCurrentView(View currentView) {
268        mCurrentView = currentView.findViewById(mId);
269    }
270
271    public void setVertical(boolean vertical) {
272        mVertical = vertical;
273        final int N = mViews.size();
274        for (int i = 0; i < N; i++) {
275            final View view = mViews.get(i);
276            if (view instanceof ButtonInterface) {
277                ((ButtonInterface) view).setVertical(vertical);
278            }
279        }
280    }
281}
282