diff --git a/res/layout/accessibility_launch_activity_preference.xml b/res/layout/accessibility_launch_activity_preference.xml index 5ec6bea4690..679120663ef 100644 --- a/res/layout/accessibility_launch_activity_preference.xml +++ b/res/layout/accessibility_launch_activity_preference.xml @@ -34,7 +34,7 @@ diff --git a/res/values/strings.xml b/res/values/strings.xml index b38552f61f0..4f67a35dc71 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -361,7 +361,7 @@ Language may differ from languages available in the app. Some apps may not support this setting. - Only apps that support language selection are shown here. + Set the language for each app. Your system, apps, and websites use the first supported language from your preferred languages. @@ -5164,7 +5164,7 @@ Battery Saver on - Learn more about Battery saver + Learn more about Battery Saver Some features may be limited @@ -5472,9 +5472,9 @@ Screen time for %s - By apps + View by apps - By systems + View by systems < %1$s @@ -9139,13 +9139,13 @@ Can access all files - Show full screen notifications + Full screen notifications - Allow app to show full screen notifications when the device is locked + Allow full screen notifications from this app - Allow the app to show notifications that take up the full screen when the device is locked. Apps may use these to highlight alarms, incoming calls, or other urgent notifications. + Allow this app to show notifications that take up the full screen when the device is locked. Apps may use these to highlight alarms, incoming calls, or other urgent notifications. Media management apps diff --git a/res/xml/security_settings_fingerprint.xml b/res/xml/security_settings_fingerprint.xml index a4ce545a7ff..0156ef97ac6 100644 --- a/res/xml/security_settings_fingerprint.xml +++ b/res/xml/security_settings_fingerprint.xml @@ -19,10 +19,21 @@ xmlns:settings="http://schemas.android.com/apk/res-auto" android:title="@string/security_settings_fingerprint_preference_title"> + + + + + + settings:controller="com.android.settings.biometrics.fingerprint.FingerprintUnlockCategoryController" + settings:isPreferenceVisible="false"> + + + diff --git a/src/com/android/settings/accessibility/PaletteListPreference.java b/src/com/android/settings/accessibility/PaletteListPreference.java index 4e10b936485..eec8b5a6cde 100644 --- a/src/com/android/settings/accessibility/PaletteListPreference.java +++ b/src/com/android/settings/accessibility/PaletteListPreference.java @@ -34,6 +34,7 @@ import android.widget.TextView; import androidx.annotation.ColorInt; import androidx.annotation.IntDef; +import androidx.core.text.TextUtilsCompat; import androidx.preference.Preference; import androidx.preference.PreferenceViewHolder; @@ -49,6 +50,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.List; +import java.util.Locale; import java.util.stream.Collectors; /** Preference that easier preview by matching name to color. */ @@ -156,10 +158,11 @@ public final class PaletteListPreference extends Preference { mGradientColors.set(Position.END, color); final GradientDrawable gradientDrawable = new GradientDrawable(); + final Locale locale = Locale.getDefault(); final Orientation orientation = - rootView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL - ? Orientation.RIGHT_LEFT - : Orientation.LEFT_RIGHT; + TextUtilsCompat.getLayoutDirectionFromLocale(locale) == View.LAYOUT_DIRECTION_RTL + ? Orientation.RIGHT_LEFT + : Orientation.LEFT_RIGHT; gradientDrawable.setOrientation(orientation); gradientDrawable.setColors(Ints.toArray(mGradientColors), Floats.toArray(mGradientOffsets)); diff --git a/src/com/android/settings/applications/AppStateLocaleBridge.java b/src/com/android/settings/applications/AppStateLocaleBridge.java index 2fea004778d..a50d61724d8 100644 --- a/src/com/android/settings/applications/AppStateLocaleBridge.java +++ b/src/com/android/settings/applications/AppStateLocaleBridge.java @@ -83,7 +83,7 @@ public class AppStateLocaleBridge extends AppStateBaseBridge { Log.d(TAG, "[" + entry.info.packageName + "]" + " has No extra info."); return false; } - return (Boolean) entry.extraInfo; + return entry.extraInfo == Boolean.TRUE; } }; diff --git a/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java b/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java index c627df3e198..f19fb91fccc 100644 --- a/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java +++ b/src/com/android/settings/applications/credentials/CredentialManagerPreferenceController.java @@ -23,6 +23,7 @@ import android.annotation.Nullable; import android.app.Activity; import android.app.Dialog; import android.content.ComponentName; +import android.content.ContentResolver; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; @@ -33,9 +34,11 @@ import android.content.res.Resources; import android.credentials.CredentialManager; import android.credentials.CredentialProviderInfo; import android.credentials.SetEnabledProvidersException; +import android.database.ContentObserver; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.Bundle; +import android.os.Handler; import android.os.OutcomeReceiver; import android.os.UserHandle; import android.provider.DeviceConfig; @@ -59,10 +62,12 @@ import androidx.preference.PreferenceScreen; import androidx.preference.SwitchPreference; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.content.PackageMonitor; import com.android.settings.R; import com.android.settings.Utils; import com.android.settings.core.BasePreferenceController; import com.android.settings.dashboard.DashboardFragment; +import com.android.settingslib.utils.ThreadUtils; import java.util.ArrayList; import java.util.HashMap; @@ -89,10 +94,12 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl private final Executor mExecutor; private final Map mPrefs = new HashMap<>(); // key is package name private final List mPendingServiceInfos = new ArrayList<>(); + private final Handler mHandler = new Handler(); private @Nullable FragmentManager mFragmentManager = null; private @Nullable Delegate mDelegate = null; private @Nullable String mFlagOverrideForTest = null; + private @Nullable PreferenceScreen mPreferenceScreen = null; public CredentialManagerPreferenceController(Context context, String preferenceKey) { super(context, preferenceKey); @@ -103,6 +110,7 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl mExecutor = ContextCompat.getMainExecutor(mContext); mCredentialManager = getCredentialManager(context, preferenceKey.equals("credentials_test")); + new SettingContentObserver(mHandler).register(context.getContentResolver()); } private @Nullable CredentialManager getCredentialManager(Context context, boolean isTest) { @@ -241,6 +249,25 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl update(); } + private void update() { + if (mCredentialManager == null) { + return; + } + + setAvailableServices( + mCredentialManager.getCredentialProviderServices( + getUser(), CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_ONLY), + null); + } + + private void updateFromExternal() { + update(); + + if (mPreferenceScreen != null) { + displayPreference(mPreferenceScreen); + } + } + @VisibleForTesting void setAvailableServices( List availableServices, @@ -276,6 +303,7 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl // Since the UI is being cleared, clear any refs. mPrefs.clear(); + mPreferenceScreen = screen; PreferenceGroup group = screen.findPreference(getPreferenceKey()); Context context = screen.getContext(); mPrefs.putAll(buildPreferenceList(context, group)); @@ -348,6 +376,10 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl Map> groupedInfos = new HashMap<>(); for (CredentialProviderInfo cpi : mServices) { String packageName = cpi.getServiceInfo().packageName; + if (isProviderHiddenBecauseOfAutofill(packageName)) { + continue; + } + if (!groupedInfos.containsKey(packageName)) { groupedInfos.put(packageName, new ArrayList<>()); } @@ -551,6 +583,23 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl return new NewProviderConfirmationDialogFragment(host, packageName, appName); } + /** If the provider is also the autofill provider then hide it. */ + @VisibleForTesting + public boolean isProviderHiddenBecauseOfAutofill(String packageName) { + final String autofillService = Settings.Secure.getStringForUser( + mContext.getContentResolver(), + Settings.Secure.AUTOFILL_SERVICE, + getUser()); + if (autofillService == null || TextUtils.isEmpty(autofillService)) { + return false; + } + if (packageName == null || TextUtils.isEmpty(packageName)) { + return false; + } + + return autofillService.startsWith(packageName); + } + @VisibleForTesting void completeEnableProviderDialogBox( int whichButton, String packageName, boolean setActivityResult) { @@ -655,20 +704,6 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl } }; - /** - * Update the data in this UI. - */ - private void update() { - if (mCredentialManager == null) { - return; - } - - setAvailableServices( - mCredentialManager.getCredentialProviderServices( - getUser(), CredentialManager.PROVIDER_FILTER_USER_PROVIDERS_ONLY), - null); - } - /** Dialog fragment parent class. */ private abstract static class CredentialManagerDialogFragment extends DialogFragment implements DialogInterface.OnClickListener { @@ -790,4 +825,28 @@ public class CredentialManagerPreferenceController extends BasePreferenceControl getDialogHost().onDialogClick(which); } } + + /** Updates the list if setting content changes. */ + private final class SettingContentObserver extends ContentObserver { + + private final Uri mAutofillService = + Settings.Secure.getUriFor(Settings.Secure.AUTOFILL_SERVICE); + + private final Uri mCredentialService = + Settings.Secure.getUriFor(Settings.Secure.CREDENTIAL_SERVICE); + + public SettingContentObserver(Handler handler) { + super(handler); + } + + public void register(ContentResolver contentResolver) { + contentResolver.registerContentObserver(mAutofillService, false, this, getUser()); + contentResolver.registerContentObserver(mCredentialService, false, this, getUser()); + } + + @Override + public void onChange(boolean selfChange, Uri uri) { + updateFromExternal(); + } + } } diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java index 40a719a35d4..a5e5f579c02 100644 --- a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java +++ b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java @@ -171,8 +171,12 @@ public class FingerprintSettings extends SubSettings { private static final String KEY_IS_ENROLLING = "is_enrolled"; private static final String KEY_REQUIRE_SCREEN_ON_TO_AUTH = "security_settings_require_screen_on_to_auth"; + private static final String KEY_FINGERPRINTS_ENROLLED_CATEGORY = + "security_settings_fingerprints_enrolled"; private static final String KEY_FINGERPRINT_UNLOCK_CATEGORY = "security_settings_fingerprint_unlock_category"; + private static final String KEY_FINGERPRINT_UNLOCK_FOOTER = + "security_settings_fingerprint_footer"; private static final int MSG_REFRESH_FINGERPRINT_TEMPLATES = 1000; private static final int MSG_FINGER_AUTH_SUCCESS = 1001; @@ -189,10 +193,15 @@ public class FingerprintSettings extends SubSettings { protected static final boolean DEBUG = false; private List mControllers; + private FingerprintUnlockCategoryController + mFingerprintUnlockCategoryPreferenceController; private FingerprintSettingsRequireScreenOnToAuthPreferenceController mRequireScreenOnToAuthPreferenceController; + private Preference mAddFingerprintPreference; private RestrictedSwitchPreference mRequireScreenOnToAuthPreference; + private PreferenceCategory mFingerprintsEnrolledCategory; private PreferenceCategory mFingerprintUnlockCategory; + private PreferenceCategory mFingerprintUnlockFooter; private FingerprintManager mFingerprintManager; private FingerprintUpdater mFingerprintUpdater; @@ -259,9 +268,6 @@ public class FingerprintSettings extends SubSettings { } private void updateDialog() { - if (isSfps()) { - setRequireScreenOnToAuthVisibility(); - } RenameDialog renameDialog = (RenameDialog) getFragmentManager(). findFragmentByTag(RenameDialog.class.getName()); if (renameDialog != null) { @@ -277,7 +283,8 @@ public class FingerprintSettings extends SubSettings { case MSG_REFRESH_FINGERPRINT_TEMPLATES: removeFingerprintPreference(msg.arg1); updateAddPreference(); - retryFingerprint(); + updateFingerprintUnlockCategoryVisibility(); + updatePreferences(); break; case MSG_FINGER_AUTH_SUCCESS: highlightFingerprintItem(msg.arg1); @@ -423,6 +430,9 @@ public class FingerprintSettings extends SubSettings { addFirstFingerprint(null); } } + final PreferenceScreen root = getPreferenceScreen(); + root.removeAll(); + addPreferencesFromResource(getPreferenceScreenResId()); updateFooterColumns(activity); } @@ -512,48 +522,33 @@ public class FingerprintSettings extends SubSettings { */ private PreferenceScreen createPreferenceHierarchy() { PreferenceScreen root = getPreferenceScreen(); - if (root != null) { - root.removeAll(); - } - final String fpPrefKey = addFingerprintItemPreferences(root); - if (isSfps()) { - scrollToPreference(fpPrefKey); - } - addPreferencesFromResource(getPreferenceScreenResId()); - mRequireScreenOnToAuthPreference = findPreference(KEY_REQUIRE_SCREEN_ON_TO_AUTH); - mFingerprintUnlockCategory = findPreference(KEY_FINGERPRINT_UNLOCK_CATEGORY); - for (AbstractPreferenceController controller : mControllers) { - ((FingerprintSettingsPreferenceController) controller).setUserId(mUserId); - } - mRequireScreenOnToAuthPreference.setChecked( - mRequireScreenOnToAuthPreferenceController.isChecked()); - mRequireScreenOnToAuthPreference.setOnPreferenceChangeListener( - (preference, newValue) -> { - boolean isChecked = ((SwitchPreference) preference).isChecked(); - mRequireScreenOnToAuthPreferenceController.setChecked(!isChecked); - return true; - }); - mFingerprintUnlockCategory.setVisible(false); - if (isSfps()) { - setRequireScreenOnToAuthVisibility(); - } + addFingerprintPreferences(root); setPreferenceScreen(root); return root; } - private void setRequireScreenOnToAuthVisibility() { - int fingerprintsEnrolled = mFingerprintManager.getEnrolledFingerprints(mUserId).size(); - final boolean removalInProgress = mRemovalSidecar.inProgress(); - // Removing last remaining fingerprint - if (fingerprintsEnrolled == 0 && removalInProgress) { - mFingerprintUnlockCategory.setVisible(false); - } else { - mFingerprintUnlockCategory.setVisible(true); + private void addFingerprintPreferences(PreferenceGroup root) { + final String fpPrefKey = addFingerprintItemPreferences(root); + if (isSfps()) { + scrollToPreference(fpPrefKey); + addFingerprintUnlockCategory(); } + for (AbstractPreferenceController controller : mControllers) { + if (controller instanceof FingerprintSettingsPreferenceController) { + ((FingerprintSettingsPreferenceController) controller).setUserId(mUserId); + } else if (controller instanceof FingerprintUnlockCategoryController) { + ((FingerprintUnlockCategoryController) controller).setUserId(mUserId); + } + } + createFooterPreference(root); } private String addFingerprintItemPreferences(PreferenceGroup root) { - root.removeAll(); + mFingerprintsEnrolledCategory = findPreference(KEY_FINGERPRINTS_ENROLLED_CATEGORY); + if (mFingerprintsEnrolledCategory != null) { + mFingerprintsEnrolledCategory.removeAll(); + } + String keyToReturn = KEY_FINGERPRINT_ADD; final List items = mFingerprintManager.getEnrolledFingerprints(mUserId); final int fingerprintCount = items.size(); @@ -576,22 +571,46 @@ public class FingerprintSettings extends SubSettings { if (mFingerprintsRenaming.containsKey(item.getBiometricId())) { pref.setTitle(mFingerprintsRenaming.get(item.getBiometricId())); } - root.addPreference(pref); + mFingerprintsEnrolledCategory.addPreference(pref); pref.setOnPreferenceChangeListener(this); } - - Preference addPreference = new Preference(root.getContext()); - addPreference.setKey(KEY_FINGERPRINT_ADD); - addPreference.setTitle(R.string.fingerprint_add_title); - addPreference.setIcon(R.drawable.ic_add_24dp); - root.addPreference(addPreference); - addPreference.setOnPreferenceChangeListener(this); - updateAddPreference(); - createFooterPreference(root); - + mAddFingerprintPreference = findPreference(KEY_FINGERPRINT_ADD); + setupAddFingerprintPreference(); return keyToReturn; } + private void setupAddFingerprintPreference() { + mAddFingerprintPreference.setOnPreferenceChangeListener(this); + updateAddPreference(); + } + + private void addFingerprintUnlockCategory() { + mFingerprintUnlockCategory = findPreference(KEY_FINGERPRINT_UNLOCK_CATEGORY); + setupFingerprintUnlockCategoryPreferences(); + updateFingerprintUnlockCategoryVisibility(); + } + + private void updateFingerprintUnlockCategoryVisibility() { + final boolean mFingerprintUnlockCategoryAvailable = + mFingerprintUnlockCategoryPreferenceController.isAvailable(); + if (mFingerprintUnlockCategory.isVisible() != mFingerprintUnlockCategoryAvailable) { + mFingerprintUnlockCategory.setVisible( + mFingerprintUnlockCategoryAvailable); + } + } + + private void setupFingerprintUnlockCategoryPreferences() { + mRequireScreenOnToAuthPreference = findPreference(KEY_REQUIRE_SCREEN_ON_TO_AUTH); + mRequireScreenOnToAuthPreference.setChecked( + mRequireScreenOnToAuthPreferenceController.isChecked()); + mRequireScreenOnToAuthPreference.setOnPreferenceChangeListener( + (preference, newValue) -> { + final boolean isChecked = ((SwitchPreference) preference).isChecked(); + mRequireScreenOnToAuthPreferenceController.setChecked(!isChecked); + return true; + }); + } + private void updateAddPreference() { if (getActivity() == null) { return; // Activity went away @@ -612,8 +631,8 @@ public class FingerprintSettings extends SubSettings { final boolean removalInProgress = mRemovalSidecar.inProgress(); CharSequence maxSummary = tooMany ? getContext().getString(R.string.fingerprint_add_max, max) : ""; - addPreference.setSummary(maxSummary); - addPreference.setEnabled(!tooMany && !removalInProgress && mToken != null); + mAddFingerprintPreference.setSummary(maxSummary); + mAddFingerprintPreference.setEnabled(!tooMany && !removalInProgress && mToken != null); } private void createFooterPreference(PreferenceGroup root) { @@ -621,6 +640,10 @@ public class FingerprintSettings extends SubSettings { if (context == null) { return; } + mFingerprintUnlockFooter = findPreference(KEY_FINGERPRINT_UNLOCK_FOOTER); + if (mFingerprintUnlockFooter != null) { + mFingerprintUnlockFooter.removeAll(); + } for (int i = 0; i < mFooterColumns.size(); ++i) { final FooterColumn column = mFooterColumns.get(i); final FooterPreference footer = new FooterPreference.Builder(context) @@ -634,7 +657,7 @@ public class FingerprintSettings extends SubSettings { footer.setLearnMoreText(column.mLearnMoreOverrideText); } } - root.addPreference(footer); + mFingerprintUnlockFooter.addPreference(footer); } } @@ -815,11 +838,17 @@ public class FingerprintSettings extends SubSettings { private List buildPreferenceControllers(Context context) { final List controllers = new ArrayList<>(); + mFingerprintUnlockCategoryPreferenceController = + new FingerprintUnlockCategoryController( + context, + KEY_FINGERPRINT_UNLOCK_CATEGORY + ); mRequireScreenOnToAuthPreferenceController = new FingerprintSettingsRequireScreenOnToAuthPreferenceController( context, KEY_REQUIRE_SCREEN_ON_TO_AUTH ); + controllers.add(mFingerprintUnlockCategoryPreferenceController); controllers.add(mRequireScreenOnToAuthPreferenceController); return controllers; } diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsRequireScreenOnToAuthPreferenceController.java b/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsRequireScreenOnToAuthPreferenceController.java index 52e6d135abc..87396dd91d5 100644 --- a/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsRequireScreenOnToAuthPreferenceController.java +++ b/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsRequireScreenOnToAuthPreferenceController.java @@ -94,7 +94,7 @@ public class FingerprintSettingsRequireScreenOnToAuthPreferenceController && mFingerprintManager.isHardwareDetected() && mFingerprintManager.isPowerbuttonFps()) { return mFingerprintManager.hasEnrolledTemplates(getUserId()) - ? AVAILABLE : DISABLED_DEPENDENT_SETTING; + ? AVAILABLE : CONDITIONALLY_UNAVAILABLE; } else { return UNSUPPORTED_ON_DEVICE; } diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintUnlockCategoryController.java b/src/com/android/settings/biometrics/fingerprint/FingerprintUnlockCategoryController.java new file mode 100644 index 00000000000..674a0dfa758 --- /dev/null +++ b/src/com/android/settings/biometrics/fingerprint/FingerprintUnlockCategoryController.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2023 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.biometrics.fingerprint; + +import android.content.Context; +import android.hardware.fingerprint.FingerprintManager; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.settings.Utils; +import com.android.settings.core.BasePreferenceController; + +/** + * Preference controller that controls the fingerprint unlock features to be shown / be hidden. + */ +public class FingerprintUnlockCategoryController extends BasePreferenceController { + private static final String TAG = "FingerprintUnlockCategoryPreferenceController"; + + private int mUserId; + @VisibleForTesting + protected FingerprintManager mFingerprintManager; + + public FingerprintUnlockCategoryController(Context context, String key) { + super(context, key); + mFingerprintManager = Utils.getFingerprintManagerOrNull(context); + } + + @Override + public int getAvailabilityStatus() { + if (mFingerprintManager != null + && mFingerprintManager.isHardwareDetected() + && mFingerprintManager.isPowerbuttonFps()) { + return mFingerprintManager.hasEnrolledTemplates(getUserId()) + ? AVAILABLE : CONDITIONALLY_UNAVAILABLE; + } else { + return UNSUPPORTED_ON_DEVICE; + } + } + + public void setUserId(int userId) { + mUserId = userId; + } + + protected int getUserId() { + return mUserId; + } +} diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintsEnrolledCategoryPreferenceController.java b/src/com/android/settings/biometrics/fingerprint/FingerprintsEnrolledCategoryPreferenceController.java new file mode 100644 index 00000000000..53d53797515 --- /dev/null +++ b/src/com/android/settings/biometrics/fingerprint/FingerprintsEnrolledCategoryPreferenceController.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2023 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.biometrics.fingerprint; + +import android.content.Context; +import android.hardware.fingerprint.FingerprintManager; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.settings.Utils; +import com.android.settings.core.BasePreferenceController; + +/** + * Preference controller that controls the enrolled fingerprints to be shown / be hidden. + */ +public class FingerprintsEnrolledCategoryPreferenceController extends BasePreferenceController { + private static final String TAG = "FingerprintsEnrolledCategoryPreferenceController"; + + private int mUserId; + @VisibleForTesting + protected FingerprintManager mFingerprintManager; + + public FingerprintsEnrolledCategoryPreferenceController(Context context, String key) { + super(context, key); + mFingerprintManager = Utils.getFingerprintManagerOrNull(context); + } + + @Override + public int getAvailabilityStatus() { + if (mFingerprintManager != null + && mFingerprintManager.isHardwareDetected()) { + return mFingerprintManager.hasEnrolledTemplates(getUserId()) + ? AVAILABLE : CONDITIONALLY_UNAVAILABLE; + } else { + return UNSUPPORTED_ON_DEVICE; + } + } + + public void setUserId(int userId) { + mUserId = userId; + } + + protected int getUserId() { + return mUserId; + } +} diff --git a/src/com/android/settings/bluetooth/BluetoothEnabler.java b/src/com/android/settings/bluetooth/BluetoothEnabler.java index 483e46af595..de49ce1ef52 100644 --- a/src/com/android/settings/bluetooth/BluetoothEnabler.java +++ b/src/com/android/settings/bluetooth/BluetoothEnabler.java @@ -223,7 +223,6 @@ public final class BluetoothEnabler implements SwitchWidgetController.OnSwitchCh mSwitchController.setDisabledByAdmin(admin); if (admin != null) { mSwitchController.setChecked(false); - mSwitchController.setEnabled(false); } return admin != null; } diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownController.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownController.java index c272a499194..b262dee93ab 100644 --- a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownController.java +++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownController.java @@ -177,8 +177,8 @@ public class BatteryUsageBreakdownController extends BasePreferenceController mAppListPreferenceGroup.setOrderingAsAdded(false); mSpinnerPreference.initializeSpinner( new String[]{ - mPrefContext.getString(R.string.battery_usage_spinner_by_apps), - mPrefContext.getString(R.string.battery_usage_spinner_by_systems) + mPrefContext.getString(R.string.battery_usage_spinner_view_by_apps), + mPrefContext.getString(R.string.battery_usage_spinner_view_by_systems) }, new AdapterView.OnItemSelectedListener() { @Override diff --git a/src/com/android/settings/location/LocationSwitchBarController.java b/src/com/android/settings/location/LocationSwitchBarController.java index c84014f04d8..b150b1d93c0 100644 --- a/src/com/android/settings/location/LocationSwitchBarController.java +++ b/src/com/android/settings/location/LocationSwitchBarController.java @@ -15,6 +15,7 @@ package com.android.settings.location; import android.content.Context; import android.os.UserHandle; +import android.os.UserManager; import android.widget.Switch; import com.android.settings.widget.SettingsMainSwitchBar; @@ -75,8 +76,12 @@ public class LocationSwitchBarController implements OnMainSwitchChangeListener, // only, it would be re-enabled again if the switch bar is not disabled. if (!hasBaseUserRestriction && admin != null) { mSwitchBar.setDisabledByAdmin(admin); + } else if (restricted) { + RestrictedLockUtils.EnforcedAdmin enforcedAdmin = RestrictedLockUtils.EnforcedAdmin + .createDefaultEnforcedAdminWithRestriction(UserManager.DISALLOW_SHARE_LOCATION); + mSwitchBar.setDisabledByAdmin(enforcedAdmin); } else { - mSwitchBar.setEnabled(!restricted); + mSwitchBar.setEnabled(true); } if (enabled != mSwitchBar.isChecked()) { diff --git a/src/com/android/settings/notification/app/ChannelPanelActivity.java b/src/com/android/settings/notification/app/ChannelPanelActivity.java index 9889183d4d7..dda1c65869c 100644 --- a/src/com/android/settings/notification/app/ChannelPanelActivity.java +++ b/src/com/android/settings/notification/app/ChannelPanelActivity.java @@ -28,10 +28,13 @@ import android.view.WindowManager; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.core.view.ViewCompat; +import androidx.core.view.WindowInsetsControllerCompat; import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentManager; import com.android.settings.R; +import com.android.settings.Utils; import com.android.settings.core.SubSettingLauncher; import com.android.settingslib.core.lifecycle.HideNonSystemOverlayMixin; @@ -99,7 +102,7 @@ public class ChannelPanelActivity extends FragmentActivity { findViewById(R.id.done).setOnClickListener(v -> finish()); findViewById(R.id.see_more).setOnClickListener(v -> launchFullSettings()); - + setupNavigationBar(); mPanelFragment = callingIntent.hasExtra(Settings.EXTRA_CONVERSATION_ID) ? new ConversationNotificationSettings() : new ChannelNotificationSettings(); @@ -107,4 +110,27 @@ public class ChannelPanelActivity extends FragmentActivity { fragmentManager.beginTransaction().replace( android.R.id.list_container, mPanelFragment).commit(); } + + /** + * Adjust bottom edge and color. + */ + private void setupNavigationBar() { + // Extend the panel all the way to the bottom of the screen, as opposed to sitting on top of + // the navigation bar. + ViewCompat.setOnApplyWindowInsetsListener(getWindow().getDecorView(), + (v, windowInsets) -> { + v.setPadding(v.getPaddingLeft(), v.getPaddingTop(), v.getPaddingRight(), 0); + return windowInsets; // propagate down to panel layout root element + }); + + // When using 3-button navigation in light mode, the system picks white navigation buttons + // which are not sufficiently contrasted from the panel background. + WindowInsetsControllerCompat windowInsetsController = + ViewCompat.getWindowInsetsController(getWindow().getDecorView()); + + if (windowInsetsController != null) { + boolean forceNavigationButtonsDark = !Utils.isNightMode(this); + windowInsetsController.setAppearanceLightNavigationBars(forceNavigationButtonsDark); + } + } } diff --git a/src/com/android/settings/widget/SettingsMainSwitchBar.java b/src/com/android/settings/widget/SettingsMainSwitchBar.java index 5ad16d79f99..8b8a9bae494 100644 --- a/src/com/android/settings/widget/SettingsMainSwitchBar.java +++ b/src/com/android/settings/widget/SettingsMainSwitchBar.java @@ -21,14 +21,12 @@ import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; import android.content.Context; import android.util.AttributeSet; import android.view.View; -import android.widget.ImageView; import android.widget.Switch; import com.android.settings.overlay.FeatureFactory; import com.android.settingslib.RestrictedLockUtils; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.widget.MainSwitchBar; -import com.android.settingslib.widget.R; /** * A {@link MainSwitchBar} with a customized Switch and provides the metrics feature. @@ -47,7 +45,6 @@ public class SettingsMainSwitchBar extends MainSwitchBar { boolean onBeforeCheckedChanged(Switch switchView, boolean isChecked); } - private ImageView mRestrictedIcon; private EnforcedAdmin mEnforcedAdmin; private boolean mDisabledByAdmin; @@ -74,14 +71,6 @@ public class SettingsMainSwitchBar extends MainSwitchBar { mMetricsFeatureProvider = FeatureFactory.getFactory(context).getMetricsFeatureProvider(); addOnSwitchChangeListener((switchView, isChecked) -> logMetrics(isChecked)); - - mRestrictedIcon = findViewById(R.id.restricted_icon); - mRestrictedIcon.setOnClickListener((View v) -> { - if (mDisabledByAdmin) { - RestrictedLockUtils.sendShowAdminSupportDetailsIntent(context, mEnforcedAdmin); - onRestrictedIconClick(); - } - }); } /** @@ -95,12 +84,9 @@ public class SettingsMainSwitchBar extends MainSwitchBar { mDisabledByAdmin = true; mTextView.setEnabled(false); mSwitch.setEnabled(false); - mSwitch.setVisibility(View.GONE); - mRestrictedIcon.setVisibility(View.VISIBLE); } else { mDisabledByAdmin = false; mSwitch.setVisibility(View.VISIBLE); - mRestrictedIcon.setVisibility(View.GONE); setEnabled(isEnabled()); } } @@ -120,11 +106,12 @@ public class SettingsMainSwitchBar extends MainSwitchBar { @Override public boolean performClick() { - return getDelegatingView().performClick(); - } + if (mDisabledByAdmin) { + performRestrictedClick(); + return true; + } - protected void onRestrictedIconClick() { - mMetricsFeatureProvider.clicked(mMetricsCategory, "switch_bar|restricted"); + return mSwitch.performClick(); } @Override @@ -157,11 +144,12 @@ public class SettingsMainSwitchBar extends MainSwitchBar { mMetricsCategory = category; } - private View getDelegatingView() { - return mDisabledByAdmin ? mRestrictedIcon : mSwitch; - } - private void logMetrics(boolean isChecked) { mMetricsFeatureProvider.changed(mMetricsCategory, "switch_bar", isChecked ? 1 : 0); } + + private void performRestrictedClick() { + RestrictedLockUtils.sendShowAdminSupportDetailsIntent(getContext(), mEnforcedAdmin); + mMetricsFeatureProvider.clicked(mMetricsCategory, "switch_bar|restricted"); + } } diff --git a/src/com/android/settings/wifi/tether/WifiTetherSettings.java b/src/com/android/settings/wifi/tether/WifiTetherSettings.java index 2774be66585..4ce59b9b53f 100644 --- a/src/com/android/settings/wifi/tether/WifiTetherSettings.java +++ b/src/com/android/settings/wifi/tether/WifiTetherSettings.java @@ -80,11 +80,14 @@ public class WifiTetherSettings extends RestrictedDashboardFragment @VisibleForTesting SettingsMainSwitchBar mMainSwitchBar; private WifiTetherSwitchBarController mSwitchBarController; - private WifiTetherSSIDPreferenceController mSSIDPreferenceController; - private WifiTetherPasswordPreferenceController mPasswordPreferenceController; + @VisibleForTesting + WifiTetherSSIDPreferenceController mSSIDPreferenceController; + @VisibleForTesting + WifiTetherPasswordPreferenceController mPasswordPreferenceController; private WifiTetherSecurityPreferenceController mSecurityPreferenceController; private WifiTetherMaximizeCompatibilityPreferenceController mMaxCompatibilityPrefController; - private WifiTetherAutoOffPreferenceController mWifiTetherAutoOffPreferenceController; + @VisibleForTesting + WifiTetherAutoOffPreferenceController mWifiTetherAutoOffPreferenceController; private boolean mUnavailable; private WifiRestriction mWifiRestriction; @@ -269,10 +272,12 @@ public class WifiTetherSettings extends RestrictedDashboardFragment setLoading(restarting, false); } - private SoftApConfiguration buildNewConfig() { - SoftApConfiguration.Builder configBuilder = new SoftApConfiguration.Builder(); + @VisibleForTesting + SoftApConfiguration buildNewConfig() { + SoftApConfiguration currentConfig = mWifiTetherViewModel.getSoftApConfiguration(); + SoftApConfiguration.Builder configBuilder = new SoftApConfiguration.Builder(currentConfig); int securityType = (mWifiTetherViewModel.isSpeedFeatureAvailable()) - ? mWifiTetherViewModel.getSoftApConfiguration().getSecurityType() + ? currentConfig.getSecurityType() : mSecurityPreferenceController.getSecurityType(); configBuilder.setSsid(mSSIDPreferenceController.getSSID()); if (securityType != SoftApConfiguration.SECURITY_TYPE_OPEN) { diff --git a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsRequireScreenOnToAuthPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsRequireScreenOnToAuthPreferenceControllerTest.java index b6df62eeff7..ebfa6d5d62d 100644 --- a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsRequireScreenOnToAuthPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsRequireScreenOnToAuthPreferenceControllerTest.java @@ -17,7 +17,7 @@ package com.android.settings.biometrics.fingerprint; import static com.android.settings.core.BasePreferenceController.AVAILABLE; -import static com.android.settings.core.BasePreferenceController.DISABLED_DEPENDENT_SETTING; +import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE; import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE; import static com.google.common.truth.Truth.assertThat; @@ -103,15 +103,15 @@ public class FingerprintSettingsRequireScreenOnToAuthPreferenceControllerTest { } @Test - public void isAvailable_isDisabled_whenSfpsHardwareDetected_AndNoEnrolledFingerprints() { + public void isUnavailable_isDisabled_whenSfpsHardwareDetected_AndNoEnrolledFingerprints() { assertThat(mController.isAvailable()).isEqualTo(false); assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE); configure_hardwareDetected_isSfps_hasEnrolledTemplates( true /* isHardwareDetected */, true /* isPowerbuttonFps */, false /* hasEnrolledTemplates */); - assertThat(mController.isAvailable()).isEqualTo(true); - assertThat(mController.getAvailabilityStatus()).isEqualTo(DISABLED_DEPENDENT_SETTING); + assertThat(mController.isAvailable()).isEqualTo(false); + assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE); } @Test @@ -122,7 +122,7 @@ public class FingerprintSettingsRequireScreenOnToAuthPreferenceControllerTest { false /* isHardwareDetected */, true /* isPowerbuttonFps */, true /* hasEnrolledTemplates */); - assertThat(mController.isAvailable()).isFalse(); + assertThat(mController.isAvailable()).isEqualTo(false); assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE); } diff --git a/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsUnlockCategoryControllerTest.java b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsUnlockCategoryControllerTest.java new file mode 100644 index 00000000000..7b6a70ed7ef --- /dev/null +++ b/tests/robotests/src/com/android/settings/biometrics/fingerprint/FingerprintSettingsUnlockCategoryControllerTest.java @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2023 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.biometrics.fingerprint; + +import static com.android.settings.core.BasePreferenceController.AVAILABLE; +import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE; +import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.content.pm.PackageManager; +import android.hardware.fingerprint.FingerprintManager; + +import com.android.settings.testutils.shadow.ShadowUtils; +import com.android.settingslib.RestrictedSwitchPreference; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; +import org.robolectric.util.ReflectionHelpers; + +@RunWith(RobolectricTestRunner.class) +@Config(shadows = {ShadowUtils.class}) +public class FingerprintSettingsUnlockCategoryControllerTest { + + @Mock + private FingerprintManager mFingerprintManager; + @Mock + private PackageManager mPackageManager; + @Mock + private RestrictedSwitchPreference mPreference; + + private Context mContext; + private FingerprintSettingsRequireScreenOnToAuthPreferenceController mController; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = spy(RuntimeEnvironment.application); + when(mContext.getSystemService(eq(Context.FINGERPRINT_SERVICE))).thenReturn( + mFingerprintManager); + when(mContext.getPackageManager()).thenReturn(mPackageManager); + + mController = spy(new FingerprintSettingsRequireScreenOnToAuthPreferenceController(mContext, + "test_key")); + ReflectionHelpers.setField(mController, "mFingerprintManager", mFingerprintManager); + } + + @After + public void tearDown() { + ShadowUtils.reset(); + } + + @Test + public void isAvailable_isEnabled_whenSfpsHardwareDetected_AndHasEnrolledFingerprints() { + assertThat(mController.isAvailable()).isEqualTo(false); + assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE); + configure_hardwareDetected_isSfps_hasEnrolledTemplates( + true /* isHardwareDetected */, + true /* isPowerbuttonFps */, + true /* hasEnrolledTemplates */); + assertThat(mController.isAvailable()).isEqualTo(true); + assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE); + } + + @Test + public void isUnavailable_isDisabled_whenSfpsHardwareDetected_AndNoEnrolledFingerprints() { + assertThat(mController.isAvailable()).isEqualTo(false); + assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE); + configure_hardwareDetected_isSfps_hasEnrolledTemplates( + true /* isHardwareDetected */, + true /* isPowerbuttonFps */, + false /* hasEnrolledTemplates */); + assertThat(mController.isAvailable()).isEqualTo(false); + assertThat(mController.getAvailabilityStatus()).isEqualTo(CONDITIONALLY_UNAVAILABLE); + } + + @Test + public void isUnavailable_whenHardwareNotDetected() { + assertThat(mController.isAvailable()).isFalse(); + assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE); + configure_hardwareDetected_isSfps_hasEnrolledTemplates( + false /* isHardwareDetected */, + true /* isPowerbuttonFps */, + true /* hasEnrolledTemplates */); + assertThat(mController.isAvailable()).isEqualTo(false); + assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE); + } + + @Test + public void isUnavailable_onNonSfpsDevice() { + assertThat(mController.isAvailable()).isFalse(); + assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE); + configure_hardwareDetected_isSfps_hasEnrolledTemplates( + true /* isHardwareDetected */, + false /* isPowerbuttonFps */, + true /* hasEnrolledTemplates */); + assertThat(mController.isAvailable()).isFalse(); + assertThat(mController.getAvailabilityStatus()).isEqualTo(UNSUPPORTED_ON_DEVICE); + } + + private void configure_hardwareDetected_isSfps_hasEnrolledTemplates( + boolean isHardwareDetected, boolean isPowerbuttonFps, boolean hasEnrolledTemplates) { + when(mFingerprintManager.isHardwareDetected()).thenReturn(isHardwareDetected); + when(mFingerprintManager.isPowerbuttonFps()).thenReturn(isPowerbuttonFps); + when(mFingerprintManager.hasEnrolledTemplates(anyInt())).thenReturn(hasEnrolledTemplates); + } + +} diff --git a/tests/robotests/src/com/android/settings/location/LocationSwitchBarControllerTest.java b/tests/robotests/src/com/android/settings/location/LocationSwitchBarControllerTest.java index 348f64d975d..50f618f5ffe 100644 --- a/tests/robotests/src/com/android/settings/location/LocationSwitchBarControllerTest.java +++ b/tests/robotests/src/com/android/settings/location/LocationSwitchBarControllerTest.java @@ -23,6 +23,7 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.content.Context; +import android.os.UserManager; import android.provider.Settings; import android.widget.Switch; @@ -108,14 +109,26 @@ public class LocationSwitchBarControllerTest { verify(mSwitchBar).setDisabledByAdmin(admin); } + @Test + public void onLocationModeChanged_Restricted_shouldDisableSwitchByAdmin() { + final RestrictedLockUtils.EnforcedAdmin admin = RestrictedLockUtils.EnforcedAdmin + .createDefaultEnforcedAdminWithRestriction(UserManager.DISALLOW_SHARE_LOCATION); + doReturn(null).when(mEnabler).getShareLocationEnforcedAdmin(anyInt()); + doReturn(false).when(mEnabler).hasShareLocationRestriction(anyInt()); + + mController.onLocationModeChanged(Settings.Secure.LOCATION_MODE_BATTERY_SAVING, true); + + verify(mSwitchBar).setDisabledByAdmin(admin); + } + @Test public void onLocationModeChanged_Restricted_shouldDisableSwitch() { doReturn(null).when(mEnabler).getShareLocationEnforcedAdmin(anyInt()); doReturn(true).when(mEnabler).hasShareLocationRestriction(anyInt()); - mController.onLocationModeChanged(Settings.Secure.LOCATION_MODE_BATTERY_SAVING, true); + mController.onLocationModeChanged(Settings.Secure.LOCATION_MODE_BATTERY_SAVING, false); - verify(mSwitchBar).setEnabled(false); + verify(mSwitchBar).setEnabled(true); } @Test diff --git a/tests/robotests/src/com/android/settings/widget/SettingsMainSwitchBarTest.java b/tests/robotests/src/com/android/settings/widget/SettingsMainSwitchBarTest.java new file mode 100644 index 00000000000..dc69d8e0dfb --- /dev/null +++ b/tests/robotests/src/com/android/settings/widget/SettingsMainSwitchBarTest.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2023 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.widget; + +import static com.google.common.truth.Truth.assertThat; + +import android.content.Context; +import android.widget.TextView; + +import com.android.settingslib.R; +import com.android.settingslib.RestrictedLockUtils; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.RuntimeEnvironment; + +@RunWith(RobolectricTestRunner.class) +public class SettingsMainSwitchBarTest { + + private SettingsMainSwitchBar mMainSwitchBar; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + final Context context = RuntimeEnvironment.application; + mMainSwitchBar = new SettingsMainSwitchBar(context); + } + + @Test + public void disabledByAdmin_shouldBeDisabled() { + mMainSwitchBar.setDisabledByAdmin(new RestrictedLockUtils.EnforcedAdmin()); + + TextView title = (TextView) mMainSwitchBar.findViewById(R.id.switch_text); + assertThat(title.isEnabled()).isFalse(); + assertThat(mMainSwitchBar.getSwitch().isEnabled()).isFalse(); + } + + @Test + public void disabledByAdmin_setNull_shouldBeEnabled() { + mMainSwitchBar.setDisabledByAdmin(null); + + TextView title = (TextView) mMainSwitchBar.findViewById(R.id.switch_text); + assertThat(title.isEnabled()).isTrue(); + assertThat(mMainSwitchBar.getSwitch().isEnabled()).isTrue(); + } +} diff --git a/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSettingsTest.java b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSettingsTest.java index 0a54c888d58..fe663abbc28 100644 --- a/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSettingsTest.java +++ b/tests/robotests/src/com/android/settings/wifi/tether/WifiTetherSettingsTest.java @@ -16,10 +16,12 @@ package com.android.settings.wifi.tether; +import static android.net.wifi.SoftApConfiguration.SECURITY_TYPE_WPA3_SAE; import static android.view.View.INVISIBLE; import static android.view.View.VISIBLE; import static com.android.settings.wifi.WifiUtils.setCanShowWifiHotspotCached; +import static com.android.settings.wifi.repository.WifiHotspotRepository.BAND_2GHZ_5GHZ_6GHZ; import static com.android.settings.wifi.tether.WifiTetherSettings.KEY_WIFI_HOTSPOT_SECURITY; import static com.android.settings.wifi.tether.WifiTetherSettings.KEY_WIFI_HOTSPOT_SPEED; @@ -41,6 +43,7 @@ import android.content.Context; import android.content.res.Resources; import android.net.ConnectivityManager; import android.net.TetheringManager; +import android.net.wifi.SoftApConfiguration; import android.net.wifi.WifiManager; import android.os.Bundle; import android.os.UserManager; @@ -84,6 +87,8 @@ public class WifiTetherSettingsTest { private static final int XML_RES = R.xml.wifi_tether_settings; private static final String[] WIFI_REGEXS = {"wifi_regexs"}; + private static final String SSID = "ssid"; + private static final String PASSWORD = "password"; @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule(); @@ -117,6 +122,12 @@ public class WifiTetherSettingsTest { private LiveData mSpeedSummary; @Mock private SettingsMainSwitchBar mMainSwitchBar; + @Mock + private WifiTetherSSIDPreferenceController mSSIDPreferenceController; + @Mock + private WifiTetherPasswordPreferenceController mPasswordPreferenceController; + @Mock + private WifiTetherAutoOffPreferenceController mWifiTetherAutoOffPreferenceController; private WifiTetherSettings mSettings; @@ -143,6 +154,12 @@ public class WifiTetherSettingsTest { mSettings = spy(new WifiTetherSettings(mWifiRestriction)); mSettings.mMainSwitchBar = mMainSwitchBar; + mSettings.mSSIDPreferenceController = mSSIDPreferenceController; + when(mSSIDPreferenceController.getSSID()).thenReturn(SSID); + mSettings.mPasswordPreferenceController = mPasswordPreferenceController; + when(mPasswordPreferenceController.getPasswordValidated(anyInt())).thenReturn(PASSWORD); + mSettings.mWifiTetherAutoOffPreferenceController = mWifiTetherAutoOffPreferenceController; + when(mWifiTetherAutoOffPreferenceController.isEnabled()).thenReturn(true); mSettings.mWifiTetherViewModel = mWifiTetherViewModel; when(mSettings.findPreference(KEY_WIFI_HOTSPOT_SECURITY)).thenReturn(mWifiHotspotSecurity); when(mSettings.findPreference(KEY_WIFI_HOTSPOT_SPEED)).thenReturn(mWifiHotspotSpeed); @@ -326,6 +343,22 @@ public class WifiTetherSettingsTest { verify(mSettings).setLoading(true, false); } + @Test + public void buildNewConfig_speedFeatureIsAvailableAndPasswordChanged_bandShouldNotBeLost() { + String newPassword = "new" + PASSWORD; + SoftApConfiguration currentConfig = new SoftApConfiguration.Builder() + .setPassphrase(PASSWORD, SECURITY_TYPE_WPA3_SAE) + .setBand(BAND_2GHZ_5GHZ_6GHZ) + .build(); + when(mWifiTetherViewModel.getSoftApConfiguration()).thenReturn(currentConfig); + when(mWifiTetherViewModel.isSpeedFeatureAvailable()).thenReturn(true); + when(mPasswordPreferenceController.getPasswordValidated(anyInt())).thenReturn(newPassword); + + SoftApConfiguration newConfig = mSettings.buildNewConfig(); + + assertThat(newConfig.getBand()).isEqualTo(currentConfig.getBand()); + } + @Test public void onRestartingChanged_restartingFalse_setLoadingFalse() { doNothing().when(mSettings).setLoading(anyBoolean(), anyBoolean()); diff --git a/tests/unit/src/com/android/settings/applications/credentials/CredentialManagerPreferenceControllerTest.java b/tests/unit/src/com/android/settings/applications/credentials/CredentialManagerPreferenceControllerTest.java index 2a2aaee9494..3145cce1ac6 100644 --- a/tests/unit/src/com/android/settings/applications/credentials/CredentialManagerPreferenceControllerTest.java +++ b/tests/unit/src/com/android/settings/applications/credentials/CredentialManagerPreferenceControllerTest.java @@ -122,6 +122,25 @@ public class CredentialManagerPreferenceControllerTest { assertThat(controller.getAvailabilityStatus()).isEqualTo(AVAILABLE); } + @Test + public void verifyHiddenIfAutofillSelectedProvider() { + CredentialManagerPreferenceController controller = + createControllerWithServices(Collections.emptyList()); + + // Set the autofill provider. + Settings.Secure.putStringForUser(mContext.getContentResolver(), + Settings.Secure.AUTOFILL_SERVICE, "com.example.test/AutofillClass", + UserHandle.myUserId()); + + // Verify the error cases + assertThat(controller.isProviderHiddenBecauseOfAutofill(null)).isFalse(); + assertThat(controller.isProviderHiddenBecauseOfAutofill("")).isFalse(); + assertThat(controller.isProviderHiddenBecauseOfAutofill("test")).isFalse(); + + // Verify the example. + assertThat(controller.isProviderHiddenBecauseOfAutofill("com.example.test")).isTrue(); + } + @Test public void displayPreference_noServices_noPreferencesAdded_useAutofillUri() { Settings.Secure.putStringForUser(