• 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 static android.content.Intent.EXTRA_USER;
20 import static android.content.Intent.EXTRA_USER_ID;
21 import static android.text.format.DateUtils.FORMAT_ABBREV_MONTH;
22 import static android.text.format.DateUtils.FORMAT_SHOW_DATE;
23 
24 import android.annotation.Nullable;
25 import android.app.ActionBar;
26 import android.app.Activity;
27 import android.app.ActivityManager;
28 import android.app.AppGlobals;
29 import android.app.IActivityManager;
30 import android.app.KeyguardManager;
31 import android.app.admin.DevicePolicyManager;
32 import android.content.ActivityNotFoundException;
33 import android.content.ComponentName;
34 import android.content.ContentResolver;
35 import android.content.Context;
36 import android.content.Intent;
37 import android.content.IntentFilter;
38 import android.content.pm.ApplicationInfo;
39 import android.content.pm.IPackageManager;
40 import android.content.pm.IntentFilterVerificationInfo;
41 import android.content.pm.PackageManager;
42 import android.content.pm.PackageManager.NameNotFoundException;
43 import android.content.pm.ResolveInfo;
44 import android.content.pm.UserInfo;
45 import android.content.res.Configuration;
46 import android.content.res.Resources;
47 import android.content.res.TypedArray;
48 import android.database.Cursor;
49 import android.graphics.Bitmap;
50 import android.graphics.Canvas;
51 import android.graphics.drawable.AdaptiveIconDrawable;
52 import android.graphics.drawable.BitmapDrawable;
53 import android.graphics.drawable.Drawable;
54 import android.graphics.drawable.VectorDrawable;
55 import android.hardware.face.FaceManager;
56 import android.hardware.fingerprint.FingerprintManager;
57 import android.net.ConnectivityManager;
58 import android.net.LinkAddress;
59 import android.net.LinkProperties;
60 import android.net.Network;
61 import android.net.wifi.WifiManager;
62 import android.os.BatteryManager;
63 import android.os.Binder;
64 import android.os.Build;
65 import android.os.Bundle;
66 import android.os.IBinder;
67 import android.os.INetworkManagementService;
68 import android.os.RemoteException;
69 import android.os.ServiceManager;
70 import android.os.UserHandle;
71 import android.os.UserManager;
72 import android.os.storage.StorageManager;
73 import android.os.storage.VolumeInfo;
74 import android.preference.PreferenceFrameLayout;
75 import android.provider.ContactsContract.CommonDataKinds;
76 import android.provider.ContactsContract.Contacts;
77 import android.provider.ContactsContract.Data;
78 import android.provider.ContactsContract.Profile;
79 import android.provider.ContactsContract.RawContacts;
80 import android.telephony.SubscriptionManager;
81 import android.telephony.TelephonyManager;
82 import android.text.Spannable;
83 import android.text.SpannableString;
84 import android.text.TextUtils;
85 import android.text.format.DateUtils;
86 import android.text.style.TtsSpan;
87 import android.util.ArraySet;
88 import android.util.IconDrawableFactory;
89 import android.util.Log;
90 import android.view.LayoutInflater;
91 import android.view.View;
92 import android.view.ViewGroup;
93 import android.widget.EditText;
94 import android.widget.ListView;
95 import android.widget.TabWidget;
96 
97 import androidx.annotation.ColorInt;
98 import androidx.annotation.NonNull;
99 import androidx.annotation.StringRes;
100 import androidx.core.graphics.drawable.IconCompat;
101 import androidx.core.graphics.drawable.RoundedBitmapDrawable;
102 import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
103 import androidx.fragment.app.Fragment;
104 import androidx.lifecycle.Lifecycle;
105 import androidx.preference.Preference;
106 import androidx.preference.PreferenceGroup;
107 
108 import com.android.internal.app.UnlaunchableAppActivity;
109 import com.android.internal.util.ArrayUtils;
110 import com.android.internal.widget.LockPatternUtils;
111 import com.android.settings.dashboard.profileselector.ProfileFragmentBridge;
112 import com.android.settings.dashboard.profileselector.ProfileSelectFragment;
113 import com.android.settings.password.ChooseLockSettingsHelper;
114 import com.android.settingslib.widget.ActionBarShadowController;
115 import com.android.settingslib.widget.AdaptiveIcon;
116 
117 import java.util.Iterator;
118 import java.util.List;
119 import java.util.Locale;
120 
121 public final class Utils extends com.android.settingslib.Utils {
122 
123     private static final String TAG = "Settings";
124 
125     public static final String FILE_PROVIDER_AUTHORITY = "com.android.settings.files";
126 
127     /**
128      * Set the preference's title to the matching activity's label.
129      */
130     public static final int UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY = 1;
131 
132     public static final String SETTINGS_PACKAGE_NAME = "com.android.settings";
133 
134     public static final String OS_PKG = "os";
135 
136     /**
137      * Whether to disable the new device identifier access restrictions.
138      */
139     public static final String PROPERTY_DEVICE_IDENTIFIER_ACCESS_RESTRICTIONS_DISABLED =
140             "device_identifier_access_restrictions_disabled";
141 
142     /**
143      * Whether to show the Permissions Hub.
144      */
145     public static final String PROPERTY_PERMISSIONS_HUB_ENABLED = "permissions_hub_enabled";
146 
147     /**
148      * Whether to show location indicators.
149      */
150     public static final String PROPERTY_LOCATION_INDICATORS_ENABLED = "location_indicators_enabled";
151 
152     /**
153      * Whether to show location indicator settings in developer options.
154      */
155     public static final String PROPERTY_LOCATION_INDICATOR_SETTINGS_ENABLED =
156             "location_indicator_settings_enabled";
157 
158     /** Whether or not app hibernation is enabled on the device **/
159     public static final String PROPERTY_APP_HIBERNATION_ENABLED = "app_hibernation_enabled";
160 
161     /** Whether or not app hibernation targets apps that target a pre-S SDK **/
162     public static final String PROPERTY_HIBERNATION_TARGETS_PRE_S_APPS =
163             "app_hibernation_targets_pre_s_apps";
164 
165     /**
166      * Finds a matching activity for a preference's intent. If a matching
167      * activity is not found, it will remove the preference.
168      *
169      * @param context The context.
170      * @param parentPreferenceGroup The preference group that contains the
171      *            preference whose intent is being resolved.
172      * @param preferenceKey The key of the preference whose intent is being
173      *            resolved.
174      * @param flags 0 or one or more of
175      *            {@link #UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY}
176      *            .
177      * @return Whether an activity was found. If false, the preference was
178      *         removed.
179      */
updatePreferenceToSpecificActivityOrRemove(Context context, PreferenceGroup parentPreferenceGroup, String preferenceKey, int flags)180     public static boolean updatePreferenceToSpecificActivityOrRemove(Context context,
181             PreferenceGroup parentPreferenceGroup, String preferenceKey, int flags) {
182 
183         final Preference preference = parentPreferenceGroup.findPreference(preferenceKey);
184         if (preference == null) {
185             return false;
186         }
187 
188         final Intent intent = preference.getIntent();
189         if (intent != null) {
190             // Find the activity that is in the system image
191             final PackageManager pm = context.getPackageManager();
192             final List<ResolveInfo> list = pm.queryIntentActivities(intent, 0);
193             final int listSize = list.size();
194             for (int i = 0; i < listSize; i++) {
195                 final ResolveInfo resolveInfo = list.get(i);
196                 if ((resolveInfo.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
197                         != 0) {
198 
199                     // Replace the intent with this specific activity
200                     preference.setIntent(new Intent().setClassName(
201                             resolveInfo.activityInfo.packageName,
202                             resolveInfo.activityInfo.name));
203 
204                     if ((flags & UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY) != 0) {
205                         // Set the preference title to the activity's label
206                         preference.setTitle(resolveInfo.loadLabel(pm));
207                     }
208 
209                     return true;
210                 }
211             }
212         }
213 
214         // Did not find a matching activity, so remove the preference
215         parentPreferenceGroup.removePreference(preference);
216 
217         return false;
218     }
219 
220     /**
221      * Returns true if Monkey is running.
222      */
isMonkeyRunning()223     public static boolean isMonkeyRunning() {
224         return ActivityManager.isUserAMonkey();
225     }
226 
227     /**
228      * Returns whether the device is voice-capable (meaning, it is also a phone).
229      */
isVoiceCapable(Context context)230     public static boolean isVoiceCapable(Context context) {
231         final TelephonyManager telephony =
232                 (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
233         return telephony != null && telephony.isVoiceCapable();
234     }
235 
236     /**
237      * Returns the WIFI IP Addresses, if any, taking into account IPv4 and IPv6 style addresses.
238      * @param context the application context
239      * @return the formatted and newline-separated IP addresses, or null if none.
240      */
getWifiIpAddresses(Context context)241     public static String getWifiIpAddresses(Context context) {
242         final WifiManager wifiManager = context.getSystemService(WifiManager.class);
243         final Network currentNetwork = wifiManager.getCurrentNetwork();
244         if (currentNetwork != null) {
245             final ConnectivityManager cm = (ConnectivityManager)
246                 context.getSystemService(Context.CONNECTIVITY_SERVICE);
247             final LinkProperties prop = cm.getLinkProperties(currentNetwork);
248             return formatIpAddresses(prop);
249         }
250         return null;
251     }
252 
formatIpAddresses(LinkProperties prop)253     private static String formatIpAddresses(LinkProperties prop) {
254         if (prop == null) return null;
255         final Iterator<LinkAddress> iter = prop.getAllLinkAddresses().iterator();
256         // If there are no entries, return null
257         if (!iter.hasNext()) return null;
258         // Concatenate all available addresses, comma separated
259         String addresses = "";
260         while (iter.hasNext()) {
261             addresses += iter.next().getAddress().getHostAddress();
262             if (iter.hasNext()) addresses += "\n";
263         }
264         return addresses;
265     }
266 
createLocaleFromString(String localeStr)267     public static Locale createLocaleFromString(String localeStr) {
268         // TODO: is there a better way to actually construct a locale that will match?
269         // The main problem is, on top of Java specs, locale.toString() and
270         // new Locale(locale.toString()).toString() do not return equal() strings in
271         // many cases, because the constructor takes the only string as the language
272         // code. So : new Locale("en", "US").toString() => "en_US"
273         // And : new Locale("en_US").toString() => "en_us"
274         if (null == localeStr)
275             return Locale.getDefault();
276         final String[] brokenDownLocale = localeStr.split("_", 3);
277         // split may not return a 0-length array.
278         if (1 == brokenDownLocale.length) {
279             return new Locale(brokenDownLocale[0]);
280         } else if (2 == brokenDownLocale.length) {
281             return new Locale(brokenDownLocale[0], brokenDownLocale[1]);
282         } else {
283             return new Locale(brokenDownLocale[0], brokenDownLocale[1], brokenDownLocale[2]);
284         }
285     }
286 
isBatteryPresent(Intent batteryChangedIntent)287     public static boolean isBatteryPresent(Intent batteryChangedIntent) {
288         return batteryChangedIntent.getBooleanExtra(BatteryManager.EXTRA_PRESENT, true);
289     }
290 
291     /**
292      * Return true if battery is present.
293      */
isBatteryPresent(Context context)294     public static boolean isBatteryPresent(Context context) {
295         Intent batteryBroadcast = context.registerReceiver(null /* receiver */,
296                 new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
297         return isBatteryPresent(batteryBroadcast);
298     }
299 
getBatteryPercentage(Intent batteryChangedIntent)300     public static String getBatteryPercentage(Intent batteryChangedIntent) {
301         return formatPercentage(getBatteryLevel(batteryChangedIntent));
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 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             list.setPaddingRelative(0 /* start */, 0 /* top */, 0 /* end */, paddingBottom);
321         }
322     }
323 
forceCustomPadding(View view, boolean additive)324     public static void forceCustomPadding(View view, boolean additive) {
325         final Resources res = view.getResources();
326 
327         final int paddingStart = additive ? view.getPaddingStart() : 0;
328         final int paddingEnd = additive ? view.getPaddingEnd() : 0;
329         final int paddingBottom = res.getDimensionPixelSize(
330                 com.android.internal.R.dimen.preference_fragment_padding_bottom);
331 
332         view.setPaddingRelative(paddingStart, 0, paddingEnd, paddingBottom);
333     }
334 
getMeProfileName(Context context, boolean full)335     public static String getMeProfileName(Context context, boolean full) {
336         if (full) {
337             return getProfileDisplayName(context);
338         } else {
339             return getShorterNameIfPossible(context);
340         }
341     }
342 
getShorterNameIfPossible(Context context)343     private static String getShorterNameIfPossible(Context context) {
344         final String given = getLocalProfileGivenName(context);
345         return !TextUtils.isEmpty(given) ? given : getProfileDisplayName(context);
346     }
347 
getLocalProfileGivenName(Context context)348     private static String getLocalProfileGivenName(Context context) {
349         final ContentResolver cr = context.getContentResolver();
350 
351         // Find the raw contact ID for the local ME profile raw contact.
352         final long localRowProfileId;
353         final Cursor localRawProfile = cr.query(
354                 Profile.CONTENT_RAW_CONTACTS_URI,
355                 new String[] {RawContacts._ID},
356                 RawContacts.ACCOUNT_TYPE + " IS NULL AND " +
357                         RawContacts.ACCOUNT_NAME + " IS NULL",
358                 null, null);
359         if (localRawProfile == null) return null;
360 
361         try {
362             if (!localRawProfile.moveToFirst()) {
363                 return null;
364             }
365             localRowProfileId = localRawProfile.getLong(0);
366         } finally {
367             localRawProfile.close();
368         }
369 
370         // Find the structured name for the raw contact.
371         final Cursor structuredName = cr.query(
372                 Profile.CONTENT_URI.buildUpon().appendPath(Contacts.Data.CONTENT_DIRECTORY).build(),
373                 new String[] {CommonDataKinds.StructuredName.GIVEN_NAME,
374                     CommonDataKinds.StructuredName.FAMILY_NAME},
375                 Data.RAW_CONTACT_ID + "=" + localRowProfileId,
376                 null, null);
377         if (structuredName == null) return null;
378 
379         try {
380             if (!structuredName.moveToFirst()) {
381                 return null;
382             }
383             String partialName = structuredName.getString(0);
384             if (TextUtils.isEmpty(partialName)) {
385                 partialName = structuredName.getString(1);
386             }
387             return partialName;
388         } finally {
389             structuredName.close();
390         }
391     }
392 
getProfileDisplayName(Context context)393     private static final String getProfileDisplayName(Context context) {
394         final ContentResolver cr = context.getContentResolver();
395         final Cursor profile = cr.query(Profile.CONTENT_URI,
396                 new String[] {Profile.DISPLAY_NAME}, null, null, null);
397         if (profile == null) return null;
398 
399         try {
400             if (!profile.moveToFirst()) {
401                 return null;
402             }
403             return profile.getString(0);
404         } finally {
405             profile.close();
406         }
407     }
408 
hasMultipleUsers(Context context)409     public static boolean hasMultipleUsers(Context context) {
410         return context.getSystemService(UserManager.class)
411                 .getUsers().size() > 1;
412     }
413 
414     /**
415      * Returns the managed profile of the current user or {@code null} if none is found or a profile
416      * exists but it is disabled.
417      */
getManagedProfile(UserManager userManager)418     public static UserHandle getManagedProfile(UserManager userManager) {
419         final List<UserHandle> userProfiles = userManager.getUserProfiles();
420         for (UserHandle profile : userProfiles) {
421             if (profile.getIdentifier() == userManager.getProcessUserId()) {
422                 continue;
423             }
424             final UserInfo userInfo = userManager.getUserInfo(profile.getIdentifier());
425             if (userInfo.isManagedProfile()) {
426                 return profile;
427             }
428         }
429         return null;
430     }
431 
432     /**
433      * Returns the managed profile of the current user or {@code null} if none is found. Unlike
434      * {@link #getManagedProfile} this method returns enabled and disabled managed profiles.
435      */
getManagedProfileWithDisabled(UserManager userManager)436     public static UserHandle getManagedProfileWithDisabled(UserManager userManager) {
437         // TODO: Call getManagedProfileId from here once Robolectric supports
438         // API level 24 and UserManager.getProfileIdsWithDisabled can be Mocked (to avoid having
439         // yet another implementation that loops over user profiles in this method). In the meantime
440         // we need to use UserManager.getProfiles that is available on API 23 (the one currently
441         // used for Settings Robolectric tests).
442         final int myUserId = UserHandle.myUserId();
443         final List<UserInfo> profiles = userManager.getProfiles(myUserId);
444         final int count = profiles.size();
445         for (int i = 0; i < count; i++) {
446             final UserInfo profile = profiles.get(i);
447             if (profile.isManagedProfile()
448                     && profile.getUserHandle().getIdentifier() != myUserId) {
449                 return profile.getUserHandle();
450             }
451         }
452         return null;
453     }
454 
455     /**
456      * Retrieves the id for the given user's managed profile.
457      *
458      * @return the managed profile id or UserHandle.USER_NULL if there is none.
459      */
getManagedProfileId(UserManager um, int parentUserId)460     public static int getManagedProfileId(UserManager um, int parentUserId) {
461         final int[] profileIds = um.getProfileIdsWithDisabled(parentUserId);
462         for (int profileId : profileIds) {
463             if (profileId != parentUserId) {
464                 return profileId;
465             }
466         }
467         return UserHandle.USER_NULL;
468     }
469 
470     /** Returns user ID of current user, throws IllegalStateException if it's not available. */
getCurrentUserId(UserManager userManager, boolean isWorkProfile)471     public static int getCurrentUserId(UserManager userManager, boolean isWorkProfile)
472             throws IllegalStateException {
473         if (isWorkProfile) {
474             final UserHandle managedUserHandle = getManagedProfile(userManager);
475             if (managedUserHandle == null) {
476                 throw new IllegalStateException("Work profile user ID is not available.");
477             }
478             return managedUserHandle.getIdentifier();
479         }
480         return UserHandle.myUserId();
481     }
482 
483     /**
484      * Returns the target user for a Settings activity.
485      * <p>
486      * User would be retrieved in this order:
487      * <ul>
488      * <li> If this activity is launched from other user, return that user id.
489      * <li> If this is launched from the Settings app in same user, return the user contained as an
490      *      extra in the arguments or intent extras.
491      * <li> Otherwise, return UserHandle.myUserId().
492      * </ul>
493      * <p>
494      * Note: This is secure in the sense that it only returns a target user different to the current
495      * one if the app launching this activity is the Settings app itself, running in the same user
496      * or in one that is in the same profile group, or if the user id is provided by the system.
497      */
getSecureTargetUser(IBinder activityToken, UserManager um, @Nullable Bundle arguments, @Nullable Bundle intentExtras)498     public static UserHandle getSecureTargetUser(IBinder activityToken,
499             UserManager um, @Nullable Bundle arguments, @Nullable Bundle intentExtras) {
500         final UserHandle currentUser = new UserHandle(UserHandle.myUserId());
501         final IActivityManager am = ActivityManager.getService();
502         try {
503             final String launchedFromPackage = am.getLaunchedFromPackage(activityToken);
504             final boolean launchedFromSettingsApp =
505                     SETTINGS_PACKAGE_NAME.equals(launchedFromPackage);
506 
507             final UserHandle launchedFromUser = new UserHandle(UserHandle.getUserId(
508                     am.getLaunchedFromUid(activityToken)));
509             if (launchedFromUser != null && !launchedFromUser.equals(currentUser)) {
510                 // Check it's secure
511                 if (isProfileOf(um, launchedFromUser)) {
512                     return launchedFromUser;
513                 }
514             }
515             final UserHandle extrasUser = getUserHandleFromBundle(intentExtras);
516             if (extrasUser != null && !extrasUser.equals(currentUser)) {
517                 // Check it's secure
518                 if (launchedFromSettingsApp && isProfileOf(um, extrasUser)) {
519                     return extrasUser;
520                 }
521             }
522             final UserHandle argumentsUser = getUserHandleFromBundle(arguments);
523             if (argumentsUser != null && !argumentsUser.equals(currentUser)) {
524                 // Check it's secure
525                 if (launchedFromSettingsApp && isProfileOf(um, argumentsUser)) {
526                     return argumentsUser;
527                 }
528             }
529         } catch (RemoteException e) {
530             // Should not happen
531             Log.v(TAG, "Could not talk to activity manager.", e);
532         }
533         return currentUser;
534     }
535 
536     /**
537      * Lookup both {@link Intent#EXTRA_USER} and {@link Intent#EXTRA_USER_ID} in the bundle
538      * and return the {@link UserHandle} object. Return {@code null} if nothing is found.
539      */
getUserHandleFromBundle(Bundle bundle)540     private static @Nullable UserHandle getUserHandleFromBundle(Bundle bundle) {
541         if (bundle == null) {
542             return null;
543         }
544         final UserHandle user = bundle.getParcelable(EXTRA_USER);
545         if (user != null) {
546             return user;
547         }
548         final int userId = bundle.getInt(EXTRA_USER_ID, -1);
549         if (userId != -1) {
550             return UserHandle.of(userId);
551         }
552         return null;
553     }
554 
555    /**
556     * Returns true if the user provided is in the same profiles group as the current user.
557     */
isProfileOf(UserManager um, UserHandle otherUser)558    private static boolean isProfileOf(UserManager um, UserHandle otherUser) {
559        if (um == null || otherUser == null) return false;
560        return (UserHandle.myUserId() == otherUser.getIdentifier())
561                || um.getUserProfiles().contains(otherUser);
562    }
563 
564     /**
565      * Queries for the UserInfo of a user. Returns null if the user doesn't exist (was removed).
566      * @param userManager Instance of UserManager
567      * @param checkUser The user to check the existence of.
568      * @return UserInfo of the user or null for non-existent user.
569      */
getExistingUser(UserManager userManager, UserHandle checkUser)570     public static UserInfo getExistingUser(UserManager userManager, UserHandle checkUser) {
571         final List<UserInfo> users = userManager.getAliveUsers();
572         final int checkUserId = checkUser.getIdentifier();
573         for (UserInfo user : users) {
574             if (user.id == checkUserId) {
575                 return user;
576             }
577         }
578         return null;
579     }
580 
inflateCategoryHeader(LayoutInflater inflater, ViewGroup parent)581     public static View inflateCategoryHeader(LayoutInflater inflater, ViewGroup parent) {
582         final TypedArray a = inflater.getContext().obtainStyledAttributes(null,
583                 com.android.internal.R.styleable.Preference,
584                 com.android.internal.R.attr.preferenceCategoryStyle, 0);
585         final int resId = a.getResourceId(com.android.internal.R.styleable.Preference_layout,
586                 0);
587         a.recycle();
588         return inflater.inflate(resId, parent, false);
589     }
590 
getHandledDomains(PackageManager pm, String packageName)591     public static ArraySet<String> getHandledDomains(PackageManager pm, String packageName) {
592         final List<IntentFilterVerificationInfo> iviList =
593                 pm.getIntentFilterVerifications(packageName);
594         final List<IntentFilter> filters = pm.getAllIntentFilters(packageName);
595 
596         final ArraySet<String> result = new ArraySet<>();
597         if (iviList != null && iviList.size() > 0) {
598             for (IntentFilterVerificationInfo ivi : iviList) {
599                 for (String host : ivi.getDomains()) {
600                     result.add(host);
601                 }
602             }
603         }
604         if (filters != null && filters.size() > 0) {
605             for (IntentFilter filter : filters) {
606                 if (filter.hasCategory(Intent.CATEGORY_BROWSABLE)
607                         && (filter.hasDataScheme(IntentFilter.SCHEME_HTTP) ||
608                                 filter.hasDataScheme(IntentFilter.SCHEME_HTTPS))) {
609                     result.addAll(filter.getHostsList());
610                 }
611             }
612         }
613         return result;
614     }
615 
616     /**
617      * Returns the application info of the currently installed MDM package.
618      */
getAdminApplicationInfo(Context context, int profileId)619     public static ApplicationInfo getAdminApplicationInfo(Context context, int profileId) {
620         final DevicePolicyManager dpm =
621                 (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
622         final ComponentName mdmPackage = dpm.getProfileOwnerAsUser(profileId);
623         if (mdmPackage == null) {
624             return null;
625         }
626         final String mdmPackageName = mdmPackage.getPackageName();
627         try {
628             final IPackageManager ipm = AppGlobals.getPackageManager();
629             final ApplicationInfo mdmApplicationInfo =
630                     ipm.getApplicationInfo(mdmPackageName, 0, profileId);
631             return mdmApplicationInfo;
632         } catch (RemoteException e) {
633             Log.e(TAG, "Error while retrieving application info for package " + mdmPackageName
634                     + ", userId " + profileId, e);
635             return null;
636         }
637     }
638 
isBandwidthControlEnabled()639     public static boolean isBandwidthControlEnabled() {
640         final INetworkManagementService netManager = INetworkManagementService.Stub
641                 .asInterface(ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
642         try {
643             return netManager.isBandwidthControlEnabled();
644         } catch (RemoteException e) {
645             return false;
646         }
647     }
648 
649     /**
650      * Returns an accessible SpannableString.
651      * @param displayText the text to display
652      * @param accessibileText the text text-to-speech engines should read
653      */
createAccessibleSequence(CharSequence displayText, String accessibileText)654     public static SpannableString createAccessibleSequence(CharSequence displayText,
655             String accessibileText) {
656         final SpannableString str = new SpannableString(displayText);
657         str.setSpan(new TtsSpan.TextBuilder(accessibileText).build(), 0,
658                 displayText.length(),
659                 Spannable.SPAN_INCLUSIVE_INCLUSIVE);
660         return str;
661     }
662 
663     /**
664      * Returns the user id present in the bundle with
665      * {@link Intent#EXTRA_USER_ID} if it belongs to the current user.
666      *
667      * @throws SecurityException if the given userId does not belong to the
668      *             current user group.
669      */
getUserIdFromBundle(Context context, Bundle bundle)670     public static int getUserIdFromBundle(Context context, Bundle bundle) {
671         return getUserIdFromBundle(context, bundle, false);
672     }
673 
674     /**
675      * Returns the user id present in the bundle with
676      * {@link Intent#EXTRA_USER_ID} if it belongs to the current user.
677      *
678      * @param isInternal indicating if the caller is "internal" to the system,
679      *            meaning we're willing to trust extras like
680      *            {@link ChooseLockSettingsHelper#EXTRA_KEY_ALLOW_ANY_USER}.
681      * @throws SecurityException if the given userId does not belong to the
682      *             current user group.
683      */
getUserIdFromBundle(Context context, Bundle bundle, boolean isInternal)684     public static int getUserIdFromBundle(Context context, Bundle bundle, boolean isInternal) {
685         if (bundle == null) {
686             return getCredentialOwnerUserId(context);
687         }
688         final boolean allowAnyUser = isInternal
689                 && bundle.getBoolean(ChooseLockSettingsHelper.EXTRA_KEY_ALLOW_ANY_USER, false);
690         final int userId = bundle.getInt(Intent.EXTRA_USER_ID, UserHandle.myUserId());
691         if (userId == LockPatternUtils.USER_FRP) {
692             return allowAnyUser ? userId : enforceSystemUser(context, userId);
693         } else {
694             return allowAnyUser ? userId : enforceSameOwner(context, userId);
695         }
696     }
697 
698     /**
699      * Returns the given user id if the current user is the system user.
700      *
701      * @throws SecurityException if the current user is not the system user.
702      */
enforceSystemUser(Context context, int userId)703     public static int enforceSystemUser(Context context, int userId) {
704         if (UserHandle.myUserId() == UserHandle.USER_SYSTEM) {
705             return userId;
706         }
707         throw new SecurityException("Given user id " + userId + " must only be used from "
708                 + "USER_SYSTEM, but current user is " + UserHandle.myUserId());
709     }
710 
711     /**
712      * Returns the given user id if it belongs to the current user.
713      *
714      * @throws SecurityException if the given userId does not belong to the current user group.
715      */
enforceSameOwner(Context context, int userId)716     public static int enforceSameOwner(Context context, int userId) {
717         final UserManager um = context.getSystemService(UserManager.class);
718         final int[] profileIds = um.getProfileIdsWithDisabled(UserHandle.myUserId());
719         if (ArrayUtils.contains(profileIds, userId)) {
720             return userId;
721         }
722         throw new SecurityException("Given user id " + userId + " does not belong to user "
723                 + UserHandle.myUserId());
724     }
725 
726     /**
727      * Returns the effective credential owner of the calling user.
728      */
getCredentialOwnerUserId(Context context)729     public static int getCredentialOwnerUserId(Context context) {
730         return getCredentialOwnerUserId(context, UserHandle.myUserId());
731     }
732 
733     /**
734      * Returns the user id of the credential owner of the given user id.
735      */
getCredentialOwnerUserId(Context context, int userId)736     public static int getCredentialOwnerUserId(Context context, int userId) {
737         final UserManager um = context.getSystemService(UserManager.class);
738         return um.getCredentialOwnerProfile(userId);
739     }
740 
741     /**
742      * Returns the credential type of the given user id.
743      */
getCredentialType(Context context, int userId)744     public static @LockPatternUtils.CredentialType int getCredentialType(Context context,
745             int userId) {
746         final LockPatternUtils lpu = new LockPatternUtils(context);
747         return lpu.getCredentialTypeForUser(userId);
748     }
749 
750     private static final StringBuilder sBuilder = new StringBuilder(50);
751     private static final java.util.Formatter sFormatter = new java.util.Formatter(
752             sBuilder, Locale.getDefault());
753 
formatDateRange(Context context, long start, long end)754     public static String formatDateRange(Context context, long start, long end) {
755         final int flags = FORMAT_SHOW_DATE | FORMAT_ABBREV_MONTH;
756 
757         synchronized (sBuilder) {
758             sBuilder.setLength(0);
759             return DateUtils.formatDateRange(context, sFormatter, start, end, flags, null)
760                     .toString();
761         }
762     }
763 
startQuietModeDialogIfNecessary(Context context, UserManager um, int userId)764     public static boolean startQuietModeDialogIfNecessary(Context context, UserManager um,
765             int userId) {
766         if (um.isQuietModeEnabled(UserHandle.of(userId))) {
767             final Intent intent = UnlaunchableAppActivity.createInQuietModeDialogIntent(userId);
768             context.startActivity(intent);
769             return true;
770         }
771         return false;
772     }
773 
unlockWorkProfileIfNecessary(Context context, int userId)774     public static boolean unlockWorkProfileIfNecessary(Context context, int userId) {
775         try {
776             if (!ActivityManager.getService().isUserRunning(userId,
777                     ActivityManager.FLAG_AND_LOCKED)) {
778                 return false;
779             }
780         } catch (RemoteException e) {
781             return false;
782         }
783         if (!(new LockPatternUtils(context)).isSecure(userId)) {
784             return false;
785         }
786         return confirmWorkProfileCredentials(context, userId);
787     }
788 
confirmWorkProfileCredentials(Context context, int userId)789     private static boolean confirmWorkProfileCredentials(Context context, int userId) {
790         final KeyguardManager km = (KeyguardManager) context.getSystemService(
791                 Context.KEYGUARD_SERVICE);
792         final Intent unlockIntent = km.createConfirmDeviceCredentialIntent(null, null, userId);
793         if (unlockIntent != null) {
794             context.startActivity(unlockIntent);
795             return true;
796         } else {
797             return false;
798         }
799     }
800 
getApplicationLabel(Context context, String packageName)801     public static CharSequence getApplicationLabel(Context context, String packageName) {
802         try {
803             final ApplicationInfo appInfo = context.getPackageManager().getApplicationInfo(
804                     packageName,
805                     PackageManager.MATCH_DISABLED_COMPONENTS
806                     | PackageManager.MATCH_ANY_USER);
807             return appInfo.loadLabel(context.getPackageManager());
808         } catch (PackageManager.NameNotFoundException e) {
809             Log.e(TAG, "Unable to find info for package: " + packageName);
810         }
811         return null;
812     }
813 
isPackageDirectBootAware(Context context, String packageName)814     public static boolean isPackageDirectBootAware(Context context, String packageName) {
815         try {
816             final ApplicationInfo ai = context.getPackageManager().getApplicationInfo(
817                     packageName, 0);
818             return ai.isDirectBootAware() || ai.isPartiallyDirectBootAware();
819         } catch (NameNotFoundException ignored) {
820         }
821         return false;
822     }
823 
824     /**
825      * Returns a context created from the given context for the given user, or null if it fails
826      */
createPackageContextAsUser(Context context, int userId)827     public static Context createPackageContextAsUser(Context context, int userId) {
828         try {
829             return context.createPackageContextAsUser(
830                     context.getPackageName(), 0 /* flags */, UserHandle.of(userId));
831         } catch (PackageManager.NameNotFoundException e) {
832             Log.e(TAG, "Failed to create user context", e);
833         }
834         return null;
835     }
836 
getFingerprintManagerOrNull(Context context)837     public static FingerprintManager getFingerprintManagerOrNull(Context context) {
838         if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
839             return (FingerprintManager) context.getSystemService(Context.FINGERPRINT_SERVICE);
840         } else {
841             return null;
842         }
843     }
844 
hasFingerprintHardware(Context context)845     public static boolean hasFingerprintHardware(Context context) {
846         final FingerprintManager fingerprintManager = getFingerprintManagerOrNull(context);
847         return fingerprintManager != null && fingerprintManager.isHardwareDetected();
848     }
849 
getFaceManagerOrNull(Context context)850     public static FaceManager getFaceManagerOrNull(Context context) {
851         if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FACE)) {
852             return (FaceManager) context.getSystemService(Context.FACE_SERVICE);
853         } else {
854             return null;
855         }
856     }
857 
hasFaceHardware(Context context)858     public static boolean hasFaceHardware(Context context) {
859         final FaceManager faceManager = getFaceManagerOrNull(context);
860         return faceManager != null && faceManager.isHardwareDetected();
861     }
862 
863     /**
864      * Return true if the device supports multiple biometrics authentications.
865      */
isMultipleBiometricsSupported(Context context)866     public static boolean isMultipleBiometricsSupported(Context context) {
867         return hasFingerprintHardware(context) && hasFaceHardware(context);
868     }
869 
870     /**
871      * Launches an intent which may optionally have a user id defined.
872      * @param fragment Fragment to use to launch the activity.
873      * @param intent Intent to launch.
874      */
launchIntent(Fragment fragment, Intent intent)875     public static void launchIntent(Fragment fragment, Intent intent) {
876         try {
877             final int userId = intent.getIntExtra(Intent.EXTRA_USER_ID, -1);
878 
879             if (userId == -1) {
880                 fragment.startActivity(intent);
881             } else {
882                 fragment.getActivity().startActivityAsUser(intent, new UserHandle(userId));
883             }
884         } catch (ActivityNotFoundException e) {
885             Log.w(TAG, "No activity found for " + intent);
886         }
887     }
888 
isDemoUser(Context context)889     public static boolean isDemoUser(Context context) {
890         return UserManager.isDeviceInDemoMode(context)
891                 && context.getSystemService(UserManager.class).isDemoUser();
892     }
893 
getDeviceOwnerComponent(Context context)894     public static ComponentName getDeviceOwnerComponent(Context context) {
895         final DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
896                 Context.DEVICE_POLICY_SERVICE);
897         return dpm.getDeviceOwnerComponentOnAnyUser();
898     }
899 
900     /**
901      * Returns if a given user is a profile of another user.
902      * @param user The user whose profiles wibe checked.
903      * @param profile The (potential) profile.
904      * @return if the profile is actually a profile
905      */
isProfileOf(UserInfo user, UserInfo profile)906     public static boolean isProfileOf(UserInfo user, UserInfo profile) {
907         return user.id == profile.id ||
908                 (user.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID
909                         && user.profileGroupId == profile.profileGroupId);
910     }
911 
912     /**
913      * Tries to initalize a volume with the given bundle. If it is a valid, private, and readable
914      * {@link VolumeInfo}, it is returned. If it is not valid, null is returned.
915      */
916     @Nullable
maybeInitializeVolume(StorageManager sm, Bundle bundle)917     public static VolumeInfo maybeInitializeVolume(StorageManager sm, Bundle bundle) {
918         final String volumeId = bundle.getString(VolumeInfo.EXTRA_VOLUME_ID,
919                 VolumeInfo.ID_PRIVATE_INTERNAL);
920         final VolumeInfo volume = sm.findVolumeById(volumeId);
921         return isVolumeValid(volume) ? volume : null;
922     }
923 
924     /**
925      * Return {@code true} if the supplied package is device owner or profile owner of at
926      * least one user.
927      * @param userManager used to get profile owner app for each user
928      * @param devicePolicyManager used to check whether it is device owner app
929      * @param packageName package to check about
930      */
isProfileOrDeviceOwner(UserManager userManager, DevicePolicyManager devicePolicyManager, String packageName)931     public static boolean isProfileOrDeviceOwner(UserManager userManager,
932             DevicePolicyManager devicePolicyManager, String packageName) {
933         final List<UserInfo> userInfos = userManager.getUsers();
934         if (devicePolicyManager.isDeviceOwnerAppOnAnyUser(packageName)) {
935             return true;
936         }
937         for (int i = 0, size = userInfos.size(); i < size; i++) {
938             final ComponentName cn = devicePolicyManager
939                     .getProfileOwnerAsUser(userInfos.get(i).id);
940             if (cn != null && cn.getPackageName().equals(packageName)) {
941                 return true;
942             }
943         }
944         return false;
945     }
946 
947     /**
948      * Return {@code true} if the supplied package is the device owner or profile owner of a
949      * given user.
950      *
951      * @param devicePolicyManager used to check whether it is device owner and profile owner app
952      * @param packageName         package to check about
953      * @param userId              the if of the relevant user
954      */
isProfileOrDeviceOwner(DevicePolicyManager devicePolicyManager, String packageName, int userId)955     public static boolean isProfileOrDeviceOwner(DevicePolicyManager devicePolicyManager,
956             String packageName, int userId) {
957         if ((devicePolicyManager.getDeviceOwnerUserId() == userId)
958                 && devicePolicyManager.isDeviceOwnerApp(packageName)) {
959             return true;
960         }
961         final ComponentName cn = devicePolicyManager.getProfileOwnerAsUser(userId);
962         if (cn != null && cn.getPackageName().equals(packageName)) {
963             return true;
964         }
965         return false;
966     }
967 
968     /**
969      * Return the resource id to represent the install status for an app
970      */
971     @StringRes
getInstallationStatus(ApplicationInfo info)972     public static int getInstallationStatus(ApplicationInfo info) {
973         if ((info.flags & ApplicationInfo.FLAG_INSTALLED) == 0) {
974             return R.string.not_installed;
975         }
976         return info.enabled ? R.string.installed : R.string.disabled;
977     }
978 
isVolumeValid(VolumeInfo volume)979     private static boolean isVolumeValid(VolumeInfo volume) {
980         return (volume != null) && (volume.getType() == VolumeInfo.TYPE_PRIVATE)
981                 && volume.isMountedReadable();
982     }
983 
setEditTextCursorPosition(EditText editText)984     public static void setEditTextCursorPosition(EditText editText) {
985         editText.setSelection(editText.getText().length());
986     }
987 
988     /**
989      * Gets the adaptive icon with a drawable that wrapped with an adaptive background using {@code
990      * backgroundColor} if it is not a {@link AdaptiveIconDrawable}
991      *
992      * If the given {@code icon} is too big, it will be auto scaled down to to avoid crashing
993      * Settings.
994      */
getAdaptiveIcon(Context context, Drawable icon, @ColorInt int backgroundColor)995     public static Drawable getAdaptiveIcon(Context context, Drawable icon,
996             @ColorInt int backgroundColor) {
997         Drawable adaptiveIcon = getSafeIcon(icon);
998 
999         if (!(adaptiveIcon instanceof AdaptiveIconDrawable)) {
1000             adaptiveIcon = new AdaptiveIcon(context, adaptiveIcon);
1001             ((AdaptiveIcon) adaptiveIcon).setBackgroundColor(backgroundColor);
1002         }
1003 
1004         return adaptiveIcon;
1005     }
1006 
1007     /**
1008      * Gets the icon with a drawable that is scaled down to to avoid crashing Settings if it's too
1009      * big and not a {@link VectorDrawable}.
1010      */
getSafeIcon(Drawable icon)1011     public static Drawable getSafeIcon(Drawable icon) {
1012         Drawable safeIcon = icon;
1013 
1014         if ((icon != null) && !(icon instanceof VectorDrawable)) {
1015             safeIcon = getSafeDrawable(icon,
1016                     /* MAX_DRAWABLE_SIZE */ 600, /* MAX_DRAWABLE_SIZE */ 600);
1017         }
1018 
1019         return safeIcon;
1020     }
1021 
1022     /**
1023      * Gets a drawable with a limited size to avoid crashing Settings if it's too big.
1024      *
1025      * @param original original drawable, typically an app icon.
1026      * @param maxWidth maximum width, in pixels.
1027      * @param maxHeight maximum height, in pixels.
1028      */
getSafeDrawable(Drawable original, int maxWidth, int maxHeight)1029     private static Drawable getSafeDrawable(Drawable original, int maxWidth, int maxHeight) {
1030         final int actualWidth = original.getMinimumWidth();
1031         final int actualHeight = original.getMinimumHeight();
1032 
1033         if (actualWidth <= maxWidth && actualHeight <= maxHeight) {
1034             return original;
1035         }
1036 
1037         final float scaleWidth = ((float) maxWidth) / actualWidth;
1038         final float scaleHeight = ((float) maxHeight) / actualHeight;
1039         final float scale = Math.min(scaleWidth, scaleHeight);
1040         final int width = (int) (actualWidth * scale);
1041         final int height = (int) (actualHeight * scale);
1042 
1043         final Bitmap bitmap;
1044         if (original instanceof BitmapDrawable) {
1045             bitmap = Bitmap.createScaledBitmap(((BitmapDrawable) original).getBitmap(), width,
1046                     height, false);
1047         } else {
1048             bitmap = createBitmap(original, width, height);
1049         }
1050         return new BitmapDrawable(null, bitmap);
1051     }
1052 
1053     /**
1054      * Create an Icon pointing to a drawable.
1055      */
createIconWithDrawable(Drawable drawable)1056     public static IconCompat createIconWithDrawable(Drawable drawable) {
1057         Bitmap bitmap;
1058         if (drawable instanceof BitmapDrawable) {
1059             bitmap = ((BitmapDrawable)drawable).getBitmap();
1060         } else {
1061             final int width = drawable.getIntrinsicWidth();
1062             final int height = drawable.getIntrinsicHeight();
1063             bitmap = createBitmap(drawable,
1064                     width > 0 ? width : 1,
1065                     height > 0 ? height : 1);
1066         }
1067         return IconCompat.createWithBitmap(bitmap);
1068     }
1069 
1070     /**
1071      * Creates a drawable with specified width and height.
1072      */
createBitmap(Drawable drawable, int width, int height)1073     public static Bitmap createBitmap(Drawable drawable, int width, int height) {
1074         final Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
1075         final Canvas canvas = new Canvas(bitmap);
1076         drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
1077         drawable.draw(canvas);
1078         return bitmap;
1079     }
1080 
1081     /**
1082      * Get the {@link Drawable} that represents the app icon
1083      */
getBadgedIcon(IconDrawableFactory iconDrawableFactory, PackageManager packageManager, String packageName, int userId)1084     public static Drawable getBadgedIcon(IconDrawableFactory iconDrawableFactory,
1085             PackageManager packageManager, String packageName, int userId) {
1086         try {
1087             final ApplicationInfo appInfo = packageManager.getApplicationInfoAsUser(
1088                     packageName, PackageManager.GET_META_DATA, userId);
1089             return iconDrawableFactory.getBadgedIcon(appInfo, userId);
1090         } catch (PackageManager.NameNotFoundException e) {
1091             return packageManager.getDefaultActivityIcon();
1092         }
1093     }
1094 
1095     /** Returns true if the current package is installed & enabled. */
isPackageEnabled(Context context, String packageName)1096     public static boolean isPackageEnabled(Context context, String packageName) {
1097         try {
1098             return context.getPackageManager().getApplicationInfo(packageName, 0).enabled;
1099         } catch (Exception e) {
1100             Log.e(TAG, "Error while retrieving application info for package " + packageName, e);
1101         }
1102         return false;
1103     }
1104 
1105     /** Get {@link Resources} by subscription id if subscription id is valid. */
getResourcesForSubId(Context context, int subId)1106     public static Resources getResourcesForSubId(Context context, int subId) {
1107         if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
1108             return SubscriptionManager.getResourcesForSubId(context, subId);
1109         } else {
1110             return context.getResources();
1111         }
1112     }
1113 
1114     /**
1115      * Returns true if SYSTEM_ALERT_WINDOW permission is available.
1116      * Starting from Q, SYSTEM_ALERT_WINDOW is disabled on low ram phones.
1117      */
isSystemAlertWindowEnabled(Context context)1118     public static boolean isSystemAlertWindowEnabled(Context context) {
1119         // SYSTEM_ALERT_WINDOW is disabled on on low ram devices starting from Q
1120         ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
1121         return !(am.isLowRamDevice() && (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q));
1122     }
1123 
1124     /**
1125      * Adds a shadow appear/disappear animation to action bar scroll.
1126      *
1127      * <p/>
1128      * This method must be called after {@link Fragment#onCreate(Bundle)}.
1129      */
setActionBarShadowAnimation(Activity activity, Lifecycle lifecycle, View scrollView)1130     public static void setActionBarShadowAnimation(Activity activity, Lifecycle lifecycle,
1131             View scrollView) {
1132         if (activity == null) {
1133             Log.w(TAG, "No activity, cannot style actionbar.");
1134             return;
1135         }
1136         final ActionBar actionBar = activity.getActionBar();
1137         if (actionBar == null) {
1138             Log.w(TAG, "No actionbar, cannot style actionbar.");
1139             return;
1140         }
1141         actionBar.setElevation(0);
1142 
1143         if (lifecycle != null && scrollView != null) {
1144             ActionBarShadowController.attachToView(activity, lifecycle, scrollView);
1145         }
1146     }
1147 
1148     /**
1149      * Return correct target fragment based on argument
1150      *
1151      * @param activity     the activity target fragment will be launched.
1152      * @param fragmentName initial target fragment name.
1153      * @param args         fragment launch arguments.
1154      */
getTargetFragment(Activity activity, String fragmentName, Bundle args)1155     public static Fragment getTargetFragment(Activity activity, String fragmentName, Bundle args) {
1156         Fragment f = null;
1157         final boolean isPersonal = args != null ? args.getInt(ProfileSelectFragment.EXTRA_PROFILE)
1158                 == ProfileSelectFragment.ProfileType.PERSONAL : false;
1159         final boolean isWork = args != null ? args.getInt(ProfileSelectFragment.EXTRA_PROFILE)
1160                 == ProfileSelectFragment.ProfileType.WORK : false;
1161         try {
1162             if (activity.getSystemService(UserManager.class).getUserProfiles().size() > 1
1163                     && ProfileFragmentBridge.FRAGMENT_MAP.get(fragmentName) != null
1164                     && !isWork && !isPersonal) {
1165                 f = Fragment.instantiate(activity,
1166                         ProfileFragmentBridge.FRAGMENT_MAP.get(fragmentName), args);
1167             } else {
1168                 f = Fragment.instantiate(activity, fragmentName, args);
1169             }
1170         } catch (Exception e) {
1171             Log.e(TAG, "Unable to get target fragment", e);
1172         }
1173         return f;
1174     }
1175 
1176     /**
1177      * Returns true if current binder uid is Settings Intelligence.
1178      */
isSettingsIntelligence(Context context)1179     public static boolean isSettingsIntelligence(Context context) {
1180         final int callingUid = Binder.getCallingUid();
1181         final String callingPackage = context.getPackageManager().getPackagesForUid(callingUid)[0];
1182         final boolean isSettingsIntelligence = TextUtils.equals(callingPackage,
1183                 context.getString(R.string.config_settingsintelligence_package_name));
1184         return isSettingsIntelligence;
1185     }
1186 
1187     /**
1188      * Returns true if the night mode is enabled.
1189      */
isNightMode(Context context)1190     public static boolean isNightMode(Context context) {
1191         final int currentNightMode =
1192                 context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
1193         return currentNightMode == Configuration.UI_MODE_NIGHT_YES;
1194     }
1195 
1196     /**
1197      * Returns a bitmap with rounded corner.
1198      *
1199      * @param context application context.
1200      * @param source bitmap to apply round corner.
1201      * @param cornerRadius corner radius value.
1202      */
convertCornerRadiusBitmap(@onNull Context context, @NonNull Bitmap source, @NonNull float cornerRadius)1203     public static Bitmap convertCornerRadiusBitmap(@NonNull Context context,
1204             @NonNull Bitmap source, @NonNull float cornerRadius) {
1205         final Bitmap roundedBitmap = Bitmap.createBitmap(source.getWidth(), source.getHeight(),
1206                 Bitmap.Config.ARGB_8888);
1207         final RoundedBitmapDrawable drawable =
1208                 RoundedBitmapDrawableFactory.create(context.getResources(), source);
1209         drawable.setAntiAlias(true);
1210         drawable.setCornerRadius(cornerRadius);
1211         final Canvas canvas = new Canvas(roundedBitmap);
1212         drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
1213         drawable.draw(canvas);
1214         return roundedBitmap;
1215     }
1216 
1217     /**
1218      * Returns the color of homepage preference icons.
1219      */
1220     @ColorInt
getHomepageIconColor(Context context)1221     public static int getHomepageIconColor(Context context) {
1222         return getColorAttrDefaultColor(context, android.R.attr.textColorPrimary);
1223     }
1224 
1225     /**
1226      * Returns the highlight color of homepage preference icons.
1227      */
1228     @ColorInt
getHomepageIconColorHighlight(Context context)1229     public static int getHomepageIconColorHighlight(Context context) {
1230         return context.getColor(R.color.accent_select_primary_text);
1231     }
1232 
1233     /**
1234      * Returns if dreams are available to the current user.
1235      */
areDreamsAvailableToCurrentUser(Context context)1236     public static boolean areDreamsAvailableToCurrentUser(Context context) {
1237         if (!context.getResources().getBoolean(
1238                 com.android.internal.R.bool.config_dreamsSupported)) {
1239             return false;
1240         }
1241 
1242         if (!context.getResources().getBoolean(
1243                 com.android.internal.R.bool.config_dreamsOnlyEnabledForDockUser)) {
1244             return true;
1245         }
1246 
1247         final UserManager userManager = context.getSystemService(UserManager.class);
1248         return userManager != null && userManager.isSystemUser();
1249     }
1250 }
1251