| /* |
| * Copyright (C) 2014 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.systemui.recents.utilities; |
| |
| import android.animation.Animator; |
| import android.animation.AnimatorSet; |
| import android.animation.RectEvaluator; |
| import android.annotation.FloatRange; |
| import android.annotation.Nullable; |
| import android.app.Activity; |
| import android.content.Context; |
| import android.content.res.Configuration; |
| import android.content.res.Resources; |
| import android.graphics.Color; |
| import android.graphics.Rect; |
| import android.graphics.RectF; |
| import android.graphics.drawable.Drawable; |
| import android.os.Handler; |
| import android.os.Message; |
| import android.os.Trace; |
| import android.util.ArraySet; |
| import android.util.IntProperty; |
| import android.util.Property; |
| import android.util.TypedValue; |
| import android.view.Surface; |
| import android.view.View; |
| import android.view.ViewGroup; |
| import android.view.ViewParent; |
| import android.view.ViewRootImpl; |
| import android.view.ViewStub; |
| |
| import com.android.systemui.shared.recents.utilities.RectFEvaluator; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| |
| /* Common code */ |
| public class Utilities { |
| |
| public static final Property<Drawable, Integer> DRAWABLE_ALPHA = |
| new IntProperty<Drawable>("drawableAlpha") { |
| @Override |
| public void setValue(Drawable object, int alpha) { |
| object.setAlpha(alpha); |
| } |
| |
| @Override |
| public Integer get(Drawable object) { |
| return object.getAlpha(); |
| } |
| }; |
| |
| public static final Property<Drawable, Rect> DRAWABLE_RECT = |
| new Property<Drawable, Rect>(Rect.class, "drawableBounds") { |
| @Override |
| public void set(Drawable object, Rect bounds) { |
| object.setBounds(bounds); |
| } |
| |
| @Override |
| public Rect get(Drawable object) { |
| return object.getBounds(); |
| } |
| }; |
| |
| public static final RectFEvaluator RECTF_EVALUATOR = new RectFEvaluator(); |
| public static final RectEvaluator RECT_EVALUATOR = new RectEvaluator(new Rect()); |
| |
| /** |
| * @return the first parent walking up the view hierarchy that has the given class type. |
| * |
| * @param parentClass must be a class derived from {@link View} |
| */ |
| public static <T extends View> T findParent(View v, Class<T> parentClass) { |
| ViewParent parent = v.getParent(); |
| while (parent != null) { |
| if (parentClass.isAssignableFrom(parent.getClass())) { |
| return (T) parent; |
| } |
| parent = parent.getParent(); |
| } |
| return null; |
| } |
| |
| /** |
| * Initializes the {@param setOut} with the given object. |
| */ |
| public static <T> ArraySet<T> objectToSet(T obj, ArraySet<T> setOut) { |
| setOut.clear(); |
| if (obj != null) { |
| setOut.add(obj); |
| } |
| return setOut; |
| } |
| |
| /** |
| * Replaces the contents of {@param setOut} with the contents of the {@param array}. |
| */ |
| public static <T> ArraySet<T> arrayToSet(T[] array, ArraySet<T> setOut) { |
| setOut.clear(); |
| if (array != null) { |
| Collections.addAll(setOut, array); |
| } |
| return setOut; |
| } |
| |
| /** |
| * @return the clamped {@param value} between the provided {@param min} and {@param max}. |
| */ |
| public static int clamp(int value, int min, int max) { |
| return Math.max(min, Math.min(max, value)); |
| } |
| |
| /** |
| * @return the clamped {@param value} between 0 and 1. |
| */ |
| public static float clamp01(float value) { |
| return Math.max(0f, Math.min(1f, value)); |
| } |
| |
| /** |
| * Scales the {@param value} to be proportionally between the {@param min} and |
| * {@param max} values. |
| * |
| * @param value must be between 0 and 1 |
| */ |
| public static float mapRange(@FloatRange(from=0.0,to=1.0) float value, float min, float max) { |
| return min + (value * (max - min)); |
| } |
| |
| /** |
| * Scales the {@param value} proportionally from {@param min} and {@param max} to 0 and 1. |
| * |
| * @param value must be between {@param min} and {@param max} |
| */ |
| public static float unmapRange(float value, float min, float max) { |
| return (value - min) / (max - min); |
| } |
| |
| /** Scales a rect about its centroid */ |
| public static void scaleRectAboutCenter(RectF r, float scale) { |
| if (scale != 1.0f) { |
| float cx = r.centerX(); |
| float cy = r.centerY(); |
| r.offset(-cx, -cy); |
| r.left *= scale; |
| r.top *= scale; |
| r.right *= scale; |
| r.bottom *= scale; |
| r.offset(cx, cy); |
| } |
| } |
| |
| /** Returns the base color overlaid with another overlay color with a specified alpha. */ |
| public static int getColorWithOverlay(int baseColor, int overlayColor, float overlayAlpha) { |
| return Color.rgb( |
| (int) (overlayAlpha * Color.red(baseColor) + |
| (1f - overlayAlpha) * Color.red(overlayColor)), |
| (int) (overlayAlpha * Color.green(baseColor) + |
| (1f - overlayAlpha) * Color.green(overlayColor)), |
| (int) (overlayAlpha * Color.blue(baseColor) + |
| (1f - overlayAlpha) * Color.blue(overlayColor))); |
| } |
| |
| /** |
| * Cancels an animation ensuring that if it has listeners, onCancel and onEnd |
| * are not called. |
| */ |
| public static void cancelAnimationWithoutCallbacks(Animator animator) { |
| if (animator != null && animator.isStarted()) { |
| removeAnimationListenersRecursive(animator); |
| animator.cancel(); |
| } |
| } |
| |
| /** |
| * Recursively removes all the listeners of all children of this animator |
| */ |
| public static void removeAnimationListenersRecursive(Animator animator) { |
| if (animator instanceof AnimatorSet) { |
| ArrayList<Animator> animators = ((AnimatorSet) animator).getChildAnimations(); |
| for (int i = animators.size() - 1; i >= 0; i--) { |
| removeAnimationListenersRecursive(animators.get(i)); |
| } |
| } |
| animator.removeAllListeners(); |
| } |
| |
| /** |
| * Sets the given {@link View}'s frame from its current translation. |
| */ |
| public static void setViewFrameFromTranslation(View v) { |
| RectF taskViewRect = new RectF(v.getLeft(), v.getTop(), v.getRight(), v.getBottom()); |
| taskViewRect.offset(v.getTranslationX(), v.getTranslationY()); |
| v.setTranslationX(0); |
| v.setTranslationY(0); |
| v.setLeftTopRightBottom((int) taskViewRect.left, (int) taskViewRect.top, |
| (int) taskViewRect.right, (int) taskViewRect.bottom); |
| } |
| |
| /** |
| * Returns a view stub for the given view id. |
| */ |
| public static ViewStub findViewStubById(View v, int stubId) { |
| return (ViewStub) v.findViewById(stubId); |
| } |
| |
| /** |
| * Returns a view stub for the given view id. |
| */ |
| public static ViewStub findViewStubById(Activity a, int stubId) { |
| return (ViewStub) a.findViewById(stubId); |
| } |
| |
| /** |
| * Used for debugging, converts DP to PX. |
| */ |
| public static float dpToPx(Resources res, float dp) { |
| return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, res.getDisplayMetrics()); |
| } |
| |
| /** |
| * Adds a trace event for debugging. |
| */ |
| public static void addTraceEvent(String event) { |
| Trace.traceBegin(Trace.TRACE_TAG_VIEW, event); |
| Trace.traceEnd(Trace.TRACE_TAG_VIEW); |
| } |
| |
| /** |
| * Returns whether this view, or one of its descendants have accessibility focus. |
| */ |
| public static boolean isDescendentAccessibilityFocused(View v) { |
| if (v.isAccessibilityFocused()) { |
| return true; |
| } |
| |
| if (v instanceof ViewGroup) { |
| ViewGroup vg = (ViewGroup) v; |
| int childCount = vg.getChildCount(); |
| for (int i = 0; i < childCount; i++) { |
| if (isDescendentAccessibilityFocused(vg.getChildAt(i))) { |
| return true; |
| } |
| } |
| } |
| return false; |
| } |
| |
| /** |
| * Returns the application configuration, which is independent of the activity's current |
| * configuration in multiwindow. |
| */ |
| public static Configuration getAppConfiguration(Context context) { |
| return context.getApplicationContext().getResources().getConfiguration(); |
| } |
| |
| /** |
| * @return The next frame name for the specified surface or -1 if the surface is no longer |
| * valid. |
| */ |
| public static long getNextFrameNumber(Surface s) { |
| return s != null && s.isValid() |
| ? s.getNextFrameNumber() |
| : -1; |
| |
| } |
| |
| /** |
| * @return The surface for the specified view. |
| */ |
| public static @Nullable Surface getSurface(View v) { |
| ViewRootImpl viewRoot = v.getViewRootImpl(); |
| if (viewRoot == null) { |
| return null; |
| } |
| return viewRoot.mSurface; |
| } |
| |
| /** |
| * Returns a lightweight dump of a rect. |
| */ |
| public static String dumpRect(Rect r) { |
| if (r == null) { |
| return "N:0,0-0,0"; |
| } |
| return r.left + "," + r.top + "-" + r.right + "," + r.bottom; |
| } |
| |
| /** |
| * Posts a runnable on a handler at the front of the queue ignoring any sync barriers. |
| */ |
| public static void postAtFrontOfQueueAsynchronously(Handler h, Runnable r) { |
| Message msg = h.obtainMessage().setCallback(r); |
| h.sendMessageAtFrontOfQueue(msg); |
| } |
| |
| /** Calculates the constrast between two colors, using the algorithm provided by the WCAG v2. */ |
| public static float computeContrastBetweenColors(int bg, int fg) { |
| float bgR = Color.red(bg) / 255f; |
| float bgG = Color.green(bg) / 255f; |
| float bgB = Color.blue(bg) / 255f; |
| bgR = (bgR < 0.03928f) ? bgR / 12.92f : (float) Math.pow((bgR + 0.055f) / 1.055f, 2.4f); |
| bgG = (bgG < 0.03928f) ? bgG / 12.92f : (float) Math.pow((bgG + 0.055f) / 1.055f, 2.4f); |
| bgB = (bgB < 0.03928f) ? bgB / 12.92f : (float) Math.pow((bgB + 0.055f) / 1.055f, 2.4f); |
| float bgL = 0.2126f * bgR + 0.7152f * bgG + 0.0722f * bgB; |
| |
| float fgR = Color.red(fg) / 255f; |
| float fgG = Color.green(fg) / 255f; |
| float fgB = Color.blue(fg) / 255f; |
| fgR = (fgR < 0.03928f) ? fgR / 12.92f : (float) Math.pow((fgR + 0.055f) / 1.055f, 2.4f); |
| fgG = (fgG < 0.03928f) ? fgG / 12.92f : (float) Math.pow((fgG + 0.055f) / 1.055f, 2.4f); |
| fgB = (fgB < 0.03928f) ? fgB / 12.92f : (float) Math.pow((fgB + 0.055f) / 1.055f, 2.4f); |
| float fgL = 0.2126f * fgR + 0.7152f * fgG + 0.0722f * fgB; |
| |
| return Math.abs((fgL + 0.05f) / (bgL + 0.05f)); |
| } |
| |
| /** |
| * @return the clamped {@param value} between the provided {@param min} and {@param max}. |
| */ |
| public static float clamp(float value, float min, float max) { |
| return Math.max(min, Math.min(max, value)); |
| } |
| |
| } |