131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project/* 231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project 331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * 431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * you may not use this file except in compliance with the License. 631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * You may obtain a copy of the License at 731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * 831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * 1031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 1131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 1231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * See the License for the specific language governing permissions and 1431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * limitations under the License. 1531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 1631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 17325dc23624160689e59fbac708cf6f222b20d025Daniel Sandlerpackage com.android.launcher3; 1831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 191ed6c4adde9c2ce597deb3e57600c664684eb639Sunny Goyalimport android.app.WallpaperManager; 20c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyalimport android.content.ComponentName; 21aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chungimport android.content.Context; 22a805e1a297c0d1fa84d9fed51e0167aa32bd42bbMichael Jurkaimport android.content.Intent; 237fc77cad3d06bd3647e550f7419e89116471240aRahul Chaturvediimport android.content.SharedPreferences; 24c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyalimport android.content.pm.ApplicationInfo; 25c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyalimport android.content.pm.PackageInfo; 26c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyalimport android.content.pm.PackageManager; 27c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyalimport android.content.pm.PackageManager.NameNotFoundException; 28c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyalimport android.content.pm.ResolveInfo; 29aafa03cbb925c74be1c13f8bb99d928be429e62fWinson Chungimport android.content.res.Resources; 3031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.graphics.Bitmap; 31c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chungimport android.graphics.Matrix; 3231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.graphics.Paint; 3331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.graphics.Rect; 34b1e2e2956e78b4845bdb2abbe3654de6445785f2Sunny Goyalimport android.graphics.RectF; 352efc7d928a3df57838f8abd8ed6fdb9eeb21b481Sandeep Siddharthaimport android.os.Build; 364e5cc64eaf1f63d866d51ce0a6bbafb3d4085c21Sunny Goyalimport android.os.Bundle; 37712ee53c67bbfb5ad4735217f3a9b063d9c60ad9Sunny Goyalimport android.os.DeadObjectException; 383483c52e6bd81b7c37eb0089940e90a6f3e6d80cSunny Goyalimport android.os.Handler; 393483c52e6bd81b7c37eb0089940e90a6f3e6d80cSunny Goyalimport android.os.Message; 40112ac95571c9b81921a912d67b9c369fb523a235Tony Wickhamimport android.os.PowerManager; 41712ee53c67bbfb5ad4735217f3a9b063d9c60ad9Sunny Goyalimport android.os.TransactionTooLargeException; 42e78e3d734b577c1ab6dc0738a83600374908ea52Sunny Goyalimport android.text.Spannable; 43e78e3d734b577c1ab6dc0738a83600374908ea52Sunny Goyalimport android.text.SpannableString; 445c97f51fd9443e461a360ff7852aa223c05d667fSunny Goyalimport android.text.TextUtils; 45e78e3d734b577c1ab6dc0738a83600374908ea52Sunny Goyalimport android.text.style.TtsSpan; 462e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohenimport android.util.DisplayMetrics; 47a805e1a297c0d1fa84d9fed51e0167aa32bd42bbMichael Jurkaimport android.util.Log; 480fe505bf82a265e51c556d7204976651cde7f55cSunny Goyalimport android.util.Pair; 492e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohenimport android.util.TypedValue; 50c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chungimport android.view.View; 51b1622cc30f2fd9b579cb918083e063685950df92Sunny Goyal 523d706ad70365052e3224fc4f4b0e7d1f5e8abf22Sunny Goyalimport com.android.launcher3.config.FeatureFlags; 536c56c68555dcb3d99b05d5faecd582a1f683cc92Sunny Goyal 545b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyalimport java.io.ByteArrayOutputStream; 55713edfce264db7edc409216d5c083f8dd6a7083fSunny Goyalimport java.io.Closeable; 565b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyalimport java.io.IOException; 57ab121c17159a7f655b772fa78c04a6d2479e2a8eSunny Goyalimport java.lang.reflect.InvocationTargetException; 5825aba0aea58b2ecbc0fd350c378fa9e45edb81c3Sunny Goyalimport java.lang.reflect.Method; 591bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickhamimport java.util.Collection; 60580edcf529b0755f2bba442e97dd02d8cdad3b82Tony Wickhamimport java.util.HashSet; 61b1622cc30f2fd9b579cb918083e063685950df92Sunny Goyalimport java.util.Locale; 628ac727b2c6627028960a1efe18ab9c72442eef48Sunny Goyalimport java.util.concurrent.Executor; 638ac727b2c6627028960a1efe18ab9c72442eef48Sunny Goyalimport java.util.concurrent.LinkedBlockingQueue; 648ac727b2c6627028960a1efe18ab9c72442eef48Sunny Goyalimport java.util.concurrent.ThreadPoolExecutor; 658ac727b2c6627028960a1efe18ab9c72442eef48Sunny Goyalimport java.util.concurrent.TimeUnit; 6682b016cb56540fe26213e817dd0dd668099c8e20Winson Chungimport java.util.regex.Matcher; 6782b016cb56540fe26213e817dd0dd668099c8e20Winson Chungimport java.util.regex.Pattern; 6831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project 6931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project/** 7031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Various utilities shared amongst the Launcher's classes. 7131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */ 7272fbec17e09a1120971621587d5005f683baafd1Mathew Inwoodpublic final class Utilities { 737fc77cad3d06bd3647e550f7419e89116471240aRahul Chaturvedi 741291a8c236c84451321438cb68855f6f2eb24959Joe Onorato private static final String TAG = "Launcher.Utilities"; 751291a8c236c84451321438cb68855f6f2eb24959Joe Onorato 7682b016cb56540fe26213e817dd0dd668099c8e20Winson Chung private static final Pattern sTrimPattern = 7782b016cb56540fe26213e817dd0dd668099c8e20Winson Chung Pattern.compile("^[\\s|\\p{javaSpaceChar}]*(.*)[\\s|\\p{javaSpaceChar}]*$"); 7882b016cb56540fe26213e817dd0dd668099c8e20Winson Chung 7953d7ee4285842732517edcccbdcaa92dccb1e107Sunny Goyal private static final int[] sLoc0 = new int[2]; 8053d7ee4285842732517edcccbdcaa92dccb1e107Sunny Goyal private static final int[] sLoc1 = new int[2]; 815e0e94f0b2ae79770dd07b66441fda6e063e64eaSunny Goyal private static final float[] sPoint = new float[2]; 825e0e94f0b2ae79770dd07b66441fda6e063e64eaSunny Goyal private static final Matrix sMatrix = new Matrix(); 835e0e94f0b2ae79770dd07b66441fda6e063e64eaSunny Goyal private static final Matrix sInverseMatrix = new Matrix(); 847ad868b86e45d6f58c186d2731ab2beb84643757Michael Jurka 858155fa2aa50a4c2ae3d4d1c599d249b6e20ec47dTony Wickham public static final boolean ATLEAST_P = 868155fa2aa50a4c2ae3d4d1c599d249b6e20ec47dTony Wickham Build.VERSION.SDK_INT >= Build.VERSION_CODES.P; 876eeb040d86ba209bffbbb9a1c59d5ca0b659f343Tony Mak 88e24cb63b811e2885a69e7df794e9972cdf5a57b9Hyunyoung Song public static final boolean ATLEAST_OREO_MR1 = 89e24cb63b811e2885a69e7df794e9972cdf5a57b9Hyunyoung Song Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1; 90e24cb63b811e2885a69e7df794e9972cdf5a57b9Hyunyoung Song 91e24cb63b811e2885a69e7df794e9972cdf5a57b9Hyunyoung Song public static final boolean ATLEAST_OREO = 92e24cb63b811e2885a69e7df794e9972cdf5a57b9Hyunyoung Song Build.VERSION.SDK_INT >= Build.VERSION_CODES.O; 93dcc0ba29a5222c9b0002604299501b716cda0b56Sunny Goyal 94f5e3744637db1598c389e62450627b2548f8f517Sunny Goyal public static final boolean ATLEAST_NOUGAT_MR1 = 95e24cb63b811e2885a69e7df794e9972cdf5a57b9Hyunyoung Song Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1; 969994b2b171ab78d1d93e8a25086d6853f766e80fSunny Goyal 97f5e3744637db1598c389e62450627b2548f8f517Sunny Goyal public static final boolean ATLEAST_NOUGAT = 98e24cb63b811e2885a69e7df794e9972cdf5a57b9Hyunyoung Song Build.VERSION.SDK_INT >= Build.VERSION_CODES.N; 99e2ec8a3cd52f2322016fcadbae8963a446e2b0b3Sunny Goyal 100be9798b6a2ef7c2c827a612203d81c67b3ec81acWinson public static final boolean ATLEAST_MARSHMALLOW = 101be9798b6a2ef7c2c827a612203d81c67b3ec81acWinson Build.VERSION.SDK_INT >= Build.VERSION_CODES.M; 1029fc953b94dbc6b99e6de08c9dcc80a0cb8e3e319Sunny Goyal 1039fc953b94dbc6b99e6de08c9dcc80a0cb8e3e319Sunny Goyal public static final boolean ATLEAST_LOLLIPOP_MR1 = 1049fc953b94dbc6b99e6de08c9dcc80a0cb8e3e319Sunny Goyal Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1; 1059fc953b94dbc6b99e6de08c9dcc80a0cb8e3e319Sunny Goyal 10683337f9e8e6ff91fe3bf64eddab3d72cc2d8369cJon Miranda public static final int SINGLE_FRAME_MS = 16; 10783337f9e8e6ff91fe3bf64eddab3d72cc2d8369cJon Miranda 10849f19f0af96ccf9da78b62a4ac9f51e40b40adc5Sunny Goyal /** 10949f19f0af96ccf9da78b62a4ac9f51e40b40adc5Sunny Goyal * Indicates if the device has a debug build. Should only be used to store additional info or 11049f19f0af96ccf9da78b62a4ac9f51e40b40adc5Sunny Goyal * add extra logging and not for changing the app behavior. 11149f19f0af96ccf9da78b62a4ac9f51e40b40adc5Sunny Goyal */ 112f0f00b30b8821b00e889dad3926da7a47a82b9a8Matthew Ng public static final boolean IS_DEBUG_DEVICE = Build.TYPE.toLowerCase().contains("debug") 113f0f00b30b8821b00e889dad3926da7a47a82b9a8Matthew Ng || Build.TYPE.toLowerCase().equals("eng"); 11449f19f0af96ccf9da78b62a4ac9f51e40b40adc5Sunny Goyal 1156f866095c0177a794050e578f148b640f4e0a0abSunny Goyal // An intent extra to indicate the horizontal scroll of the wallpaper. 1166f866095c0177a794050e578f148b640f4e0a0abSunny Goyal public static final String EXTRA_WALLPAPER_OFFSET = "com.android.launcher3.WALLPAPER_OFFSET"; 1176f866095c0177a794050e578f148b640f4e0a0abSunny Goyal 118629a67c5ac33409ebccf13284505a4cadc65656aTony public static final int COLOR_EXTRACTION_JOB_ID = 1; 1198231596619aa1e67be46f22f87da09b8407722e6Sunny Goyal public static final int WALLPAPER_COMPAT_JOB_ID = 2; 120629a67c5ac33409ebccf13284505a4cadc65656aTony 1218ac727b2c6627028960a1efe18ab9c72442eef48Sunny Goyal // These values are same as that in {@link AsyncTask}. 1228ac727b2c6627028960a1efe18ab9c72442eef48Sunny Goyal private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors(); 1238ac727b2c6627028960a1efe18ab9c72442eef48Sunny Goyal private static final int CORE_POOL_SIZE = CPU_COUNT + 1; 1248ac727b2c6627028960a1efe18ab9c72442eef48Sunny Goyal private static final int MAXIMUM_POOL_SIZE = CPU_COUNT * 2 + 1; 1258ac727b2c6627028960a1efe18ab9c72442eef48Sunny Goyal private static final int KEEP_ALIVE = 1; 1268ac727b2c6627028960a1efe18ab9c72442eef48Sunny Goyal /** 1278ac727b2c6627028960a1efe18ab9c72442eef48Sunny Goyal * An {@link Executor} to be used with async task with no limit on the queue size. 1288ac727b2c6627028960a1efe18ab9c72442eef48Sunny Goyal */ 1298ac727b2c6627028960a1efe18ab9c72442eef48Sunny Goyal public static final Executor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor( 1308ac727b2c6627028960a1efe18ab9c72442eef48Sunny Goyal CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE, 1318ac727b2c6627028960a1efe18ab9c72442eef48Sunny Goyal TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>()); 1328ac727b2c6627028960a1efe18ab9c72442eef48Sunny Goyal 1334bbf419bf98c00decc74b429320258c2a16faeecSunny Goyal public static boolean isPropertyEnabled(String propertyName) { 1347ad868b86e45d6f58c186d2731ab2beb84643757Michael Jurka return Log.isLoggable(propertyName, Log.VERBOSE); 1357ad868b86e45d6f58c186d2731ab2beb84643757Michael Jurka } 1367ad868b86e45d6f58c186d2731ab2beb84643757Michael Jurka 13731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project /** 138c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung * Given a coordinate relative to the descendant, find the coordinate in a parent view's 139c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung * coordinates. 140c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung * 141c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung * @param descendant The descendant to which the passed coordinate is relative. 142e8b5d20d94cb03878137a7fdf65d7a88270b73f8Sunny Goyal * @param ancestor The root view to make the coordinates relative to. 143c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung * @param coord The coordinate that we want mapped. 144c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung * @param includeRootScroll Whether or not to account for the scroll of the descendant: 145c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung * sometimes this is relevant as in a child's coordinates within the descendant. 146c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung * @return The factor by which this descendant is scaled relative to this DragLayer. Caution 147c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung * this scale factor is assumed to be equal in X and Y, and so if at any point this 148c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung * assumption fails, we will need to return a pair of scale factors. 149c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung */ 150e8b5d20d94cb03878137a7fdf65d7a88270b73f8Sunny Goyal public static float getDescendantCoordRelativeToAncestor( 151e8b5d20d94cb03878137a7fdf65d7a88270b73f8Sunny Goyal View descendant, View ancestor, int[] coord, boolean includeRootScroll) { 1525e0e94f0b2ae79770dd07b66441fda6e063e64eaSunny Goyal sPoint[0] = coord[0]; 1535e0e94f0b2ae79770dd07b66441fda6e063e64eaSunny Goyal sPoint[1] = coord[1]; 1545e0e94f0b2ae79770dd07b66441fda6e063e64eaSunny Goyal 1558cf47a5121205486e20694bf48eafc171175027aSunny Goyal float scale = 1.0f; 156c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung View v = descendant; 157e8b5d20d94cb03878137a7fdf65d7a88270b73f8Sunny Goyal while(v != ancestor && v != null) { 158c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung // For TextViews, scroll has a meaning which relates to the text position 159c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung // which is very strange... ignore the scroll. 1608cf47a5121205486e20694bf48eafc171175027aSunny Goyal if (v != descendant || includeRootScroll) { 1615e0e94f0b2ae79770dd07b66441fda6e063e64eaSunny Goyal sPoint[0] -= v.getScrollX(); 1625e0e94f0b2ae79770dd07b66441fda6e063e64eaSunny Goyal sPoint[1] -= v.getScrollY(); 163c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung } 164c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung 1655e0e94f0b2ae79770dd07b66441fda6e063e64eaSunny Goyal v.getMatrix().mapPoints(sPoint); 1665e0e94f0b2ae79770dd07b66441fda6e063e64eaSunny Goyal sPoint[0] += v.getLeft(); 1675e0e94f0b2ae79770dd07b66441fda6e063e64eaSunny Goyal sPoint[1] += v.getTop(); 1688cf47a5121205486e20694bf48eafc171175027aSunny Goyal scale *= v.getScaleX(); 1698cf47a5121205486e20694bf48eafc171175027aSunny Goyal 1708cf47a5121205486e20694bf48eafc171175027aSunny Goyal v = (View) v.getParent(); 171c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung } 172c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung 1735e0e94f0b2ae79770dd07b66441fda6e063e64eaSunny Goyal coord[0] = Math.round(sPoint[0]); 1745e0e94f0b2ae79770dd07b66441fda6e063e64eaSunny Goyal coord[1] = Math.round(sPoint[1]); 175c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung return scale; 176c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung } 177c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung 178c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung /** 179e8b5d20d94cb03878137a7fdf65d7a88270b73f8Sunny Goyal * Inverse of {@link #getDescendantCoordRelativeToAncestor(View, View, int[], boolean)}. 180c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung */ 1815e0e94f0b2ae79770dd07b66441fda6e063e64eaSunny Goyal public static void mapCoordInSelfToDescendant(View descendant, View root, int[] coord) { 1825e0e94f0b2ae79770dd07b66441fda6e063e64eaSunny Goyal sMatrix.reset(); 183c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung View v = descendant; 184c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung while(v != root) { 1855e0e94f0b2ae79770dd07b66441fda6e063e64eaSunny Goyal sMatrix.postTranslate(-v.getScrollX(), -v.getScrollY()); 1865e0e94f0b2ae79770dd07b66441fda6e063e64eaSunny Goyal sMatrix.postConcat(v.getMatrix()); 1875e0e94f0b2ae79770dd07b66441fda6e063e64eaSunny Goyal sMatrix.postTranslate(v.getLeft(), v.getTop()); 188c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung v = (View) v.getParent(); 189c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung } 1905e0e94f0b2ae79770dd07b66441fda6e063e64eaSunny Goyal sMatrix.postTranslate(-v.getScrollX(), -v.getScrollY()); 1915e0e94f0b2ae79770dd07b66441fda6e063e64eaSunny Goyal sMatrix.invert(sInverseMatrix); 1925e0e94f0b2ae79770dd07b66441fda6e063e64eaSunny Goyal 1935e0e94f0b2ae79770dd07b66441fda6e063e64eaSunny Goyal sPoint[0] = coord[0]; 1945e0e94f0b2ae79770dd07b66441fda6e063e64eaSunny Goyal sPoint[1] = coord[1]; 1955e0e94f0b2ae79770dd07b66441fda6e063e64eaSunny Goyal sInverseMatrix.mapPoints(sPoint); 1965e0e94f0b2ae79770dd07b66441fda6e063e64eaSunny Goyal coord[0] = Math.round(sPoint[0]); 1975e0e94f0b2ae79770dd07b66441fda6e063e64eaSunny Goyal coord[1] = Math.round(sPoint[1]); 198c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung } 199c763c4e4d28c256d1368be3fc1c4526c8b9bd232Winson Chung 20002dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monk /** 20102dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monk * Utility method to determine whether the given point, in local coordinates, 20202dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monk * is inside the view, where the area of the view is expanded by the slop factor. 20302dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monk * This method is called while processing touch-move events to determine if the event 20402dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monk * is still within the view. 20502dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monk */ 20602dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monk public static boolean pointInView(View v, float localX, float localY, float slop) { 20702dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monk return localX >= -slop && localY >= -slop && localX < (v.getWidth() + slop) && 20802dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monk localY < (v.getHeight() + slop); 20902dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monk } 21002dd7aea3d8ac94126a8f8069e6762592ea60326Jason Monk 211a52ecb0390c85afb385371bb844bb496c59ddf87Sunny Goyal public static int[] getCenterDeltaInScreenSpace(View v0, View v1) { 21263f1ec00fbbd109130d1e476371dbc9a87bb544dAdam Cohen v0.getLocationInWindow(sLoc0); 21363f1ec00fbbd109130d1e476371dbc9a87bb544dAdam Cohen v1.getLocationInWindow(sLoc1); 21463f1ec00fbbd109130d1e476371dbc9a87bb544dAdam Cohen 21563f1ec00fbbd109130d1e476371dbc9a87bb544dAdam Cohen sLoc0[0] += (v0.getMeasuredWidth() * v0.getScaleX()) / 2; 21663f1ec00fbbd109130d1e476371dbc9a87bb544dAdam Cohen sLoc0[1] += (v0.getMeasuredHeight() * v0.getScaleY()) / 2; 21763f1ec00fbbd109130d1e476371dbc9a87bb544dAdam Cohen sLoc1[0] += (v1.getMeasuredWidth() * v1.getScaleX()) / 2; 21863f1ec00fbbd109130d1e476371dbc9a87bb544dAdam Cohen sLoc1[1] += (v1.getMeasuredHeight() * v1.getScaleY()) / 2; 219a52ecb0390c85afb385371bb844bb496c59ddf87Sunny Goyal return new int[] {sLoc1[0] - sLoc0[0], sLoc1[1] - sLoc0[1]}; 22063f1ec00fbbd109130d1e476371dbc9a87bb544dAdam Cohen } 22163f1ec00fbbd109130d1e476371dbc9a87bb544dAdam Cohen 222b1e2e2956e78b4845bdb2abbe3654de6445785f2Sunny Goyal public static void scaleRectFAboutCenter(RectF r, float scale) { 223b1e2e2956e78b4845bdb2abbe3654de6445785f2Sunny Goyal if (scale != 1.0f) { 224b1e2e2956e78b4845bdb2abbe3654de6445785f2Sunny Goyal float cx = r.centerX(); 225b1e2e2956e78b4845bdb2abbe3654de6445785f2Sunny Goyal float cy = r.centerY(); 226b1e2e2956e78b4845bdb2abbe3654de6445785f2Sunny Goyal r.offset(-cx, -cy); 227b1e2e2956e78b4845bdb2abbe3654de6445785f2Sunny Goyal r.left = r.left * scale; 228b1e2e2956e78b4845bdb2abbe3654de6445785f2Sunny Goyal r.top = r.top * scale ; 229b1e2e2956e78b4845bdb2abbe3654de6445785f2Sunny Goyal r.right = r.right * scale; 230b1e2e2956e78b4845bdb2abbe3654de6445785f2Sunny Goyal r.bottom = r.bottom * scale; 231b1e2e2956e78b4845bdb2abbe3654de6445785f2Sunny Goyal r.offset(cx, cy); 232b1e2e2956e78b4845bdb2abbe3654de6445785f2Sunny Goyal } 233b1e2e2956e78b4845bdb2abbe3654de6445785f2Sunny Goyal } 234b1e2e2956e78b4845bdb2abbe3654de6445785f2Sunny Goyal 2356f6a06ac470df4f58a6eea902b79a8813c44c8f7Jon Miranda public static void scaleRectAboutCenter(Rect r, float scale) { 2366f6a06ac470df4f58a6eea902b79a8813c44c8f7Jon Miranda if (scale != 1.0f) { 2376f6a06ac470df4f58a6eea902b79a8813c44c8f7Jon Miranda int cx = r.centerX(); 2386f6a06ac470df4f58a6eea902b79a8813c44c8f7Jon Miranda int cy = r.centerY(); 2396f6a06ac470df4f58a6eea902b79a8813c44c8f7Jon Miranda r.offset(-cx, -cy); 2403e803c7a4bec4d14006057d918fe8663c7d36769Winson Chung scaleRect(r, scale); 2413e803c7a4bec4d14006057d918fe8663c7d36769Winson Chung r.offset(cx, cy); 2423e803c7a4bec4d14006057d918fe8663c7d36769Winson Chung } 2433e803c7a4bec4d14006057d918fe8663c7d36769Winson Chung } 2446f6a06ac470df4f58a6eea902b79a8813c44c8f7Jon Miranda 2453e803c7a4bec4d14006057d918fe8663c7d36769Winson Chung public static void scaleRect(Rect r, float scale) { 2463e803c7a4bec4d14006057d918fe8663c7d36769Winson Chung if (scale != 1.0f) { 2476f6a06ac470df4f58a6eea902b79a8813c44c8f7Jon Miranda r.left = (int) (r.left * scale + 0.5f); 2486f6a06ac470df4f58a6eea902b79a8813c44c8f7Jon Miranda r.top = (int) (r.top * scale + 0.5f); 2496f6a06ac470df4f58a6eea902b79a8813c44c8f7Jon Miranda r.right = (int) (r.right * scale + 0.5f); 2506f6a06ac470df4f58a6eea902b79a8813c44c8f7Jon Miranda r.bottom = (int) (r.bottom * scale + 0.5f); 2516f6a06ac470df4f58a6eea902b79a8813c44c8f7Jon Miranda } 2526f6a06ac470df4f58a6eea902b79a8813c44c8f7Jon Miranda } 2536f6a06ac470df4f58a6eea902b79a8813c44c8f7Jon Miranda 2543e803c7a4bec4d14006057d918fe8663c7d36769Winson Chung public static void insetRect(Rect r, Rect insets) { 2553e803c7a4bec4d14006057d918fe8663c7d36769Winson Chung r.left = Math.min(r.right, r.left + insets.left); 2563e803c7a4bec4d14006057d918fe8663c7d36769Winson Chung r.top = Math.min(r.bottom, r.top + insets.top); 2573e803c7a4bec4d14006057d918fe8663c7d36769Winson Chung r.right = Math.max(r.left, r.right - insets.right); 2583e803c7a4bec4d14006057d918fe8663c7d36769Winson Chung r.bottom = Math.max(r.top, r.bottom - insets.bottom); 2593e803c7a4bec4d14006057d918fe8663c7d36769Winson Chung } 2603e803c7a4bec4d14006057d918fe8663c7d36769Winson Chung 2616f6a06ac470df4f58a6eea902b79a8813c44c8f7Jon Miranda public static float shrinkRect(Rect r, float scaleX, float scaleY) { 262e96798e885e3ac97b6de0a1c598eb09cf62349afJon Miranda float scale = Math.min(Math.min(scaleX, scaleY), 1.0f); 263e96798e885e3ac97b6de0a1c598eb09cf62349afJon Miranda if (scale < 1.0f) { 264e96798e885e3ac97b6de0a1c598eb09cf62349afJon Miranda int deltaX = (int) (r.width() * (scaleX - scale) * 0.5f); 265e96798e885e3ac97b6de0a1c598eb09cf62349afJon Miranda r.left += deltaX; 266e96798e885e3ac97b6de0a1c598eb09cf62349afJon Miranda r.right -= deltaX; 267e96798e885e3ac97b6de0a1c598eb09cf62349afJon Miranda 268e96798e885e3ac97b6de0a1c598eb09cf62349afJon Miranda int deltaY = (int) (r.height() * (scaleY - scale) * 0.5f); 269e96798e885e3ac97b6de0a1c598eb09cf62349afJon Miranda r.top += deltaY; 270e96798e885e3ac97b6de0a1c598eb09cf62349afJon Miranda r.bottom -= deltaY; 271106bf64f4a5b4b7772c971f62b6207b5a73529a2Sunny Goyal } 272e96798e885e3ac97b6de0a1c598eb09cf62349afJon Miranda return scale; 2733a6e7f330e680ef718ca7c0921d842efb4d8bbaeWinson Chung } 2743a6e7f330e680ef718ca7c0921d842efb4d8bbaeWinson Chung 2753e803c7a4bec4d14006057d918fe8663c7d36769Winson Chung public static float mapRange(float value, float min, float max) { 2763e803c7a4bec4d14006057d918fe8663c7d36769Winson Chung return min + (value * (max - min)); 2773e803c7a4bec4d14006057d918fe8663c7d36769Winson Chung } 2783e803c7a4bec4d14006057d918fe8663c7d36769Winson Chung 2790e947fbdbb49d2d58b4d1719224ded4c3f18707aSunny Goyal public static boolean isSystemApp(Context context, Intent intent) { 280c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal PackageManager pm = context.getPackageManager(); 281c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal ComponentName cn = intent.getComponent(); 282c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal String packageName = null; 283c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal if (cn == null) { 284c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal ResolveInfo info = pm.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY); 285c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal if ((info != null) && (info.activityInfo != null)) { 286c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal packageName = info.activityInfo.packageName; 287c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal } 288c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal } else { 289c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal packageName = cn.getPackageName(); 290c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal } 291c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal if (packageName != null) { 292c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal try { 293c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal PackageInfo info = pm.getPackageInfo(packageName, 0); 294c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal return (info != null) && (info.applicationInfo != null) && 295c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal ((info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0); 296c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal } catch (NameNotFoundException e) { 297c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal return false; 298c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal } 299c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal } else { 300c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal return false; 301c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal } 302c5c60ad3592f53549c9ffaa58e9a87b0480080e8Sunny Goyal } 30395abbb330ce9bbaf23594245f0f8a795c8118038Sunny Goyal 3040fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal /* 3050fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal * Finds a system apk which had a broadcast receiver listening to a particular action. 3060fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal * @param action intent action used to find the apk 3070fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal * @return a pair of apk package name and the resources. 3080fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal */ 3090fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal static Pair<String, Resources> findSystemApk(String action, PackageManager pm) { 3100fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal final Intent intent = new Intent(action); 3110fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal for (ResolveInfo info : pm.queryBroadcastReceivers(intent, 0)) { 3120fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal if (info.activityInfo != null && 3130fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal (info.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { 3140fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal final String packageName = info.activityInfo.packageName; 3150fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal try { 3160fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal final Resources res = pm.getResourcesForApplication(packageName); 3170fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal return Pair.create(packageName, res); 3180fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal } catch (NameNotFoundException e) { 3190fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal Log.w(TAG, "Failed to find resources for " + packageName); 3200fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal } 3210fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal } 3220fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal } 3230fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal return null; 3240fe505bf82a265e51c556d7204976651cde7f55cSunny Goyal } 325fafca5299e13e0f44d1d2332d7669d55ad38fdb5Sunny Goyal 326594d76dc66cb5666830b62594909fed187987d42Sunny Goyal /** 3275b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal * Compresses the bitmap to a byte array for serialization. 3285b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal */ 3295b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal public static byte[] flattenBitmap(Bitmap bitmap) { 3305b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal // Try go guesstimate how much space the icon will take when serialized 3315b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal // to avoid unnecessary allocations/copies during the write. 3325b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal int size = bitmap.getWidth() * bitmap.getHeight() * 4; 3335b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal ByteArrayOutputStream out = new ByteArrayOutputStream(size); 3345b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal try { 3355b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal bitmap.compress(Bitmap.CompressFormat.PNG, 100, out); 3365b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal out.flush(); 3375b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal out.close(); 3385b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal return out.toByteArray(); 3395b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } catch (IOException e) { 3405b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal Log.w(TAG, "Could not write bitmap"); 3415b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal return null; 3425b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 3435b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal } 3445b0e669169ea2c951bf2f6f71faf793b24db3c23Sunny Goyal 345f7a29e83f06909b378dba39c83a522375682710aSunny Goyal /** 34682b016cb56540fe26213e817dd0dd668099c8e20Winson Chung * Trims the string, removing all whitespace at the beginning and end of the string. 34782b016cb56540fe26213e817dd0dd668099c8e20Winson Chung * Non-breaking whitespaces are also removed. 34882b016cb56540fe26213e817dd0dd668099c8e20Winson Chung */ 34982b016cb56540fe26213e817dd0dd668099c8e20Winson Chung public static String trim(CharSequence s) { 350afa77e947d7b286c29cd6fc590b88d6cb425334fWinson Chung if (s == null) { 351afa77e947d7b286c29cd6fc590b88d6cb425334fWinson Chung return null; 352afa77e947d7b286c29cd6fc590b88d6cb425334fWinson Chung } 353afa77e947d7b286c29cd6fc590b88d6cb425334fWinson Chung 35482b016cb56540fe26213e817dd0dd668099c8e20Winson Chung // Just strip any sequence of whitespace or java space characters from the beginning and end 35582b016cb56540fe26213e817dd0dd668099c8e20Winson Chung Matcher m = sTrimPattern.matcher(s); 35682b016cb56540fe26213e817dd0dd668099c8e20Winson Chung return m.replaceAll("$1"); 35782b016cb56540fe26213e817dd0dd668099c8e20Winson Chung } 3587066003b2032a49ae5e59dab9b706259bdeb7e6eSunny Goyal 3592c6e5ccbcd7c3f87e7e85029782440600dc0a3d8Winson Chung /** 3602c6e5ccbcd7c3f87e7e85029782440600dc0a3d8Winson Chung * Calculates the height of a given string at a specific text size. 3612c6e5ccbcd7c3f87e7e85029782440600dc0a3d8Winson Chung */ 362baec6ffae2c260180dbdf2c6b2ca2f38e1df8f1aSunny Goyal public static int calculateTextHeight(float textSizePx) { 3632c6e5ccbcd7c3f87e7e85029782440600dc0a3d8Winson Chung Paint p = new Paint(); 3642c6e5ccbcd7c3f87e7e85029782440600dc0a3d8Winson Chung p.setTextSize(textSizePx); 3652c6e5ccbcd7c3f87e7e85029782440600dc0a3d8Winson Chung Paint.FontMetrics fm = p.getFontMetrics(); 366baec6ffae2c260180dbdf2c6b2ca2f38e1df8f1aSunny Goyal return (int) Math.ceil(fm.bottom - fm.top); 3672c6e5ccbcd7c3f87e7e85029782440600dc0a3d8Winson Chung } 3682c6e5ccbcd7c3f87e7e85029782440600dc0a3d8Winson Chung 369b1777447d9b9700b48f8060f8b318f2363c43e8dWinson Chung /** 370b1777447d9b9700b48f8060f8b318f2363c43e8dWinson Chung * Convenience println with multiple args. 371b1777447d9b9700b48f8060f8b318f2363c43e8dWinson Chung */ 372b1777447d9b9700b48f8060f8b318f2363c43e8dWinson Chung public static void println(String key, Object... args) { 373b1777447d9b9700b48f8060f8b318f2363c43e8dWinson Chung StringBuilder b = new StringBuilder(); 374b1777447d9b9700b48f8060f8b318f2363c43e8dWinson Chung b.append(key); 375b1777447d9b9700b48f8060f8b318f2363c43e8dWinson Chung b.append(": "); 376b1777447d9b9700b48f8060f8b318f2363c43e8dWinson Chung boolean isFirstArgument = true; 377b1777447d9b9700b48f8060f8b318f2363c43e8dWinson Chung for (Object arg : args) { 378b1777447d9b9700b48f8060f8b318f2363c43e8dWinson Chung if (isFirstArgument) { 379b1777447d9b9700b48f8060f8b318f2363c43e8dWinson Chung isFirstArgument = false; 380b1777447d9b9700b48f8060f8b318f2363c43e8dWinson Chung } else { 381b1777447d9b9700b48f8060f8b318f2363c43e8dWinson Chung b.append(", "); 382b1777447d9b9700b48f8060f8b318f2363c43e8dWinson Chung } 383b1777447d9b9700b48f8060f8b318f2363c43e8dWinson Chung b.append(arg); 384b1777447d9b9700b48f8060f8b318f2363c43e8dWinson Chung } 385b1777447d9b9700b48f8060f8b318f2363c43e8dWinson Chung System.out.println(b.toString()); 386b1777447d9b9700b48f8060f8b318f2363c43e8dWinson Chung } 387b1777447d9b9700b48f8060f8b318f2363c43e8dWinson Chung 3887066003b2032a49ae5e59dab9b706259bdeb7e6eSunny Goyal public static boolean isRtl(Resources res) { 389a52ecb0390c85afb385371bb844bb496c59ddf87Sunny Goyal return res.getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_RTL; 3907066003b2032a49ae5e59dab9b706259bdeb7e6eSunny Goyal } 3912bd3d7d1cb5e4d8d826982d11b456739fed6b817Hyunyoung Song 3925c97f51fd9443e461a360ff7852aa223c05d667fSunny Goyal /** 3935c97f51fd9443e461a360ff7852aa223c05d667fSunny Goyal * Returns true if the intent is a valid launch intent for a launcher activity of an app. 3945c97f51fd9443e461a360ff7852aa223c05d667fSunny Goyal * This is used to identify shortcuts which are different from the ones exposed by the 3955c97f51fd9443e461a360ff7852aa223c05d667fSunny Goyal * applications' manifest file. 3965c97f51fd9443e461a360ff7852aa223c05d667fSunny Goyal * 3975c97f51fd9443e461a360ff7852aa223c05d667fSunny Goyal * @param launchIntent The intent that will be launched when the shortcut is clicked. 3985c97f51fd9443e461a360ff7852aa223c05d667fSunny Goyal */ 3995c97f51fd9443e461a360ff7852aa223c05d667fSunny Goyal public static boolean isLauncherAppTarget(Intent launchIntent) { 4004e5cc64eaf1f63d866d51ce0a6bbafb3d4085c21Sunny Goyal if (launchIntent != null 4015c97f51fd9443e461a360ff7852aa223c05d667fSunny Goyal && Intent.ACTION_MAIN.equals(launchIntent.getAction()) 4025c97f51fd9443e461a360ff7852aa223c05d667fSunny Goyal && launchIntent.getComponent() != null 4035c97f51fd9443e461a360ff7852aa223c05d667fSunny Goyal && launchIntent.getCategories() != null 4045c97f51fd9443e461a360ff7852aa223c05d667fSunny Goyal && launchIntent.getCategories().size() == 1 4055c97f51fd9443e461a360ff7852aa223c05d667fSunny Goyal && launchIntent.hasCategory(Intent.CATEGORY_LAUNCHER) 4064e5cc64eaf1f63d866d51ce0a6bbafb3d4085c21Sunny Goyal && TextUtils.isEmpty(launchIntent.getDataString())) { 4074e5cc64eaf1f63d866d51ce0a6bbafb3d4085c21Sunny Goyal // An app target can either have no extra or have ItemInfo.EXTRA_PROFILE. 4084e5cc64eaf1f63d866d51ce0a6bbafb3d4085c21Sunny Goyal Bundle extras = launchIntent.getExtras(); 40924bb66a1c5a435ab0c55b4a97e788bdc2595bf84Sunny Goyal return extras == null || extras.keySet().isEmpty(); 41024bb66a1c5a435ab0c55b4a97e788bdc2595bf84Sunny Goyal } 4114e5cc64eaf1f63d866d51ce0a6bbafb3d4085c21Sunny Goyal return false; 4125c97f51fd9443e461a360ff7852aa223c05d667fSunny Goyal } 4132e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen 4142e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen public static float dpiFromPx(int size, DisplayMetrics metrics){ 4152e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen float densityRatio = (float) metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT; 4162e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen return (size / densityRatio); 4172e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen } 4182e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen public static int pxFromDp(float size, DisplayMetrics metrics) { 4192e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen return (int) Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 4202e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen size, metrics)); 4212e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen } 4222e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen public static int pxFromSp(float size, DisplayMetrics metrics) { 4232e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen return (int) Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 4242e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen size, metrics)); 4252e6da1539bc7286336b3c24d96ab76434939ce4dAdam Cohen } 426b1622cc30f2fd9b579cb918083e063685950df92Sunny Goyal 427b1622cc30f2fd9b579cb918083e063685950df92Sunny Goyal public static String createDbSelectionQuery(String columnName, Iterable<?> values) { 428b1622cc30f2fd9b579cb918083e063685950df92Sunny Goyal return String.format(Locale.ENGLISH, "%s IN (%s)", columnName, TextUtils.join(", ", values)); 429b1622cc30f2fd9b579cb918083e063685950df92Sunny Goyal } 43025aba0aea58b2ecbc0fd350c378fa9e45edb81c3Sunny Goyal 43125aba0aea58b2ecbc0fd350c378fa9e45edb81c3Sunny Goyal public static boolean isBootCompleted() { 432dfc8b6685bf330b203cb16b67c39bed936030306Sunny Goyal return "1".equals(getSystemProperty("sys.boot_completed", "1")); 433dfc8b6685bf330b203cb16b67c39bed936030306Sunny Goyal } 434dfc8b6685bf330b203cb16b67c39bed936030306Sunny Goyal 435dfc8b6685bf330b203cb16b67c39bed936030306Sunny Goyal public static String getSystemProperty(String property, String defaultValue) { 43625aba0aea58b2ecbc0fd350c378fa9e45edb81c3Sunny Goyal try { 43725aba0aea58b2ecbc0fd350c378fa9e45edb81c3Sunny Goyal Class clazz = Class.forName("android.os.SystemProperties"); 43825aba0aea58b2ecbc0fd350c378fa9e45edb81c3Sunny Goyal Method getter = clazz.getDeclaredMethod("get", String.class); 439dfc8b6685bf330b203cb16b67c39bed936030306Sunny Goyal String value = (String) getter.invoke(null, property); 440dfc8b6685bf330b203cb16b67c39bed936030306Sunny Goyal if (!TextUtils.isEmpty(value)) { 441dfc8b6685bf330b203cb16b67c39bed936030306Sunny Goyal return value; 442dfc8b6685bf330b203cb16b67c39bed936030306Sunny Goyal } 44325aba0aea58b2ecbc0fd350c378fa9e45edb81c3Sunny Goyal } catch (Exception e) { 44425aba0aea58b2ecbc0fd350c378fa9e45edb81c3Sunny Goyal Log.d(TAG, "Unable to read system properties"); 44525aba0aea58b2ecbc0fd350c378fa9e45edb81c3Sunny Goyal } 446dfc8b6685bf330b203cb16b67c39bed936030306Sunny Goyal return defaultValue; 44725aba0aea58b2ecbc0fd350c378fa9e45edb81c3Sunny Goyal } 44829d853c2ddf6432685a54e3966820f1a81cee183Tony Wickham 44929d853c2ddf6432685a54e3966820f1a81cee183Tony Wickham /** 45029d853c2ddf6432685a54e3966820f1a81cee183Tony Wickham * Ensures that a value is within given bounds. Specifically: 45129d853c2ddf6432685a54e3966820f1a81cee183Tony Wickham * If value is less than lowerBound, return lowerBound; else if value is greater than upperBound, 45229d853c2ddf6432685a54e3966820f1a81cee183Tony Wickham * return upperBound; else return value unchanged. 45329d853c2ddf6432685a54e3966820f1a81cee183Tony Wickham */ 454f549dab31d0fa3e4d0cf8d6025b20e49aafb2d59Tony Wickham public static int boundToRange(int value, int lowerBound, int upperBound) { 455f549dab31d0fa3e4d0cf8d6025b20e49aafb2d59Tony Wickham return Math.max(lowerBound, Math.min(value, upperBound)); 456f549dab31d0fa3e4d0cf8d6025b20e49aafb2d59Tony Wickham } 457f549dab31d0fa3e4d0cf8d6025b20e49aafb2d59Tony Wickham 458f549dab31d0fa3e4d0cf8d6025b20e49aafb2d59Tony Wickham /** 459f549dab31d0fa3e4d0cf8d6025b20e49aafb2d59Tony Wickham * @see #boundToRange(int, int, int). 460f549dab31d0fa3e4d0cf8d6025b20e49aafb2d59Tony Wickham */ 461f549dab31d0fa3e4d0cf8d6025b20e49aafb2d59Tony Wickham public static float boundToRange(float value, float lowerBound, float upperBound) { 46229d853c2ddf6432685a54e3966820f1a81cee183Tony Wickham return Math.max(lowerBound, Math.min(value, upperBound)); 46329d853c2ddf6432685a54e3966820f1a81cee183Tony Wickham } 4649d4380856ff41ecb26c0d5aee1747b6060d2ef0eSunny Goyal 465e78e3d734b577c1ab6dc0738a83600374908ea52Sunny Goyal /** 466e78e3d734b577c1ab6dc0738a83600374908ea52Sunny Goyal * Wraps a message with a TTS span, so that a different message is spoken than 467e78e3d734b577c1ab6dc0738a83600374908ea52Sunny Goyal * what is getting displayed. 468e78e3d734b577c1ab6dc0738a83600374908ea52Sunny Goyal * @param msg original message 469e78e3d734b577c1ab6dc0738a83600374908ea52Sunny Goyal * @param ttsMsg message to be spoken 470e78e3d734b577c1ab6dc0738a83600374908ea52Sunny Goyal */ 471e78e3d734b577c1ab6dc0738a83600374908ea52Sunny Goyal public static CharSequence wrapForTts(CharSequence msg, String ttsMsg) { 472a52ecb0390c85afb385371bb844bb496c59ddf87Sunny Goyal SpannableString spanned = new SpannableString(msg); 473a52ecb0390c85afb385371bb844bb496c59ddf87Sunny Goyal spanned.setSpan(new TtsSpan.TextBuilder(ttsMsg).build(), 474a52ecb0390c85afb385371bb844bb496c59ddf87Sunny Goyal 0, spanned.length(), Spannable.SPAN_INCLUSIVE_INCLUSIVE); 475a52ecb0390c85afb385371bb844bb496c59ddf87Sunny Goyal return spanned; 476e78e3d734b577c1ab6dc0738a83600374908ea52Sunny Goyal } 47712fb9fc3c3133c3a748deef7a0265e6a11a24cd6Winson 47812fb9fc3c3133c3a748deef7a0265e6a11a24cd6Winson /** 47912fb9fc3c3133c3a748deef7a0265e6a11a24cd6Winson * Replacement for Long.compare() which was added in API level 19. 48012fb9fc3c3133c3a748deef7a0265e6a11a24cd6Winson */ 48112fb9fc3c3133c3a748deef7a0265e6a11a24cd6Winson public static int longCompare(long lhs, long rhs) { 48212fb9fc3c3133c3a748deef7a0265e6a11a24cd6Winson return lhs < rhs ? -1 : (lhs == rhs ? 0 : 1); 48312fb9fc3c3133c3a748deef7a0265e6a11a24cd6Winson } 484f725824fa2091cab44cf1bcbfe5b5b8d06475560Sunny Goyal 485f725824fa2091cab44cf1bcbfe5b5b8d06475560Sunny Goyal public static SharedPreferences getPrefs(Context context) { 486f725824fa2091cab44cf1bcbfe5b5b8d06475560Sunny Goyal return context.getSharedPreferences( 487f725824fa2091cab44cf1bcbfe5b5b8d06475560Sunny Goyal LauncherFiles.SHARED_PREFERENCES_KEY, Context.MODE_PRIVATE); 488f725824fa2091cab44cf1bcbfe5b5b8d06475560Sunny Goyal } 489112ac95571c9b81921a912d67b9c369fb523a235Tony Wickham 4909d887a2c452f652624f0d28950c1b69cb37a8e23Sunny Goyal public static SharedPreferences getDevicePrefs(Context context) { 4919d887a2c452f652624f0d28950c1b69cb37a8e23Sunny Goyal return context.getSharedPreferences( 4929d887a2c452f652624f0d28950c1b69cb37a8e23Sunny Goyal LauncherFiles.DEVICE_PREFERENCES_KEY, Context.MODE_PRIVATE); 4939d887a2c452f652624f0d28950c1b69cb37a8e23Sunny Goyal } 4949d887a2c452f652624f0d28950c1b69cb37a8e23Sunny Goyal 4958155fa2aa50a4c2ae3d4d1c599d249b6e20ec47dTony Wickham public static boolean isPowerSaverPreventingAnimation(Context context) { 4968155fa2aa50a4c2ae3d4d1c599d249b6e20ec47dTony Wickham if (ATLEAST_P) { 4978155fa2aa50a4c2ae3d4d1c599d249b6e20ec47dTony Wickham // Battery saver mode no longer prevents animations. 4988155fa2aa50a4c2ae3d4d1c599d249b6e20ec47dTony Wickham return false; 4998155fa2aa50a4c2ae3d4d1c599d249b6e20ec47dTony Wickham } 500112ac95571c9b81921a912d67b9c369fb523a235Tony Wickham PowerManager powerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE); 501a52ecb0390c85afb385371bb844bb496c59ddf87Sunny Goyal return powerManager.isPowerSaveMode(); 502112ac95571c9b81921a912d67b9c369fb523a235Tony Wickham } 503e1483fb1cdabb33e7031bdebba96212d920c7416Sunny Goyal 5040de011705b132eacdd10f7bfb5cdc4bd79a147e8Hyunyoung Song public static boolean isWallpaperAllowed(Context context) { 505f5e3744637db1598c389e62450627b2548f8f517Sunny Goyal if (ATLEAST_NOUGAT) { 5061ed6c4adde9c2ce597deb3e57600c664684eb639Sunny Goyal try { 5071ed6c4adde9c2ce597deb3e57600c664684eb639Sunny Goyal WallpaperManager wm = context.getSystemService(WallpaperManager.class); 508367da9f422e7fad45da351e79b1ade29c366ef7eKenny Guy return (Boolean) wm.getClass().getDeclaredMethod("isSetWallpaperAllowed") 5091ed6c4adde9c2ce597deb3e57600c664684eb639Sunny Goyal .invoke(wm); 5101ed6c4adde9c2ce597deb3e57600c664684eb639Sunny Goyal } catch (Exception e) { } 5111ed6c4adde9c2ce597deb3e57600c664684eb639Sunny Goyal } 5121ed6c4adde9c2ce597deb3e57600c664684eb639Sunny Goyal return true; 5131ed6c4adde9c2ce597deb3e57600c664684eb639Sunny Goyal } 5141ed6c4adde9c2ce597deb3e57600c664684eb639Sunny Goyal 515713edfce264db7edc409216d5c083f8dd6a7083fSunny Goyal public static void closeSilently(Closeable c) { 516713edfce264db7edc409216d5c083f8dd6a7083fSunny Goyal if (c != null) { 517713edfce264db7edc409216d5c083f8dd6a7083fSunny Goyal try { 518713edfce264db7edc409216d5c083f8dd6a7083fSunny Goyal c.close(); 519713edfce264db7edc409216d5c083f8dd6a7083fSunny Goyal } catch (IOException e) { 5203d706ad70365052e3224fc4f4b0e7d1f5e8abf22Sunny Goyal if (FeatureFlags.IS_DOGFOOD_BUILD) { 521713edfce264db7edc409216d5c083f8dd6a7083fSunny Goyal Log.d(TAG, "Error closing", e); 522713edfce264db7edc409216d5c083f8dd6a7083fSunny Goyal } 523713edfce264db7edc409216d5c083f8dd6a7083fSunny Goyal } 524713edfce264db7edc409216d5c083f8dd6a7083fSunny Goyal } 525713edfce264db7edc409216d5c083f8dd6a7083fSunny Goyal } 526713edfce264db7edc409216d5c083f8dd6a7083fSunny Goyal 527e1483fb1cdabb33e7031bdebba96212d920c7416Sunny Goyal /** 5283f732190cc6c8feef53383d369b66dcf38f06e44Sunny Goyal * Returns true if {@param original} contains all entries defined in {@param updates} and 5293f732190cc6c8feef53383d369b66dcf38f06e44Sunny Goyal * have the same value. 5303f732190cc6c8feef53383d369b66dcf38f06e44Sunny Goyal * The comparison uses {@link Object#equals(Object)} to compare the values. 5313f732190cc6c8feef53383d369b66dcf38f06e44Sunny Goyal */ 5323f732190cc6c8feef53383d369b66dcf38f06e44Sunny Goyal public static boolean containsAll(Bundle original, Bundle updates) { 5333f732190cc6c8feef53383d369b66dcf38f06e44Sunny Goyal for (String key : updates.keySet()) { 5343f732190cc6c8feef53383d369b66dcf38f06e44Sunny Goyal Object value1 = updates.get(key); 5353f732190cc6c8feef53383d369b66dcf38f06e44Sunny Goyal Object value2 = original.get(key); 5363f732190cc6c8feef53383d369b66dcf38f06e44Sunny Goyal if (value1 == null) { 5373f732190cc6c8feef53383d369b66dcf38f06e44Sunny Goyal if (value2 != null) { 5383f732190cc6c8feef53383d369b66dcf38f06e44Sunny Goyal return false; 5393f732190cc6c8feef53383d369b66dcf38f06e44Sunny Goyal } 5403f732190cc6c8feef53383d369b66dcf38f06e44Sunny Goyal } else if (!value1.equals(value2)) { 5413f732190cc6c8feef53383d369b66dcf38f06e44Sunny Goyal return false; 5423f732190cc6c8feef53383d369b66dcf38f06e44Sunny Goyal } 5433f732190cc6c8feef53383d369b66dcf38f06e44Sunny Goyal } 5443f732190cc6c8feef53383d369b66dcf38f06e44Sunny Goyal return true; 5453f732190cc6c8feef53383d369b66dcf38f06e44Sunny Goyal } 5463f732190cc6c8feef53383d369b66dcf38f06e44Sunny Goyal 5471bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickham /** Returns whether the collection is null or empty. */ 5481bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickham public static boolean isEmpty(Collection c) { 5491bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickham return c == null || c.isEmpty(); 5501bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickham } 5511bce7fd342875be8f7c1f82c8cf21d0199c8d544Tony Wickham 552712ee53c67bbfb5ad4735217f3a9b063d9c60ad9Sunny Goyal public static boolean isBinderSizeError(Exception e) { 553712ee53c67bbfb5ad4735217f3a9b063d9c60ad9Sunny Goyal return e.getCause() instanceof TransactionTooLargeException 554712ee53c67bbfb5ad4735217f3a9b063d9c60ad9Sunny Goyal || e.getCause() instanceof DeadObjectException; 555712ee53c67bbfb5ad4735217f3a9b063d9c60ad9Sunny Goyal } 556ab121c17159a7f655b772fa78c04a6d2479e2a8eSunny Goyal 557ab121c17159a7f655b772fa78c04a6d2479e2a8eSunny Goyal public static <T> T getOverrideObject(Class<T> clazz, Context context, int resId) { 558ab121c17159a7f655b772fa78c04a6d2479e2a8eSunny Goyal String className = context.getString(resId); 559ab121c17159a7f655b772fa78c04a6d2479e2a8eSunny Goyal if (!TextUtils.isEmpty(className)) { 560ab121c17159a7f655b772fa78c04a6d2479e2a8eSunny Goyal try { 561ab121c17159a7f655b772fa78c04a6d2479e2a8eSunny Goyal Class<?> cls = Class.forName(className); 562ab121c17159a7f655b772fa78c04a6d2479e2a8eSunny Goyal return (T) cls.getDeclaredConstructor(Context.class).newInstance(context); 563ab121c17159a7f655b772fa78c04a6d2479e2a8eSunny Goyal } catch (ClassNotFoundException | InstantiationException | IllegalAccessException 564ab121c17159a7f655b772fa78c04a6d2479e2a8eSunny Goyal | ClassCastException | NoSuchMethodException | InvocationTargetException e) { 565ab121c17159a7f655b772fa78c04a6d2479e2a8eSunny Goyal Log.e(TAG, "Bad overriden class", e); 566ab121c17159a7f655b772fa78c04a6d2479e2a8eSunny Goyal } 567ab121c17159a7f655b772fa78c04a6d2479e2a8eSunny Goyal } 568ab121c17159a7f655b772fa78c04a6d2479e2a8eSunny Goyal 569ab121c17159a7f655b772fa78c04a6d2479e2a8eSunny Goyal try { 570ab121c17159a7f655b772fa78c04a6d2479e2a8eSunny Goyal return clazz.newInstance(); 571ab121c17159a7f655b772fa78c04a6d2479e2a8eSunny Goyal } catch (InstantiationException|IllegalAccessException e) { 572ab121c17159a7f655b772fa78c04a6d2479e2a8eSunny Goyal throw new RuntimeException(e); 573ab121c17159a7f655b772fa78c04a6d2479e2a8eSunny Goyal } 574ab121c17159a7f655b772fa78c04a6d2479e2a8eSunny Goyal } 575580edcf529b0755f2bba442e97dd02d8cdad3b82Tony Wickham 576580edcf529b0755f2bba442e97dd02d8cdad3b82Tony Wickham /** 577580edcf529b0755f2bba442e97dd02d8cdad3b82Tony Wickham * Returns a HashSet with a single element. We use this instead of Collections.singleton() 578580edcf529b0755f2bba442e97dd02d8cdad3b82Tony Wickham * because HashSet ensures all operations, such as remove, are supported. 579580edcf529b0755f2bba442e97dd02d8cdad3b82Tony Wickham */ 580580edcf529b0755f2bba442e97dd02d8cdad3b82Tony Wickham public static <T> HashSet<T> singletonHashSet(T elem) { 581580edcf529b0755f2bba442e97dd02d8cdad3b82Tony Wickham HashSet<T> hashSet = new HashSet<>(1); 582580edcf529b0755f2bba442e97dd02d8cdad3b82Tony Wickham hashSet.add(elem); 583580edcf529b0755f2bba442e97dd02d8cdad3b82Tony Wickham return hashSet; 584580edcf529b0755f2bba442e97dd02d8cdad3b82Tony Wickham } 58548198d004af64d0d7c8b86bc243087f68dc374c9Mario Bertschler 5863483c52e6bd81b7c37eb0089940e90a6f3e6d80cSunny Goyal /** 5873483c52e6bd81b7c37eb0089940e90a6f3e6d80cSunny Goyal * Utility method to post a runnable on the handler, skipping the synchronization barriers. 5883483c52e6bd81b7c37eb0089940e90a6f3e6d80cSunny Goyal */ 5893483c52e6bd81b7c37eb0089940e90a6f3e6d80cSunny Goyal public static void postAsyncCallback(Handler handler, Runnable callback) { 5903483c52e6bd81b7c37eb0089940e90a6f3e6d80cSunny Goyal Message msg = Message.obtain(handler, callback); 5913483c52e6bd81b7c37eb0089940e90a6f3e6d80cSunny Goyal msg.setAsynchronous(true); 5923483c52e6bd81b7c37eb0089940e90a6f3e6d80cSunny Goyal handler.sendMessage(msg); 5933483c52e6bd81b7c37eb0089940e90a6f3e6d80cSunny Goyal } 59431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project} 595