1 /*
2  * Copyright (C) 2019 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.launcher3.testing.shared;
18 
19 import android.content.res.Resources;
20 import android.util.DisplayMetrics;
21 import android.util.TypedValue;
22 
23 public class ResourceUtils {
24     private static final float EPSILON = 0.0001f;
25     public static final int DEFAULT_NAVBAR_VALUE = 48;
26     public static final int INVALID_RESOURCE_HANDLE = -1;
27     public static final String NAVBAR_LANDSCAPE_LEFT_RIGHT_SIZE = "navigation_bar_width";
28     public static final String NAVBAR_BOTTOM_GESTURE_SIZE = "navigation_bar_gesture_height";
29     public static final String NAVBAR_BOTTOM_GESTURE_LARGER_SIZE =
30             "navigation_bar_gesture_larger_height";
31 
32     public static final String NAVBAR_HEIGHT = "navigation_bar_height";
33     public static final String NAVBAR_HEIGHT_LANDSCAPE = "navigation_bar_height_landscape";
34 
35     public static final String STATUS_BAR_HEIGHT = "status_bar_height";
36     public static final String STATUS_BAR_HEIGHT_LANDSCAPE = "status_bar_height_landscape";
37     public static final String STATUS_BAR_HEIGHT_PORTRAIT = "status_bar_height_portrait";
38 
39     public static final String NAV_BAR_INTERACTION_MODE_RES_NAME = "config_navBarInteractionMode";
40 
getNavbarSize(String resName, Resources res)41     public static int getNavbarSize(String resName, Resources res) {
42         return getDimenByName(resName, res, DEFAULT_NAVBAR_VALUE);
43     }
44 
getDimenByName(String resName, Resources res, int defaultValue)45     public static int getDimenByName(String resName, Resources res, int defaultValue) {
46         final int frameSize;
47         final int frameSizeResID = res.getIdentifier(resName, "dimen", "android");
48         if (frameSizeResID != 0) {
49             frameSize = res.getDimensionPixelSize(frameSizeResID);
50         } else {
51             frameSize = pxFromDp(defaultValue, res.getDisplayMetrics());
52         }
53         return frameSize;
54     }
55 
getBoolByName(String resName, Resources res, boolean defaultValue)56     public static boolean getBoolByName(String resName, Resources res, boolean defaultValue) {
57         final boolean val;
58         final int resId = res.getIdentifier(resName, "bool", "android");
59         if (resId != 0) {
60             val = res.getBoolean(resId);
61         } else {
62             val = defaultValue;
63         }
64         return val;
65     }
66 
getIntegerByName(String resName, Resources res, int defaultValue)67     public static int getIntegerByName(String resName, Resources res, int defaultValue) {
68         int resId = res.getIdentifier(resName, "integer", "android");
69         return resId != 0 ? res.getInteger(resId) : defaultValue;
70     }
71 
pxFromDp(float size, DisplayMetrics metrics)72     public static int pxFromDp(float size, DisplayMetrics metrics) {
73         return pxFromDp(size, metrics, 1f);
74     }
75 
pxFromDp(float size, DisplayMetrics metrics, float scale)76     public static int pxFromDp(float size, DisplayMetrics metrics, float scale) {
77         float value = scale * TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, size, metrics);
78         return size < 0 ? INVALID_RESOURCE_HANDLE : roundPxValueFromFloat(value);
79     }
80 
81     /**
82      * Rounds a pixel value, taking into account floating point errors.
83      *
84      * <p>If a dp (or sp) value typically returns a half pixel, such as 20dp at a 2.625 density
85      * returning 52.5px, there is a small chance that due to floating-point errors, the value will
86      * be stored as 52.499999. As we round to the nearest pixel, this could cause a 1px difference
87      * in final values, which we correct for in this method.
88      */
roundPxValueFromFloat(float value)89     public static int roundPxValueFromFloat(float value) {
90         float fraction = (float) (value - Math.floor(value));
91         if (Math.abs(0.5f - fraction) < EPSILON) {
92             // Note: we add for negative values as well, as Math.round brings -.5 to the next
93             // "highest" value, e.g. Math.round(-2.5) == -2 [i.e. (int)Math.floor(a + 0.5d)]
94             value += EPSILON;
95         }
96         return Math.round(value);
97     }
98 }
99