diff --git a/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollProgressViewModel.java b/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollProgressViewModel.java index b1b420db9a3..695ea0d0c0f 100644 --- a/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollProgressViewModel.java +++ b/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollProgressViewModel.java @@ -16,6 +16,8 @@ package com.android.settings.biometrics2.ui.viewmodel; +import static android.hardware.fingerprint.FingerprintManager.ENROLL_ENROLL; + import static com.android.settings.biometrics2.ui.model.EnrollmentProgress.INITIAL_REMAINING; import static com.android.settings.biometrics2.ui.model.EnrollmentProgress.INITIAL_STEPS; @@ -63,7 +65,6 @@ public class FingerprintEnrollProgressViewModel extends AndroidViewModel { private final int mUserId; private final FingerprintUpdater mFingerprintUpdater; - private final MessageDisplayController mMessageDisplayController; @Nullable private CancellationSignal mCancellationSignal = null; private final EnrollmentCallback mEnrollmentCallback = new EnrollmentCallback() { @@ -81,6 +82,9 @@ public class FingerprintEnrollProgressViewModel extends AndroidViewModel { @Override public void onEnrollmentHelp(int helpMsgId, CharSequence helpString) { + if (DEBUG) { + Log.d(TAG, "onEnrollmentHelp(" + helpMsgId + ", " + helpString + ")"); + } mHelpMessageLiveData.postValue(new EnrollmentStatusMessage(helpMsgId, helpString)); } @@ -113,20 +117,6 @@ public class FingerprintEnrollProgressViewModel extends AndroidViewModel { super(application); mFingerprintUpdater = fingerprintUpdater; mUserId = userId; - - final Resources res = application.getResources(); - mMessageDisplayController = - res.getBoolean(R.bool.enrollment_message_display_controller_flag) - ? new MessageDisplayController( - application.getMainThreadHandler(), - mEnrollmentCallback, - SystemClock.elapsedRealtimeClock(), - res.getInteger(R.integer.enrollment_help_minimum_time_display), - res.getInteger(R.integer.enrollment_progress_minimum_time_display), - res.getBoolean(R.bool.enrollment_progress_priority_over_help), - res.getBoolean(R.bool.enrollment_prioritize_acquire_messages), - res.getInteger(R.integer.enrollment_collect_time)) - : null; } public void setToken(byte[] token) { @@ -195,9 +185,24 @@ public class FingerprintEnrollProgressViewModel extends AndroidViewModel { mErrorMessageLiveData.setValue(null); mCancellationSignal = new CancellationSignal(); - mFingerprintUpdater.enroll(mToken, mCancellationSignal, mUserId, - mMessageDisplayController != null ? mMessageDisplayController : mEnrollmentCallback, - reason); + + final Resources res = getApplication().getResources(); + if (reason == ENROLL_ENROLL + && res.getBoolean(R.bool.enrollment_message_display_controller_flag)) { + final EnrollmentCallback callback = new MessageDisplayController( + getApplication().getMainThreadHandler(), + mEnrollmentCallback, + SystemClock.elapsedRealtimeClock(), + res.getInteger(R.integer.enrollment_help_minimum_time_display), + res.getInteger(R.integer.enrollment_progress_minimum_time_display), + res.getBoolean(R.bool.enrollment_progress_priority_over_help), + res.getBoolean(R.bool.enrollment_prioritize_acquire_messages), + res.getInteger(R.integer.enrollment_collect_time)); + mFingerprintUpdater.enroll(mToken, mCancellationSignal, mUserId, callback, reason); + } else { + mFingerprintUpdater.enroll(mToken, mCancellationSignal, mUserId, mEnrollmentCallback, + reason); + } return true; } diff --git a/src/com/android/settings/dashboard/profileselector/ProfileFragmentBridge.java b/src/com/android/settings/dashboard/profileselector/ProfileFragmentBridge.java index 2bcc02e2b04..1e5145acb6d 100644 --- a/src/com/android/settings/dashboard/profileselector/ProfileFragmentBridge.java +++ b/src/com/android/settings/dashboard/profileselector/ProfileFragmentBridge.java @@ -22,6 +22,7 @@ import com.android.settings.accounts.AccountDashboardFragment; import com.android.settings.applications.manageapplications.ManageApplications; import com.android.settings.deviceinfo.StorageDashboardFragment; import com.android.settings.inputmethod.AvailableVirtualKeyboardFragment; +import com.android.settings.inputmethod.NewKeyboardLayoutEnabledLocalesFragment; import com.android.settings.location.LocationServices; import java.util.Map; @@ -49,5 +50,7 @@ public class ProfileFragmentBridge { ProfileSelectStorageFragment.class.getName()); FRAGMENT_MAP.put(AvailableVirtualKeyboardFragment.class.getName(), ProfileSelectKeyboardFragment.class.getName()); + FRAGMENT_MAP.put(NewKeyboardLayoutEnabledLocalesFragment.class.getName(), + ProfileSelectPhysicalKeyboardFragment.class.getName()); } } diff --git a/src/com/android/settings/dashboard/profileselector/ProfileSelectPhysicalKeyboardFragment.java b/src/com/android/settings/dashboard/profileselector/ProfileSelectPhysicalKeyboardFragment.java new file mode 100644 index 00000000000..3c1546e7d95 --- /dev/null +++ b/src/com/android/settings/dashboard/profileselector/ProfileSelectPhysicalKeyboardFragment.java @@ -0,0 +1,72 @@ +/* + * 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.dashboard.profileselector; + +import android.hardware.input.InputDeviceIdentifier; +import android.os.Bundle; +import android.provider.Settings; + +import androidx.fragment.app.Fragment; + +import com.android.settings.R; +import com.android.settings.inputmethod.NewKeyboardLayoutEnabledLocalesFragment; + +/** + * When current user has work profile, this fragment used following fragments to represent the + * enabled IMEs keyboard layout settings page. + * + *

{@link NewKeyboardLayoutEnabledLocalesFragment} used to show both of personal/work user + * enabled IMEs and their physical keyboard layouts.

+ */ +public final class ProfileSelectPhysicalKeyboardFragment extends ProfileSelectFragment { + + private InputDeviceIdentifier mInputDeviceIdentifier; + + @Override + public void onCreate(Bundle icicle) { + super.onCreate(icicle); + Bundle arguments = getArguments(); + mInputDeviceIdentifier = + arguments.getParcelable(Settings.EXTRA_INPUT_DEVICE_IDENTIFIER); + } + + @Override + protected int getPreferenceScreenResId() { + return R.xml.keyboard_settings_enabled_locales_list; + } + + @Override + public Fragment[] getFragments() { + final Bundle personalOnly = new Bundle(); + personalOnly.putInt(EXTRA_PROFILE, ProfileType.PERSONAL); + final Fragment personalFragment = new NewKeyboardLayoutEnabledLocalesFragment(); + personalOnly.putParcelable( + Settings.EXTRA_INPUT_DEVICE_IDENTIFIER, mInputDeviceIdentifier); + personalFragment.setArguments(personalOnly); + + final Bundle workOnly = new Bundle(); + workOnly.putInt(EXTRA_PROFILE, ProfileType.WORK); + final Fragment workFragment = new NewKeyboardLayoutEnabledLocalesFragment(); + workOnly.putParcelable(Settings.EXTRA_INPUT_DEVICE_IDENTIFIER, mInputDeviceIdentifier); + workFragment.setArguments(workOnly); + + return new Fragment[]{ + personalFragment, + workFragment + }; + } +} diff --git a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownController.java b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownController.java index 0be6c988ec7..2121c60218b 100644 --- a/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownController.java +++ b/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownController.java @@ -23,6 +23,7 @@ import android.graphics.drawable.Drawable; import android.os.Handler; import android.os.Looper; import android.text.TextUtils; +import android.util.ArraySet; import android.util.Log; import android.view.View; import android.widget.AdapterView; @@ -48,9 +49,11 @@ import com.android.settingslib.core.lifecycle.events.OnDestroy; import com.android.settingslib.core.lifecycle.events.OnResume; import com.android.settingslib.widget.FooterPreference; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Set; /** Controller for battery usage breakdown preference group. */ public class BatteryUsageBreakdownController extends BasePreferenceController @@ -61,6 +64,7 @@ public class BatteryUsageBreakdownController extends BasePreferenceController private static final String SPINNER_PREFERENCE_KEY = "battery_usage_spinner"; private static final String APP_LIST_PREFERENCE_KEY = "app_list"; private static final String PACKAGE_NAME_NONE = "none"; + private static final List EMPTY_ENTRY_LIST = new ArrayList<>(); private static int sUiMode = Configuration.UI_MODE_NIGHT_UNDEFINED; @@ -183,7 +187,7 @@ public class BatteryUsageBreakdownController extends BasePreferenceController if (mSpinnerPosition != position) { mSpinnerPosition = position; mHandler.post(() -> { - removeAndCacheAllPreferences(); + removeAndCacheAllUnusedPreferences(); addAllPreferences(); mMetricsFeatureProvider.action( mPrefContext, @@ -238,27 +242,34 @@ public class BatteryUsageBreakdownController extends BasePreferenceController private void showSpinnerAndAppList() { if (mBatteryDiffData == null) { mHandler.post(() -> { - removeAndCacheAllPreferences(); + removeAndCacheAllUnusedPreferences(); }); return; } mSpinnerPreference.setVisible(true); mAppListPreferenceGroup.setVisible(true); mHandler.post(() -> { - removeAndCacheAllPreferences(); + removeAndCacheAllUnusedPreferences(); addAllPreferences(); }); } + private List getBatteryDiffEntries() { + if (mBatteryDiffData == null) { + return EMPTY_ENTRY_LIST; + } + return mSpinnerPosition == 0 + ? mBatteryDiffData.getAppDiffEntryList() + : mBatteryDiffData.getSystemDiffEntryList(); + } + @VisibleForTesting void addAllPreferences() { if (mBatteryDiffData == null) { return; } final long start = System.currentTimeMillis(); - final List entries = mSpinnerPosition == 0 - ? mBatteryDiffData.getAppDiffEntryList() - : mBatteryDiffData.getSystemDiffEntryList(); + final List entries = getBatteryDiffEntries(); int prefIndex = mAppListPreferenceGroup.getPreferenceCount(); for (BatteryDiffEntry entry : entries) { boolean isAdded = false; @@ -272,7 +283,6 @@ public class BatteryUsageBreakdownController extends BasePreferenceController PowerGaugePreference pref = mAppListPreferenceGroup.findPreference(prefKey); if (pref != null) { isAdded = true; - Log.w(TAG, "preference should be removed for:" + entry.getPackageName()); } else { pref = (PowerGaugePreference) mPreferenceCache.get(prefKey); } @@ -301,16 +311,25 @@ public class BatteryUsageBreakdownController extends BasePreferenceController } @VisibleForTesting - void removeAndCacheAllPreferences() { + void removeAndCacheAllUnusedPreferences() { + List entries = getBatteryDiffEntries(); + Set entryKeySet = new ArraySet<>(); + for (BatteryDiffEntry entry : entries) { + entryKeySet.add(entry.getKey()); + } + final int prefsCount = mAppListPreferenceGroup.getPreferenceCount(); - for (int index = 0; index < prefsCount; index++) { + for (int index = prefsCount - 1; index >= 0; index--) { final Preference pref = mAppListPreferenceGroup.getPreference(index); - if (TextUtils.isEmpty(pref.getKey())) { + if (entryKeySet.contains(pref.getKey())) { + // The pref is still used, don't remove. continue; } - mPreferenceCache.put(pref.getKey(), pref); + if (!TextUtils.isEmpty(pref.getKey())) { + mPreferenceCache.put(pref.getKey(), pref); + } + mAppListPreferenceGroup.removePreference(pref); } - mAppListPreferenceGroup.removeAll(); } @VisibleForTesting diff --git a/src/com/android/settings/inputmethod/NewKeyboardLayoutEnabledLocalesFragment.java b/src/com/android/settings/inputmethod/NewKeyboardLayoutEnabledLocalesFragment.java index 3344f4e99d0..054ce610944 100644 --- a/src/com/android/settings/inputmethod/NewKeyboardLayoutEnabledLocalesFragment.java +++ b/src/com/android/settings/inputmethod/NewKeyboardLayoutEnabledLocalesFragment.java @@ -23,6 +23,7 @@ import android.hardware.input.InputManager; import android.hardware.input.KeyboardLayout; import android.os.Bundle; import android.os.UserHandle; +import android.os.UserManager; import android.util.Log; import android.view.InputDevice; import android.view.inputmethod.InputMethodInfo; @@ -34,8 +35,10 @@ import androidx.preference.PreferenceCategory; import androidx.preference.PreferenceScreen; import com.android.settings.R; +import com.android.settings.Utils; import com.android.settings.core.SubSettingLauncher; import com.android.settings.dashboard.DashboardFragment; +import com.android.settings.dashboard.profileselector.ProfileSelectFragment; import com.android.settings.inputmethod.NewKeyboardSettingsUtils.KeyboardInfo; import java.util.ArrayList; @@ -56,6 +59,39 @@ public class NewKeyboardLayoutEnabledLocalesFragment extends DashboardFragment private Context mContext; private ArrayList mKeyboardInfoList = new ArrayList<>(); + @Override + public void onAttach(Context context) { + super.onAttach(context); + + mContext = context; + final int profileType = getArguments().getInt(ProfileSelectFragment.EXTRA_PROFILE); + final int currentUserId = UserHandle.myUserId(); + final int newUserId; + final UserManager userManager = mContext.getSystemService(UserManager.class); + + switch (profileType) { + case ProfileSelectFragment.ProfileType.WORK: { + // If the user is a managed profile user, use currentUserId directly. Or get the + // managed profile userId instead. + newUserId = userManager.isManagedProfile() + ? currentUserId : Utils.getManagedProfileId(userManager, currentUserId); + break; + } + case ProfileSelectFragment.ProfileType.PERSONAL: { + final UserHandle primaryUser = userManager.getPrimaryUser().getUserHandle(); + newUserId = primaryUser.getIdentifier(); + break; + } + default: + newUserId = currentUserId; + } + + mUserId = newUserId; + mIm = mContext.getSystemService(InputManager.class); + mImm = mContext.getSystemService(InputMethodManager.class); + mInputDeviceId = -1; + } + @Override public void onActivityCreated(final Bundle icicle) { super.onActivityCreated(icicle); @@ -74,13 +110,39 @@ public class NewKeyboardLayoutEnabledLocalesFragment extends DashboardFragment } final String title = inputDevice.getName(); getActivity().setTitle(title); + } + + @Override + public void onStart() { + super.onStart(); + mIm.registerInputDeviceListener(this, null); + InputDevice inputDevice = + NewKeyboardSettingsUtils.getInputDevice(mIm, mInputDeviceIdentifier); + if (inputDevice == null) { + getActivity().finish(); + return; + } + mInputDeviceId = inputDevice.getId(); + } + + @Override + public void onResume() { + super.onResume(); updateCheckedState(); } + @Override + public void onStop() { + super.onStop(); + mIm.unregisterInputDeviceListener(this); + mInputDeviceId = -1; + } + private void updateCheckedState() { if (NewKeyboardSettingsUtils.getInputDevice(mIm, mInputDeviceIdentifier) == null) { return; } + PreferenceScreen preferenceScreen = getPreferenceScreen(); preferenceScreen.removeAll(); List infoList = mImm.getEnabledInputMethodListAsUser(mUserId); @@ -95,7 +157,7 @@ public class NewKeyboardLayoutEnabledLocalesFragment extends DashboardFragment for (InputMethodInfo info : infoList) { mKeyboardInfoList.clear(); List subtypes = - mImm.getEnabledInputMethodSubtypeList(info, true); + mImm.getEnabledInputMethodSubtypeListAsUser(info.getId(), true, mUserId); for (InputMethodSubtype subtype : subtypes) { if (subtype.isSuitableForPhysicalKeyboardLayoutMapping()) { mapLanguageWithLayout(info, subtype); @@ -188,42 +250,6 @@ public class NewKeyboardLayoutEnabledLocalesFragment extends DashboardFragment } } - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - mContext = getContext(); - mIm = mContext.getSystemService(InputManager.class); - mImm = mContext.getSystemService(InputMethodManager.class); - mInputDeviceId = -1; - mUserId = UserHandle.myUserId(); - } - - @Override - public void onStart() { - super.onStart(); - mIm.registerInputDeviceListener(this, null); - InputDevice inputDevice = - NewKeyboardSettingsUtils.getInputDevice(mIm, mInputDeviceIdentifier); - if (inputDevice == null) { - getActivity().finish(); - return; - } - mInputDeviceId = inputDevice.getId(); - } - - @Override - public void onStop() { - super.onStop(); - mIm.unregisterInputDeviceListener(this); - mInputDeviceId = -1; - } - - @Override - public void onResume() { - super.onResume(); - updateCheckedState(); - } - @Override protected String getLogTag() { return TAG; diff --git a/src/com/android/settings/network/AirplaneModePreferenceController.java b/src/com/android/settings/network/AirplaneModePreferenceController.java index 720a33409c2..5b4ce1b00b9 100644 --- a/src/com/android/settings/network/AirplaneModePreferenceController.java +++ b/src/com/android/settings/network/AirplaneModePreferenceController.java @@ -79,7 +79,7 @@ public class AirplaneModePreferenceController extends TogglePreferenceController @Override public boolean handlePreferenceTreeClick(Preference preference) { - if (KEY_AIRPLANE_MODE.equals(preference.getKey()) + if (KEY_AIRPLANE_MODE.equals(preference.getKey()) && isAvailable() && mAirplaneModeEnabler.isInEcmMode()) { // In ECM mode launch ECM app dialog if (mFragment != null) { @@ -141,12 +141,14 @@ public class AirplaneModePreferenceController extends TogglePreferenceController @Override public void onDestroy() { - mAirplaneModeEnabler.close(); + if (isAvailable()) { + mAirplaneModeEnabler.close(); + } } public void onActivityResult(int requestCode, int resultCode, Intent data) { - if (requestCode == REQUEST_CODE_EXIT_ECM) { + if (requestCode == REQUEST_CODE_EXIT_ECM && isAvailable()) { final boolean isChoiceYes = (resultCode == Activity.RESULT_OK); // Set Airplane mode based on the return value and checkbox state mAirplaneModeEnabler.setAirplaneModeInECM(isChoiceYes, @@ -156,7 +158,7 @@ public class AirplaneModePreferenceController extends TogglePreferenceController @Override public boolean isChecked() { - return mAirplaneModeEnabler.isAirplaneModeOn(); + return isAvailable() && mAirplaneModeEnabler.isAirplaneModeOn(); } @Override @@ -164,7 +166,9 @@ public class AirplaneModePreferenceController extends TogglePreferenceController if (isChecked() == isChecked) { return false; } - mAirplaneModeEnabler.setAirplaneMode(isChecked); + if (isAvailable()) { + mAirplaneModeEnabler.setAirplaneMode(isChecked); + } return true; } diff --git a/src/com/android/settings/network/telephony/MobileNetworkSettings.java b/src/com/android/settings/network/telephony/MobileNetworkSettings.java index ce8305308c0..83d2117af1b 100644 --- a/src/com/android/settings/network/telephony/MobileNetworkSettings.java +++ b/src/com/android/settings/network/telephony/MobileNetworkSettings.java @@ -350,10 +350,15 @@ public class MobileNetworkSettings extends AbstractMobileNetworkSettings impleme } } + @Override + public void onPause() { + mMobileNetworkRepository.removeRegister(this); + super.onPause(); + } + @Override public void onDestroy() { super.onDestroy(); - mMobileNetworkRepository.removeRegister(this); } @VisibleForTesting diff --git a/src/com/android/settings/nfc/NfcEnabler.java b/src/com/android/settings/nfc/NfcEnabler.java index 88482d59d8b..fe8762b8a90 100644 --- a/src/com/android/settings/nfc/NfcEnabler.java +++ b/src/com/android/settings/nfc/NfcEnabler.java @@ -18,9 +18,6 @@ package com.android.settings.nfc; import android.content.Context; import android.nfc.NfcAdapter; -import android.provider.Settings; - -import androidx.annotation.VisibleForTesting; import com.android.settingslib.widget.MainSwitchPreference; @@ -41,7 +38,7 @@ public class NfcEnabler extends BaseNfcEnabler { switch (newState) { case NfcAdapter.STATE_OFF: mPreference.updateStatus(false); - mPreference.setEnabled(isToggleable()); + mPreference.setEnabled(true); break; case NfcAdapter.STATE_ON: mPreference.updateStatus(true); @@ -57,15 +54,4 @@ public class NfcEnabler extends BaseNfcEnabler { break; } } - - @VisibleForTesting - boolean isToggleable() { - if (NfcPreferenceController.isToggleableInAirplaneMode(mContext) - || !NfcPreferenceController.shouldTurnOffNFCInAirplaneMode(mContext)) { - return true; - } - final int airplaneMode = Settings.Global.getInt( - mContext.getContentResolver(), Settings.Global.AIRPLANE_MODE_ON, 0); - return airplaneMode != 1; - } } diff --git a/src/com/android/settings/nfc/NfcPreferenceController.java b/src/com/android/settings/nfc/NfcPreferenceController.java index 483fead807e..2ba00c6670a 100644 --- a/src/com/android/settings/nfc/NfcPreferenceController.java +++ b/src/com/android/settings/nfc/NfcPreferenceController.java @@ -21,7 +21,6 @@ import android.content.Intent; import android.content.IntentFilter; import android.net.Uri; import android.nfc.NfcAdapter; -import android.provider.Settings; import android.util.Log; import android.widget.Switch; @@ -128,18 +127,6 @@ public class NfcPreferenceController extends TogglePreferenceController } } - public static boolean shouldTurnOffNFCInAirplaneMode(Context context) { - final String airplaneModeRadios = Settings.Global.getString(context.getContentResolver(), - Settings.Global.AIRPLANE_MODE_RADIOS); - return airplaneModeRadios != null && airplaneModeRadios.contains(Settings.Global.RADIO_NFC); - } - - public static boolean isToggleableInAirplaneMode(Context context) { - final String toggleable = Settings.Global.getString(context.getContentResolver(), - Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS); - return toggleable != null && toggleable.contains(Settings.Global.RADIO_NFC); - } - /** * Listener for background changes to NFC. * diff --git a/src/com/android/settings/users/TimeoutToDockUserPreferenceController.java b/src/com/android/settings/users/TimeoutToDockUserPreferenceController.java index 57e8d402825..322a4abbeed 100644 --- a/src/com/android/settings/users/TimeoutToDockUserPreferenceController.java +++ b/src/com/android/settings/users/TimeoutToDockUserPreferenceController.java @@ -20,6 +20,7 @@ import static android.provider.Settings.Secure.TIMEOUT_TO_DOCK_USER; import android.content.Context; import android.os.UserHandle; +import android.os.UserManager; import android.provider.Settings; import androidx.preference.PreferenceScreen; @@ -34,6 +35,8 @@ import java.util.Arrays; * automatically switch to the designated Dock User when the device is docked. */ public class TimeoutToDockUserPreferenceController extends BasePreferenceController { + private final UserManager mUserManager; + private final String[] mEntries; private final String[] mValues; @@ -41,6 +44,8 @@ public class TimeoutToDockUserPreferenceController extends BasePreferenceControl String preferenceKey) { super(context, preferenceKey); + mUserManager = context.getSystemService(UserManager.class); + mEntries = mContext.getResources().getStringArray( com.android.settings.R.array.switch_to_dock_user_when_docked_timeout_entries); mValues = mContext.getResources().getStringArray( @@ -62,9 +67,10 @@ public class TimeoutToDockUserPreferenceController extends BasePreferenceControl return UNSUPPORTED_ON_DEVICE; } - // Multi-user feature disabled by user. + // Multi-user feature disabled by user, or user switching blocked on the user. if (Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.USER_SWITCHER_ENABLED, 0) != 1) { + Settings.Global.USER_SWITCHER_ENABLED, 0) != 1 + || mUserManager.hasUserRestriction(UserManager.DISALLOW_USER_SWITCH)) { return CONDITIONALLY_UNAVAILABLE; } diff --git a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownControllerTest.java b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownControllerTest.java index 37f05bc0d8a..16fec0909e0 100644 --- a/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownControllerTest.java +++ b/tests/robotests/src/com/android/settings/fuelgauge/batteryusage/BatteryUsageBreakdownControllerTest.java @@ -55,6 +55,7 @@ import java.util.TimeZone; @RunWith(RobolectricTestRunner.class) public final class BatteryUsageBreakdownControllerTest { private static final String PREF_KEY = "pref_key"; + private static final String PREF_KEY2 = "pref_key2"; private static final String PREF_SUMMARY = "fake preference summary"; @Mock @@ -175,7 +176,24 @@ public final class BatteryUsageBreakdownControllerTest { } @Test - public void removeAndCacheAllPreferences_buildCacheAndRemoveAllPreference() { + public void removeAndCacheAllUnusedPreferences_removePerf_buildCacheAndRemoveAllPreference() { + doReturn(1).when(mAppListPreferenceGroup).getPreferenceCount(); + doReturn(mPowerGaugePreference).when(mAppListPreferenceGroup).getPreference(0); + doReturn(PREF_KEY2).when(mBatteryHistEntry).getKey(); + doReturn(PREF_KEY).when(mPowerGaugePreference).getKey(); + doReturn(mPowerGaugePreference).when(mAppListPreferenceGroup).findPreference(PREF_KEY); + // Ensures the testing data is correct. + assertThat(mBatteryUsageBreakdownController.mPreferenceCache).isEmpty(); + + mBatteryUsageBreakdownController.removeAndCacheAllUnusedPreferences(); + + assertThat(mBatteryUsageBreakdownController.mPreferenceCache.get(PREF_KEY)) + .isEqualTo(mPowerGaugePreference); + verify(mAppListPreferenceGroup).removePreference(mPowerGaugePreference); + } + + @Test + public void removeAndCacheAllUnusedPreferences_keepPerf_KeepAllPreference() { doReturn(1).when(mAppListPreferenceGroup).getPreferenceCount(); doReturn(mPowerGaugePreference).when(mAppListPreferenceGroup).getPreference(0); doReturn(PREF_KEY).when(mBatteryHistEntry).getKey(); @@ -184,11 +202,10 @@ public final class BatteryUsageBreakdownControllerTest { // Ensures the testing data is correct. assertThat(mBatteryUsageBreakdownController.mPreferenceCache).isEmpty(); - mBatteryUsageBreakdownController.removeAndCacheAllPreferences(); + mBatteryUsageBreakdownController.removeAndCacheAllUnusedPreferences(); - assertThat(mBatteryUsageBreakdownController.mPreferenceCache.get(PREF_KEY)) - .isEqualTo(mPowerGaugePreference); - verify(mAppListPreferenceGroup).removeAll(); + verify(mAppListPreferenceGroup, never()).removePreference(any()); + assertThat(mBatteryUsageBreakdownController.mPreferenceCache).isEmpty(); } @Test diff --git a/tests/robotests/src/com/android/settings/nfc/NfcEnablerTest.java b/tests/robotests/src/com/android/settings/nfc/NfcEnablerTest.java index cc451906214..5299bbdb10c 100644 --- a/tests/robotests/src/com/android/settings/nfc/NfcEnablerTest.java +++ b/tests/robotests/src/com/android/settings/nfc/NfcEnablerTest.java @@ -16,15 +16,12 @@ package com.android.settings.nfc; -import static com.google.common.truth.Truth.assertThat; - import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; -import android.content.ContentResolver; import android.content.Context; import android.nfc.NfcAdapter; -import android.provider.Settings; import com.android.settingslib.widget.MainSwitchPreference; @@ -52,55 +49,14 @@ public class NfcEnablerTest { mNfcEnabler = spy(new NfcEnabler(mContext, mNfcPreference)); } - @Test - public void isToggleable_AirplaneModeOff_shouldReturnTrue() { - final ContentResolver contentResolver = mContext.getContentResolver(); - Settings.Global.putInt(contentResolver, Settings.Global.AIRPLANE_MODE_ON, 0); - Settings.Global.putString(contentResolver, - Settings.Global.AIRPLANE_MODE_RADIOS, Settings.Global.RADIO_NFC); - Settings.Global.putString(contentResolver, - Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS, Settings.Global.RADIO_NFC); - - assertThat(mNfcEnabler.isToggleable()).isTrue(); - } - - @Test - public void isToggleable_AirplaneModeOnNfcNotInAirplaneModeRadio_shouldReturnTrue() { - final ContentResolver contentResolver = mContext.getContentResolver(); - Settings.Global.putInt(contentResolver, Settings.Global.AIRPLANE_MODE_ON, 1); - Settings.Global.putString(contentResolver, Settings.Global.AIRPLANE_MODE_RADIOS, ""); - - assertThat(mNfcEnabler.isToggleable()).isTrue(); - } - - @Test - public void isToggleable_AirplaneModeOnNfcToggleable_shouldReturnTrue() { - final ContentResolver contentResolver = mContext.getContentResolver(); - Settings.Global.putInt(contentResolver, Settings.Global.AIRPLANE_MODE_ON, 1); - Settings.Global.putString(contentResolver, - Settings.Global.AIRPLANE_MODE_RADIOS, Settings.Global.RADIO_NFC); - Settings.Global.putString(contentResolver, - Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS, Settings.Global.RADIO_NFC); - - assertThat(mNfcEnabler.isToggleable()).isTrue(); - } - - @Test - public void isToggleable_AirplaneModeOnNfcNotToggleable_shouldReturnFalse() { - final ContentResolver contentResolver = mContext.getContentResolver(); - Settings.Global.putInt(contentResolver, Settings.Global.AIRPLANE_MODE_ON, 1); - Settings.Global.putString(contentResolver, - Settings.Global.AIRPLANE_MODE_RADIOS, Settings.Global.RADIO_NFC); - Settings.Global.putString(contentResolver, - Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS, ""); - - assertThat(mNfcEnabler.isToggleable()).isFalse(); - } - @Test public void handleNfcStateChanged_stateOff_shouldCheckIfPreferenceEnableState() { mNfcEnabler.handleNfcStateChanged(NfcAdapter.STATE_OFF); + verify(mNfcPreference).updateStatus(false); + verify(mNfcPreference).setEnabled(true); - verify(mNfcEnabler).isToggleable(); + mNfcEnabler.handleNfcStateChanged(NfcAdapter.STATE_ON); + verify(mNfcPreference).updateStatus(true); + verify(mNfcPreference, times(2)).setEnabled(true); } } diff --git a/tests/robotests/src/com/android/settings/nfc/NfcPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/nfc/NfcPreferenceControllerTest.java index 3ca553bc3ba..4db51aab3b6 100644 --- a/tests/robotests/src/com/android/settings/nfc/NfcPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/nfc/NfcPreferenceControllerTest.java @@ -28,7 +28,6 @@ import android.content.Intent; import android.nfc.NfcAdapter; import android.nfc.NfcManager; import android.os.UserManager; -import android.provider.Settings; import androidx.preference.PreferenceScreen; @@ -188,44 +187,6 @@ public class NfcPreferenceControllerTest { assertThat(mNfcController.hasAsyncUpdate()).isTrue(); } - @Test - public void isToggleableInAirplaneMode_containNfc_shouldReturnTrue() { - Settings.Global.putString(mContext.getContentResolver(), - Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS, - Settings.Global.RADIO_NFC); - Settings.Global.putInt(mContext.getContentResolver(), - Settings.Global.AIRPLANE_MODE_ON, 1); - - assertThat(NfcPreferenceController.isToggleableInAirplaneMode(mContext)).isTrue(); - } - - @Test - public void isToggleableInAirplaneMode_withoutNfc_shouldReturnFalse() { - Settings.Global.putString(mContext.getContentResolver(), - Settings.Global.AIRPLANE_MODE_TOGGLEABLE_RADIOS, - "null"); - Settings.Global.putInt(mContext.getContentResolver(), - Settings.Global.AIRPLANE_MODE_ON, 1); - - assertThat(NfcPreferenceController.isToggleableInAirplaneMode(mContext)).isFalse(); - } - - @Test - public void shouldTurnOffNFCInAirplaneMode_airplaneModeRadiosContainsNfc_shouldReturnTrue() { - Settings.Global.putString(mContext.getContentResolver(), - Settings.Global.AIRPLANE_MODE_RADIOS, Settings.Global.RADIO_NFC); - - assertThat(NfcPreferenceController.shouldTurnOffNFCInAirplaneMode(mContext)).isTrue(); - } - - @Test - public void shouldTurnOffNFCInAirplaneMode_airplaneModeRadiosWithoutNfc_shouldReturnFalse() { - Settings.Global.putString(mContext.getContentResolver(), - Settings.Global.AIRPLANE_MODE_RADIOS, ""); - - assertThat(NfcPreferenceController.shouldTurnOffNFCInAirplaneMode(mContext)).isFalse(); - } - @Test public void ncfSliceWorker_nfcBroadcast_noExtra_sliceDoesntUpdate() { final NfcSliceWorker worker = spy( diff --git a/tests/robotests/src/com/android/settings/users/TimeoutToDockUserPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/users/TimeoutToDockUserPreferenceControllerTest.java index 2e7e2d797be..3d8e8930775 100644 --- a/tests/robotests/src/com/android/settings/users/TimeoutToDockUserPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/users/TimeoutToDockUserPreferenceControllerTest.java @@ -27,6 +27,7 @@ import static org.mockito.Mockito.when; import android.content.Context; import android.content.res.Resources; import android.os.UserHandle; +import android.os.UserManager; import android.provider.Settings; import androidx.test.core.app.ApplicationProvider; @@ -41,6 +42,8 @@ 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.annotation.Config; @@ -51,6 +54,9 @@ public class TimeoutToDockUserPreferenceControllerTest { private Resources mResources; private TimeoutToDockUserPreferenceController mController; + @Mock + private UserManager mUserManager; + private static final String FAKE_PREFERENCE_KEY = "timeout_to_dock_user_preference"; private String[] mEntries; @@ -58,9 +64,12 @@ public class TimeoutToDockUserPreferenceControllerTest { @Before public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = spy(ApplicationProvider.getApplicationContext()); mResources = spy(mContext.getResources()); doReturn(mResources).when(mContext).getResources(); + when(mContext.getSystemService(UserManager.class)).thenReturn(mUserManager); mEntries = mResources.getStringArray( R.array.switch_to_dock_user_when_docked_timeout_entries); @@ -78,6 +87,9 @@ public class TimeoutToDockUserPreferenceControllerTest { Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.USER_SWITCHER_ENABLED, 1); + // User switching not blocked. + when(mUserManager.hasUserRestriction(UserManager.DISALLOW_USER_SWITCH)).thenReturn(false); + // Set to user 1; ShadowUserHandle.setUid(1); } @@ -106,6 +118,14 @@ public class TimeoutToDockUserPreferenceControllerTest { BasePreferenceController.CONDITIONALLY_UNAVAILABLE); } + @Test + public void getAvailabilityStatus_userSwitchingBlocked_returnConditionallyUnavailable() { + when(mUserManager.hasUserRestriction(UserManager.DISALLOW_USER_SWITCH)).thenReturn(true); + + assertThat(mController.getAvailabilityStatus()).isEqualTo( + BasePreferenceController.CONDITIONALLY_UNAVAILABLE); + } + @Test public void getAvailabilityStatus_isCurrentlyMainUser_returnDisabledForUser() { when(Utils.canCurrentUserDream(mContext)).thenReturn(true); diff --git a/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollProgressViewModelTest.java b/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollProgressViewModelTest.java index 323618a1d63..6190c5e3f8f 100644 --- a/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollProgressViewModelTest.java +++ b/tests/unit/src/com/android/settings/biometrics2/ui/viewmodel/FingerprintEnrollProgressViewModelTest.java @@ -21,6 +21,8 @@ import static android.hardware.fingerprint.FingerprintManager.ENROLL_FIND_SENSOR import static android.hardware.fingerprint.FingerprintManager.EnrollReason; import static android.hardware.fingerprint.FingerprintManager.EnrollmentCallback; +import static com.android.settings.Utils.SETTINGS_PACKAGE_NAME; + import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.anyInt; @@ -29,18 +31,24 @@ import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.never; import static org.mockito.Mockito.only; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.Application; import android.content.res.Resources; import android.os.CancellationSignal; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import androidx.annotation.NonNull; import androidx.lifecycle.LiveData; +import androidx.test.core.app.ApplicationProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; -import com.android.settings.R; import com.android.settings.biometrics.fingerprint.FingerprintUpdater; +import com.android.settings.biometrics.fingerprint.MessageDisplayController; import com.android.settings.biometrics2.ui.model.EnrollmentProgress; import com.android.settings.biometrics2.ui.model.EnrollmentStatusMessage; import com.android.settings.testutils.InstantTaskExecutorRule; @@ -68,12 +76,18 @@ public class FingerprintEnrollProgressViewModelTest { private FingerprintEnrollProgressViewModel mViewModel; private final TestWrapper mCancellationSignalWrapper = new TestWrapper<>(); private final TestWrapper mCallbackWrapper = new TestWrapper<>(); + private int mEnrollmentMessageDisplayControllerFlagResId; @Before public void setUp() { + mEnrollmentMessageDisplayControllerFlagResId = ApplicationProvider.getApplicationContext() + .getResources().getIdentifier("enrollment_message_display_controller_flag", "bool", + SETTINGS_PACKAGE_NAME); + when(mApplication.getResources()).thenReturn(mResources); - when(mResources.getBoolean(R.bool.enrollment_message_display_controller_flag)) - .thenReturn(false); + + // Not use MessageDisplayController by default + when(mResources.getBoolean(mEnrollmentMessageDisplayControllerFlagResId)).thenReturn(false); mViewModel = new FingerprintEnrollProgressViewModel(mApplication, mFingerprintUpdater, TEST_USER_ID); @@ -88,7 +102,7 @@ public class FingerprintEnrollProgressViewModelTest { } @Test - public void testStartEnrollment() { + public void testStartFindSensor() { @EnrollReason final int enrollReason = ENROLL_FIND_SENSOR; final byte[] token = new byte[] { 1, 2, 3 }; mViewModel.setToken(token); @@ -99,6 +113,54 @@ public class FingerprintEnrollProgressViewModelTest { assertThat(ret).isTrue(); verify(mFingerprintUpdater, only()).enroll(eq(token), any(CancellationSignal.class), eq(TEST_USER_ID), any(EnrollmentCallback.class), eq(enrollReason)); + assertThat(mCallbackWrapper.mValue instanceof MessageDisplayController).isFalse(); + } + + @Test + public void testStartEnrolling() { + @EnrollReason final int enrollReason = ENROLL_ENROLL; + final byte[] token = new byte[] { 1, 2, 3 }; + mViewModel.setToken(token); + + // Start enrollment + final boolean ret = mViewModel.startEnrollment(enrollReason); + + assertThat(ret).isTrue(); + verify(mFingerprintUpdater, only()).enroll(eq(token), any(CancellationSignal.class), + eq(TEST_USER_ID), any(EnrollmentCallback.class), eq(enrollReason)); + assertThat(mCallbackWrapper.mValue instanceof MessageDisplayController).isFalse(); + } + + @Test + public void testStartEnrollingWithMessageDisplayController() { + // Enable MessageDisplayController and mock handler for it + when(mResources.getBoolean(mEnrollmentMessageDisplayControllerFlagResId)).thenReturn(true); + when(mApplication.getMainThreadHandler()).thenReturn(new TestHandler()); + + @EnrollReason final int enrollReason = ENROLL_ENROLL; + final byte[] token = new byte[] { 1, 2, 3 }; + mViewModel.setToken(token); + + // Start enrollment + final boolean ret = mViewModel.startEnrollment(enrollReason); + + assertThat(ret).isTrue(); + verify(mFingerprintUpdater, only()).enroll(eq(token), any(CancellationSignal.class), + eq(TEST_USER_ID), any(MessageDisplayController.class), eq(enrollReason)); + assertThat(mCallbackWrapper.mValue).isNotNull(); + + assertThat(mCallbackWrapper.mValue instanceof MessageDisplayController).isTrue(); + final EnrollmentCallback callback1 = mCallbackWrapper.mValue; + + // Cancel and start again + mViewModel.cancelEnrollment(); + mViewModel.startEnrollment(enrollReason); + + // Shall not use the same MessageDisplayController + verify(mFingerprintUpdater, times(2)).enroll(eq(token), any(CancellationSignal.class), + eq(TEST_USER_ID), any(MessageDisplayController.class), eq(enrollReason)); + assertThat(mCallbackWrapper.mValue).isNotNull(); + assertThat(callback1).isNotEqualTo(mCallbackWrapper.mValue); } @Test @@ -162,6 +224,48 @@ public class FingerprintEnrollProgressViewModelTest { assertThat(progress.getRemaining()).isEqualTo(0); } + @Test + public void testProgressUpdateWithMessageDisplayController() { + // Enable MessageDisplayController and mock handler for it + when(mResources.getBoolean(mEnrollmentMessageDisplayControllerFlagResId)).thenReturn(true); + when(mApplication.getMainThreadHandler()).thenReturn(new TestHandler()); + + mViewModel.setToken(new byte[] { 1, 2, 3 }); + + // Start enrollment + final boolean ret = mViewModel.startEnrollment(ENROLL_ENROLL); + assertThat(ret).isTrue(); + assertThat(mCallbackWrapper.mValue).isNotNull(); + + // Test default value + final LiveData progressLiveData = mViewModel.getProgressLiveData(); + EnrollmentProgress progress = progressLiveData.getValue(); + assertThat(progress).isNotNull(); + assertThat(progress.getSteps()).isEqualTo(-1); + assertThat(progress.getRemaining()).isEqualTo(0); + + // Update first progress + mCallbackWrapper.mValue.onEnrollmentProgress(25); + progress = progressLiveData.getValue(); + assertThat(progress).isNotNull(); + assertThat(progress.getSteps()).isEqualTo(25); + assertThat(progress.getRemaining()).isEqualTo(25); + + // Update second progress + mCallbackWrapper.mValue.onEnrollmentProgress(20); + progress = progressLiveData.getValue(); + assertThat(progress).isNotNull(); + assertThat(progress.getSteps()).isEqualTo(25); + assertThat(progress.getRemaining()).isEqualTo(20); + + // Update latest progress + mCallbackWrapper.mValue.onEnrollmentProgress(0); + progress = progressLiveData.getValue(); + assertThat(progress).isNotNull(); + assertThat(progress.getSteps()).isEqualTo(25); + assertThat(progress.getRemaining()).isEqualTo(0); + } + @Test public void testGetErrorMessageLiveData() { // Start enrollment @@ -262,4 +366,17 @@ public class FingerprintEnrollProgressViewModelTest { private static class TestWrapper { T mValue; } + + private static class TestHandler extends Handler { + + TestHandler() { + super(Looper.getMainLooper()); + } + + @Override + public boolean sendMessageAtTime(@NonNull Message msg, long uptimeMillis) { + msg.getCallback().run(); + return true; + } + } }