diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 79821d3985a..6e82b11ad29 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -111,6 +111,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/values/strings.xml b/res/values/strings.xml
index ed867d2c4cf..7fecac48a99 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -461,7 +461,7 @@
Next
-
+
Languages
@@ -470,6 +470,29 @@
Add a language
+
+ Language
+
+
+ Preferred Language
+
+
+ App Languages
+
+
+ Set the language for each app
+
+
+ App Language
+
+
+ Suggested languages
+
+
+ All languages
+
+
+ The app is set to %1$s by default and doesn\u2019t support multiple languages.
- Remove selected language?
diff --git a/res/xml/app_info_settings.xml b/res/xml/app_info_settings.xml
index 14429607ec2..562c7d17192 100644
--- a/res/xml/app_info_settings.xml
+++ b/res/xml/app_info_settings.xml
@@ -88,6 +88,12 @@
android:title="@string/power_usage_summary_title"
android:summary="@string/summary_placeholder" />
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/res/xml/language_and_input.xml b/res/xml/language_and_input.xml
index f33ef5cb444..f2b6d8a1df9 100644
--- a/res/xml/language_and_input.xml
+++ b/res/xml/language_and_input.xml
@@ -19,12 +19,28 @@
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:settings="http://schemas.android.com/apk/res-auto"
android:title="@string/language_settings">
+
+
-
+
+
+
+
+
+
locales, Locale appLocale) {
+ if (locales == null) {
+ return;
+ }
+
+ for (Locale locale : locales) {
+ RadioButtonPreference pref = new RadioButtonPreference(getContext());
+ pref.setTitle(locale.getDisplayName(locale));
+ pref.setKey(locale.toLanguageTag());
+ pref.setChecked(locale.equals(appLocale));
+ pref.setOnClickListener(this);
+ group.addPreference(pref);
+ }
+ }
+
+ @VisibleForTesting
+ static class AppLocaleDetailsHelper {
+ private String mPackageName;
+ private Context mContext;
+ private TelephonyManager mTelephonyManager;
+ private LocaleManager mLocaleManager;
+
+ private Collection mSuggestedLocales = new ArrayList<>();;
+ private Collection mSupportedLocales = new ArrayList<>();;
+
+ AppLocaleDetailsHelper(Context context, String packageName) {
+ mContext = context;
+ mPackageName = packageName;
+ mTelephonyManager = context.getSystemService(TelephonyManager.class);
+ mLocaleManager = context.getSystemService(LocaleManager.class);
+ }
+
+ /** Handle suggested and supported locales for UI display. */
+ public void handleAllLocalesData() {
+ clearLocalesData();
+ handleSuggestedLocales();
+ handleSupportedLocales();
+ }
+
+ /** Gets suggested locales in the app. */
+ public Collection getSuggestedLocales() {
+ return mSuggestedLocales;
+ }
+
+ /** Gets supported locales in the app. */
+ public Collection getSupportedLocales() {
+ return mSupportedLocales;
+ }
+
+ @VisibleForTesting
+ void handleSuggestedLocales() {
+ LocaleList currentSystemLocales = getCurrentSystemLocales();
+ Locale simLocale = mTelephonyManager.getSimLocale();
+ Locale appLocale = getAppDefaultLocale(mContext, mPackageName);
+ // 1st locale in suggested languages group.
+ if (appLocale != null) {
+ mSuggestedLocales.add(appLocale);
+ }
+ // 2nd locale in suggested languages group.
+ if (simLocale != null && !simLocale.equals(appLocale)) {
+ mSuggestedLocales.add(simLocale);
+ }
+ // Other locales in suggested languages group.
+ for (int i = 0; i < currentSystemLocales.size(); i++) {
+ Locale locale = currentSystemLocales.get(i);
+ if (!locale.equals(appLocale) && !locale.equals(simLocale)) {
+ mSuggestedLocales.add(locale);
+ }
+ }
+ }
+
+ @VisibleForTesting
+ void handleSupportedLocales() {
+ //TODO Waiting for PackageManager api
+ String[] languages = getAssetSystemLocales();
+
+ for (String language : languages) {
+ mSupportedLocales.add(Locale.forLanguageTag(language));
+ }
+ if (mSuggestedLocales != null || !mSuggestedLocales.isEmpty()) {
+ mSupportedLocales.removeAll(mSuggestedLocales);
+ }
+ }
+
+ private void clearLocalesData() {
+ mSuggestedLocales.clear();
+ mSupportedLocales.clear();
+ }
+
+ /** Gets per app's default locale */
+ public static Locale getAppDefaultLocale(Context context, String packageName) {
+ LocaleManager localeManager = context.getSystemService(LocaleManager.class);
+ LocaleList localeList = (localeManager == null)
+ ? new LocaleList() : localeManager.getApplicationLocales(packageName);
+ return localeList.isEmpty() ? null : localeList.get(0);
+ }
+
+ /** Sets per app's default language to system. */
+ public void setAppDefaultLocale(String languageTag) {
+ if (languageTag.isEmpty()) {
+ Log.w(TAG, "[setAppDefaultLocale] No language tag.");
+ return;
+ }
+ setAppDefaultLocale(LocaleList.forLanguageTags(languageTag));
+ }
+
+ /** Sets per app's default language to system. */
+ public void setAppDefaultLocale(LocaleList localeList) {
+ if (mLocaleManager == null) {
+ Log.w(TAG, "LocaleManager is null, and cannot set the app locale up.");
+ return;
+ }
+ mLocaleManager.setApplicationLocales(mPackageName, localeList);
+ }
+
+ @VisibleForTesting
+ LocaleList getCurrentSystemLocales() {
+ return Resources.getSystem().getConfiguration().getLocales();
+ }
+
+ @VisibleForTesting
+ String[] getAssetSystemLocales() {
+ try {
+ PackageManager packageManager = mContext.getPackageManager();
+ return packageManager.getResourcesForApplication(
+ packageManager.getPackageInfo(mPackageName, PackageManager.MATCH_ALL)
+ .applicationInfo).getAssets().getNonSystemLocales();
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.w(TAG, "Can not found the package name : " + e);
+ }
+ return new String[0];
+ }
+ }
+}
diff --git a/src/com/android/settings/applications/appinfo/AppLocalePreferenceController.java b/src/com/android/settings/applications/appinfo/AppLocalePreferenceController.java
new file mode 100644
index 00000000000..f1e43ad1ee9
--- /dev/null
+++ b/src/com/android/settings/applications/appinfo/AppLocalePreferenceController.java
@@ -0,0 +1,48 @@
+/*
+ * 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 android.content.Context;
+import android.util.FeatureFlagUtils;
+
+import com.android.settings.SettingsPreferenceFragment;
+
+/**
+ * A controller to update current locale information of application.
+ */
+public class AppLocalePreferenceController extends AppInfoPreferenceControllerBase {
+ public AppLocalePreferenceController(Context context, String key) {
+ super(context, key);
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ return FeatureFlagUtils
+ .isEnabled(mContext, FeatureFlagUtils.SETTINGS_APP_LANGUAGE_SELECTION)
+ ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
+ }
+
+ @Override
+ protected Class extends SettingsPreferenceFragment> getDetailFragmentClass() {
+ return AppLocaleDetails.class;
+ }
+
+ @Override
+ public CharSequence getSummary() {
+ return AppLocaleDetails.getSummary(mContext, mParent.getAppEntry().info.packageName);
+ }
+}
diff --git a/src/com/android/settings/applications/appinfo/ManageAppLocalePreferenceController.java b/src/com/android/settings/applications/appinfo/ManageAppLocalePreferenceController.java
new file mode 100644
index 00000000000..aa12b626eb7
--- /dev/null
+++ b/src/com/android/settings/applications/appinfo/ManageAppLocalePreferenceController.java
@@ -0,0 +1,40 @@
+/*
+ * 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 android.content.Context;
+import android.util.FeatureFlagUtils;
+
+import com.android.settings.core.BasePreferenceController;
+
+/**
+ * A controller to update current locale information of application
+ * and a entry to launch {@link ManageApplications}.
+ * TODO(209775925) After feature release, this class may be removed.
+ */
+public class ManageAppLocalePreferenceController extends BasePreferenceController {
+ public ManageAppLocalePreferenceController(Context context, String key) {
+ super(context, key);
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ return FeatureFlagUtils
+ .isEnabled(mContext, FeatureFlagUtils.SETTINGS_APP_LANGUAGE_SELECTION)
+ ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
+ }
+}
diff --git a/src/com/android/settings/applications/manageapplications/ManageApplications.java b/src/com/android/settings/applications/manageapplications/ManageApplications.java
index 7b5c2218f7d..d98548280fb 100644
--- a/src/com/android/settings/applications/manageapplications/ManageApplications.java
+++ b/src/com/android/settings/applications/manageapplications/ManageApplications.java
@@ -108,6 +108,7 @@ import com.android.settings.applications.AppStorageSettings;
import com.android.settings.applications.UsageAccessDetails;
import com.android.settings.applications.appinfo.AlarmsAndRemindersDetails;
import com.android.settings.applications.appinfo.AppInfoDashboardFragment;
+import com.android.settings.applications.appinfo.AppLocaleDetails;
import com.android.settings.applications.appinfo.DrawOverlayDetails;
import com.android.settings.applications.appinfo.ExternalSourcesDetails;
import com.android.settings.applications.appinfo.ManageExternalStorageDetails;
@@ -231,6 +232,7 @@ public class ManageApplications extends InstrumentedFragment
public static final int LIST_MANAGE_EXTERNAL_STORAGE = 11;
public static final int LIST_TYPE_ALARMS_AND_REMINDERS = 12;
public static final int LIST_TYPE_MEDIA_MANAGEMENT_APPS = 13;
+ public static final int LIST_TYPE_APPS_LOCAL = 14;
// List types that should show instant apps.
public static final Set LIST_TYPES_WITH_INSTANT = new ArraySet<>(Arrays.asList(
@@ -318,6 +320,8 @@ public class ManageApplications extends InstrumentedFragment
ServiceManager.getService(Context.USAGE_STATS_SERVICE));
mNotificationBackend = new NotificationBackend();
mSortOrder = R.id.sort_order_recent_notification;
+ } else if (className.equals(AppLocaleDetails.class.getName())) {
+ mListType = LIST_TYPE_APPS_LOCAL;
} else {
mListType = LIST_TYPE_MAIN;
}
@@ -500,6 +504,8 @@ public class ManageApplications extends InstrumentedFragment
return SettingsEnums.ALARMS_AND_REMINDERS;
case LIST_TYPE_MEDIA_MANAGEMENT_APPS:
return SettingsEnums.MEDIA_MANAGEMENT_APPS;
+ case LIST_TYPE_APPS_LOCAL:
+ return SettingsEnums.APPS_LOCALE_LIST;
default:
return SettingsEnums.PAGE_UNKNOWN;
}
@@ -623,6 +629,10 @@ public class ManageApplications extends InstrumentedFragment
startAppInfoFragment(MediaManagementAppsDetails.class,
R.string.media_management_apps_title);
break;
+ case LIST_TYPE_APPS_LOCAL:
+ startAppInfoFragment(AppLocaleDetails.class,
+ R.string.app_locale_picker_title);
+ break;
// TODO: Figure out if there is a way where we can spin up the profile's settings
// process ahead of time, to avoid a long load of data when user clicks on a managed
// app. Maybe when they load the list of apps that contains managed profile apps.
@@ -899,6 +909,8 @@ public class ManageApplications extends InstrumentedFragment
screenTitle = R.string.alarms_and_reminders_title;
} else if (className.equals(Settings.NotificationAppListActivity.class.getName())) {
screenTitle = R.string.app_notifications_title;
+ } else if (className.equals(AppLocaleDetails.class.getName())) {
+ screenTitle = R.string.app_locales_picker_menu_title;
} else {
if (screenTitle == -1) {
screenTitle = R.string.all_apps;
@@ -1521,6 +1533,10 @@ public class ManageApplications extends InstrumentedFragment
case LIST_TYPE_MEDIA_MANAGEMENT_APPS:
holder.setSummary(MediaManagementAppsDetails.getSummary(mContext, entry));
break;
+ case LIST_TYPE_APPS_LOCAL:
+ holder.setSummary(AppLocaleDetails
+ .getSummary(mContext, entry.info.packageName));
+ break;
default:
holder.updateSizeText(entry, mManageApplications.mInvalidSizeStr, mWhichSize);
break;
diff --git a/tests/unit/src/com/android/settings/applications/appinfo/AppLocaleDetailsTest.java b/tests/unit/src/com/android/settings/applications/appinfo/AppLocaleDetailsTest.java
new file mode 100644
index 00000000000..a97656c4b71
--- /dev/null
+++ b/tests/unit/src/com/android/settings/applications/appinfo/AppLocaleDetailsTest.java
@@ -0,0 +1,198 @@
+/*
+ * 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 org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.app.LocaleManager;
+import android.content.Context;
+import android.os.LocaleList;
+import android.os.Looper;
+import android.telephony.TelephonyManager;
+
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.google.common.collect.Iterables;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.Locale;
+
+@RunWith(AndroidJUnit4.class)
+public class AppLocaleDetailsTest {
+ private static final String APP_PACKAGE_NAME = "app_package_name";
+
+ @Mock
+ private TelephonyManager mTelephonyManager;
+ @Mock
+ private LocaleManager mLocaleManager;
+
+ private Context mContext;
+ private LocaleList mSystemLocales;
+ private Locale mSimLocale;
+ private LocaleList mAppLocale;
+ private String[] mAssetLocales;
+
+ @Before
+ @UiThreadTest
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
+ mContext = spy(ApplicationProvider.getApplicationContext());
+ when(mContext.getSystemService(TelephonyManager.class)).thenReturn(mTelephonyManager);
+ when(mContext.getSystemService(LocaleManager.class)).thenReturn(mLocaleManager);
+
+ setupInitialLocales("en",
+ "uk",
+ "en, uk, jp, ne",
+ new String[]{"en", "ne", "ms", "pa"});
+ }
+
+ @Test
+ @UiThreadTest
+ public void handleAllLocalesData_localeManagerIsNull_noCrash() {
+ when(mContext.getSystemService(LocaleManager.class)).thenReturn(null);
+
+ DummyAppLocaleDetailsHelper helper =
+ new DummyAppLocaleDetailsHelper(mContext, APP_PACKAGE_NAME);
+
+ helper.handleAllLocalesData();
+ }
+
+ @Test
+ @UiThreadTest
+ public void handleAllLocalesData_1stLocaleOfSuggestedLocaleListIsAppLocale() {
+ DummyAppLocaleDetailsHelper helper =
+ new DummyAppLocaleDetailsHelper(mContext, APP_PACKAGE_NAME);
+
+ helper.handleAllLocalesData();
+
+ Locale locale = Iterables.get(helper.getSuggestedLocales(), 0);
+ assertTrue(locale.equals(mAppLocale.get(0)));
+ }
+
+ @Test
+ @UiThreadTest
+ public void handleAllLocalesData_2ndLocaleOfSuggestedLocaleListIsSimLocale() {
+ DummyAppLocaleDetailsHelper helper =
+ new DummyAppLocaleDetailsHelper(mContext, APP_PACKAGE_NAME);
+
+ helper.handleAllLocalesData();
+
+ Locale locale = Iterables.get(helper.getSuggestedLocales(), 1);
+ assertTrue(locale.equals(mSimLocale));
+ }
+
+ @Test
+ @UiThreadTest
+ public void handleAllLocalesData_withoutAppLocale_1stLocaleOfSuggestedLocaleListIsSimLocal() {
+ setupInitialLocales("",
+ "uk",
+ "en, uk, jp, ne",
+ new String[]{"en", "ne", "ms", "pa"});
+ DummyAppLocaleDetailsHelper helper =
+ new DummyAppLocaleDetailsHelper(mContext, APP_PACKAGE_NAME);
+
+ helper.handleAllLocalesData();
+
+ Locale locale = Iterables.get(helper.getSuggestedLocales(), 0);
+ assertTrue(locale.equals(mSimLocale));
+ }
+
+ @Test
+ @UiThreadTest
+ public void handleAllLocalesData_noAppAndSimLocale_1stLocaleIsFirstOneInSystemLocales() {
+ setupInitialLocales("",
+ "",
+ "en, uk, jp, ne",
+ new String[]{"en", "ne", "ms", "pa"});
+ DummyAppLocaleDetailsHelper helper =
+ new DummyAppLocaleDetailsHelper(mContext, APP_PACKAGE_NAME);
+
+ helper.handleAllLocalesData();
+
+ Locale locale = Iterables.get(helper.getSuggestedLocales(), 0);
+ assertTrue(locale.equals(mSystemLocales.get(0)));
+ }
+
+ @Test
+ @UiThreadTest
+ public void handleAllLocalesData_supportLocaleListIsNotEmpty() {
+ DummyAppLocaleDetailsHelper helper =
+ new DummyAppLocaleDetailsHelper(mContext, APP_PACKAGE_NAME);
+
+ helper.handleAllLocalesData();
+
+ assertFalse(helper.getSupportedLocales().isEmpty());
+ }
+
+ /**
+ * Sets the initial Locale data
+ *
+ * @param appLocale Application locale, it shall be a language tag.
+ * example: "en"
+ * @param simLocale SIM carrier locale, it shall be a language tag.
+ * example: "en"
+ * @param systemLocales System locales, a locale list by a multiple language tags with comma.
+ * example: "en, uk, jp"
+ * @param assetLocales Asset locales, a locale list by a multiple language tags with String
+ * array.
+ * example: new String[] {"en", "ne", "ms", "pa"}
+ */
+ private void setupInitialLocales(String appLocale,
+ String simLocale,
+ String systemLocales,
+ String[] assetLocales) {
+ mAppLocale = LocaleList.forLanguageTags(appLocale);
+ mSimLocale = Locale.forLanguageTag(simLocale);
+ mSystemLocales = LocaleList.forLanguageTags(systemLocales);
+ mAssetLocales = assetLocales;
+ when(mTelephonyManager.getSimLocale()).thenReturn(simLocale.isEmpty() ? null : mSimLocale);
+ when(mLocaleManager.getApplicationLocales(anyString())).thenReturn(mAppLocale);
+ }
+
+ private class DummyAppLocaleDetailsHelper
+ extends AppLocaleDetails.AppLocaleDetailsHelper {
+
+ DummyAppLocaleDetailsHelper(Context context, String packageName) {
+ super(context, packageName);
+ }
+
+ @Override
+ String[] getAssetSystemLocales() {
+ return mAssetLocales;
+ }
+
+ @Override
+ LocaleList getCurrentSystemLocales() {
+ return mSystemLocales;
+ }
+ }
+
+}
diff --git a/tests/unit/src/com/android/settings/applications/appinfo/AppLocalePreferenceControllerTest.java b/tests/unit/src/com/android/settings/applications/appinfo/AppLocalePreferenceControllerTest.java
new file mode 100644
index 00000000000..d7e3f923297
--- /dev/null
+++ b/tests/unit/src/com/android/settings/applications/appinfo/AppLocalePreferenceControllerTest.java
@@ -0,0 +1,66 @@
+/*
+ * 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.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.spy;
+
+import android.content.Context;
+import android.util.FeatureFlagUtils;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+import com.android.settings.core.BasePreferenceController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+public class AppLocalePreferenceControllerTest {
+
+ private Context mContext;
+ private AppLocalePreferenceController mController;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext = spy(ApplicationProvider.getApplicationContext());
+
+ mController = spy(new AppLocalePreferenceController(mContext, "test_key"));
+ FeatureFlagUtils
+ .setEnabled(mContext, FeatureFlagUtils.SETTINGS_APP_LANGUAGE_SELECTION, true);
+ }
+
+ @Test
+ public void getAvailabilityStatus_featureFlagOff_shouldReturnUnavailable() {
+ FeatureFlagUtils
+ .setEnabled(mContext, FeatureFlagUtils.SETTINGS_APP_LANGUAGE_SELECTION, false);
+
+ assertThat(mController.getAvailabilityStatus())
+ .isEqualTo(BasePreferenceController.CONDITIONALLY_UNAVAILABLE);
+ }
+
+ @Test
+ public void getAvailabilityStatus_featureFlagOn_shouldReturnAvailable() {
+ assertThat(mController.getAvailabilityStatus())
+ .isEqualTo(BasePreferenceController.AVAILABLE);
+ }
+}
diff --git a/tests/unit/src/com/android/settings/applications/appinfo/ManageAppLocalePreferenceControllerTest.java b/tests/unit/src/com/android/settings/applications/appinfo/ManageAppLocalePreferenceControllerTest.java
new file mode 100644
index 00000000000..648c7570304
--- /dev/null
+++ b/tests/unit/src/com/android/settings/applications/appinfo/ManageAppLocalePreferenceControllerTest.java
@@ -0,0 +1,66 @@
+/*
+ * 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.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.spy;
+
+import android.content.Context;
+import android.util.FeatureFlagUtils;
+
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+
+
+import com.android.settings.core.BasePreferenceController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+public class ManageAppLocalePreferenceControllerTest {
+ private Context mContext;
+ private ManageAppLocalePreferenceController mController;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ mContext = spy(ApplicationProvider.getApplicationContext());
+ mController = spy(new ManageAppLocalePreferenceController(mContext, "a key"));
+
+ FeatureFlagUtils
+ .setEnabled(mContext, FeatureFlagUtils.SETTINGS_APP_LANGUAGE_SELECTION, true);
+ }
+
+ @Test
+ public void getAvailabilityStatus_featureFlagOff_shouldReturnUnavailable() {
+ FeatureFlagUtils
+ .setEnabled(mContext, FeatureFlagUtils.SETTINGS_APP_LANGUAGE_SELECTION, false);
+
+ assertThat(mController.getAvailabilityStatus())
+ .isEqualTo(BasePreferenceController.CONDITIONALLY_UNAVAILABLE);
+ }
+
+ @Test
+ public void getAvailabilityStatus_featureFlagOn_shouldReturnAvailable() {
+ assertThat(mController.getAvailabilityStatus())
+ .isEqualTo(BasePreferenceController.AVAILABLE);
+ }
+}