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