diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 310ed3840ee..6e82b11ad29 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -111,6 +111,7 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/res/layout/dialog_sim_status.xml b/res/layout/dialog_sim_status.xml
index 27d12a8cb1c..c169e586d1d 100644
--- a/res/layout/dialog_sim_status.xml
+++ b/res/layout/dialog_sim_status.xml
@@ -166,6 +166,7 @@
android:id="@+id/esim_id_value"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:textIsSelectable="true"
android:text="@string/device_info_not_available"/>
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/src/com/android/settings/core/gateway/SettingsGateway.java b/src/com/android/settings/core/gateway/SettingsGateway.java
index 87e176e2bc5..e94fafc3cd7 100644
--- a/src/com/android/settings/core/gateway/SettingsGateway.java
+++ b/src/com/android/settings/core/gateway/SettingsGateway.java
@@ -123,6 +123,7 @@ import com.android.settings.network.NetworkDashboardFragment;
import com.android.settings.network.NetworkProviderSettings;
import com.android.settings.network.apn.ApnEditor;
import com.android.settings.network.apn.ApnSettings;
+import com.android.settings.network.telephony.MobileNetworkSettings;
import com.android.settings.network.telephony.NetworkSelectSettings;
import com.android.settings.nfc.AndroidBeam;
import com.android.settings.nfc.PaymentSettings;
@@ -329,7 +330,8 @@ public class SettingsGateway {
AlarmsAndRemindersDetails.class.getName(),
MediaManagementAppsDetails.class.getName(),
AutoBrightnessSettings.class.getName(),
- OneHandedSettings.class.getName()
+ OneHandedSettings.class.getName(),
+ MobileNetworkSettings.class.getName()
};
public static final String[] SETTINGS_FOR_RESTRICTED = {
diff --git a/src/com/android/settings/network/MobileNetworkSummaryController.java b/src/com/android/settings/network/MobileNetworkSummaryController.java
index 94d1ff5da5e..1a85a7fa341 100644
--- a/src/com/android/settings/network/MobileNetworkSummaryController.java
+++ b/src/com/android/settings/network/MobileNetworkSummaryController.java
@@ -36,7 +36,7 @@ import com.android.settings.R;
import com.android.settings.core.PreferenceControllerMixin;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.network.helper.SubscriptionAnnotation;
-import com.android.settings.network.telephony.MobileNetworkActivity;
+import com.android.settings.network.telephony.MobileNetworkUtils;
import com.android.settings.overlay.FeatureFactory;
import com.android.settings.widget.AddPreference;
import com.android.settingslib.Utils;
@@ -190,12 +190,8 @@ public class MobileNetworkSummaryController extends AbstractPreferenceController
SubscriptionAnnotation info = subs.get(0);
if (info.getSubInfo().isEmbedded() || info.isActive()
|| mStatusCache.isPhysicalSimDisableSupport()) {
- final Intent intent = new Intent(mContext, MobileNetworkActivity.class);
- intent.putExtra(Settings.EXTRA_SUB_ID, info.getSubscriptionId());
- // MobileNetworkActivity is singleTask, set SplitPairRule to show in 2-pane.
- MobileNetworkTwoPaneUtils.registerTwoPaneForMobileNetwork(mContext, intent,
- null);
- mContext.startActivity(intent);
+ MobileNetworkUtils.launchMobileNetworkSettings(mContext,
+ info.getSubInfo());
return true;
}
diff --git a/src/com/android/settings/network/NetworkProviderDownloadedSimListController.java b/src/com/android/settings/network/NetworkProviderDownloadedSimListController.java
index 1bb50cbaf5e..48cd8aa9c0e 100644
--- a/src/com/android/settings/network/NetworkProviderDownloadedSimListController.java
+++ b/src/com/android/settings/network/NetworkProviderDownloadedSimListController.java
@@ -36,7 +36,6 @@ import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceScreen;
import com.android.settings.R;
-import com.android.settings.network.telephony.MobileNetworkActivity;
import com.android.settings.network.telephony.MobileNetworkUtils;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.lifecycle.Lifecycle;
@@ -128,11 +127,7 @@ public class NetworkProviderDownloadedSimListController extends
pref.setSummary(getSummary(subId));
pref.setOnPreferenceClickListener(clickedPref -> {
- final Intent intent = new Intent(mContext, MobileNetworkActivity.class);
- intent.putExtra(Settings.EXTRA_SUB_ID, info.getSubscriptionId());
- // MobileNetworkActivity is singleTask, set SplitPairRule to show in 2-pane.
- MobileNetworkTwoPaneUtils.registerTwoPaneForMobileNetwork(mContext, intent, null);
- mContext.startActivity(intent);
+ MobileNetworkUtils.launchMobileNetworkSettings(mContext, info);
return true;
});
mPreferences.put(subId, pref);
diff --git a/src/com/android/settings/network/NetworkProviderSimListController.java b/src/com/android/settings/network/NetworkProviderSimListController.java
index d6eaab8e14a..77d665a14b0 100644
--- a/src/com/android/settings/network/NetworkProviderSimListController.java
+++ b/src/com/android/settings/network/NetworkProviderSimListController.java
@@ -36,7 +36,7 @@ import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceScreen;
import com.android.settings.R;
-import com.android.settings.network.telephony.MobileNetworkActivity;
+import com.android.settings.network.telephony.MobileNetworkUtils;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
@@ -126,12 +126,7 @@ public class NetworkProviderSimListController extends AbstractPreferenceControll
SubscriptionUtil.startToggleSubscriptionDialogActivity(mContext, subId,
true);
} else {
- final Intent intent = new Intent(mContext, MobileNetworkActivity.class);
- intent.putExtra(Settings.EXTRA_SUB_ID, info.getSubscriptionId());
- // MobileNetworkActivity is singleTask, set SplitPairRule to show in 2-pane.
- MobileNetworkTwoPaneUtils.registerTwoPaneForMobileNetwork(mContext, intent,
- null);
- mContext.startActivity(intent);
+ MobileNetworkUtils.launchMobileNetworkSettings(mContext, info);
}
return true;
});
diff --git a/src/com/android/settings/network/SubscriptionUtil.java b/src/com/android/settings/network/SubscriptionUtil.java
index d7e5876c5a4..1ba05025778 100644
--- a/src/com/android/settings/network/SubscriptionUtil.java
+++ b/src/com/android/settings/network/SubscriptionUtil.java
@@ -24,6 +24,7 @@ import static com.android.internal.util.CollectionUtils.emptyIfNull;
import android.annotation.Nullable;
import android.content.Context;
import android.os.ParcelUuid;
+import android.provider.Settings;
import android.telephony.PhoneNumberUtils;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
@@ -37,6 +38,8 @@ import androidx.annotation.VisibleForTesting;
import com.android.internal.telephony.MccTable;
import com.android.settings.R;
+import com.android.settings.network.helper.SelectableSubscriptions;
+import com.android.settings.network.helper.SubscriptionAnnotation;
import com.android.settings.network.telephony.DeleteEuiccSubscriptionDialogActivity;
import com.android.settings.network.telephony.ToggleSubscriptionDialogActivity;
import com.android.settingslib.DeviceInfoUtils;
@@ -48,6 +51,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -643,4 +647,49 @@ public class SubscriptionUtil {
private static int getDefaultDataSubscriptionId() {
return SubscriptionManager.getDefaultDataSubscriptionId();
}
+
+
+ /**
+ * Select one of the subscription as the default subscription.
+ * @param subAnnoList a list of {@link SubscriptionAnnotation}
+ * @return ideally the {@link SubscriptionAnnotation} as expected
+ */
+ private static SubscriptionAnnotation getDefaultSubscriptionSelection(
+ List subAnnoList) {
+ return (subAnnoList == null) ? null :
+ subAnnoList.stream()
+ .filter(SubscriptionAnnotation::isDisplayAllowed)
+ .filter(SubscriptionAnnotation::isActive)
+ .findFirst().orElse(null);
+ }
+
+ public static SubscriptionInfo getSubscriptionOrDefault(Context context, int subscriptionId) {
+ return getSubscription(context, subscriptionId,
+ (subscriptionId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) ? null : (
+ subAnnoList -> getDefaultSubscriptionSelection(subAnnoList)
+ ));
+ }
+
+ /**
+ * Get the current subscription to display. First check whether intent has {@link
+ * Settings#EXTRA_SUB_ID} and if so find the subscription with that id.
+ * If not, select default one based on {@link Function} provided.
+ *
+ * @param preferredSubscriptionId preferred subscription id
+ * @param selectionOfDefault when true current subscription is absent
+ */
+ private static SubscriptionInfo getSubscription(Context context, int preferredSubscriptionId,
+ Function, SubscriptionAnnotation> selectionOfDefault) {
+ List subList =
+ (new SelectableSubscriptions(context, true)).call();
+ Log.d(TAG, "get subId=" + preferredSubscriptionId + " from " + subList);
+ SubscriptionAnnotation currentSubInfo = subList.stream()
+ .filter(SubscriptionAnnotation::isDisplayAllowed)
+ .filter(subAnno -> (subAnno.getSubscriptionId() == preferredSubscriptionId))
+ .findFirst().orElse(null);
+ if ((currentSubInfo == null) && (selectionOfDefault != null)) {
+ currentSubInfo = selectionOfDefault.apply(subList);
+ }
+ return (currentSubInfo == null) ? null : currentSubInfo.getSubInfo();
+ }
}
diff --git a/src/com/android/settings/network/SubscriptionsPreferenceController.java b/src/com/android/settings/network/SubscriptionsPreferenceController.java
index 554188872ff..87c46974fb9 100644
--- a/src/com/android/settings/network/SubscriptionsPreferenceController.java
+++ b/src/com/android/settings/network/SubscriptionsPreferenceController.java
@@ -55,7 +55,6 @@ import androidx.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.network.telephony.DataConnectivityListener;
-import com.android.settings.network.telephony.MobileNetworkActivity;
import com.android.settings.network.telephony.MobileNetworkUtils;
import com.android.settings.network.telephony.SignalStrengthListener;
import com.android.settings.network.telephony.TelephonyDisplayInfoListener;
@@ -237,7 +236,7 @@ public class SubscriptionsPreferenceController extends AbstractPreferenceControl
});
mSubsGearPref.setOnGearClickListener(p ->
- startMobileNetworkActivity(mContext, subInfo.getSubscriptionId()));
+ MobileNetworkUtils.launchMobileNetworkSettings(mContext, subInfo));
}
if (!(mContext.getSystemService(UserManager.class)).isAdminUser()) {
@@ -335,14 +334,6 @@ public class SubscriptionsPreferenceController extends AbstractPreferenceControl
mSubsGearPref.setSummary("");
}
- private static void startMobileNetworkActivity(Context context, int subId) {
- final Intent intent = new Intent(context, MobileNetworkActivity.class);
- intent.putExtra(Settings.EXTRA_SUB_ID, subId);
- // MobileNetworkActivity is singleTask, set SplitPairRule to show in 2-pane.
- MobileNetworkTwoPaneUtils.registerTwoPaneForMobileNetwork(context, intent, null);
- context.startActivity(intent);
- }
-
@VisibleForTesting
boolean shouldInflateSignalStrength(int subId) {
return SignalStrengthUtil.shouldInflateSignalStrength(mContext, subId);
diff --git a/src/com/android/settings/network/telephony/MobileNetworkActivity.java b/src/com/android/settings/network/telephony/MobileNetworkActivity.java
index bbff57d56ec..d3ff5469921 100644
--- a/src/com/android/settings/network/telephony/MobileNetworkActivity.java
+++ b/src/com/android/settings/network/telephony/MobileNetworkActivity.java
@@ -18,8 +18,8 @@ package com.android.settings.network.telephony;
import static com.android.settings.SettingsActivity.EXTRA_FRAGMENT_ARG_KEY;
-import android.app.ActionBar;
-import android.content.Context;
+import android.app.Activity;
+import android.app.settings.SettingsEnums;
import android.content.Intent;
import android.os.Bundle;
import android.os.UserManager;
@@ -29,84 +29,27 @@ import android.telephony.SubscriptionManager;
import android.telephony.ims.ImsRcsManager;
import android.text.TextUtils;
import android.util.Log;
-import android.view.View;
-import android.widget.Toolbar;
-import androidx.annotation.NonNull;
-import androidx.annotation.VisibleForTesting;
-import androidx.fragment.app.Fragment;
-import androidx.fragment.app.FragmentManager;
-import androidx.fragment.app.FragmentTransaction;
-import androidx.lifecycle.Lifecycle;
-import com.android.settings.R;
-import com.android.settings.core.SettingsBaseActivity;
-import com.android.settings.network.ProxySubscriptionManager;
+import com.android.settings.SettingsActivity;
+import com.android.settings.Utils;
+import com.android.settings.activityembedding.ActivityEmbeddingUtils;
import com.android.settings.network.SubscriptionUtil;
-import com.android.settings.network.helper.SelectableSubscriptions;
-import com.android.settings.network.helper.SubscriptionAnnotation;
-
-import java.util.List;
-import java.util.function.Function;
/**
- * Activity for displaying MobileNetworkSettings
+ * Activity for displaying MobileNetworkSettings.
+ *
+ * @Deprecated The MobileNetworkActivity should be removed in Android U. Instead of using the
+ * singleTask activity which will cause an additional window transition when users launch the SIMs
+ * page, using the {@link com.android.settings.Settings.SubscriptionSettingsActivity} which can be
+ * managed by {@link SettingsActivity} and be migrated into the Settings architecture.
*/
-public class MobileNetworkActivity extends SettingsBaseActivity
- implements ProxySubscriptionManager.OnActiveSubscriptionChangedListener {
+@Deprecated
+public class MobileNetworkActivity extends Activity {
private static final String TAG = "MobileNetworkActivity";
- @VisibleForTesting
- static final String MOBILE_SETTINGS_TAG = "mobile_settings:";
- @VisibleForTesting
- static final int SUB_ID_NULL = Integer.MIN_VALUE;
-
- @VisibleForTesting
- ProxySubscriptionManager mProxySubscriptionMgr;
-
- private int mCurSubscriptionId = SUB_ID_NULL;
-
- // This flag forces subscription information fragment to be re-created.
- // Otherwise, fragment will be kept when subscription id has not been changed.
- //
- // Set initial value to true allows subscription information fragment to be re-created when
- // Activity re-create occur.
- private boolean mPendingSubscriptionChange = true;
-
- @Override
- protected void onNewIntent(Intent intent) {
- super.onNewIntent(intent);
- validate(intent);
- setIntent(intent);
-
- int updateSubscriptionIndex = mCurSubscriptionId;
- if (intent != null) {
- updateSubscriptionIndex = intent.getIntExtra(Settings.EXTRA_SUB_ID, SUB_ID_NULL);
- }
- SubscriptionInfo info = getSubscriptionOrDefault(updateSubscriptionIndex);
- if (info == null) {
- Log.d(TAG, "Invalid subId request " + mCurSubscriptionId
- + " -> " + updateSubscriptionIndex);
- return;
- }
-
- int oldSubId = mCurSubscriptionId;
- updateSubscriptions(info, null);
-
- // If the subscription has changed or the new intent doesnt contain the opt in action,
- // remove the old discovery dialog. If the activity is being recreated, we will see
- // onCreate -> onNewIntent, so the dialog will first be recreated for the old subscription
- // and then removed.
- if (mCurSubscriptionId != oldSubId || !doesIntentContainOptInAction(intent)) {
- removeContactDiscoveryDialog(oldSubId);
- }
- // evaluate showing the new discovery dialog if this intent contains an action to show the
- // opt-in.
- if (doesIntentContainOptInAction(intent)) {
- maybeShowContactDiscoveryDialog(info);
- }
- }
-
+ public static final String SHOW_CAPABILITY_DISCOVERY_OPT_IN =
+ "show_capability_discovery_opt_in";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -116,318 +59,63 @@ public class MobileNetworkActivity extends SettingsBaseActivity
return;
}
- final Toolbar toolbar = findViewById(R.id.action_bar);
- toolbar.setVisibility(View.VISIBLE);
- setActionBar(toolbar);
-
- final ActionBar actionBar = getActionBar();
- if (actionBar != null) {
- actionBar.setDisplayHomeAsUpEnabled(true);
- actionBar.setDisplayShowTitleEnabled(true);
- }
-
- getProxySubscriptionManager().setLifecycle(getLifecycle());
-
- final Intent startIntent = getIntent();
- validate(startIntent);
- mCurSubscriptionId = savedInstanceState != null
- ? savedInstanceState.getInt(Settings.EXTRA_SUB_ID, SUB_ID_NULL)
- : ((startIntent != null)
- ? startIntent.getIntExtra(Settings.EXTRA_SUB_ID, SUB_ID_NULL)
- : SUB_ID_NULL);
- // perform registration after mCurSubscriptionId been configured.
- registerActiveSubscriptionsListener();
-
- SubscriptionInfo subscription = getSubscriptionOrDefault(mCurSubscriptionId);
- if (subscription == null) {
- Log.d(TAG, "Invalid subId request " + mCurSubscriptionId);
- tryToFinishActivity();
+ // TODO: Move these intent's extra into SubscriptionSettingsActivity if the
+ // MobileNetworkActivity is removed in Android U.
+ Intent intent = getIntent();
+ if (intent == null) {
+ Log.d(TAG, "onCreate(), intent = null");
+ this.finish();
return;
}
- maybeShowContactDiscoveryDialog(subscription);
-
- updateSubscriptions(subscription, null);
- }
-
- @VisibleForTesting
- ProxySubscriptionManager getProxySubscriptionManager() {
- if (mProxySubscriptionMgr == null) {
- mProxySubscriptionMgr = ProxySubscriptionManager.getInstance(this);
- }
- return mProxySubscriptionMgr;
- }
-
- @VisibleForTesting
- void registerActiveSubscriptionsListener() {
- getProxySubscriptionManager().addActiveSubscriptionsListener(this);
- }
-
- /**
- * Implementation of ProxySubscriptionManager.OnActiveSubscriptionChangedListener
- */
- public void onChanged() {
- mPendingSubscriptionChange = false;
-
- if (mCurSubscriptionId == SUB_ID_NULL) {
- return;
+ Intent trampolineIntent;
+ final Intent subscriptionSettingsIntent = new Intent(this,
+ com.android.settings.Settings.SubscriptionSettingsActivity.class);
+ if (!ActivityEmbeddingUtils.isEmbeddingActivityEnabled(this) || !isTaskRoot()) {
+ trampolineIntent = subscriptionSettingsIntent;
+ } else {
+ trampolineIntent = new Intent(Settings.ACTION_SETTINGS_EMBED_DEEP_LINK_ACTIVITY)
+ .setPackage(Utils.SETTINGS_PACKAGE_NAME);
+ trampolineIntent.putExtra(
+ android.provider.Settings.EXTRA_SETTINGS_EMBEDDED_DEEP_LINK_INTENT_URI,
+ subscriptionSettingsIntent.toUri(Intent.URI_INTENT_SCHEME));
}
- if (!getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED)) {
- mPendingSubscriptionChange = true;
- return;
+ int subId = intent.getIntExtra(Settings.EXTRA_SUB_ID,
+ SubscriptionManager.INVALID_SUBSCRIPTION_ID);
+ SubscriptionInfo subInfo = SubscriptionUtil.getSubscriptionOrDefault(this, subId);
+ CharSequence title = SubscriptionUtil.getUniqueSubscriptionDisplayName(subInfo, this);
+ trampolineIntent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE, title);
+ trampolineIntent.putExtra(Settings.EXTRA_SUB_ID, subId);
+ if (Settings.ACTION_MMS_MESSAGE_SETTING.equals(intent.getAction())) {
+ // highlight "mms_message" preference.
+ trampolineIntent.putExtra(EXTRA_FRAGMENT_ARG_KEY, "mms_message");
}
- SubscriptionInfo subInfo = getSubscription(mCurSubscriptionId, null);
- if (subInfo != null) {
- if (mCurSubscriptionId != subInfo.getSubscriptionId()) {
- // update based on subscription status change
- removeContactDiscoveryDialog(mCurSubscriptionId);
- updateSubscriptions(subInfo, null);
- }
- return;
+ if (doesIntentContainOptInAction(intent)) {
+ trampolineIntent.putExtra(SHOW_CAPABILITY_DISCOVERY_OPT_IN,
+ maybeShowContactDiscoveryDialog(subId));
}
- Log.w(TAG, "subId missing: " + mCurSubscriptionId);
-
- // When UI is not the active one, avoid from destroy it immediately
- // but wait until onResume() to see if subscription back online again.
- // This is to avoid from glitch behavior of subscription which changes
- // the UI when UI is considered as in the background or only partly
- // visible.
- if (!getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.RESUMED)) {
- mPendingSubscriptionChange = true;
- return;
- }
-
- // Subscription could be missing
- tryToFinishActivity();
- }
-
- protected void runSubscriptionUpdate(Runnable onUpdateRemaining) {
- SubscriptionInfo subInfo = getSubscription(mCurSubscriptionId, null);
- if (subInfo == null) {
- onUpdateRemaining.run();
- tryToFinishActivity();
- return;
- }
- if (mCurSubscriptionId != subInfo.getSubscriptionId()) {
- removeContactDiscoveryDialog(mCurSubscriptionId);
- updateSubscriptions(subInfo, null);
- }
- onUpdateRemaining.run();
- }
-
- protected void tryToFinishActivity() {
- if ((!isFinishing()) && (!isDestroyed())) {
+ startActivity(trampolineIntent);
+ if (isTaskRoot()) {
+ finishAndRemoveTask();
+ } else {
finish();
}
}
- @Override
- protected void onStart() {
- getProxySubscriptionManager().setLifecycle(getLifecycle());
- if (mPendingSubscriptionChange) {
- mPendingSubscriptionChange = false;
- runSubscriptionUpdate(() -> super.onStart());
- return;
- }
- super.onStart();
- }
-
- @Override
- protected void onResume() {
- if (mPendingSubscriptionChange) {
- mPendingSubscriptionChange = false;
- runSubscriptionUpdate(() -> super.onResume());
- return;
- }
- super.onResume();
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- if (mProxySubscriptionMgr == null) {
- return;
- }
- mProxySubscriptionMgr.removeActiveSubscriptionsListener(this);
- }
-
- @Override
- protected void onSaveInstanceState(@NonNull Bundle outState) {
- super.onSaveInstanceState(outState);
- saveInstanceState(outState);
- }
-
- @VisibleForTesting
- void saveInstanceState(@NonNull Bundle outState) {
- outState.putInt(Settings.EXTRA_SUB_ID, mCurSubscriptionId);
- }
-
- private void updateTitleAndNavigation(SubscriptionInfo subscription) {
- // Set the title to the name of the subscription. If we don't have subscription info, the
- // title will just default to the label for this activity that's already specified in
- // AndroidManifest.xml.
- if (subscription != null) {
- setTitle(SubscriptionUtil.getUniqueSubscriptionDisplayName(subscription, this));
- }
- }
-
- @VisibleForTesting
- void updateSubscriptions(SubscriptionInfo subscription, Bundle savedInstanceState) {
- if (subscription == null) {
- return;
- }
- final int subscriptionIndex = subscription.getSubscriptionId();
-
- updateTitleAndNavigation(subscription);
- if (savedInstanceState == null) {
- switchFragment(subscription);
- }
-
- mCurSubscriptionId = subscriptionIndex;
- }
-
- /**
- * Select one of the subscription as the default subscription.
- * @param subAnnoList a list of {@link SubscriptionAnnotation}
- * @return ideally the {@link SubscriptionAnnotation} as expected
- */
- protected SubscriptionAnnotation defaultSubscriptionSelection(
- List subAnnoList) {
- return (subAnnoList == null) ? null :
- subAnnoList.stream()
- .filter(SubscriptionAnnotation::isDisplayAllowed)
- .filter(SubscriptionAnnotation::isActive)
- .findFirst().orElse(null);
- }
-
- protected SubscriptionInfo getSubscriptionOrDefault(int subscriptionId) {
- return getSubscription(subscriptionId,
- (subscriptionId != SUB_ID_NULL) ? null : (
- subAnnoList -> defaultSubscriptionSelection(subAnnoList)
- ));
- }
-
- /**
- * Get the current subscription to display. First check whether intent has {@link
- * Settings#EXTRA_SUB_ID} and if so find the subscription with that id.
- * If not, select default one based on {@link Function} provided.
- *
- * @param preferredSubscriptionId preferred subscription id
- * @param selectionOfDefault when true current subscription is absent
- */
- @VisibleForTesting
- protected SubscriptionInfo getSubscription(int preferredSubscriptionId,
- Function, SubscriptionAnnotation> selectionOfDefault) {
- List subList =
- (new SelectableSubscriptions(this, true)).call();
- Log.d(TAG, "get subId=" + preferredSubscriptionId + " from " + subList);
- SubscriptionAnnotation currentSubInfo = subList.stream()
- .filter(SubscriptionAnnotation::isDisplayAllowed)
- .filter(subAnno -> (subAnno.getSubscriptionId() == preferredSubscriptionId))
- .findFirst().orElse(null);
- if ((currentSubInfo == null) && (selectionOfDefault != null)) {
- currentSubInfo = selectionOfDefault.apply(subList);
- }
- return (currentSubInfo == null) ? null : currentSubInfo.getSubInfo();
- }
-
- @VisibleForTesting
- SubscriptionInfo getSubscriptionForSubId(int subId) {
- return SubscriptionUtil.getAvailableSubscription(this,
- getProxySubscriptionManager(), subId);
- }
-
- @VisibleForTesting
- void switchFragment(SubscriptionInfo subInfo) {
- final FragmentManager fragmentManager = getSupportFragmentManager();
- final FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
-
- final int subId = subInfo.getSubscriptionId();
- final Intent intent = getIntent();
- final Bundle bundle = new Bundle();
- bundle.putInt(Settings.EXTRA_SUB_ID, subId);
- if (intent != null && Settings.ACTION_MMS_MESSAGE_SETTING.equals(intent.getAction())) {
- // highlight "mms_message" preference.
- bundle.putString(EXTRA_FRAGMENT_ARG_KEY, "mms_message");
- }
-
- final String fragmentTag = buildFragmentTag(subId);
- if (fragmentManager.findFragmentByTag(fragmentTag) != null) {
- Log.d(TAG, "Construct fragment: " + fragmentTag);
- }
-
- final Fragment fragment = new MobileNetworkSettings();
- fragment.setArguments(bundle);
- fragmentTransaction.replace(R.id.content_frame, fragment, fragmentTag);
- fragmentTransaction.commitAllowingStateLoss();
- }
-
- private void removeContactDiscoveryDialog(int subId) {
- ContactDiscoveryDialogFragment fragment = getContactDiscoveryFragment(subId);
- if (fragment != null) {
- fragment.dismiss();
- }
- }
-
- private ContactDiscoveryDialogFragment getContactDiscoveryFragment(int subId) {
- // In the case that we are rebuilding this activity after it has been destroyed and
- // recreated, look up the dialog in the fragment manager.
- return (ContactDiscoveryDialogFragment) getSupportFragmentManager()
- .findFragmentByTag(ContactDiscoveryDialogFragment.getFragmentTag(subId));
- }
-
- private void maybeShowContactDiscoveryDialog(SubscriptionInfo info) {
- int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
- CharSequence carrierName = "";
- if (info != null) {
- subId = info.getSubscriptionId();
- carrierName = SubscriptionUtil.getUniqueSubscriptionDisplayName(info, this);
- }
+ private boolean maybeShowContactDiscoveryDialog(int subId) {
// If this activity was launched using ACTION_SHOW_CAPABILITY_DISCOVERY_OPT_IN, show the
// associated dialog only if the opt-in has not been granted yet.
- boolean showOptInDialog = doesIntentContainOptInAction(getIntent())
- // has the carrier config enabled capability discovery?
- && MobileNetworkUtils.isContactDiscoveryVisible(this, subId)
+ return MobileNetworkUtils.isContactDiscoveryVisible(this, subId)
// has the user already enabled this configuration?
&& !MobileNetworkUtils.isContactDiscoveryEnabled(this, subId);
- ContactDiscoveryDialogFragment fragment = getContactDiscoveryFragment(subId);
- if (showOptInDialog) {
- if (fragment == null) {
- fragment = ContactDiscoveryDialogFragment.newInstance(subId, carrierName);
- }
- // Only try to show the dialog if it has not already been added, otherwise we may
- // accidentally add it multiple times, causing multiple dialogs.
- if (!fragment.isAdded()) {
- fragment.show(getSupportFragmentManager(),
- ContactDiscoveryDialogFragment.getFragmentTag(subId));
- }
- }
}
- private boolean doesIntentContainOptInAction(Intent intent) {
+ public static boolean doesIntentContainOptInAction(Intent intent) {
String intentAction = (intent != null ? intent.getAction() : null);
return TextUtils.equals(intentAction,
ImsRcsManager.ACTION_SHOW_CAPABILITY_DISCOVERY_OPT_IN);
}
-
- private void validate(Intent intent) {
- // Do not allow ACTION_SHOW_CAPABILITY_DISCOVERY_OPT_IN without a subscription id specified,
- // since we do not want the user to accidentally turn on capability polling for the wrong
- // subscription.
- if (doesIntentContainOptInAction(intent)) {
- if (SUB_ID_NULL == intent.getIntExtra(Settings.EXTRA_SUB_ID, SUB_ID_NULL)) {
- throw new IllegalArgumentException("Intent with action "
- + "SHOW_CAPABILITY_DISCOVERY_OPT_IN must also include the extra "
- + "Settings#EXTRA_SUB_ID");
- }
- }
- }
-
- @VisibleForTesting
- String buildFragmentTag(int subscriptionId) {
- return MOBILE_SETTINGS_TAG + subscriptionId;
- }
}
diff --git a/src/com/android/settings/network/telephony/MobileNetworkSettings.java b/src/com/android/settings/network/telephony/MobileNetworkSettings.java
index ba80a8ce659..cf0f889befd 100644
--- a/src/com/android/settings/network/telephony/MobileNetworkSettings.java
+++ b/src/com/android/settings/network/telephony/MobileNetworkSettings.java
@@ -23,8 +23,10 @@ import android.content.Intent;
import android.os.Bundle;
import android.os.UserManager;
import android.provider.Settings;
+import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
+import android.telephony.ims.ImsRcsManager;
import android.text.TextUtils;
import android.util.Log;
import android.view.Menu;
@@ -39,6 +41,7 @@ import com.android.settings.datausage.BillingCyclePreferenceController;
import com.android.settings.datausage.DataUsageSummaryPreferenceController;
import com.android.settings.network.ActiveSubscriptionsListener;
import com.android.settings.network.CarrierWifiTogglePreferenceController;
+import com.android.settings.network.SubscriptionUtil;
import com.android.settings.network.telephony.cdma.CdmaSubscriptionPreferenceController;
import com.android.settings.network.telephony.cdma.CdmaSystemSelectPreferenceController;
import com.android.settings.network.telephony.gsm.AutoSelectPreferenceController;
@@ -115,9 +118,16 @@ public class MobileNetworkSettings extends AbstractMobileNetworkSettings {
@Override
protected List createPreferenceControllers(Context context) {
- mSubId = getArguments().getInt(Settings.EXTRA_SUB_ID,
- MobileNetworkUtils.getSearchableSubscriptionId(context));
- Log.i(LOG_TAG, "display subId: " + mSubId);
+ Intent intent = getIntent();
+ if (intent != null) {
+ mSubId = intent.getIntExtra(Settings.EXTRA_SUB_ID,
+ MobileNetworkUtils.getSearchableSubscriptionId(context));
+ Log.i(LOG_TAG, "display subId from intent: " + mSubId);
+ } else {
+ mSubId = getArguments().getInt(Settings.EXTRA_SUB_ID,
+ MobileNetworkUtils.getSearchableSubscriptionId(context));
+ Log.i(LOG_TAG, "display subId from getArguments(): " + mSubId);
+ }
if (!SubscriptionManager.isValidSubscriptionId(mSubId)) {
return Arrays.asList();
@@ -131,6 +141,30 @@ public class MobileNetworkSettings extends AbstractMobileNetworkSettings {
public void onAttach(Context context) {
super.onAttach(context);
+ Intent intent = getIntent();
+ SubscriptionInfo info = SubscriptionUtil.getSubscriptionOrDefault(context, mSubId);
+ if (info == null) {
+ Log.d(LOG_TAG, "Invalid subId request " + mSubId);
+ return;
+ }
+
+ int oldSubId = mSubId;
+ updateSubscriptions(info);
+ // If the subscription has changed or the new intent does not contain the opt in action,
+ // remove the old discovery dialog. If the activity is being recreated, we will see
+ // onCreate -> onNewIntent, so the dialog will first be recreated for the old subscription
+ // and then removed.
+ if (!MobileNetworkActivity.doesIntentContainOptInAction(intent)) {
+ removeContactDiscoveryDialog(oldSubId);
+ }
+
+ // evaluate showing the new discovery dialog if this intent contains an action to show the
+ // opt-in.
+ if (MobileNetworkActivity.doesIntentContainOptInAction(intent)) {
+ showContactDiscoveryDialog(
+ SubscriptionUtil.getSubscriptionOrDefault(context, mSubId));
+ }
+
final DataUsageSummaryPreferenceController dataUsageSummaryPreferenceController =
use(DataUsageSummaryPreferenceController.class);
if (dataUsageSummaryPreferenceController != null) {
@@ -339,4 +373,49 @@ public class MobileNetworkSettings extends AbstractMobileNetworkSettings {
return context.getSystemService(UserManager.class).isAdminUser();
}
};
+
+ private ContactDiscoveryDialogFragment getContactDiscoveryFragment(int subId) {
+ // In the case that we are rebuilding this activity after it has been destroyed and
+ // recreated, look up the dialog in the fragment manager.
+ return (ContactDiscoveryDialogFragment) getChildFragmentManager()
+ .findFragmentByTag(ContactDiscoveryDialogFragment.getFragmentTag(subId));
+ }
+
+
+ private void removeContactDiscoveryDialog(int subId) {
+ ContactDiscoveryDialogFragment fragment = getContactDiscoveryFragment(subId);
+ if (fragment != null) {
+ fragment.dismiss();
+ }
+ }
+
+ private void showContactDiscoveryDialog(SubscriptionInfo info) {
+ if (info == null) {
+ Log.d(LOG_TAG, "Invalid subId request " + mSubId);
+ onDestroy();
+ return;
+ }
+
+ CharSequence carrierName = SubscriptionUtil.getUniqueSubscriptionDisplayName(info,
+ getContext());
+ ContactDiscoveryDialogFragment fragment = getContactDiscoveryFragment(mSubId);
+ if (fragment == null) {
+ fragment = ContactDiscoveryDialogFragment.newInstance(mSubId, carrierName);
+ }
+ // Only try to show the dialog if it has not already been added, otherwise we may
+ // accidentally add it multiple times, causing multiple dialogs.
+ if (!fragment.isAdded()) {
+ fragment.show(getChildFragmentManager(),
+ ContactDiscoveryDialogFragment.getFragmentTag(mSubId));
+ }
+ }
+
+ private void updateSubscriptions(SubscriptionInfo subscription) {
+ if (subscription == null) {
+ return;
+ }
+ final int subscriptionIndex = subscription.getSubscriptionId();
+
+ mSubId = subscriptionIndex;
+ }
}
diff --git a/src/com/android/settings/network/telephony/MobileNetworkUtils.java b/src/com/android/settings/network/telephony/MobileNetworkUtils.java
index 658f65090a1..e2d158dfe5d 100644
--- a/src/com/android/settings/network/telephony/MobileNetworkUtils.java
+++ b/src/com/android/settings/network/telephony/MobileNetworkUtils.java
@@ -45,6 +45,7 @@ import android.graphics.drawable.LayerDrawable;
import android.net.ConnectivityManager;
import android.net.Network;
import android.net.NetworkCapabilities;
+import android.os.Bundle;
import android.os.PersistableBundle;
import android.os.SystemClock;
import android.os.SystemProperties;
@@ -73,9 +74,11 @@ import com.android.internal.util.ArrayUtils;
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.core.BasePreferenceController;
+import com.android.settings.core.SubSettingLauncher;
import com.android.settings.network.SubscriptionUtil;
import com.android.settings.network.ims.WifiCallingQueryImsState;
import com.android.settings.network.telephony.TelephonyConstants.TelephonyManagerConstants;
+import com.android.settingslib.core.instrumentation.Instrumentable;
import com.android.settingslib.development.DevelopmentSettingsEnabler;
import com.android.settingslib.graph.SignalDrawable;
import com.android.settingslib.utils.ThreadUtils;
@@ -1008,4 +1011,21 @@ public class MobileNetworkUtils {
return context.getResources().getString(resId);
}
+ public static void launchMobileNetworkSettings(Context context, SubscriptionInfo info) {
+ final int subId = info.getSubscriptionId();
+ if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
+ Log.d(TAG, "launchMobileNetworkSettings fail, subId is invalid");
+ return;
+ }
+
+ final Bundle extra = new Bundle();
+ extra.putInt(Settings.EXTRA_SUB_ID, subId);
+ new SubSettingLauncher(context)
+ .setTitleText(SubscriptionUtil.getUniqueSubscriptionDisplayName(info, context))
+ .setDestination(MobileNetworkSettings.class.getCanonicalName())
+ .setSourceMetricsCategory(Instrumentable.METRICS_CATEGORY_UNKNOWN)
+ .setArguments(extra)
+ .launch();
+ }
+
}
diff --git a/tests/robotests/src/com/android/settings/network/telephony/MobileNetworkActivityTest.java b/tests/robotests/src/com/android/settings/network/telephony/MobileNetworkActivityTest.java
index 459d77ea867..5729208ecfe 100644
--- a/tests/robotests/src/com/android/settings/network/telephony/MobileNetworkActivityTest.java
+++ b/tests/robotests/src/com/android/settings/network/telephony/MobileNetworkActivityTest.java
@@ -16,13 +16,10 @@
package com.android.settings.network.telephony;
-import static androidx.lifecycle.Lifecycle.State;
import static com.google.common.truth.Truth.assertThat;
-import static org.mockito.Mockito.anyInt;
import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
import static org.robolectric.Shadows.shadowOf;
import android.content.Context;
@@ -30,21 +27,17 @@ import android.content.Intent;
import android.os.Bundle;
import android.os.UserManager;
import android.provider.Settings;
-import android.telephony.CarrierConfigManager;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyManager;
import androidx.test.core.app.ActivityScenario;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
-import com.android.internal.telephony.TelephonyIntents;
-import com.android.settings.network.ProxySubscriptionManager;
+import com.android.settings.SettingsActivity;
import org.junit.After;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -58,22 +51,16 @@ import org.robolectric.shadows.ShadowSubscriptionManager.SubscriptionInfoBuilder
@RunWith(AndroidJUnit4.class)
public class MobileNetworkActivityTest {
- private static final int CURRENT_SUB_ID = 3;
- private static final int PREV_SUB_ID = 1;
+ private static final int SUB_ID = 1;
+ private static final String DISPLAY_NAME = "SUB_ID";
private Context mContext;
private ShadowContextImpl mShadowContextImpl;
private Intent mTestIntent;
-
@Mock
private UserManager mUserManager;
- @Mock
- private TelephonyManager mTelephonyManager;
-
private ShadowSubscriptionManager mSubscriptionManager;
- private SubscriptionInfo mSubscriptionInfo1;
- private SubscriptionInfo mSubscriptionInfo2;
-
+ private SubscriptionInfo mSubscriptionInfo;
private ActivityScenario mMobileNetworkActivity;
@Before
@@ -82,20 +69,16 @@ public class MobileNetworkActivityTest {
mContext = ApplicationProvider.getApplicationContext();
mShadowContextImpl = Shadow.extract(RuntimeEnvironment.application.getBaseContext());
-
+ mSubscriptionManager = shadowOf(mContext.getSystemService(SubscriptionManager.class));
mShadowContextImpl.setSystemService(Context.USER_SERVICE, mUserManager);
doReturn(true).when(mUserManager).isAdminUser();
- mShadowContextImpl.setSystemService(Context.TELEPHONY_SERVICE, mTelephonyManager);
- doReturn(mTelephonyManager).when(mTelephonyManager).createForSubscriptionId(anyInt());
-
- mTestIntent = new Intent(mContext, MockMobileNetworkActivity.class);
-
- mSubscriptionManager = shadowOf(mContext.getSystemService(SubscriptionManager.class));
- mSubscriptionInfo1 = SubscriptionInfoBuilder.newBuilder()
- .setId(PREV_SUB_ID).buildSubscriptionInfo();
- mSubscriptionInfo2 = SubscriptionInfoBuilder.newBuilder()
- .setId(CURRENT_SUB_ID).buildSubscriptionInfo();
+ mTestIntent = new Intent(mContext, MobileNetworkActivity.class);
+ mSubscriptionInfo = SubscriptionInfoBuilder.newBuilder()
+ .setId(SUB_ID).setDisplayName(DISPLAY_NAME).buildSubscriptionInfo();
+ mTestIntent.putExtra(Settings.EXTRA_SUB_ID, SUB_ID);
+ mTestIntent.putExtra(SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE,
+ mSubscriptionInfo.getDisplayName());
}
@After
@@ -105,116 +88,21 @@ public class MobileNetworkActivityTest {
}
}
- private static class MockMobileNetworkActivity extends MobileNetworkActivity {
- private MockMobileNetworkActivity() {
- super();
- }
-
- private SubscriptionInfo mSubscriptionInFragment;
-
- @Override
- ProxySubscriptionManager getProxySubscriptionManager() {
- if (mProxySubscriptionMgr == null) {
- mProxySubscriptionMgr = mock(ProxySubscriptionManager.class);
- }
- return mProxySubscriptionMgr;
- }
-
- @Override
- void registerActiveSubscriptionsListener() {
- onChanged();
- }
-
- @Override
- void switchFragment(SubscriptionInfo subInfo) {
- mSubscriptionInFragment = subInfo;
- }
- }
-
private ActivityScenario createTargetActivity(Intent activityIntent) {
return ActivityScenario.launch(activityIntent);
}
@Test
- @Ignore
- public void updateBottomNavigationView_oneSubscription_shouldNotCrash() {
- mSubscriptionManager.setActiveSubscriptionInfos(mSubscriptionInfo1);
-
+ public void onCreate_getExtraFromIntent() {
+ mSubscriptionManager.setActiveSubscriptionInfos(mSubscriptionInfo);
mMobileNetworkActivity = createTargetActivity(mTestIntent);
- mMobileNetworkActivity.moveToState(State.STARTED);
- }
-
- @Test
- @Ignore
- public void updateBottomNavigationView_twoSubscription_shouldNotCrash() {
- mSubscriptionManager.setActiveSubscriptionInfos(mSubscriptionInfo1, mSubscriptionInfo2);
-
- mMobileNetworkActivity = createTargetActivity(mTestIntent);
-
- mMobileNetworkActivity.moveToState(State.STARTED);
- }
-
- @Test
- @Ignore
- public void switchFragment_switchBetweenTwoSubscriptions() {
- mSubscriptionManager.setActiveSubscriptionInfos(mSubscriptionInfo1, mSubscriptionInfo2);
-
- mTestIntent.putExtra(Settings.EXTRA_SUB_ID, PREV_SUB_ID);
- mMobileNetworkActivity = createTargetActivity(mTestIntent);
-
- mMobileNetworkActivity.moveToState(State.STARTED);
-
- mMobileNetworkActivity.onActivity(activity -> {
- final MockMobileNetworkActivity mockActivity = (MockMobileNetworkActivity) activity;
- mockActivity.switchFragment(mSubscriptionInfo1);
- assertThat(mockActivity.mSubscriptionInFragment).isEqualTo(mSubscriptionInfo1);
- });
- }
-
- @Test
- @Ignore
- public void switchFragment_subscriptionsUpdate_notifyByIntent() {
- mSubscriptionManager.setActiveSubscriptionInfos(mSubscriptionInfo1, mSubscriptionInfo2);
-
- mTestIntent.putExtra(Settings.EXTRA_SUB_ID, PREV_SUB_ID);
- mMobileNetworkActivity = createTargetActivity(mTestIntent);
-
- mMobileNetworkActivity.moveToState(State.STARTED);
-
- mMobileNetworkActivity.onActivity(activity -> {
- final MockMobileNetworkActivity mockActivity = (MockMobileNetworkActivity) activity;
- mockActivity.switchFragment(mSubscriptionInfo1);
- assertThat(mockActivity.mSubscriptionInFragment).isEqualTo(mSubscriptionInfo1);
-
- mContext.sendBroadcast(new Intent(
- CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED), null);
-
- mockActivity.switchFragment(mSubscriptionInfo2);
- assertThat(mockActivity.mSubscriptionInFragment).isEqualTo(mSubscriptionInfo2);
-
- mContext.sendBroadcast(new Intent(
- TelephonyIntents.ACTION_RADIO_TECHNOLOGY_CHANGED), null);
-
- mockActivity.switchFragment(mSubscriptionInfo1);
- assertThat(mockActivity.mSubscriptionInFragment).isEqualTo(mSubscriptionInfo1);
- });
- }
-
- @Test
- @Ignore
- public void onSaveInstanceState_saveCurrentSubId() {
- mSubscriptionManager.setActiveSubscriptionInfos(mSubscriptionInfo1, mSubscriptionInfo2);
-
- mTestIntent.putExtra(Settings.EXTRA_SUB_ID, PREV_SUB_ID);
- mMobileNetworkActivity = createTargetActivity(mTestIntent);
-
- mMobileNetworkActivity.moveToState(State.STARTED);
-
mMobileNetworkActivity.onActivity(activity -> {
final Bundle bundle = new Bundle();
- activity.saveInstanceState(bundle);
- assertThat(bundle.getInt(Settings.EXTRA_SUB_ID)).isEqualTo(PREV_SUB_ID);
+ activity.onCreate(bundle);
+ assertThat(bundle.getInt(Settings.EXTRA_SUB_ID)).isEqualTo(SUB_ID);
+ assertThat(bundle.getString(SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE)).isEqualTo(
+ DISPLAY_NAME);
});
}
}
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);
+ }
+}