1 /* 2 * Copyright (C) 2021 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 package com.android.settings.applications.appinfo; 17 18 import static com.android.settings.widget.EntityHeaderController.ActionType; 19 20 import android.app.Activity; 21 import android.app.LocaleManager; 22 import android.app.settings.SettingsEnums; 23 import android.content.Context; 24 import android.content.pm.ApplicationInfo; 25 import android.content.pm.PackageManager; 26 import android.os.Bundle; 27 import android.os.LocaleList; 28 import android.os.UserHandle; 29 import android.util.FeatureFlagUtils; 30 import android.util.Log; 31 import android.view.LayoutInflater; 32 import android.view.View; 33 import android.view.ViewGroup; 34 import android.widget.TextView; 35 36 import androidx.preference.Preference; 37 38 import com.android.internal.app.LocaleHelper; 39 import com.android.settings.R; 40 import com.android.settings.SettingsPreferenceFragment; 41 import com.android.settings.Utils; 42 import com.android.settings.applications.AppInfoBase; 43 import com.android.settings.applications.AppLocaleUtil; 44 import com.android.settings.widget.EntityHeaderController; 45 import com.android.settingslib.applications.AppUtils; 46 import com.android.settingslib.widget.LayoutPreference; 47 48 import java.util.Locale; 49 50 /** 51 * TODO(b/223503670): Implement the unittest. 52 * A fragment to show the current app locale info. 53 */ 54 public class AppLocaleDetails extends SettingsPreferenceFragment { 55 private static final String TAG = "AppLocaleDetails"; 56 57 private static final String KEY_APP_DESCRIPTION = "app_locale_description"; 58 private static final String KEY_APP_DISCLAIMER = "app_locale_disclaimer"; 59 60 private boolean mCreated = false; 61 private String mPackageName; 62 private LayoutPreference mPrefOfDescription; 63 private Preference mPrefOfDisclaimer; 64 private ApplicationInfo mApplicationInfo; 65 66 /** 67 * Create a instance of AppLocaleDetails. 68 * @param packageName Indicates which application need to show the locale picker. 69 * @param uid User id. 70 */ newInstance(String packageName, int uid)71 public static AppLocaleDetails newInstance(String packageName, int uid) { 72 AppLocaleDetails appLocaleDetails = new AppLocaleDetails(); 73 Bundle bundle = new Bundle(); 74 bundle.putString(AppInfoBase.ARG_PACKAGE_NAME, packageName); 75 bundle.putInt(AppInfoBase.ARG_PACKAGE_UID, uid); 76 appLocaleDetails.setArguments(bundle); 77 return appLocaleDetails; 78 } 79 80 @Override onCreate(Bundle savedInstanceState)81 public void onCreate(Bundle savedInstanceState) { 82 super.onCreate(savedInstanceState); 83 Bundle bundle = getArguments(); 84 mPackageName = bundle.getString(AppInfoBase.ARG_PACKAGE_NAME, ""); 85 if (mPackageName.isEmpty()) { 86 Log.d(TAG, "There is no package name."); 87 finish(); 88 } 89 int uid = bundle.getInt(AppInfoBase.ARG_PACKAGE_UID, getContext().getUserId()); 90 91 addPreferencesFromResource(R.xml.app_locale_details); 92 mPrefOfDescription = getPreferenceScreen().findPreference(KEY_APP_DESCRIPTION); 93 mPrefOfDisclaimer = getPreferenceScreen().findPreference(KEY_APP_DISCLAIMER); 94 mApplicationInfo = getApplicationInfo(mPackageName, uid); 95 setDisclaimerPreference(); 96 } 97 98 // Override here so we don't have an empty screen 99 @Override onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)100 public View onCreateView(LayoutInflater inflater, 101 ViewGroup container, 102 Bundle savedInstanceState) { 103 // if we don't have a package, show a page saying this is unsupported 104 if (mPackageName.isEmpty()) { 105 return inflater.inflate(R.layout.manage_applications_apps_unsupported, null); 106 } 107 return super.onCreateView(inflater, container, savedInstanceState); 108 } 109 110 @Override onResume()111 public void onResume() { 112 super.onResume(); 113 refreshUi(); 114 } 115 refreshUi()116 private void refreshUi() { 117 setDescription(); 118 } 119 120 @Override getMetricsCategory()121 public int getMetricsCategory() { 122 return SettingsEnums.APPS_LOCALE_LIST; 123 } 124 125 @Override onActivityCreated(Bundle savedInstanceState)126 public void onActivityCreated(Bundle savedInstanceState) { 127 super.onActivityCreated(savedInstanceState); 128 if (mCreated) { 129 Log.w(TAG, "onActivityCreated: ignoring duplicate call"); 130 return; 131 } 132 mCreated = true; 133 if (mPackageName == null) { 134 return; 135 } 136 // Creates a head icon button of app on this page. 137 final Activity activity = getActivity(); 138 final Preference pref = EntityHeaderController 139 .newInstance(activity, this, null /* header */) 140 .setIcon(Utils.getBadgedIcon(getContext(), mApplicationInfo)) 141 .setLabel(mApplicationInfo.loadLabel(getContext().getPackageManager())) 142 .setIsInstantApp(AppUtils.isInstant(mApplicationInfo)) 143 .setPackageName(mPackageName) 144 .setUid(mApplicationInfo.uid) 145 .setHasAppInfoLink(true) 146 .setButtonActions(ActionType.ACTION_NONE, ActionType.ACTION_NONE) 147 .setOrder(10) 148 .done(getPrefContext()); 149 getPreferenceScreen().addPreference(pref); 150 } 151 setDisclaimerPreference()152 private void setDisclaimerPreference() { 153 if (FeatureFlagUtils.isEnabled( 154 getContext(), FeatureFlagUtils.SETTINGS_APP_LOCALE_OPT_IN_ENABLED)) { 155 mPrefOfDisclaimer.setVisible(false); 156 } 157 } 158 setDescription()159 private void setDescription() { 160 int res = getAppDescription(); 161 if (res != -1) { 162 mPrefOfDescription.setVisible(true); 163 TextView description = (TextView) mPrefOfDescription.findViewById(R.id.description); 164 description.setText(getContext().getString(res)); 165 } 166 } 167 getApplicationInfo(String packageName, int userId)168 private ApplicationInfo getApplicationInfo(String packageName, int userId) { 169 ApplicationInfo applicationInfo; 170 try { 171 applicationInfo = getContext().getPackageManager() 172 .getApplicationInfoAsUser(packageName, /* flags= */ 0, userId); 173 return applicationInfo; 174 } catch (PackageManager.NameNotFoundException e) { 175 Log.w(TAG, "Application info not found for: " + packageName); 176 return null; 177 } 178 } 179 getAppDescription()180 private int getAppDescription() { 181 LocaleList packageLocaleList = AppLocaleUtil.getPackageLocales(getContext(), mPackageName); 182 String[] assetLocaleList = AppLocaleUtil.getAssetLocales(getContext(), mPackageName); 183 // TODO add apended url string, "Learn more", to these both sentenses. 184 if ((packageLocaleList != null && packageLocaleList.isEmpty()) 185 || (packageLocaleList == null && assetLocaleList.length == 0)) { 186 return R.string.desc_no_available_supported_locale; 187 } 188 return -1; 189 } 190 191 /** Gets per app's default locale */ getAppDefaultLocale(Context context, String packageName)192 public static Locale getAppDefaultLocale(Context context, String packageName) { 193 LocaleManager localeManager = context.getSystemService(LocaleManager.class); 194 try { 195 LocaleList localeList = (localeManager == null) 196 ? null : localeManager.getApplicationLocales(packageName); 197 return localeList == null ? null : localeList.get(0); 198 } catch (IllegalArgumentException e) { 199 Log.w(TAG, "package name : " + packageName + " is not correct. " + e); 200 } 201 return null; 202 } 203 204 /** 205 * TODO (b209962418) Do a performance test to low end device. 206 * @return Return the summary to show the current app's language. 207 */ getSummary(Context context, ApplicationInfo app)208 public static CharSequence getSummary(Context context, ApplicationInfo app) { 209 final UserHandle userHandle = UserHandle.getUserHandleForUid(app.uid); 210 final Context contextAsUser = context.createContextAsUser(userHandle, 0); 211 Locale appLocale = getAppDefaultLocale(contextAsUser, app.packageName); 212 if (appLocale == null) { 213 return context.getString(R.string.preference_of_system_locale_summary); 214 } else { 215 return LocaleHelper.getDisplayName(appLocale.stripExtensions(), appLocale, true); 216 } 217 } 218 } 219