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