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.PackageInfo;
7 import android.content.pm.PackageManager;
8 import android.content.pm.PackageManager.NameNotFoundException;
9 import android.content.pm.Signature;
10 import android.content.pm.UserInfo;
11 import android.content.res.ColorStateList;
12 import android.content.res.Resources;
13 import android.content.res.TypedArray;
14 import android.graphics.Bitmap;
15 import android.graphics.Color;
16 import android.graphics.drawable.Drawable;
17 import android.location.LocationManager;
18 import android.media.AudioManager;
19 import android.net.ConnectivityManager;
20 import android.os.BatteryManager;
21 import android.os.SystemProperties;
22 import android.os.UserHandle;
23 import android.os.UserManager;
24 import android.print.PrintManager;
25 import android.provider.Settings;
26 import android.telephony.AccessNetworkConstants;
27 import android.telephony.NetworkRegistrationInfo;
28 import android.telephony.ServiceState;
29 
30 import com.android.internal.annotations.VisibleForTesting;
31 import com.android.internal.util.UserIcons;
32 import com.android.settingslib.drawable.UserIconDrawable;
33 
34 import java.text.NumberFormat;
35 
36 public class Utils {
37 
38     private static final String CURRENT_MODE_KEY = "CURRENT_MODE";
39     private static final String NEW_MODE_KEY = "NEW_MODE";
40     @VisibleForTesting
41     static final String STORAGE_MANAGER_ENABLED_PROPERTY =
42             "ro.storage_manager.enabled";
43 
44     private static Signature[] sSystemSignature;
45     private static String sPermissionControllerPackageName;
46     private static String sServicesSystemSharedLibPackageName;
47     private static String sSharedSystemSharedLibPackageName;
48 
49     static final int[] WIFI_PIE = {
50             com.android.internal.R.drawable.ic_wifi_signal_0,
51             com.android.internal.R.drawable.ic_wifi_signal_1,
52             com.android.internal.R.drawable.ic_wifi_signal_2,
53             com.android.internal.R.drawable.ic_wifi_signal_3,
54             com.android.internal.R.drawable.ic_wifi_signal_4
55     };
56 
updateLocationEnabled(Context context, boolean enabled, int userId, int source)57     public static void updateLocationEnabled(Context context, boolean enabled, int userId,
58             int source) {
59         LocationManager locationManager = context.getSystemService(LocationManager.class);
60 
61         Settings.Secure.putIntForUser(
62                 context.getContentResolver(), Settings.Secure.LOCATION_CHANGER, source,
63                 userId);
64 
65         Intent intent = new Intent(LocationManager.MODE_CHANGING_ACTION);
66         final int oldMode = locationManager.isLocationEnabled()
67                 ? Settings.Secure.LOCATION_MODE_ON
68                 : Settings.Secure.LOCATION_MODE_OFF;
69         final int newMode = enabled
70                 ? Settings.Secure.LOCATION_MODE_ON
71                 : Settings.Secure.LOCATION_MODE_OFF;
72         intent.putExtra(CURRENT_MODE_KEY, oldMode);
73         intent.putExtra(NEW_MODE_KEY, newMode);
74         context.sendBroadcastAsUser(
75                 intent, UserHandle.of(userId), android.Manifest.permission.WRITE_SECURE_SETTINGS);
76 
77         locationManager.setLocationEnabledForUser(enabled, UserHandle.of(userId));
78     }
79 
80     /**
81      * Return string resource that best describes combination of tethering
82      * options available on this device.
83      */
getTetheringLabel(ConnectivityManager cm)84     public static int getTetheringLabel(ConnectivityManager cm) {
85         String[] usbRegexs = cm.getTetherableUsbRegexs();
86         String[] wifiRegexs = cm.getTetherableWifiRegexs();
87         String[] bluetoothRegexs = cm.getTetherableBluetoothRegexs();
88 
89         boolean usbAvailable = usbRegexs.length != 0;
90         boolean wifiAvailable = wifiRegexs.length != 0;
91         boolean bluetoothAvailable = bluetoothRegexs.length != 0;
92 
93         if (wifiAvailable && usbAvailable && bluetoothAvailable) {
94             return R.string.tether_settings_title_all;
95         } else if (wifiAvailable && usbAvailable) {
96             return R.string.tether_settings_title_all;
97         } else if (wifiAvailable && bluetoothAvailable) {
98             return R.string.tether_settings_title_all;
99         } else if (wifiAvailable) {
100             return R.string.tether_settings_title_wifi;
101         } else if (usbAvailable && bluetoothAvailable) {
102             return R.string.tether_settings_title_usb_bluetooth;
103         } else if (usbAvailable) {
104             return R.string.tether_settings_title_usb;
105         } else {
106             return R.string.tether_settings_title_bluetooth;
107         }
108     }
109 
110     /**
111      * Returns a label for the user, in the form of "User: user name" or "Work profile".
112      */
getUserLabel(Context context, UserInfo info)113     public static String getUserLabel(Context context, UserInfo info) {
114         String name = info != null ? info.name : null;
115         if (info.isManagedProfile()) {
116             // We use predefined values for managed profiles
117             return context.getString(R.string.managed_user_title);
118         } else if (info.isGuest()) {
119             name = context.getString(R.string.user_guest);
120         }
121         if (name == null && info != null) {
122             name = Integer.toString(info.id);
123         } else if (info == null) {
124             name = context.getString(R.string.unknown);
125         }
126         return context.getResources().getString(R.string.running_process_item_user_label, name);
127     }
128 
129     /**
130      * Returns a circular icon for a user.
131      */
getUserIcon(Context context, UserManager um, UserInfo user)132     public static Drawable getUserIcon(Context context, UserManager um, UserInfo user) {
133         final int iconSize = UserIconDrawable.getSizeForList(context);
134         if (user.isManagedProfile()) {
135             Drawable drawable =  UserIconDrawable.getManagedUserDrawable(context);
136             drawable.setBounds(0, 0, iconSize, iconSize);
137             return drawable;
138         }
139         if (user.iconPath != null) {
140             Bitmap icon = um.getUserIcon(user.id);
141             if (icon != null) {
142                 return new UserIconDrawable(iconSize).setIcon(icon).bake();
143             }
144         }
145         return new UserIconDrawable(iconSize).setIconDrawable(
146                 UserIcons.getDefaultUserIcon(context.getResources(), user.id, /* light= */ false))
147                 .bake();
148     }
149 
150     /** Formats a double from 0.0..100.0 with an option to round **/
formatPercentage(double percentage, boolean round)151     public static String formatPercentage(double percentage, boolean round) {
152         final int localPercentage = round ? Math.round((float) percentage) : (int) percentage;
153         return formatPercentage(localPercentage);
154     }
155 
156     /** Formats the ratio of amount/total as a percentage. */
formatPercentage(long amount, long total)157     public static String formatPercentage(long amount, long total) {
158         return formatPercentage(((double) amount) / total);
159     }
160 
161     /** Formats an integer from 0..100 as a percentage. */
formatPercentage(int percentage)162     public static String formatPercentage(int percentage) {
163         return formatPercentage(((double) percentage) / 100.0);
164     }
165 
166     /** Formats a double from 0.0..1.0 as a percentage. */
formatPercentage(double percentage)167     public static String formatPercentage(double percentage) {
168         return NumberFormat.getPercentInstance().format(percentage);
169     }
170 
getBatteryLevel(Intent batteryChangedIntent)171     public static int getBatteryLevel(Intent batteryChangedIntent) {
172         int level = batteryChangedIntent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0);
173         int scale = batteryChangedIntent.getIntExtra(BatteryManager.EXTRA_SCALE, 100);
174         return (level * 100) / scale;
175     }
176 
getBatteryStatus(Resources res, Intent batteryChangedIntent)177     public static String getBatteryStatus(Resources res, Intent batteryChangedIntent) {
178         int status = batteryChangedIntent.getIntExtra(BatteryManager.EXTRA_STATUS,
179                 BatteryManager.BATTERY_STATUS_UNKNOWN);
180         String statusString;
181         if (status == BatteryManager.BATTERY_STATUS_CHARGING) {
182             statusString = res.getString(R.string.battery_info_status_charging);
183         } else if (status == BatteryManager.BATTERY_STATUS_DISCHARGING) {
184             statusString = res.getString(R.string.battery_info_status_discharging);
185         } else if (status == BatteryManager.BATTERY_STATUS_NOT_CHARGING) {
186             statusString = res.getString(R.string.battery_info_status_not_charging);
187         } else if (status == BatteryManager.BATTERY_STATUS_FULL) {
188             statusString = res.getString(R.string.battery_info_status_full);
189         } else {
190             statusString = res.getString(R.string.battery_info_status_unknown);
191         }
192 
193         return statusString;
194     }
195 
getColorAccent(Context context)196     public static ColorStateList getColorAccent(Context context) {
197         return getColorAttr(context, android.R.attr.colorAccent);
198     }
199 
getColorError(Context context)200     public static ColorStateList getColorError(Context context) {
201         return getColorAttr(context, android.R.attr.colorError);
202     }
203 
204     @ColorInt
getColorAccentDefaultColor(Context context)205     public static int getColorAccentDefaultColor(Context context) {
206         return getColorAttrDefaultColor(context, android.R.attr.colorAccent);
207     }
208 
209     @ColorInt
getColorErrorDefaultColor(Context context)210     public static int getColorErrorDefaultColor(Context context) {
211         return getColorAttrDefaultColor(context, android.R.attr.colorError);
212     }
213 
214     @ColorInt
getColorStateListDefaultColor(Context context, int resId)215     public static int getColorStateListDefaultColor(Context context, int resId) {
216         final ColorStateList list =
217                 context.getResources().getColorStateList(resId, context.getTheme());
218         return list.getDefaultColor();
219     }
220 
221     @ColorInt
getDisabled(Context context, int inputColor)222     public static int getDisabled(Context context, int inputColor) {
223         return applyAlphaAttr(context, android.R.attr.disabledAlpha, inputColor);
224     }
225 
226     @ColorInt
applyAlphaAttr(Context context, int attr, int inputColor)227     public static int applyAlphaAttr(Context context, int attr, int inputColor) {
228         TypedArray ta = context.obtainStyledAttributes(new int[]{attr});
229         float alpha = ta.getFloat(0, 0);
230         ta.recycle();
231         return applyAlpha(alpha, inputColor);
232     }
233 
234     @ColorInt
applyAlpha(float alpha, int inputColor)235     public static int applyAlpha(float alpha, int inputColor) {
236         alpha *= Color.alpha(inputColor);
237         return Color.argb((int) (alpha), Color.red(inputColor), Color.green(inputColor),
238                 Color.blue(inputColor));
239     }
240 
241     @ColorInt
getColorAttrDefaultColor(Context context, int attr)242     public static int getColorAttrDefaultColor(Context context, int attr) {
243         TypedArray ta = context.obtainStyledAttributes(new int[]{attr});
244         @ColorInt int colorAccent = ta.getColor(0, 0);
245         ta.recycle();
246         return colorAccent;
247     }
248 
getColorAttr(Context context, int attr)249     public static ColorStateList getColorAttr(Context context, int attr) {
250         TypedArray ta = context.obtainStyledAttributes(new int[]{attr});
251         ColorStateList stateList = null;
252         try {
253             stateList = ta.getColorStateList(0);
254         } finally {
255             ta.recycle();
256         }
257         return stateList;
258     }
259 
getThemeAttr(Context context, int attr)260     public static int getThemeAttr(Context context, int attr) {
261         TypedArray ta = context.obtainStyledAttributes(new int[]{attr});
262         int theme = ta.getResourceId(0, 0);
263         ta.recycle();
264         return theme;
265     }
266 
getDrawable(Context context, int attr)267     public static Drawable getDrawable(Context context, int attr) {
268         TypedArray ta = context.obtainStyledAttributes(new int[]{attr});
269         Drawable drawable = ta.getDrawable(0);
270         ta.recycle();
271         return drawable;
272     }
273 
274     /**
275      * Determine whether a package is a "system package", in which case certain things (like
276      * disabling notifications or disabling the package altogether) should be disallowed.
277      */
isSystemPackage(Resources resources, PackageManager pm, PackageInfo pkg)278     public static boolean isSystemPackage(Resources resources, PackageManager pm, PackageInfo pkg) {
279         if (sSystemSignature == null) {
280             sSystemSignature = new Signature[]{getSystemSignature(pm)};
281         }
282         if (sPermissionControllerPackageName == null) {
283             sPermissionControllerPackageName = pm.getPermissionControllerPackageName();
284         }
285         if (sServicesSystemSharedLibPackageName == null) {
286             sServicesSystemSharedLibPackageName = pm.getServicesSystemSharedLibraryPackageName();
287         }
288         if (sSharedSystemSharedLibPackageName == null) {
289             sSharedSystemSharedLibPackageName = pm.getSharedSystemSharedLibraryPackageName();
290         }
291         return (sSystemSignature[0] != null
292                 && sSystemSignature[0].equals(getFirstSignature(pkg)))
293                 || pkg.packageName.equals(sPermissionControllerPackageName)
294                 || pkg.packageName.equals(sServicesSystemSharedLibPackageName)
295                 || pkg.packageName.equals(sSharedSystemSharedLibPackageName)
296                 || pkg.packageName.equals(PrintManager.PRINT_SPOOLER_PACKAGE_NAME)
297                 || isDeviceProvisioningPackage(resources, pkg.packageName);
298     }
299 
getFirstSignature(PackageInfo pkg)300     private static Signature getFirstSignature(PackageInfo pkg) {
301         if (pkg != null && pkg.signatures != null && pkg.signatures.length > 0) {
302             return pkg.signatures[0];
303         }
304         return null;
305     }
306 
getSystemSignature(PackageManager pm)307     private static Signature getSystemSignature(PackageManager pm) {
308         try {
309             final PackageInfo sys = pm.getPackageInfo("android", PackageManager.GET_SIGNATURES);
310             return getFirstSignature(sys);
311         } catch (NameNotFoundException e) {
312         }
313         return null;
314     }
315 
316     /**
317      * Returns {@code true} if the supplied package is the device provisioning app. Otherwise,
318      * returns {@code false}.
319      */
isDeviceProvisioningPackage(Resources resources, String packageName)320     public static boolean isDeviceProvisioningPackage(Resources resources, String packageName) {
321         String deviceProvisioningPackage = resources.getString(
322                 com.android.internal.R.string.config_deviceProvisioningPackage);
323         return deviceProvisioningPackage != null && deviceProvisioningPackage.equals(packageName);
324     }
325 
326     /**
327      * Returns the Wifi icon resource for a given RSSI level.
328      *
329      * @param level The number of bars to show (0-4)
330      * @throws IllegalArgumentException if an invalid RSSI level is given.
331      */
getWifiIconResource(int level)332     public static int getWifiIconResource(int level) {
333         if (level < 0 || level >= WIFI_PIE.length) {
334             throw new IllegalArgumentException("No Wifi icon found for level: " + level);
335         }
336         return WIFI_PIE[level];
337     }
338 
getDefaultStorageManagerDaysToRetain(Resources resources)339     public static int getDefaultStorageManagerDaysToRetain(Resources resources) {
340         int defaultDays = Settings.Secure.AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN_DEFAULT;
341         try {
342             defaultDays =
343                     resources.getInteger(
344                             com.android
345                                     .internal
346                                     .R
347                                     .integer
348                                     .config_storageManagerDaystoRetainDefault);
349         } catch (Resources.NotFoundException e) {
350             // We are likely in a test environment.
351         }
352         return defaultDays;
353     }
354 
isWifiOnly(Context context)355     public static boolean isWifiOnly(Context context) {
356         return !context.getSystemService(ConnectivityManager.class)
357                 .isNetworkSupported(ConnectivityManager.TYPE_MOBILE);
358     }
359 
360     /** Returns if the automatic storage management feature is turned on or not. **/
isStorageManagerEnabled(Context context)361     public static boolean isStorageManagerEnabled(Context context) {
362         boolean isDefaultOn;
363         try {
364             isDefaultOn = SystemProperties.getBoolean(STORAGE_MANAGER_ENABLED_PROPERTY, false);
365         } catch (Resources.NotFoundException e) {
366             isDefaultOn = false;
367         }
368         return Settings.Secure.getInt(context.getContentResolver(),
369                 Settings.Secure.AUTOMATIC_STORAGE_MANAGER_ENABLED,
370                 isDefaultOn ? 1 : 0)
371                 != 0;
372     }
373 
374     /**
375      * get that {@link AudioManager#getMode()} is in ringing/call/communication(VoIP) status.
376      */
isAudioModeOngoingCall(Context context)377     public static boolean isAudioModeOngoingCall(Context context) {
378         final AudioManager audioManager = context.getSystemService(AudioManager.class);
379         final int audioMode = audioManager.getMode();
380         return audioMode == AudioManager.MODE_RINGTONE
381                 || audioMode == AudioManager.MODE_IN_CALL
382                 || audioMode == AudioManager.MODE_IN_COMMUNICATION;
383     }
384 
385     /**
386      * Return the service state is in-service or not.
387      * To make behavior consistent with SystemUI and Settings/AboutPhone/SIM status UI
388      *
389      * @param serviceState Service state. {@link ServiceState}
390      */
isInService(ServiceState serviceState)391     public static boolean isInService(ServiceState serviceState) {
392         if (serviceState == null) {
393             return false;
394         }
395         int state = getCombinedServiceState(serviceState);
396         if (state == ServiceState.STATE_POWER_OFF
397                 || state == ServiceState.STATE_OUT_OF_SERVICE
398                 || state == ServiceState.STATE_EMERGENCY_ONLY) {
399             return false;
400         } else {
401             return true;
402         }
403     }
404 
405     /**
406      * Return the combined service state.
407      * To make behavior consistent with SystemUI and Settings/AboutPhone/SIM status UI
408      *
409      * @param serviceState Service state. {@link ServiceState}
410      */
getCombinedServiceState(ServiceState serviceState)411     public static int getCombinedServiceState(ServiceState serviceState) {
412         if (serviceState == null) {
413             return ServiceState.STATE_OUT_OF_SERVICE;
414         }
415 
416         // Consider the device to be in service if either voice or data
417         // service is available. Some SIM cards are marketed as data-only
418         // and do not support voice service, and on these SIM cards, we
419         // want to show signal bars for data service as well as the "no
420         // service" or "emergency calls only" text that indicates that voice
421         // is not available. Note that we ignore the IWLAN service state
422         // because that state indicates the use of VoWIFI and not cell service
423         final int state = serviceState.getState();
424         final int dataState = serviceState.getDataRegistrationState();
425 
426         if (state == ServiceState.STATE_OUT_OF_SERVICE
427                 || state == ServiceState.STATE_EMERGENCY_ONLY) {
428             if (dataState == ServiceState.STATE_IN_SERVICE && isNotInIwlan(serviceState)) {
429                 return ServiceState.STATE_IN_SERVICE;
430             }
431         }
432         return state;
433     }
434 
isNotInIwlan(ServiceState serviceState)435     private static boolean isNotInIwlan(ServiceState serviceState) {
436         final NetworkRegistrationInfo networkRegWlan = serviceState.getNetworkRegistrationInfo(
437                 NetworkRegistrationInfo.DOMAIN_PS,
438                 AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
439         if (networkRegWlan == null) {
440             return true;
441         }
442 
443         final boolean isInIwlan = (networkRegWlan.getRegistrationState()
444                 == NetworkRegistrationInfo.REGISTRATION_STATE_HOME)
445                 || (networkRegWlan.getRegistrationState()
446                 == NetworkRegistrationInfo.REGISTRATION_STATE_ROAMING);
447         return !isInIwlan;
448     }
449 }
450