• 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.FeatureFlagUtils;
89 import android.util.IconDrawableFactory;
90 import android.util.Log;
91 import android.view.LayoutInflater;
92 import android.view.View;
93 import android.view.ViewGroup;
94 import android.widget.EditText;
95 import android.widget.ListView;
96 import android.widget.TabWidget;
97 
98 import androidx.annotation.ColorInt;
99 import androidx.annotation.NonNull;
100 import androidx.annotation.StringRes;
101 import androidx.core.graphics.drawable.IconCompat;
102 import androidx.core.graphics.drawable.RoundedBitmapDrawable;
103 import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
104 import androidx.fragment.app.Fragment;
105 import androidx.lifecycle.Lifecycle;
106 import androidx.preference.Preference;
107 import androidx.preference.PreferenceGroup;
108 
109 import com.android.internal.app.UnlaunchableAppActivity;
110 import com.android.internal.util.ArrayUtils;
111 import com.android.internal.widget.LockPatternUtils;
112 import com.android.settings.dashboard.profileselector.ProfileFragmentBridge;
113 import com.android.settings.dashboard.profileselector.ProfileSelectFragment;
114 import com.android.settings.password.ChooseLockSettingsHelper;
115 import com.android.settingslib.widget.ActionBarShadowController;
116 import com.android.settingslib.widget.AdaptiveIcon;
117 
118 import java.util.Iterator;
119 import java.util.List;
120 import java.util.Locale;
121 
122 public final class Utils extends com.android.settingslib.Utils {
123 
124     private static final String TAG = "Settings";
125 
126     public static final String FILE_PROVIDER_AUTHORITY = "com.android.settings.files";
127 
128     /**
129      * Set the preference's title to the matching activity's label.
130      */
131     public static final int UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY = 1;
132 
133     public static final String SETTINGS_PACKAGE_NAME = "com.android.settings";
134 
135     public static final String OS_PKG = "os";
136 
137     /**
138      * Whether to disable the new device identifier access restrictions.
139      */
140     public static final String PROPERTY_DEVICE_IDENTIFIER_ACCESS_RESTRICTIONS_DISABLED =
141             "device_identifier_access_restrictions_disabled";
142 
143     /**
144      * Whether to show the Permissions Hub.
145      */
146     public static final String PROPERTY_PERMISSIONS_HUB_ENABLED = "permissions_hub_enabled";
147 
148     /**
149      * Whether to show location indicators.
150      */
151     public static final String PROPERTY_LOCATION_INDICATORS_ENABLED = "location_indicators_enabled";
152 
153     /**
154      * Whether to show location indicator settings in developer options.
155      */
156     public static final String PROPERTY_LOCATION_INDICATOR_SETTINGS_ENABLED =
157             "location_indicator_settings_enabled";
158 
159     /** Whether or not app hibernation is enabled on the device **/
160     public static final String PROPERTY_APP_HIBERNATION_ENABLED = "app_hibernation_enabled";
161 
162     /** Whether or not app hibernation targets apps that target a pre-S SDK **/
163     public static final String PROPERTY_HIBERNATION_TARGETS_PRE_S_APPS =
164             "app_hibernation_targets_pre_s_apps";
165 
166     /**
167      * Finds a matching activity for a preference's intent. If a matching
168      * activity is not found, it will remove the preference.
169      *
170      * @param context The context.
171      * @param parentPreferenceGroup The preference group that contains the
172      *            preference whose intent is being resolved.
173      * @param preferenceKey The key of the preference whose intent is being
174      *            resolved.
175      * @param flags 0 or one or more of
176      *            {@link #UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY}
177      *            .
178      * @return Whether an activity was found. If false, the preference was
179      *         removed.
180      */
updatePreferenceToSpecificActivityOrRemove(Context context, PreferenceGroup parentPreferenceGroup, String preferenceKey, int flags)181     public static boolean updatePreferenceToSpecificActivityOrRemove(Context context,
182             PreferenceGroup parentPreferenceGroup, String preferenceKey, int flags) {
183 
184         final Preference preference = parentPreferenceGroup.findPreference(preferenceKey);
185         if (preference == null) {
186             return false;
187         }
188 
189         final Intent intent = preference.getIntent();
190         if (intent != null) {
191             // Find the activity that is in the system image
192             final PackageManager pm = context.getPackageManager();
193             final List<ResolveInfo> list = pm.queryIntentActivities(intent, 0);
194             final int listSize = list.size();
195             for (int i = 0; i < listSize; i++) {
196                 final ResolveInfo resolveInfo = list.get(i);
197                 if ((resolveInfo.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM)
198                         != 0) {
199 
200                     // Replace the intent with this specific activity
201                     preference.setIntent(new Intent().setClassName(
202                             resolveInfo.activityInfo.packageName,
203                             resolveInfo.activityInfo.name));
204 
205                     if ((flags & UPDATE_PREFERENCE_FLAG_SET_TITLE_TO_MATCHING_ACTIVITY) != 0) {
206                         // Set the preference title to the activity's label
207                         preference.setTitle(resolveInfo.loadLabel(pm));
208                     }
209 
210                     return true;
211                 }
212             }
213         }
214 
215         // Did not find a matching activity, so remove the preference
216         parentPreferenceGroup.removePreference(preference);
217 
218         return false;
219     }
220 
221     /**
222      * Returns true if Monkey is running.
223      */
isMonkeyRunning()224     public static boolean isMonkeyRunning() {
225         return ActivityManager.isUserAMonkey();
226     }
227 
228     /**
229      * Returns whether the device is voice-capable (meaning, it is also a phone).
230      */
isVoiceCapable(Context context)231     public static boolean isVoiceCapable(Context context) {
232         final TelephonyManager telephony =
233                 (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
234         return telephony != null && telephony.isVoiceCapable();
235     }
236 
237     /**
238      * Returns the WIFI IP Addresses, if any, taking into account IPv4 and IPv6 style addresses.
239      * @param context the application context
240      * @return the formatted and newline-separated IP addresses, or null if none.
241      */
getWifiIpAddresses(Context context)242     public static String getWifiIpAddresses(Context context) {
243         final WifiManager wifiManager = context.getSystemService(WifiManager.class);
244         final Network currentNetwork = wifiManager.getCurrentNetwork();
245         if (currentNetwork != null) {
246             final ConnectivityManager cm = (ConnectivityManager)
247                 context.getSystemService(Context.CONNECTIVITY_SERVICE);
248             final LinkProperties prop = cm.getLinkProperties(currentNetwork);
249             return formatIpAddresses(prop);
250         }
251         return null;
252     }
253 
formatIpAddresses(LinkProperties prop)254     private static String formatIpAddresses(LinkProperties prop) {
255         if (prop == null) return null;
256         final Iterator<LinkAddress> iter = prop.getAllLinkAddresses().iterator();
257         // If there are no entries, return null
258         if (!iter.hasNext()) return null;
259         // Concatenate all available addresses, comma separated
260         String addresses = "";
261         while (iter.hasNext()) {
262             addresses += iter.next().getAddress().getHostAddress();
263             if (iter.hasNext()) addresses += "\n";
264         }
265         return addresses;
266     }
267 
createLocaleFromString(String localeStr)268     public static Locale createLocaleFromString(String localeStr) {
269         // TODO: is there a better way to actually construct a locale that will match?
270         // The main problem is, on top of Java specs, locale.toString() and
271         // new Locale(locale.toString()).toString() do not return equal() strings in
272         // many cases, because the constructor takes the only string as the language
273         // code. So : new Locale("en", "US").toString() => "en_US"
274         // And : new Locale("en_US").toString() => "en_us"
275         if (null == localeStr)
276             return Locale.getDefault();
277         final String[] brokenDownLocale = localeStr.split("_", 3);
278         // split may not return a 0-length array.
279         if (1 == brokenDownLocale.length) {
280             return new Locale(brokenDownLocale[0]);
281         } else if (2 == brokenDownLocale.length) {
282             return new Locale(brokenDownLocale[0], brokenDownLocale[1]);
283         } else {
284             return new Locale(brokenDownLocale[0], brokenDownLocale[1], brokenDownLocale[2]);
285         }
286     }
287 
isBatteryPresent(Intent batteryChangedIntent)288     public static boolean isBatteryPresent(Intent batteryChangedIntent) {
289         return batteryChangedIntent.getBooleanExtra(BatteryManager.EXTRA_PRESENT, true);
290     }
291 
292     /**
293      * Return true if battery is present.
294      */
isBatteryPresent(Context context)295     public static boolean isBatteryPresent(Context context) {
296         Intent batteryBroadcast = context.registerReceiver(null /* receiver */,
297                 new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
298         return isBatteryPresent(batteryBroadcast);
299     }
300 
getBatteryPercentage(Intent batteryChangedIntent)301     public static String getBatteryPercentage(Intent batteryChangedIntent) {
302         return formatPercentage(getBatteryLevel(batteryChangedIntent));
303     }
304 
305     /**
306      * Prepare a custom preferences layout, moving padding to {@link ListView}
307      * when outside scrollbars are requested. Usually used to display
308      * {@link ListView} and {@link TabWidget} with correct padding.
309      */
prepareCustomPreferencesList( ViewGroup parent, View child, View list, boolean ignoreSidePadding)310     public static void prepareCustomPreferencesList(
311             ViewGroup parent, View child, View list, boolean ignoreSidePadding) {
312         final boolean movePadding = list.getScrollBarStyle() == View.SCROLLBARS_OUTSIDE_OVERLAY;
313         if (movePadding) {
314             final Resources res = list.getResources();
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             list.setPaddingRelative(0 /* start */, 0 /* top */, 0 /* end */, paddingBottom);
322         }
323     }
324 
forceCustomPadding(View view, boolean additive)325     public static void forceCustomPadding(View view, boolean additive) {
326         final Resources res = view.getResources();
327 
328         final int paddingStart = additive ? view.getPaddingStart() : 0;
329         final int paddingEnd = additive ? view.getPaddingEnd() : 0;
330         final int paddingBottom = res.getDimensionPixelSize(
331                 com.android.internal.R.dimen.preference_fragment_padding_bottom);
332 
333         view.setPaddingRelative(paddingStart, 0, paddingEnd, paddingBottom);
334     }
335 
getMeProfileName(Context context, boolean full)336     public static String getMeProfileName(Context context, boolean full) {
337         if (full) {
338             return getProfileDisplayName(context);
339         } else {
340             return getShorterNameIfPossible(context);
341         }
342     }
343 
getShorterNameIfPossible(Context context)344     private static String getShorterNameIfPossible(Context context) {
345         final String given = getLocalProfileGivenName(context);
346         return !TextUtils.isEmpty(given) ? given : getProfileDisplayName(context);
347     }
348 
getLocalProfileGivenName(Context context)349     private static String getLocalProfileGivenName(Context context) {
350         final ContentResolver cr = context.getContentResolver();
351 
352         // Find the raw contact ID for the local ME profile raw contact.
353         final long localRowProfileId;
354         final Cursor localRawProfile = cr.query(
355                 Profile.CONTENT_RAW_CONTACTS_URI,
356                 new String[] {RawContacts._ID},
357                 RawContacts.ACCOUNT_TYPE + " IS NULL AND " +
358                         RawContacts.ACCOUNT_NAME + " IS NULL",
359                 null, null);
360         if (localRawProfile == null) return null;
361 
362         try {
363             if (!localRawProfile.moveToFirst()) {
364                 return null;
365             }
366             localRowProfileId = localRawProfile.getLong(0);
367         } finally {
368             localRawProfile.close();
369         }
370 
371         // Find the structured name for the raw contact.
372         final Cursor structuredName = cr.query(
373                 Profile.CONTENT_URI.buildUpon().appendPath(Contacts.Data.CONTENT_DIRECTORY).build(),
374                 new String[] {CommonDataKinds.StructuredName.GIVEN_NAME,
375                     CommonDataKinds.StructuredName.FAMILY_NAME},
376                 Data.RAW_CONTACT_ID + "=" + localRowProfileId,
377                 null, null);
378         if (structuredName == null) return null;
379 
380         try {
381             if (!structuredName.moveToFirst()) {
382                 return null;
383             }
384             String partialName = structuredName.getString(0);
385             if (TextUtils.isEmpty(partialName)) {
386                 partialName = structuredName.getString(1);
387             }
388             return partialName;
389         } finally {
390             structuredName.close();
391         }
392     }
393 
getProfileDisplayName(Context context)394     private static final String getProfileDisplayName(Context context) {
395         final ContentResolver cr = context.getContentResolver();
396         final Cursor profile = cr.query(Profile.CONTENT_URI,
397                 new String[] {Profile.DISPLAY_NAME}, null, null, null);
398         if (profile == null) return null;
399 
400         try {
401             if (!profile.moveToFirst()) {
402                 return null;
403             }
404             return profile.getString(0);
405         } finally {
406             profile.close();
407         }
408     }
409 
hasMultipleUsers(Context context)410     public static boolean hasMultipleUsers(Context context) {
411         return context.getSystemService(UserManager.class)
412                 .getUsers().size() > 1;
413     }
414 
415     /**
416      * Returns the managed profile of the current user or {@code null} if none is found or a profile
417      * exists but it is disabled.
418      */
getManagedProfile(UserManager userManager)419     public static UserHandle getManagedProfile(UserManager userManager) {
420         final List<UserHandle> userProfiles = userManager.getUserProfiles();
421         for (UserHandle profile : userProfiles) {
422             if (profile.getIdentifier() == userManager.getUserHandle()) {
423                 continue;
424             }
425             final UserInfo userInfo = userManager.getUserInfo(profile.getIdentifier());
426             if (userInfo.isManagedProfile()) {
427                 return profile;
428             }
429         }
430         return null;
431     }
432 
433     /**
434      * Returns the managed profile of the current user or {@code null} if none is found. Unlike
435      * {@link #getManagedProfile} this method returns enabled and disabled managed profiles.
436      */
getManagedProfileWithDisabled(UserManager userManager)437     public static UserHandle getManagedProfileWithDisabled(UserManager userManager) {
438         // TODO: Call getManagedProfileId from here once Robolectric supports
439         // API level 24 and UserManager.getProfileIdsWithDisabled can be Mocked (to avoid having
440         // yet another implementation that loops over user profiles in this method). In the meantime
441         // we need to use UserManager.getProfiles that is available on API 23 (the one currently
442         // used for Settings Robolectric tests).
443         final int myUserId = UserHandle.myUserId();
444         final List<UserInfo> profiles = userManager.getProfiles(myUserId);
445         final int count = profiles.size();
446         for (int i = 0; i < count; i++) {
447             final UserInfo profile = profiles.get(i);
448             if (profile.isManagedProfile()
449                     && profile.getUserHandle().getIdentifier() != myUserId) {
450                 return profile.getUserHandle();
451             }
452         }
453         return null;
454     }
455 
456     /**
457      * Retrieves the id for the given user's managed profile.
458      *
459      * @return the managed profile id or UserHandle.USER_NULL if there is none.
460      */
getManagedProfileId(UserManager um, int parentUserId)461     public static int getManagedProfileId(UserManager um, int parentUserId) {
462         final int[] profileIds = um.getProfileIdsWithDisabled(parentUserId);
463         for (int profileId : profileIds) {
464             if (profileId != parentUserId) {
465                 return profileId;
466             }
467         }
468         return UserHandle.USER_NULL;
469     }
470 
471     /** Returns user ID of current user, throws IllegalStateException if it's not available. */
getCurrentUserId(UserManager userManager, boolean isWorkProfile)472     public static int getCurrentUserId(UserManager userManager, boolean isWorkProfile)
473             throws IllegalStateException {
474         if (isWorkProfile) {
475             final UserHandle managedUserHandle = getManagedProfile(userManager);
476             if (managedUserHandle == null) {
477                 throw new IllegalStateException("Work profile user ID is not available.");
478             }
479             return managedUserHandle.getIdentifier();
480         }
481         return UserHandle.myUserId();
482     }
483 
484     /**
485      * Returns the target user for a Settings activity.
486      * <p>
487      * User would be retrieved in this order:
488      * <ul>
489      * <li> If this activity is launched from other user, return that user id.
490      * <li> If this is launched from the Settings app in same user, return the user contained as an
491      *      extra in the arguments or intent extras.
492      * <li> Otherwise, return UserHandle.myUserId().
493      * </ul>
494      * <p>
495      * Note: This is secure in the sense that it only returns a target user different to the current
496      * one if the app launching this activity is the Settings app itself, running in the same user
497      * or in one that is in the same profile group, or if the user id is provided by the system.
498      */
getSecureTargetUser(IBinder activityToken, UserManager um, @Nullable Bundle arguments, @Nullable Bundle intentExtras)499     public static UserHandle getSecureTargetUser(IBinder activityToken,
500             UserManager um, @Nullable Bundle arguments, @Nullable Bundle intentExtras) {
501         final UserHandle currentUser = new UserHandle(UserHandle.myUserId());
502         final IActivityManager am = ActivityManager.getService();
503         try {
504             final String launchedFromPackage = am.getLaunchedFromPackage(activityToken);
505             final boolean launchedFromSettingsApp =
506                     SETTINGS_PACKAGE_NAME.equals(launchedFromPackage);
507 
508             final UserHandle launchedFromUser = new UserHandle(UserHandle.getUserId(
509                     am.getLaunchedFromUid(activityToken)));
510             if (launchedFromUser != null && !launchedFromUser.equals(currentUser)) {
511                 // Check it's secure
512                 if (isProfileOf(um, launchedFromUser)) {
513                     return launchedFromUser;
514                 }
515             }
516             final UserHandle extrasUser = getUserHandleFromBundle(intentExtras);
517             if (extrasUser != null && !extrasUser.equals(currentUser)) {
518                 // Check it's secure
519                 if (launchedFromSettingsApp && isProfileOf(um, extrasUser)) {
520                     return extrasUser;
521                 }
522             }
523             final UserHandle argumentsUser = getUserHandleFromBundle(arguments);
524             if (argumentsUser != null && !argumentsUser.equals(currentUser)) {
525                 // Check it's secure
526                 if (launchedFromSettingsApp && isProfileOf(um, argumentsUser)) {
527                     return argumentsUser;
528                 }
529             }
530         } catch (RemoteException e) {
531             // Should not happen
532             Log.v(TAG, "Could not talk to activity manager.", e);
533         }
534         return currentUser;
535     }
536 
537     /**
538      * Lookup both {@link Intent#EXTRA_USER} and {@link Intent#EXTRA_USER_ID} in the bundle
539      * and return the {@link UserHandle} object. Return {@code null} if nothing is found.
540      */
getUserHandleFromBundle(Bundle bundle)541     private static @Nullable UserHandle getUserHandleFromBundle(Bundle bundle) {
542         if (bundle == null) {
543             return null;
544         }
545         final UserHandle user = bundle.getParcelable(EXTRA_USER);
546         if (user != null) {
547             return user;
548         }
549         final int userId = bundle.getInt(EXTRA_USER_ID, -1);
550         if (userId != -1) {
551             return UserHandle.of(userId);
552         }
553         return null;
554     }
555 
556    /**
557     * Returns true if the user provided is in the same profiles group as the current user.
558     */
isProfileOf(UserManager um, UserHandle otherUser)559    private static boolean isProfileOf(UserManager um, UserHandle otherUser) {
560        if (um == null || otherUser == null) return false;
561        return (UserHandle.myUserId() == otherUser.getIdentifier())
562                || um.getUserProfiles().contains(otherUser);
563    }
564 
565     /**
566      * Queries for the UserInfo of a user. Returns null if the user doesn't exist (was removed).
567      * @param userManager Instance of UserManager
568      * @param checkUser The user to check the existence of.
569      * @return UserInfo of the user or null for non-existent user.
570      */
getExistingUser(UserManager userManager, UserHandle checkUser)571     public static UserInfo getExistingUser(UserManager userManager, UserHandle checkUser) {
572         final List<UserInfo> users = userManager.getAliveUsers();
573         final int checkUserId = checkUser.getIdentifier();
574         for (UserInfo user : users) {
575             if (user.id == checkUserId) {
576                 return user;
577             }
578         }
579         return null;
580     }
581 
inflateCategoryHeader(LayoutInflater inflater, ViewGroup parent)582     public static View inflateCategoryHeader(LayoutInflater inflater, ViewGroup parent) {
583         final TypedArray a = inflater.getContext().obtainStyledAttributes(null,
584                 com.android.internal.R.styleable.Preference,
585                 com.android.internal.R.attr.preferenceCategoryStyle, 0);
586         final int resId = a.getResourceId(com.android.internal.R.styleable.Preference_layout,
587                 0);
588         a.recycle();
589         return inflater.inflate(resId, parent, false);
590     }
591 
getHandledDomains(PackageManager pm, String packageName)592     public static ArraySet<String> getHandledDomains(PackageManager pm, String packageName) {
593         final List<IntentFilterVerificationInfo> iviList =
594                 pm.getIntentFilterVerifications(packageName);
595         final List<IntentFilter> filters = pm.getAllIntentFilters(packageName);
596 
597         final ArraySet<String> result = new ArraySet<>();
598         if (iviList != null && iviList.size() > 0) {
599             for (IntentFilterVerificationInfo ivi : iviList) {
600                 for (String host : ivi.getDomains()) {
601                     result.add(host);
602                 }
603             }
604         }
605         if (filters != null && filters.size() > 0) {
606             for (IntentFilter filter : filters) {
607                 if (filter.hasCategory(Intent.CATEGORY_BROWSABLE)
608                         && (filter.hasDataScheme(IntentFilter.SCHEME_HTTP) ||
609                                 filter.hasDataScheme(IntentFilter.SCHEME_HTTPS))) {
610                     result.addAll(filter.getHostsList());
611                 }
612             }
613         }
614         return result;
615     }
616 
617     /**
618      * Returns the application info of the currently installed MDM package.
619      */
getAdminApplicationInfo(Context context, int profileId)620     public static ApplicationInfo getAdminApplicationInfo(Context context, int profileId) {
621         final DevicePolicyManager dpm =
622                 (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
623         final ComponentName mdmPackage = dpm.getProfileOwnerAsUser(profileId);
624         if (mdmPackage == null) {
625             return null;
626         }
627         final String mdmPackageName = mdmPackage.getPackageName();
628         try {
629             final IPackageManager ipm = AppGlobals.getPackageManager();
630             final ApplicationInfo mdmApplicationInfo =
631                     ipm.getApplicationInfo(mdmPackageName, 0, profileId);
632             return mdmApplicationInfo;
633         } catch (RemoteException e) {
634             Log.e(TAG, "Error while retrieving application info for package " + mdmPackageName
635                     + ", userId " + profileId, e);
636             return null;
637         }
638     }
639 
isBandwidthControlEnabled()640     public static boolean isBandwidthControlEnabled() {
641         final INetworkManagementService netManager = INetworkManagementService.Stub
642                 .asInterface(ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
643         try {
644             return netManager.isBandwidthControlEnabled();
645         } catch (RemoteException e) {
646             return false;
647         }
648     }
649 
650     /**
651      * Returns an accessible SpannableString.
652      * @param displayText the text to display
653      * @param accessibileText the text text-to-speech engines should read
654      */
createAccessibleSequence(CharSequence displayText, String accessibileText)655     public static SpannableString createAccessibleSequence(CharSequence displayText,
656             String accessibileText) {
657         final SpannableString str = new SpannableString(displayText);
658         str.setSpan(new TtsSpan.TextBuilder(accessibileText).build(), 0,
659                 displayText.length(),
660                 Spannable.SPAN_INCLUSIVE_INCLUSIVE);
661         return str;
662     }
663 
664     /**
665      * Returns the user id present in the bundle with
666      * {@link Intent#EXTRA_USER_ID} if it belongs to the current user.
667      *
668      * @throws SecurityException if the given userId does not belong to the
669      *             current user group.
670      */
getUserIdFromBundle(Context context, Bundle bundle)671     public static int getUserIdFromBundle(Context context, Bundle bundle) {
672         return getUserIdFromBundle(context, bundle, false);
673     }
674 
675     /**
676      * Returns the user id present in the bundle with
677      * {@link Intent#EXTRA_USER_ID} if it belongs to the current user.
678      *
679      * @param isInternal indicating if the caller is "internal" to the system,
680      *            meaning we're willing to trust extras like
681      *            {@link ChooseLockSettingsHelper#EXTRA_KEY_ALLOW_ANY_USER}.
682      * @throws SecurityException if the given userId does not belong to the
683      *             current user group.
684      */
getUserIdFromBundle(Context context, Bundle bundle, boolean isInternal)685     public static int getUserIdFromBundle(Context context, Bundle bundle, boolean isInternal) {
686         if (bundle == null) {
687             return getCredentialOwnerUserId(context);
688         }
689         final boolean allowAnyUser = isInternal
690                 && bundle.getBoolean(ChooseLockSettingsHelper.EXTRA_KEY_ALLOW_ANY_USER, false);
691         final int userId = bundle.getInt(Intent.EXTRA_USER_ID, UserHandle.myUserId());
692         if (userId == LockPatternUtils.USER_FRP) {
693             return allowAnyUser ? userId : enforceSystemUser(context, userId);
694         } else {
695             return allowAnyUser ? userId : enforceSameOwner(context, userId);
696         }
697     }
698 
699     /**
700      * Returns the given user id if the current user is the system user.
701      *
702      * @throws SecurityException if the current user is not the system user.
703      */
enforceSystemUser(Context context, int userId)704     public static int enforceSystemUser(Context context, int userId) {
705         if (UserHandle.myUserId() == UserHandle.USER_SYSTEM) {
706             return userId;
707         }
708         throw new SecurityException("Given user id " + userId + " must only be used from "
709                 + "USER_SYSTEM, but current user is " + UserHandle.myUserId());
710     }
711 
712     /**
713      * Returns the given user id if it belongs to the current user.
714      *
715      * @throws SecurityException if the given userId does not belong to the current user group.
716      */
enforceSameOwner(Context context, int userId)717     public static int enforceSameOwner(Context context, int userId) {
718         final UserManager um = context.getSystemService(UserManager.class);
719         final int[] profileIds = um.getProfileIdsWithDisabled(UserHandle.myUserId());
720         if (ArrayUtils.contains(profileIds, userId)) {
721             return userId;
722         }
723         throw new SecurityException("Given user id " + userId + " does not belong to user "
724                 + UserHandle.myUserId());
725     }
726 
727     /**
728      * Returns the effective credential owner of the calling user.
729      */
getCredentialOwnerUserId(Context context)730     public static int getCredentialOwnerUserId(Context context) {
731         return getCredentialOwnerUserId(context, UserHandle.myUserId());
732     }
733 
734     /**
735      * Returns the user id of the credential owner of the given user id.
736      */
getCredentialOwnerUserId(Context context, int userId)737     public static int getCredentialOwnerUserId(Context context, int userId) {
738         final UserManager um = context.getSystemService(UserManager.class);
739         return um.getCredentialOwnerProfile(userId);
740     }
741 
742     /**
743      * Returns the credential type of the given user id.
744      */
getCredentialType(Context context, int userId)745     public static @LockPatternUtils.CredentialType int getCredentialType(Context context,
746             int userId) {
747         final LockPatternUtils lpu = new LockPatternUtils(context);
748         return lpu.getCredentialTypeForUser(userId);
749     }
750 
751     private static final StringBuilder sBuilder = new StringBuilder(50);
752     private static final java.util.Formatter sFormatter = new java.util.Formatter(
753             sBuilder, Locale.getDefault());
754 
formatDateRange(Context context, long start, long end)755     public static String formatDateRange(Context context, long start, long end) {
756         final int flags = FORMAT_SHOW_DATE | FORMAT_ABBREV_MONTH;
757 
758         synchronized (sBuilder) {
759             sBuilder.setLength(0);
760             return DateUtils.formatDateRange(context, sFormatter, start, end, flags, null)
761                     .toString();
762         }
763     }
764 
startQuietModeDialogIfNecessary(Context context, UserManager um, int userId)765     public static boolean startQuietModeDialogIfNecessary(Context context, UserManager um,
766             int userId) {
767         if (um.isQuietModeEnabled(UserHandle.of(userId))) {
768             final Intent intent = UnlaunchableAppActivity.createInQuietModeDialogIntent(userId);
769             context.startActivity(intent);
770             return true;
771         }
772         return false;
773     }
774 
unlockWorkProfileIfNecessary(Context context, int userId)775     public static boolean unlockWorkProfileIfNecessary(Context context, int userId) {
776         try {
777             if (!ActivityManager.getService().isUserRunning(userId,
778                     ActivityManager.FLAG_AND_LOCKED)) {
779                 return false;
780             }
781         } catch (RemoteException e) {
782             return false;
783         }
784         if (!(new LockPatternUtils(context)).isSecure(userId)) {
785             return false;
786         }
787         return confirmWorkProfileCredentials(context, userId);
788     }
789 
confirmWorkProfileCredentials(Context context, int userId)790     private static boolean confirmWorkProfileCredentials(Context context, int userId) {
791         final KeyguardManager km = (KeyguardManager) context.getSystemService(
792                 Context.KEYGUARD_SERVICE);
793         final Intent unlockIntent = km.createConfirmDeviceCredentialIntent(null, null, userId);
794         if (unlockIntent != null) {
795             context.startActivity(unlockIntent);
796             return true;
797         } else {
798             return false;
799         }
800     }
801 
getApplicationLabel(Context context, String packageName)802     public static CharSequence getApplicationLabel(Context context, String packageName) {
803         try {
804             final ApplicationInfo appInfo = context.getPackageManager().getApplicationInfo(
805                     packageName,
806                     PackageManager.MATCH_DISABLED_COMPONENTS
807                     | PackageManager.MATCH_ANY_USER);
808             return appInfo.loadLabel(context.getPackageManager());
809         } catch (PackageManager.NameNotFoundException e) {
810             Log.e(TAG, "Unable to find info for package: " + packageName);
811         }
812         return null;
813     }
814 
isPackageDirectBootAware(Context context, String packageName)815     public static boolean isPackageDirectBootAware(Context context, String packageName) {
816         try {
817             final ApplicationInfo ai = context.getPackageManager().getApplicationInfo(
818                     packageName, 0);
819             return ai.isDirectBootAware() || ai.isPartiallyDirectBootAware();
820         } catch (NameNotFoundException ignored) {
821         }
822         return false;
823     }
824 
825     /**
826      * Returns a context created from the given context for the given user, or null if it fails
827      */
createPackageContextAsUser(Context context, int userId)828     public static Context createPackageContextAsUser(Context context, int userId) {
829         try {
830             return context.createPackageContextAsUser(
831                     context.getPackageName(), 0 /* flags */, UserHandle.of(userId));
832         } catch (PackageManager.NameNotFoundException e) {
833             Log.e(TAG, "Failed to create user context", e);
834         }
835         return null;
836     }
837 
getFingerprintManagerOrNull(Context context)838     public static FingerprintManager getFingerprintManagerOrNull(Context context) {
839         if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
840             return (FingerprintManager) context.getSystemService(Context.FINGERPRINT_SERVICE);
841         } else {
842             return null;
843         }
844     }
845 
hasFingerprintHardware(Context context)846     public static boolean hasFingerprintHardware(Context context) {
847         final FingerprintManager fingerprintManager = getFingerprintManagerOrNull(context);
848         return fingerprintManager != null && fingerprintManager.isHardwareDetected();
849     }
850 
getFaceManagerOrNull(Context context)851     public static FaceManager getFaceManagerOrNull(Context context) {
852         if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FACE)) {
853             return (FaceManager) context.getSystemService(Context.FACE_SERVICE);
854         } else {
855             return null;
856         }
857     }
858 
hasFaceHardware(Context context)859     public static boolean hasFaceHardware(Context context) {
860         final FaceManager faceManager = getFaceManagerOrNull(context);
861         return faceManager != null && faceManager.isHardwareDetected();
862     }
863 
864     /**
865      * Return true if the device supports multiple biometrics authentications.
866      */
isMultipleBiometricsSupported(Context context)867     public static boolean isMultipleBiometricsSupported(Context context) {
868         return hasFingerprintHardware(context) && hasFaceHardware(context);
869     }
870 
871     /**
872      * Launches an intent which may optionally have a user id defined.
873      * @param fragment Fragment to use to launch the activity.
874      * @param intent Intent to launch.
875      */
launchIntent(Fragment fragment, Intent intent)876     public static void launchIntent(Fragment fragment, Intent intent) {
877         try {
878             final int userId = intent.getIntExtra(Intent.EXTRA_USER_ID, -1);
879 
880             if (userId == -1) {
881                 fragment.startActivity(intent);
882             } else {
883                 fragment.getActivity().startActivityAsUser(intent, new UserHandle(userId));
884             }
885         } catch (ActivityNotFoundException e) {
886             Log.w(TAG, "No activity found for " + intent);
887         }
888     }
889 
isDemoUser(Context context)890     public static boolean isDemoUser(Context context) {
891         return UserManager.isDeviceInDemoMode(context)
892                 && context.getSystemService(UserManager.class).isDemoUser();
893     }
894 
getDeviceOwnerComponent(Context context)895     public static ComponentName getDeviceOwnerComponent(Context context) {
896         final DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(
897                 Context.DEVICE_POLICY_SERVICE);
898         return dpm.getDeviceOwnerComponentOnAnyUser();
899     }
900 
901     /**
902      * Returns if a given user is a profile of another user.
903      * @param user The user whose profiles wibe checked.
904      * @param profile The (potential) profile.
905      * @return if the profile is actually a profile
906      */
isProfileOf(UserInfo user, UserInfo profile)907     public static boolean isProfileOf(UserInfo user, UserInfo profile) {
908         return user.id == profile.id ||
909                 (user.profileGroupId != UserInfo.NO_PROFILE_GROUP_ID
910                         && user.profileGroupId == profile.profileGroupId);
911     }
912 
913     /**
914      * Tries to initalize a volume with the given bundle. If it is a valid, private, and readable
915      * {@link VolumeInfo}, it is returned. If it is not valid, null is returned.
916      */
917     @Nullable
maybeInitializeVolume(StorageManager sm, Bundle bundle)918     public static VolumeInfo maybeInitializeVolume(StorageManager sm, Bundle bundle) {
919         final String volumeId = bundle.getString(VolumeInfo.EXTRA_VOLUME_ID,
920                 VolumeInfo.ID_PRIVATE_INTERNAL);
921         final VolumeInfo volume = sm.findVolumeById(volumeId);
922         return isVolumeValid(volume) ? volume : null;
923     }
924 
925     /**
926      * Return {@code true} if the supplied package is device owner or profile owner of at
927      * least one user.
928      * @param userManager used to get profile owner app for each user
929      * @param devicePolicyManager used to check whether it is device owner app
930      * @param packageName package to check about
931      */
isProfileOrDeviceOwner(UserManager userManager, DevicePolicyManager devicePolicyManager, String packageName)932     public static boolean isProfileOrDeviceOwner(UserManager userManager,
933             DevicePolicyManager devicePolicyManager, String packageName) {
934         final List<UserInfo> userInfos = userManager.getUsers();
935         if (devicePolicyManager.isDeviceOwnerAppOnAnyUser(packageName)) {
936             return true;
937         }
938         for (int i = 0, size = userInfos.size(); i < size; i++) {
939             final ComponentName cn = devicePolicyManager
940                     .getProfileOwnerAsUser(userInfos.get(i).id);
941             if (cn != null && cn.getPackageName().equals(packageName)) {
942                 return true;
943             }
944         }
945         return false;
946     }
947 
948     /**
949      * Return {@code true} if the supplied package is the device owner or profile owner of a
950      * given user.
951      *
952      * @param devicePolicyManager used to check whether it is device owner and profile owner app
953      * @param packageName         package to check about
954      * @param userId              the if of the relevant user
955      */
isProfileOrDeviceOwner(DevicePolicyManager devicePolicyManager, String packageName, int userId)956     public static boolean isProfileOrDeviceOwner(DevicePolicyManager devicePolicyManager,
957             String packageName, int userId) {
958         if ((devicePolicyManager.getDeviceOwnerUserId() == userId)
959                 && devicePolicyManager.isDeviceOwnerApp(packageName)) {
960             return true;
961         }
962         final ComponentName cn = devicePolicyManager.getProfileOwnerAsUser(userId);
963         if (cn != null && cn.getPackageName().equals(packageName)) {
964             return true;
965         }
966         return false;
967     }
968 
969     /**
970      * Return the resource id to represent the install status for an app
971      */
972     @StringRes
getInstallationStatus(ApplicationInfo info)973     public static int getInstallationStatus(ApplicationInfo info) {
974         if ((info.flags & ApplicationInfo.FLAG_INSTALLED) == 0) {
975             return R.string.not_installed;
976         }
977         return info.enabled ? R.string.installed : R.string.disabled;
978     }
979 
isVolumeValid(VolumeInfo volume)980     private static boolean isVolumeValid(VolumeInfo volume) {
981         return (volume != null) && (volume.getType() == VolumeInfo.TYPE_PRIVATE)
982                 && volume.isMountedReadable();
983     }
984 
setEditTextCursorPosition(EditText editText)985     public static void setEditTextCursorPosition(EditText editText) {
986         editText.setSelection(editText.getText().length());
987     }
988 
989     /**
990      * Gets the adaptive icon with a drawable that wrapped with an adaptive background using {@code
991      * backgroundColor} if it is not a {@link AdaptiveIconDrawable}
992      *
993      * If the given {@code icon} is too big, it will be auto scaled down to to avoid crashing
994      * Settings.
995      */
getAdaptiveIcon(Context context, Drawable icon, @ColorInt int backgroundColor)996     public static Drawable getAdaptiveIcon(Context context, Drawable icon,
997             @ColorInt int backgroundColor) {
998         Drawable adaptiveIcon = getSafeIcon(icon);
999 
1000         if (!(adaptiveIcon instanceof AdaptiveIconDrawable)) {
1001             adaptiveIcon = new AdaptiveIcon(context, adaptiveIcon);
1002             ((AdaptiveIcon) adaptiveIcon).setBackgroundColor(backgroundColor);
1003         }
1004 
1005         return adaptiveIcon;
1006     }
1007 
1008     /**
1009      * Gets the icon with a drawable that is scaled down to to avoid crashing Settings if it's too
1010      * big and not a {@link VectorDrawable}.
1011      */
getSafeIcon(Drawable icon)1012     public static Drawable getSafeIcon(Drawable icon) {
1013         Drawable safeIcon = icon;
1014 
1015         if ((icon != null) && !(icon instanceof VectorDrawable)) {
1016             safeIcon = getSafeDrawable(icon, 500, 500);
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.textColorSecondary);
1223     }
1224 
isProviderModelEnabled(Context context)1225     public static boolean isProviderModelEnabled(Context context) {
1226         return FeatureFlagUtils.isEnabled(context, FeatureFlagUtils.SETTINGS_PROVIDER_MODEL);
1227     }
1228 }
1229