• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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 static android.app.StatusBarManager.NAVBAR_BACK_DISMISS_IME;
20 import static android.app.StatusBarManager.NAVBAR_IME_SWITCHER_BUTTON_VISIBLE;
21 import static android.app.StatusBarManager.NAVBAR_IME_VISIBLE;
22 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
23 
24 import android.annotation.TargetApi;
25 import android.app.StatusBarManager.NavbarFlags;
26 import android.content.Context;
27 import android.content.res.Resources;
28 import android.graphics.Color;
29 import android.graphics.Rect;
30 import android.inputmethodservice.InputMethodService;
31 import android.inputmethodservice.InputMethodService.BackDispositionMode;
32 import android.os.Build;
33 import android.os.Handler;
34 import android.os.Message;
35 import android.util.DisplayMetrics;
36 import android.view.Surface;
37 import android.view.WindowManager;
38 
39 import com.android.systemui.shared.recents.model.Task;
40 import com.android.systemui.utils.windowmanager.WindowManagerUtils;
41 
42 /* Common code */
43 public class Utilities {
44 
45     private static final float TABLET_MIN_DPS = 600;
46 
47     /**
48      * Posts a runnable on a handler at the front of the queue ignoring any sync barriers.
49      */
postAtFrontOfQueueAsynchronously(Handler h, Runnable r)50     public static void postAtFrontOfQueueAsynchronously(Handler h, Runnable r) {
51         Message msg = h.obtainMessage().setCallback(r);
52         h.sendMessageAtFrontOfQueue(msg);
53     }
54 
isRotationAnimationCCW(int from, int to)55     public static boolean isRotationAnimationCCW(int from, int to) {
56         // All 180deg WM rotation animations are CCW, match that
57         if (from == Surface.ROTATION_0 && to == Surface.ROTATION_90) return false;
58         if (from == Surface.ROTATION_0 && to == Surface.ROTATION_180) return true; //180d so CCW
59         if (from == Surface.ROTATION_0 && to == Surface.ROTATION_270) return true;
60         if (from == Surface.ROTATION_90 && to == Surface.ROTATION_0) return true;
61         if (from == Surface.ROTATION_90 && to == Surface.ROTATION_180) return false;
62         if (from == Surface.ROTATION_90 && to == Surface.ROTATION_270) return true; //180d so CCW
63         if (from == Surface.ROTATION_180 && to == Surface.ROTATION_0) return true; //180d so CCW
64         if (from == Surface.ROTATION_180 && to == Surface.ROTATION_90) return true;
65         if (from == Surface.ROTATION_180 && to == Surface.ROTATION_270) return false;
66         if (from == Surface.ROTATION_270 && to == Surface.ROTATION_0) return false;
67         if (from == Surface.ROTATION_270 && to == Surface.ROTATION_90) return true; //180d so CCW
68         if (from == Surface.ROTATION_270 && to == Surface.ROTATION_180) return true;
69         return false; // Default
70     }
71 
72     /**
73      * Compares the ratio of two quantities and returns whether that ratio is greater than the
74      * provided bound. Order of quantities does not matter. Bound should be a decimal representation
75      * of a percentage.
76      */
isRelativePercentDifferenceGreaterThan(float first, float second, float bound)77     public static boolean isRelativePercentDifferenceGreaterThan(float first, float second,
78             float bound) {
79         return (Math.abs(first - second) / Math.abs((first + second) / 2.0f)) > bound;
80     }
81 
82     /** Calculates the constrast between two colors, using the algorithm provided by the WCAG v2. */
computeContrastBetweenColors(int bg, int fg)83     public static float computeContrastBetweenColors(int bg, int fg) {
84         float bgR = Color.red(bg) / 255f;
85         float bgG = Color.green(bg) / 255f;
86         float bgB = Color.blue(bg) / 255f;
87         bgR = (bgR < 0.03928f) ? bgR / 12.92f : (float) Math.pow((bgR + 0.055f) / 1.055f, 2.4f);
88         bgG = (bgG < 0.03928f) ? bgG / 12.92f : (float) Math.pow((bgG + 0.055f) / 1.055f, 2.4f);
89         bgB = (bgB < 0.03928f) ? bgB / 12.92f : (float) Math.pow((bgB + 0.055f) / 1.055f, 2.4f);
90         float bgL = 0.2126f * bgR + 0.7152f * bgG + 0.0722f * bgB;
91 
92         float fgR = Color.red(fg) / 255f;
93         float fgG = Color.green(fg) / 255f;
94         float fgB = Color.blue(fg) / 255f;
95         fgR = (fgR < 0.03928f) ? fgR / 12.92f : (float) Math.pow((fgR + 0.055f) / 1.055f, 2.4f);
96         fgG = (fgG < 0.03928f) ? fgG / 12.92f : (float) Math.pow((fgG + 0.055f) / 1.055f, 2.4f);
97         fgB = (fgB < 0.03928f) ? fgB / 12.92f : (float) Math.pow((fgB + 0.055f) / 1.055f, 2.4f);
98         float fgL = 0.2126f * fgR + 0.7152f * fgG + 0.0722f * fgB;
99 
100         return Math.abs((fgL + 0.05f) / (bgL + 0.05f));
101     }
102 
103     /**
104      * @return the clamped {@param value} between the provided {@param min} and {@param max}.
105      */
clamp(float value, float min, float max)106     public static float clamp(float value, float min, float max) {
107         return Math.max(min, Math.min(max, value));
108     }
109 
110     /**
111      * Updates the navigation bar state flags with the given IME state.
112      *
113      * @param oldFlags        current navigation bar state flags.
114      * @param backDisposition the IME back disposition mode. Only takes effect if
115      *                        {@code isImeVisible} is {@code true}.
116      * @param isImeVisible    whether the IME is currently visible.
117      * @param showImeSwitcher whether the IME Switcher button should be shown. Only takes effect if
118      *                        {@code isImeVisible} is {@code true}.
119      */
120     @NavbarFlags
updateNavbarFlagsFromIme(@avbarFlags int oldFlags, @BackDispositionMode int backDisposition, boolean isImeVisible, boolean showImeSwitcher)121     public static int updateNavbarFlagsFromIme(@NavbarFlags int oldFlags,
122             @BackDispositionMode int backDisposition, boolean isImeVisible,
123             boolean showImeSwitcher) {
124         int flags = oldFlags;
125         switch (backDisposition) {
126             case InputMethodService.BACK_DISPOSITION_DEFAULT:
127             case InputMethodService.BACK_DISPOSITION_WILL_NOT_DISMISS:
128             case InputMethodService.BACK_DISPOSITION_WILL_DISMISS:
129                 if (isImeVisible) {
130                     flags |= NAVBAR_BACK_DISMISS_IME;
131                 } else {
132                     flags &= ~NAVBAR_BACK_DISMISS_IME;
133                 }
134                 break;
135             case InputMethodService.BACK_DISPOSITION_ADJUST_NOTHING:
136                 flags &= ~NAVBAR_BACK_DISMISS_IME;
137                 break;
138         }
139         if (isImeVisible) {
140             flags |= NAVBAR_IME_VISIBLE;
141         } else {
142             flags &= ~NAVBAR_IME_VISIBLE;
143         }
144         if (showImeSwitcher && isImeVisible) {
145             flags |= NAVBAR_IME_SWITCHER_BUTTON_VISIBLE;
146         } else {
147             flags &= ~NAVBAR_IME_SWITCHER_BUTTON_VISIBLE;
148         }
149 
150         return flags;
151     }
152 
153     /** @return whether or not {@param context} represents that of a large screen device or not */
154     @TargetApi(Build.VERSION_CODES.R)
isLargeScreen(Context context)155     public static boolean isLargeScreen(Context context) {
156         return isLargeScreen(WindowManagerUtils.getWindowManager(context), context.getResources());
157     }
158 
159     /** @return whether or not {@param context} represents that of a large screen device or not */
isLargeScreen(WindowManager windowManager, Resources resources)160     public static boolean isLargeScreen(WindowManager windowManager, Resources resources) {
161         final Rect bounds = windowManager.getCurrentWindowMetrics().getBounds();
162 
163         float smallestWidth = dpiFromPx(Math.min(bounds.width(), bounds.height()),
164                 resources.getConfiguration().densityDpi);
165         return smallestWidth >= TABLET_MIN_DPS;
166     }
167 
dpiFromPx(float size, int densityDpi)168     public static float dpiFromPx(float size, int densityDpi) {
169         float densityRatio = (float) densityDpi / DisplayMetrics.DENSITY_DEFAULT;
170         return (size / densityRatio);
171     }
172 
173     /** Whether a task is in freeform mode. */
isFreeformTask(Task task)174     public static boolean isFreeformTask(Task task) {
175         return task != null && task.getKey() != null
176                 && task.getKey().windowingMode == WINDOWING_MODE_FREEFORM;
177     }
178 }
179