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 static android.content.Intent.EXTRA_USER; 20 import static android.content.Intent.EXTRA_USER_ID; 21 import static android.text.format.DateUtils.FORMAT_ABBREV_MONTH; 22 import static android.text.format.DateUtils.FORMAT_SHOW_DATE; 23 24 import android.annotation.Nullable; 25 import android.app.ActionBar; 26 import android.app.Activity; 27 import android.app.ActivityManager; 28 import android.app.AppGlobals; 29 import android.app.IActivityManager; 30 import android.app.KeyguardManager; 31 import android.app.admin.DevicePolicyManager; 32 import android.content.ActivityNotFoundException; 33 import android.content.ComponentName; 34 import android.content.ContentResolver; 35 import android.content.Context; 36 import android.content.Intent; 37 import android.content.IntentFilter; 38 import android.content.pm.ApplicationInfo; 39 import android.content.pm.IPackageManager; 40 import android.content.pm.IntentFilterVerificationInfo; 41 import android.content.pm.PackageManager; 42 import android.content.pm.PackageManager.NameNotFoundException; 43 import android.content.pm.ResolveInfo; 44 import android.content.pm.UserInfo; 45 import android.content.res.Configuration; 46 import android.content.res.Resources; 47 import android.content.res.TypedArray; 48 import android.database.Cursor; 49 import android.graphics.Bitmap; 50 import android.graphics.Canvas; 51 import android.graphics.drawable.AdaptiveIconDrawable; 52 import android.graphics.drawable.BitmapDrawable; 53 import android.graphics.drawable.Drawable; 54 import android.graphics.drawable.VectorDrawable; 55 import android.hardware.face.FaceManager; 56 import android.hardware.fingerprint.FingerprintManager; 57 import android.net.ConnectivityManager; 58 import android.net.LinkAddress; 59 import android.net.LinkProperties; 60 import android.net.Network; 61 import android.net.wifi.WifiManager; 62 import android.os.BatteryManager; 63 import android.os.Binder; 64 import android.os.Build; 65 import android.os.Bundle; 66 import android.os.IBinder; 67 import android.os.INetworkManagementService; 68 import android.os.RemoteException; 69 import android.os.ServiceManager; 70 import android.os.UserHandle; 71 import android.os.UserManager; 72 import android.os.storage.StorageManager; 73 import android.os.storage.VolumeInfo; 74 import android.preference.PreferenceFrameLayout; 75 import android.provider.ContactsContract.CommonDataKinds; 76 import android.provider.ContactsContract.Contacts; 77 import android.provider.ContactsContract.Data; 78 import android.provider.ContactsContract.Profile; 79 import android.provider.ContactsContract.RawContacts; 80 import android.telephony.SubscriptionManager; 81 import android.telephony.TelephonyManager; 82 import android.text.Spannable; 83 import android.text.SpannableString; 84 import android.text.TextUtils; 85 import android.text.format.DateUtils; 86 import android.text.style.TtsSpan; 87 import android.util.ArraySet; 88 import android.util.IconDrawableFactory; 89 import android.util.Log; 90 import android.view.LayoutInflater; 91 import android.view.View; 92 import android.view.ViewGroup; 93 import android.widget.EditText; 94 import android.widget.ListView; 95 import android.widget.TabWidget; 96 97 import androidx.annotation.ColorInt; 98 import androidx.annotation.NonNull; 99 import androidx.annotation.StringRes; 100 import androidx.core.graphics.drawable.IconCompat; 101 import androidx.core.graphics.drawable.RoundedBitmapDrawable; 102 import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory; 103 import androidx.fragment.app.Fragment; 104 import androidx.lifecycle.Lifecycle; 105 import androidx.preference.Preference; 106 import androidx.preference.PreferenceGroup; 107 108 import com.android.internal.app.UnlaunchableAppActivity; 109 import com.android.internal.util.ArrayUtils; 110 import com.android.internal.widget.LockPatternUtils; 111 import com.android.settings.dashboard.profileselector.ProfileFragmentBridge; 112 import com.android.settings.dashboard.profileselector.ProfileSelectFragment; 113 import com.android.settings.password.ChooseLockSettingsHelper; 114 import com.android.settingslib.widget.ActionBarShadowController; 115 import com.android.settingslib.widget.AdaptiveIcon; 116 117 import java.util.Iterator; 118 import java.util.List; 119 import java.util.Locale; 120 121 public final class Utils extends com.android.settingslib.Utils { 122 123 private static final String TAG = "Settings"; 124 125 public static final String FILE_PROVIDER_AUTHORITY = "com.android.settings.files"; 126 127 /** 128 * Set the preference's title to the matching activity's label. 129 */ 130 public static final int UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY = 1; 131 132 public static final String SETTINGS_PACKAGE_NAME = "com.android.settings"; 133 134 public static final String OS_PKG = "os"; 135 136 /** 137 * Whether to disable the new device identifier access restrictions. 138 */ 139 public static final String PROPERTY_DEVICE_IDENTIFIER_ACCESS_RESTRICTIONS_DISABLED = 140 "device_identifier_access_restrictions_disabled"; 141 142 /** 143 * Whether to show the Permissions Hub. 144 */ 145 public static final String PROPERTY_PERMISSIONS_HUB_ENABLED = "permissions_hub_enabled"; 146 147 /** 148 * Whether to show location indicators. 149 */ 150 public static final String PROPERTY_LOCATION_INDICATORS_ENABLED = "location_indicators_enabled"; 151 152 /** 153 * Whether to show location indicator settings in developer options. 154 */ 155 public static final String PROPERTY_LOCATION_INDICATOR_SETTINGS_ENABLED = 156 "location_indicator_settings_enabled"; 157 158 /** Whether or not app hibernation is enabled on the device **/ 159 public static final String PROPERTY_APP_HIBERNATION_ENABLED = "app_hibernation_enabled"; 160 161 /** Whether or not app hibernation targets apps that target a pre-S SDK **/ 162 public static final String PROPERTY_HIBERNATION_TARGETS_PRE_S_APPS = 163 "app_hibernation_targets_pre_s_apps"; 164 165 /** 166 * Finds a matching activity for a preference's intent. If a matching 167 * activity is not found, it will remove the preference. 168 * 169 * @param context The context. 170 * @param parentPreferenceGroup The preference group that contains the 171 * preference whose intent is being resolved. 172 * @param preferenceKey The key of the preference whose intent is being 173 * resolved. 174 * @param flags 0 or one or more of 175 * {@link #UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY} 176 * . 177 * @return Whether an activity was found. If false, the preference was 178 * removed. 179 */ updatePreferenceToSpecificActivityOrRemove(Context context, PreferenceGroup parentPreferenceGroup, String preferenceKey, int flags)180 public static boolean updatePreferenceToSpecificActivityOrRemove(Context context, 181 PreferenceGroup parentPreferenceGroup, String preferenceKey, int flags) { 182 183 final Preference preference = parentPreferenceGroup.findPreference(preferenceKey); 184 if (preference == null) { 185 return false; 186 } 187 188 final Intent intent = preference.getIntent(); 189 if (intent != null) { 190 // Find the activity that is in the system image 191 final PackageManager pm = context.getPackageManager(); 192 final List<ResolveInfo> list = pm.queryIntentActivities(intent, 0); 193 final int listSize = list.size(); 194 for (int i = 0; i < listSize; i++) { 195 final ResolveInfo resolveInfo = list.get(i); 196 if ((resolveInfo.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) 197 != 0) { 198 199 // Replace the intent with this specific activity 200 preference.setIntent(new Intent().setClassName( 201 resolveInfo.activityInfo.packageName, 202 resolveInfo.activityInfo.name)); 203 204 if ((flags & UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY) != 0) { 205 // Set the preference title to the activity's label 206 preference.setTitle(resolveInfo.loadLabel(pm)); 207 } 208 209 return true; 210 } 211 } 212 } 213 214 // Did not find a matching activity, so remove the preference 215 parentPreferenceGroup.removePreference(preference); 216 217 return false; 218 } 219 220 /** 221 * Returns true if Monkey is running. 222 */ isMonkeyRunning()223 public static boolean isMonkeyRunning() { 224 return ActivityManager.isUserAMonkey(); 225 } 226 227 /** 228 * Returns whether the device is voice-capable (meaning, it is also a phone). 229 */ isVoiceCapable(Context context)230 public static boolean isVoiceCapable(Context context) { 231 final TelephonyManager telephony = 232 (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); 233 return telephony != null && telephony.isVoiceCapable(); 234 } 235 236 /** 237 * Returns the WIFI IP Addresses, if any, taking into account IPv4 and IPv6 style addresses. 238 * @param context the application context 239 * @return the formatted and newline-separated IP addresses, or null if none. 240 */ getWifiIpAddresses(Context context)241 public static String getWifiIpAddresses(Context context) { 242 final WifiManager wifiManager = context.getSystemService(WifiManager.class); 243 final Network currentNetwork = wifiManager.getCurrentNetwork(); 244 if (currentNetwork != null) { 245 final ConnectivityManager cm = (ConnectivityManager) 246 context.getSystemService(Context.CONNECTIVITY_SERVICE); 247 final LinkProperties prop = cm.getLinkProperties(currentNetwork); 248 return formatIpAddresses(prop); 249 } 250 return null; 251 } 252 formatIpAddresses(LinkProperties prop)253 private static String formatIpAddresses(LinkProperties prop) { 254 if (prop == null) return null; 255 final Iterator<LinkAddress> iter = prop.getAllLinkAddresses().iterator(); 256 // If there are no entries, return null 257 if (!iter.hasNext()) return null; 258 // Concatenate all available addresses, comma separated 259 String addresses = ""; 260 while (iter.hasNext()) { 261 addresses += iter.next().getAddress().getHostAddress(); 262 if (iter.hasNext()) addresses += "\n"; 263 } 264 return addresses; 265 } 266 createLocaleFromString(String localeStr)267 public static Locale createLocaleFromString(String localeStr) { 268 // TODO: is there a better way to actually construct a locale that will match? 269 // The main problem is, on top of Java specs, locale.toString() and 270 // new Locale(locale.toString()).toString() do not return equal() strings in 271 // many cases, because the constructor takes the only string as the language 272 // code. So : new Locale("en", "US").toString() => "en_US" 273 // And : new Locale("en_US").toString() => "en_us" 274 if (null == localeStr) 275 return Locale.getDefault(); 276 final String[] brokenDownLocale = localeStr.split("_", 3); 277 // split may not return a 0-length array. 278 if (1 == brokenDownLocale.length) { 279 return new Locale(brokenDownLocale[0]); 280 } else if (2 == brokenDownLocale.length) { 281 return new Locale(brokenDownLocale[0], brokenDownLocale[1]); 282 } else { 283 return new Locale(brokenDownLocale[0], brokenDownLocale[1], brokenDownLocale[2]); 284 } 285 } 286 isBatteryPresent(Intent batteryChangedIntent)287 public static boolean isBatteryPresent(Intent batteryChangedIntent) { 288 return batteryChangedIntent.getBooleanExtra(BatteryManager.EXTRA_PRESENT, true); 289 } 290 291 /** 292 * Return true if battery is present. 293 */ isBatteryPresent(Context context)294 public static boolean isBatteryPresent(Context context) { 295 Intent batteryBroadcast = context.registerReceiver(null /* receiver */, 296 new IntentFilter(Intent.ACTION_BATTERY_CHANGED)); 297 return isBatteryPresent(batteryBroadcast); 298 } 299 getBatteryPercentage(Intent batteryChangedIntent)300 public static String getBatteryPercentage(Intent batteryChangedIntent) { 301 return formatPercentage(getBatteryLevel(batteryChangedIntent)); 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 paddingBottom = res.getDimensionPixelSize( 315 com.android.internal.R.dimen.preference_fragment_padding_bottom); 316 317 if (parent instanceof PreferenceFrameLayout) { 318 ((PreferenceFrameLayout.LayoutParams) child.getLayoutParams()).removeBorders = true; 319 } 320 list.setPaddingRelative(0 /* start */, 0 /* top */, 0 /* end */, paddingBottom); 321 } 322 } 323 forceCustomPadding(View view, boolean additive)324 public static void forceCustomPadding(View view, boolean additive) { 325 final Resources res = view.getResources(); 326 327 final int paddingStart = additive ? view.getPaddingStart() : 0; 328 final int paddingEnd = additive ? view.getPaddingEnd() : 0; 329 final int paddingBottom = res.getDimensionPixelSize( 330 com.android.internal.R.dimen.preference_fragment_padding_bottom); 331 332 view.setPaddingRelative(paddingStart, 0, paddingEnd, paddingBottom); 333 } 334 getMeProfileName(Context context, boolean full)335 public static String getMeProfileName(Context context, boolean full) { 336 if (full) { 337 return getProfileDisplayName(context); 338 } else { 339 return getShorterNameIfPossible(context); 340 } 341 } 342 getShorterNameIfPossible(Context context)343 private static String getShorterNameIfPossible(Context context) { 344 final String given = getLocalProfileGivenName(context); 345 return !TextUtils.isEmpty(given) ? given : getProfileDisplayName(context); 346 } 347 getLocalProfileGivenName(Context context)348 private static String getLocalProfileGivenName(Context context) { 349 final ContentResolver cr = context.getContentResolver(); 350 351 // Find the raw contact ID for the local ME profile raw contact. 352 final long localRowProfileId; 353 final Cursor localRawProfile = cr.query( 354 Profile.CONTENT_RAW_CONTACTS_URI, 355 new String[] {RawContacts._ID}, 356 RawContacts.ACCOUNT_TYPE + " IS NULL AND " + 357 RawContacts.ACCOUNT_NAME + " IS NULL", 358 null, null); 359 if (localRawProfile == null) return null; 360 361 try { 362 if (!localRawProfile.moveToFirst()) { 363 return null; 364 } 365 localRowProfileId = localRawProfile.getLong(0); 366 } finally { 367 localRawProfile.close(); 368 } 369 370 // Find the structured name for the raw contact. 371 final Cursor structuredName = cr.query( 372 Profile.CONTENT_URI.buildUpon().appendPath(Contacts.Data.CONTENT_DIRECTORY).build(), 373 new String[] {CommonDataKinds.StructuredName.GIVEN_NAME, 374 CommonDataKinds.StructuredName.FAMILY_NAME}, 375 Data.RAW_CONTACT_ID + "=" + localRowProfileId, 376 null, null); 377 if (structuredName == null) return null; 378 379 try { 380 if (!structuredName.moveToFirst()) { 381 return null; 382 } 383 String partialName = structuredName.getString(0); 384 if (TextUtils.isEmpty(partialName)) { 385 partialName = structuredName.getString(1); 386 } 387 return partialName; 388 } finally { 389 structuredName.close(); 390 } 391 } 392 getProfileDisplayName(Context context)393 private static final String getProfileDisplayName(Context context) { 394 final ContentResolver cr = context.getContentResolver(); 395 final Cursor profile = cr.query(Profile.CONTENT_URI, 396 new String[] {Profile.DISPLAY_NAME}, null, null, null); 397 if (profile == null) return null; 398 399 try { 400 if (!profile.moveToFirst()) { 401 return null; 402 } 403 return profile.getString(0); 404 } finally { 405 profile.close(); 406 } 407 } 408 hasMultipleUsers(Context context)409 public static boolean hasMultipleUsers(Context context) { 410 return context.getSystemService(UserManager.class) 411 .getUsers().size() > 1; 412 } 413 414 /** 415 * Returns the managed profile of the current user or {@code null} if none is found or a profile 416 * exists but it is disabled. 417 */ getManagedProfile(UserManager userManager)418 public static UserHandle getManagedProfile(UserManager userManager) { 419 final List<UserHandle> userProfiles = userManager.getUserProfiles(); 420 for (UserHandle profile : userProfiles) { 421 if (profile.getIdentifier() == userManager.getProcessUserId()) { 422 continue; 423 } 424 final UserInfo userInfo = userManager.getUserInfo(profile.getIdentifier()); 425 if (userInfo.isManagedProfile()) { 426 return profile; 427 } 428 } 429 return null; 430 } 431 432 /** 433 * Returns the managed profile of the current user or {@code null} if none is found. Unlike 434 * {@link #getManagedProfile} this method returns enabled and disabled managed profiles. 435 */ getManagedProfileWithDisabled(UserManager userManager)436 public static UserHandle getManagedProfileWithDisabled(UserManager userManager) { 437 // TODO: Call getManagedProfileId from here once Robolectric supports 438 // API level 24 and UserManager.getProfileIdsWithDisabled can be Mocked (to avoid having 439 // yet another implementation that loops over user profiles in this method). In the meantime 440 // we need to use UserManager.getProfiles that is available on API 23 (the one currently 441 // used for Settings Robolectric tests). 442 final int myUserId = UserHandle.myUserId(); 443 final List<UserInfo> profiles = userManager.getProfiles(myUserId); 444 final int count = profiles.size(); 445 for (int i = 0; i < count; i++) { 446 final UserInfo profile = profiles.get(i); 447 if (profile.isManagedProfile() 448 && profile.getUserHandle().getIdentifier() != myUserId) { 449 return profile.getUserHandle(); 450 } 451 } 452 return null; 453 } 454 455 /** 456 * Retrieves the id for the given user's managed profile. 457 * 458 * @return the managed profile id or UserHandle.USER_NULL if there is none. 459 */ getManagedProfileId(UserManager um, int parentUserId)460 public static int getManagedProfileId(UserManager um, int parentUserId) { 461 final int[] profileIds = um.getProfileIdsWithDisabled(parentUserId); 462 for (int profileId : profileIds) { 463 if (profileId != parentUserId) { 464 return profileId; 465 } 466 } 467 return UserHandle.USER_NULL; 468 } 469 470 /** Returns user ID of current user, throws IllegalStateException if it's not available. */ getCurrentUserId(UserManager userManager, boolean isWorkProfile)471 public static int getCurrentUserId(UserManager userManager, boolean isWorkProfile) 472 throws IllegalStateException { 473 if (isWorkProfile) { 474 final UserHandle managedUserHandle = getManagedProfile(userManager); 475 if (managedUserHandle == null) { 476 throw new IllegalStateException("Work profile user ID is not available."); 477 } 478 return managedUserHandle.getIdentifier(); 479 } 480 return UserHandle.myUserId(); 481 } 482 483 /** 484 * Returns the target user for a Settings activity. 485 * <p> 486 * User would be retrieved in this order: 487 * <ul> 488 * <li> If this activity is launched from other user, return that user id. 489 * <li> If this is launched from the Settings app in same user, return the user contained as an 490 * extra in the arguments or intent extras. 491 * <li> Otherwise, return UserHandle.myUserId(). 492 * </ul> 493 * <p> 494 * Note: This is secure in the sense that it only returns a target user different to the current 495 * one if the app launching this activity is the Settings app itself, running in the same user 496 * or in one that is in the same profile group, or if the user id is provided by the system. 497 */ getSecureTargetUser(IBinder activityToken, UserManager um, @Nullable Bundle arguments, @Nullable Bundle intentExtras)498 public static UserHandle getSecureTargetUser(IBinder activityToken, 499 UserManager um, @Nullable Bundle arguments, @Nullable Bundle intentExtras) { 500 final UserHandle currentUser = new UserHandle(UserHandle.myUserId()); 501 final IActivityManager am = ActivityManager.getService(); 502 try { 503 final String launchedFromPackage = am.getLaunchedFromPackage(activityToken); 504 final boolean launchedFromSettingsApp = 505 SETTINGS_PACKAGE_NAME.equals(launchedFromPackage); 506 507 final UserHandle launchedFromUser = new UserHandle(UserHandle.getUserId( 508 am.getLaunchedFromUid(activityToken))); 509 if (launchedFromUser != null && !launchedFromUser.equals(currentUser)) { 510 // Check it's secure 511 if (isProfileOf(um, launchedFromUser)) { 512 return launchedFromUser; 513 } 514 } 515 final UserHandle extrasUser = getUserHandleFromBundle(intentExtras); 516 if (extrasUser != null && !extrasUser.equals(currentUser)) { 517 // Check it's secure 518 if (launchedFromSettingsApp && isProfileOf(um, extrasUser)) { 519 return extrasUser; 520 } 521 } 522 final UserHandle argumentsUser = getUserHandleFromBundle(arguments); 523 if (argumentsUser != null && !argumentsUser.equals(currentUser)) { 524 // Check it's secure 525 if (launchedFromSettingsApp && isProfileOf(um, argumentsUser)) { 526 return argumentsUser; 527 } 528 } 529 } catch (RemoteException e) { 530 // Should not happen 531 Log.v(TAG, "Could not talk to activity manager.", e); 532 } 533 return currentUser; 534 } 535 536 /** 537 * Lookup both {@link Intent#EXTRA_USER} and {@link Intent#EXTRA_USER_ID} in the bundle 538 * and return the {@link UserHandle} object. Return {@code null} if nothing is found. 539 */ getUserHandleFromBundle(Bundle bundle)540 private static @Nullable UserHandle getUserHandleFromBundle(Bundle bundle) { 541 if (bundle == null) { 542 return null; 543 } 544 final UserHandle user = bundle.getParcelable(EXTRA_USER); 545 if (user != null) { 546 return user; 547 } 548 final int userId = bundle.getInt(EXTRA_USER_ID, -1); 549 if (userId != -1) { 550 return UserHandle.of(userId); 551 } 552 return null; 553 } 554 555 /** 556 * Returns true if the user provided is in the same profiles group as the current user. 557 */ isProfileOf(UserManager um, UserHandle otherUser)558 private static boolean isProfileOf(UserManager um, UserHandle otherUser) { 559 if (um == null || otherUser == null) return false; 560 return (UserHandle.myUserId() == otherUser.getIdentifier()) 561 || um.getUserProfiles().contains(otherUser); 562 } 563 564 /** 565 * Queries for the UserInfo of a user. Returns null if the user doesn't exist (was removed). 566 * @param userManager Instance of UserManager 567 * @param checkUser The user to check the existence of. 568 * @return UserInfo of the user or null for non-existent user. 569 */ getExistingUser(UserManager userManager, UserHandle checkUser)570 public static UserInfo getExistingUser(UserManager userManager, UserHandle checkUser) { 571 final List<UserInfo> users = userManager.getAliveUsers(); 572 final int checkUserId = checkUser.getIdentifier(); 573 for (UserInfo user : users) { 574 if (user.id == checkUserId) { 575 return user; 576 } 577 } 578 return null; 579 } 580 inflateCategoryHeader(LayoutInflater inflater, ViewGroup parent)581 public static View inflateCategoryHeader(LayoutInflater inflater, ViewGroup parent) { 582 final TypedArray a = inflater.getContext().obtainStyledAttributes(null, 583 com.android.internal.R.styleable.Preference, 584 com.android.internal.R.attr.preferenceCategoryStyle, 0); 585 final int resId = a.getResourceId(com.android.internal.R.styleable.Preference_layout, 586 0); 587 a.recycle(); 588 return inflater.inflate(resId, parent, false); 589 } 590 getHandledDomains(PackageManager pm, String packageName)591 public static ArraySet<String> getHandledDomains(PackageManager pm, String packageName) { 592 final List<IntentFilterVerificationInfo> iviList = 593 pm.getIntentFilterVerifications(packageName); 594 final List<IntentFilter> filters = pm.getAllIntentFilters(packageName); 595 596 final ArraySet<String> result = new ArraySet<>(); 597 if (iviList != null && iviList.size() > 0) { 598 for (IntentFilterVerificationInfo ivi : iviList) { 599 for (String host : ivi.getDomains()) { 600 result.add(host); 601 } 602 } 603 } 604 if (filters != null && filters.size() > 0) { 605 for (IntentFilter filter : filters) { 606 if (filter.hasCategory(Intent.CATEGORY_BROWSABLE) 607 && (filter.hasDataScheme(IntentFilter.SCHEME_HTTP) || 608 filter.hasDataScheme(IntentFilter.SCHEME_HTTPS))) { 609 result.addAll(filter.getHostsList()); 610 } 611 } 612 } 613 return result; 614 } 615 616 /** 617 * Returns the application info of the currently installed MDM package. 618 */ getAdminApplicationInfo(Context context, int profileId)619 public static ApplicationInfo getAdminApplicationInfo(Context context, int profileId) { 620 final DevicePolicyManager dpm = 621 (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE); 622 final ComponentName mdmPackage = dpm.getProfileOwnerAsUser(profileId); 623 if (mdmPackage == null) { 624 return null; 625 } 626 final String mdmPackageName = mdmPackage.getPackageName(); 627 try { 628 final IPackageManager ipm = AppGlobals.getPackageManager(); 629 final ApplicationInfo mdmApplicationInfo = 630 ipm.getApplicationInfo(mdmPackageName, 0, profileId); 631 return mdmApplicationInfo; 632 } catch (RemoteException e) { 633 Log.e(TAG, "Error while retrieving application info for package " + mdmPackageName 634 + ", userId " + profileId, e); 635 return null; 636 } 637 } 638 isBandwidthControlEnabled()639 public static boolean isBandwidthControlEnabled() { 640 final INetworkManagementService netManager = INetworkManagementService.Stub 641 .asInterface(ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE)); 642 try { 643 return netManager.isBandwidthControlEnabled(); 644 } catch (RemoteException e) { 645 return false; 646 } 647 } 648 649 /** 650 * Returns an accessible SpannableString. 651 * @param displayText the text to display 652 * @param accessibileText the text text-to-speech engines should read 653 */ createAccessibleSequence(CharSequence displayText, String accessibileText)654 public static SpannableString createAccessibleSequence(CharSequence displayText, 655 String accessibileText) { 656 final SpannableString str = new SpannableString(displayText); 657 str.setSpan(new TtsSpan.TextBuilder(accessibileText).build(), 0, 658 displayText.length(), 659 Spannable.SPAN_INCLUSIVE_INCLUSIVE); 660 return str; 661 } 662 663 /** 664 * Returns the user id present in the bundle with 665 * {@link Intent#EXTRA_USER_ID} if it belongs to the current user. 666 * 667 * @throws SecurityException if the given userId does not belong to the 668 * current user group. 669 */ getUserIdFromBundle(Context context, Bundle bundle)670 public static int getUserIdFromBundle(Context context, Bundle bundle) { 671 return getUserIdFromBundle(context, bundle, false); 672 } 673 674 /** 675 * Returns the user id present in the bundle with 676 * {@link Intent#EXTRA_USER_ID} if it belongs to the current user. 677 * 678 * @param isInternal indicating if the caller is "internal" to the system, 679 * meaning we're willing to trust extras like 680 * {@link ChooseLockSettingsHelper#EXTRA_KEY_ALLOW_ANY_USER}. 681 * @throws SecurityException if the given userId does not belong to the 682 * current user group. 683 */ getUserIdFromBundle(Context context, Bundle bundle, boolean isInternal)684 public static int getUserIdFromBundle(Context context, Bundle bundle, boolean isInternal) { 685 if (bundle == null) { 686 return getCredentialOwnerUserId(context); 687 } 688 final boolean allowAnyUser = isInternal 689 && bundle.getBoolean(ChooseLockSettingsHelper.EXTRA_KEY_ALLOW_ANY_USER, false); 690 final int userId = bundle.getInt(Intent.EXTRA_USER_ID, UserHandle.myUserId()); 691 if (userId == LockPatternUtils.USER_FRP) { 692 return allowAnyUser ? userId : enforceSystemUser(context, userId); 693 } else { 694 return allowAnyUser ? userId : enforceSameOwner(context, userId); 695 } 696 } 697 698 /** 699 * Returns the given user id if the current user is the system user. 700 * 701 * @throws SecurityException if the current user is not the system user. 702 */ enforceSystemUser(Context context, int userId)703 public static int enforceSystemUser(Context context, int userId) { 704 if (UserHandle.myUserId() == UserHandle.USER_SYSTEM) { 705 return userId; 706 } 707 throw new SecurityException("Given user id " + userId + " must only be used from " 708 + "USER_SYSTEM, but current user is " + UserHandle.myUserId()); 709 } 710 711 /** 712 * Returns the given user id if it belongs to the current user. 713 * 714 * @throws SecurityException if the given userId does not belong to the current user group. 715 */ enforceSameOwner(Context context, int userId)716 public static int enforceSameOwner(Context context, int userId) { 717 final UserManager um = context.getSystemService(UserManager.class); 718 final int[] profileIds = um.getProfileIdsWithDisabled(UserHandle.myUserId()); 719 if (ArrayUtils.contains(profileIds, userId)) { 720 return userId; 721 } 722 throw new SecurityException("Given user id " + userId + " does not belong to user " 723 + UserHandle.myUserId()); 724 } 725 726 /** 727 * Returns the effective credential owner of the calling user. 728 */ getCredentialOwnerUserId(Context context)729 public static int getCredentialOwnerUserId(Context context) { 730 return getCredentialOwnerUserId(context, UserHandle.myUserId()); 731 } 732 733 /** 734 * Returns the user id of the credential owner of the given user id. 735 */ getCredentialOwnerUserId(Context context, int userId)736 public static int getCredentialOwnerUserId(Context context, int userId) { 737 final UserManager um = context.getSystemService(UserManager.class); 738 return um.getCredentialOwnerProfile(userId); 739 } 740 741 /** 742 * Returns the credential type of the given user id. 743 */ getCredentialType(Context context, int userId)744 public static @LockPatternUtils.CredentialType int getCredentialType(Context context, 745 int userId) { 746 final LockPatternUtils lpu = new LockPatternUtils(context); 747 return lpu.getCredentialTypeForUser(userId); 748 } 749 750 private static final StringBuilder sBuilder = new StringBuilder(50); 751 private static final java.util.Formatter sFormatter = new java.util.Formatter( 752 sBuilder, Locale.getDefault()); 753 formatDateRange(Context context, long start, long end)754 public static String formatDateRange(Context context, long start, long end) { 755 final int flags = FORMAT_SHOW_DATE | FORMAT_ABBREV_MONTH; 756 757 synchronized (sBuilder) { 758 sBuilder.setLength(0); 759 return DateUtils.formatDateRange(context, sFormatter, start, end, flags, null) 760 .toString(); 761 } 762 } 763 startQuietModeDialogIfNecessary(Context context, UserManager um, int userId)764 public static boolean startQuietModeDialogIfNecessary(Context context, UserManager um, 765 int userId) { 766 if (um.isQuietModeEnabled(UserHandle.of(userId))) { 767 final Intent intent = UnlaunchableAppActivity.createInQuietModeDialogIntent(userId); 768 context.startActivity(intent); 769 return true; 770 } 771 return false; 772 } 773 unlockWorkProfileIfNecessary(Context context, int userId)774 public static boolean unlockWorkProfileIfNecessary(Context context, int userId) { 775 try { 776 if (!ActivityManager.getService().isUserRunning(userId, 777 ActivityManager.FLAG_AND_LOCKED)) { 778 return false; 779 } 780 } catch (RemoteException e) { 781 return false; 782 } 783 if (!(new LockPatternUtils(context)).isSecure(userId)) { 784 return false; 785 } 786 return confirmWorkProfileCredentials(context, userId); 787 } 788 confirmWorkProfileCredentials(Context context, int userId)789 private static boolean confirmWorkProfileCredentials(Context context, int userId) { 790 final KeyguardManager km = (KeyguardManager) context.getSystemService( 791 Context.KEYGUARD_SERVICE); 792 final Intent unlockIntent = km.createConfirmDeviceCredentialIntent(null, null, userId); 793 if (unlockIntent != null) { 794 context.startActivity(unlockIntent); 795 return true; 796 } else { 797 return false; 798 } 799 } 800 getApplicationLabel(Context context, String packageName)801 public static CharSequence getApplicationLabel(Context context, String packageName) { 802 try { 803 final ApplicationInfo appInfo = context.getPackageManager().getApplicationInfo( 804 packageName, 805 PackageManager.MATCH_DISABLED_COMPONENTS 806 | PackageManager.MATCH_ANY_USER); 807 return appInfo.loadLabel(context.getPackageManager()); 808 } catch (PackageManager.NameNotFoundException e) { 809 Log.e(TAG, "Unable to find info for package: " + packageName); 810 } 811 return null; 812 } 813 isPackageDirectBootAware(Context context, String packageName)814 public static boolean isPackageDirectBootAware(Context context, String packageName) { 815 try { 816 final ApplicationInfo ai = context.getPackageManager().getApplicationInfo( 817 packageName, 0); 818 return ai.isDirectBootAware() || ai.isPartiallyDirectBootAware(); 819 } catch (NameNotFoundException ignored) { 820 } 821 return false; 822 } 823 824 /** 825 * Returns a context created from the given context for the given user, or null if it fails 826 */ createPackageContextAsUser(Context context, int userId)827 public static Context createPackageContextAsUser(Context context, int userId) { 828 try { 829 return context.createPackageContextAsUser( 830 context.getPackageName(), 0 /* flags */, UserHandle.of(userId)); 831 } catch (PackageManager.NameNotFoundException e) { 832 Log.e(TAG, "Failed to create user context", e); 833 } 834 return null; 835 } 836 getFingerprintManagerOrNull(Context context)837 public static FingerprintManager getFingerprintManagerOrNull(Context context) { 838 if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) { 839 return (FingerprintManager) context.getSystemService(Context.FINGERPRINT_SERVICE); 840 } else { 841 return null; 842 } 843 } 844 hasFingerprintHardware(Context context)845 public static boolean hasFingerprintHardware(Context context) { 846 final FingerprintManager fingerprintManager = getFingerprintManagerOrNull(context); 847 return fingerprintManager != null && fingerprintManager.isHardwareDetected(); 848 } 849 getFaceManagerOrNull(Context context)850 public static FaceManager getFaceManagerOrNull(Context context) { 851 if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FACE)) { 852 return (FaceManager) context.getSystemService(Context.FACE_SERVICE); 853 } else { 854 return null; 855 } 856 } 857 hasFaceHardware(Context context)858 public static boolean hasFaceHardware(Context context) { 859 final FaceManager faceManager = getFaceManagerOrNull(context); 860 return faceManager != null && faceManager.isHardwareDetected(); 861 } 862 863 /** 864 * Return true if the device supports multiple biometrics authentications. 865 */ isMultipleBiometricsSupported(Context context)866 public static boolean isMultipleBiometricsSupported(Context context) { 867 return hasFingerprintHardware(context) && hasFaceHardware(context); 868 } 869 870 /** 871 * Launches an intent which may optionally have a user id defined. 872 * @param fragment Fragment to use to launch the activity. 873 * @param intent Intent to launch. 874 */ launchIntent(Fragment fragment, Intent intent)875 public static void launchIntent(Fragment fragment, Intent intent) { 876 try { 877 final int userId = intent.getIntExtra(Intent.EXTRA_USER_ID, -1); 878 879 if (userId == -1) { 880 fragment.startActivity(intent); 881 } else { 882 fragment.getActivity().startActivityAsUser(intent, new UserHandle(userId)); 883 } 884 } catch (ActivityNotFoundException e) { 885 Log.w(TAG, "No activity found for " + intent); 886 } 887 } 888 isDemoUser(Context context)889 public static boolean isDemoUser(Context context) { 890 return UserManager.isDeviceInDemoMode(context) 891 && context.getSystemService(UserManager.class).isDemoUser(); 892 } 893 getDeviceOwnerComponent(Context context)894 public static ComponentName getDeviceOwnerComponent(Context context) { 895 final DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService( 896 Context.DEVICE_POLICY_SERVICE); 897 return dpm.getDeviceOwnerComponentOnAnyUser(); 898 } 899 900 /** 901 * Returns if a given user is a profile of another user. 902 * @param user The user whose profiles wibe checked. 903 * @param profile The (potential) profile. 904 * @return if the profile is actually a profile 905 */ isProfileOf(UserInfo user, UserInfo profile)906 public static boolean isProfileOf(UserInfo user, UserInfo profile) { 907 return user.id == profile.id || 908 (user.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID 909 && user.profileGroupId == profile.profileGroupId); 910 } 911 912 /** 913 * Tries to initalize a volume with the given bundle. If it is a valid, private, and readable 914 * {@link VolumeInfo}, it is returned. If it is not valid, null is returned. 915 */ 916 @Nullable maybeInitializeVolume(StorageManager sm, Bundle bundle)917 public static VolumeInfo maybeInitializeVolume(StorageManager sm, Bundle bundle) { 918 final String volumeId = bundle.getString(VolumeInfo.EXTRA_VOLUME_ID, 919 VolumeInfo.ID_PRIVATE_INTERNAL); 920 final VolumeInfo volume = sm.findVolumeById(volumeId); 921 return isVolumeValid(volume) ? volume : null; 922 } 923 924 /** 925 * Return {@code true} if the supplied package is device owner or profile owner of at 926 * least one user. 927 * @param userManager used to get profile owner app for each user 928 * @param devicePolicyManager used to check whether it is device owner app 929 * @param packageName package to check about 930 */ isProfileOrDeviceOwner(UserManager userManager, DevicePolicyManager devicePolicyManager, String packageName)931 public static boolean isProfileOrDeviceOwner(UserManager userManager, 932 DevicePolicyManager devicePolicyManager, String packageName) { 933 final List<UserInfo> userInfos = userManager.getUsers(); 934 if (devicePolicyManager.isDeviceOwnerAppOnAnyUser(packageName)) { 935 return true; 936 } 937 for (int i = 0, size = userInfos.size(); i < size; i++) { 938 final ComponentName cn = devicePolicyManager 939 .getProfileOwnerAsUser(userInfos.get(i).id); 940 if (cn != null && cn.getPackageName().equals(packageName)) { 941 return true; 942 } 943 } 944 return false; 945 } 946 947 /** 948 * Return {@code true} if the supplied package is the device owner or profile owner of a 949 * given user. 950 * 951 * @param devicePolicyManager used to check whether it is device owner and profile owner app 952 * @param packageName package to check about 953 * @param userId the if of the relevant user 954 */ isProfileOrDeviceOwner(DevicePolicyManager devicePolicyManager, String packageName, int userId)955 public static boolean isProfileOrDeviceOwner(DevicePolicyManager devicePolicyManager, 956 String packageName, int userId) { 957 if ((devicePolicyManager.getDeviceOwnerUserId() == userId) 958 && devicePolicyManager.isDeviceOwnerApp(packageName)) { 959 return true; 960 } 961 final ComponentName cn = devicePolicyManager.getProfileOwnerAsUser(userId); 962 if (cn != null && cn.getPackageName().equals(packageName)) { 963 return true; 964 } 965 return false; 966 } 967 968 /** 969 * Return the resource id to represent the install status for an app 970 */ 971 @StringRes getInstallationStatus(ApplicationInfo info)972 public static int getInstallationStatus(ApplicationInfo info) { 973 if ((info.flags & ApplicationInfo.FLAG_INSTALLED) == 0) { 974 return R.string.not_installed; 975 } 976 return info.enabled ? R.string.installed : R.string.disabled; 977 } 978 isVolumeValid(VolumeInfo volume)979 private static boolean isVolumeValid(VolumeInfo volume) { 980 return (volume != null) && (volume.getType() == VolumeInfo.TYPE_PRIVATE) 981 && volume.isMountedReadable(); 982 } 983 setEditTextCursorPosition(EditText editText)984 public static void setEditTextCursorPosition(EditText editText) { 985 editText.setSelection(editText.getText().length()); 986 } 987 988 /** 989 * Gets the adaptive icon with a drawable that wrapped with an adaptive background using {@code 990 * backgroundColor} if it is not a {@link AdaptiveIconDrawable} 991 * 992 * If the given {@code icon} is too big, it will be auto scaled down to to avoid crashing 993 * Settings. 994 */ getAdaptiveIcon(Context context, Drawable icon, @ColorInt int backgroundColor)995 public static Drawable getAdaptiveIcon(Context context, Drawable icon, 996 @ColorInt int backgroundColor) { 997 Drawable adaptiveIcon = getSafeIcon(icon); 998 999 if (!(adaptiveIcon instanceof AdaptiveIconDrawable)) { 1000 adaptiveIcon = new AdaptiveIcon(context, adaptiveIcon); 1001 ((AdaptiveIcon) adaptiveIcon).setBackgroundColor(backgroundColor); 1002 } 1003 1004 return adaptiveIcon; 1005 } 1006 1007 /** 1008 * Gets the icon with a drawable that is scaled down to to avoid crashing Settings if it's too 1009 * big and not a {@link VectorDrawable}. 1010 */ getSafeIcon(Drawable icon)1011 public static Drawable getSafeIcon(Drawable icon) { 1012 Drawable safeIcon = icon; 1013 1014 if ((icon != null) && !(icon instanceof VectorDrawable)) { 1015 safeIcon = getSafeDrawable(icon, 1016 /* MAX_DRAWABLE_SIZE */ 600, /* MAX_DRAWABLE_SIZE */ 600); 1017 } 1018 1019 return safeIcon; 1020 } 1021 1022 /** 1023 * Gets a drawable with a limited size to avoid crashing Settings if it's too big. 1024 * 1025 * @param original original drawable, typically an app icon. 1026 * @param maxWidth maximum width, in pixels. 1027 * @param maxHeight maximum height, in pixels. 1028 */ getSafeDrawable(Drawable original, int maxWidth, int maxHeight)1029 private static Drawable getSafeDrawable(Drawable original, int maxWidth, int maxHeight) { 1030 final int actualWidth = original.getMinimumWidth(); 1031 final int actualHeight = original.getMinimumHeight(); 1032 1033 if (actualWidth <= maxWidth && actualHeight <= maxHeight) { 1034 return original; 1035 } 1036 1037 final float scaleWidth = ((float) maxWidth) / actualWidth; 1038 final float scaleHeight = ((float) maxHeight) / actualHeight; 1039 final float scale = Math.min(scaleWidth, scaleHeight); 1040 final int width = (int) (actualWidth * scale); 1041 final int height = (int) (actualHeight * scale); 1042 1043 final Bitmap bitmap; 1044 if (original instanceof BitmapDrawable) { 1045 bitmap = Bitmap.createScaledBitmap(((BitmapDrawable) original).getBitmap(), width, 1046 height, false); 1047 } else { 1048 bitmap = createBitmap(original, width, height); 1049 } 1050 return new BitmapDrawable(null, bitmap); 1051 } 1052 1053 /** 1054 * Create an Icon pointing to a drawable. 1055 */ createIconWithDrawable(Drawable drawable)1056 public static IconCompat createIconWithDrawable(Drawable drawable) { 1057 Bitmap bitmap; 1058 if (drawable instanceof BitmapDrawable) { 1059 bitmap = ((BitmapDrawable)drawable).getBitmap(); 1060 } else { 1061 final int width = drawable.getIntrinsicWidth(); 1062 final int height = drawable.getIntrinsicHeight(); 1063 bitmap = createBitmap(drawable, 1064 width > 0 ? width : 1, 1065 height > 0 ? height : 1); 1066 } 1067 return IconCompat.createWithBitmap(bitmap); 1068 } 1069 1070 /** 1071 * Creates a drawable with specified width and height. 1072 */ createBitmap(Drawable drawable, int width, int height)1073 public static Bitmap createBitmap(Drawable drawable, int width, int height) { 1074 final Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); 1075 final Canvas canvas = new Canvas(bitmap); 1076 drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); 1077 drawable.draw(canvas); 1078 return bitmap; 1079 } 1080 1081 /** 1082 * Get the {@link Drawable} that represents the app icon 1083 */ getBadgedIcon(IconDrawableFactory iconDrawableFactory, PackageManager packageManager, String packageName, int userId)1084 public static Drawable getBadgedIcon(IconDrawableFactory iconDrawableFactory, 1085 PackageManager packageManager, String packageName, int userId) { 1086 try { 1087 final ApplicationInfo appInfo = packageManager.getApplicationInfoAsUser( 1088 packageName, PackageManager.GET_META_DATA, userId); 1089 return iconDrawableFactory.getBadgedIcon(appInfo, userId); 1090 } catch (PackageManager.NameNotFoundException e) { 1091 return packageManager.getDefaultActivityIcon(); 1092 } 1093 } 1094 1095 /** Returns true if the current package is installed & enabled. */ isPackageEnabled(Context context, String packageName)1096 public static boolean isPackageEnabled(Context context, String packageName) { 1097 try { 1098 return context.getPackageManager().getApplicationInfo(packageName, 0).enabled; 1099 } catch (Exception e) { 1100 Log.e(TAG, "Error while retrieving application info for package " + packageName, e); 1101 } 1102 return false; 1103 } 1104 1105 /** Get {@link Resources} by subscription id if subscription id is valid. */ getResourcesForSubId(Context context, int subId)1106 public static Resources getResourcesForSubId(Context context, int subId) { 1107 if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) { 1108 return SubscriptionManager.getResourcesForSubId(context, subId); 1109 } else { 1110 return context.getResources(); 1111 } 1112 } 1113 1114 /** 1115 * Returns true if SYSTEM_ALERT_WINDOW permission is available. 1116 * Starting from Q, SYSTEM_ALERT_WINDOW is disabled on low ram phones. 1117 */ isSystemAlertWindowEnabled(Context context)1118 public static boolean isSystemAlertWindowEnabled(Context context) { 1119 // SYSTEM_ALERT_WINDOW is disabled on on low ram devices starting from Q 1120 ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); 1121 return !(am.isLowRamDevice() && (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)); 1122 } 1123 1124 /** 1125 * Adds a shadow appear/disappear animation to action bar scroll. 1126 * 1127 * <p/> 1128 * This method must be called after {@link Fragment#onCreate(Bundle)}. 1129 */ setActionBarShadowAnimation(Activity activity, Lifecycle lifecycle, View scrollView)1130 public static void setActionBarShadowAnimation(Activity activity, Lifecycle lifecycle, 1131 View scrollView) { 1132 if (activity == null) { 1133 Log.w(TAG, "No activity, cannot style actionbar."); 1134 return; 1135 } 1136 final ActionBar actionBar = activity.getActionBar(); 1137 if (actionBar == null) { 1138 Log.w(TAG, "No actionbar, cannot style actionbar."); 1139 return; 1140 } 1141 actionBar.setElevation(0); 1142 1143 if (lifecycle != null && scrollView != null) { 1144 ActionBarShadowController.attachToView(activity, lifecycle, scrollView); 1145 } 1146 } 1147 1148 /** 1149 * Return correct target fragment based on argument 1150 * 1151 * @param activity the activity target fragment will be launched. 1152 * @param fragmentName initial target fragment name. 1153 * @param args fragment launch arguments. 1154 */ getTargetFragment(Activity activity, String fragmentName, Bundle args)1155 public static Fragment getTargetFragment(Activity activity, String fragmentName, Bundle args) { 1156 Fragment f = null; 1157 final boolean isPersonal = args != null ? args.getInt(ProfileSelectFragment.EXTRA_PROFILE) 1158 == ProfileSelectFragment.ProfileType.PERSONAL : false; 1159 final boolean isWork = args != null ? args.getInt(ProfileSelectFragment.EXTRA_PROFILE) 1160 == ProfileSelectFragment.ProfileType.WORK : false; 1161 try { 1162 if (activity.getSystemService(UserManager.class).getUserProfiles().size() > 1 1163 && ProfileFragmentBridge.FRAGMENT_MAP.get(fragmentName) != null 1164 && !isWork && !isPersonal) { 1165 f = Fragment.instantiate(activity, 1166 ProfileFragmentBridge.FRAGMENT_MAP.get(fragmentName), args); 1167 } else { 1168 f = Fragment.instantiate(activity, fragmentName, args); 1169 } 1170 } catch (Exception e) { 1171 Log.e(TAG, "Unable to get target fragment", e); 1172 } 1173 return f; 1174 } 1175 1176 /** 1177 * Returns true if current binder uid is Settings Intelligence. 1178 */ isSettingsIntelligence(Context context)1179 public static boolean isSettingsIntelligence(Context context) { 1180 final int callingUid = Binder.getCallingUid(); 1181 final String callingPackage = context.getPackageManager().getPackagesForUid(callingUid)[0]; 1182 final boolean isSettingsIntelligence = TextUtils.equals(callingPackage, 1183 context.getString(R.string.config_settingsintelligence_package_name)); 1184 return isSettingsIntelligence; 1185 } 1186 1187 /** 1188 * Returns true if the night mode is enabled. 1189 */ isNightMode(Context context)1190 public static boolean isNightMode(Context context) { 1191 final int currentNightMode = 1192 context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK; 1193 return currentNightMode == Configuration.UI_MODE_NIGHT_YES; 1194 } 1195 1196 /** 1197 * Returns a bitmap with rounded corner. 1198 * 1199 * @param context application context. 1200 * @param source bitmap to apply round corner. 1201 * @param cornerRadius corner radius value. 1202 */ convertCornerRadiusBitmap(@onNull Context context, @NonNull Bitmap source, @NonNull float cornerRadius)1203 public static Bitmap convertCornerRadiusBitmap(@NonNull Context context, 1204 @NonNull Bitmap source, @NonNull float cornerRadius) { 1205 final Bitmap roundedBitmap = Bitmap.createBitmap(source.getWidth(), source.getHeight(), 1206 Bitmap.Config.ARGB_8888); 1207 final RoundedBitmapDrawable drawable = 1208 RoundedBitmapDrawableFactory.create(context.getResources(), source); 1209 drawable.setAntiAlias(true); 1210 drawable.setCornerRadius(cornerRadius); 1211 final Canvas canvas = new Canvas(roundedBitmap); 1212 drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); 1213 drawable.draw(canvas); 1214 return roundedBitmap; 1215 } 1216 1217 /** 1218 * Returns the color of homepage preference icons. 1219 */ 1220 @ColorInt getHomepageIconColor(Context context)1221 public static int getHomepageIconColor(Context context) { 1222 return getColorAttrDefaultColor(context, android.R.attr.textColorPrimary); 1223 } 1224 1225 /** 1226 * Returns the highlight color of homepage preference icons. 1227 */ 1228 @ColorInt getHomepageIconColorHighlight(Context context)1229 public static int getHomepageIconColorHighlight(Context context) { 1230 return context.getColor(R.color.accent_select_primary_text); 1231 } 1232 1233 /** 1234 * Returns if dreams are available to the current user. 1235 */ areDreamsAvailableToCurrentUser(Context context)1236 public static boolean areDreamsAvailableToCurrentUser(Context context) { 1237 if (!context.getResources().getBoolean( 1238 com.android.internal.R.bool.config_dreamsSupported)) { 1239 return false; 1240 } 1241 1242 if (!context.getResources().getBoolean( 1243 com.android.internal.R.bool.config_dreamsOnlyEnabledForDockUser)) { 1244 return true; 1245 } 1246 1247 final UserManager userManager = context.getSystemService(UserManager.class); 1248 return userManager != null && userManager.isSystemUser(); 1249 } 1250 } 1251