Snap for 8105868 from 031104f18e to tm-release

Change-Id: I1a2f9093e2702719cf9377db1575d7db87c83d0d
This commit is contained in:
Android Build Coastguard Worker
2022-01-22 04:09:11 +00:00
35 changed files with 1100 additions and 176 deletions

View File

@@ -1596,4 +1596,15 @@
<item>2</item>
<item>4</item>
</string-array>
<!-- All the preference when the open app supports TapPay -->
<string-array name="nfc_payment_favor">
<item>Always</item>
<item>Except when another payment app is open</item>
</string-array>
<!-- All the values of the preference when the open app supports TapPay -->
<string-array name="nfc_payment_favor_values">
<item>0</item>
<item>1</item>
</string-array>
</resources>

View File

@@ -573,4 +573,14 @@
<!-- Whether to give option to add restricted profiles -->
<bool name="config_offer_restricted_profiles">false</bool>
<!-- An array of packages for which Applications whose per-app locale cannot be changed. -->
<string-array name="config_disallowed_app_localeChange_packages" translatable="false">
<!--
<item>com.example.package.first</item>
<item>com.example.package.second</item>
<item>...</item>
-->
</string-array>
</resources>

View File

@@ -7596,7 +7596,25 @@
<string name="user_copy_apps_menu_title">Install available apps</string>
<!-- NFC payment settings --><skip/>
<!-- Title for NFC payment settings page [CHAR LIMIT=40] -->
<string name="nfc_payment_settings_title">Contactless payments</string>
<!-- Title for NFC default payment settings page [CHAR LIMIT=40] -->
<string name="nfc_default_payment_settings_title">Default payment app</string>
<!-- Text string explaining how Tap and Pay works [CHAR LIMIT=100] -->
<string name="nfc_default_payment_footer">To make a payment using a payment app, hold the back of your device to a payment terminal</string>
<!-- Text string linking to a page explaining how Tap and Pay works [CHAR LIMIT=40] -->
<string name="nfc_more_details">Learn more</string>
<!-- Strings shown in a dialog when a user tries to set a work app as a nfc default payment app --><skip/>
<!-- Title for the dialog [CHAR LIMIT=40] -->
<string name="nfc_default_payment_workapp_confirmation_title">Set work app as default payment app?</string>
<!-- Header text for the dialog [CHAR LIMIT=40] -->
<string name="nfc_default_payment_workapp_confirmation_message_title">To make a payment using a work app:</string>
<!-- Text string in the dialog [CHAR LIMIT=60] -->
<string name="nfc_default_payment_workapp_confirmation_message_1">work profile must be turned on.</string>
<!-- Text string in the dialog [CHAR LIMIT=60] -->
<string name="nfc_default_payment_workapp_confirmation_message_2">you\u2019ll need to enter your work profile lock if you have one.</string>
<!-- Caption for button linking to a page explaining how Tap and Pay works-->
<string name="nfc_payment_how_it_works">How it works</string>
<!-- String shown when there are no NFC payment applications installed -->
@@ -7608,7 +7626,9 @@
<!-- String indicating the label of the default payment app and a description of its state; eg Google Wallet - MasterCard 1234 -->
<string name="nfc_payment_app_and_desc"><xliff:g id="app">%1$s</xliff:g> - <xliff:g id="description">%2$s</xliff:g></string>
<!-- Header for what to do when the open app supports TapPay: use the default set app, or the open app -->
<string name="nfc_payment_use_default">Use default</string>
<string name="nfc_payment_use_default">Use default payment app</string>
<!-- Header for a dialog asking what to do when the open app supports TapPay [CHAR LIMIT=40] -->
<string name="nfc_payment_use_default_dialog">Use default payment app</string>
<!-- Always use the default app (independent of what app is open) -->
<string name="nfc_payment_favor_default">Always</string>
<!-- If open app supports TapPay, use that app instead of the default -->

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
android:title="@string/nfc_default_payment_settings_title"/>

View File

@@ -19,16 +19,17 @@
xmlns:settings="http://schemas.android.com/apk/res-auto"
android:title="@string/nfc_payment_settings_title">
<com.android.settings.nfc.NfcPaymentPreference
android:key="nfc_payment"
android:title="@string/nfc_payment_default"
android:dialogTitle="@string/nfc_payment_pay_with"
android:widgetLayout="@layout/preference_widget_gear"
settings:controller="com.android.settings.nfc.NfcPaymentPreferenceController"/>
<com.android.settings.widget.GearPreference
android:key="nfc_payment_app"
android:title="@string/nfc_default_payment_settings_title"
android:fragment="com.android.settings.nfc.DefaultPaymentSettings"/>
<DropDownPreference
<ListPreference
android:key="nfc_foreground"
android:title="@string/nfc_payment_use_default"
settings:controller="com.android.settings.nfc.NfcForegroundPreferenceController"/>
android:dialogTitle="@string/nfc_payment_use_default_dialog"
settings:controller="com.android.settings.nfc.NfcForegroundPreferenceController"
android:entries="@array/nfc_payment_favor"
android:entryValues="@array/nfc_payment_favor_values" />
</PreferenceScreen>

View File

@@ -0,0 +1,68 @@
/*
* Copyright (C) 2022 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;
import android.app.ActivityManager;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.util.Log;
import com.android.settings.R;
import com.android.settingslib.applications.ApplicationsState.AppEntry;
/** This class provides methods that help dealing with per app locale. */
public class AppLocaleUtil {
private static final String TAG = AppLocaleUtil.class.getSimpleName();
/**
* Decides the UI display of per app locale.
*/
public static boolean canDisplayLocaleUi(Context context, AppEntry app) {
return !isDisallowedPackage(context, app.info.packageName)
&& !isSignedWithPlatformKey(context, app.info.packageName)
&& app.hasLauncherEntry;
}
private static boolean isDisallowedPackage(Context context, String packageName) {
final String[] disallowedPackages = context.getResources().getStringArray(
R.array.config_disallowed_app_localeChange_packages);
for (String disallowedPackage : disallowedPackages) {
if (packageName.equals(disallowedPackage)) {
return true;
}
}
return false;
}
private static boolean isSignedWithPlatformKey(Context context, String packageName) {
PackageInfo packageInfo = null;
PackageManager packageManager = context.getPackageManager();
ActivityManager activityManager = context.getSystemService(ActivityManager.class);
try {
packageInfo = packageManager.getPackageInfoAsUser(
packageName, /* flags= */ 0,
activityManager.getCurrentUser());
} catch (PackageManager.NameNotFoundException ex) {
Log.e(TAG, "package not found: " + packageName);
}
if (packageInfo == null) {
return false;
}
return packageInfo.applicationInfo.isSignedWithPlatformKey();
}
}

View File

@@ -0,0 +1,77 @@
/*
* Copyright (C) 2022 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;
import android.content.Context;
import android.util.Log;
import com.android.settingslib.applications.ApplicationsState;
import com.android.settingslib.applications.ApplicationsState.AppEntry;
import com.android.settingslib.applications.ApplicationsState.AppFilter;
import java.util.List;
/**
* Creates a application filter to restrict UI display of applications.
* This is to avoid users from changing the per apps locale
* Also provides app filters that can use the info.
*/
public class AppStateLocaleBridge extends AppStateBaseBridge {
private static final String TAG = AppStateLocaleBridge.class.getSimpleName();
private final Context mContext;
public AppStateLocaleBridge(Context context, ApplicationsState appState,
Callback callback) {
super(appState, callback);
mContext = context;
}
@Override
protected void updateExtraInfo(AppEntry app, String packageName, int uid) {
app.extraInfo = AppLocaleUtil.canDisplayLocaleUi(mContext, app)
? Boolean.TRUE : Boolean.FALSE;
}
@Override
protected void loadAllExtraInfo() {
final List<AppEntry> allApps = mAppSession.getAllApps();
for (int i = 0; i < allApps.size(); i++) {
AppEntry app = allApps.get(i);
app.extraInfo = AppLocaleUtil.canDisplayLocaleUi(mContext, app)
? Boolean.TRUE : Boolean.FALSE;
}
}
/** For the Settings which shows category of per app's locale. */
public static final AppFilter FILTER_APPS_LOCALE =
new AppFilter() {
@Override
public void init() {
}
@Override
public boolean filterApp(AppEntry entry) {
if (entry.extraInfo == null) {
Log.d(TAG, "No extra info.");
return false;
}
return (Boolean) entry.extraInfo;
}
};
}

View File

