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