1 package com.android.settingslib; 2 3 import static android.app.admin.DevicePolicyResources.Strings.Settings.WORK_PROFILE_USER_LABEL; 4 5 import android.annotation.ColorInt; 6 import android.annotation.Nullable; 7 import android.app.admin.DevicePolicyManager; 8 import android.content.Context; 9 import android.content.Intent; 10 import android.content.pm.ApplicationInfo; 11 import android.content.pm.PackageInfo; 12 import android.content.pm.PackageManager; 13 import android.content.pm.PackageManager.NameNotFoundException; 14 import android.content.pm.Signature; 15 import android.content.pm.UserInfo; 16 import android.content.res.ColorStateList; 17 import android.content.res.Resources; 18 import android.content.res.TypedArray; 19 import android.graphics.Bitmap; 20 import android.graphics.Canvas; 21 import android.graphics.Color; 22 import android.graphics.ColorFilter; 23 import android.graphics.ColorMatrix; 24 import android.graphics.ColorMatrixColorFilter; 25 import android.graphics.drawable.Drawable; 26 import android.hardware.usb.UsbManager; 27 import android.hardware.usb.UsbPort; 28 import android.hardware.usb.UsbPortStatus; 29 import android.location.LocationManager; 30 import android.media.AudioManager; 31 import android.net.NetworkCapabilities; 32 import android.net.TetheringManager; 33 import android.net.vcn.VcnTransportInfo; 34 import android.net.wifi.WifiInfo; 35 import android.os.BatteryManager; 36 import android.os.Build; 37 import android.os.SystemProperties; 38 import android.os.UserHandle; 39 import android.os.UserManager; 40 import android.print.PrintManager; 41 import android.provider.Settings; 42 import android.telephony.AccessNetworkConstants; 43 import android.telephony.NetworkRegistrationInfo; 44 import android.telephony.ServiceState; 45 import android.telephony.TelephonyManager; 46 import android.util.Log; 47 48 import androidx.annotation.NonNull; 49 import androidx.annotation.RequiresApi; 50 import androidx.core.graphics.drawable.RoundedBitmapDrawable; 51 import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory; 52 53 import com.android.internal.annotations.VisibleForTesting; 54 import com.android.internal.util.UserIcons; 55 import com.android.launcher3.icons.BaseIconFactory.IconOptions; 56 import com.android.launcher3.icons.IconFactory; 57 import com.android.settingslib.drawable.UserIconDrawable; 58 import com.android.settingslib.fuelgauge.BatteryStatus; 59 import com.android.settingslib.utils.BuildCompatUtils; 60 61 import java.text.NumberFormat; 62 import java.util.List; 63 64 public class Utils { 65 66 @VisibleForTesting 67 static final String STORAGE_MANAGER_ENABLED_PROPERTY = 68 "ro.storage_manager.enabled"; 69 70 @VisibleForTesting 71 static final String INCOMPATIBLE_CHARGER_WARNING_DISABLED = 72 "incompatible_charger_warning_disabled"; 73 74 private static Signature[] sSystemSignature; 75 private static String sPermissionControllerPackageName; 76 private static String sServicesSystemSharedLibPackageName; 77 private static String sSharedSystemSharedLibPackageName; 78 79 static final int[] WIFI_PIE = { 80 com.android.internal.R.drawable.ic_wifi_signal_0, 81 com.android.internal.R.drawable.ic_wifi_signal_1, 82 com.android.internal.R.drawable.ic_wifi_signal_2, 83 com.android.internal.R.drawable.ic_wifi_signal_3, 84 com.android.internal.R.drawable.ic_wifi_signal_4 85 }; 86 87 static final int[] SHOW_X_WIFI_PIE = { 88 R.drawable.ic_show_x_wifi_signal_0, 89 R.drawable.ic_show_x_wifi_signal_1, 90 R.drawable.ic_show_x_wifi_signal_2, 91 R.drawable.ic_show_x_wifi_signal_3, 92 R.drawable.ic_show_x_wifi_signal_4 93 }; 94 updateLocationEnabled(Context context, boolean enabled, int userId, int source)95 public static void updateLocationEnabled(Context context, boolean enabled, int userId, 96 int source) { 97 Settings.Secure.putIntForUser( 98 context.getContentResolver(), Settings.Secure.LOCATION_CHANGER, source, 99 userId); 100 101 LocationManager locationManager = context.getSystemService(LocationManager.class); 102 locationManager.setLocationEnabledForUser(enabled, UserHandle.of(userId)); 103 } 104 105 /** 106 * Return string resource that best describes combination of tethering 107 * options available on this device. 108 */ getTetheringLabel(TetheringManager tm)109 public static int getTetheringLabel(TetheringManager tm) { 110 String[] usbRegexs = tm.getTetherableUsbRegexs(); 111 String[] wifiRegexs = tm.getTetherableWifiRegexs(); 112 String[] bluetoothRegexs = tm.getTetherableBluetoothRegexs(); 113 114 boolean usbAvailable = usbRegexs.length != 0; 115 boolean wifiAvailable = wifiRegexs.length != 0; 116 boolean bluetoothAvailable = bluetoothRegexs.length != 0; 117 118 if (wifiAvailable && usbAvailable && bluetoothAvailable) { 119 return R.string.tether_settings_title_all; 120 } else if (wifiAvailable && usbAvailable) { 121 return R.string.tether_settings_title_all; 122 } else if (wifiAvailable && bluetoothAvailable) { 123 return R.string.tether_settings_title_all; 124 } else if (wifiAvailable) { 125 return R.string.tether_settings_title_wifi; 126 } else if (usbAvailable && bluetoothAvailable) { 127 return R.string.tether_settings_title_usb_bluetooth; 128 } else if (usbAvailable) { 129 return R.string.tether_settings_title_usb; 130 } else { 131 return R.string.tether_settings_title_bluetooth; 132 } 133 } 134 135 /** 136 * Returns a label for the user, in the form of "User: user name" or "Work profile". 137 */ getUserLabel(Context context, UserInfo info)138 public static String getUserLabel(Context context, UserInfo info) { 139 String name = info != null ? info.name : null; 140 if (info.isManagedProfile()) { 141 // We use predefined values for managed profiles 142 return BuildCompatUtils.isAtLeastT() 143 ? getUpdatableManagedUserTitle(context) 144 : context.getString(R.string.managed_user_title); 145 } else if (info.isGuest()) { 146 name = context.getString(com.android.internal.R.string.guest_name); 147 } 148 if (name == null && info != null) { 149 name = Integer.toString(info.id); 150 } else if (info == null) { 151 name = context.getString(R.string.unknown); 152 } 153 return context.getResources().getString(R.string.running_process_item_user_label, name); 154 } 155 156 @RequiresApi(Build.VERSION_CODES.TIRAMISU) getUpdatableManagedUserTitle(Context context)157 private static String getUpdatableManagedUserTitle(Context context) { 158 return context.getSystemService(DevicePolicyManager.class).getResources().getString( 159 WORK_PROFILE_USER_LABEL, 160 () -> context.getString(R.string.managed_user_title)); 161 } 162 163 /** 164 * Returns a circular icon for a user. 165 */ getUserIcon(Context context, UserManager um, UserInfo user)166 public static Drawable getUserIcon(Context context, UserManager um, UserInfo user) { 167 final int iconSize = UserIconDrawable.getDefaultSize(context); 168 if (user.isManagedProfile()) { 169 Drawable drawable = UserIconDrawable.getManagedUserDrawable(context); 170 drawable.setBounds(0, 0, iconSize, iconSize); 171 return drawable; 172 } 173 if (user.iconPath != null) { 174 Bitmap icon = um.getUserIcon(user.id); 175 if (icon != null) { 176 return new UserIconDrawable(iconSize).setIcon(icon).bake(); 177 } 178 } 179 return new UserIconDrawable(iconSize).setIconDrawable( 180 UserIcons.getDefaultUserIcon(context.getResources(), user.id, /* light= */ false)) 181 .bake(); 182 } 183 184 /** Formats a double from 0.0..100.0 with an option to round **/ formatPercentage(double percentage, boolean round)185 public static String formatPercentage(double percentage, boolean round) { 186 final int localPercentage = round ? Math.round((float) percentage) : (int) percentage; 187 return formatPercentage(localPercentage); 188 } 189 190 /** Formats the ratio of amount/total as a percentage. */ formatPercentage(long amount, long total)191 public static String formatPercentage(long amount, long total) { 192 return formatPercentage(((double) amount) / total); 193 } 194 195 /** Formats an integer from 0..100 as a percentage. */ formatPercentage(int percentage)196 public static String formatPercentage(int percentage) { 197 return formatPercentage(((double) percentage) / 100.0); 198 } 199 200 /** Formats a double from 0.0..1.0 as a percentage. */ formatPercentage(double percentage)201 public static String formatPercentage(double percentage) { 202 return NumberFormat.getPercentInstance().format(percentage); 203 } 204 getBatteryLevel(Intent batteryChangedIntent)205 public static int getBatteryLevel(Intent batteryChangedIntent) { 206 int level = batteryChangedIntent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0); 207 int scale = batteryChangedIntent.getIntExtra(BatteryManager.EXTRA_SCALE, 100); 208 return (level * 100) / scale; 209 } 210 211 /** 212 * Get battery status string 213 * 214 * @param context the context 215 * @param batteryChangedIntent battery broadcast intent received from {@link 216 * Intent.ACTION_BATTERY_CHANGED}. 217 * @param compactStatus to present compact battery charging string if {@code true} 218 * @return battery status string 219 */ getBatteryStatus(Context context, Intent batteryChangedIntent, boolean compactStatus)220 public static String getBatteryStatus(Context context, Intent batteryChangedIntent, 221 boolean compactStatus) { 222 final int status = batteryChangedIntent.getIntExtra(BatteryManager.EXTRA_STATUS, 223 BatteryManager.BATTERY_STATUS_UNKNOWN); 224 final Resources res = context.getResources(); 225 226 String statusString = res.getString(R.string.battery_info_status_unknown); 227 final BatteryStatus batteryStatus = new BatteryStatus(batteryChangedIntent); 228 229 if (batteryStatus.isCharged()) { 230 statusString = res.getString(compactStatus 231 ? R.string.battery_info_status_full_charged 232 : R.string.battery_info_status_full); 233 } else { 234 if (status == BatteryManager.BATTERY_STATUS_CHARGING) { 235 if (compactStatus) { 236 statusString = res.getString(R.string.battery_info_status_charging); 237 } else if (batteryStatus.isPluggedInWired()) { 238 switch (batteryStatus.getChargingSpeed(context)) { 239 case BatteryStatus.CHARGING_FAST: 240 statusString = res.getString( 241 R.string.battery_info_status_charging_fast); 242 break; 243 case BatteryStatus.CHARGING_SLOWLY: 244 statusString = res.getString( 245 R.string.battery_info_status_charging_slow); 246 break; 247 default: 248 statusString = res.getString(R.string.battery_info_status_charging); 249 break; 250 } 251 } else if (batteryStatus.isPluggedInDock()) { 252 statusString = res.getString(R.string.battery_info_status_charging_dock); 253 } else { 254 statusString = res.getString(R.string.battery_info_status_charging_wireless); 255 } 256 } else if (status == BatteryManager.BATTERY_STATUS_DISCHARGING) { 257 statusString = res.getString(R.string.battery_info_status_discharging); 258 } else if (status == BatteryManager.BATTERY_STATUS_NOT_CHARGING) { 259 statusString = res.getString(R.string.battery_info_status_not_charging); 260 } 261 } 262 263 return statusString; 264 } 265 getColorAccent(Context context)266 public static ColorStateList getColorAccent(Context context) { 267 return getColorAttr(context, android.R.attr.colorAccent); 268 } 269 getColorError(Context context)270 public static ColorStateList getColorError(Context context) { 271 return getColorAttr(context, android.R.attr.colorError); 272 } 273 274 @ColorInt getColorAccentDefaultColor(Context context)275 public static int getColorAccentDefaultColor(Context context) { 276 return getColorAttrDefaultColor(context, android.R.attr.colorAccent); 277 } 278 279 @ColorInt getColorErrorDefaultColor(Context context)280 public static int getColorErrorDefaultColor(Context context) { 281 return getColorAttrDefaultColor(context, android.R.attr.colorError); 282 } 283 284 @ColorInt getColorStateListDefaultColor(Context context, int resId)285 public static int getColorStateListDefaultColor(Context context, int resId) { 286 final ColorStateList list = 287 context.getResources().getColorStateList(resId, context.getTheme()); 288 return list.getDefaultColor(); 289 } 290 291 /** 292 * This method computes disabled color from normal color 293 * 294 * @param context the context 295 * @param inputColor normal color. 296 * @return disabled color. 297 */ 298 @ColorInt getDisabled(Context context, int inputColor)299 public static int getDisabled(Context context, int inputColor) { 300 return applyAlphaAttr(context, android.R.attr.disabledAlpha, inputColor); 301 } 302 303 @ColorInt applyAlphaAttr(Context context, int attr, int inputColor)304 public static int applyAlphaAttr(Context context, int attr, int inputColor) { 305 TypedArray ta = context.obtainStyledAttributes(new int[]{attr}); 306 float alpha = ta.getFloat(0, 0); 307 ta.recycle(); 308 return applyAlpha(alpha, inputColor); 309 } 310 311 @ColorInt applyAlpha(float alpha, int inputColor)312 public static int applyAlpha(float alpha, int inputColor) { 313 alpha *= Color.alpha(inputColor); 314 return Color.argb((int) (alpha), Color.red(inputColor), Color.green(inputColor), 315 Color.blue(inputColor)); 316 } 317 318 @ColorInt getColorAttrDefaultColor(Context context, int attr)319 public static int getColorAttrDefaultColor(Context context, int attr) { 320 return getColorAttrDefaultColor(context, attr, 0); 321 } 322 323 /** 324 * Get color styled attribute {@code attr}, default to {@code defValue} if not found. 325 */ 326 @ColorInt getColorAttrDefaultColor(Context context, int attr, @ColorInt int defValue)327 public static int getColorAttrDefaultColor(Context context, int attr, @ColorInt int defValue) { 328 TypedArray ta = context.obtainStyledAttributes(new int[]{attr}); 329 @ColorInt int colorAccent = ta.getColor(0, defValue); 330 ta.recycle(); 331 return colorAccent; 332 } 333 getColorAttr(Context context, int attr)334 public static ColorStateList getColorAttr(Context context, int attr) { 335 TypedArray ta = context.obtainStyledAttributes(new int[]{attr}); 336 ColorStateList stateList = null; 337 try { 338 stateList = ta.getColorStateList(0); 339 } finally { 340 ta.recycle(); 341 } 342 return stateList; 343 } 344 getThemeAttr(Context context, int attr)345 public static int getThemeAttr(Context context, int attr) { 346 return getThemeAttr(context, attr, 0); 347 } 348 getThemeAttr(Context context, int attr, int defaultValue)349 public static int getThemeAttr(Context context, int attr, int defaultValue) { 350 TypedArray ta = context.obtainStyledAttributes(new int[]{attr}); 351 int theme = ta.getResourceId(0, defaultValue); 352 ta.recycle(); 353 return theme; 354 } 355 getDrawable(Context context, int attr)356 public static Drawable getDrawable(Context context, int attr) { 357 TypedArray ta = context.obtainStyledAttributes(new int[]{attr}); 358 Drawable drawable = ta.getDrawable(0); 359 ta.recycle(); 360 return drawable; 361 } 362 363 /** 364 * Create a color matrix suitable for a ColorMatrixColorFilter that modifies only the color but 365 * preserves the alpha for a given drawable 366 * @param color 367 * @return a color matrix that uses the source alpha and given color 368 */ getAlphaInvariantColorMatrixForColor(@olorInt int color)369 public static ColorMatrix getAlphaInvariantColorMatrixForColor(@ColorInt int color) { 370 int r = Color.red(color); 371 int g = Color.green(color); 372 int b = Color.blue(color); 373 374 ColorMatrix cm = new ColorMatrix(new float[] { 375 0, 0, 0, 0, r, 376 0, 0, 0, 0, g, 377 0, 0, 0, 0, b, 378 0, 0, 0, 1, 0 }); 379 380 return cm; 381 } 382 383 /** 384 * Create a ColorMatrixColorFilter to tint a drawable but retain its alpha characteristics 385 * 386 * @return a ColorMatrixColorFilter which changes the color of the output but is invariant on 387 * the source alpha 388 */ getAlphaInvariantColorFilterForColor(@olorInt int color)389 public static ColorFilter getAlphaInvariantColorFilterForColor(@ColorInt int color) { 390 return new ColorMatrixColorFilter(getAlphaInvariantColorMatrixForColor(color)); 391 } 392 393 /** 394 * Determine whether a package is a "system package", in which case certain things (like 395 * disabling notifications or disabling the package altogether) should be disallowed. 396 * <p> 397 * Note: This function is just for UI treatment, and should not be used for security purposes. 398 * 399 * @deprecated Use {@link ApplicationInfo#isSignedWithPlatformKey()} and 400 * {@link #isEssentialPackage} instead. 401 */ 402 @Deprecated isSystemPackage(Resources resources, PackageManager pm, PackageInfo pkg)403 public static boolean isSystemPackage(Resources resources, PackageManager pm, PackageInfo pkg) { 404 if (sSystemSignature == null) { 405 sSystemSignature = new Signature[]{getSystemSignature(pm)}; 406 } 407 return (sSystemSignature[0] != null && sSystemSignature[0].equals(getFirstSignature(pkg))) 408 || isEssentialPackage(resources, pm, pkg.packageName); 409 } 410 getFirstSignature(PackageInfo pkg)411 private static Signature getFirstSignature(PackageInfo pkg) { 412 if (pkg != null && pkg.signatures != null && pkg.signatures.length > 0) { 413 return pkg.signatures[0]; 414 } 415 return null; 416 } 417 getSystemSignature(PackageManager pm)418 private static Signature getSystemSignature(PackageManager pm) { 419 try { 420 final PackageInfo sys = pm.getPackageInfo("android", PackageManager.GET_SIGNATURES); 421 return getFirstSignature(sys); 422 } catch (NameNotFoundException e) { 423 } 424 return null; 425 } 426 427 /** 428 * Determine whether a package is a "essential package". 429 * <p> 430 * In which case certain things (like disabling the package) should be disallowed. 431 */ isEssentialPackage( Resources resources, PackageManager pm, String packageName)432 public static boolean isEssentialPackage( 433 Resources resources, PackageManager pm, String packageName) { 434 if (sPermissionControllerPackageName == null) { 435 sPermissionControllerPackageName = pm.getPermissionControllerPackageName(); 436 } 437 if (sServicesSystemSharedLibPackageName == null) { 438 sServicesSystemSharedLibPackageName = pm.getServicesSystemSharedLibraryPackageName(); 439 } 440 if (sSharedSystemSharedLibPackageName == null) { 441 sSharedSystemSharedLibPackageName = pm.getSharedSystemSharedLibraryPackageName(); 442 } 443 return packageName.equals(sPermissionControllerPackageName) 444 || packageName.equals(sServicesSystemSharedLibPackageName) 445 || packageName.equals(sSharedSystemSharedLibPackageName) 446 || packageName.equals(PrintManager.PRINT_SPOOLER_PACKAGE_NAME) 447 || isDeviceProvisioningPackage(resources, packageName); 448 } 449 450 /** 451 * Returns {@code true} if the supplied package is the device provisioning app. Otherwise, 452 * returns {@code false}. 453 */ isDeviceProvisioningPackage(Resources resources, String packageName)454 public static boolean isDeviceProvisioningPackage(Resources resources, String packageName) { 455 String deviceProvisioningPackage = resources.getString( 456 com.android.internal.R.string.config_deviceProvisioningPackage); 457 return deviceProvisioningPackage != null && deviceProvisioningPackage.equals(packageName); 458 } 459 460 /** 461 * Returns the Wifi icon resource for a given RSSI level. 462 * 463 * @param level The number of bars to show (0-4) 464 * @throws IllegalArgumentException if an invalid RSSI level is given. 465 */ getWifiIconResource(int level)466 public static int getWifiIconResource(int level) { 467 return getWifiIconResource(false /* showX */, level); 468 } 469 470 /** 471 * Returns the Wifi icon resource for a given RSSI level. 472 * 473 * @param showX True if a connected Wi-Fi network has the problem which should show Pie+x 474 * signal icon to users. 475 * @param level The number of bars to show (0-4) 476 * @throws IllegalArgumentException if an invalid RSSI level is given. 477 */ getWifiIconResource(boolean showX, int level)478 public static int getWifiIconResource(boolean showX, int level) { 479 if (level < 0 || level >= WIFI_PIE.length) { 480 throw new IllegalArgumentException("No Wifi icon found for level: " + level); 481 } 482 return showX ? SHOW_X_WIFI_PIE[level] : WIFI_PIE[level]; 483 } 484 getDefaultStorageManagerDaysToRetain(Resources resources)485 public static int getDefaultStorageManagerDaysToRetain(Resources resources) { 486 int defaultDays = Settings.Secure.AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN_DEFAULT; 487 try { 488 defaultDays = 489 resources.getInteger( 490 com.android 491 .internal 492 .R 493 .integer 494 .config_storageManagerDaystoRetainDefault); 495 } catch (Resources.NotFoundException e) { 496 // We are likely in a test environment. 497 } 498 return defaultDays; 499 } 500 isWifiOnly(Context context)501 public static boolean isWifiOnly(Context context) { 502 return !context.getSystemService(TelephonyManager.class).isDataCapable(); 503 } 504 505 /** Returns if the automatic storage management feature is turned on or not. **/ isStorageManagerEnabled(Context context)506 public static boolean isStorageManagerEnabled(Context context) { 507 boolean isDefaultOn; 508 try { 509 isDefaultOn = SystemProperties.getBoolean(STORAGE_MANAGER_ENABLED_PROPERTY, false); 510 } catch (Resources.NotFoundException e) { 511 isDefaultOn = false; 512 } 513 return Settings.Secure.getInt(context.getContentResolver(), 514 Settings.Secure.AUTOMATIC_STORAGE_MANAGER_ENABLED, 515 isDefaultOn ? 1 : 0) 516 != 0; 517 } 518 519 /** 520 * get that {@link AudioManager#getMode()} is in ringing/call/communication(VoIP) status. 521 */ isAudioModeOngoingCall(Context context)522 public static boolean isAudioModeOngoingCall(Context context) { 523 final AudioManager audioManager = context.getSystemService(AudioManager.class); 524 final int audioMode = audioManager.getMode(); 525 return audioMode == AudioManager.MODE_RINGTONE 526 || audioMode == AudioManager.MODE_IN_CALL 527 || audioMode == AudioManager.MODE_IN_COMMUNICATION; 528 } 529 530 /** 531 * Return the service state is in-service or not. 532 * To make behavior consistent with SystemUI and Settings/AboutPhone/SIM status UI 533 * 534 * @param serviceState Service state. {@link ServiceState} 535 */ isInService(ServiceState serviceState)536 public static boolean isInService(ServiceState serviceState) { 537 if (serviceState == null) { 538 return false; 539 } 540 int state = getCombinedServiceState(serviceState); 541 if (state == ServiceState.STATE_POWER_OFF 542 || state == ServiceState.STATE_OUT_OF_SERVICE 543 || state == ServiceState.STATE_EMERGENCY_ONLY) { 544 return false; 545 } else { 546 return true; 547 } 548 } 549 550 /** 551 * Return the combined service state. 552 * To make behavior consistent with SystemUI and Settings/AboutPhone/SIM status UI 553 * 554 * @param serviceState Service state. {@link ServiceState} 555 */ getCombinedServiceState(ServiceState serviceState)556 public static int getCombinedServiceState(ServiceState serviceState) { 557 if (serviceState == null) { 558 return ServiceState.STATE_OUT_OF_SERVICE; 559 } 560 561 // Consider the device to be in service if either voice or data 562 // service is available. Some SIM cards are marketed as data-only 563 // and do not support voice service, and on these SIM cards, we 564 // want to show signal bars for data service as well as the "no 565 // service" or "emergency calls only" text that indicates that voice 566 // is not available. Note that we ignore the IWLAN service state 567 // because that state indicates the use of VoWIFI and not cell service 568 final int state = serviceState.getState(); 569 final int dataState = serviceState.getDataRegistrationState(); 570 571 if (state == ServiceState.STATE_OUT_OF_SERVICE 572 || state == ServiceState.STATE_EMERGENCY_ONLY) { 573 if (dataState == ServiceState.STATE_IN_SERVICE && isNotInIwlan(serviceState)) { 574 return ServiceState.STATE_IN_SERVICE; 575 } 576 } 577 return state; 578 } 579 580 /** Get the corresponding adaptive icon drawable. */ getBadgedIcon(Context context, Drawable icon, UserHandle user)581 public static Drawable getBadgedIcon(Context context, Drawable icon, UserHandle user) { 582 UserManager um = context.getSystemService(UserManager.class); 583 boolean isClone = um.getProfiles(user.getIdentifier()).stream() 584 .anyMatch(profile -> 585 profile.isCloneProfile() && profile.id == user.getIdentifier()); 586 try (IconFactory iconFactory = IconFactory.obtain(context)) { 587 return iconFactory 588 .createBadgedIconBitmap( 589 icon, 590 new IconOptions().setUser(user).setIsCloneProfile(isClone)) 591 .newIcon(context); 592 } 593 } 594 595 /** Get the {@link Drawable} that represents the app icon */ getBadgedIcon(Context context, ApplicationInfo appInfo)596 public static Drawable getBadgedIcon(Context context, ApplicationInfo appInfo) { 597 return getBadgedIcon(context, appInfo.loadUnbadgedIcon(context.getPackageManager()), 598 UserHandle.getUserHandleForUid(appInfo.uid)); 599 } 600 isNotInIwlan(ServiceState serviceState)601 private static boolean isNotInIwlan(ServiceState serviceState) { 602 final NetworkRegistrationInfo networkRegWlan = serviceState.getNetworkRegistrationInfo( 603 NetworkRegistrationInfo.DOMAIN_PS, 604 AccessNetworkConstants.TRANSPORT_TYPE_WLAN); 605 if (networkRegWlan == null) { 606 return true; 607 } 608 609 final boolean isInIwlan = (networkRegWlan.getRegistrationState() 610 == NetworkRegistrationInfo.REGISTRATION_STATE_HOME) 611 || (networkRegWlan.getRegistrationState() 612 == NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING); 613 return !isInIwlan; 614 } 615 616 /** 617 * Returns a bitmap with rounded corner. 618 * 619 * @param context application context. 620 * @param source bitmap to apply round corner. 621 * @param cornerRadius corner radius value. 622 */ convertCornerRadiusBitmap(@onNull Context context, @NonNull Bitmap source, @NonNull float cornerRadius)623 public static Bitmap convertCornerRadiusBitmap(@NonNull Context context, 624 @NonNull Bitmap source, @NonNull float cornerRadius) { 625 final Bitmap roundedBitmap = Bitmap.createBitmap(source.getWidth(), source.getHeight(), 626 Bitmap.Config.ARGB_8888); 627 final RoundedBitmapDrawable drawable = 628 RoundedBitmapDrawableFactory.create(context.getResources(), source); 629 drawable.setAntiAlias(true); 630 drawable.setCornerRadius(cornerRadius); 631 final Canvas canvas = new Canvas(roundedBitmap); 632 drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); 633 drawable.draw(canvas); 634 return roundedBitmap; 635 } 636 637 /** 638 * Returns the WifiInfo for the underlying WiFi network of the VCN network, returns null if the 639 * input NetworkCapabilities is not for a VCN network with underlying WiFi network. 640 * 641 * TODO(b/238425913): Move this method to be inside systemui not settingslib once we've migrated 642 * off of {@link WifiStatusTracker} and {@link NetworkControllerImpl}. 643 * 644 * @param networkCapabilities NetworkCapabilities of the network. 645 */ 646 @Nullable tryGetWifiInfoForVcn(NetworkCapabilities networkCapabilities)647 public static WifiInfo tryGetWifiInfoForVcn(NetworkCapabilities networkCapabilities) { 648 if (networkCapabilities.getTransportInfo() == null 649 || !(networkCapabilities.getTransportInfo() instanceof VcnTransportInfo)) { 650 return null; 651 } 652 VcnTransportInfo vcnTransportInfo = 653 (VcnTransportInfo) networkCapabilities.getTransportInfo(); 654 return vcnTransportInfo.getWifiInfo(); 655 } 656 657 /** Whether there is any incompatible chargers in the current UsbPort? */ containsIncompatibleChargers(Context context, String tag)658 public static boolean containsIncompatibleChargers(Context context, String tag) { 659 // Avoid the caller doesn't have permission to read the "Settings.Secure" data. 660 try { 661 // Whether the incompatible charger warning is disabled or not 662 if (Settings.Secure.getInt(context.getContentResolver(), 663 INCOMPATIBLE_CHARGER_WARNING_DISABLED, 0) == 1) { 664 Log.d(tag, "containsIncompatibleChargers: disabled"); 665 return false; 666 } 667 } catch (Exception e) { 668 Log.e(tag, "containsIncompatibleChargers()", e); 669 return false; 670 } 671 672 final List<UsbPort> usbPortList = 673 context.getSystemService(UsbManager.class).getPorts(); 674 if (usbPortList == null || usbPortList.isEmpty()) { 675 return false; 676 } 677 for (UsbPort usbPort : usbPortList) { 678 Log.d(tag, "usbPort: " + usbPort); 679 if (!usbPort.supportsComplianceWarnings()) { 680 continue; 681 } 682 final UsbPortStatus usbStatus = usbPort.getStatus(); 683 if (usbStatus == null || !usbStatus.isConnected()) { 684 continue; 685 } 686 final int[] complianceWarnings = usbStatus.getComplianceWarnings(); 687 if (complianceWarnings == null || complianceWarnings.length == 0) { 688 continue; 689 } 690 for (int complianceWarningType : complianceWarnings) { 691 switch (complianceWarningType) { 692 case UsbPortStatus.COMPLIANCE_WARNING_OTHER: 693 case UsbPortStatus.COMPLIANCE_WARNING_DEBUG_ACCESSORY: 694 return true; 695 default: 696 break; 697 } 698 } 699 } 700 return false; 701 } 702 703 } 704