Home | History | Annotate | Download | only in settingslib
      1 package com.android.settingslib;
      2 
      3 import static android.telephony.ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN;
      4 
      5 import android.annotation.ColorInt;
      6 import android.content.Context;
      7 import android.content.Intent;
      8 import android.content.pm.PackageInfo;
      9 import android.content.pm.PackageManager;
     10 import android.content.pm.PackageManager.NameNotFoundException;
     11 import android.content.pm.Signature;
     12 import android.content.pm.UserInfo;
     13 import android.content.res.ColorStateList;
     14 import android.content.res.Resources;
     15 import android.content.res.TypedArray;
     16 import android.graphics.Bitmap;
     17 import android.graphics.Color;
     18 import android.graphics.drawable.Drawable;
     19 import android.location.LocationManager;
     20 import android.media.AudioManager;
     21 import android.net.ConnectivityManager;
     22 import android.os.BatteryManager;
     23 import android.os.SystemProperties;
     24 import android.os.UserHandle;
     25 import android.os.UserManager;
     26 import android.print.PrintManager;
     27 import android.provider.Settings;
     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 
     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      */
     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      */
    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      */
    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 **/
    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. */
    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. */
    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. */
    167     public static String formatPercentage(double percentage) {
    168         return NumberFormat.getPercentInstance().format(percentage);
    169     }
    170 
    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 
    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 
    196     public static ColorStateList getColorAccent(Context context) {
    197         return getColorAttr(context, android.R.attr.colorAccent);
    198     }
    199 
    200     public static ColorStateList getColorError(Context context) {
    201         return getColorAttr(context, android.R.attr.colorError);
    202     }
    203 
    204     @ColorInt
    205     public static int getColorAccentDefaultColor(Context context) {
    206         return getColorAttrDefaultColor(context, android.R.attr.colorAccent);
    207     }
    208 
    209     @ColorInt
    210     public static int getColorErrorDefaultColor(Context context) {
    211         return getColorAttrDefaultColor(context, android.R.attr.colorError);
    212     }
    213 
    214     @ColorInt
    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
    222     public static int getDisabled(Context context, int inputColor) {
    223         return applyAlphaAttr(context, android.R.attr.disabledAlpha, inputColor);
    224     }
    225 
    226     @ColorInt
    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
    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
    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 
    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 
    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 
    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      */
    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 
    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 
    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      */
    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      */
    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 
    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 
    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. **/
    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      */
    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      */
    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      */
    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         int state = serviceState.getState();
    424         int dataState = serviceState.getDataRegState();
    425         if (state == ServiceState.STATE_OUT_OF_SERVICE
    426                 || state == ServiceState.STATE_EMERGENCY_ONLY) {
    427             if (dataState == ServiceState.STATE_IN_SERVICE
    428                     && serviceState.getDataNetworkType() != RIL_RADIO_TECHNOLOGY_IWLAN) {
    429                 return ServiceState.STATE_IN_SERVICE;
    430             }
    431         }
    432         return state;
    433     }
    434 }
    435