1 /* 2 * Copyright (C) 2014 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.recents.utilities; 18 19 import android.animation.Animator; 20 import android.animation.AnimatorSet; 21 import android.animation.RectEvaluator; 22 import android.annotation.FloatRange; 23 import android.annotation.Nullable; 24 import android.app.Activity; 25 import android.content.Context; 26 import android.content.res.Configuration; 27 import android.content.res.Resources; 28 import android.graphics.Color; 29 import android.graphics.Rect; 30 import android.graphics.RectF; 31 import android.graphics.drawable.Drawable; 32 import android.os.Handler; 33 import android.os.Message; 34 import android.os.Trace; 35 import android.util.ArraySet; 36 import android.util.IntProperty; 37 import android.util.Property; 38 import android.util.TypedValue; 39 import android.view.Surface; 40 import android.view.View; 41 import android.view.ViewGroup; 42 import android.view.ViewParent; 43 import android.view.ViewRootImpl; 44 import android.view.ViewStub; 45 46 import com.android.systemui.shared.recents.utilities.RectFEvaluator; 47 import java.util.ArrayList; 48 import java.util.Collections; 49 50 /* Common code */ 51 public class Utilities { 52 53 public static final Property<Drawable, Integer> DRAWABLE_ALPHA = 54 new IntProperty<Drawable>("drawableAlpha") { 55 @Override 56 public void setValue(Drawable object, int alpha) { 57 object.setAlpha(alpha); 58 } 59 60 @Override 61 public Integer get(Drawable object) { 62 return object.getAlpha(); 63 } 64 }; 65 66 public static final Property<Drawable, Rect> DRAWABLE_RECT = 67 new Property<Drawable, Rect>(Rect.class, "drawableBounds") { 68 @Override 69 public void set(Drawable object, Rect bounds) { 70 object.setBounds(bounds); 71 } 72 73 @Override 74 public Rect get(Drawable object) { 75 return object.getBounds(); 76 } 77 }; 78 79 public static final RectFEvaluator RECTF_EVALUATOR = new RectFEvaluator(); 80 public static final RectEvaluator RECT_EVALUATOR = new RectEvaluator(new Rect()); 81 82 /** 83 * @return the first parent walking up the view hierarchy that has the given class type. 84 * 85 * @param parentClass must be a class derived from {@link View} 86 */ findParent(View v, Class<T> parentClass)87 public static <T extends View> T findParent(View v, Class<T> parentClass) { 88 ViewParent parent = v.getParent(); 89 while (parent != null) { 90 if (parentClass.isAssignableFrom(parent.getClass())) { 91 return (T) parent; 92 } 93 parent = parent.getParent(); 94 } 95 return null; 96 } 97 98 /** 99 * Initializes the {@param setOut} with the given object. 100 */ objectToSet(T obj, ArraySet<T> setOut)101 public static <T> ArraySet<T> objectToSet(T obj, ArraySet<T> setOut) { 102 setOut.clear(); 103 if (obj != null) { 104 setOut.add(obj); 105 } 106 return setOut; 107 } 108 109 /** 110 * Replaces the contents of {@param setOut} with the contents of the {@param array}. 111 */ arrayToSet(T[] array, ArraySet<T> setOut)112 public static <T> ArraySet<T> arrayToSet(T[] array, ArraySet<T> setOut) { 113 setOut.clear(); 114 if (array != null) { 115 Collections.addAll(setOut, array); 116 } 117 return setOut; 118 } 119 120 /** 121 * @return the clamped {@param value} between the provided {@param min} and {@param max}. 122 */ clamp(int value, int min, int max)123 public static int clamp(int value, int min, int max) { 124 return Math.max(min, Math.min(max, value)); 125 } 126 127 /** 128 * @return the clamped {@param value} between 0 and 1. 129 */ clamp01(float value)130 public static float clamp01(float value) { 131 return Math.max(0f, Math.min(1f, value)); 132 } 133 134 /** 135 * Scales the {@param value} to be proportionally between the {@param min} and 136 * {@param max} values. 137 * 138 * @param value must be between 0 and 1 139 */ mapRange(@loatRangefrom=0.0,to=1.0) float value, float min, float max)140 public static float mapRange(@FloatRange(from=0.0,to=1.0) float value, float min, float max) { 141 return min + (value * (max - min)); 142 } 143 144 /** 145 * Scales the {@param value} proportionally from {@param min} and {@param max} to 0 and 1. 146 * 147 * @param value must be between {@param min} and {@param max} 148 */ unmapRange(float value, float min, float max)149 public static float unmapRange(float value, float min, float max) { 150 return (value - min) / (max - min); 151 } 152 153 /** Scales a rect about its centroid */ scaleRectAboutCenter(RectF r, float scale)154 public static void scaleRectAboutCenter(RectF r, float scale) { 155 if (scale != 1.0f) { 156 float cx = r.centerX(); 157 float cy = r.centerY(); 158 r.offset(-cx, -cy); 159 r.left *= scale; 160 r.top *= scale; 161 r.right *= scale; 162 r.bottom *= scale; 163 r.offset(cx, cy); 164 } 165 } 166 167 /** Returns the base color overlaid with another overlay color with a specified alpha. */ getColorWithOverlay(int baseColor, int overlayColor, float overlayAlpha)168 public static int getColorWithOverlay(int baseColor, int overlayColor, float overlayAlpha) { 169 return Color.rgb( 170 (int) (overlayAlpha * Color.red(baseColor) + 171 (1f - overlayAlpha) * Color.red(overlayColor)), 172 (int) (overlayAlpha * Color.green(baseColor) + 173 (1f - overlayAlpha) * Color.green(overlayColor)), 174 (int) (overlayAlpha * Color.blue(baseColor) + 175 (1f - overlayAlpha) * Color.blue(overlayColor))); 176 } 177 178 /** 179 * Cancels an animation ensuring that if it has listeners, onCancel and onEnd 180 * are not called. 181 */ cancelAnimationWithoutCallbacks(Animator animator)182 public static void cancelAnimationWithoutCallbacks(Animator animator) { 183 if (animator != null && animator.isStarted()) { 184 removeAnimationListenersRecursive(animator); 185 animator.cancel(); 186 } 187 } 188 189 /** 190 * Recursively removes all the listeners of all children of this animator 191 */ removeAnimationListenersRecursive(Animator animator)192 public static void removeAnimationListenersRecursive(Animator animator) { 193 if (animator instanceof AnimatorSet) { 194 ArrayList<Animator> animators = ((AnimatorSet) animator).getChildAnimations(); 195 for (int i = animators.size() - 1; i >= 0; i--) { 196 removeAnimationListenersRecursive(animators.get(i)); 197 } 198 } 199 animator.removeAllListeners(); 200 } 201 202 /** 203 * Sets the given {@link View}'s frame from its current translation. 204 */ setViewFrameFromTranslation(View v)205 public static void setViewFrameFromTranslation(View v) { 206 RectF taskViewRect = new RectF(v.getLeft(), v.getTop(), v.getRight(), v.getBottom()); 207 taskViewRect.offset(v.getTranslationX(), v.getTranslationY()); 208 v.setTranslationX(0); 209 v.setTranslationY(0); 210 v.setLeftTopRightBottom((int) taskViewRect.left, (int) taskViewRect.top, 211 (int) taskViewRect.right, (int) taskViewRect.bottom); 212 } 213 214 /** 215 * Returns a view stub for the given view id. 216 */ findViewStubById(View v, int stubId)217 public static ViewStub findViewStubById(View v, int stubId) { 218 return (ViewStub) v.findViewById(stubId); 219 } 220 221 /** 222 * Returns a view stub for the given view id. 223 */ findViewStubById(Activity a, int stubId)224 public static ViewStub findViewStubById(Activity a, int stubId) { 225 return (ViewStub) a.findViewById(stubId); 226 } 227 228 /** 229 * Used for debugging, converts DP to PX. 230 */ dpToPx(Resources res, float dp)231 public static float dpToPx(Resources res, float dp) { 232 return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, res.getDisplayMetrics()); 233 } 234 235 /** 236 * Adds a trace event for debugging. 237 */ addTraceEvent(String event)238 public static void addTraceEvent(String event) { 239 Trace.traceBegin(Trace.TRACE_TAG_VIEW, event); 240 Trace.traceEnd(Trace.TRACE_TAG_VIEW); 241 } 242 243 /** 244 * Returns whether this view, or one of its descendants have accessibility focus. 245 */ isDescendentAccessibilityFocused(View v)246 public static boolean isDescendentAccessibilityFocused(View v) { 247 if (v.isAccessibilityFocused()) { 248 return true; 249 } 250 251 if (v instanceof ViewGroup) { 252 ViewGroup vg = (ViewGroup) v; 253 int childCount = vg.getChildCount(); 254 for (int i = 0; i < childCount; i++) { 255 if (isDescendentAccessibilityFocused(vg.getChildAt(i))) { 256 return true; 257 } 258 } 259 } 260 return false; 261 } 262 263 /** 264 * Returns the application configuration, which is independent of the activity's current 265 * configuration in multiwindow. 266 */ getAppConfiguration(Context context)267 public static Configuration getAppConfiguration(Context context) { 268 return context.getApplicationContext().getResources().getConfiguration(); 269 } 270 271 /** 272 * @return The next frame name for the specified surface or -1 if the surface is no longer 273 * valid. 274 */ getNextFrameNumber(Surface s)275 public static long getNextFrameNumber(Surface s) { 276 return s != null && s.isValid() 277 ? s.getNextFrameNumber() 278 : -1; 279 280 } 281 282 /** 283 * @return The surface for the specified view. 284 */ getSurface(View v)285 public static @Nullable Surface getSurface(View v) { 286 ViewRootImpl viewRoot = v.getViewRootImpl(); 287 if (viewRoot == null) { 288 return null; 289 } 290 return viewRoot.mSurface; 291 } 292 293 /** 294 * Returns a lightweight dump of a rect. 295 */ dumpRect(Rect r)296 public static String dumpRect(Rect r) { 297 if (r == null) { 298 return "N:0,0-0,0"; 299 } 300 return r.left + "," + r.top + "-" + r.right + "," + r.bottom; 301 } 302 303 /** 304 * Posts a runnable on a handler at the front of the queue ignoring any sync barriers. 305 */ postAtFrontOfQueueAsynchronously(Handler h, Runnable r)306 public static void postAtFrontOfQueueAsynchronously(Handler h, Runnable r) { 307 Message msg = h.obtainMessage().setCallback(r); 308 h.sendMessageAtFrontOfQueue(msg); 309 } 310 311 /** Calculates the constrast between two colors, using the algorithm provided by the WCAG v2. */ computeContrastBetweenColors(int bg, int fg)312 public static float computeContrastBetweenColors(int bg, int fg) { 313 float bgR = Color.red(bg) / 255f; 314 float bgG = Color.green(bg) / 255f; 315 float bgB = Color.blue(bg) / 255f; 316 bgR = (bgR < 0.03928f) ? bgR / 12.92f : (float) Math.pow((bgR + 0.055f) / 1.055f, 2.4f); 317 bgG = (bgG < 0.03928f) ? bgG / 12.92f : (float) Math.pow((bgG + 0.055f) / 1.055f, 2.4f); 318 bgB = (bgB < 0.03928f) ? bgB / 12.92f : (float) Math.pow((bgB + 0.055f) / 1.055f, 2.4f); 319 float bgL = 0.2126f * bgR + 0.7152f * bgG + 0.0722f * bgB; 320 321 float fgR = Color.red(fg) / 255f; 322 float fgG = Color.green(fg) / 255f; 323 float fgB = Color.blue(fg) / 255f; 324 fgR = (fgR < 0.03928f) ? fgR / 12.92f : (float) Math.pow((fgR + 0.055f) / 1.055f, 2.4f); 325 fgG = (fgG < 0.03928f) ? fgG / 12.92f : (float) Math.pow((fgG + 0.055f) / 1.055f, 2.4f); 326 fgB = (fgB < 0.03928f) ? fgB / 12.92f : (float) Math.pow((fgB + 0.055f) / 1.055f, 2.4f); 327 float fgL = 0.2126f * fgR + 0.7152f * fgG + 0.0722f * fgB; 328 329 return Math.abs((fgL + 0.05f) / (bgL + 0.05f)); 330 } 331 332 /** 333 * @return the clamped {@param value} between the provided {@param min} and {@param max}. 334 */ clamp(float value, float min, float max)335 public static float clamp(float value, float min, float max) { 336 return Math.max(min, Math.min(max, value)); 337 } 338 339 } 340