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 // Discretize the alpha updates to prevent too frequent updates when there is a long 207 // alpha animation 208 int prevAlpha = (int) (getAlpha() * 255); 209 int nextAlpha = (int) (alpha * 255); 210 if (prevAlpha != nextAlpha) { 211 mAlpha = nextAlpha / 255f; 212 final int N = mViews.size(); 213 for (int i = 0; i < N; i++) { 214 mViews.get(i).setAlpha(mAlpha); 215 } 216 } 217 } 218 } 219 setDarkIntensity(float darkIntensity)220 public void setDarkIntensity(float darkIntensity) { 221 mDarkIntensity = darkIntensity; 222 final int N = mViews.size(); 223 for (int i = 0; i < N; i++) { 224 if (mViews.get(i) instanceof ButtonInterface) { 225 ((ButtonInterface) mViews.get(i)).setDarkIntensity(darkIntensity); 226 } 227 } 228 } 229 setDelayTouchFeedback(boolean delay)230 public void setDelayTouchFeedback(boolean delay) { 231 mDelayTouchFeedback = delay; 232 final int N = mViews.size(); 233 for (int i = 0; i < N; i++) { 234 if (mViews.get(i) instanceof ButtonInterface) { 235 ((ButtonInterface) mViews.get(i)).setDelayTouchFeedback(delay); 236 } 237 } 238 } 239 setOnClickListener(View.OnClickListener clickListener)240 public void setOnClickListener(View.OnClickListener clickListener) { 241 mClickListener = clickListener; 242 final int N = mViews.size(); 243 for (int i = 0; i < N; i++) { 244 mViews.get(i).setOnClickListener(mClickListener); 245 } 246 } 247 setOnTouchListener(View.OnTouchListener touchListener)248 public void setOnTouchListener(View.OnTouchListener touchListener) { 249 mTouchListener = touchListener; 250 final int N = mViews.size(); 251 for (int i = 0; i < N; i++) { 252 mViews.get(i).setOnTouchListener(mTouchListener); 253 } 254 } 255 setLongClickable(boolean isLongClickable)256 public void setLongClickable(boolean isLongClickable) { 257 mLongClickable = isLongClickable; 258 final int N = mViews.size(); 259 for (int i = 0; i < N; i++) { 260 mViews.get(i).setLongClickable(mLongClickable); 261 } 262 } 263 setOnLongClickListener(View.OnLongClickListener longClickListener)264 public void setOnLongClickListener(View.OnLongClickListener longClickListener) { 265 mLongClickListener = longClickListener; 266 final int N = mViews.size(); 267 for (int i = 0; i < N; i++) { 268 mViews.get(i).setOnLongClickListener(mLongClickListener); 269 } 270 } 271 setOnHoverListener(View.OnHoverListener hoverListener)272 public void setOnHoverListener(View.OnHoverListener hoverListener) { 273 mOnHoverListener = hoverListener; 274 final int N = mViews.size(); 275 for (int i = 0; i < N; i++) { 276 mViews.get(i).setOnHoverListener(mOnHoverListener); 277 } 278 } 279 setAccessibilityDelegate(AccessibilityDelegate delegate)280 public void setAccessibilityDelegate(AccessibilityDelegate delegate) { 281 mAccessibilityDelegate = delegate; 282 final int N = mViews.size(); 283 for (int i = 0; i < N; i++) { 284 mViews.get(i).setAccessibilityDelegate(delegate); 285 } 286 } 287 setClickable(boolean clickable)288 public void setClickable(boolean clickable) { 289 abortCurrentGesture(); 290 final int N = mViews.size(); 291 for (int i = 0; i < N; i++) { 292 mViews.get(i).setClickable(clickable); 293 } 294 } 295 setTranslation(int x, int y, int z)296 public void setTranslation(int x, int y, int z) { 297 final int N = mViews.size(); 298 for (int i = 0; i < N; i++) { 299 final View view = mViews.get(i); 300 view.setTranslationX(x); 301 view.setTranslationY(y); 302 view.setTranslationZ(z); 303 } 304 } 305 getViews()306 public ArrayList<View> getViews() { 307 return mViews; 308 } 309 getCurrentView()310 public View getCurrentView() { 311 return mCurrentView; 312 } 313 setCurrentView(View currentView)314 public void setCurrentView(View currentView) { 315 mCurrentView = currentView.findViewById(mId); 316 if (mImageDrawable != null) { 317 mImageDrawable.setCallback(mCurrentView); 318 } 319 if (mCurrentView != null) { 320 mCurrentView.setTranslationX(0); 321 mCurrentView.setTranslationY(0); 322 mCurrentView.setTranslationZ(0); 323 } 324 } 325 setVertical(boolean vertical)326 public void setVertical(boolean vertical) { 327 mVertical = vertical; 328 final int N = mViews.size(); 329 for (int i = 0; i < N; i++) { 330 final View view = mViews.get(i); 331 if (view instanceof ButtonInterface) { 332 ((ButtonInterface) view).setVertical(vertical); 333 } 334 } 335 } 336 337 /** 338 * Executes when button is detached from window. 339 */ onDestroy()340 protected void onDestroy() { 341 } 342 } 343