Home | History | Annotate | Download | only in settings
      1 /**
      2  * Copyright (C) 2007 Google Inc.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
      5  * use this file except in compliance with the License. You may obtain a copy
      6  * of the License at
      7  *
      8  * http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
     12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
     13  * License for the specific language governing permissions and limitations
     14  * under the License.
     15  */
     16 
     17 package com.android.settings;
     18 
     19 import android.annotation.Nullable;
     20 import android.app.ActivityManager;
     21 import android.app.ActivityManagerNative;
     22 import android.app.AlertDialog;
     23 import android.app.AppGlobals;
     24 import android.app.Dialog;
     25 import android.app.Fragment;
     26 import android.app.IActivityManager;
     27 import android.app.admin.DevicePolicyManager;
     28 import android.content.ComponentName;
     29 import android.content.ContentResolver;
     30 import android.content.Context;
     31 import android.content.DialogInterface;
     32 import android.content.Intent;
     33 import android.content.IntentFilter;
     34 import android.content.pm.ApplicationInfo;
     35 import android.content.pm.IPackageManager;
     36 import android.content.pm.IntentFilterVerificationInfo;
     37 import android.content.pm.PackageInfo;
     38 import android.content.pm.PackageManager;
     39 import android.content.pm.PackageManager.NameNotFoundException;
     40 import android.content.pm.ResolveInfo;
     41 import android.content.pm.Signature;
     42 import android.content.pm.UserInfo;
     43 import android.content.res.Resources;
     44 import android.content.res.Resources.NotFoundException;
     45 import android.content.res.TypedArray;
     46 import android.database.Cursor;
     47 import android.graphics.Bitmap;
     48 import android.graphics.BitmapFactory;
     49 import android.graphics.drawable.Drawable;
     50 import android.hardware.usb.IUsbManager;
     51 import android.net.ConnectivityManager;
     52 import android.net.LinkProperties;
     53 import android.net.Uri;
     54 import android.os.BatteryManager;
     55 import android.os.Bundle;
     56 import android.os.IBinder;
     57 import android.os.INetworkManagementService;
     58 import android.os.RemoteException;
     59 import android.os.ServiceManager;
     60 import android.os.UserHandle;
     61 import android.os.UserManager;
     62 import android.os.storage.StorageManager;
     63 import android.preference.Preference;
     64 import android.preference.PreferenceFrameLayout;
     65 import android.preference.PreferenceGroup;
     66 import android.provider.ContactsContract.CommonDataKinds;
     67 import android.provider.ContactsContract.Contacts;
     68 import android.provider.ContactsContract.Data;
     69 import android.provider.ContactsContract.Profile;
     70 import android.provider.ContactsContract.RawContacts;
     71 import android.service.persistentdata.PersistentDataBlockManager;
     72 import android.telephony.TelephonyManager;
     73 import android.text.Spannable;
     74 import android.text.SpannableString;
     75 import android.text.TextUtils;
     76 import android.text.style.TtsSpan;
     77 import android.util.ArraySet;
     78 import android.util.Log;
     79 import android.util.SparseArray;
     80 import android.view.LayoutInflater;
     81 import android.view.View;
     82 import android.view.ViewGroup;
     83 import android.view.animation.Animation;
     84 import android.view.animation.Animation.AnimationListener;
     85 import android.view.animation.AnimationUtils;
     86 import android.widget.ListView;
     87 import android.widget.TabWidget;
     88 
     89 import com.android.internal.util.UserIcons;
     90 import com.android.settings.UserAdapter.UserDetails;
     91 import com.android.settings.dashboard.DashboardTile;
     92 import com.android.settings.drawable.CircleFramedDrawable;
     93 import com.android.settingslib.applications.ApplicationsState;
     94 
     95 import java.io.IOException;
     96 import java.io.InputStream;
     97 import java.net.InetAddress;
     98 import java.text.NumberFormat;
     99 import java.util.ArrayList;
    100 import java.util.Iterator;
    101 import java.util.List;
    102 import java.util.Locale;
    103 
    104 import static android.content.Intent.EXTRA_USER;
    105 
    106 public final class Utils {
    107     private static final String TAG = "Settings";
    108 
    109     /**
    110      * Set the preference's title to the matching activity's label.
    111      */
    112     public static final int UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY = 1;
    113 
    114     /**
    115      * The opacity level of a disabled icon.
    116      */
    117     public static final float DISABLED_ALPHA = 0.4f;
    118 
    119     /**
    120      * Color spectrum to use to indicate badness.  0 is completely transparent (no data),
    121      * 1 is most bad (red), the last value is least bad (green).
    122      */
    123     public static final int[] BADNESS_COLORS = new int[] {
    124             0x00000000, 0xffc43828, 0xffe54918, 0xfff47b00,
    125             0xfffabf2c, 0xff679e37, 0xff0a7f42
    126     };
    127 
    128     /**
    129      * Name of the meta-data item that should be set in the AndroidManifest.xml
    130      * to specify the icon that should be displayed for the preference.
    131      */
    132     public static final String META_DATA_PREFERENCE_ICON = "com.android.settings.icon";
    133 
    134     /**
    135      * Name of the meta-data item that should be set in the AndroidManifest.xml
    136      * to specify the title that should be displayed for the preference.
    137      */
    138     public static final String META_DATA_PREFERENCE_TITLE = "com.android.settings.title";
    139 
    140     /**
    141      * Name of the meta-data item that should be set in the AndroidManifest.xml
    142      * to specify the summary text that should be displayed for the preference.
    143      */
    144     public static final String META_DATA_PREFERENCE_SUMMARY = "com.android.settings.summary";
    145 
    146     private static final String SETTINGS_PACKAGE_NAME = "com.android.settings";
    147 
    148     private static final int SECONDS_PER_MINUTE = 60;
    149     private static final int SECONDS_PER_HOUR = 60 * 60;
    150     private static final int SECONDS_PER_DAY = 24 * 60 * 60;
    151 
    152     public static final String OS_PKG = "os";
    153 
    154     private static SparseArray<Bitmap> sDarkDefaultUserBitmapCache = new SparseArray<Bitmap>();
    155 
    156     /**
    157      * Finds a matching activity for a preference's intent. If a matching
    158      * activity is not found, it will remove the preference.
    159      *
    160      * @param context The context.
    161      * @param parentPreferenceGroup The preference group that contains the
    162      *            preference whose intent is being resolved.
    163      * @param preferenceKey The key of the preference whose intent is being
    164      *            resolved.
    165      * @param flags 0 or one or more of
    166      *            {@link #UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY}
    167      *            .
    168      * @return Whether an activity was found. If false, the preference was
    169      *         removed.
    170      */
    171     public static boolean updatePreferenceToSpecificActivityOrRemove(Context context,
    172             PreferenceGroup parentPreferenceGroup, String preferenceKey, int flags) {
    173 
    174         Preference preference = parentPreferenceGroup.findPreference(preferenceKey);
    175         if (preference == null) {
    176             return false;
    177         }
    178 
    179         Intent intent = preference.getIntent();
    180         if (intent != null) {
    181             // Find the activity that is in the system image
    182             PackageManager pm = context.getPackageManager();
    183             List<ResolveInfo> list = pm.queryIntentActivities(intent, 0);
    184             int listSize = list.size();
    185             for (int i = 0; i < listSize; i++) {
    186                 ResolveInfo resolveInfo = list.get(i);
    187                 if ((resolveInfo.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
    188                         != 0) {
    189 
    190                     // Replace the intent with this specific activity
    191                     preference.setIntent(new Intent().setClassName(
    192                             resolveInfo.activityInfo.packageName,
    193                             resolveInfo.activityInfo.name));
    194 
    195                     if ((flags & UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY) != 0) {
    196                         // Set the preference title to the activity's label
    197                         preference.setTitle(resolveInfo.loadLabel(pm));
    198                     }
    199 
    200                     return true;
    201                 }
    202             }
    203         }
    204 
    205         // Did not find a matching activity, so remove the preference
    206         parentPreferenceGroup.removePreference(preference);
    207 
    208         return false;
    209     }
    210 
    211     public static boolean updateTileToSpecificActivityFromMetaDataOrRemove(Context context,
    212             DashboardTile tile) {
    213 
    214         Intent intent = tile.intent;
    215         if (intent != null) {
    216             // Find the activity that is in the system image
    217             PackageManager pm = context.getPackageManager();
    218             List<ResolveInfo> list = tile.userHandle.size() != 0
    219                     ? pm.queryIntentActivitiesAsUser(intent, PackageManager.GET_META_DATA,
    220                             tile.userHandle.get(0).getIdentifier())
    221                     : pm.queryIntentActivities(intent, PackageManager.GET_META_DATA);
    222             int listSize = list.size();
    223             for (int i = 0; i < listSize; i++) {
    224                 ResolveInfo resolveInfo = list.get(i);
    225                 if ((resolveInfo.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
    226                         != 0) {
    227                     int icon = 0;
    228                     CharSequence title = null;
    229                     String summary = null;
    230 
    231                     // Get the activity's meta-data
    232                     try {
    233                         Resources res = pm.getResourcesForApplication(
    234                                 resolveInfo.activityInfo.packageName);
    235                         Bundle metaData = resolveInfo.activityInfo.metaData;
    236 
    237                         if (res != null && metaData != null) {
    238                             if (metaData.containsKey(META_DATA_PREFERENCE_ICON)) {
    239                                 icon = metaData.getInt(META_DATA_PREFERENCE_ICON);
    240                             }
    241                             if (metaData.containsKey(META_DATA_PREFERENCE_TITLE)) {
    242                                 title = res.getString(metaData.getInt(META_DATA_PREFERENCE_TITLE));
    243                             }
    244                             if (metaData.containsKey(META_DATA_PREFERENCE_SUMMARY)) {
    245                                 summary = res.getString(
    246                                         metaData.getInt(META_DATA_PREFERENCE_SUMMARY));
    247                             }
    248                         }
    249                     } catch (NameNotFoundException | NotFoundException e) {
    250                         // Ignore
    251                     }
    252 
    253                     // Set the preference title to the activity's label if no
    254                     // meta-data is found
    255                     if (TextUtils.isEmpty(title)) {
    256                         title = resolveInfo.loadLabel(pm).toString();
    257                     }
    258                     if (icon == 0) {
    259                         icon = resolveInfo.activityInfo.icon;
    260                     }
    261 
    262                     // Set icon, title and summary for the preference
    263                     tile.iconRes = icon;
    264                     tile.iconPkg = resolveInfo.activityInfo.packageName;
    265                     tile.title = title;
    266                     tile.summary = summary;
    267                     // Replace the intent with this specific activity
    268                     tile.intent = new Intent().setClassName(resolveInfo.activityInfo.packageName,
    269                             resolveInfo.activityInfo.name);
    270 
    271                     return true;
    272                 }
    273             }
    274         }
    275 
    276         return false;
    277     }
    278 
    279     /**
    280      * Returns true if Monkey is running.
    281      */
    282     public static boolean isMonkeyRunning() {
    283         return ActivityManager.isUserAMonkey();
    284     }
    285 
    286     /**
    287      * Returns whether the device is voice-capable (meaning, it is also a phone).
    288      */
    289     public static boolean isVoiceCapable(Context context) {
    290         TelephonyManager telephony =
    291                 (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
    292         return telephony != null && telephony.isVoiceCapable();
    293     }
    294 
    295     public static boolean isWifiOnly(Context context) {
    296         ConnectivityManager cm = (ConnectivityManager)context.getSystemService(
    297                 Context.CONNECTIVITY_SERVICE);
    298         return (cm.isNetworkSupported(ConnectivityManager.TYPE_MOBILE) == false);
    299     }
    300 
    301     /**
    302      * Returns the WIFI IP Addresses, if any, taking into account IPv4 and IPv6 style addresses.
    303      * @param context the application context
    304      * @return the formatted and newline-separated IP addresses, or null if none.
    305      */
    306     public static String getWifiIpAddresses(Context context) {
    307         ConnectivityManager cm = (ConnectivityManager)
    308                 context.getSystemService(Context.CONNECTIVITY_SERVICE);
    309         LinkProperties prop = cm.getLinkProperties(ConnectivityManager.TYPE_WIFI);
    310         return formatIpAddresses(prop);
    311     }
    312 
    313     /**
    314      * Returns the default link's IP addresses, if any, taking into account IPv4 and IPv6 style
    315      * addresses.
    316      * @param context the application context
    317      * @return the formatted and newline-separated IP addresses, or null if none.
    318      */
    319     public static String getDefaultIpAddresses(ConnectivityManager cm) {
    320         LinkProperties prop = cm.getActiveLinkProperties();
    321         return formatIpAddresses(prop);
    322     }
    323 
    324     private static String formatIpAddresses(LinkProperties prop) {
    325         if (prop == null) return null;
    326         Iterator<InetAddress> iter = prop.getAllAddresses().iterator();
    327         // If there are no entries, return null
    328         if (!iter.hasNext()) return null;
    329         // Concatenate all available addresses, comma separated
    330         String addresses = "";
    331         while (iter.hasNext()) {
    332             addresses += iter.next().getHostAddress();
    333             if (iter.hasNext()) addresses += "\n";
    334         }
    335         return addresses;
    336     }
    337 
    338     public static Locale createLocaleFromString(String localeStr) {
    339         // TODO: is there a better way to actually construct a locale that will match?
    340         // The main problem is, on top of Java specs, locale.toString() and
    341         // new Locale(locale.toString()).toString() do not return equal() strings in
    342         // many cases, because the constructor takes the only string as the language
    343         // code. So : new Locale("en", "US").toString() => "en_US"
    344         // And : new Locale("en_US").toString() => "en_us"
    345         if (null == localeStr)
    346             return Locale.getDefault();
    347         String[] brokenDownLocale = localeStr.split("_", 3);
    348         // split may not return a 0-length array.
    349         if (1 == brokenDownLocale.length) {
    350             return new Locale(brokenDownLocale[0]);
    351         } else if (2 == brokenDownLocale.length) {
    352             return new Locale(brokenDownLocale[0], brokenDownLocale[1]);
    353         } else {
    354             return new Locale(brokenDownLocale[0], brokenDownLocale[1], brokenDownLocale[2]);
    355         }
    356     }
    357 
    358     /** Formats the ratio of amount/total as a percentage. */
    359     public static String formatPercentage(long amount, long total) {
    360         return formatPercentage(((double) amount) / total);
    361     }
    362 
    363     /** Formats an integer from 0..100 as a percentage. */
    364     public static String formatPercentage(int percentage) {
    365         return formatPercentage(((double) percentage) / 100.0);
    366     }
    367 
    368     /** Formats a double from 0.0..1.0 as a percentage. */
    369     private static String formatPercentage(double percentage) {
    370       return NumberFormat.getPercentInstance().format(percentage);
    371     }
    372 
    373     public static boolean isBatteryPresent(Intent batteryChangedIntent) {
    374         return batteryChangedIntent.getBooleanExtra(BatteryManager.EXTRA_PRESENT, true);
    375     }
    376 
    377     public static String getBatteryPercentage(Intent batteryChangedIntent) {
    378         return formatPercentage(getBatteryLevel(batteryChangedIntent));
    379     }
    380 
    381     public static int getBatteryLevel(Intent batteryChangedIntent) {
    382         int level = batteryChangedIntent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0);
    383         int scale = batteryChangedIntent.getIntExtra(BatteryManager.EXTRA_SCALE, 100);
    384         return (level * 100) / scale;
    385     }
    386 
    387     public static String getBatteryStatus(Resources res, Intent batteryChangedIntent) {
    388         final Intent intent = batteryChangedIntent;
    389 
    390         int plugType = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0);
    391         int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS,
    392                 BatteryManager.BATTERY_STATUS_UNKNOWN);
    393         String statusString;
    394         if (status == BatteryManager.BATTERY_STATUS_CHARGING) {
    395             int resId;
    396             if (plugType == BatteryManager.BATTERY_PLUGGED_AC) {
    397                 resId = R.string.battery_info_status_charging_ac;
    398             } else if (plugType == BatteryManager.BATTERY_PLUGGED_USB) {
    399                 resId = R.string.battery_info_status_charging_usb;
    400             } else if (plugType == BatteryManager.BATTERY_PLUGGED_WIRELESS) {
    401                 resId = R.string.battery_info_status_charging_wireless;
    402             } else {
    403                 resId = R.string.battery_info_status_charging;
    404             }
    405             statusString = res.getString(resId);
    406         } else if (status == BatteryManager.BATTERY_STATUS_DISCHARGING) {
    407             statusString = res.getString(R.string.battery_info_status_discharging);
    408         } else if (status == BatteryManager.BATTERY_STATUS_NOT_CHARGING) {
    409             statusString = res.getString(R.string.battery_info_status_not_charging);
    410         } else if (status == BatteryManager.BATTERY_STATUS_FULL) {
    411             statusString = res.getString(R.string.battery_info_status_full);
    412         } else {
    413             statusString = res.getString(R.string.battery_info_status_unknown);
    414         }
    415 
    416         return statusString;
    417     }
    418 
    419     public static void forcePrepareCustomPreferencesList(
    420             ViewGroup parent, View child, ListView list, boolean ignoreSidePadding) {
    421         list.setScrollBarStyle(View.SCROLLBARS_OUTSIDE_OVERLAY);
    422         list.setClipToPadding(false);
    423         prepareCustomPreferencesList(parent, child, list, ignoreSidePadding);
    424     }
    425 
    426     /**
    427      * Prepare a custom preferences layout, moving padding to {@link ListView}
    428      * when outside scrollbars are requested. Usually used to display
    429      * {@link ListView} and {@link TabWidget} with correct padding.
    430      */
    431     public static void prepareCustomPreferencesList(
    432             ViewGroup parent, View child, View list, boolean ignoreSidePadding) {
    433         final boolean movePadding = list.getScrollBarStyle() == View.SCROLLBARS_OUTSIDE_OVERLAY;
    434         if (movePadding) {
    435             final Resources res = list.getResources();
    436             final int paddingSide = res.getDimensionPixelSize(R.dimen.settings_side_margin);
    437             final int paddingBottom = res.getDimensionPixelSize(
    438                     com.android.internal.R.dimen.preference_fragment_padding_bottom);
    439 
    440             if (parent instanceof PreferenceFrameLayout) {
    441                 ((PreferenceFrameLayout.LayoutParams) child.getLayoutParams()).removeBorders = true;
    442 
    443                 final int effectivePaddingSide = ignoreSidePadding ? 0 : paddingSide;
    444                 list.setPaddingRelative(effectivePaddingSide, 0, effectivePaddingSide, paddingBottom);
    445             } else {
    446                 list.setPaddingRelative(paddingSide, 0, paddingSide, paddingBottom);
    447             }
    448         }
    449     }
    450 
    451     public static void forceCustomPadding(View view, boolean additive) {
    452         final Resources res = view.getResources();
    453         final int paddingSide = res.getDimensionPixelSize(R.dimen.settings_side_margin);
    454 
    455         final int paddingStart = paddingSide + (additive ? view.getPaddingStart() : 0);
    456         final int paddingEnd = paddingSide + (additive ? view.getPaddingEnd() : 0);
    457         final int paddingBottom = res.getDimensionPixelSize(
    458                 com.android.internal.R.dimen.preference_fragment_padding_bottom);
    459 
    460         view.setPaddingRelative(paddingStart, 0, paddingEnd, paddingBottom);
    461     }
    462 
    463     /**
    464      * Return string resource that best describes combination of tethering
    465      * options available on this device.
    466      */
    467     public static int getTetheringLabel(ConnectivityManager cm) {
    468         String[] usbRegexs = cm.getTetherableUsbRegexs();
    469         String[] wifiRegexs = cm.getTetherableWifiRegexs();
    470         String[] bluetoothRegexs = cm.getTetherableBluetoothRegexs();
    471 
    472         boolean usbAvailable = usbRegexs.length != 0;
    473         boolean wifiAvailable = wifiRegexs.length != 0;
    474         boolean bluetoothAvailable = bluetoothRegexs.length != 0;
    475 
    476         if (wifiAvailable && usbAvailable && bluetoothAvailable) {
    477             return R.string.tether_settings_title_all;
    478         } else if (wifiAvailable && usbAvailable) {
    479             return R.string.tether_settings_title_all;
    480         } else if (wifiAvailable && bluetoothAvailable) {
    481             return R.string.tether_settings_title_all;
    482         } else if (wifiAvailable) {
    483             return R.string.tether_settings_title_wifi;
    484         } else if (usbAvailable && bluetoothAvailable) {
    485             return R.string.tether_settings_title_usb_bluetooth;
    486         } else if (usbAvailable) {
    487             return R.string.tether_settings_title_usb;
    488         } else {
    489             return R.string.tether_settings_title_bluetooth;
    490         }
    491     }
    492 
    493     /* Used by UserSettings as well. Call this on a non-ui thread. */
    494     public static boolean copyMeProfilePhoto(Context context, UserInfo user) {
    495         Uri contactUri = Profile.CONTENT_URI;
    496 
    497         InputStream avatarDataStream = Contacts.openContactPhotoInputStream(
    498                     context.getContentResolver(),
    499                     contactUri, true);
    500         // If there's no profile photo, assign a default avatar
    501         if (avatarDataStream == null) {
    502             return false;
    503         }
    504         int userId = user != null ? user.id : UserHandle.myUserId();
    505         UserManager um = (UserManager) context.getSystemService(Context.USER_SERVICE);
    506         Bitmap icon = BitmapFactory.decodeStream(avatarDataStream);
    507         um.setUserIcon(userId, icon);
    508         try {
    509             avatarDataStream.close();
    510         } catch (IOException ioe) { }
    511         return true;
    512     }
    513 
    514     public static String getMeProfileName(Context context, boolean full) {
    515         if (full) {
    516             return getProfileDisplayName(context);
    517         } else {
    518             return getShorterNameIfPossible(context);
    519         }
    520     }
    521 
    522     private static String getShorterNameIfPossible(Context context) {
    523         final String given = getLocalProfileGivenName(context);
    524         return !TextUtils.isEmpty(given) ? given : getProfileDisplayName(context);
    525     }
    526 
    527     private static String getLocalProfileGivenName(Context context) {
    528         final ContentResolver cr = context.getContentResolver();
    529 
    530         // Find the raw contact ID for the local ME profile raw contact.
    531         final long localRowProfileId;
    532         final Cursor localRawProfile = cr.query(
    533                 Profile.CONTENT_RAW_CONTACTS_URI,
    534                 new String[] {RawContacts._ID},
    535                 RawContacts.ACCOUNT_TYPE + " IS NULL AND " +
    536                         RawContacts.ACCOUNT_NAME + " IS NULL",
    537                 null, null);
    538         if (localRawProfile == null) return null;
    539 
    540         try {
    541             if (!localRawProfile.moveToFirst()) {
    542                 return null;
    543             }
    544             localRowProfileId = localRawProfile.getLong(0);
    545         } finally {
    546             localRawProfile.close();
    547         }
    548 
    549         // Find the structured name for the raw contact.
    550         final Cursor structuredName = cr.query(
    551                 Profile.CONTENT_URI.buildUpon().appendPath(Contacts.Data.CONTENT_DIRECTORY).build(),
    552                 new String[] {CommonDataKinds.StructuredName.GIVEN_NAME,
    553                     CommonDataKinds.StructuredName.FAMILY_NAME},
    554                 Data.RAW_CONTACT_ID + "=" + localRowProfileId,
    555                 null, null);
    556         if (structuredName == null) return null;
    557 
    558         try {
    559             if (!structuredName.moveToFirst()) {
    560                 return null;
    561             }
    562             String partialName = structuredName.getString(0);
    563             if (TextUtils.isEmpty(partialName)) {
    564                 partialName = structuredName.getString(1);
    565             }
    566             return partialName;
    567         } finally {
    568             structuredName.close();
    569         }
    570     }
    571 
    572     private static final String getProfileDisplayName(Context context) {
    573         final ContentResolver cr = context.getContentResolver();
    574         final Cursor profile = cr.query(Profile.CONTENT_URI,
    575                 new String[] {Profile.DISPLAY_NAME}, null, null, null);
    576         if (profile == null) return null;
    577 
    578         try {
    579             if (!profile.moveToFirst()) {
    580                 return null;
    581             }
    582             return profile.getString(0);
    583         } finally {
    584             profile.close();
    585         }
    586     }
    587 
    588     /** Not global warming, it's global change warning. */
    589     public static Dialog buildGlobalChangeWarningDialog(final Context context, int titleResId,
    590             final Runnable positiveAction) {
    591         final AlertDialog.Builder builder = new AlertDialog.Builder(context);
    592         builder.setTitle(titleResId);
    593         builder.setMessage(R.string.global_change_warning);
    594         builder.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
    595             @Override
    596             public void onClick(DialogInterface dialog, int which) {
    597                 positiveAction.run();
    598             }
    599         });
    600         builder.setNegativeButton(android.R.string.cancel, null);
    601 
    602         return builder.create();
    603     }
    604 
    605     public static boolean hasMultipleUsers(Context context) {
    606         return ((UserManager) context.getSystemService(Context.USER_SERVICE))
    607                 .getUsers().size() > 1;
    608     }
    609 
    610     /**
    611      * Start a new instance of the activity, showing only the given fragment.
    612      * When launched in this mode, the given preference fragment will be instantiated and fill the
    613      * entire activity.
    614      *
    615      * @param context The context.
    616      * @param fragmentName The name of the fragment to display.
    617      * @param args Optional arguments to supply to the fragment.
    618      * @param resultTo Option fragment that should receive the result of the activity launch.
    619      * @param resultRequestCode If resultTo is non-null, this is the request code in which
    620      *                          to report the result.
    621      * @param titleResId resource id for the String to display for the title of this set
    622      *                   of preferences.
    623      * @param title String to display for the title of this set of preferences.
    624      */
    625     public static void startWithFragment(Context context, String fragmentName, Bundle args,
    626             Fragment resultTo, int resultRequestCode, int titleResId,
    627             CharSequence title) {
    628         startWithFragment(context, fragmentName, args, resultTo, resultRequestCode,
    629                 null /* titleResPackageName */, titleResId, title, false /* not a shortcut */);
    630     }
    631 
    632     /**
    633      * Start a new instance of the activity, showing only the given fragment.
    634      * When launched in this mode, the given preference fragment will be instantiated and fill the
    635      * entire activity.
    636      *
    637      * @param context The context.
    638      * @param fragmentName The name of the fragment to display.
    639      * @param args Optional arguments to supply to the fragment.
    640      * @param resultTo Option fragment that should receive the result of the activity launch.
    641      * @param resultRequestCode If resultTo is non-null, this is the request code in which
    642      *                          to report the result.
    643      * @param titleResPackageName Optional package name for the resource id of the title.
    644      * @param titleResId resource id for the String to display for the title of this set
    645      *                   of preferences.
    646      * @param title String to display for the title of this set of preferences.
    647      */
    648     public static void startWithFragment(Context context, String fragmentName, Bundle args,
    649             Fragment resultTo, int resultRequestCode, String titleResPackageName, int titleResId,
    650             CharSequence title) {
    651         startWithFragment(context, fragmentName, args, resultTo, resultRequestCode,
    652                 titleResPackageName, titleResId, title, false /* not a shortcut */);
    653     }
    654 
    655     public static void startWithFragment(Context context, String fragmentName, Bundle args,
    656             Fragment resultTo, int resultRequestCode, int titleResId,
    657             CharSequence title, boolean isShortcut) {
    658         Intent intent = onBuildStartFragmentIntent(context, fragmentName, args,
    659                 null /* titleResPackageName */, titleResId, title, isShortcut);
    660         if (resultTo == null) {
    661             context.startActivity(intent);
    662         } else {
    663             resultTo.startActivityForResult(intent, resultRequestCode);
    664         }
    665     }
    666 
    667     public static void startWithFragment(Context context, String fragmentName, Bundle args,
    668             Fragment resultTo, int resultRequestCode, String titleResPackageName, int titleResId,
    669             CharSequence title, boolean isShortcut) {
    670         Intent intent = onBuildStartFragmentIntent(context, fragmentName, args, titleResPackageName,
    671                 titleResId, title, isShortcut);
    672         if (resultTo == null) {
    673             context.startActivity(intent);
    674         } else {
    675             resultTo.startActivityForResult(intent, resultRequestCode);
    676         }
    677     }
    678 
    679     public static void startWithFragmentAsUser(Context context, String fragmentName, Bundle args,
    680             int titleResId, CharSequence title, boolean isShortcut,
    681             UserHandle userHandle) {
    682         Intent intent = onBuildStartFragmentIntent(context, fragmentName, args,
    683                 null /* titleResPackageName */, titleResId, title, isShortcut);
    684         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    685         intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
    686         context.startActivityAsUser(intent, userHandle);
    687     }
    688 
    689     public static void startWithFragmentAsUser(Context context, String fragmentName, Bundle args,
    690             String titleResPackageName, int titleResId, CharSequence title, boolean isShortcut,
    691             UserHandle userHandle) {
    692         Intent intent = onBuildStartFragmentIntent(context, fragmentName, args, titleResPackageName,
    693                 titleResId, title, isShortcut);
    694         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    695         intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
    696         context.startActivityAsUser(intent, userHandle);
    697     }
    698 
    699     /**
    700      * Build an Intent to launch a new activity showing the selected fragment.
    701      * The implementation constructs an Intent that re-launches the current activity with the
    702      * appropriate arguments to display the fragment.
    703      *
    704      *
    705      * @param context The Context.
    706      * @param fragmentName The name of the fragment to display.
    707      * @param args Optional arguments to supply to the fragment.
    708      * @param titleResPackageName Optional package name for the resource id of the title.
    709      * @param titleResId Optional title resource id to show for this item.
    710      * @param title Optional title to show for this item.
    711      * @param isShortcut  tell if this is a Launcher Shortcut or not
    712      * @return Returns an Intent that can be launched to display the given
    713      * fragment.
    714      */
    715     public static Intent onBuildStartFragmentIntent(Context context, String fragmentName,
    716             Bundle args, String titleResPackageName, int titleResId, CharSequence title,
    717             boolean isShortcut) {
    718         Intent intent = new Intent(Intent.ACTION_MAIN);
    719         intent.setClass(context, SubSettings.class);
    720         intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT, fragmentName);
    721         intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_ARGUMENTS, args);
    722         intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE_RES_PACKAGE_NAME,
    723                 titleResPackageName);
    724         intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE_RESID, titleResId);
    725         intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE, title);
    726         intent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_AS_SHORTCUT, isShortcut);
    727         return intent;
    728     }
    729 
    730     /**
    731      * Returns the managed profile of the current user or null if none found.
    732      */
    733     public static UserHandle getManagedProfile(UserManager userManager) {
    734         List<UserHandle> userProfiles = userManager.getUserProfiles();
    735         final int count = userProfiles.size();
    736         for (int i = 0; i < count; i++) {
    737             final UserHandle profile = userProfiles.get(i);
    738             if (profile.getIdentifier() == userManager.getUserHandle()) {
    739                 continue;
    740             }
    741             final UserInfo userInfo = userManager.getUserInfo(profile.getIdentifier());
    742             if (userInfo.isManagedProfile()) {
    743                 return profile;
    744             }
    745         }
    746         return null;
    747     }
    748 
    749     /**
    750      * Returns true if the current profile is a managed one.
    751      */
    752     public static boolean isManagedProfile(UserManager userManager) {
    753         UserInfo currentUser = userManager.getUserInfo(userManager.getUserHandle());
    754         return currentUser.isManagedProfile();
    755     }
    756 
    757     /**
    758      * Creates a {@link UserAdapter} if there is more than one profile on the device.
    759      *
    760      * <p> The adapter can be used to populate a spinner that switches between the Settings
    761      * app on the different profiles.
    762      *
    763      * @return a {@link UserAdapter} or null if there is only one profile.
    764      */
    765     public static UserAdapter createUserSpinnerAdapter(UserManager userManager,
    766             Context context) {
    767         List<UserHandle> userProfiles = userManager.getUserProfiles();
    768         if (userProfiles.size() < 2) {
    769             return null;
    770         }
    771 
    772         UserHandle myUserHandle = new UserHandle(UserHandle.myUserId());
    773         // The first option should be the current profile
    774         userProfiles.remove(myUserHandle);
    775         userProfiles.add(0, myUserHandle);
    776 
    777         return createUserAdapter(userManager, context, userProfiles);
    778     }
    779 
    780     public static UserAdapter createUserAdapter(UserManager userManager,
    781             Context context, List<UserHandle> userProfiles) {
    782         ArrayList<UserDetails> userDetails = new ArrayList<UserDetails>(userProfiles.size());
    783         final int count = userProfiles.size();
    784         for (int i = 0; i < count; i++) {
    785             userDetails.add(new UserDetails(userProfiles.get(i), userManager, context));
    786         }
    787         return new UserAdapter(context, userDetails);
    788     }
    789 
    790     /**
    791      * Returns the target user for a Settings activity.
    792      *
    793      * The target user can be either the current user, the user that launched this activity or
    794      * the user contained as an extra in the arguments or intent extras.
    795      *
    796      * Note: This is secure in the sense that it only returns a target user different to the current
    797      * one if the app launching this activity is the Settings app itself, running in the same user
    798      * or in one that is in the same profile group, or if the user id is provided by the system.
    799      */
    800     public static UserHandle getSecureTargetUser(IBinder activityToken,
    801            UserManager um, @Nullable Bundle arguments, @Nullable Bundle intentExtras) {
    802         UserHandle currentUser = new UserHandle(UserHandle.myUserId());
    803         IActivityManager am = ActivityManagerNative.getDefault();
    804         try {
    805             String launchedFromPackage = am.getLaunchedFromPackage(activityToken);
    806             boolean launchedFromSettingsApp = SETTINGS_PACKAGE_NAME.equals(launchedFromPackage);
    807 
    808             UserHandle launchedFromUser = new UserHandle(UserHandle.getUserId(
    809                     am.getLaunchedFromUid(activityToken)));
    810             if (launchedFromUser != null && !launchedFromUser.equals(currentUser)) {
    811                 // Check it's secure
    812                 if (isProfileOf(um, launchedFromUser)) {
    813                     return launchedFromUser;
    814                 }
    815             }
    816             UserHandle extrasUser = intentExtras != null
    817                     ? (UserHandle) intentExtras.getParcelable(EXTRA_USER) : null;
    818             if (extrasUser != null && !extrasUser.equals(currentUser)) {
    819                 // Check it's secure
    820                 if (launchedFromSettingsApp && isProfileOf(um, extrasUser)) {
    821                     return extrasUser;
    822                 }
    823             }
    824             UserHandle argumentsUser = arguments != null
    825                     ? (UserHandle) arguments.getParcelable(EXTRA_USER) : null;
    826             if (argumentsUser != null && !argumentsUser.equals(currentUser)) {
    827                 // Check it's secure
    828                 if (launchedFromSettingsApp && isProfileOf(um, argumentsUser)) {
    829                     return argumentsUser;
    830                 }
    831             }
    832         } catch (RemoteException e) {
    833             // Should not happen
    834             Log.v(TAG, "Could not talk to activity manager.", e);
    835         }
    836         return currentUser;
    837    }
    838 
    839     /**
    840      * Returns the target user for a Settings activity.
    841      *
    842      * The target user can be either the current user, the user that launched this activity or
    843      * the user contained as an extra in the arguments or intent extras.
    844      *
    845      * You should use {@link #getSecureTargetUser(IBinder, UserManager, Bundle, Bundle)} if
    846      * possible.
    847      *
    848      * @see #getInsecureTargetUser(IBinder, Bundle, Bundle)
    849      */
    850    public static UserHandle getInsecureTargetUser(IBinder activityToken, @Nullable Bundle arguments,
    851            @Nullable Bundle intentExtras) {
    852        UserHandle currentUser = new UserHandle(UserHandle.myUserId());
    853        IActivityManager am = ActivityManagerNative.getDefault();
    854        try {
    855            UserHandle launchedFromUser = new UserHandle(UserHandle.getUserId(
    856                    am.getLaunchedFromUid(activityToken)));
    857            if (launchedFromUser != null && !launchedFromUser.equals(currentUser)) {
    858                return launchedFromUser;
    859            }
    860            UserHandle extrasUser = intentExtras != null
    861                    ? (UserHandle) intentExtras.getParcelable(EXTRA_USER) : null;
    862            if (extrasUser != null && !extrasUser.equals(currentUser)) {
    863                return extrasUser;
    864            }
    865            UserHandle argumentsUser = arguments != null
    866                    ? (UserHandle) arguments.getParcelable(EXTRA_USER) : null;
    867            if (argumentsUser != null && !argumentsUser.equals(currentUser)) {
    868                return argumentsUser;
    869            }
    870        } catch (RemoteException e) {
    871            // Should not happen
    872            Log.v(TAG, "Could not talk to activity manager.", e);
    873            return null;
    874        }
    875        return currentUser;
    876    }
    877 
    878    /**
    879     * Returns true if the user provided is in the same profiles group as the current user.
    880     */
    881    private static boolean isProfileOf(UserManager um, UserHandle otherUser) {
    882        if (um == null || otherUser == null) return false;
    883        return (UserHandle.myUserId() == otherUser.getIdentifier())
    884                || um.getUserProfiles().contains(otherUser);
    885    }
    886 
    887 
    888     /**
    889      * Returns whether or not this device is able to be OEM unlocked.
    890      */
    891     static boolean isOemUnlockEnabled(Context context) {
    892         PersistentDataBlockManager manager =(PersistentDataBlockManager)
    893                 context.getSystemService(Context.PERSISTENT_DATA_BLOCK_SERVICE);
    894         return manager.getOemUnlockEnabled();
    895     }
    896 
    897     /**
    898      * Allows enabling or disabling OEM unlock on this device. OEM unlocked
    899      * devices allow users to flash other OSes to them.
    900      */
    901     static void setOemUnlockEnabled(Context context, boolean enabled) {
    902         PersistentDataBlockManager manager =(PersistentDataBlockManager)
    903                 context.getSystemService(Context.PERSISTENT_DATA_BLOCK_SERVICE);
    904         manager.setOemUnlockEnabled(enabled);
    905     }
    906 
    907     /**
    908      * Returns a circular icon for a user.
    909      */
    910     public static Drawable getUserIcon(Context context, UserManager um, UserInfo user) {
    911         if (user.isManagedProfile()) {
    912             // We use predefined values for managed profiles
    913             Bitmap b = BitmapFactory.decodeResource(context.getResources(),
    914                     com.android.internal.R.drawable.ic_corp_icon);
    915             return CircleFramedDrawable.getInstance(context, b);
    916         }
    917         if (user.iconPath != null) {
    918             Bitmap icon = um.getUserIcon(user.id);
    919             if (icon != null) {
    920                 return CircleFramedDrawable.getInstance(context, icon);
    921             }
    922         }
    923         return CircleFramedDrawable.getInstance(context, UserIcons.convertToBitmap(
    924                 UserIcons.getDefaultUserIcon(user.id, /* light= */ false)));
    925     }
    926 
    927     /**
    928      * Returns a label for the user, in the form of "User: user name" or "Work profile".
    929      */
    930     public static String getUserLabel(Context context, UserInfo info) {
    931         String name = info != null ? info.name : null;
    932         if (info.isManagedProfile()) {
    933             // We use predefined values for managed profiles
    934             return context.getString(R.string.managed_user_title);
    935         } else if (info.isGuest()) {
    936             name = context.getString(R.string.user_guest);
    937         }
    938         if (name == null && info != null) {
    939             name = Integer.toString(info.id);
    940         } else if (info == null) {
    941             name = context.getString(R.string.unknown);
    942         }
    943         return context.getResources().getString(R.string.running_process_item_user_label, name);
    944     }
    945 
    946     /**
    947      * Return whether or not the user should have a SIM Cards option in Settings.
    948      * TODO: Change back to returning true if count is greater than one after testing.
    949      * TODO: See bug 16533525.
    950      */
    951     public static boolean showSimCardTile(Context context) {
    952         final TelephonyManager tm =
    953                 (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
    954 
    955         return tm.getSimCount() > 1;
    956     }
    957 
    958     /**
    959      * Determine whether a package is a "system package", in which case certain things (like
    960      * disabling notifications or disabling the package altogether) should be disallowed.
    961      */
    962     public static boolean isSystemPackage(PackageManager pm, PackageInfo pkg) {
    963         if (sSystemSignature == null) {
    964             sSystemSignature = new Signature[]{ getSystemSignature(pm) };
    965         }
    966         return sSystemSignature[0] != null && sSystemSignature[0].equals(getFirstSignature(pkg));
    967     }
    968 
    969     private static Signature[] sSystemSignature;
    970 
    971     private static Signature getFirstSignature(PackageInfo pkg) {
    972         if (pkg != null && pkg.signatures != null && pkg.signatures.length > 0) {
    973             return pkg.signatures[0];
    974         }
    975         return null;
    976     }
    977 
    978     private static Signature getSystemSignature(PackageManager pm) {
    979         try {
    980             final PackageInfo sys = pm.getPackageInfo("android", PackageManager.GET_SIGNATURES);
    981             return getFirstSignature(sys);
    982         } catch (NameNotFoundException e) {
    983         }
    984         return null;
    985     }
    986 
    987     /**
    988      * Returns elapsed time for the given millis, in the following format:
    989      * 2d 5h 40m 29s
    990      * @param context the application context
    991      * @param millis the elapsed time in milli seconds
    992      * @param withSeconds include seconds?
    993      * @return the formatted elapsed time
    994      */
    995     public static String formatElapsedTime(Context context, double millis, boolean withSeconds) {
    996         StringBuilder sb = new StringBuilder();
    997         int seconds = (int) Math.floor(millis / 1000);
    998         if (!withSeconds) {
    999             // Round up.
   1000             seconds += 30;
   1001         }
   1002 
   1003         int days = 0, hours = 0, minutes = 0;
   1004         if (seconds >= SECONDS_PER_DAY) {
   1005             days = seconds / SECONDS_PER_DAY;
   1006             seconds -= days * SECONDS_PER_DAY;
   1007         }
   1008         if (seconds >= SECONDS_PER_HOUR) {
   1009             hours = seconds / SECONDS_PER_HOUR;
   1010             seconds -= hours * SECONDS_PER_HOUR;
   1011         }
   1012         if (seconds >= SECONDS_PER_MINUTE) {
   1013             minutes = seconds / SECONDS_PER_MINUTE;
   1014             seconds -= minutes * SECONDS_PER_MINUTE;
   1015         }
   1016         if (withSeconds) {
   1017             if (days > 0) {
   1018                 sb.append(context.getString(R.string.battery_history_days,
   1019                         days, hours, minutes, seconds));
   1020             } else if (hours > 0) {
   1021                 sb.append(context.getString(R.string.battery_history_hours,
   1022                         hours, minutes, seconds));
   1023             } else if (minutes > 0) {
   1024                 sb.append(context.getString(R.string.battery_history_minutes, minutes, seconds));
   1025             } else {
   1026                 sb.append(context.getString(R.string.battery_history_seconds, seconds));
   1027             }
   1028         } else {
   1029             if (days > 0) {
   1030                 sb.append(context.getString(R.string.battery_history_days_no_seconds,
   1031                         days, hours, minutes));
   1032             } else if (hours > 0) {
   1033                 sb.append(context.getString(R.string.battery_history_hours_no_seconds,
   1034                         hours, minutes));
   1035             } else {
   1036                 sb.append(context.getString(R.string.battery_history_minutes_no_seconds, minutes));
   1037             }
   1038         }
   1039         return sb.toString();
   1040     }
   1041 
   1042     /**
   1043      * Queries for the UserInfo of a user. Returns null if the user doesn't exist (was removed).
   1044      * @param userManager Instance of UserManager
   1045      * @param checkUser The user to check the existence of.
   1046      * @return UserInfo of the user or null for non-existent user.
   1047      */
   1048     public static UserInfo getExistingUser(UserManager userManager, UserHandle checkUser) {
   1049         final List<UserInfo> users = userManager.getUsers(true /* excludeDying */);
   1050         final int checkUserId = checkUser.getIdentifier();
   1051         for (UserInfo user : users) {
   1052             if (user.id == checkUserId) {
   1053                 return user;
   1054             }
   1055         }
   1056         return null;
   1057     }
   1058 
   1059     public static View inflateCategoryHeader(LayoutInflater inflater, ViewGroup parent) {
   1060         final TypedArray a = inflater.getContext().obtainStyledAttributes(null,
   1061                 com.android.internal.R.styleable.Preference,
   1062                 com.android.internal.R.attr.preferenceCategoryStyle, 0);
   1063         final int resId = a.getResourceId(com.android.internal.R.styleable.Preference_layout,
   1064                 0);
   1065         a.recycle();
   1066         return inflater.inflate(resId, parent, false);
   1067     }
   1068 
   1069     /**
   1070      * Return if we are running low on storage space or not.
   1071      *
   1072      * @param context The context
   1073      * @return true if we are running low on storage space
   1074      */
   1075     public static boolean isLowStorage(Context context) {
   1076         final StorageManager sm = StorageManager.from(context);
   1077         return (sm.getStorageBytesUntilLow(context.getFilesDir()) < 0);
   1078     }
   1079 
   1080     /**
   1081      * Returns a default user icon (as a {@link Bitmap}) for the given user.
   1082      *
   1083      * Note that for guest users, you should pass in {@code UserHandle.USER_NULL}.
   1084      * @param userId the user id or {@code UserHandle.USER_NULL} for a non-user specific icon
   1085      */
   1086     public static Bitmap getDefaultUserIconAsBitmap(int userId) {
   1087         Bitmap bitmap = null;
   1088         // Try finding the corresponding bitmap in the dark bitmap cache
   1089         bitmap = sDarkDefaultUserBitmapCache.get(userId);
   1090         if (bitmap == null) {
   1091             bitmap = UserIcons.convertToBitmap(UserIcons.getDefaultUserIcon(userId, false));
   1092             // Save it to cache
   1093             sDarkDefaultUserBitmapCache.put(userId, bitmap);
   1094         }
   1095         return bitmap;
   1096     }
   1097 
   1098     public static boolean hasUsbDefaults(IUsbManager usbManager, String packageName) {
   1099         try {
   1100             if (usbManager != null) {
   1101                 return usbManager.hasDefaults(packageName, UserHandle.myUserId());
   1102             }
   1103         } catch (RemoteException e) {
   1104             Log.e(TAG, "mUsbManager.hasDefaults", e);
   1105         }
   1106         return false;
   1107     }
   1108 
   1109     public static boolean hasPreferredActivities(PackageManager pm, String packageName) {
   1110         // Get list of preferred activities
   1111         List<ComponentName> prefActList = new ArrayList<>();
   1112         // Intent list cannot be null. so pass empty list
   1113         List<IntentFilter> intentList = new ArrayList<>();
   1114         pm.getPreferredActivities(intentList, prefActList, packageName);
   1115         Log.d(TAG, "Have " + prefActList.size() + " number of activities in preferred list");
   1116         return prefActList.size() > 0;
   1117     }
   1118 
   1119     public static ArraySet<String> getHandledDomains(PackageManager pm, String packageName) {
   1120         List<IntentFilterVerificationInfo> iviList = pm.getIntentFilterVerifications(packageName);
   1121         List<IntentFilter> filters = pm.getAllIntentFilters(packageName);
   1122 
   1123         ArraySet<String> result = new ArraySet<>();
   1124         if (iviList.size() > 0) {
   1125             for (IntentFilterVerificationInfo ivi : iviList) {
   1126                 for (String host : ivi.getDomains()) {
   1127                     result.add(host);
   1128                 }
   1129             }
   1130         }
   1131         if (filters != null && filters.size() > 0) {
   1132             for (IntentFilter filter : filters) {
   1133                 if (filter.hasCategory(Intent.CATEGORY_BROWSABLE)
   1134                         && (filter.hasDataScheme(IntentFilter.SCHEME_HTTP) ||
   1135                                 filter.hasDataScheme(IntentFilter.SCHEME_HTTPS))) {
   1136                     result.addAll(filter.getHostsList());
   1137                 }
   1138             }
   1139         }
   1140         return result;
   1141     }
   1142 
   1143     public static CharSequence getLaunchByDeafaultSummary(ApplicationsState.AppEntry appEntry,
   1144             IUsbManager usbManager, PackageManager pm, Context context) {
   1145         String packageName = appEntry.info.packageName;
   1146         boolean hasPreferred = hasPreferredActivities(pm, packageName)
   1147                 || hasUsbDefaults(usbManager, packageName);
   1148         int status = pm.getIntentVerificationStatus(packageName, UserHandle.myUserId());
   1149         boolean hasDomainURLsPreference =
   1150                 (status == PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS) ||
   1151                 (status == PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER);
   1152         return context.getString(hasPreferred || hasDomainURLsPreference
   1153                 ? R.string.launch_defaults_some
   1154                 : R.string.launch_defaults_none);
   1155     }
   1156 
   1157     public static void handleLoadingContainer(View loading, View doneLoading, boolean done,
   1158             boolean animate) {
   1159         setViewShown(loading, !done, animate);
   1160         setViewShown(doneLoading, done, animate);
   1161     }
   1162 
   1163     private static void setViewShown(final View view, boolean shown, boolean animate) {
   1164         if (animate) {
   1165             Animation animation = AnimationUtils.loadAnimation(view.getContext(),
   1166                     shown ? android.R.anim.fade_in : android.R.anim.fade_out);
   1167             if (shown) {
   1168                 view.setVisibility(View.VISIBLE);
   1169             } else {
   1170                 animation.setAnimationListener(new AnimationListener() {
   1171                     @Override
   1172                     public void onAnimationStart(Animation animation) {
   1173                     }
   1174 
   1175                     @Override
   1176                     public void onAnimationRepeat(Animation animation) {
   1177                     }
   1178 
   1179                     @Override
   1180                     public void onAnimationEnd(Animation animation) {
   1181                         view.setVisibility(View.INVISIBLE);
   1182                     }
   1183                 });
   1184             }
   1185             view.startAnimation(animation);
   1186         } else {
   1187             view.clearAnimation();
   1188             view.setVisibility(shown ? View.VISIBLE : View.INVISIBLE);
   1189         }
   1190     }
   1191 
   1192     /**
   1193      * Returns the application info of the currently installed MDM package.
   1194      */
   1195     public static ApplicationInfo getAdminApplicationInfo(Context context, int profileId) {
   1196         DevicePolicyManager dpm =
   1197                 (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
   1198         ComponentName mdmPackage = dpm.getProfileOwnerAsUser(profileId);
   1199         if (mdmPackage == null) {
   1200             return null;
   1201         }
   1202         String mdmPackageName = mdmPackage.getPackageName();
   1203         try {
   1204             IPackageManager ipm = AppGlobals.getPackageManager();
   1205             ApplicationInfo mdmApplicationInfo =
   1206                     ipm.getApplicationInfo(mdmPackageName, 0, profileId);
   1207             return mdmApplicationInfo;
   1208         } catch (RemoteException e) {
   1209             Log.e(TAG, "Error while retrieving application info for package " + mdmPackageName
   1210                     + ", userId " + profileId, e);
   1211             return null;
   1212         }
   1213     }
   1214 
   1215     public static boolean isBandwidthControlEnabled() {
   1216         final INetworkManagementService netManager = INetworkManagementService.Stub
   1217                 .asInterface(ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
   1218         try {
   1219             return netManager.isBandwidthControlEnabled();
   1220         } catch (RemoteException e) {
   1221             return false;
   1222         }
   1223     }
   1224 
   1225     /**
   1226      * Returns an accessible SpannableString.
   1227      * @param displayText the text to display
   1228      * @param accessibileText the text text-to-speech engines should read
   1229      */
   1230     public static SpannableString createAccessibleSequence(CharSequence displayText,
   1231             String accessibileText) {
   1232         SpannableString str = new SpannableString(displayText);
   1233         str.setSpan(new TtsSpan.TextBuilder(accessibileText).build(), 0,
   1234                 displayText.length(),
   1235                 Spannable.SPAN_INCLUSIVE_INCLUSIVE);
   1236         return str;
   1237     }
   1238 
   1239     public static int getEffectiveUserId(Context context) {
   1240         UserManager um = UserManager.get(context);
   1241         if (um != null) {
   1242             return um.getCredentialOwnerProfile(UserHandle.myUserId());
   1243         } else {
   1244             Log.e(TAG, "Unable to acquire UserManager");
   1245             return UserHandle.myUserId();
   1246         }
   1247     }
   1248 }
   1249 
   1250