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