/* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.settings.applications.appinfo; import static com.android.settings.widget.EntityHeaderController.ActionType; import android.app.Activity; import android.app.LocaleManager; import android.app.settings.SettingsEnums; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.os.Bundle; import android.os.LocaleList; import android.os.UserHandle; import android.util.FeatureFlagUtils; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; import androidx.preference.Preference; import com.android.internal.app.LocaleHelper; import com.android.settings.R; import com.android.settings.SettingsPreferenceFragment; import com.android.settings.Utils; import com.android.settings.applications.AppInfoBase; import com.android.settings.applications.AppLocaleUtil; import com.android.settings.widget.EntityHeaderController; import com.android.settingslib.applications.AppUtils; import com.android.settingslib.widget.LayoutPreference; import java.util.Locale; /** * TODO(b/223503670): Implement the unittest. * A fragment to show the current app locale info. */ public class AppLocaleDetails extends SettingsPreferenceFragment { private static final String TAG = "AppLocaleDetails"; private static final String KEY_APP_DESCRIPTION = "app_locale_description"; private static final String KEY_APP_DISCLAIMER = "app_locale_disclaimer"; private boolean mCreated = false; private String mPackageName; private LayoutPreference mPrefOfDescription; private Preference mPrefOfDisclaimer; private ApplicationInfo mApplicationInfo; /** * Create a instance of AppLocaleDetails. * @param packageName Indicates which application need to show the locale picker. * @param uid User id. */ public static AppLocaleDetails newInstance(String packageName, int uid) { AppLocaleDetails appLocaleDetails = new AppLocaleDetails(); Bundle bundle = new Bundle(); bundle.putString(AppInfoBase.ARG_PACKAGE_NAME, packageName); bundle.putInt(AppInfoBase.ARG_PACKAGE_UID, uid); appLocaleDetails.setArguments(bundle); return appLocaleDetails; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Bundle bundle = getArguments(); mPackageName = bundle.getString(AppInfoBase.ARG_PACKAGE_NAME, ""); if (mPackageName.isEmpty()) { Log.d(TAG, "There is no package name."); finish(); } int uid = bundle.getInt(AppInfoBase.ARG_PACKAGE_UID, getContext().getUserId()); addPreferencesFromResource(R.xml.app_locale_details); mPrefOfDescription = getPreferenceScreen().findPreference(KEY_APP_DESCRIPTION); mPrefOfDisclaimer = getPreferenceScreen().findPreference(KEY_APP_DISCLAIMER); mApplicationInfo = getApplicationInfo(mPackageName, uid); setDisclaimerPreference(); } // Override here so we don't have an empty screen @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // if we don't have a package, show a page saying this is unsupported if (mPackageName.isEmpty()) { return inflater.inflate(R.layout.manage_applications_apps_unsupported, null); } return super.onCreateView(inflater, container, savedInstanceState); } @Override public void onResume() { super.onResume(); refreshUi(); } private void refreshUi() { setDescription(); } @Override public int getMetricsCategory() { return SettingsEnums.APPS_LOCALE_LIST; } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); if (mCreated) { Log.w(TAG, "onActivityCreated: ignoring duplicate call"); return; } mCreated = true; if (mPackageName == null) { return; } // Creates a head icon button of app on this page. final Activity activity = getActivity(); final Preference pref = EntityHeaderController .newInstance(activity, this, null /* header */) .setIcon(Utils.getBadgedIcon(getContext(), mApplicationInfo)) .setLabel(mApplicationInfo.loadLabel(getContext().getPackageManager())) .setIsInstantApp(AppUtils.isInstant(mApplicationInfo)) .setPackageName(mPackageName) .setUid(mApplicationInfo.uid) .setHasAppInfoLink(true) .setButtonActions(ActionType.ACTION_NONE, ActionType.ACTION_NONE) .setOrder(10) .done(getPrefContext()); getPreferenceScreen().addPreference(pref); } private void setDisclaimerPreference() { if (FeatureFlagUtils.isEnabled( getContext(), FeatureFlagUtils.SETTINGS_APP_LOCALE_OPT_IN_ENABLED)) { mPrefOfDisclaimer.setVisible(false); } } private void setDescription() { int res = getAppDescription(); if (res != -1) { mPrefOfDescription.setVisible(true); TextView description = (TextView) mPrefOfDescription.findViewById(R.id.description); description.setText(getContext().getString(res)); } } private ApplicationInfo getApplicationInfo(String packageName, int userId) { ApplicationInfo applicationInfo; try { applicationInfo = getContext().getPackageManager() .getApplicationInfoAsUser(packageName, /* flags= */ 0, userId); return applicationInfo; } catch (PackageManager.NameNotFoundException e) { Log.w(TAG, "Application info not found for: " + packageName); return null; } } private int getAppDescription() { LocaleList packageLocaleList = AppLocaleUtil.getPackageLocales(getContext(), mPackageName); String[] assetLocaleList = AppLocaleUtil.getAssetLocales(getContext(), mPackageName); // TODO add apended url string, "Learn more", to these both sentenses. if ((packageLocaleList != null && packageLocaleList.isEmpty()) || (packageLocaleList == null && assetLocaleList.length == 0)) { return R.string.desc_no_available_supported_locale; } return -1; } /** Gets per app's default locale */ public static Locale getAppDefaultLocale(Context context, String packageName) { LocaleManager localeManager = context.getSystemService(LocaleManager.class); try { LocaleList localeList = (localeManager == null) ? null : localeManager.getApplicationLocales(packageName); return localeList == null ? null : localeList.get(0); } catch (IllegalArgumentException e) { Log.w(TAG, "package name : " + packageName + " is not correct. " + e); } return null; } /** * TODO (b209962418) Do a performance test to low end device. * @return Return the summary to show the current app's language. */ public static CharSequence getSummary(Context context, ApplicationInfo app) { final UserHandle userHandle = UserHandle.getUserHandleForUid(app.uid); final Context contextAsUser = context.createContextAsUser(userHandle, 0); Locale appLocale = getAppDefaultLocale(contextAsUser, app.packageName); if (appLocale == null) { return context.getString(R.string.preference_of_system_locale_summary); } else { return LocaleHelper.getDisplayName(appLocale.stripExtensions(), appLocale, true); } } }