@@ -37,6 +37,8 @@ import androidx.appcompat.app.AlertDialog;
import androidx.preference.Preference;
import androidx.preference.PreferenceGroup;
import com.android.internal.app.LocalePicker;
import com.android.internal.app.LocalePicker.LocaleInfo;
import com.android.settings.R;
import com.android.settings.Utils;
import com.android.settings.applications.AppInfoBase;
@@ -45,8 +47,11 @@ import com.android.settingslib.applications.AppUtils;
import com.android.settingslib.widget.LayoutPreference;
import com.android.settingslib.widget.RadioButtonPreference;
import com.google.common.collect.Iterables;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Locale;
/**
@@ -200,8 +205,8 @@ public class AppLocaleDetails extends AppInfoBase implements RadioButtonPreferen
private TelephonyManager mTelephonyManager;
private LocaleManager mLocaleManager;
private Collection<Locale> mSuggestedLocales = new ArrayList<>();;
private Collection<Locale> mSupportedLocales = new ArrayList<>();;
private Collection<Locale> mSuggestedLocales = new ArrayList<>();
private Collection<Locale> mSupportedLocales = new ArrayList<>();
AppLocaleDetailsHelper(Context context, String packageName) {
mContext = context;
@@ -230,25 +235,41 @@ public class AppLocaleDetails extends AppInfoBase implements RadioButtonPreferen
@VisibleForTesting
void handleSuggestedLocales() {
LocaleList currentSystemLocales = getCurrentSystemLocales();
Locale simLocale = mTelephonyManager.getSimLocale();
Locale appLocale = getAppDefaultLocale(mContext, mPackageName);
String simCountry = mTelephonyManager.getSimCountryIso().toUpperCase(Locale.US);
String networkCountry = mTelephonyManager.getNetworkCountryIso().toUpperCase(Locale.US);
// 1st locale in suggested languages group.
if (appLocale != null) {
mSuggestedLocales.add(appLocale);
}
// 2nd locale in suggested languages group.
if (simLocale != null && !compareLocale(simLocale, appLocale)) {
mSuggestedLocales.add(simLocale);
final List<LocaleInfo> localeInfos = LocalePicker.getAllAssetLocales(mContext, false);
for (LocaleInfo localeInfo : localeInfos) {
Locale locale = localeInfo.getLocale();
String localeCountry = locale.getCountry().toUpperCase(Locale.US);
if (!compareLocale(locale, appLocale)
&& isCountrySuggestedLocale(localeCountry, simCountry, networkCountry)) {
mSuggestedLocales.add(locale);
}
}
// Other locales in suggested languages group.
for (int i = 0; i < currentSystemLocales.size(); i++) {
Locale locale = currentSystemLocales.get(i);
if (!compareLocale(locale, appLocale) && !compareLocale(locale, simLocale)) {
boolean isInSuggestedLocales = false;
for (int j = 0; j < mSuggestedLocales.size(); j++) {
Locale suggestedLocale = Iterables.get(mSuggestedLocales, j);
if (compareLocale(locale, suggestedLocale)) {
isInSuggestedLocales = true;
break;
}
}
if (!isInSuggestedLocales) {
mSuggestedLocales.add(locale);
}
}
}
@VisibleForTesting
static boolean compareLocale(Locale source, Locale target) {
if (source == null && target == null) {
return true;
@@ -259,6 +280,13 @@ public class AppLocaleDetails extends AppInfoBase implements RadioButtonPreferen
}
}
private static boolean isCountrySuggestedLocale(String localeCountry,
String simCountry,
String networkCountry) {
return ((!simCountry.isEmpty() && simCountry.equals(localeCountry))
|| (!networkCountry.isEmpty() && networkCountry.equals(localeCountry)));
}
@VisibleForTesting
void handleSupportedLocales() {
//TODO Waiting for PackageManager api

View File

@@ -20,20 +20,23 @@ import android.content.Context;
import android.util.FeatureFlagUtils;
import com.android.settings.SettingsPreferenceFragment;
import com.android.settings.applications.AppLocaleUtil;
/**
* A controller to update current locale information of application.
*/
public class AppLocalePreferenceController extends AppInfoPreferenceControllerBase {
private static final String TAG = AppLocalePreferenceController.class.getSimpleName();
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;
boolean isFeatureOn = FeatureFlagUtils
.isEnabled(mContext, FeatureFlagUtils.SETTINGS_APP_LANGUAGE_SELECTION);
return isFeatureOn && canDisplayLocaleUi() ? AVAILABLE : CONDITIONALLY_UNAVAILABLE;
}
@Override
@@ -45,4 +48,8 @@ public class AppLocalePreferenceController extends AppInfoPreferenceControllerBa
public CharSequence getSummary() {
return AppLocaleDetails.getSummary(mContext, mParent.getAppEntry().info.packageName);
}
boolean canDisplayLocaleUi() {
return AppLocaleUtil.canDisplayLocaleUi(mContext, mParent.getAppEntry());
}
}

View File

