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