Home | History | Annotate | Download | only in misc
      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.misc;
     18 
     19 import android.content.Intent;
     20 import android.graphics.Color;
     21 import android.graphics.Matrix;
     22 import android.graphics.Rect;
     23 import android.view.View;
     24 import com.android.systemui.recents.RecentsConfiguration;
     25 
     26 import java.lang.reflect.InvocationTargetException;
     27 import java.lang.reflect.Method;
     28 import java.util.ArrayList;
     29 
     30 /* Common code */
     31 public class Utilities {
     32 
     33     // Reflection methods for altering shadows
     34     private static Method sPropertyMethod;
     35     static {
     36         try {
     37             Class<?> c = Class.forName("android.view.GLES20Canvas");
     38             sPropertyMethod = c.getDeclaredMethod("setProperty", String.class, String.class);
     39             if (!sPropertyMethod.isAccessible()) sPropertyMethod.setAccessible(true);
     40         } catch (ClassNotFoundException e) {
     41             e.printStackTrace();
     42         } catch (NoSuchMethodException e) {
     43             e.printStackTrace();
     44         }
     45     }
     46 
     47     /**
     48      * Calculates a consistent animation duration (ms) for all animations depending on the movement
     49      * of the object being animated.
     50      */
     51     public static int calculateTranslationAnimationDuration(int distancePx) {
     52         return calculateTranslationAnimationDuration(distancePx, 100);
     53     }
     54     public static int calculateTranslationAnimationDuration(int distancePx, int minDuration) {
     55         RecentsConfiguration config = RecentsConfiguration.getInstance();
     56         return Math.max(minDuration, (int) (1000f /* ms/s */ *
     57                 (Math.abs(distancePx) / config.animationPxMovementPerSecond)));
     58     }
     59 
     60     /** Scales a rect about its centroid */
     61     public static void scaleRectAboutCenter(Rect r, float scale) {
     62         if (scale != 1.0f) {
     63             int cx = r.centerX();
     64             int cy = r.centerY();
     65             r.offset(-cx, -cy);
     66             r.left = (int) (r.left * scale + 0.5f);
     67             r.top = (int) (r.top * scale + 0.5f);
     68             r.right = (int) (r.right * scale + 0.5f);
     69             r.bottom = (int) (r.bottom * scale + 0.5f);
     70             r.offset(cx, cy);
     71         }
     72     }
     73 
     74     /** Maps a coorindate in a descendant view into the parent. */
     75     public static float mapCoordInDescendentToSelf(View descendant, View root,
     76             float[] coord, boolean includeRootScroll) {
     77         ArrayList<View> ancestorChain = new ArrayList<View>();
     78 
     79         float[] pt = {coord[0], coord[1]};
     80 
     81         View v = descendant;
     82         while(v != root && v != null) {
     83             ancestorChain.add(v);
     84             v = (View) v.getParent();
     85         }
     86         ancestorChain.add(root);
     87 
     88         float scale = 1.0f;
     89         int count = ancestorChain.size();
     90         for (int i = 0; i < count; i++) {
     91             View v0 = ancestorChain.get(i);
     92             // For TextViews, scroll has a meaning which relates to the text position
     93             // which is very strange... ignore the scroll.
     94             if (v0 != descendant || includeRootScroll) {
     95                 pt[0] -= v0.getScrollX();
     96                 pt[1] -= v0.getScrollY();
     97             }
     98 
     99             v0.getMatrix().mapPoints(pt);
    100             pt[0] += v0.getLeft();
    101             pt[1] += v0.getTop();
    102             scale *= v0.getScaleX();
    103         }
    104 
    105         coord[0] = pt[0];
    106         coord[1] = pt[1];
    107         return scale;
    108     }
    109 
    110     /** Maps a coordinate in the root to a descendent. */
    111     public static float mapCoordInSelfToDescendent(View descendant, View root,
    112             float[] coord, Matrix tmpInverseMatrix) {
    113         ArrayList<View> ancestorChain = new ArrayList<View>();
    114 
    115         float[] pt = {coord[0], coord[1]};
    116 
    117         View v = descendant;
    118         while(v != root) {
    119             ancestorChain.add(v);
    120             v = (View) v.getParent();
    121         }
    122         ancestorChain.add(root);
    123 
    124         float scale = 1.0f;
    125         int count = ancestorChain.size();
    126         tmpInverseMatrix.set(Matrix.IDENTITY_MATRIX);
    127         for (int i = count - 1; i >= 0; i--) {
    128             View ancestor = ancestorChain.get(i);
    129             View next = i > 0 ? ancestorChain.get(i-1) : null;
    130 
    131             pt[0] += ancestor.getScrollX();
    132             pt[1] += ancestor.getScrollY();
    133 
    134             if (next != null) {
    135                 pt[0] -= next.getLeft();
    136                 pt[1] -= next.getTop();
    137                 next.getMatrix().invert(tmpInverseMatrix);
    138                 tmpInverseMatrix.mapPoints(pt);
    139                 scale *= next.getScaleX();
    140             }
    141         }
    142 
    143         coord[0] = pt[0];
    144         coord[1] = pt[1];
    145         return scale;
    146     }
    147 
    148     /** Calculates the constrast between two colors, using the algorithm provided by the WCAG v2. */
    149     public static float computeContrastBetweenColors(int bg, int fg) {
    150         float bgR = Color.red(bg) / 255f;
    151         float bgG = Color.green(bg) / 255f;
    152         float bgB = Color.blue(bg) / 255f;
    153         bgR = (bgR < 0.03928f) ? bgR / 12.92f : (float) Math.pow((bgR + 0.055f) / 1.055f, 2.4f);
    154         bgG = (bgG < 0.03928f) ? bgG / 12.92f : (float) Math.pow((bgG + 0.055f) / 1.055f, 2.4f);
    155         bgB = (bgB < 0.03928f) ? bgB / 12.92f : (float) Math.pow((bgB + 0.055f) / 1.055f, 2.4f);
    156         float bgL = 0.2126f * bgR + 0.7152f * bgG + 0.0722f * bgB;
    157 
    158         float fgR = Color.red(fg) / 255f;
    159         float fgG = Color.green(fg) / 255f;
    160         float fgB = Color.blue(fg) / 255f;
    161         fgR = (fgR < 0.03928f) ? fgR / 12.92f : (float) Math.pow((fgR + 0.055f) / 1.055f, 2.4f);
    162         fgG = (fgG < 0.03928f) ? fgG / 12.92f : (float) Math.pow((fgG + 0.055f) / 1.055f, 2.4f);
    163         fgB = (fgB < 0.03928f) ? fgB / 12.92f : (float) Math.pow((fgB + 0.055f) / 1.055f, 2.4f);
    164         float fgL = 0.2126f * fgR + 0.7152f * fgG + 0.0722f * fgB;
    165 
    166         return Math.abs((fgL + 0.05f) / (bgL + 0.05f));
    167     }
    168 
    169     /** Returns the base color overlaid with another overlay color with a specified alpha. */
    170     public static int getColorWithOverlay(int baseColor, int overlayColor, float overlayAlpha) {
    171         return Color.rgb(
    172             (int) (overlayAlpha * Color.red(baseColor) +
    173                     (1f - overlayAlpha) * Color.red(overlayColor)),
    174             (int) (overlayAlpha * Color.green(baseColor) +
    175                     (1f - overlayAlpha) * Color.green(overlayColor)),
    176             (int) (overlayAlpha * Color.blue(baseColor) +
    177                     (1f - overlayAlpha) * Color.blue(overlayColor)));
    178     }
    179 
    180     /** Sets some private shadow properties. */
    181     public static void setShadowProperty(String property, String value)
    182             throws IllegalAccessException, InvocationTargetException {
    183         sPropertyMethod.invoke(null, property, value);
    184     }
    185 
    186     /** Returns whether the specified intent is a document. */
    187     public static boolean isDocument(Intent intent) {
    188         int flags = intent.getFlags();
    189         return (flags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) == Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
    190     }
    191 }
    192