@@ -21,6 +21,7 @@ import androidx.annotation.IntDef;
import com.android.settings.R;
import com.android.settings.applications.AppStateAlarmsAndRemindersBridge;
import com.android.settings.applications.AppStateInstallAppsBridge;
import com.android.settings.applications.AppStateLocaleBridge;
import com.android.settings.applications.AppStateManageExternalStorageBridge;
import com.android.settings.applications.AppStateMediaManagementAppsBridge;
import com.android.settings.applications.AppStateNotificationBridge;
@@ -54,6 +55,7 @@ public class AppFilterRegistry {
FILTER_APPS_BLOCKED,
FILTER_ALARMS_AND_REMINDERS,
FILTER_APPS_MEDIA_MANAGEMENT,
FILTER_APPS_LOCALE,
})
@interface FilterType {
}
@@ -79,14 +81,15 @@ public class AppFilterRegistry {
public static final int FILTER_MANAGE_EXTERNAL_STORAGE = 17;
public static final int FILTER_ALARMS_AND_REMINDERS = 18;
public static final int FILTER_APPS_MEDIA_MANAGEMENT = 19;
// Next id: 20. If you add an entry here, length of mFilters should be updated
public static final int FILTER_APPS_LOCALE = 20;
// Next id: 21. If you add an entry here, length of mFilters should be updated
private static AppFilterRegistry sRegistry;
private final AppFilterItem[] mFilters;
private AppFilterRegistry() {
mFilters = new AppFilterItem[20];
mFilters = new AppFilterItem[21];
// High power allowlist, on
mFilters[FILTER_APPS_POWER_ALLOWLIST] = new AppFilterItem(
@@ -203,8 +206,16 @@ public class AppFilterRegistry {
AppStateMediaManagementAppsBridge.FILTER_MEDIA_MANAGEMENT_APPS,
FILTER_APPS_MEDIA_MANAGEMENT,
R.string.media_management_apps_title);
// Apps that can configurate appication's locale.
mFilters[FILTER_APPS_LOCALE] = new AppFilterItem(
AppStateLocaleBridge.FILTER_APPS_LOCALE,
FILTER_APPS_LOCALE,
R.string.app_locale_picker_title);
}
public static AppFilterRegistry getInstance() {
if (sRegistry == null) {
sRegistry = new AppFilterRegistry();
@@ -235,6 +246,8 @@ public class AppFilterRegistry {
return FILTER_ALARMS_AND_REMINDERS;
case ManageApplications.LIST_TYPE_MEDIA_MANAGEMENT_APPS:
return FILTER_APPS_MEDIA_MANAGEMENT;
case ManageApplications.LIST_TYPE_APPS_LOCALE:
return FILTER_APPS_LOCALE;
default:
return FILTER_APPS_ALL;
}

View File

@@ -95,6 +95,7 @@ import com.android.settings.applications.AppStateAlarmsAndRemindersBridge;
import com.android.settings.applications.AppStateAppOpsBridge.PermissionState;
import com.android.settings.applications.AppStateBaseBridge;
import com.android.settings.applications.AppStateInstallAppsBridge;
import com.android.settings.applications.AppStateLocaleBridge;
import com.android.settings.applications.AppStateManageExternalStorageBridge;
import com.android.settings.applications.AppStateMediaManagementAppsBridge;
import com.android.settings.applications.AppStateNotificationBridge;
@@ -232,7 +233,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;
public static final int LIST_TYPE_APPS_LOCALE = 14;
// List types that should show instant apps.
public static final Set<Integer> LIST_TYPES_WITH_INSTANT = new ArraySet<>(Arrays.asList(
@@ -321,7 +322,7 @@ public class ManageApplications extends InstrumentedFragment
mNotificationBackend = new NotificationBackend();
mSortOrder = R.id.sort_order_recent_notification;
} else if (className.equals(AppLocaleDetails.class.getName())) {
mListType = LIST_TYPE_APPS_LOCAL;
mListType = LIST_TYPE_APPS_LOCALE;
} else {
mListType = LIST_TYPE_MAIN;
}
@@ -504,7 +505,7 @@ 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:
case LIST_TYPE_APPS_LOCALE:
return SettingsEnums.APPS_LOCALE_LIST;
default:
return SettingsEnums.PAGE_UNKNOWN;
@@ -629,7 +630,7 @@ public class ManageApplications extends InstrumentedFragment
startAppInfoFragment(MediaManagementAppsDetails.class,
R.string.media_management_apps_title);
break;
case LIST_TYPE_APPS_LOCAL:
case LIST_TYPE_APPS_LOCALE:
startAppInfoFragment(AppLocaleDetails.class,
R.string.app_locale_picker_title);
break;
@@ -743,9 +744,9 @@ public class ManageApplications extends InstrumentedFragment
&& mSortOrder != R.id.sort_order_size);
mOptionsMenu.findItem(R.id.show_system).setVisible(!mShowSystem
&& mListType != LIST_TYPE_HIGH_POWER);
&& mListType != LIST_TYPE_HIGH_POWER && mListType != LIST_TYPE_APPS_LOCALE);
mOptionsMenu.findItem(R.id.hide_system).setVisible(mShowSystem
&& mListType != LIST_TYPE_HIGH_POWER);
&& mListType != LIST_TYPE_HIGH_POWER && mListType != LIST_TYPE_APPS_LOCALE);
mOptionsMenu.findItem(R.id.reset_app_preferences).setVisible(mListType == LIST_TYPE_MAIN);
@@ -1100,6 +1101,8 @@ public class ManageApplications extends InstrumentedFragment
mExtraInfoBridge = new AppStateAlarmsAndRemindersBridge(mContext, mState, this);
} else if (mManageApplications.mListType == LIST_TYPE_MEDIA_MANAGEMENT_APPS) {
mExtraInfoBridge = new AppStateMediaManagementAppsBridge(mContext, mState, this);
} else if (mManageApplications.mListType == LIST_TYPE_APPS_LOCALE) {
mExtraInfoBridge = new AppStateLocaleBridge(mContext, mState, this);
} else {
mExtraInfoBridge = null;
}
@@ -1533,7 +1536,7 @@ public class ManageApplications extends InstrumentedFragment
case LIST_TYPE_MEDIA_MANAGEMENT_APPS:
holder.setSummary(MediaManagementAppsDetails.getSummary(mContext, entry));
break;
case LIST_TYPE_APPS_LOCAL:
case LIST_TYPE_APPS_LOCALE:
holder.setSummary(AppLocaleDetails
.getSummary(mContext, entry.info.packageName));
break;

View File

@@ -20,6 +20,7 @@ import android.content.Intent;
import android.icu.text.RelativeDateTimeFormatter;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
@@ -85,11 +86,17 @@ public class RecentLocationAccessPreferenceController extends LocationBasePrefer
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
mCategoryRecentLocationRequests = screen.findPreference(getPreferenceKey());
}
@Override
public void updateState(Preference preference) {
mCategoryRecentLocationRequests.removeAll();
final Context prefContext = mCategoryRecentLocationRequests.getContext();
final List<RecentAppOpsAccess.Access> recentLocationAccesses = new ArrayList<>();
final UserManager userManager = UserManager.get(mContext);
for (RecentAppOpsAccess.Access access : mRecentLocationApps.getAppListSorted(
/* showSystemApps= */ false)) {
final boolean showSystem = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.LOCATION_SHOW_SYSTEM_OPS, 0) == 1;
for (RecentAppOpsAccess.Access access : mRecentLocationApps.getAppListSorted(showSystem)) {
if (isRequestMatchesProfileType(userManager, access, mType)) {
recentLocationAccesses.add(access);
if (recentLocationAccesses.size() == MAX_APPS) {

View File

@@ -17,6 +17,7 @@ package com.android.settings.location;
import android.content.Context;
import android.os.Bundle;
import android.provider.Settings;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
@@ -36,7 +37,6 @@ public class RecentLocationAccessSeeAllFragment extends DashboardFragment {
private static final int MENU_SHOW_SYSTEM = Menu.FIRST + 1;
private static final int MENU_HIDE_SYSTEM = Menu.FIRST + 2;
private static final String EXTRA_SHOW_SYSTEM = "show_system";
private boolean mShowSystem = false;
private MenuItem mShowSystemMenu;
@@ -58,18 +58,8 @@ public class RecentLocationAccessSeeAllFragment extends DashboardFragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
mShowSystem = savedInstanceState.getBoolean(EXTRA_SHOW_SYSTEM, mShowSystem);
}
if (mController != null) {
mController.setShowSystem(mShowSystem);
}
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean(EXTRA_SHOW_SYSTEM, mShowSystem);
mShowSystem = Settings.Secure.getInt(getContentResolver(),
Settings.Secure.LOCATION_SHOW_SYSTEM_OPS, 0) == 1;
}
@Override
@@ -88,6 +78,8 @@ public class RecentLocationAccessSeeAllFragment extends DashboardFragment {
case MENU_SHOW_SYSTEM:
case MENU_HIDE_SYSTEM:
mShowSystem = menuItem.getItemId() == MENU_SHOW_SYSTEM;
Settings.Secure.putInt(getContentResolver(),
Settings.Secure.LOCATION_SHOW_SYSTEM_OPS, mShowSystem ? 1 : 0);
updateMenu();
if (mController != null) {
mController.setShowSystem(mShowSystem);

View File

@@ -20,6 +20,7 @@ import static com.android.settings.location.RecentLocationAccessPreferenceContro
import android.content.Context;
import android.os.UserManager;
import android.provider.Settings;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
@@ -43,6 +44,8 @@ public class RecentLocationAccessSeeAllPreferenceController
public RecentLocationAccessSeeAllPreferenceController(Context context, String key) {
super(context, key);
mShowSystem = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.LOCATION_SHOW_SYSTEM_OPS, 0) == 1;
mRecentLocationAccesses = RecentAppOpsAccess.createForLocation(context);
}

View File

@@ -17,6 +17,7 @@ import android.content.Context;
import android.os.Bundle;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Settings;
import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
@@ -83,8 +84,11 @@ public class RecentLocationRequestPreferenceController extends LocationBasePrefe
final Context prefContext = mCategoryRecentLocationRequests.getContext();
final List<RecentLocationApps.Request> recentLocationRequests = new ArrayList<>();
final UserManager userManager = UserManager.get(mContext);
final boolean showSystem = Settings.Secure.getInt(mContext.getContentResolver(),
Settings.Secure.LOCATION_SHOW_SYSTEM_OPS, 0) == 1;
for (RecentLocationApps.Request request : mRecentLocationApps.getAppListSorted(
false /* systemApps */)) {
showSystem)) {
if (isRequestMatchesProfileType(userManager, request, mType)) {
recentLocationRequests.add(request);
if (recentLocationRequests.size() == MAX_APPS) {

View File

@@ -0,0 +1,278 @@
/*
* Copyright (C) 2022 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.nfc;
import android.app.settings.SettingsEnums;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.os.UserHandle;
import android.os.UserManager;
import android.text.Layout;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.TextUtils;
import android.text.style.AlignmentSpan;
import android.text.style.BulletSpan;
import android.text.style.ClickableSpan;
import android.text.style.RelativeSizeSpan;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.applications.defaultapps.DefaultAppPickerFragment;
import com.android.settings.nfc.PaymentBackend.PaymentAppInfo;
import com.android.settingslib.widget.CandidateInfo;
import com.android.settingslib.widget.FooterPreference;
import com.android.settingslib.widget.SelectorWithWidgetPreference;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
/**
* DefaultPaymentSettings handles the NFC default payment app selection.
*/
public class DefaultPaymentSettings extends DefaultAppPickerFragment {
public static final String TAG = "DefaultPaymentSettings";
private PaymentBackend mPaymentBackend;
private List<PaymentAppInfo> mAppInfos;
private Preference mFooterPreference;
@Override
public int getMetricsCategory() {
return SettingsEnums.NFC_PAYMENT;
}
@Override
protected int getPreferenceScreenResId() {
return R.xml.nfc_default_payment_settings;
}
@Override
protected String getDefaultKey() {
PaymentAppInfo defaultAppInfo = mPaymentBackend.getDefaultApp();
if (defaultAppInfo != null) {
return defaultAppInfo.componentName.flattenToString() + " "
+ defaultAppInfo.userHandle.getIdentifier();
}
return null;
}
@Override
protected boolean setDefaultKey(String key) {
String[] keys = key.split(" ");
if (keys.length >= 2) {
mPaymentBackend.setDefaultPaymentApp(ComponentName.unflattenFromString(keys[0]),
Integer.parseInt(keys[1]));
}
return true;
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
mPaymentBackend = new PaymentBackend(getActivity());
mAppInfos = mPaymentBackend.getPaymentAppInfos();
}
@Override
protected void addStaticPreferences(PreferenceScreen screen) {
if (mFooterPreference == null) {
setupFooterPreference();
}
screen.addPreference(mFooterPreference);
}
@Override
public void onResume() {
super.onResume();
mPaymentBackend.onResume();
}
@Override
public void onPause() {
super.onPause();
mPaymentBackend.onPause();
}
/**
* Comparator for NfcPaymentCandidateInfo.
*/
public class NfcPaymentCandidateInfoComparator implements Comparator<NfcPaymentCandidateInfo> {
/**
* Compare the NfcPaymentCandidateInfo by the label string.
*/
public int compare(NfcPaymentCandidateInfo obj1, NfcPaymentCandidateInfo obj2) {
if (obj1.loadLabel() == obj2.loadLabel()) {
return 0;
}
if (obj1.loadLabel() == null) {
return -1;
}
if (obj2.loadLabel() == null) {
return 1;
}
return obj1.loadLabel().toString().compareTo(obj2.loadLabel().toString());
}
}
@Override
public void bindPreferenceExtra(SelectorWithWidgetPreference pref, String key,
CandidateInfo info, String defaultKey, String systemDefaultKey) {
final NfcPaymentCandidateInfo candidateInfo = (NfcPaymentCandidateInfo) info;
if (candidateInfo.isManagedProfile()) {
pref.setSummary("Work");
}
}
@Override
protected List<? extends CandidateInfo> getCandidates() {
final List<NfcPaymentCandidateInfo> candidates = new ArrayList<>();
for (PaymentAppInfo appInfo: mAppInfos) {
UserManager um = getContext().createContextAsUser(
appInfo.userHandle, /*flags=*/0).getSystemService(UserManager.class);
boolean isManagedProfile = um.isManagedProfile(appInfo.userHandle.getIdentifier());
CharSequence label;
label = appInfo.label;
candidates.add(new NfcPaymentCandidateInfo(
appInfo.componentName.flattenToString(),
label,
appInfo.icon,
appInfo.userHandle.getIdentifier(),
isManagedProfile));
}
Collections.sort(candidates, new NfcPaymentCandidateInfoComparator());
return candidates;
}
@VisibleForTesting
class NfcPaymentCandidateInfo extends CandidateInfo {
private final String mKey;
private final CharSequence mLabel;
private final Drawable mDrawable;
private final int mUserId;
private final boolean mIsManagedProfile;
NfcPaymentCandidateInfo(String key, CharSequence label, Drawable drawable, int userId,
boolean isManagedProfile) {
super(true /* enabled */);
mKey = key;
mLabel = label;
mDrawable = drawable;
mUserId = userId;
mIsManagedProfile = isManagedProfile;
}
@Override
public CharSequence loadLabel() {
return mLabel;
}
@Override
public Drawable loadIcon() {
return mDrawable;
}
@Override
public String getKey() {
return mKey + " " + mUserId;
}
public boolean isManagedProfile() {
return mIsManagedProfile;
}
}
@Override
protected CharSequence getConfirmationMessage(CandidateInfo appInfo) {
if (appInfo == null) {
return null;
}
NfcPaymentCandidateInfo paymentInfo = (NfcPaymentCandidateInfo) appInfo;
UserManager um = getContext().createContextAsUser(UserHandle.of(paymentInfo.mUserId),
/*flags=*/0).getSystemService(UserManager.class);
boolean isManagedProfile = um.isManagedProfile(paymentInfo.mUserId);
if (!isManagedProfile) {
return null;
}
final String title = getContext().getString(
R.string.nfc_default_payment_workapp_confirmation_title);
final String messageTitle = getContext().getString(
R.string.nfc_default_payment_workapp_confirmation_message_title);
final String messageOne = getContext().getString(
R.string.nfc_default_payment_workapp_confirmation_message_1);
final String messageTwo = getContext().getString(
R.string.nfc_default_payment_workapp_confirmation_message_2);
final SpannableString titleString = new SpannableString(title);
final SpannableString messageString = new SpannableString(messageTitle);
final SpannableString oneString = new SpannableString(messageOne);
final SpannableString twoString = new SpannableString(messageTwo);
titleString.setSpan(new RelativeSizeSpan(1.5f), 0, title.length(),
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
titleString.setSpan(new AlignmentSpan.Standard(Layout.Alignment.ALIGN_CENTER), 0,
title.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
messageString.setSpan(new AlignmentSpan.Standard(Layout.Alignment.ALIGN_CENTER), 0,
messageTitle.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
oneString.setSpan(new BulletSpan(20), 0, messageOne.length(),
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
twoString.setSpan(new BulletSpan(20), 0, messageTwo.length(),
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
return TextUtils.concat(titleString, "\n\n", messageString, "\n\n", oneString, "\n",
twoString);
}
private void setupFooterPreference() {
final String textNfcDefaultPaymentFooter = getResources().getString(
R.string.nfc_default_payment_footer);
final String textMoreDetails = getResources().getString(R.string.nfc_more_details);
final SpannableString spannableString = new SpannableString(
textNfcDefaultPaymentFooter + System.lineSeparator()
+ System.lineSeparator() + textMoreDetails);
final ClickableSpan clickableSpan = new ClickableSpan() {
@Override
public void onClick(@NonNull View widget) {
Intent howItWorksIntent = new Intent(getActivity(), HowItWorks.class);
startActivity(howItWorksIntent);
}
};
if (textNfcDefaultPaymentFooter != null && textMoreDetails != null) {
spannableString.setSpan(clickableSpan, textNfcDefaultPaymentFooter.length() + 1,
textNfcDefaultPaymentFooter.length() + textMoreDetails.length() + 2,
Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
mFooterPreference = new FooterPreference(getContext());
mFooterPreference.setLayoutResource(R.layout.preference_footer);
mFooterPreference.setTitle(spannableString);
mFooterPreference.setSelectable(false);
mFooterPreference.setIcon(R.drawable.ic_info_outline_24dp);
}
}

View File

@@ -0,0 +1,146 @@
/*
* Copyright (C) 2022 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.nfc;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.nfc.NfcAdapter;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import com.android.settings.applications.defaultapps.DefaultAppPreferenceController;
import com.android.settings.nfc.PaymentBackend.PaymentAppInfo;
import com.android.settingslib.applications.DefaultAppInfo;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.core.lifecycle.LifecycleObserver;
import com.android.settingslib.core.lifecycle.events.OnPause;
import com.android.settingslib.core.lifecycle.events.OnResume;
import java.util.List;
/**
* NfcDefaultPaymentPreferenceController shows an app icon and text summary for current selected
* default payment, and links to the nfc default payment selection page.
*/
public class NfcDefaultPaymentPreferenceController extends DefaultAppPreferenceController implements
PaymentBackend.Callback, LifecycleObserver, OnResume, OnPause {
private static final String TAG = "NfcDefaultPaymentController";
private static final String KEY = "nfc_payment_app";
private PaymentBackend mPaymentBackend;
private Preference mPreference;
private Context mContext;
public NfcDefaultPaymentPreferenceController(Context context, Lifecycle lifecycle) {
super(context);
mContext = context;
mPaymentBackend = new PaymentBackend(context);
if (lifecycle != null) {
lifecycle.addObserver(this);
}
}
@Override
public boolean isAvailable() {
final PackageManager pm = mContext.getPackageManager();
if (!pm.hasSystemFeature(PackageManager.FEATURE_NFC)) {
return false;
}
if (NfcAdapter.getDefaultAdapter(mContext) == null) {
return false;
}
if (mPaymentBackend == null) {
mPaymentBackend = new PaymentBackend(mContext);
}
final List<PaymentAppInfo> appInfos = mPaymentBackend.getPaymentAppInfos();
return (appInfos != null && !appInfos.isEmpty())
? true
: false;
}
@Override
public String getPreferenceKey() {
return KEY;
}
@Override
public void onResume() {
if (mPaymentBackend != null) {
mPaymentBackend.registerCallback(this);
mPaymentBackend.onResume();
}
}
@Override
public void onPause() {
if (mPaymentBackend != null) {
mPaymentBackend.unregisterCallback(this);
mPaymentBackend.onPause();
}
}
@Override
public void displayPreference(PreferenceScreen screen) {
mPreference = screen.findPreference(getPreferenceKey());
super.displayPreference(screen);
}
@Override
public void updateState(Preference preference) {
super.updateState(preference);
preference.setIconSpaceReserved(true);
}
@Override
public void onPaymentAppsChanged() {
updateState(mPreference);
}
/**
* PaymentDefaultAppInfo is used to store the default payment app info.
*/
public static class PaymentDefaultAppInfo extends DefaultAppInfo {
public PaymentAppInfo mInfo;
public PaymentDefaultAppInfo(Context context, PackageManager pm, int userId,
PaymentAppInfo info) {
super(context, pm, userId, info.componentName);
mInfo = info;
}
@Override
public Drawable loadIcon() {
return mInfo.icon;
}
}
@Override
protected DefaultAppInfo getDefaultAppInfo() {
if (mPaymentBackend == null) {
return null;
}
final PaymentAppInfo defaultApp = mPaymentBackend.getDefaultApp();
if (defaultApp != null) {
return new PaymentDefaultAppInfo(mContext, mPackageManager,
defaultApp.userHandle.getIdentifier(), defaultApp);
}
return null;
}
}

View File

@@ -16,11 +16,9 @@ package com.android.settings.nfc;
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.content.pm.PackageManager;
import android.text.TextUtils;
import androidx.preference.DropDownPreference;
import androidx.preference.ListPreference;
import androidx.preference.Preference;
import androidx.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.core.BasePreferenceController;
@@ -36,13 +34,18 @@ public class NfcForegroundPreferenceController extends BasePreferenceController
PaymentBackend.Callback, Preference.OnPreferenceChangeListener,
LifecycleObserver, OnStart, OnStop {
private DropDownPreference mPreference;
private ListPreference mPreference;
private PaymentBackend mPaymentBackend;
private MetricsFeatureProvider mMetricsFeatureProvider;
private final String[] mListValues;
private final String[] mListEntries;
public NfcForegroundPreferenceController(Context context, String key) {
super(context, key);
mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider();
mListValues = context.getResources().getStringArray(R.array.nfc_payment_favor_values);
mListEntries = context.getResources().getStringArray(R.array.nfc_payment_favor);
}
public void setPaymentBackend(PaymentBackend backend) {
@@ -78,21 +81,6 @@ public class NfcForegroundPreferenceController extends BasePreferenceController
: UNSUPPORTED_ON_DEVICE;
}
@Override
public void displayPreference(PreferenceScreen screen) {
super.displayPreference(screen);
mPreference = screen.findPreference(getPreferenceKey());
if (mPreference == null) {
return;
}
mPreference.setEntries(new CharSequence[]{
mContext.getText(R.string.nfc_payment_favor_open),
mContext.getText(R.string.nfc_payment_favor_default)
});
mPreference.setEntryValues(new CharSequence[]{"1", "0"});
}
@Override
public void onPaymentAppsChanged() {
updateState(mPreference);
@@ -100,26 +88,29 @@ public class NfcForegroundPreferenceController extends BasePreferenceController
@Override
public void updateState(Preference preference) {
if (preference instanceof DropDownPreference) {
((DropDownPreference) preference).setValue(
mPaymentBackend.isForegroundMode() ? "1" : "0");
}
super.updateState(preference);
if (!(preference instanceof ListPreference)) {
return;
}
final ListPreference listPreference = (ListPreference) preference;
listPreference.setIconSpaceReserved(true);
listPreference.setValue(mListValues[mPaymentBackend.isForegroundMode() ? 1 : 0]);
}
@Override
public CharSequence getSummary() {
return mPreference.getEntry();
return mListEntries[mPaymentBackend.isForegroundMode() ? 1 : 0];
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
if (!(preference instanceof DropDownPreference)) {
if (!(preference instanceof ListPreference)) {
return false;
}
final DropDownPreference pref = (DropDownPreference) preference;
final ListPreference listPreference = (ListPreference) preference;
final String newValueString = (String) newValue;
pref.setSummary(pref.getEntries()[pref.findIndexOfValue(newValueString)]);
listPreference.setSummary(mListEntries[listPreference.findIndexOfValue(newValueString)]);
final boolean foregroundMode = Integer.parseInt(newValueString) != 0;
mPaymentBackend.setForegroundMode(foregroundMode);
mMetricsFeatureProvider.action(mContext,
@@ -127,12 +118,4 @@ public class NfcForegroundPreferenceController extends BasePreferenceController
: SettingsEnums.ACTION_NFC_PAYMENT_ALWAYS_SETTING);
return true;
}
@Override
public void updateNonIndexableKeys(List<String> keys) {
final String key = getPreferenceKey();
if (!TextUtils.isEmpty(key)) {
keys.add(key);
}
}
}
}

View File

@@ -20,6 +20,7 @@ import android.app.ActivityManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.nfc.NfcAdapter;
import android.nfc.cardemulation.ApduServiceInfo;
import android.nfc.cardemulation.CardEmulation;
@@ -50,6 +51,7 @@ public class PaymentBackend {
public ComponentName componentName;
public ComponentName settingsComponent;
public UserHandle userHandle;
public Drawable icon;
}
/**
@@ -131,6 +133,7 @@ public class PaymentBackend {
appInfo.settingsComponent = null;
}
appInfo.description = service.getDescription();
appInfo.icon = pm.getUserBadgedIcon(service.loadIcon(pm), appInfo.userHandle);
appInfos.add(appInfo);
}

View File

@@ -18,15 +18,11 @@ package com.android.settings.nfc;
import android.app.settings.SettingsEnums;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.os.Bundle;
import android.os.UserHandle;
import android.os.UserManager;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
@@ -37,8 +33,12 @@ import androidx.preference.PreferenceScreen;
import com.android.settings.R;
import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.search.BaseSearchIndexProvider;
import com.android.settingslib.core.AbstractPreferenceController;
import com.android.settingslib.core.lifecycle.Lifecycle;
import com.android.settingslib.search.SearchIndexable;
import java.util.ArrayList;
import java.util.List;
@SearchIndexable
public class PaymentSettings extends DashboardFragment {
@@ -61,13 +61,24 @@ public class PaymentSettings extends DashboardFragment {
return R.xml.nfc_payment_settings;
}
@Override
protected List<AbstractPreferenceController> createPreferenceControllers(Context context) {
return buildPreferenceControllers(context, getSettingsLifecycle());
}
private static List<AbstractPreferenceController> buildPreferenceControllers(Context context,
Lifecycle lifecycle) {
final List<AbstractPreferenceController> controllers = new ArrayList<>();
controllers.add(new NfcDefaultPaymentPreferenceController(context, lifecycle));
return controllers;
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
mPaymentBackend = new PaymentBackend(getActivity());
setHasOptionsMenu(true);
use(NfcPaymentPreferenceController.class).setPaymentBackend(mPaymentBackend);
use(NfcForegroundPreferenceController.class).setPaymentBackend(mPaymentBackend);
}
@@ -93,15 +104,6 @@ public class PaymentSettings extends DashboardFragment {
mPaymentBackend.onPause();
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
MenuItem menuItem = menu.add(R.string.nfc_payment_how_it_works);
Intent howItWorksIntent = new Intent(getActivity(), HowItWorks.class);
menuItem.setIntent(howItWorksIntent);
menuItem.setShowAsActionFlags(MenuItem.SHOW_AS_ACTION_NEVER);
}
@VisibleForTesting
boolean isShowEmptyImage(PreferenceScreen screen) {
for (int i = 0; i < screen.getPreferenceCount(); i++) {
@@ -127,4 +129,4 @@ public class PaymentSettings extends DashboardFragment {
return pm.hasSystemFeature(PackageManager.FEATURE_NFC);
}
};
}
}

View File

@@ -74,6 +74,9 @@ public class UserDetailsSettings extends SettingsPreferenceFragment
private static final int DIALOG_SETUP_USER = 4;
private static final int DIALOG_CONFIRM_RESET_GUEST = 5;
/** Whether to enable the app_copying fragment. */
private static final boolean SHOW_APP_COPYING_PREF = false;
private UserManager mUserManager;
private UserCapabilities mUserCaps;
private boolean mGuestUserAutoCreated;
@@ -298,6 +301,9 @@ public class UserDetailsSettings extends SettingsPreferenceFragment
if (mGuestUserAutoCreated) {
mRemoveUserPref.setEnabled((mUserInfo.flags & UserInfo.FLAG_INITIALIZED) != 0);
}
if (!SHOW_APP_COPYING_PREF) {
removePreference(KEY_APP_COPYING);
}
} else {
mPhonePref.setChecked(!mUserManager.hasUserRestriction(
UserManager.DISALLOW_OUTGOING_CALLS, new UserHandle(userId)));
@@ -410,6 +416,9 @@ public class UserDetailsSettings extends SettingsPreferenceFragment
}
private void openAppCopyingScreen() {
if (!SHOW_APP_COPYING_PREF) {
return;
}
final Bundle extras = new Bundle();
extras.putInt(AppRestrictionsFragment.EXTRA_USER_ID, mUserInfo.id);
new SubSettingLauncher(getContext())

View File

@@ -503,7 +503,8 @@ public class UserSettings extends SettingsPreferenceFragment
private void onAddSupervisedUserClicked() {
final Intent intent = new Intent()
.setAction(UserManager.ACTION_CREATE_SUPERVISED_USER)
.setPackage(mConfigSupervisedUserCreationPackage);
.setPackage(mConfigSupervisedUserCreationPackage)
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// TODO(b/209659998): [to-be-removed] fallback activity for supervised user creation.
if (getActivity().getPackageManager().resolveActivity(intent, 0) == null) {

View File

@@ -18,6 +18,15 @@ package com.android.settings;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.net.wifi.p2p.WifiP2pManager;
import android.os.Looper;
import android.view.LayoutInflater;
import android.widget.TextView;
@@ -25,7 +34,6 @@ import androidx.fragment.app.FragmentActivity;
import com.android.settings.testutils.shadow.ShadowBluetoothAdapter;
import com.android.settings.testutils.shadow.ShadowRecoverySystem;
import com.android.settings.testutils.shadow.ShadowWifiP2pManager;
import org.junit.After;
import org.junit.Before;
@@ -39,27 +47,31 @@ import org.robolectric.RobolectricTestRunner;
import org.robolectric.annotation.Config;
@RunWith(RobolectricTestRunner.class)
@Config(shadows = {ShadowRecoverySystem.class,
ShadowWifiP2pManager.class, ShadowBluetoothAdapter.class
})
@Config(shadows = {ShadowRecoverySystem.class, ShadowBluetoothAdapter.class})
public class ResetNetworkConfirmTest {
private FragmentActivity mActivity;
@Mock
private WifiP2pManager mWifiP2pManager;
@Mock
private ResetNetworkConfirm mResetNetworkConfirm;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
when(mWifiP2pManager.initialize(any(Context.class), any(Looper.class), any()))
.thenReturn(mock(WifiP2pManager.Channel.class));
mResetNetworkConfirm = new ResetNetworkConfirm();
mActivity = Robolectric.setupActivity(FragmentActivity.class);
mActivity = spy(Robolectric.setupActivity(FragmentActivity.class));
when(mActivity.getSystemService(Context.WIFI_P2P_SERVICE)).thenReturn(mWifiP2pManager);
mResetNetworkConfirm.mActivity = mActivity;
}
@After
public void tearDown() {
ShadowRecoverySystem.reset();
ShadowWifiP2pManager.reset();
}
@Test
@@ -88,11 +100,10 @@ public class ResetNetworkConfirmTest {
* Test for WifiP2pManager factoryReset method.
*/
@Test
@Ignore
public void testResetNetworkData_resetP2p() {
mResetNetworkConfirm.p2pFactoryReset(mActivity);
assertThat(ShadowWifiP2pManager.getFactoryResetCount()).isEqualTo(1);
verify(mWifiP2pManager).factoryReset(any(WifiP2pManager.Channel.class), any());
}
@Test

View File

@@ -18,6 +18,7 @@ package com.android.settings.accounts;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
@@ -32,7 +33,6 @@ import androidx.preference.SwitchPreference;
import com.android.settings.R;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -106,10 +106,9 @@ public class WorkModePreferenceControllerTest {
}
@Test
@Ignore
public void onStart_shouldRegisterReceiver() {
mController.onStart();
verify(mContext).registerReceiver(eq(mController.mReceiver), any());
verify(mContext).registerReceiver(eq(mController.mReceiver), any(), anyInt());
}
@Test

View File

@@ -48,7 +48,6 @@ import java.util.Collections;
@RunWith(RobolectricTestRunner.class)
public class DreamPickerControllerTest {
private DreamPickerController mController;
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private DreamBackend mBackend;
private Context mContext;
@@ -63,31 +62,36 @@ public class DreamPickerControllerTest {
mPreference = new LayoutPreference(mContext, R.layout.dream_picker_layout);
when(mScreen.findPreference(anyString())).thenReturn(mPreference);
}
mController = new DreamPickerController(
private DreamPickerController buildController() {
final DreamPickerController controller = new DreamPickerController(
mContext,
/* preferenceKey= */ "test",
mBackend);
mController.displayPreference(mScreen);
controller.displayPreference(mScreen);
return controller;
}
@Test
public void isDisabledIfNoDreamsAvailable() {
when(mBackend.getDreamInfos()).thenReturn(new ArrayList<>(0));
assertThat(mController.isAvailable()).isFalse();
final DreamPickerController controller = buildController();
assertThat(controller.isAvailable()).isFalse();
}
@Test
public void isEnabledIfDreamsAvailable() {
when(mBackend.getDreamInfos()).thenReturn(Collections.singletonList(new DreamInfo()));
assertThat(mController.isAvailable()).isTrue();
final DreamPickerController controller = buildController();
assertThat(controller.isAvailable()).isTrue();
}
@Test
public void testDreamDisplayedInList() {
when(mBackend.getDreamInfos()).thenReturn(Collections.singletonList(new DreamInfo()));
mController.updateState(mPreference);
final DreamPickerController controller = buildController();
controller.updateState(mPreference);
RecyclerView view = mPreference.findViewById(R.id.dream_list);
assertThat(view.getAdapter().getItemCount()).isEqualTo(1);
@@ -100,7 +104,8 @@ public class DreamPickerControllerTest {
mockDreamInfo.isActive = true;
when(mBackend.getDreamInfos()).thenReturn(Collections.singletonList(mockDreamInfo));
mController.updateState(mPreference);
final DreamPickerController controller = buildController();
controller.updateState(mPreference);
Button view = mPreference.findViewById(R.id.preview_button);
view.performClick();

View File

@@ -22,13 +22,13 @@ import static org.mockito.Mockito.when;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import java.util.Date;
import org.robolectric.RobolectricTestRunner;
@RunWith(RobolectricTestRunner.class)
public class BugReportsPreferenceControllerTest
extends AdminActionPreferenceControllerTestBase {
extends AdminActionPreferenceControllerTestBase {
@Override
public void setUp() {
@@ -39,7 +39,7 @@ public class BugReportsPreferenceControllerTest
@Override
public void setDate(Date date) {
when(mFeatureFactory.enterprisePrivacyFeatureProvider.getLastBugReportRequestTime())
.thenReturn(date);
.thenReturn(date);
}
@Test

View File

@@ -43,7 +43,6 @@ import com.android.settings.widget.RestrictedAppPreference;
import com.android.settingslib.core.lifecycle.Lifecycle;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Answers;
@@ -98,16 +97,15 @@ public class LocationInjectedServicesPreferenceControllerTest {
}
@Test
@Ignore
public void onResume_shouldRegisterListener() {
mController.onResume();
verify(mContext).registerReceiver(eq(mController.mInjectedSettingsReceiver),
eq(mController.INTENT_FILTER_INJECTED_SETTING_CHANGED));
eq(mController.INTENT_FILTER_INJECTED_SETTING_CHANGED),
anyInt());
}
@Test
@Ignore
public void onPause_shouldUnregisterListener() {
mController.onResume();
mController.onPause();

View File

@@ -19,9 +19,12 @@ import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.os.UserHandle;
import android.provider.Settings;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.TextView;
@@ -34,12 +37,15 @@ import com.android.settings.dashboard.DashboardFragment;
import com.android.settings.testutils.shadow.ShadowDeviceConfig;
import com.android.settingslib.applications.RecentAppOpsAccess;
import com.google.common.collect.ImmutableList;
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;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
@@ -107,4 +113,20 @@ public class RecentLocationAccessPreferenceControllerTest {
mContext.getText(R.string.location_recent_location_access_view_details));
assertThat(details.hasOnClickListeners()).isTrue();
}
/** Verifies the title text, details text are correct, and the click listener is set. */
@Test
public void updateState_showSystemAccess() {
doReturn(ImmutableList.of(
new RecentAppOpsAccess.Access("app", UserHandle.CURRENT, null, "app", "", 0)))
.when(mRecentLocationApps).getAppListSorted(false);
doReturn(new ArrayList<>()).when(mRecentLocationApps).getAppListSorted(true);
mController.displayPreference(mScreen);
mController.updateState(mLayoutPreference);
verify(mLayoutPreference).addPreference(Mockito.any());
Settings.Secure.putInt(
mContext.getContentResolver(), Settings.Secure.LOCATION_SHOW_SYSTEM_OPS, 1);
verify(mLayoutPreference, Mockito.times(1)).addPreference(Mockito.any());
}
}

View File

@@ -26,6 +26,7 @@ import static org.mockito.Mockito.when;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.UserHandle;
import android.provider.Settings;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceScreen;
@@ -81,6 +82,25 @@ public class RecentLocationRequestPreferenceControllerTest {
verify(mCategory, times(3)).addPreference(any());
}
@Test
public void updateState_whenAppListMoreThanThree_showSystem() {
when(mController.mRecentLocationApps.getAppListSorted(false))
.thenReturn(createMockRequest(2));
when(mController.mRecentLocationApps.getAppListSorted(true))
.thenReturn(createMockRequest(3));
mController.displayPreference(mScreen);
verify(mCategory, times(2)).addPreference(any());
Settings.Secure.putInt(
mContext.getContentResolver(),
Settings.Secure.LOCATION_SHOW_SYSTEM_OPS,
1);
mController.displayPreference(mScreen);
verify(mCategory, times(5)).addPreference(any());
}
@Test
public void updateState_workProfile_shouldShowOnlyWorkProfileApps() {
final List<RecentLocationApps.Request> requests = createMockRequest(6);

View File

@@ -26,7 +26,7 @@ import android.app.settings.SettingsEnums;
import android.content.Context;
import android.content.pm.PackageManager;
import androidx.preference.DropDownPreference;
import androidx.preference.ListPreference;
import androidx.preference.PreferenceScreen;
import com.android.settings.R;
@@ -39,7 +39,6 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
import org.robolectric.util.ReflectionHelpers;
import java.util.ArrayList;
@@ -56,7 +55,7 @@ public class NfcForegroundPreferenceControllerTest {
private PackageManager mManager;
private Context mContext;
private DropDownPreference mPreference;
private ListPreference mPreference;
private NfcForegroundPreferenceController mController;
private FakeFeatureFactory mFakeFeatureFactory;
@@ -67,7 +66,9 @@ public class NfcForegroundPreferenceControllerTest {
when(mContext.getPackageManager()).thenReturn(mManager);
mFakeFeatureFactory = FakeFeatureFactory.setupForTest();
mController = new NfcForegroundPreferenceController(mContext, PREF_KEY);
mPreference = new DropDownPreference(mContext);
mPreference = new ListPreference(mContext);
mPreference.setEntries(R.array.nfc_payment_favor);
mPreference.setEntryValues(R.array.nfc_payment_favor_values);
when(mScreen.findPreference(PREF_KEY)).thenReturn(mPreference);
}
@@ -146,17 +147,14 @@ public class NfcForegroundPreferenceControllerTest {
final CharSequence favorDefault = mContext.getText(R.string.nfc_payment_favor_default);
final CharSequence favorOpen = mContext.getText(R.string.nfc_payment_favor_open);
assertThat(mPreference.getEntry()).isEqualTo(favorDefault);
assertThat(mPreference.getSummary()).isEqualTo(favorDefault);
mPreference.setValueIndex(0);
mPreference.callChangeListener(mPreference.getEntryValues()[0]);
mPreference.setValueIndex(1);
mPreference.callChangeListener(mPreference.getEntryValues()[1]);
verify(mPaymentBackend).setForegroundMode(true);
assertThat(mPreference.getEntry()).isEqualTo(favorOpen);
assertThat(mPreference.getSummary()).isEqualTo(favorOpen);
mPreference.setValueIndex(1);
mPreference.callChangeListener(mPreference.getEntryValues()[1]);
mPreference.setValueIndex(0);
mPreference.callChangeListener(mPreference.getEntryValues()[0]);
verify(mPaymentBackend).setForegroundMode(false);
assertThat(mPreference.getEntry()).isEqualTo(favorDefault);
assertThat(mPreference.getSummary()).isEqualTo(favorDefault);
@@ -168,16 +166,16 @@ public class NfcForegroundPreferenceControllerTest {
mController.displayPreference(mScreen);
mController.onPaymentAppsChanged();
mPreference.setValueIndex(0);
mPreference.callChangeListener(mPreference.getEntryValues()[0]);
mPreference.setValueIndex(1);
mPreference.callChangeListener(mPreference.getEntryValues()[1]);
verify(mPaymentBackend).setForegroundMode(true);
verify(mFakeFeatureFactory.metricsFeatureProvider).action(mContext,
SettingsEnums.ACTION_NFC_PAYMENT_FOREGROUND_SETTING);
mPreference.setValueIndex(1);
mPreference.callChangeListener(mPreference.getEntryValues()[1]);
mPreference.setValueIndex(0);
mPreference.callChangeListener(mPreference.getEntryValues()[0]);
verify(mPaymentBackend).setForegroundMode(false);
verify(mFakeFeatureFactory.metricsFeatureProvider).action(mContext,
SettingsEnums.ACTION_NFC_PAYMENT_ALWAYS_SETTING);
}
}
}

View File

@@ -53,7 +53,7 @@ import java.util.List;
@Config(shadows = {PaymentSettingsTest.ShadowPaymentBackend.class, ShadowNfcAdapter.class})
public class PaymentSettingsTest {
static final String PAYMENT_KEY = "nfc_payment";
static final String PAYMENT_KEY = "nfc_payment_app";
static final String FOREGROUND_KEY = "nfc_foreground";
private Context mContext;
@@ -160,4 +160,4 @@ public class PaymentSettingsTest {
return mAppInfos;
}
}
}
}

View File

@@ -664,6 +664,7 @@ public class UserSettingsTest {
public void onPreferenceClick_addSupervisedUserClicked_startIntentWithAction() {
final String intentPackage = "testPackage";
final String intentAction = UserManager.ACTION_CREATE_SUPERVISED_USER;
final int intentFlags = Intent.FLAG_ACTIVITY_NEW_TASK;
final int metricsAction = SettingsEnums.ACTION_USER_SUPERVISED_ADD;
try {
setConfigSupervisedUserCreationPackage(intentPackage);
@@ -676,6 +677,7 @@ public class UserSettingsTest {
verify(mFragment).startActivity(captor.capture());
assertThat(captor.getValue().getPackage()).isEqualTo(intentPackage);
assertThat(captor.getValue().getAction()).isEqualTo(intentAction);
assertThat(captor.getValue().getFlags() & intentFlags).isGreaterThan(0);
verify(mMetricsFeatureProvider).action(any(), eq(metricsAction));
} finally {

View File

@@ -0,0 +1,135 @@
/*
* Copyright (C) 2022 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;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.app.ActivityManager;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import com.android.settingslib.applications.ApplicationsState.AppEntry;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@RunWith(AndroidJUnit4.class)
public class AppLocaleUtilTest {
@Mock
private PackageManager mPackageManager;
@Mock
private ActivityManager mActivityManager;
@Mock
private AppEntry mEntry;
@Mock
private ApplicationInfo mApplicationInfo;
@Mock
private Resources mResources;
private Context mContext;
private String mDisallowedPackage = "com.disallowed.package";
private String mAallowedPackage = "com.allowed.package";
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = spy(ApplicationProvider.getApplicationContext());
when(mContext.getPackageManager()).thenReturn(mPackageManager);
when(mContext.getSystemService(ActivityManager.class)).thenReturn(mActivityManager);
}
@Test
public void isDisplayLocaleUi_showUI() throws PackageManager.NameNotFoundException {
setTestAppEntry(mAallowedPackage);
setDisallowedPackageName(mDisallowedPackage);
setApplicationInfo(/*no platform key*/false);
mEntry.hasLauncherEntry = true;
assertTrue(AppLocaleUtil.canDisplayLocaleUi(mContext, mEntry));
}
@Test
public void isDisplayLocaleUi_notShowUI_hasPlatformKey()
throws PackageManager.NameNotFoundException {
setTestAppEntry(mAallowedPackage);
setDisallowedPackageName(mDisallowedPackage);
setApplicationInfo(/*has platform key*/true);
mEntry.hasLauncherEntry = true;
assertFalse(AppLocaleUtil.canDisplayLocaleUi(mContext, mEntry));
}
@Test
public void isDisplayLocaleUi_notShowUI_noLauncherEntry()
throws PackageManager.NameNotFoundException {
setTestAppEntry(mAallowedPackage);
setDisallowedPackageName(mDisallowedPackage);
setApplicationInfo(/*no platform key*/false);
mEntry.hasLauncherEntry = false;
assertFalse(AppLocaleUtil.canDisplayLocaleUi(mContext, mEntry));
}
@Test
public void isDisplayLocaleUi_notShowUI_matchDisallowedPackageList()
throws PackageManager.NameNotFoundException {
setTestAppEntry(mDisallowedPackage);
setDisallowedPackageName(mDisallowedPackage);
setApplicationInfo(/*no platform key*/false);
mEntry.hasLauncherEntry = false;
assertFalse(AppLocaleUtil.canDisplayLocaleUi(mContext, mEntry));
}
private void setTestAppEntry(String packageName) {
mEntry.info = mApplicationInfo;
mApplicationInfo.packageName = packageName;
}
private void setDisallowedPackageName(String packageName) {
when(mContext.getResources()).thenReturn(mResources);
when(mResources.getStringArray(anyInt())).thenReturn(new String[]{packageName});
}
private void setApplicationInfo(boolean signedWithPlatformKey)
throws PackageManager.NameNotFoundException {
ApplicationInfo applicationInfo = new ApplicationInfo();
if (signedWithPlatformKey) {
applicationInfo.privateFlags = applicationInfo.privateFlags
| ApplicationInfo.PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY;
}
PackageInfo packageInfo = new PackageInfo();
packageInfo.applicationInfo = applicationInfo;
when(mPackageManager.getPackageInfoAsUser(anyString(), anyInt(), anyInt())).thenReturn(
packageInfo);
}
}

View File

@@ -53,7 +53,6 @@ public class AppLocaleDetailsTest {
private Context mContext;
private LocaleList mSystemLocales;
private Locale mSimLocale;
private LocaleList mAppLocale;
private String[] mAssetLocales;
@@ -69,7 +68,8 @@ public class AppLocaleDetailsTest {
when(mContext.getSystemService(LocaleManager.class)).thenReturn(mLocaleManager);
setupInitialLocales("en",
"uk",
"tw",
"jp",
"en, uk, jp, ne",
new String[]{"en", "ne", "ms", "pa"});
}
@@ -88,6 +88,8 @@ public class AppLocaleDetailsTest {
@Test
@UiThreadTest
public void handleAllLocalesData_1stLocaleOfSuggestedLocaleListIsAppLocale() {
Locale simCountryLocale = new Locale("zh", "TW");
Locale networkCountryLocale = new Locale("ja", "JP");
DummyAppLocaleDetailsHelper helper =
new DummyAppLocaleDetailsHelper(mContext, APP_PACKAGE_NAME);
@@ -95,25 +97,17 @@ public class AppLocaleDetailsTest {
Locale locale = Iterables.get(helper.getSuggestedLocales(), 0);
assertTrue(locale.equals(mAppLocale.get(0)));
assertTrue(helper.getSuggestedLocales().contains(simCountryLocale));
assertTrue(helper.getSuggestedLocales().contains(networkCountryLocale));
}
@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() {
public void handleAllLocalesData_withoutAppLocale_1stSuggestedLocaleIsSimCountryLocale() {
Locale simCountryLocale = new Locale("zh", "TW");
setupInitialLocales("",
"uk",
"tw",
"",
"en, uk, jp, ne",
new String[]{"en", "ne", "ms", "pa"});
DummyAppLocaleDetailsHelper helper =
@@ -122,13 +116,34 @@ public class AppLocaleDetailsTest {
helper.handleAllLocalesData();
Locale locale = Iterables.get(helper.getSuggestedLocales(), 0);
assertTrue(locale.equals(mSimLocale));
assertTrue(locale.equals(simCountryLocale));
assertFalse(helper.getSuggestedLocales().contains(mAppLocale.get(0)));
}
@Test
@UiThreadTest
public void handleAllLocalesData_noAppAndSimLocale_1stLocaleIsFirstOneInSystemLocales() {
public void handleAllLocalesData_withoutAppLocale_1stSuggestedLocaleIsNetworkCountryLocale() {
Locale networkCountryLocale = new Locale("en", "GB");
setupInitialLocales("",
"",
"gb",
"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(networkCountryLocale));
assertFalse(helper.getSuggestedLocales().contains(mAppLocale.get(0)));
}
@Test
@UiThreadTest
public void handleAllLocalesData_noAppAndSimNetworkLocale_1stLocaleIsFirstOneInSystemLocales() {
setupInitialLocales("",
"",
"",
"en, uk, jp, ne",
new String[]{"en", "ne", "ms", "pa"});
@@ -175,25 +190,34 @@ public class AppLocaleDetailsTest {
/**
* 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"}
* @param appLocale Application locale, it shall be a language tag.
* example: "en"
*
* @param simCountry The ISO-3166-1 alpha-2 country code equivalent for the SIM
* provider's country code.
* example: "us"
*
* @param networkCountry The ISO-3166-1 alpha-2 country code equivalent of the MCC
* (Mobile Country Code) of the current registered operato
* or the cell nearby.
* example: "us"
*
* @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 simCountry,
String networkCountry,
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(mTelephonyManager.getSimCountryIso()).thenReturn(simCountry);
when(mTelephonyManager.getNetworkCountryIso()).thenReturn(networkCountry);
when(mLocaleManager.getApplicationLocales(anyString())).thenReturn(mAppLocale);
}

View File

@@ -18,8 +18,6 @@ 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;
@@ -37,20 +35,27 @@ import org.mockito.MockitoAnnotations;
public class AppLocalePreferenceControllerTest {
private Context mContext;
private boolean mCanDisplayLocaleUi;
private AppLocalePreferenceController mController;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = spy(ApplicationProvider.getApplicationContext());
mContext = ApplicationProvider.getApplicationContext();
mController = spy(new AppLocalePreferenceController(mContext, "test_key"));
mController = new AppLocalePreferenceController(mContext, "test_key") {
@Override
boolean canDisplayLocaleUi() {
return mCanDisplayLocaleUi;
}
};
FeatureFlagUtils
.setEnabled(mContext, FeatureFlagUtils.SETTINGS_APP_LANGUAGE_SELECTION, true);
}
@Test
public void getAvailabilityStatus_featureFlagOff_shouldReturnUnavailable() {
public void getAvailabilityStatus_canShowUiButFeatureFlagOff_shouldReturnUnavailable() {
mCanDisplayLocaleUi = true;
FeatureFlagUtils
.setEnabled(mContext, FeatureFlagUtils.SETTINGS_APP_LANGUAGE_SELECTION, false);
@@ -59,8 +64,28 @@ public class AppLocalePreferenceControllerTest {
}
@Test
public void getAvailabilityStatus_featureFlagOn_shouldReturnAvailable() {
public void getAvailabilityStatus_canShowUiAndFeatureFlagOn_shouldReturnAvailable() {
mCanDisplayLocaleUi = true;
assertThat(mController.getAvailabilityStatus())
.isEqualTo(BasePreferenceController.AVAILABLE);
}
@Test
public void getAvailabilityStatus_featureFlagOnButCanNotShowUi_shouldReturnUnavailable() {
mCanDisplayLocaleUi = false;
assertThat(mController.getAvailabilityStatus())
.isEqualTo(BasePreferenceController.CONDITIONALLY_UNAVAILABLE);
}
@Test
public void getAvailabilityStatus_featureFlagOffAndCanNotShowUi_shouldReturnUnavailable() {
mCanDisplayLocaleUi = false;
FeatureFlagUtils
.setEnabled(mContext, FeatureFlagUtils.SETTINGS_APP_LANGUAGE_SELECTION, false);
assertThat(mController.getAvailabilityStatus())
.isEqualTo(BasePreferenceController.CONDITIONALLY_UNAVAILABLE);
}
}