• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy 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,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.settings.applications;
18 
19 import android.annotation.NonNull;
20 import android.app.ActivityManager;
21 import android.app.LocaleConfig;
22 import android.content.Context;
23 import android.content.Intent;
24 import android.content.pm.PackageInfo;
25 import android.content.pm.PackageManager;
26 import android.content.pm.ResolveInfo;
27 import android.os.LocaleList;
28 import android.util.FeatureFlagUtils;
29 import android.util.Log;
30 
31 import com.android.settings.R;
32 
33 import java.util.List;
34 
35 /** This class provides methods that help dealing with per app locale. */
36 public class AppLocaleUtil {
37     private static final String TAG = AppLocaleUtil.class.getSimpleName();
38 
39     public static final Intent LAUNCHER_ENTRY_INTENT =
40             new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_LAUNCHER);
41 
42     /**
43      * Decides the UI display of per app locale.
44      */
canDisplayLocaleUi( @onNull Context context, @NonNull String packageName, @NonNull List<ResolveInfo> infos)45     public static boolean canDisplayLocaleUi(
46             @NonNull Context context,
47             @NonNull String packageName,
48             @NonNull List<ResolveInfo> infos) {
49         boolean isDisallowedPackage = isDisallowedPackage(context, packageName);
50         boolean hasLauncherEntry = hasLauncherEntry(packageName, infos);
51         boolean isSignedWithPlatformKey = isSignedWithPlatformKey(context, packageName);
52         boolean canDisplay = !isDisallowedPackage
53                 && !isSignedWithPlatformKey
54                 && hasLauncherEntry
55                 && isAppLocaleSupported(context, packageName);
56 
57         Log.i(TAG, "Can display preference - [" + packageName + "] :"
58                 + " isDisallowedPackage : " + isDisallowedPackage
59                 + " / isSignedWithPlatformKey : " + isSignedWithPlatformKey
60                 + " / hasLauncherEntry : " + hasLauncherEntry
61                 + " / canDisplay : " + canDisplay);
62         return canDisplay;
63     }
64 
isDisallowedPackage(Context context, String packageName)65     private static boolean isDisallowedPackage(Context context, String packageName) {
66         final String[] disallowedPackages = context.getResources().getStringArray(
67                 R.array.config_disallowed_app_localeChange_packages);
68         for (String disallowedPackage : disallowedPackages) {
69             if (packageName.equals(disallowedPackage)) {
70                 return true;
71             }
72         }
73         return false;
74     }
75 
isSignedWithPlatformKey(Context context, String packageName)76     private static boolean isSignedWithPlatformKey(Context context, String packageName) {
77         PackageInfo packageInfo = null;
78         PackageManager packageManager = context.getPackageManager();
79         ActivityManager activityManager = context.getSystemService(ActivityManager.class);
80         try {
81             packageInfo = packageManager.getPackageInfoAsUser(
82                     packageName, /* flags= */ 0,
83                     activityManager.getCurrentUser());
84         } catch (PackageManager.NameNotFoundException ex) {
85             Log.e(TAG, "package not found: " + packageName);
86         }
87         if (packageInfo == null) {
88             return false;
89         }
90         return packageInfo.applicationInfo.isSignedWithPlatformKey();
91     }
92 
hasLauncherEntry(String packageName, List<ResolveInfo> infos)93     private static boolean hasLauncherEntry(String packageName, List<ResolveInfo> infos) {
94         return infos.stream()
95                 .anyMatch(info -> info.activityInfo.packageName.equals(packageName));
96     }
97 
98     /**
99      * Check the function of per app language is supported by current application.
100      */
isAppLocaleSupported(Context context, String packageName)101     public static boolean isAppLocaleSupported(Context context, String packageName) {
102         LocaleList localeList = getPackageLocales(context, packageName);
103         if (localeList != null) {
104             return localeList.size() > 0;
105         }
106 
107         if (FeatureFlagUtils.isEnabled(
108                 context, FeatureFlagUtils.SETTINGS_APP_LOCALE_OPT_IN_ENABLED)) {
109             return false;
110         }
111 
112         return getAssetLocales(context, packageName).length > 0;
113     }
114 
115     /**
116      * Get locales fron AssetManager.
117      */
getAssetLocales(Context context, String packageName)118     public static String[] getAssetLocales(Context context, String packageName) {
119         try {
120             PackageManager packageManager = context.getPackageManager();
121             String[] locales = packageManager.getResourcesForApplication(
122                     packageManager.getPackageInfo(packageName, PackageManager.MATCH_ALL)
123                             .applicationInfo).getAssets().getNonSystemLocales();
124             if (locales == null) {
125                 Log.i(TAG, "[" + packageName + "] locales are null.");
126             }
127             if (locales.length <= 0) {
128                 Log.i(TAG, "[" + packageName + "] locales length is 0.");
129                 return new String[0];
130             }
131             String locale = locales[0];
132             Log.i(TAG, "First asset locale - [" + packageName + "] " + locale);
133             return locales;
134         } catch (PackageManager.NameNotFoundException e) {
135             Log.w(TAG, "Can not found the package name : " + packageName + " / " + e);
136         }
137         return new String[0];
138     }
139 
140     /**
141      * Get locales from LocaleConfig.
142      */
getPackageLocales(Context context, String packageName)143     public static LocaleList getPackageLocales(Context context, String packageName) {
144         try {
145             LocaleConfig localeConfig =
146                     new LocaleConfig(context.createPackageContext(packageName, 0));
147             if (localeConfig.getStatus() == LocaleConfig.STATUS_SUCCESS) {
148                 return localeConfig.getSupportedLocales();
149             }
150         } catch (PackageManager.NameNotFoundException e) {
151             Log.w(TAG, "Can not found the package name : " + packageName + " / " + e);
152         }
153         return null;
154     }
155 }
156