• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package com.android.settingslib;
2 
3 import android.annotation.ColorInt;
4 import android.content.Context;
5 import android.content.Intent;
6 import android.content.pm.ApplicationInfo;
7 import android.content.pm.PackageInfo;
8 import android.content.pm.PackageManager;
9 import android.content.pm.PackageManager.NameNotFoundException;
10 import android.content.pm.Signature;
11 import android.content.pm.UserInfo;
12 import android.content.res.ColorStateList;
13 import android.content.res.Resources;
14 import android.content.res.TypedArray;
15 import android.graphics.Bitmap;
16 import android.graphics.Canvas;
17 import android.graphics.Color;
18 import android.graphics.ColorFilter;
19 import android.graphics.ColorMatrix;
20 import android.graphics.ColorMatrixColorFilter;
21 import android.graphics.drawable.BitmapDrawable;
22 import android.graphics.drawable.Drawable;
23 import android.location.LocationManager;
24 import android.media.AudioManager;
25 import android.net.ConnectivityManager;
26 import android.os.BatteryManager;
27 import android.os.SystemProperties;
28 import android.os.UserHandle;
29 import android.os.UserManager;
30 import android.print.PrintManager;
31 import android.provider.Settings;
32 import android.telephony.AccessNetworkConstants;
33 import android.telephony.NetworkRegistrationInfo;
34 import android.telephony.ServiceState;
35 
36 import androidx.annotation.NonNull;
37 import androidx.core.graphics.drawable.RoundedBitmapDrawable;
38 import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
39 
40 import com.android.internal.annotations.VisibleForTesting;
41 import com.android.internal.util.UserIcons;
42 import com.android.launcher3.icons.IconFactory;
43 import com.android.settingslib.drawable.UserIconDrawable;
44 import com.android.settingslib.fuelgauge.BatteryStatus;
45 
46 import java.text.NumberFormat;
47 
48 public class Utils {
49 
50     @VisibleForTesting
51     static final String STORAGE_MANAGER_ENABLED_PROPERTY =
52             "ro.storage_manager.enabled";
53 
54     private static Signature[] sSystemSignature;
55     private static String sPermissionControllerPackageName;
56     private static String sServicesSystemSharedLibPackageName;
57     private static String sSharedSystemSharedLibPackageName;
58 
59     static final int[] WIFI_PIE = {
60         com.android.internal.R.drawable.ic_wifi_signal_0,
61         com.android.internal.R.drawable.ic_wifi_signal_1,
62         com.android.internal.R.drawable.ic_wifi_signal_2,
63         com.android.internal.R.drawable.ic_wifi_signal_3,
64         com.android.internal.R.drawable.ic_wifi_signal_4
65     };
66 
67     static final int[] SHOW_X_WIFI_PIE = {
68         R.drawable.ic_show_x_wifi_signal_0,
69         R.drawable.ic_show_x_wifi_signal_1,
70         R.drawable.ic_show_x_wifi_signal_2,
71         R.drawable.ic_show_x_wifi_signal_3,
72         R.drawable.ic_show_x_wifi_signal_4
73     };
74 
updateLocationEnabled(Context context, boolean enabled, int userId, int source)75     public static void updateLocationEnabled(Context context, boolean enabled, int userId,
76             int source) {
77         Settings.Secure.putIntForUser(
78                 context.getContentResolver(), Settings.Secure.LOCATION_CHANGER, source,
79                 userId);
80 
81         LocationManager locationManager = context.getSystemService(LocationManager.class);
82         locationManager.setLocationEnabledForUser(enabled, UserHandle.of(userId));
83     }
84 
85     /**
86      * Return string resource that best describes combination of tethering
87      * options available on this device.
88      */
getTetheringLabel(ConnectivityManager cm)89     public static int getTetheringLabel(ConnectivityManager cm) {
90         String[] usbRegexs = cm.getTetherableUsbRegexs();
91         String[] wifiRegexs = cm.getTetherableWifiRegexs();
92         String[] bluetoothRegexs = cm.getTetherableBluetoothRegexs();
93 
94         boolean usbAvailable = usbRegexs.length != 0;
95         boolean wifiAvailable = wifiRegexs.length != 0;
96         boolean bluetoothAvailable = bluetoothRegexs.length != 0;
97 
98         if (wifiAvailable && usbAvailable && bluetoothAvailable) {
99             return R.string.tether_settings_title_all;
100         } else if (wifiAvailable && usbAvailable) {
101             return R.string.tether_settings_title_all;
102         } else if (wifiAvailable && bluetoothAvailable) {
103             return R.string.tether_settings_title_all;
104         } else if (wifiAvailable) {
105             return R.string.tether_settings_title_wifi;
106         } else if (usbAvailable && bluetoothAvailable) {
107             return R.string.tether_settings_title_usb_bluetooth;
108         } else if (usbAvailable) {
109             return R.string.tether_settings_title_usb;
110         } else {
111             return R.string.tether_settings_title_bluetooth;
112         }
113     }
114 
115     /**
116      * Returns a label for the user, in the form of "User: user name" or "Work profile".
117      */
getUserLabel(Context context, UserInfo info)118     public static String getUserLabel(Context context, UserInfo info) {
119         String name = info != null ? info.name : null;
120         if (info.isManagedProfile()) {
121             // We use predefined values for managed profiles
122             return context.getString(R.string.managed_user_title);
123         } else if (info.isGuest()) {
124             name = context.getString(R.string.user_guest);
125         }
126         if (name == null && info != null) {
127             name = Integer.toString(info.id);
128         } else if (info == null) {
129             name = context.getString(R.string.unknown);
130         }
131         return context.getResources().getString(R.string.running_process_item_user_label, name);
132     }
133 
134     /**
135      * Returns a circular icon for a user.
136      */
getUserIcon(Context context, UserManager um, UserInfo user)137     public static Drawable getUserIcon(Context context, UserManager um, UserInfo user) {
138         final int iconSize = UserIconDrawable.getSizeForList(context);
139         if (user.isManagedProfile()) {
140             Drawable drawable = UserIconDrawable.getManagedUserDrawable(context);
141             drawable.setBounds(0, 0, iconSize, iconSize);
142             return drawable;
143         }
144         if (user.iconPath != null) {
145             Bitmap icon = um.getUserIcon(user.id);
146             if (icon != null) {
147                 return new UserIconDrawable(iconSize).setIcon(icon).bake();
148             }
149         }
150         return new UserIconDrawable(iconSize).setIconDrawable(
151                 UserIcons.getDefaultUserIcon(context.getResources(), user.id, /* light= */ false))
152                 .bake();
153     }
154 
155     /** Formats a double from 0.0..100.0 with an option to round **/
formatPercentage(double percentage, boolean round)156     public static String formatPercentage(double percentage, boolean round) {
157         final int localPercentage = round ? Math.round((float) percentage) : (int) percentage;
158         return formatPercentage(localPercentage);
159     }
160 
161     /** Formats the ratio of amount/total as a percentage. */
formatPercentage(long amount, long total)162     public static String formatPercentage(long amount, long total) {
163         return formatPercentage(((double) amount) / total);
164     }
165 
166     /** Formats an integer from 0..100 as a percentage. */
formatPercentage(int percentage)167     public static String formatPercentage(int percentage) {
168         return formatPercentage(((double) percentage) / 100.0);
169     }
170 
171     /** Formats a double from 0.0..1.0 as a percentage. */
formatPercentage(double percentage)172     public static String formatPercentage(double percentage) {
173         return NumberFormat.getPercentInstance().format(percentage);
174     }
175 
getBatteryLevel(Intent batteryChangedIntent)176     public static int getBatteryLevel(Intent batteryChangedIntent) {
177         int level = batteryChangedIntent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0);
178         int scale = batteryChangedIntent.getIntExtra(BatteryManager.EXTRA_SCALE, 100);
179         return (level * 100) / scale;
180     }
181 
182     /**
183      * Get battery status string
184      *
185      * @param context the context
186      * @param batteryChangedIntent battery broadcast intent received from {@link
187      *                             Intent.ACTION_BATTERY_CHANGED}.
188      * @return battery status string
189      */
getBatteryStatus(Context context, Intent batteryChangedIntent)190     public static String getBatteryStatus(Context context, Intent batteryChangedIntent) {
191         final int status = batteryChangedIntent.getIntExtra(BatteryManager.EXTRA_STATUS,
192                 BatteryManager.BATTERY_STATUS_UNKNOWN);
193         final Resources res = context.getResources();
194 
195         String statusString = res.getString(R.string.battery_info_status_unknown);
196         final BatteryStatus batteryStatus = new BatteryStatus(batteryChangedIntent);
197 
198         if (batteryStatus.isCharged()) {
199             statusString = res.getString(R.string.battery_info_status_full);
200         } else {
201             if (status == BatteryManager.BATTERY_STATUS_CHARGING) {
202                 switch (batteryStatus.getChargingSpeed(context)) {
203                     case BatteryStatus.CHARGING_FAST:
204                         statusString = res.getString(R.string.battery_info_status_charging_fast);
205                         break;
206                     case BatteryStatus.CHARGING_SLOWLY:
207                         statusString = res.getString(R.string.battery_info_status_charging_slow);
208                         break;
209                     default:
210                         statusString = res.getString(R.string.battery_info_status_charging);
211                         break;
212                 }
213 
214             } else if (status == BatteryManager.BATTERY_STATUS_DISCHARGING) {
215                 statusString = res.getString(R.string.battery_info_status_discharging);
216             } else if (status == BatteryManager.BATTERY_STATUS_NOT_CHARGING) {
217                 statusString = res.getString(R.string.battery_info_status_not_charging);
218             }
219         }
220 
221         return statusString;
222     }
223 
getColorAccent(Context context)224     public static ColorStateList getColorAccent(Context context) {
225         return getColorAttr(context, android.R.attr.colorAccent);
226     }
227 
getColorError(Context context)228     public static ColorStateList getColorError(Context context) {
229         return getColorAttr(context, android.R.attr.colorError);
230     }
231 
232     @ColorInt
getColorAccentDefaultColor(Context context)233     public static int getColorAccentDefaultColor(Context context) {
234         return getColorAttrDefaultColor(context, android.R.attr.colorAccent);
235     }
236 
237     @ColorInt
getColorErrorDefaultColor(Context context)238     public static int getColorErrorDefaultColor(Context context) {
239         return getColorAttrDefaultColor(context, android.R.attr.colorError);
240     }
241 
242     @ColorInt
getColorStateListDefaultColor(Context context, int resId)243     public static int getColorStateListDefaultColor(Context context, int resId) {
244         final ColorStateList list =
245                 context.getResources().getColorStateList(resId, context.getTheme());
246         return list.getDefaultColor();
247     }
248 
249     /**
250      * This method computes disabled color from normal color
251      *
252      * @param context the context
253      * @param inputColor normal color.
254      * @return disabled color.
255      */
256     @ColorInt
getDisabled(Context context, int inputColor)257     public static int getDisabled(Context context, int inputColor) {
258         return applyAlphaAttr(context, android.R.attr.disabledAlpha, inputColor);
259     }
260 
261     @ColorInt
applyAlphaAttr(Context context, int attr, int inputColor)262     public static int applyAlphaAttr(Context context, int attr, int inputColor) {
263         TypedArray ta = context.obtainStyledAttributes(new int[]{attr});
264         float alpha = ta.getFloat(0, 0);
265         ta.recycle();
266         return applyAlpha(alpha, inputColor);
267     }
268 
269     @ColorInt
applyAlpha(float alpha, int inputColor)270     public static int applyAlpha(float alpha, int inputColor) {
271         alpha *= Color.alpha(inputColor);
272         return Color.argb((int) (alpha), Color.red(inputColor), Color.green(inputColor),
273                 Color.blue(inputColor));
274     }
275 
276     @ColorInt
getColorAttrDefaultColor(Context context, int attr)277     public static int getColorAttrDefaultColor(Context context, int attr) {
278         TypedArray ta = context.obtainStyledAttributes(new int[]{attr});
279         @ColorInt int colorAccent = ta.getColor(0, 0);
280         ta.recycle();
281         return colorAccent;
282     }
283 
getColorAttr(Context context, int attr)284     public static ColorStateList getColorAttr(Context context, int attr) {
285         TypedArray ta = context.obtainStyledAttributes(new int[]{attr});
286         ColorStateList stateList = null;
287         try {
288             stateList = ta.getColorStateList(0);
289         } finally {
290             ta.recycle();
291         }
292         return stateList;
293     }
294 
getThemeAttr(Context context, int attr)295     public static int getThemeAttr(Context context, int attr) {
296         return getThemeAttr(context, attr, 0);
297     }
298 
getThemeAttr(Context context, int attr, int defaultValue)299     public static int getThemeAttr(Context context, int attr, int defaultValue) {
300         TypedArray ta = context.obtainStyledAttributes(new int[]{attr});
301         int theme = ta.getResourceId(0, defaultValue);
302         ta.recycle();
303         return theme;
304     }
305 
getDrawable(Context context, int attr)306     public static Drawable getDrawable(Context context, int attr) {
307         TypedArray ta = context.obtainStyledAttributes(new int[]{attr});
308         Drawable drawable = ta.getDrawable(0);
309         ta.recycle();
310         return drawable;
311     }
312 
313     /**
314     * Create a color matrix suitable for a ColorMatrixColorFilter that modifies only the color but
315     * preserves the alpha for a given drawable
316     * @param color
317     * @return a color matrix that uses the source alpha and given color
318     */
getAlphaInvariantColorMatrixForColor(@olorInt int color)319     public static ColorMatrix getAlphaInvariantColorMatrixForColor(@ColorInt int color) {
320         int r = Color.red(color);
321         int g = Color.green(color);
322         int b = Color.blue(color);
323 
324         ColorMatrix cm = new ColorMatrix(new float[] {
325                 0, 0, 0, 0, r,
326                 0, 0, 0, 0, g,
327                 0, 0, 0, 0, b,
328                 0, 0, 0, 1, 0 });
329 
330         return cm;
331     }
332 
333     /**
334      * Create a ColorMatrixColorFilter to tint a drawable but retain its alpha characteristics
335      *
336      * @return a ColorMatrixColorFilter which changes the color of the output but is invariant on
337      * the source alpha
338      */
getAlphaInvariantColorFilterForColor(@olorInt int color)339     public static ColorFilter getAlphaInvariantColorFilterForColor(@ColorInt int color) {
340         return new ColorMatrixColorFilter(getAlphaInvariantColorMatrixForColor(color));
341     }
342 
343     /**
344      * Determine whether a package is a "system package", in which case certain things (like
345      * disabling notifications or disabling the package altogether) should be disallowed.
346      */
isSystemPackage(Resources resources, PackageManager pm, PackageInfo pkg)347     public static boolean isSystemPackage(Resources resources, PackageManager pm, PackageInfo pkg) {
348         if (sSystemSignature == null) {
349             sSystemSignature = new Signature[]{getSystemSignature(pm)};
350         }
351         if (sPermissionControllerPackageName == null) {
352             sPermissionControllerPackageName = pm.getPermissionControllerPackageName();
353         }
354         if (sServicesSystemSharedLibPackageName == null) {
355             sServicesSystemSharedLibPackageName = pm.getServicesSystemSharedLibraryPackageName();
356         }
357         if (sSharedSystemSharedLibPackageName == null) {
358             sSharedSystemSharedLibPackageName = pm.getSharedSystemSharedLibraryPackageName();
359         }
360         return (sSystemSignature[0] != null
361                 && sSystemSignature[0].equals(getFirstSignature(pkg)))
362                 || pkg.packageName.equals(sPermissionControllerPackageName)
363                 || pkg.packageName.equals(sServicesSystemSharedLibPackageName)
364                 || pkg.packageName.equals(sSharedSystemSharedLibPackageName)
365                 || pkg.packageName.equals(PrintManager.PRINT_SPOOLER_PACKAGE_NAME)
366                 || isDeviceProvisioningPackage(resources, pkg.packageName);
367     }
368 
getFirstSignature(PackageInfo pkg)369     private static Signature getFirstSignature(PackageInfo pkg) {
370         if (pkg != null && pkg.signatures != null && pkg.signatures.length > 0) {
371             return pkg.signatures[0];
372         }
373         return null;
374     }
375 
getSystemSignature(PackageManager pm)376     private static Signature getSystemSignature(PackageManager pm) {
377         try {
378             final PackageInfo sys = pm.getPackageInfo("android", PackageManager.GET_SIGNATURES);
379             return getFirstSignature(sys);
380         } catch (NameNotFoundException e) {
381         }
382         return null;
383     }
384 
385     /**
386      * Returns {@code true} if the supplied package is the device provisioning app. Otherwise,
387      * returns {@code false}.
388      */
isDeviceProvisioningPackage(Resources resources, String packageName)389     public static boolean isDeviceProvisioningPackage(Resources resources, String packageName) {
390         String deviceProvisioningPackage = resources.getString(
391                 com.android.internal.R.string.config_deviceProvisioningPackage);
392         return deviceProvisioningPackage != null && deviceProvisioningPackage.equals(packageName);
393     }
394 
395     /**
396      * Returns the Wifi icon resource for a given RSSI level.
397      *
398      * @param level The number of bars to show (0-4)
399      * @throws IllegalArgumentException if an invalid RSSI level is given.
400      */
getWifiIconResource(int level)401     public static int getWifiIconResource(int level) {
402         return getWifiIconResource(false /* showX */, level);
403     }
404 
405     /**
406      * Returns the Wifi icon resource for a given RSSI level.
407      *
408      * @param showX True if a connected Wi-Fi network has the problem which should show Pie+x
409      *              signal icon to users.
410      * @param level The number of bars to show (0-4)
411      * @throws IllegalArgumentException if an invalid RSSI level is given.
412      */
getWifiIconResource(boolean showX, int level)413     public static int getWifiIconResource(boolean showX, int level) {
414         if (level < 0 || level >= WIFI_PIE.length) {
415             throw new IllegalArgumentException("No Wifi icon found for level: " + level);
416         }
417         return showX ? SHOW_X_WIFI_PIE[level] : WIFI_PIE[level];
418     }
419 
getDefaultStorageManagerDaysToRetain(Resources resources)420     public static int getDefaultStorageManagerDaysToRetain(Resources resources) {
421         int defaultDays = Settings.Secure.AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN_DEFAULT;
422         try {
423             defaultDays =
424                     resources.getInteger(
425                             com.android
426                                     .internal
427                                     .R
428                                     .integer
429                                     .config_storageManagerDaystoRetainDefault);
430         } catch (Resources.NotFoundException e) {
431             // We are likely in a test environment.
432         }
433         return defaultDays;
434     }
435 
isWifiOnly(Context context)436     public static boolean isWifiOnly(Context context) {
437         return !context.getSystemService(ConnectivityManager.class)
438                 .isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
439     }
440 
441     /** Returns if the automatic storage management feature is turned on or not. **/
isStorageManagerEnabled(Context context)442     public static boolean isStorageManagerEnabled(Context context) {
443         boolean isDefaultOn;
444         try {
445             isDefaultOn = SystemProperties.getBoolean(STORAGE_MANAGER_ENABLED_PROPERTY, false);
446         } catch (Resources.NotFoundException e) {
447             isDefaultOn = false;
448         }
449         return Settings.Secure.getInt(context.getContentResolver(),
450                 Settings.Secure.AUTOMATIC_STORAGE_MANAGER_ENABLED,
451                 isDefaultOn ? 1 : 0)
452                 != 0;
453     }
454 
455     /**
456      * get that {@link AudioManager#getMode()} is in ringing/call/communication(VoIP) status.
457      */
isAudioModeOngoingCall(Context context)458     public static boolean isAudioModeOngoingCall(Context context) {
459         final AudioManager audioManager = context.getSystemService(AudioManager.class);
460         final int audioMode = audioManager.getMode();
461         return audioMode == AudioManager.MODE_RINGTONE
462                 || audioMode == AudioManager.MODE_IN_CALL
463                 || audioMode == AudioManager.MODE_IN_COMMUNICATION;
464     }
465 
466     /**
467      * Return the service state is in-service or not.
468      * To make behavior consistent with SystemUI and Settings/AboutPhone/SIM status UI
469      *
470      * @param serviceState Service state. {@link ServiceState}
471      */
isInService(ServiceState serviceState)472     public static boolean isInService(ServiceState serviceState) {
473         if (serviceState == null) {
474             return false;
475         }
476         int state = getCombinedServiceState(serviceState);
477         if (state == ServiceState.STATE_POWER_OFF
478                 || state == ServiceState.STATE_OUT_OF_SERVICE
479                 || state == ServiceState.STATE_EMERGENCY_ONLY) {
480             return false;
481         } else {
482             return true;
483         }
484     }
485 
486     /**
487      * Return the combined service state.
488      * To make behavior consistent with SystemUI and Settings/AboutPhone/SIM status UI
489      *
490      * @param serviceState Service state. {@link ServiceState}
491      */
getCombinedServiceState(ServiceState serviceState)492     public static int getCombinedServiceState(ServiceState serviceState) {
493         if (serviceState == null) {
494             return ServiceState.STATE_OUT_OF_SERVICE;
495         }
496 
497         // Consider the device to be in service if either voice or data
498         // service is available. Some SIM cards are marketed as data-only
499         // and do not support voice service, and on these SIM cards, we
500         // want to show signal bars for data service as well as the "no
501         // service" or "emergency calls only" text that indicates that voice
502         // is not available. Note that we ignore the IWLAN service state
503         // because that state indicates the use of VoWIFI and not cell service
504         final int state = serviceState.getState();
505         final int dataState = serviceState.getDataRegistrationState();
506 
507         if (state == ServiceState.STATE_OUT_OF_SERVICE
508                 || state == ServiceState.STATE_EMERGENCY_ONLY) {
509             if (dataState == ServiceState.STATE_IN_SERVICE && isNotInIwlan(serviceState)) {
510                 return ServiceState.STATE_IN_SERVICE;
511             }
512         }
513         return state;
514     }
515 
516     /** Get the corresponding adaptive icon drawable. */
getBadgedIcon(Context context, Drawable icon, UserHandle user)517     public static Drawable getBadgedIcon(Context context, Drawable icon, UserHandle user) {
518         try (IconFactory iconFactory = IconFactory.obtain(context)) {
519             final Bitmap iconBmp = iconFactory.createBadgedIconBitmap(icon, user,
520                     true /* shrinkNonAdaptiveIcons */).icon;
521             return new BitmapDrawable(context.getResources(), iconBmp);
522         }
523     }
524 
525     /** Get the {@link Drawable} that represents the app icon */
getBadgedIcon(Context context, ApplicationInfo appInfo)526     public static Drawable getBadgedIcon(Context context, ApplicationInfo appInfo) {
527         return getBadgedIcon(context, appInfo.loadUnbadgedIcon(context.getPackageManager()),
528                 UserHandle.getUserHandleForUid(appInfo.uid));
529     }
530 
isNotInIwlan(ServiceState serviceState)531     private static boolean isNotInIwlan(ServiceState serviceState) {
532         final NetworkRegistrationInfo networkRegWlan = serviceState.getNetworkRegistrationInfo(
533                 NetworkRegistrationInfo.DOMAIN_PS,
534                 AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
535         if (networkRegWlan == null) {
536             return true;
537         }
538 
539         final boolean isInIwlan = (networkRegWlan.getRegistrationState()
540                 == NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
541                 || (networkRegWlan.getRegistrationState()
542                 == NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING);
543         return !isInIwlan;
544     }
545 
546     /**
547      * Returns a bitmap with rounded corner.
548      *
549      * @param context application context.
550      * @param source bitmap to apply round corner.
551      * @param cornerRadius corner radius value.
552      */
convertCornerRadiusBitmap(@onNull Context context, @NonNull Bitmap source, @NonNull float cornerRadius)553     public static Bitmap convertCornerRadiusBitmap(@NonNull Context context,
554             @NonNull Bitmap source, @NonNull float cornerRadius) {
555         final Bitmap roundedBitmap = Bitmap.createBitmap(source.getWidth(), source.getHeight(),
556                 Bitmap.Config.ARGB_8888);
557         final RoundedBitmapDrawable drawable =
558                 RoundedBitmapDrawableFactory.create(context.getResources(), source);
559         drawable.setAntiAlias(true);
560         drawable.setCornerRadius(cornerRadius);
561         final Canvas canvas = new Canvas(roundedBitmap);
562         drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
563         drawable.draw(canvas);
564         return roundedBitmap;
565     }
566 }
567