Utils.java revision 38ba9a2d4350fc7d063ec21c994183258bf7a443
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 17package com.android.settings; 18 19import android.app.ActivityManager; 20import android.app.AlertDialog; 21import android.app.Dialog; 22import android.app.Fragment; 23import android.app.IActivityManager; 24import android.content.ContentResolver; 25import android.content.Context; 26import android.content.DialogInterface; 27import android.content.Intent; 28import android.content.pm.ApplicationInfo; 29import android.content.pm.PackageManager; 30import android.content.pm.PackageManager.NameNotFoundException; 31import android.content.pm.ResolveInfo; 32import android.content.pm.UserInfo; 33import android.content.res.Resources; 34import android.content.res.Resources.NotFoundException; 35import android.database.Cursor; 36import android.graphics.Bitmap; 37import android.graphics.BitmapFactory; 38import android.graphics.drawable.Drawable; 39import android.net.ConnectivityManager; 40import android.net.LinkProperties; 41import android.net.Uri; 42import android.os.BatteryManager; 43import android.os.Bundle; 44import android.os.IBinder; 45import android.os.RemoteException; 46import android.os.UserHandle; 47import android.os.UserManager; 48import android.preference.Preference; 49import android.preference.PreferenceFrameLayout; 50import android.preference.PreferenceGroup; 51import android.provider.ContactsContract.CommonDataKinds; 52import android.provider.ContactsContract.Contacts; 53import android.provider.ContactsContract.Data; 54import android.provider.ContactsContract.Profile; 55import android.provider.ContactsContract.RawContacts; 56import android.service.persistentdata.PersistentDataBlockManager; 57import android.telephony.TelephonyManager; 58import android.text.TextUtils; 59import android.util.Log; 60import android.view.View; 61import android.view.ViewGroup; 62import android.widget.ListView; 63import android.widget.TabWidget; 64import com.android.settings.dashboard.DashboardCategory; 65import com.android.settings.dashboard.DashboardTile; 66 67import java.io.IOException; 68import java.io.InputStream; 69import java.net.InetAddress; 70import java.util.Iterator; 71import java.util.List; 72import java.util.Locale; 73 74public final class Utils { 75 private static final String TAG = "Settings"; 76 /** 77 * Set the preference's title to the matching activity's label. 78 */ 79 public static final int UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY = 1; 80 81 /** 82 * The opacity level of a disabled icon. 83 */ 84 public static final float DISABLED_ALPHA = 0.4f; 85 86 /** 87 * Color spectrum to use to indicate badness. 0 is completely transparent (no data), 88 * 1 is most bad (red), the last value is least bad (green). 89 */ 90 public static final int[] BADNESS_COLORS = new int[] { 91 0x00000000, 0xffc43828, 0xffe54918, 0xfff47b00, 92 0xfffabf2c, 0xff679e37, 0xff0a7f42 93 }; 94 95 /** 96 * Name of the meta-data item that should be set in the AndroidManifest.xml 97 * to specify the icon that should be displayed for the preference. 98 */ 99 private static final String META_DATA_PREFERENCE_ICON = "com.android.settings.icon"; 100 101 /** 102 * Name of the meta-data item that should be set in the AndroidManifest.xml 103 * to specify the title that should be displayed for the preference. 104 */ 105 private static final String META_DATA_PREFERENCE_TITLE = "com.android.settings.title"; 106 107 /** 108 * Name of the meta-data item that should be set in the AndroidManifest.xml 109 * to specify the summary text that should be displayed for the preference. 110 */ 111 private static final String META_DATA_PREFERENCE_SUMMARY = "com.android.settings.summary"; 112 113 /** 114 * Finds a matching activity for a preference's intent. If a matching 115 * activity is not found, it will remove the preference. 116 * 117 * @param context The context. 118 * @param parentPreferenceGroup The preference group that contains the 119 * preference whose intent is being resolved. 120 * @param preferenceKey The key of the preference whose intent is being 121 * resolved. 122 * @param flags 0 or one or more of 123 * {@link #UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY} 124 * . 125 * @return Whether an activity was found. If false, the preference was 126 * removed. 127 */ 128 public static boolean updatePreferenceToSpecificActivityOrRemove(Context context, 129 PreferenceGroup parentPreferenceGroup, String preferenceKey, int flags) { 130 131 Preference preference = parentPreferenceGroup.findPreference(preferenceKey); 132 if (preference == null) { 133 return false; 134 } 135 136 Intent intent = preference.getIntent(); 137 if (intent != null) { 138 // Find the activity that is in the system image 139 PackageManager pm = context.getPackageManager(); 140 List<ResolveInfo> list = pm.queryIntentActivities(intent, 0); 141 int listSize = list.size(); 142 for (int i = 0; i < listSize; i++) { 143 ResolveInfo resolveInfo = list.get(i); 144 if ((resolveInfo.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) 145 != 0) { 146 147 // Replace the intent with this specific activity 148 preference.setIntent(new Intent().setClassName( 149 resolveInfo.activityInfo.packageName, 150 resolveInfo.activityInfo.name)); 151 152 if ((flags & UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY) != 0) { 153 // Set the preference title to the activity's label 154 preference.setTitle(resolveInfo.loadLabel(pm)); 155 } 156 157 return true; 158 } 159 } 160 } 161 162 // Did not find a matching activity, so remove the preference 163 parentPreferenceGroup.removePreference(preference); 164 165 return false; 166 } 167 168 public static boolean updateTileToSpecificActivityFromMetaDataOrRemove(Context context, 169 DashboardCategory target, DashboardTile tile) { 170 171 Intent intent = tile.intent; 172 if (intent != null) { 173 // Find the activity that is in the system image 174 PackageManager pm = context.getPackageManager(); 175 List<ResolveInfo> list = pm.queryIntentActivities(intent, PackageManager.GET_META_DATA); 176 int listSize = list.size(); 177 for (int i = 0; i < listSize; i++) { 178 ResolveInfo resolveInfo = list.get(i); 179 if ((resolveInfo.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) 180 != 0) { 181 Drawable icon = null; 182 String title = null; 183 String summary = null; 184 185 // Get the activity's meta-data 186 try { 187 Resources res = pm.getResourcesForApplication( 188 resolveInfo.activityInfo.packageName); 189 Bundle metaData = resolveInfo.activityInfo.metaData; 190 191 if (res != null && metaData != null) { 192 icon = res.getDrawable(metaData.getInt(META_DATA_PREFERENCE_ICON)); 193 title = res.getString(metaData.getInt(META_DATA_PREFERENCE_TITLE)); 194 summary = res.getString(metaData.getInt(META_DATA_PREFERENCE_SUMMARY)); 195 } 196 } catch (NameNotFoundException e) { 197 // Ignore 198 } catch (NotFoundException e) { 199 // Ignore 200 } 201 202 // Set the preference title to the activity's label if no 203 // meta-data is found 204 if (TextUtils.isEmpty(title)) { 205 title = resolveInfo.loadLabel(pm).toString(); 206 } 207 208 // Set icon, title and summary for the preference 209 // TODO: 210 //tile.icon = icon; 211 tile.title = title; 212 tile.summary = summary; 213 // Replace the intent with this specific activity 214 tile.intent = new Intent().setClassName(resolveInfo.activityInfo.packageName, 215 resolveInfo.activityInfo.name); 216 217 return true; 218 } 219 } 220 } 221 222 // Did not find a matching activity, so remove the preference 223 target.removeTile(tile); 224 225 return false; 226 } 227 228 /** 229 * Returns true if Monkey is running. 230 */ 231 public static boolean isMonkeyRunning() { 232 return ActivityManager.isUserAMonkey(); 233 } 234 235 /** 236 * Returns whether the device is voice-capable (meaning, it is also a phone). 237 */ 238 public static boolean isVoiceCapable(Context context) { 239 TelephonyManager telephony = 240 (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); 241 return telephony != null && telephony.isVoiceCapable(); 242 } 243 244 public static boolean isWifiOnly(Context context) { 245 ConnectivityManager cm = (ConnectivityManager)context.getSystemService( 246 Context.CONNECTIVITY_SERVICE); 247 return (cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE) == false); 248 } 249 250 /** 251 * Returns the WIFI IP Addresses, if any, taking into account IPv4 and IPv6 style addresses. 252 * @param context the application context 253 * @return the formatted and newline-separated IP addresses, or null if none. 254 */ 255 public static String getWifiIpAddresses(Context context) { 256 ConnectivityManager cm = (ConnectivityManager) 257 context.getSystemService(Context.CONNECTIVITY_SERVICE); 258 LinkProperties prop = cm.getLinkProperties(ConnectivityManager.TYPE_WIFI); 259 return formatIpAddresses(prop); 260 } 261 262 /** 263 * Returns the default link's IP addresses, if any, taking into account IPv4 and IPv6 style 264 * addresses. 265 * @param context the application context 266 * @return the formatted and newline-separated IP addresses, or null if none. 267 */ 268 public static String getDefaultIpAddresses(ConnectivityManager cm) { 269 LinkProperties prop = cm.getActiveLinkProperties(); 270 return formatIpAddresses(prop); 271 } 272 273 private static String formatIpAddresses(LinkProperties prop) { 274 if (prop == null) return null; 275 Iterator<InetAddress> iter = prop.getAllAddresses().iterator(); 276 // If there are no entries, return null 277 if (!iter.hasNext()) return null; 278 // Concatenate all available addresses, comma separated 279 String addresses = ""; 280 while (iter.hasNext()) { 281 addresses += iter.next().getHostAddress(); 282 if (iter.hasNext()) addresses += "\n"; 283 } 284 return addresses; 285 } 286 287 public static Locale createLocaleFromString(String localeStr) { 288 // TODO: is there a better way to actually construct a locale that will match? 289 // The main problem is, on top of Java specs, locale.toString() and 290 // new Locale(locale.toString()).toString() do not return equal() strings in 291 // many cases, because the constructor takes the only string as the language 292 // code. So : new Locale("en", "US").toString() => "en_US" 293 // And : new Locale("en_US").toString() => "en_us" 294 if (null == localeStr) 295 return Locale.getDefault(); 296 String[] brokenDownLocale = localeStr.split("_", 3); 297 // split may not return a 0-length array. 298 if (1 == brokenDownLocale.length) { 299 return new Locale(brokenDownLocale[0]); 300 } else if (2 == brokenDownLocale.length) { 301 return new Locale(brokenDownLocale[0], brokenDownLocale[1]); 302 } else { 303 return new Locale(brokenDownLocale[0], brokenDownLocale[1], brokenDownLocale[2]); 304 } 305 } 306 307 public static boolean isBatteryPresent(Intent batteryChangedIntent) { 308 return batteryChangedIntent.getBooleanExtra(BatteryManager.EXTRA_PRESENT, true); 309 } 310 311 public static String getBatteryPercentage(Intent batteryChangedIntent) { 312 return String.valueOf(getBatteryLevel(batteryChangedIntent)) + "%"; 313 } 314 315 public static int getBatteryLevel(Intent batteryChangedIntent) { 316 int level = batteryChangedIntent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0); 317 int scale = batteryChangedIntent.getIntExtra(BatteryManager.EXTRA_SCALE, 100); 318 return (level * 100) / scale; 319 } 320 321 public static String getBatteryStatus(Resources res, Intent batteryChangedIntent) { 322 final Intent intent = batteryChangedIntent; 323 324 int plugType = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0); 325 int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, 326 BatteryManager.BATTERY_STATUS_UNKNOWN); 327 String statusString; 328 if (status == BatteryManager.BATTERY_STATUS_CHARGING) { 329 int resId; 330 if (plugType == BatteryManager.BATTERY_PLUGGED_AC) { 331 resId = R.string.battery_info_status_charging_ac; 332 } else if (plugType == BatteryManager.BATTERY_PLUGGED_USB) { 333 resId = R.string.battery_info_status_charging_usb; 334 } else if (plugType == BatteryManager.BATTERY_PLUGGED_WIRELESS) { 335 resId = R.string.battery_info_status_charging_wireless; 336 } else { 337 resId = R.string.battery_info_status_charging; 338 } 339 statusString = res.getString(resId); 340 } else if (status == BatteryManager.BATTERY_STATUS_DISCHARGING) { 341 statusString = res.getString(R.string.battery_info_status_discharging); 342 } else if (status == BatteryManager.BATTERY_STATUS_NOT_CHARGING) { 343 statusString = res.getString(R.string.battery_info_status_not_charging); 344 } else if (status == BatteryManager.BATTERY_STATUS_FULL) { 345 statusString = res.getString(R.string.battery_info_status_full); 346 } else { 347 statusString = res.getString(R.string.battery_info_status_unknown); 348 } 349 350 return statusString; 351 } 352 353 public static void forcePrepareCustomPreferencesList( 354 ViewGroup parent, View child, ListView list, boolean ignoreSidePadding) { 355 list.setScrollBarStyle(View.SCROLLBARS_OUTSIDE_OVERLAY); 356 list.setClipToPadding(false); 357 prepareCustomPreferencesList(parent, child, list, ignoreSidePadding); 358 } 359 360 /** 361 * Prepare a custom preferences layout, moving padding to {@link ListView} 362 * when outside scrollbars are requested. Usually used to display 363 * {@link ListView} and {@link TabWidget} with correct padding. 364 */ 365 public static void prepareCustomPreferencesList( 366 ViewGroup parent, View child, View list, boolean ignoreSidePadding) { 367 final boolean movePadding = list.getScrollBarStyle() == View.SCROLLBARS_OUTSIDE_OVERLAY; 368 if (movePadding) { 369 final Resources res = list.getResources(); 370 final int paddingSide = res.getDimensionPixelSize(R.dimen.settings_side_margin); 371 final int paddingBottom = res.getDimensionPixelSize( 372 com.android.internal.R.dimen.preference_fragment_padding_bottom); 373 374 if (parent instanceof PreferenceFrameLayout) { 375 ((PreferenceFrameLayout.LayoutParams) child.getLayoutParams()).removeBorders = true; 376 377 final int effectivePaddingSide = ignoreSidePadding ? 0 : paddingSide; 378 list.setPaddingRelative(effectivePaddingSide, 0, effectivePaddingSide, paddingBottom); 379 } else { 380 list.setPaddingRelative(paddingSide, 0, paddingSide, paddingBottom); 381 } 382 } 383 } 384 385 public static void forceCustomPadding(View view) { 386 final Resources res = view.getResources(); 387 final int paddingSide = res.getDimensionPixelSize(R.dimen.settings_side_margin); 388 final int paddingBottom = res.getDimensionPixelSize( 389 com.android.internal.R.dimen.preference_fragment_padding_bottom); 390 391 view.setPaddingRelative(paddingSide, 0, paddingSide, paddingBottom); 392 } 393 394 /** 395 * Return string resource that best describes combination of tethering 396 * options available on this device. 397 */ 398 public static int getTetheringLabel(ConnectivityManager cm) { 399 String[] usbRegexs = cm.getTetherableUsbRegexs(); 400 String[] wifiRegexs = cm.getTetherableWifiRegexs(); 401 String[] bluetoothRegexs = cm.getTetherableBluetoothRegexs(); 402 403 boolean usbAvailable = usbRegexs.length != 0; 404 boolean wifiAvailable = wifiRegexs.length != 0; 405 boolean bluetoothAvailable = bluetoothRegexs.length != 0; 406 407 if (wifiAvailable && usbAvailable && bluetoothAvailable) { 408 return R.string.tether_settings_title_all; 409 } else if (wifiAvailable && usbAvailable) { 410 return R.string.tether_settings_title_all; 411 } else if (wifiAvailable && bluetoothAvailable) { 412 return R.string.tether_settings_title_all; 413 } else if (wifiAvailable) { 414 return R.string.tether_settings_title_wifi; 415 } else if (usbAvailable && bluetoothAvailable) { 416 return R.string.tether_settings_title_usb_bluetooth; 417 } else if (usbAvailable) { 418 return R.string.tether_settings_title_usb; 419 } else { 420 return R.string.tether_settings_title_bluetooth; 421 } 422 } 423 424 /* Used by UserSettings as well. Call this on a non-ui thread. */ 425 public static boolean copyMeProfilePhoto(Context context, UserInfo user) { 426 Uri contactUri = Profile.CONTENT_URI; 427 428 InputStream avatarDataStream = Contacts.openContactPhotoInputStream( 429 context.getContentResolver(), 430 contactUri, true); 431 // If there's no profile photo, assign a default avatar 432 if (avatarDataStream == null) { 433 return false; 434 } 435 int userId = user != null ? user.id : UserHandle.myUserId(); 436 UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE); 437 Bitmap icon = BitmapFactory.decodeStream(avatarDataStream); 438 um.setUserIcon(userId, icon); 439 try { 440 avatarDataStream.close(); 441 } catch (IOException ioe) { } 442 return true; 443 } 444 445 public static String getMeProfileName(Context context, boolean full) { 446 if (full) { 447 return getProfileDisplayName(context); 448 } else { 449 return getShorterNameIfPossible(context); 450 } 451 } 452 453 private static String getShorterNameIfPossible(Context context) { 454 final String given = getLocalProfileGivenName(context); 455 return !TextUtils.isEmpty(given) ? given : getProfileDisplayName(context); 456 } 457 458 private static String getLocalProfileGivenName(Context context) { 459 final ContentResolver cr = context.getContentResolver(); 460 461 // Find the raw contact ID for the local ME profile raw contact. 462 final long localRowProfileId; 463 final Cursor localRawProfile = cr.query( 464 Profile.CONTENT_RAW_CONTACTS_URI, 465 new String[] {RawContacts._ID}, 466 RawContacts.ACCOUNT_TYPE + " IS NULL AND " + 467 RawContacts.ACCOUNT_NAME + " IS NULL", 468 null, null); 469 if (localRawProfile == null) return null; 470 471 try { 472 if (!localRawProfile.moveToFirst()) { 473 return null; 474 } 475 localRowProfileId = localRawProfile.getLong(0); 476 } finally { 477 localRawProfile.close(); 478 } 479 480 // Find the structured name for the raw contact. 481 final Cursor structuredName = cr.query( 482 Profile.CONTENT_URI.buildUpon().appendPath(Contacts.Data.CONTENT_DIRECTORY).build(), 483 new String[] {CommonDataKinds.StructuredName.GIVEN_NAME, 484 CommonDataKinds.StructuredName.FAMILY_NAME}, 485 Data.RAW_CONTACT_ID + "=" + localRowProfileId, 486 null, null); 487 if (structuredName == null) return null; 488 489 try { 490 if (!structuredName.moveToFirst()) { 491 return null; 492 } 493 String partialName = structuredName.getString(0); 494 if (TextUtils.isEmpty(partialName)) { 495 partialName = structuredName.getString(1); 496 } 497 return partialName; 498 } finally { 499 structuredName.close(); 500 } 501 } 502 503 private static final String getProfileDisplayName(Context context) { 504 final ContentResolver cr = context.getContentResolver(); 505 final Cursor profile = cr.query(Profile.CONTENT_URI, 506 new String[] {Profile.DISPLAY_NAME}, null, null, null); 507 if (profile == null) return null; 508 509 try { 510 if (!profile.moveToFirst()) { 511 return null; 512 } 513 return profile.getString(0); 514 } finally { 515 profile.close(); 516 } 517 } 518 519 /** Not global warming, it's global change warning. */ 520 public static Dialog buildGlobalChangeWarningDialog(final Context context, int titleResId, 521 final Runnable positiveAction) { 522 final AlertDialog.Builder builder = new AlertDialog.Builder(context); 523 builder.setTitle(titleResId); 524 builder.setMessage(R.string.global_change_warning); 525 builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { 526 @Override 527 public void onClick(DialogInterface dialog, int which) { 528 positiveAction.run(); 529 } 530 }); 531 builder.setNegativeButton(android.R.string.cancel, null); 532 533 return builder.create(); 534 } 535 536 public static boolean hasMultipleUsers(Context context) { 537 return ((UserManager) context.getSystemService(Context.USER_SERVICE)) 538 .getUsers().size() > 1; 539 } 540 541 /** 542 * Start a new instance of the activity, showing only the given fragment. 543 * When launched in this mode, the given preference fragment will be instantiated and fill the 544 * entire activity. 545 * 546 * @param context The context. 547 * @param fragmentName The name of the fragment to display. 548 * @param args Optional arguments to supply to the fragment. 549 * @param resultTo Option fragment that should receive the result of the activity launch. 550 * @param resultRequestCode If resultTo is non-null, this is the request code in which 551 * to report the result. 552 * @param titleResId resource id for the String to display for the title of this set 553 * of preferences. 554 * @param title String to display for the title of this set of preferences. 555 */ 556 public static void startWithFragment(Context context, String fragmentName, Bundle args, 557 Fragment resultTo, int resultRequestCode, int titleResId, CharSequence title) { 558 startWithFragment(context, fragmentName, args, resultTo, resultRequestCode, 559 titleResId, title, false /* not a shortcut */); 560 } 561 562 public static void startWithFragment(Context context, String fragmentName, Bundle args, 563 Fragment resultTo, int resultRequestCode, int titleResId, CharSequence title, 564 boolean isShortcut) { 565 Intent intent = onBuildStartFragmentIntent(context, fragmentName, args, titleResId, 566 title, isShortcut); 567 if (resultTo == null) { 568 context.startActivity(intent); 569 } else { 570 resultTo.startActivityForResult(intent, resultRequestCode); 571 } 572 } 573 574 /** 575 * Build an Intent to launch a new activity showing the selected fragment. 576 * The implementation constructs an Intent that re-launches the current activity with the 577 * appropriate arguments to display the fragment. 578 * 579 * 580 * @param context The Context. 581 * @param fragmentName The name of the fragment to display. 582 * @param args Optional arguments to supply to the fragment. 583 * @param titleResId Optional title resource id to show for this item. 584 * @param title Optional title to show for this item. 585 * @param isShortcut tell if this is a Launcher Shortcut or not 586 * @return Returns an Intent that can be launched to display the given 587 * fragment. 588 */ 589 public static Intent onBuildStartFragmentIntent(Context context, String fragmentName, 590 Bundle args, int titleResId, CharSequence title, boolean isShortcut) { 591 Intent intent = new Intent(Intent.ACTION_MAIN); 592 intent.setClass(context, SubSettings.class); 593 intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT, fragmentName); 594 intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS, args); 595 intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE_RESID, titleResId); 596 intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE, title); 597 intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_AS_SHORTCUT, isShortcut); 598 return intent; 599 } 600 601 /** 602 * Returns the managed profile of the current user or null if none found. 603 */ 604 public static UserHandle getManagedProfile(UserManager userManager) { 605 List<UserHandle> userProfiles = userManager.getUserProfiles(); 606 final int count = userProfiles.size(); 607 for (int i = 0; i < count; i++) { 608 final UserHandle profile = userProfiles.get(i); 609 if (profile.getIdentifier() == userManager.getUserHandle()) { 610 continue; 611 } 612 final UserInfo userInfo = userManager.getUserInfo(profile.getIdentifier()); 613 if (userInfo.isManagedProfile()) { 614 return profile; 615 } 616 } 617 return null; 618 } 619 620 /** 621 * Returns true if the current profile is a managed one. 622 */ 623 public static boolean isManagedProfile(UserManager userManager) { 624 UserInfo currentUser = userManager.getUserInfo(userManager.getUserHandle()); 625 return currentUser.isManagedProfile(); 626 } 627 628 /** 629 * Returns the {@link UserHandle} of the profile that a settings screen should refer to. 630 * 631 * <p> This takes into account the id of the user that triggered the settings screen. 632 */ 633 public static UserHandle getProfileToDisplay(IActivityManager am, IBinder activityToken, 634 Bundle arguments) { 635 int currentUser = UserHandle.getCallingUserId(); 636 // Check to see if it was called from a different user 637 try { 638 int launchedFromUser = UserHandle.getUserId(am.getLaunchedFromUid(activityToken)); 639 if (launchedFromUser != currentUser) { 640 // This is a forwarded intent 641 return new UserHandle(launchedFromUser); 642 } 643 } catch (RemoteException e) { 644 // Should not happen 645 Log.v(TAG, "Could not get launching user."); 646 } 647 // TODO: Check fragment arguments. See: http://b/15466880 648 649 // Default to current profile 650 return new UserHandle(currentUser); 651 } 652 653 /** 654 * Creates a dialog to confirm with the user if it's ok to remove the user 655 * and delete all the data. 656 * 657 * @param context a Context object 658 * @param removingUserId The userId of the user to remove 659 * @param onConfirmListener Callback object for positive action 660 * @return the created Dialog 661 */ 662 public static Dialog createRemoveConfirmationDialog(Context context, int removingUserId, 663 DialogInterface.OnClickListener onConfirmListener) { 664 UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE); 665 UserInfo userInfo = um.getUserInfo(removingUserId); 666 Dialog dlg = new AlertDialog.Builder(context) 667 .setTitle(UserHandle.myUserId() == removingUserId 668 ? R.string.user_confirm_remove_self_title 669 : (userInfo.isRestricted() 670 ? R.string.user_profile_confirm_remove_title 671 : R.string.user_confirm_remove_title)) 672 .setMessage(UserHandle.myUserId() == removingUserId 673 ? R.string.user_confirm_remove_self_message 674 : (userInfo.isRestricted() 675 ? R.string.user_profile_confirm_remove_message 676 : R.string.user_confirm_remove_message)) 677 .setPositiveButton(R.string.user_delete_button, 678 onConfirmListener) 679 .setNegativeButton(android.R.string.cancel, null) 680 .create(); 681 return dlg; 682 } 683 684 /** 685 * Returns whether or not this device is able to be OEM unlocked. 686 */ 687 static boolean isOemUnlockEnabled(Context context) { 688 PersistentDataBlockManager manager =(PersistentDataBlockManager) 689 context.getSystemService(Context.PERSISTENT_DATA_BLOCK_SERVICE); 690 return manager.getOemUnlockEnabled(); 691 } 692 693 /** 694 * Allows enabling or disabling OEM unlock on this device. OEM unlocked 695 * devices allow users to flash other OSes to them. 696 */ 697 static void setOemUnlockEnabled(Context context, boolean enabled) { 698 PersistentDataBlockManager manager =(PersistentDataBlockManager) 699 context.getSystemService(Context.PERSISTENT_DATA_BLOCK_SERVICE); 700 manager.setOemUnlockEnabled(enabled); 701 } 702} 703