1 /** 2 * Copyright (C) 2007 Google Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 * use this file except in compliance with the License. You may obtain a copy 6 * 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, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations 14 * under the License. 15 */ 16 17 package com.android.settings; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.app.ActivityManager; 22 import android.app.ActivityManagerNative; 23 import android.app.AlertDialog; 24 import android.app.AppGlobals; 25 import android.app.Dialog; 26 import android.app.Fragment; 27 import android.app.IActivityManager; 28 import android.app.KeyguardManager; 29 import android.app.admin.DevicePolicyManager; 30 import android.content.ComponentName; 31 import android.content.ContentResolver; 32 import android.content.Context; 33 import android.content.DialogInterface; 34 import android.content.Intent; 35 import android.content.IntentFilter; 36 import android.content.pm.ApplicationInfo; 37 import android.content.pm.IPackageManager; 38 import android.content.pm.IntentFilterVerificationInfo; 39 import android.content.pm.PackageManager; 40 import android.content.pm.PackageManager.NameNotFoundException; 41 import android.content.pm.ResolveInfo; 42 import android.content.pm.UserInfo; 43 import android.content.res.Resources; 44 import android.content.res.TypedArray; 45 import android.database.Cursor; 46 import android.graphics.Bitmap; 47 import android.graphics.BitmapFactory; 48 import android.net.ConnectivityManager; 49 import android.net.LinkProperties; 50 import android.net.Uri; 51 import android.os.BatteryManager; 52 import android.os.Bundle; 53 import android.os.IBinder; 54 import android.os.INetworkManagementService; 55 import android.os.Looper; 56 import android.os.RemoteException; 57 import android.os.ServiceManager; 58 import android.os.UserHandle; 59 import android.os.UserManager; 60 import android.os.storage.StorageManager; 61 import android.preference.PreferenceFrameLayout; 62 import android.provider.ContactsContract.CommonDataKinds; 63 import android.provider.ContactsContract.Contacts; 64 import android.provider.ContactsContract.Data; 65 import android.provider.ContactsContract.Profile; 66 import android.provider.ContactsContract.RawContacts; 67 import android.provider.Settings; 68 import android.service.persistentdata.PersistentDataBlockManager; 69 import android.support.v7.preference.Preference; 70 import android.support.v7.preference.PreferenceGroup; 71 import android.support.v7.preference.PreferenceManager; 72 import android.support.v7.preference.PreferenceScreen; 73 import android.telephony.TelephonyManager; 74 import android.text.Spannable; 75 import android.text.SpannableString; 76 import android.text.TextUtils; 77 import android.text.format.DateUtils; 78 import android.text.style.TtsSpan; 79 import android.util.ArraySet; 80 import android.util.Log; 81 import android.util.SparseArray; 82 import android.util.TypedValue; 83 import android.view.LayoutInflater; 84 import android.view.View; 85 import android.view.ViewGroup; 86 import android.view.animation.Animation; 87 import android.view.animation.Animation.AnimationListener; 88 import android.view.animation.AnimationUtils; 89 import android.widget.ListView; 90 import android.widget.TabWidget; 91 import com.android.internal.app.UnlaunchableAppActivity; 92 import com.android.internal.util.ArrayUtils; 93 import com.android.internal.util.UserIcons; 94 import com.android.internal.widget.LockPatternUtils; 95 96 import java.io.IOException; 97 import java.io.InputStream; 98 import java.net.InetAddress; 99 import java.util.ArrayList; 100 import java.util.Iterator; 101 import java.util.List; 102 import java.util.Locale; 103 104 import static android.content.Intent.EXTRA_USER; 105 import static android.content.Intent.EXTRA_USER_ID; 106 import static android.text.format.DateUtils.FORMAT_ABBREV_MONTH; 107 import static android.text.format.DateUtils.FORMAT_SHOW_DATE; 108 109 public final class Utils extends com.android.settingslib.Utils { 110 111 private static final String TAG = "Settings"; 112 113 /** 114 * Set the preference's title to the matching activity's label. 115 */ 116 public static final int UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY = 1; 117 118 /** 119 * The opacity level of a disabled icon. 120 */ 121 public static final float DISABLED_ALPHA = 0.4f; 122 123 /** 124 * Color spectrum to use to indicate badness. 0 is completely transparent (no data), 125 * 1 is most bad (red), the last value is least bad (green). 126 */ 127 public static final int[] BADNESS_COLORS = new int[] { 128 0x00000000, 0xffc43828, 0xffe54918, 0xfff47b00, 129 0xfffabf2c, 0xff679e37, 0xff0a7f42 130 }; 131 132 private static final String SETTINGS_PACKAGE_NAME = "com.android.settings"; 133 134 private static final int SECONDS_PER_MINUTE = 60; 135 private static final int SECONDS_PER_HOUR = 60 * 60; 136 private static final int SECONDS_PER_DAY = 24 * 60 * 60; 137 138 public static final String OS_PKG = "os"; 139 140 private static SparseArray<Bitmap> sDarkDefaultUserBitmapCache = new SparseArray<Bitmap>(); 141 142 /** 143 * Finds a matching activity for a preference's intent. If a matching 144 * activity is not found, it will remove the preference. 145 * 146 * @param context The context. 147 * @param parentPreferenceGroup The preference group that contains the 148 * preference whose intent is being resolved. 149 * @param preferenceKey The key of the preference whose intent is being 150 * resolved. 151 * @param flags 0 or one or more of 152 * {@link #UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY} 153 * . 154 * @return Whether an activity was found. If false, the preference was 155 * removed. 156 */ updatePreferenceToSpecificActivityOrRemove(Context context, PreferenceGroup parentPreferenceGroup, String preferenceKey, int flags)157 public static boolean updatePreferenceToSpecificActivityOrRemove(Context context, 158 PreferenceGroup parentPreferenceGroup, String preferenceKey, int flags) { 159 160 Preference preference = parentPreferenceGroup.findPreference(preferenceKey); 161 if (preference == null) { 162 return false; 163 } 164 165 Intent intent = preference.getIntent(); 166 if (intent != null) { 167 // Find the activity that is in the system image 168 PackageManager pm = context.getPackageManager(); 169 List<ResolveInfo> list = pm.queryIntentActivities(intent, 0); 170 int listSize = list.size(); 171 for (int i = 0; i < listSize; i++) { 172 ResolveInfo resolveInfo = list.get(i); 173 if ((resolveInfo.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) 174 != 0) { 175 176 // Replace the intent with this specific activity 177 preference.setIntent(new Intent().setClassName( 178 resolveInfo.activityInfo.packageName, 179 resolveInfo.activityInfo.name)); 180 181 if ((flags & UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY) != 0) { 182 // Set the preference title to the activity's label 183 preference.setTitle(resolveInfo.loadLabel(pm)); 184 } 185 186 return true; 187 } 188 } 189 } 190 191 // Did not find a matching activity, so remove the preference 192 parentPreferenceGroup.removePreference(preference); 193 194 return false; 195 } 196 197 /** 198 * Returns the UserManager for a given context 199 * 200 * @throws IllegalStateException if no UserManager could be retrieved. 201 */ getUserManager(Context context)202 public static UserManager getUserManager(Context context) { 203 UserManager um = UserManager.get(context); 204 if (um == null) { 205 throw new IllegalStateException("Unable to load UserManager"); 206 } 207 return um; 208 } 209 210 /** 211 * Returns true if Monkey is running. 212 */ isMonkeyRunning()213 public static boolean isMonkeyRunning() { 214 return ActivityManager.isUserAMonkey(); 215 } 216 217 /** 218 * Returns whether the device is voice-capable (meaning, it is also a phone). 219 */ isVoiceCapable(Context context)220 public static boolean isVoiceCapable(Context context) { 221 TelephonyManager telephony = 222 (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); 223 return telephony != null && telephony.isVoiceCapable(); 224 } 225 isWifiOnly(Context context)226 public static boolean isWifiOnly(Context context) { 227 ConnectivityManager cm = (ConnectivityManager)context.getSystemService( 228 Context.CONNECTIVITY_SERVICE); 229 return (cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE) == false); 230 } 231 232 /** 233 * Returns the WIFI IP Addresses, if any, taking into account IPv4 and IPv6 style addresses. 234 * @param context the application context 235 * @return the formatted and newline-separated IP addresses, or null if none. 236 */ getWifiIpAddresses(Context context)237 public static String getWifiIpAddresses(Context context) { 238 ConnectivityManager cm = (ConnectivityManager) 239 context.getSystemService(Context.CONNECTIVITY_SERVICE); 240 LinkProperties prop = cm.getLinkProperties(ConnectivityManager.TYPE_WIFI); 241 return formatIpAddresses(prop); 242 } 243 244 /** 245 * Returns the default link's IP addresses, if any, taking into account IPv4 and IPv6 style 246 * addresses. 247 * @param context the application context 248 * @return the formatted and newline-separated IP addresses, or null if none. 249 */ getDefaultIpAddresses(ConnectivityManager cm)250 public static String getDefaultIpAddresses(ConnectivityManager cm) { 251 LinkProperties prop = cm.getActiveLinkProperties(); 252 return formatIpAddresses(prop); 253 } 254 formatIpAddresses(LinkProperties prop)255 private static String formatIpAddresses(LinkProperties prop) { 256 if (prop == null) return null; 257 Iterator<InetAddress> iter = prop.getAllAddresses().iterator(); 258 // If there are no entries, return null 259 if (!iter.hasNext()) return null; 260 // Concatenate all available addresses, comma separated 261 String addresses = ""; 262 while (iter.hasNext()) { 263 addresses += iter.next().getHostAddress(); 264 if (iter.hasNext()) addresses += "\n"; 265 } 266 return addresses; 267 } 268 createLocaleFromString(String localeStr)269 public static Locale createLocaleFromString(String localeStr) { 270 // TODO: is there a better way to actually construct a locale that will match? 271 // The main problem is, on top of Java specs, locale.toString() and 272 // new Locale(locale.toString()).toString() do not return equal() strings in 273 // many cases, because the constructor takes the only string as the language 274 // code. So : new Locale("en", "US").toString() => "en_US" 275 // And : new Locale("en_US").toString() => "en_us" 276 if (null == localeStr) 277 return Locale.getDefault(); 278 String[] brokenDownLocale = localeStr.split("_", 3); 279 // split may not return a 0-length array. 280 if (1 == brokenDownLocale.length) { 281 return new Locale(brokenDownLocale[0]); 282 } else if (2 == brokenDownLocale.length) { 283 return new Locale(brokenDownLocale[0], brokenDownLocale[1]); 284 } else { 285 return new Locale(brokenDownLocale[0], brokenDownLocale[1], brokenDownLocale[2]); 286 } 287 } 288 isBatteryPresent(Intent batteryChangedIntent)289 public static boolean isBatteryPresent(Intent batteryChangedIntent) { 290 return batteryChangedIntent.getBooleanExtra(BatteryManager.EXTRA_PRESENT, true); 291 } 292 getBatteryPercentage(Intent batteryChangedIntent)293 public static String getBatteryPercentage(Intent batteryChangedIntent) { 294 return formatPercentage(getBatteryLevel(batteryChangedIntent)); 295 } 296 forcePrepareCustomPreferencesList( ViewGroup parent, View child, ListView list, boolean ignoreSidePadding)297 public static void forcePrepareCustomPreferencesList( 298 ViewGroup parent, View child, ListView list, boolean ignoreSidePadding) { 299 list.setScrollBarStyle(View.SCROLLBARS_OUTSIDE_OVERLAY); 300 list.setClipToPadding(false); 301 prepareCustomPreferencesList(parent, child, list, ignoreSidePadding); 302 } 303 304 /** 305 * Prepare a custom preferences layout, moving padding to {@link ListView} 306 * when outside scrollbars are requested. Usually used to display 307 * {@link ListView} and {@link TabWidget} with correct padding. 308 */ prepareCustomPreferencesList( ViewGroup parent, View child, View list, boolean ignoreSidePadding)309 public static void prepareCustomPreferencesList( 310 ViewGroup parent, View child, View list, boolean ignoreSidePadding) { 311 final boolean movePadding = list.getScrollBarStyle() == View.SCROLLBARS_OUTSIDE_OVERLAY; 312 if (movePadding) { 313 final Resources res = list.getResources(); 314 final int paddingSide = res.getDimensionPixelSize(R.dimen.settings_side_margin); 315 final int paddingBottom = res.getDimensionPixelSize( 316 com.android.internal.R.dimen.preference_fragment_padding_bottom); 317 318 if (parent instanceof PreferenceFrameLayout) { 319 ((PreferenceFrameLayout.LayoutParams) child.getLayoutParams()).removeBorders = true; 320 321 final int effectivePaddingSide = ignoreSidePadding ? 0 : paddingSide; 322 list.setPaddingRelative(effectivePaddingSide, 0, effectivePaddingSide, paddingBottom); 323 } else { 324 list.setPaddingRelative(paddingSide, 0, paddingSide, paddingBottom); 325 } 326 } 327 } 328 forceCustomPadding(View view, boolean additive)329 public static void forceCustomPadding(View view, boolean additive) { 330 final Resources res = view.getResources(); 331 final int paddingSide = res.getDimensionPixelSize(R.dimen.settings_side_margin); 332 333 final int paddingStart = paddingSide + (additive ? view.getPaddingStart() : 0); 334 final int paddingEnd = paddingSide + (additive ? view.getPaddingEnd() : 0); 335 final int paddingBottom = res.getDimensionPixelSize( 336 com.android.internal.R.dimen.preference_fragment_padding_bottom); 337 338 view.setPaddingRelative(paddingStart, 0, paddingEnd, paddingBottom); 339 } 340 341 /* Used by UserSettings as well. Call this on a non-ui thread. */ copyMeProfilePhoto(Context context, UserInfo user)342 public static void copyMeProfilePhoto(Context context, UserInfo user) { 343 Uri contactUri = Profile.CONTENT_URI; 344 345 int userId = user != null ? user.id : UserHandle.myUserId(); 346 347 InputStream avatarDataStream = Contacts.openContactPhotoInputStream( 348 context.getContentResolver(), 349 contactUri, true); 350 // If there's no profile photo, assign a default avatar 351 if (avatarDataStream == null) { 352 assignDefaultPhoto(context, userId); 353 return; 354 } 355 356 UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE); 357 Bitmap icon = BitmapFactory.decodeStream(avatarDataStream); 358 um.setUserIcon(userId, icon); 359 try { 360 avatarDataStream.close(); 361 } catch (IOException ioe) { } 362 } 363 assignDefaultPhoto(Context context, int userId)364 public static void assignDefaultPhoto(Context context, int userId) { 365 UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE); 366 Bitmap bitmap = getDefaultUserIconAsBitmap(userId); 367 um.setUserIcon(userId, bitmap); 368 } 369 getMeProfileName(Context context, boolean full)370 public static String getMeProfileName(Context context, boolean full) { 371 if (full) { 372 return getProfileDisplayName(context); 373 } else { 374 return getShorterNameIfPossible(context); 375 } 376 } 377 getShorterNameIfPossible(Context context)378 private static String getShorterNameIfPossible(Context context) { 379 final String given = getLocalProfileGivenName(context); 380 return !TextUtils.isEmpty(given) ? given : getProfileDisplayName(context); 381 } 382 getLocalProfileGivenName(Context context)383 private static String getLocalProfileGivenName(Context context) { 384 final ContentResolver cr = context.getContentResolver(); 385 386 // Find the raw contact ID for the local ME profile raw contact. 387 final long localRowProfileId; 388 final Cursor localRawProfile = cr.query( 389 Profile.CONTENT_RAW_CONTACTS_URI, 390 new String[] {RawContacts._ID}, 391 RawContacts.ACCOUNT_TYPE + " IS NULL AND " + 392 RawContacts.ACCOUNT_NAME + " IS NULL", 393 null, null); 394 if (localRawProfile == null) return null; 395 396 try { 397 if (!localRawProfile.moveToFirst()) { 398 return null; 399 } 400 localRowProfileId = localRawProfile.getLong(0); 401 } finally { 402 localRawProfile.close(); 403 } 404 405 // Find the structured name for the raw contact. 406 final Cursor structuredName = cr.query( 407 Profile.CONTENT_URI.buildUpon().appendPath(Contacts.Data.CONTENT_DIRECTORY).build(), 408 new String[] {CommonDataKinds.StructuredName.GIVEN_NAME, 409 CommonDataKinds.StructuredName.FAMILY_NAME}, 410 Data.RAW_CONTACT_ID + "=" + localRowProfileId, 411 null, null); 412 if (structuredName == null) return null; 413 414 try { 415 if (!structuredName.moveToFirst()) { 416 return null; 417 } 418 String partialName = structuredName.getString(0); 419 if (TextUtils.isEmpty(partialName)) { 420 partialName = structuredName.getString(1); 421 } 422 return partialName; 423 } finally { 424 structuredName.close(); 425 } 426 } 427 getProfileDisplayName(Context context)428 private static final String getProfileDisplayName(Context context) { 429 final ContentResolver cr = context.getContentResolver(); 430 final Cursor profile = cr.query(Profile.CONTENT_URI, 431 new String[] {Profile.DISPLAY_NAME}, null, null, null); 432 if (profile == null) return null; 433 434 try { 435 if (!profile.moveToFirst()) { 436 return null; 437 } 438 return profile.getString(0); 439 } finally { 440 profile.close(); 441 } 442 } 443 444 /** Not global warming, it's global change warning. */ buildGlobalChangeWarningDialog(final Context context, int titleResId, final Runnable positiveAction)445 public static Dialog buildGlobalChangeWarningDialog(final Context context, int titleResId, 446 final Runnable positiveAction) { 447 final AlertDialog.Builder builder = new AlertDialog.Builder(context); 448 builder.setTitle(titleResId); 449 builder.setMessage(R.string.global_change_warning); 450 builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { 451 @Override 452 public void onClick(DialogInterface dialog, int which) { 453 positiveAction.run(); 454 } 455 }); 456 builder.setNegativeButton(android.R.string.cancel, null); 457 458 return builder.create(); 459 } 460 hasMultipleUsers(Context context)461 public static boolean hasMultipleUsers(Context context) { 462 return ((UserManager) context.getSystemService(Context.USER_SERVICE)) 463 .getUsers().size() > 1; 464 } 465 466 /** 467 * Start a new instance of the activity, showing only the given fragment. 468 * When launched in this mode, the given preference fragment will be instantiated and fill the 469 * entire activity. 470 * 471 * @param context The context. 472 * @param fragmentName The name of the fragment to display. 473 * @param args Optional arguments to supply to the fragment. 474 * @param resultTo Option fragment that should receive the result of the activity launch. 475 * @param resultRequestCode If resultTo is non-null, this is the request code in which 476 * to report the result. 477 * @param titleResId resource id for the String to display for the title of this set 478 * of preferences. 479 * @param title String to display for the title of this set of preferences. 480 */ startWithFragment(Context context, String fragmentName, Bundle args, Fragment resultTo, int resultRequestCode, int titleResId, CharSequence title)481 public static void startWithFragment(Context context, String fragmentName, Bundle args, 482 Fragment resultTo, int resultRequestCode, int titleResId, 483 CharSequence title) { 484 startWithFragment(context, fragmentName, args, resultTo, resultRequestCode, 485 null /* titleResPackageName */, titleResId, title, false /* not a shortcut */); 486 } 487 488 /** 489 * Start a new instance of the activity, showing only the given fragment. 490 * When launched in this mode, the given preference fragment will be instantiated and fill the 491 * entire activity. 492 * 493 * @param context The context. 494 * @param fragmentName The name of the fragment to display. 495 * @param args Optional arguments to supply to the fragment. 496 * @param resultTo Option fragment that should receive the result of the activity launch. 497 * @param resultRequestCode If resultTo is non-null, this is the request code in which 498 * to report the result. 499 * @param titleResPackageName Optional package name for the resource id of the title. 500 * @param titleResId resource id for the String to display for the title of this set 501 * of preferences. 502 * @param title String to display for the title of this set of preferences. 503 */ startWithFragment(Context context, String fragmentName, Bundle args, Fragment resultTo, int resultRequestCode, String titleResPackageName, int titleResId, CharSequence title)504 public static void startWithFragment(Context context, String fragmentName, Bundle args, 505 Fragment resultTo, int resultRequestCode, String titleResPackageName, int titleResId, 506 CharSequence title) { 507 startWithFragment(context, fragmentName, args, resultTo, resultRequestCode, 508 titleResPackageName, titleResId, title, false /* not a shortcut */); 509 } 510 startWithFragment(Context context, String fragmentName, Bundle args, Fragment resultTo, int resultRequestCode, int titleResId, CharSequence title, boolean isShortcut)511 public static void startWithFragment(Context context, String fragmentName, Bundle args, 512 Fragment resultTo, int resultRequestCode, int titleResId, 513 CharSequence title, boolean isShortcut) { 514 Intent intent = onBuildStartFragmentIntent(context, fragmentName, args, 515 null /* titleResPackageName */, titleResId, title, isShortcut); 516 if (resultTo == null) { 517 context.startActivity(intent); 518 } else { 519 resultTo.getActivity().startActivityForResult(intent, resultRequestCode); 520 } 521 } 522 startWithFragment(Context context, String fragmentName, Bundle args, Fragment resultTo, int resultRequestCode, String titleResPackageName, int titleResId, CharSequence title, boolean isShortcut)523 public static void startWithFragment(Context context, String fragmentName, Bundle args, 524 Fragment resultTo, int resultRequestCode, String titleResPackageName, int titleResId, 525 CharSequence title, boolean isShortcut) { 526 Intent intent = onBuildStartFragmentIntent(context, fragmentName, args, titleResPackageName, 527 titleResId, title, isShortcut); 528 if (resultTo == null) { 529 context.startActivity(intent); 530 } else { 531 resultTo.startActivityForResult(intent, resultRequestCode); 532 } 533 } 534 startWithFragmentAsUser(Context context, String fragmentName, Bundle args, int titleResId, CharSequence title, boolean isShortcut, UserHandle userHandle)535 public static void startWithFragmentAsUser(Context context, String fragmentName, Bundle args, 536 int titleResId, CharSequence title, boolean isShortcut, 537 UserHandle userHandle) { 538 // workaround to avoid crash in b/17523189 539 if (userHandle.getIdentifier() == UserHandle.myUserId()) { 540 startWithFragment(context, fragmentName, args, null, 0, titleResId, title, isShortcut); 541 } else { 542 Intent intent = onBuildStartFragmentIntent(context, fragmentName, args, 543 null /* titleResPackageName */, titleResId, title, isShortcut); 544 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 545 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); 546 context.startActivityAsUser(intent, userHandle); 547 } 548 } 549 startWithFragmentAsUser(Context context, String fragmentName, Bundle args, String titleResPackageName, int titleResId, CharSequence title, boolean isShortcut, UserHandle userHandle)550 public static void startWithFragmentAsUser(Context context, String fragmentName, Bundle args, 551 String titleResPackageName, int titleResId, CharSequence title, boolean isShortcut, 552 UserHandle userHandle) { 553 // workaround to avoid crash in b/17523189 554 if (userHandle.getIdentifier() == UserHandle.myUserId()) { 555 startWithFragment(context, fragmentName, args, null, 0, titleResPackageName, titleResId, 556 title, isShortcut); 557 } else { 558 Intent intent = onBuildStartFragmentIntent(context, fragmentName, args, 559 titleResPackageName, titleResId, title, isShortcut); 560 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 561 intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); 562 context.startActivityAsUser(intent, userHandle); 563 } 564 } 565 566 /** 567 * Build an Intent to launch a new activity showing the selected fragment. 568 * The implementation constructs an Intent that re-launches the current activity with the 569 * appropriate arguments to display the fragment. 570 * 571 * 572 * @param context The Context. 573 * @param fragmentName The name of the fragment to display. 574 * @param args Optional arguments to supply to the fragment. 575 * @param titleResPackageName Optional package name for the resource id of the title. 576 * @param titleResId Optional title resource id to show for this item. 577 * @param title Optional title to show for this item. 578 * @param isShortcut tell if this is a Launcher Shortcut or not 579 * @return Returns an Intent that can be launched to display the given 580 * fragment. 581 */ onBuildStartFragmentIntent(Context context, String fragmentName, Bundle args, String titleResPackageName, int titleResId, CharSequence title, boolean isShortcut)582 public static Intent onBuildStartFragmentIntent(Context context, String fragmentName, 583 Bundle args, String titleResPackageName, int titleResId, CharSequence title, 584 boolean isShortcut) { 585 Intent intent = new Intent(Intent.ACTION_MAIN); 586 intent.setClass(context, SubSettings.class); 587 intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT, fragmentName); 588 intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS, args); 589 intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE_RES_PACKAGE_NAME, 590 titleResPackageName); 591 intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE_RESID, titleResId); 592 intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE, title); 593 intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_AS_SHORTCUT, isShortcut); 594 return intent; 595 } 596 597 /** 598 * Returns the managed profile of the current user or null if none found. 599 */ getManagedProfile(UserManager userManager)600 public static UserHandle getManagedProfile(UserManager userManager) { 601 List<UserHandle> userProfiles = userManager.getUserProfiles(); 602 final int count = userProfiles.size(); 603 for (int i = 0; i < count; i++) { 604 final UserHandle profile = userProfiles.get(i); 605 if (profile.getIdentifier() == userManager.getUserHandle()) { 606 continue; 607 } 608 final UserInfo userInfo = userManager.getUserInfo(profile.getIdentifier()); 609 if (userInfo.isManagedProfile()) { 610 return profile; 611 } 612 } 613 return null; 614 } 615 616 /** 617 * Returns true if the current profile is a managed one. 618 * 619 * @throws IllegalArgumentException if userManager is null. 620 */ isManagedProfile(@onNull UserManager userManager)621 public static boolean isManagedProfile(@NonNull UserManager userManager) { 622 return isManagedProfile(userManager, UserHandle.myUserId()); 623 } 624 625 /** 626 * Retrieves the id for the given user's managed profile. 627 * 628 * @return the managed profile id or UserHandle.USER_NULL if there is none. 629 */ getManagedProfileId(UserManager um, int parentUserId)630 public static int getManagedProfileId(UserManager um, int parentUserId) { 631 int[] profileIds = um.getProfileIdsWithDisabled(parentUserId); 632 for (int profileId : profileIds) { 633 if (profileId != parentUserId) { 634 return profileId; 635 } 636 } 637 return UserHandle.USER_NULL; 638 } 639 640 /** 641 * Returns true if the userId passed in is a managed profile. 642 * 643 * @throws IllegalArgumentException if userManager is null. 644 */ isManagedProfile(@onNull UserManager userManager, int userId)645 public static boolean isManagedProfile(@NonNull UserManager userManager, int userId) { 646 if (userManager == null) { 647 throw new IllegalArgumentException("userManager must not be null"); 648 } 649 UserInfo userInfo = userManager.getUserInfo(userId); 650 return (userInfo != null) ? userInfo.isManagedProfile() : false; 651 } 652 653 /** 654 * Returns the target user for a Settings activity. 655 * <p> 656 * User would be retrieved in this order: 657 * <ul> 658 * <li> If this activity is launched from other user, return that user id. 659 * <li> If this is launched from the Settings app in same user, return the user contained as an 660 * extra in the arguments or intent extras. 661 * <li> Otherwise, return UserHandle.myUserId(). 662 * </ul> 663 * <p> 664 * Note: This is secure in the sense that it only returns a target user different to the current 665 * one if the app launching this activity is the Settings app itself, running in the same user 666 * or in one that is in the same profile group, or if the user id is provided by the system. 667 */ getSecureTargetUser(IBinder activityToken, UserManager um, @Nullable Bundle arguments, @Nullable Bundle intentExtras)668 public static UserHandle getSecureTargetUser(IBinder activityToken, 669 UserManager um, @Nullable Bundle arguments, @Nullable Bundle intentExtras) { 670 UserHandle currentUser = new UserHandle(UserHandle.myUserId()); 671 IActivityManager am = ActivityManagerNative.getDefault(); 672 try { 673 String launchedFromPackage = am.getLaunchedFromPackage(activityToken); 674 boolean launchedFromSettingsApp = SETTINGS_PACKAGE_NAME.equals(launchedFromPackage); 675 676 UserHandle launchedFromUser = new UserHandle(UserHandle.getUserId( 677 am.getLaunchedFromUid(activityToken))); 678 if (launchedFromUser != null && !launchedFromUser.equals(currentUser)) { 679 // Check it's secure 680 if (isProfileOf(um, launchedFromUser)) { 681 return launchedFromUser; 682 } 683 } 684 UserHandle extrasUser = getUserHandleFromBundle(intentExtras); 685 if (extrasUser != null && !extrasUser.equals(currentUser)) { 686 // Check it's secure 687 if (launchedFromSettingsApp && isProfileOf(um, extrasUser)) { 688 return extrasUser; 689 } 690 } 691 UserHandle argumentsUser = getUserHandleFromBundle(arguments); 692 if (argumentsUser != null && !argumentsUser.equals(currentUser)) { 693 // Check it's secure 694 if (launchedFromSettingsApp && isProfileOf(um, argumentsUser)) { 695 return argumentsUser; 696 } 697 } 698 } catch (RemoteException e) { 699 // Should not happen 700 Log.v(TAG, "Could not talk to activity manager.", e); 701 } 702 return currentUser; 703 } 704 705 /** 706 * Lookup both {@link Intent#EXTRA_USER} and {@link Intent#EXTRA_USER_ID} in the bundle 707 * and return the {@link UserHandle} object. Return {@code null} if nothing is found. 708 */ getUserHandleFromBundle(Bundle bundle)709 private static @Nullable UserHandle getUserHandleFromBundle(Bundle bundle) { 710 if (bundle == null) { 711 return null; 712 } 713 final UserHandle user = bundle.getParcelable(EXTRA_USER); 714 if (user != null) { 715 return user; 716 } 717 final int userId = bundle.getInt(EXTRA_USER_ID, -1); 718 if (userId != -1) { 719 return UserHandle.of(userId); 720 } 721 return null; 722 } 723 724 /** 725 * Returns the target user for a Settings activity. 726 * 727 * The target user can be either the current user, the user that launched this activity or 728 * the user contained as an extra in the arguments or intent extras. 729 * 730 * You should use {@link #getSecureTargetUser(IBinder, UserManager, Bundle, Bundle)} if 731 * possible. 732 * 733 * @see #getInsecureTargetUser(IBinder, Bundle, Bundle) 734 */ getInsecureTargetUser(IBinder activityToken, @Nullable Bundle arguments, @Nullable Bundle intentExtras)735 public static UserHandle getInsecureTargetUser(IBinder activityToken, @Nullable Bundle arguments, 736 @Nullable Bundle intentExtras) { 737 UserHandle currentUser = new UserHandle(UserHandle.myUserId()); 738 IActivityManager am = ActivityManagerNative.getDefault(); 739 try { 740 UserHandle launchedFromUser = new UserHandle(UserHandle.getUserId( 741 am.getLaunchedFromUid(activityToken))); 742 if (launchedFromUser != null && !launchedFromUser.equals(currentUser)) { 743 return launchedFromUser; 744 } 745 UserHandle extrasUser = intentExtras != null 746 ? (UserHandle) intentExtras.getParcelable(EXTRA_USER) : null; 747 if (extrasUser != null && !extrasUser.equals(currentUser)) { 748 return extrasUser; 749 } 750 UserHandle argumentsUser = arguments != null 751 ? (UserHandle) arguments.getParcelable(EXTRA_USER) : null; 752 if (argumentsUser != null && !argumentsUser.equals(currentUser)) { 753 return argumentsUser; 754 } 755 } catch (RemoteException e) { 756 // Should not happen 757 Log.v(TAG, "Could not talk to activity manager.", e); 758 return null; 759 } 760 return currentUser; 761 } 762 763 /** 764 * Returns true if the user provided is in the same profiles group as the current user. 765 */ isProfileOf(UserManager um, UserHandle otherUser)766 private static boolean isProfileOf(UserManager um, UserHandle otherUser) { 767 if (um == null || otherUser == null) return false; 768 return (UserHandle.myUserId() == otherUser.getIdentifier()) 769 || um.getUserProfiles().contains(otherUser); 770 } 771 772 773 /** 774 * Returns whether or not this device is able to be OEM unlocked. 775 */ isOemUnlockEnabled(Context context)776 static boolean isOemUnlockEnabled(Context context) { 777 PersistentDataBlockManager manager =(PersistentDataBlockManager) 778 context.getSystemService(Context.PERSISTENT_DATA_BLOCK_SERVICE); 779 return manager.getOemUnlockEnabled(); 780 } 781 782 /** 783 * Allows enabling or disabling OEM unlock on this device. OEM unlocked 784 * devices allow users to flash other OSes to them. 785 */ setOemUnlockEnabled(Context context, boolean enabled)786 static void setOemUnlockEnabled(Context context, boolean enabled) { 787 try { 788 PersistentDataBlockManager manager = (PersistentDataBlockManager) 789 context.getSystemService(Context.PERSISTENT_DATA_BLOCK_SERVICE); 790 manager.setOemUnlockEnabled(enabled); 791 } catch (SecurityException e) { 792 Log.e(TAG, "Fail to set oem unlock.", e); 793 } 794 } 795 796 /** 797 * Return whether or not the user should have a SIM Cards option in Settings. 798 * TODO: Change back to returning true if count is greater than one after testing. 799 * TODO: See bug 16533525. 800 */ showSimCardTile(Context context)801 public static boolean showSimCardTile(Context context) { 802 final TelephonyManager tm = 803 (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); 804 805 return tm.getSimCount() > 1; 806 } 807 808 /** 809 * Returns elapsed time for the given millis, in the following format: 810 * 2d 5h 40m 29s 811 * @param context the application context 812 * @param millis the elapsed time in milli seconds 813 * @param withSeconds include seconds? 814 * @return the formatted elapsed time 815 */ formatElapsedTime(Context context, double millis, boolean withSeconds)816 public static String formatElapsedTime(Context context, double millis, boolean withSeconds) { 817 StringBuilder sb = new StringBuilder(); 818 int seconds = (int) Math.floor(millis / 1000); 819 if (!withSeconds) { 820 // Round up. 821 seconds += 30; 822 } 823 824 int days = 0, hours = 0, minutes = 0; 825 if (seconds >= SECONDS_PER_DAY) { 826 days = seconds / SECONDS_PER_DAY; 827 seconds -= days * SECONDS_PER_DAY; 828 } 829 if (seconds >= SECONDS_PER_HOUR) { 830 hours = seconds / SECONDS_PER_HOUR; 831 seconds -= hours * SECONDS_PER_HOUR; 832 } 833 if (seconds >= SECONDS_PER_MINUTE) { 834 minutes = seconds / SECONDS_PER_MINUTE; 835 seconds -= minutes * SECONDS_PER_MINUTE; 836 } 837 if (withSeconds) { 838 if (days > 0) { 839 sb.append(context.getString(R.string.battery_history_days, 840 days, hours, minutes, seconds)); 841 } else if (hours > 0) { 842 sb.append(context.getString(R.string.battery_history_hours, 843 hours, minutes, seconds)); 844 } else if (minutes > 0) { 845 sb.append(context.getString(R.string.battery_history_minutes, minutes, seconds)); 846 } else { 847 sb.append(context.getString(R.string.battery_history_seconds, seconds)); 848 } 849 } else { 850 if (days > 0) { 851 sb.append(context.getString(R.string.battery_history_days_no_seconds, 852 days, hours, minutes)); 853 } else if (hours > 0) { 854 sb.append(context.getString(R.string.battery_history_hours_no_seconds, 855 hours, minutes)); 856 } else { 857 sb.append(context.getString(R.string.battery_history_minutes_no_seconds, minutes)); 858 } 859 } 860 return sb.toString(); 861 } 862 863 /** 864 * Queries for the UserInfo of a user. Returns null if the user doesn't exist (was removed). 865 * @param userManager Instance of UserManager 866 * @param checkUser The user to check the existence of. 867 * @return UserInfo of the user or null for non-existent user. 868 */ getExistingUser(UserManager userManager, UserHandle checkUser)869 public static UserInfo getExistingUser(UserManager userManager, UserHandle checkUser) { 870 final List<UserInfo> users = userManager.getUsers(true /* excludeDying */); 871 final int checkUserId = checkUser.getIdentifier(); 872 for (UserInfo user : users) { 873 if (user.id == checkUserId) { 874 return user; 875 } 876 } 877 return null; 878 } 879 inflateCategoryHeader(LayoutInflater inflater, ViewGroup parent)880 public static View inflateCategoryHeader(LayoutInflater inflater, ViewGroup parent) { 881 final TypedArray a = inflater.getContext().obtainStyledAttributes(null, 882 com.android.internal.R.styleable.Preference, 883 com.android.internal.R.attr.preferenceCategoryStyle, 0); 884 final int resId = a.getResourceId(com.android.internal.R.styleable.Preference_layout, 885 0); 886 a.recycle(); 887 return inflater.inflate(resId, parent, false); 888 } 889 890 /** 891 * Return if we are running low on storage space or not. 892 * 893 * @param context The context 894 * @return true if we are running low on storage space 895 */ isLowStorage(Context context)896 public static boolean isLowStorage(Context context) { 897 final StorageManager sm = StorageManager.from(context); 898 return (sm.getStorageBytesUntilLow(context.getFilesDir()) < 0); 899 } 900 901 /** 902 * Returns a default user icon (as a {@link Bitmap}) for the given user. 903 * 904 * Note that for guest users, you should pass in {@code UserHandle.USER_NULL}. 905 * @param userId the user id or {@code UserHandle.USER_NULL} for a non-user specific icon 906 */ getDefaultUserIconAsBitmap(int userId)907 public static Bitmap getDefaultUserIconAsBitmap(int userId) { 908 Bitmap bitmap = null; 909 // Try finding the corresponding bitmap in the dark bitmap cache 910 bitmap = sDarkDefaultUserBitmapCache.get(userId); 911 if (bitmap == null) { 912 bitmap = UserIcons.convertToBitmap(UserIcons.getDefaultUserIcon(userId, false)); 913 // Save it to cache 914 sDarkDefaultUserBitmapCache.put(userId, bitmap); 915 } 916 return bitmap; 917 } 918 hasPreferredActivities(PackageManager pm, String packageName)919 public static boolean hasPreferredActivities(PackageManager pm, String packageName) { 920 // Get list of preferred activities 921 List<ComponentName> prefActList = new ArrayList<>(); 922 // Intent list cannot be null. so pass empty list 923 List<IntentFilter> intentList = new ArrayList<>(); 924 pm.getPreferredActivities(intentList, prefActList, packageName); 925 Log.d(TAG, "Have " + prefActList.size() + " number of activities in preferred list"); 926 return prefActList.size() > 0; 927 } 928 getHandledDomains(PackageManager pm, String packageName)929 public static ArraySet<String> getHandledDomains(PackageManager pm, String packageName) { 930 List<IntentFilterVerificationInfo> iviList = pm.getIntentFilterVerifications(packageName); 931 List<IntentFilter> filters = pm.getAllIntentFilters(packageName); 932 933 ArraySet<String> result = new ArraySet<>(); 934 if (iviList.size() > 0) { 935 for (IntentFilterVerificationInfo ivi : iviList) { 936 for (String host : ivi.getDomains()) { 937 result.add(host); 938 } 939 } 940 } 941 if (filters != null && filters.size() > 0) { 942 for (IntentFilter filter : filters) { 943 if (filter.hasCategory(Intent.CATEGORY_BROWSABLE) 944 && (filter.hasDataScheme(IntentFilter.SCHEME_HTTP) || 945 filter.hasDataScheme(IntentFilter.SCHEME_HTTPS))) { 946 result.addAll(filter.getHostsList()); 947 } 948 } 949 } 950 return result; 951 } 952 handleLoadingContainer(View loading, View doneLoading, boolean done, boolean animate)953 public static void handleLoadingContainer(View loading, View doneLoading, boolean done, 954 boolean animate) { 955 setViewShown(loading, !done, animate); 956 setViewShown(doneLoading, done, animate); 957 } 958 setViewShown(final View view, boolean shown, boolean animate)959 private static void setViewShown(final View view, boolean shown, boolean animate) { 960 if (animate) { 961 Animation animation = AnimationUtils.loadAnimation(view.getContext(), 962 shown ? android.R.anim.fade_in : android.R.anim.fade_out); 963 if (shown) { 964 view.setVisibility(View.VISIBLE); 965 } else { 966 animation.setAnimationListener(new AnimationListener() { 967 @Override 968 public void onAnimationStart(Animation animation) { 969 } 970 971 @Override 972 public void onAnimationRepeat(Animation animation) { 973 } 974 975 @Override 976 public void onAnimationEnd(Animation animation) { 977 view.setVisibility(View.INVISIBLE); 978 } 979 }); 980 } 981 view.startAnimation(animation); 982 } else { 983 view.clearAnimation(); 984 view.setVisibility(shown ? View.VISIBLE : View.INVISIBLE); 985 } 986 } 987 988 /** 989 * Returns the application info of the currently installed MDM package. 990 */ getAdminApplicationInfo(Context context, int profileId)991 public static ApplicationInfo getAdminApplicationInfo(Context context, int profileId) { 992 DevicePolicyManager dpm = 993 (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE); 994 ComponentName mdmPackage = dpm.getProfileOwnerAsUser(profileId); 995 if (mdmPackage == null) { 996 return null; 997 } 998 String mdmPackageName = mdmPackage.getPackageName(); 999 try { 1000 IPackageManager ipm = AppGlobals.getPackageManager(); 1001 ApplicationInfo mdmApplicationInfo = 1002 ipm.getApplicationInfo(mdmPackageName, 0, profileId); 1003 return mdmApplicationInfo; 1004 } catch (RemoteException e) { 1005 Log.e(TAG, "Error while retrieving application info for package " + mdmPackageName 1006 + ", userId " + profileId, e); 1007 return null; 1008 } 1009 } 1010 isBandwidthControlEnabled()1011 public static boolean isBandwidthControlEnabled() { 1012 final INetworkManagementService netManager = INetworkManagementService.Stub 1013 .asInterface(ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE)); 1014 try { 1015 return netManager.isBandwidthControlEnabled(); 1016 } catch (RemoteException e) { 1017 return false; 1018 } 1019 } 1020 1021 /** 1022 * Returns an accessible SpannableString. 1023 * @param displayText the text to display 1024 * @param accessibileText the text text-to-speech engines should read 1025 */ createAccessibleSequence(CharSequence displayText, String accessibileText)1026 public static SpannableString createAccessibleSequence(CharSequence displayText, 1027 String accessibileText) { 1028 SpannableString str = new SpannableString(displayText); 1029 str.setSpan(new TtsSpan.TextBuilder(accessibileText).build(), 0, 1030 displayText.length(), 1031 Spannable.SPAN_INCLUSIVE_INCLUSIVE); 1032 return str; 1033 } 1034 1035 /** 1036 * Returns the user id present in the bundle with {@link Intent#EXTRA_USER_ID} if it 1037 * belongs to the current user. 1038 * 1039 * @throws SecurityException if the given userId does not belong to the current user group. 1040 */ getUserIdFromBundle(Context context, Bundle bundle)1041 public static int getUserIdFromBundle(Context context, Bundle bundle) { 1042 if (bundle == null) { 1043 return getCredentialOwnerUserId(context); 1044 } 1045 int userId = bundle.getInt(Intent.EXTRA_USER_ID, UserHandle.myUserId()); 1046 return enforceSameOwner(context, userId); 1047 } 1048 1049 /** 1050 * Returns the given user id if it belongs to the current user. 1051 * 1052 * @throws SecurityException if the given userId does not belong to the current user group. 1053 */ enforceSameOwner(Context context, int userId)1054 public static int enforceSameOwner(Context context, int userId) { 1055 final UserManager um = getUserManager(context); 1056 final int[] profileIds = um.getProfileIdsWithDisabled(UserHandle.myUserId()); 1057 if (ArrayUtils.contains(profileIds, userId)) { 1058 return userId; 1059 } 1060 throw new SecurityException("Given user id " + userId + " does not belong to user " 1061 + UserHandle.myUserId()); 1062 } 1063 1064 /** 1065 * Returns the effective credential owner of the calling user. 1066 */ getCredentialOwnerUserId(Context context)1067 public static int getCredentialOwnerUserId(Context context) { 1068 return getCredentialOwnerUserId(context, UserHandle.myUserId()); 1069 } 1070 1071 /** 1072 * Returns the user id of the credential owner of the given user id. 1073 */ getCredentialOwnerUserId(Context context, int userId)1074 public static int getCredentialOwnerUserId(Context context, int userId) { 1075 UserManager um = getUserManager(context); 1076 return um.getCredentialOwnerProfile(userId); 1077 } 1078 resolveResource(Context context, int attr)1079 public static int resolveResource(Context context, int attr) { 1080 TypedValue value = new TypedValue(); 1081 context.getTheme().resolveAttribute(attr, value, true); 1082 return value.resourceId; 1083 } 1084 1085 private static final StringBuilder sBuilder = new StringBuilder(50); 1086 private static final java.util.Formatter sFormatter = new java.util.Formatter( 1087 sBuilder, Locale.getDefault()); 1088 formatDateRange(Context context, long start, long end)1089 public static String formatDateRange(Context context, long start, long end) { 1090 final int flags = FORMAT_SHOW_DATE | FORMAT_ABBREV_MONTH; 1091 1092 synchronized (sBuilder) { 1093 sBuilder.setLength(0); 1094 return DateUtils.formatDateRange(context, sFormatter, start, end, flags, null) 1095 .toString(); 1096 } 1097 } 1098 getNonIndexable(int xml, Context context)1099 public static List<String> getNonIndexable(int xml, Context context) { 1100 if (Looper.myLooper() == null) { 1101 // Hack to make sure Preferences can initialize. Prefs expect a looper, but 1102 // don't actually use it for the basic stuff here. 1103 Looper.prepare(); 1104 } 1105 final List<String> ret = new ArrayList<>(); 1106 PreferenceManager manager = new PreferenceManager(context); 1107 PreferenceScreen screen = manager.inflateFromResource(context, xml, null); 1108 checkPrefs(screen, ret); 1109 1110 return ret; 1111 } 1112 checkPrefs(PreferenceGroup group, List<String> ret)1113 private static void checkPrefs(PreferenceGroup group, List<String> ret) { 1114 if (group == null) return; 1115 for (int i = 0; i < group.getPreferenceCount(); i++) { 1116 Preference pref = group.getPreference(i); 1117 if (pref instanceof SelfAvailablePreference 1118 && !((SelfAvailablePreference) pref).isAvailable(group.getContext())) { 1119 ret.add(pref.getKey()); 1120 if (pref instanceof PreferenceGroup) { 1121 addAll((PreferenceGroup) pref, ret); 1122 } 1123 } else if (pref instanceof PreferenceGroup) { 1124 checkPrefs((PreferenceGroup) pref, ret); 1125 } 1126 } 1127 } 1128 addAll(PreferenceGroup group, List<String> ret)1129 private static void addAll(PreferenceGroup group, List<String> ret) { 1130 if (group == null) return; 1131 for (int i = 0; i < group.getPreferenceCount(); i++) { 1132 Preference pref = group.getPreference(i); 1133 ret.add(pref.getKey()); 1134 if (pref instanceof PreferenceGroup) { 1135 addAll((PreferenceGroup) pref, ret); 1136 } 1137 } 1138 } 1139 isDeviceProvisioned(Context context)1140 public static boolean isDeviceProvisioned(Context context) { 1141 return Settings.Global.getInt(context.getContentResolver(), 1142 Settings.Global.DEVICE_PROVISIONED, 0) != 0; 1143 } 1144 startQuietModeDialogIfNecessary(Context context, UserManager um, int userId)1145 public static boolean startQuietModeDialogIfNecessary(Context context, UserManager um, 1146 int userId) { 1147 if (um.isQuietModeEnabled(UserHandle.of(userId))) { 1148 final Intent intent = UnlaunchableAppActivity.createInQuietModeDialogIntent(userId); 1149 context.startActivity(intent); 1150 return true; 1151 } 1152 return false; 1153 } 1154 unlockWorkProfileIfNecessary(Context context, int userId)1155 public static boolean unlockWorkProfileIfNecessary(Context context, int userId) { 1156 try { 1157 if (!ActivityManagerNative.getDefault().isUserRunning(userId, 1158 ActivityManager.FLAG_AND_LOCKED)) { 1159 return false; 1160 } 1161 } catch (RemoteException e) { 1162 return false; 1163 } 1164 if (!(new LockPatternUtils(context)).isSecure(userId)) { 1165 return false; 1166 } 1167 final KeyguardManager km = (KeyguardManager) context.getSystemService( 1168 Context.KEYGUARD_SERVICE); 1169 final Intent unlockIntent = km.createConfirmDeviceCredentialIntent(null, null, userId); 1170 if (unlockIntent != null) { 1171 context.startActivity(unlockIntent); 1172 return true; 1173 } else { 1174 return false; 1175 } 1176 1177 } 1178 getApplicationLabel(Context context, String packageName)1179 public static CharSequence getApplicationLabel(Context context, String packageName) { 1180 try { 1181 final ApplicationInfo appInfo = context.getPackageManager().getApplicationInfo( 1182 packageName, 1183 PackageManager.MATCH_DISABLED_COMPONENTS 1184 | PackageManager.MATCH_UNINSTALLED_PACKAGES); 1185 return appInfo.loadLabel(context.getPackageManager()); 1186 } catch (PackageManager.NameNotFoundException e) { 1187 Log.w(TAG, "Unable to find info for package: " + packageName); 1188 } 1189 return null; 1190 } 1191 isPackageEnabled(Context context, String packageName)1192 public static boolean isPackageEnabled(Context context, String packageName) { 1193 try { 1194 return context.getPackageManager().getApplicationInfo(packageName, 0).enabled; 1195 } catch (NameNotFoundException e) { 1196 // Thrown by PackageManager.getApplicationInfo if the package does not exist 1197 } 1198 return false; 1199 } 1200 isPackageDirectBootAware(Context context, String packageName)1201 public static boolean isPackageDirectBootAware(Context context, String packageName) { 1202 try { 1203 final ApplicationInfo ai = context.getPackageManager().getApplicationInfo( 1204 packageName, 0); 1205 return ai.isDirectBootAware() || ai.isPartiallyDirectBootAware(); 1206 } catch (NameNotFoundException ignored) { 1207 } 1208 return false; 1209 } 1210 isCarrierDemoUser(Context context)1211 public static boolean isCarrierDemoUser(Context context) { 1212 final String carrierDemoModeSetting = 1213 context.getString(com.android.internal.R.string.config_carrierDemoModeSetting); 1214 return UserManager.isDeviceInDemoMode(context) 1215 && getUserManager(context).isDemoUser() 1216 && !TextUtils.isEmpty(carrierDemoModeSetting) 1217 && Settings.Secure.getInt( 1218 context.getContentResolver(), carrierDemoModeSetting, 0) == 1; 1219 } 1220 } 1221