1d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd/* 2d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Copyright (C) 2015 The Android Open Source Project 3d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * 4d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Licensed under the Apache License, Version 2.0 (the "License"); 5d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * you may not use this file except in compliance with the License. 6d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * You may obtain a copy of the License at 7d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * 8d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * http://www.apache.org/licenses/LICENSE-2.0 9d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * 10d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Unless required by applicable law or agreed to in writing, software 11d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * distributed under the License is distributed on an "AS IS" BASIS, 12d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * See the License for the specific language governing permissions and 14d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * limitations under the License. 15d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 16d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 17d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddpackage com.android.messaging.util; 18d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 19d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.Manifest; 20d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.content.Context; 21d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.content.pm.PackageManager; 22d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.os.Build; 23d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.os.UserHandle; 24d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.os.UserManager; 25d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 26d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.Factory; 27d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 28d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.util.ArrayList; 29d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.util.Hashtable; 30d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.util.Set; 31d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 32d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd/** 33d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Android OS version utilities 34d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 35d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddpublic class OsUtil { 36d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private static boolean sIsAtLeastICS_MR1; 37d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private static boolean sIsAtLeastJB; 38d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private static boolean sIsAtLeastJB_MR1; 39d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private static boolean sIsAtLeastJB_MR2; 40d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private static boolean sIsAtLeastKLP; 41d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private static boolean sIsAtLeastL; 42d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private static boolean sIsAtLeastL_MR1; 43d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private static boolean sIsAtLeastM; 44d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 45d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private static Boolean sIsSecondaryUser = null; 46d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 47d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd static { 48d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final int v = getApiVersion(); 49d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd sIsAtLeastICS_MR1 = v >= android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1; 50d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd sIsAtLeastJB = v >= android.os.Build.VERSION_CODES.JELLY_BEAN; 51d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd sIsAtLeastJB_MR1 = v >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1; 52d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd sIsAtLeastJB_MR2 = v >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR2; 53d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd sIsAtLeastKLP = v >= android.os.Build.VERSION_CODES.KITKAT; 54d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd sIsAtLeastL = v >= android.os.Build.VERSION_CODES.LOLLIPOP; 55d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd sIsAtLeastL_MR1 = v >= android.os.Build.VERSION_CODES.LOLLIPOP_MR1; 56d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd sIsAtLeastM = v >= android.os.Build.VERSION_CODES.M; 57d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 58d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 59d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 60d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * @return True if the version of Android that we're running on is at least Ice Cream Sandwich 61d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * MR1 (API level 15). 62d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 63d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public static boolean isAtLeastICS_MR1() { 64d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return sIsAtLeastICS_MR1; 65d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 66d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 67d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 68d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * @return True if the version of Android that we're running on is at least Jelly Bean 69d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * (API level 16). 70d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 71d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public static boolean isAtLeastJB() { 72d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return sIsAtLeastJB; 73d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 74d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 75d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 76d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * @return True if the version of Android that we're running on is at least Jelly Bean MR1 77d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * (API level 17). 78d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 79d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public static boolean isAtLeastJB_MR1() { 80d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return sIsAtLeastJB_MR1; 81d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 82d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 83d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 84d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * @return True if the version of Android that we're running on is at least Jelly Bean MR2 85d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * (API level 18). 86d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 87d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public static boolean isAtLeastJB_MR2() { 88d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return sIsAtLeastJB_MR2; 89d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 90d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 91d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 92d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * @return True if the version of Android that we're running on is at least KLP 93d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * (API level 19). 94d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 95d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public static boolean isAtLeastKLP() { 96d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return sIsAtLeastKLP; 97d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 98d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 99d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 100d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * @return True if the version of Android that we're running on is at least L 101d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * (API level 21). 102d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 103d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public static boolean isAtLeastL() { 104d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return sIsAtLeastL; 105d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 106d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 107d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 108d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * @return True if the version of Android that we're running on is at least L MR1 109d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * (API level 22). 110d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 111d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public static boolean isAtLeastL_MR1() { 112d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return sIsAtLeastL_MR1; 113d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 114d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 115d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 116d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * @return True if the version of Android that we're running on is at least M 117d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * (API level 23). 118d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 119d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public static boolean isAtLeastM() { 120d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return sIsAtLeastM; 121d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 122d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 123d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 124d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * @return The Android API version of the OS that we're currently running on. 125d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 126d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public static int getApiVersion() { 127d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return android.os.Build.VERSION.SDK_INT; 128d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 129d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 130d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public static boolean isSecondaryUser() { 131d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (sIsSecondaryUser == null) { 132d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final Context context = Factory.get().getApplicationContext(); 133d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd boolean isSecondaryUser = false; 134d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 135d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd // Only check for newer devices (but not the nexus 10) 136d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (OsUtil.sIsAtLeastJB_MR1 && !"Nexus 10".equals(Build.MODEL)) { 137d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final UserHandle uh = android.os.Process.myUserHandle(); 138d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final UserManager userManager = 139d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd (UserManager) context.getSystemService(Context.USER_SERVICE); 140d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (userManager != null) { 141d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final long userSerialNumber = userManager.getSerialNumberForUser(uh); 142d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd isSecondaryUser = (0 != userSerialNumber); 143d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 144d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 145d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd sIsSecondaryUser = isSecondaryUser; 146d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 147d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return sIsSecondaryUser; 148d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 149d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 150d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 151d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Creates a joined string from a Set<String> using the given delimiter. 152d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * @param values 153d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * @param delimiter 154d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * @return 155d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 156d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public static String joinFromSetWithDelimiter( 157d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final Set<String> values, final String delimiter) { 158d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (values != null) { 159d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final StringBuilder joinedStringBuilder = new StringBuilder(); 160d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd boolean firstValue = true; 161d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd for (final String value : values) { 162d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (firstValue) { 163d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd firstValue = false; 164d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } else { 165d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd joinedStringBuilder.append(delimiter); 166d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 167d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd joinedStringBuilder.append(value); 168d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 169d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return joinedStringBuilder.toString(); 170d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 171d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return null; 172d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 173d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 174d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private static Hashtable<String, Integer> sPermissions = new Hashtable<String, Integer>(); 175d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 176d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 177d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Check if the app has the specified permission. If it does not, the app needs to use 178d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * {@link android.app.Activity#requestPermission}. Note that if it 179d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * returns true, it cannot return false in the same process as the OS kills the process when 180d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * any permission is revoked. 181d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * @param permission A permission from {@link android.Manifest.permission} 182d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 183d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public static boolean hasPermission(final String permission) { 184d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (OsUtil.isAtLeastM()) { 185d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd // It is safe to cache the PERMISSION_GRANTED result as the process gets killed if the 186d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd // user revokes the permission setting. However, PERMISSION_DENIED should not be 187d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd // cached as the process does not get killed if the user enables the permission setting. 188d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (!sPermissions.containsKey(permission) 189d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd || sPermissions.get(permission) == PackageManager.PERMISSION_DENIED) { 190d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final Context context = Factory.get().getApplicationContext(); 191d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final int permissionState = context.checkSelfPermission(permission); 192d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd sPermissions.put(permission, permissionState); 193d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 194d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return sPermissions.get(permission) == PackageManager.PERMISSION_GRANTED; 195d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } else { 196d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return true; 197d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 198d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 199d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 200d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** Does the app have all the specified permissions */ 201d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public static boolean hasPermissions(final String[] permissions) { 202d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd for (final String permission : permissions) { 203d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (!hasPermission(permission)) { 204d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return false; 205d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 206d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 207d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return true; 208d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 209d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 210d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public static boolean hasPhonePermission() { 211d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return hasPermission(Manifest.permission.READ_PHONE_STATE); 212d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 213d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 214d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public static boolean hasSmsPermission() { 215d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return hasPermission(Manifest.permission.READ_SMS); 216d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 217d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 218d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public static boolean hasLocationPermission() { 219d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return OsUtil.hasPermission(Manifest.permission.ACCESS_FINE_LOCATION); 220d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 221d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 222d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 223d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public static boolean hasStoragePermission() { 224d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd // Note that READ_EXTERNAL_STORAGE and WRITE_EXTERNAL_STORAGE are granted or denied 225d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd // together. 226d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return OsUtil.hasPermission(Manifest.permission.READ_EXTERNAL_STORAGE); 227d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 228d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 229d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public static boolean hasRecordAudioPermission() { 230d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return OsUtil.hasPermission(Manifest.permission.RECORD_AUDIO); 231d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 232d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 233d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** 234d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Returns array with the set of permissions that have not been granted from the given set. 235d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * The array will be empty if the app has all of the specified permissions. Note that calling 236d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * {@link Activity#requestPermissions} for an already granted permission can prompt the user 237d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * again, and its up to the app to only request permissions that are missing. 238d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */ 239d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public static String[] getMissingPermissions(final String[] permissions) { 240d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final ArrayList<String> missingList = new ArrayList<String>(); 241d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd for (final String permission : permissions) { 242d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd if (!hasPermission(permission)) { 243d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd missingList.add(permission); 244d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 245d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 246d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 247d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd final String[] missingArray = new String[missingList.size()]; 248d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd missingList.toArray(missingArray); 249d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return missingArray; 250d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 251d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 252d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd private static String[] sRequiredPermissions = new String[] { 253d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd // Required to read existing SMS threads 254d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd Manifest.permission.READ_SMS, 255d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd // Required for knowing the phone number, number of SIMs, etc. 256d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd Manifest.permission.READ_PHONE_STATE, 257d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd // This is not strictly required, but simplifies the contact picker scenarios 258d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd Manifest.permission.READ_CONTACTS, 259d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd }; 260d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 261d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd /** Does the app have the minimum set of permissions required to operate. */ 262d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public static boolean hasRequiredPermissions() { 263d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return hasPermissions(sRequiredPermissions); 264d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 265d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd 266d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd public static String[] getMissingRequiredPermissions() { 267d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd return getMissingPermissions(sRequiredPermissions); 268d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd } 269d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd} 270