diff --git a/Android.bp b/Android.bp index 4d07913b11a..fd97dc36b4b 100644 --- a/Android.bp +++ b/Android.bp @@ -149,14 +149,17 @@ filegroup { srcs: ["proguard.flags"], } -// The sources for Settings need to be exposed to SettingsGoogle, etc. -// so they can run the com.android.settingslib.search.IndexableProcessor -// over all the sources together. +// Deprecated. The sources for Settings need to be exposed to ArcSettings, so they can run the +// com.android.settingslib.search.IndexableProcessor over all the sources together. +// Use "-Acom.android.settingslib.search.processor.package=" instead to generate the search data +// separately for different modules. filegroup { name: "Settings_srcs", srcs: ["src/**/*.java", "src/**/*.kt"], } +// Deprecated. Do not depend on this, only depend on Settings-core, and its manifest is also +// included. filegroup { name: "Settings_manifest", srcs: ["AndroidManifest.xml"], diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 29a0faab9b1..edc6c4dc8f8 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -4898,6 +4898,7 @@ diff --git a/res/values/strings.xml b/res/values/strings.xml index f279af3cdd6..a90a3f7bd03 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -7089,7 +7089,7 @@ background, theme, grid, customize, personalize - icon, accent, color + icon, accent, color, home screen, lock screen, shortcut, clock size default, assistant diff --git a/res/xml/development_settings.xml b/res/xml/development_settings.xml index 68e4e78945b..b26005a65bb 100644 --- a/res/xml/development_settings.xml +++ b/res/xml/development_settings.xml @@ -464,6 +464,11 @@ android:title="@string/pointer_location" android:summary="@string/pointer_location_summary" /> + + getConnectedHearingAidDeviceList() { - if (!isHearingAidSupported()) { + if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled() + || !isHearingAidSupported()) { return new ArrayList<>(); } final List deviceList = new ArrayList<>(); @@ -88,9 +89,6 @@ public class HearingAidHelper { * supported. */ public boolean isHearingAidSupported() { - if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) { - return false; - } final List supportedList = mBluetoothAdapter.getSupportedProfiles(); return supportedList.contains(BluetoothProfile.HEARING_AID) || supportedList.contains(BluetoothProfile.HAP_CLIENT); diff --git a/src/com/android/settings/accessibility/HearingAidUtils.java b/src/com/android/settings/accessibility/HearingAidUtils.java index 42484f9df66..43150937ab6 100644 --- a/src/com/android/settings/accessibility/HearingAidUtils.java +++ b/src/com/android/settings/accessibility/HearingAidUtils.java @@ -23,6 +23,7 @@ import androidx.fragment.app.FragmentManager; import com.android.settings.bluetooth.HearingAidPairingDialogFragment; import com.android.settingslib.bluetooth.CachedBluetoothDevice; +import com.android.settingslib.bluetooth.CsipSetCoordinatorProfile; import com.android.settingslib.bluetooth.HearingAidInfo; /** Provides utility methods related hearing aids. */ @@ -40,6 +41,11 @@ public final class HearingAidUtils { */ public static void launchHearingAidPairingDialog(FragmentManager fragmentManager, @NonNull CachedBluetoothDevice device) { + // No need to show the pair another ear dialog if the device supports and enables CSIP. + // CSIP will pair other devices in the same set automatically. + if (isCsipSupportedAndEnabled(device)) { + return; + } if (device.isConnectedAshaHearingAidDevice() && device.getDeviceMode() == HearingAidInfo.DeviceMode.MODE_BINAURAL && device.getSubDevice() == null) { @@ -56,4 +62,10 @@ public final class HearingAidUtils { HearingAidPairingDialogFragment.newInstance(device.getAddress()).show(fragmentManager, HearingAidPairingDialogFragment.TAG); } + + private static boolean isCsipSupportedAndEnabled(@NonNull CachedBluetoothDevice device) { + return device.getProfiles().stream().anyMatch( + profile -> (profile instanceof CsipSetCoordinatorProfile) + && (profile.isEnabled(device.getDevice()))); + } } diff --git a/src/com/android/settings/accounts/WorkModePreferenceController.java b/src/com/android/settings/accounts/WorkModePreferenceController.java index a261afccaa6..46440f6690f 100644 --- a/src/com/android/settings/accounts/WorkModePreferenceController.java +++ b/src/com/android/settings/accounts/WorkModePreferenceController.java @@ -16,31 +16,42 @@ package com.android.settings.accounts; import android.content.Context; +import android.widget.Switch; import androidx.lifecycle.DefaultLifecycleObserver; import androidx.lifecycle.LifecycleOwner; import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; -import com.android.internal.annotations.VisibleForTesting; import com.android.settings.R; +import com.android.settings.core.BasePreferenceController; import com.android.settings.slices.SliceData; -import com.android.settings.widget.SettingsMainSwitchPreferenceController; import com.android.settingslib.widget.MainSwitchPreference; +import com.android.settingslib.widget.OnMainSwitchChangeListener; import org.jetbrains.annotations.NotNull; -public class WorkModePreferenceController extends SettingsMainSwitchPreferenceController - implements Preference.OnPreferenceChangeListener, DefaultLifecycleObserver, +/** Controller for "Work apps" toggle that allows the user to enable/disable quiet mode. */ +public class WorkModePreferenceController extends BasePreferenceController + implements OnMainSwitchChangeListener, DefaultLifecycleObserver, ManagedProfileQuietModeEnabler.QuietModeChangeListener { private final ManagedProfileQuietModeEnabler mQuietModeEnabler; + private MainSwitchPreference mPreference; public WorkModePreferenceController(Context context, String key) { super(context, key); mQuietModeEnabler = new ManagedProfileQuietModeEnabler(context, this); } + @Override + public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); + mPreference = screen.findPreference(getPreferenceKey()); + mPreference.addOnSwitchChangeListener(this); + } + @Override public int getAvailabilityStatus() { return (mQuietModeEnabler.isAvailable()) ? AVAILABLE : DISABLED_FOR_USER; @@ -57,19 +68,18 @@ public class WorkModePreferenceController extends SettingsMainSwitchPreferenceCo } @Override - public boolean isChecked() { - return !mQuietModeEnabler.isQuietModeEnabled(); + public void onSwitchChanged(Switch switchView, boolean isChecked) { + mQuietModeEnabler.setQuietModeEnabled(!isChecked); } @Override - public boolean setChecked(boolean isChecked) { - mQuietModeEnabler.setQuietModeEnabled(!isChecked); - return true; + public final void updateState(Preference preference) { + mPreference.updateStatus(!mQuietModeEnabler.isQuietModeEnabled()); } @Override public void onQuietModeChanged() { - updateState(mSwitchPreference); + updateState(mPreference); } @Override @@ -82,9 +92,4 @@ public class WorkModePreferenceController extends SettingsMainSwitchPreferenceCo public int getSliceHighlightMenuRes() { return R.string.menu_key_accounts; } - - @VisibleForTesting - void setPreference(MainSwitchPreference preference) { - mSwitchPreference = preference; - } } diff --git a/src/com/android/settings/biometrics/face/FaceSettings.java b/src/com/android/settings/biometrics/face/FaceSettings.java index 979faa22fc2..54775f84a9e 100644 --- a/src/com/android/settings/biometrics/face/FaceSettings.java +++ b/src/com/android/settings/biometrics/face/FaceSettings.java @@ -208,6 +208,10 @@ public class FaceSettings extends DashboardFragment { mRemoveButton = findPreference(FaceSettingsRemoveButtonPreferenceController.KEY); mEnrollButton = findPreference(FaceSettingsEnrollButtonPreferenceController.KEY); + final boolean hasEnrolled = mFaceManager.hasEnrolledTemplates(mUserId); + mEnrollButton.setVisible(!hasEnrolled); + mRemoveButton.setVisible(hasEnrolled); + // There is no better way to do this :/ for (AbstractPreferenceController controller : mControllers) { if (controller instanceof FaceSettingsPreferenceController) { @@ -233,8 +237,6 @@ public class FaceSettings extends DashboardFragment { public void onStart() { super.onStart(); final boolean hasEnrolled = mFaceManager.hasEnrolledTemplates(mUserId); - mEnrollButton.setVisible(!hasEnrolled); - mRemoveButton.setVisible(hasEnrolled); // When the user has face id registered but failed enrolling in device lock state, // lead users directly to the confirm deletion dialog in Face Unlock settings. diff --git a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java index f7be1aa47b1..047b2194be8 100644 --- a/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java +++ b/src/com/android/settings/development/DevelopmentSettingsDashboardFragment.java @@ -675,6 +675,7 @@ public class DevelopmentSettingsDashboardFragment extends RestrictedDashboardFra controllers.add(new NfcVerboseVendorLogPreferenceController(context, fragment)); controllers.add(new ShowTapsPreferenceController(context)); controllers.add(new PointerLocationPreferenceController(context)); + controllers.add(new ShowKeyPressesPreferenceController(context)); controllers.add(new ShowSurfaceUpdatesPreferenceController(context)); controllers.add(new ShowLayoutBoundsPreferenceController(context)); controllers.add(new ShowRefreshRatePreferenceController(context)); diff --git a/src/com/android/settings/development/ShowKeyPressesPreferenceController.java b/src/com/android/settings/development/ShowKeyPressesPreferenceController.java new file mode 100644 index 00000000000..247f59a5385 --- /dev/null +++ b/src/com/android/settings/development/ShowKeyPressesPreferenceController.java @@ -0,0 +1,72 @@ +/* + * Copyright 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.development; + +import android.content.Context; +import android.provider.Settings; + +import androidx.annotation.VisibleForTesting; +import androidx.preference.Preference; +import androidx.preference.SwitchPreference; + +import com.android.settings.core.PreferenceControllerMixin; +import com.android.settingslib.development.DeveloperOptionsPreferenceController; + +/** PreferenceController that controls the "Show key presses" developer option. */ +public class ShowKeyPressesPreferenceController extends + DeveloperOptionsPreferenceController implements + Preference.OnPreferenceChangeListener, PreferenceControllerMixin { + + private static final String SHOW_KEY_PRESSES_KEY = "show_key_presses"; + + @VisibleForTesting + static final int SETTING_VALUE_ON = 1; + @VisibleForTesting + static final int SETTING_VALUE_OFF = 0; + + public ShowKeyPressesPreferenceController(Context context) { + super(context); + } + + @Override + public String getPreferenceKey() { + return SHOW_KEY_PRESSES_KEY; + } + + @Override + public boolean onPreferenceChange(Preference preference, Object newValue) { + final boolean isEnabled = (Boolean) newValue; + Settings.System.putInt(mContext.getContentResolver(), + Settings.System.SHOW_KEY_PRESSES, isEnabled ? SETTING_VALUE_ON : SETTING_VALUE_OFF); + return true; + } + + @Override + public void updateState(Preference preference) { + int showKeyPresses = Settings.System.getInt(mContext.getContentResolver(), + Settings.System.SHOW_KEY_PRESSES, SETTING_VALUE_OFF); + ((SwitchPreference) mPreference).setChecked(showKeyPresses != SETTING_VALUE_OFF); + } + + @Override + protected void onDeveloperOptionsSwitchDisabled() { + super.onDeveloperOptionsSwitchDisabled(); + Settings.System.putInt(mContext.getContentResolver(), Settings.System.SHOW_KEY_PRESSES, + SETTING_VALUE_OFF); + ((SwitchPreference) mPreference).setChecked(false); + } +} diff --git a/src/com/android/settings/network/tether/TetherSettings.java b/src/com/android/settings/network/tether/TetherSettings.java index 9fa8730cf10..6f6ba8efa71 100644 --- a/src/com/android/settings/network/tether/TetherSettings.java +++ b/src/com/android/settings/network/tether/TetherSettings.java @@ -145,19 +145,13 @@ public class TetherSettings extends RestrictedSettingsFragment super(UserManager.DISALLOW_CONFIG_TETHERING); } - @Override - public void onAttach(Context context) { - super.onAttach(context); - TetheringManagerModel model = new ViewModelProvider(this).get(TetheringManagerModel.class); - mWifiTetherPreferenceController = - new WifiTetherPreferenceController(context, getSettingsLifecycle(), model); - mTm = model.getTetheringManager(); - model.getTetheredInterfaces().observe(this, this::onTetheredInterfacesChanged); - } - @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); + setIfOnlyAvailableForAdmins(true); + if (isUiRestricted()) { + return; + } addPreferencesFromResource(R.xml.tether_prefs); mContext = getContext(); @@ -165,13 +159,8 @@ public class TetherSettings extends RestrictedSettingsFragment mDataSaverEnabled = mDataSaverBackend.isDataSaverEnabled(); mDataSaverFooter = findPreference(KEY_DATA_SAVER_FOOTER); - setIfOnlyAvailableForAdmins(true); - if (isUiRestricted()) { - getPreferenceScreen().removeAll(); - return; - } - setupTetherPreference(); + setupViewModel(); final Activity activity = getActivity(); BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); @@ -223,8 +212,22 @@ public class TetherSettings extends RestrictedSettingsFragment onDataSaverChanged(mDataSaverBackend.isDataSaverEnabled()); } + @VisibleForTesting + void setupViewModel() { + TetheringManagerModel model = new ViewModelProvider(this).get(TetheringManagerModel.class); + mWifiTetherPreferenceController = + new WifiTetherPreferenceController(getContext(), getSettingsLifecycle(), model); + mTm = model.getTetheringManager(); + model.getTetheredInterfaces().observe(this, this::onTetheredInterfacesChanged); + } + @Override public void onDestroy() { + if (isUiRestricted()) { + super.onDestroy(); + return; + } + mDataSaverBackend.remListener(this); BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); diff --git a/tests/robotests/src/com/android/settings/accessibility/HearingAidHelperTest.java b/tests/robotests/src/com/android/settings/accessibility/HearingAidHelperTest.java index 194b766dd75..3889cf04e02 100644 --- a/tests/robotests/src/com/android/settings/accessibility/HearingAidHelperTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/HearingAidHelperTest.java @@ -95,8 +95,7 @@ public class HearingAidHelperTest { } @Test - public void isHearingAidSupported_supported_returnTrue() { - mBluetoothAdapter.enable(); + public void isHearingAidSupported_ashaSupported_returnTrue() { mShadowBluetoothAdapter.clearSupportedProfiles(); mShadowBluetoothAdapter.addSupportedProfiles(BluetoothProfile.HEARING_AID); @@ -104,15 +103,20 @@ public class HearingAidHelperTest { } @Test - public void isHearingAidSupported_bluetoothOff_returnFalse() { + public void isHearingAidSupported_hapSupported_returnTrue() { + mShadowBluetoothAdapter.clearSupportedProfiles(); + mShadowBluetoothAdapter.addSupportedProfiles(BluetoothProfile.HAP_CLIENT); + + assertThat(mHelper.isHearingAidSupported()).isTrue(); + } + + @Test + public void isHearingAidSupported_unsupported_returnFalse() { mShadowBluetoothAdapter.clearSupportedProfiles(); - mShadowBluetoothAdapter.addSupportedProfiles(BluetoothProfile.HEARING_AID); - mBluetoothAdapter.disable(); assertThat(mHelper.isHearingAidSupported()).isFalse(); } - @Test public void isAllHearingAidRelatedProfilesReady_allReady_returnTrue() { when(mHearingAidProfile.isProfileReady()).thenReturn(true); diff --git a/tests/robotests/src/com/android/settings/accessibility/HearingAidUtilsTest.java b/tests/robotests/src/com/android/settings/accessibility/HearingAidUtilsTest.java index 09db6e92d1c..56ab08237c7 100644 --- a/tests/robotests/src/com/android/settings/accessibility/HearingAidUtilsTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/HearingAidUtilsTest.java @@ -37,8 +37,10 @@ import com.android.settings.testutils.shadow.ShadowBluetoothUtils; import com.android.settings.utils.ActivityControllerWrapper; import com.android.settingslib.bluetooth.CachedBluetoothDevice; import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager; +import com.android.settingslib.bluetooth.CsipSetCoordinatorProfile; import com.android.settingslib.bluetooth.HearingAidInfo; import com.android.settingslib.bluetooth.LocalBluetoothManager; +import com.android.settingslib.bluetooth.LocalBluetoothProfile; import org.junit.Before; import org.junit.Rule; @@ -52,6 +54,9 @@ import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; import org.robolectric.shadow.api.Shadow; +import java.util.ArrayList; +import java.util.List; + /** Tests for {@link HearingAidUtils}. */ @RunWith(RobolectricTestRunner.class) @Config(shadows = {ShadowAlertDialogCompat.class, ShadowBluetoothAdapter.class, @@ -72,6 +77,8 @@ public class HearingAidUtilsTest { private LocalBluetoothManager mLocalBluetoothManager; @Mock private CachedBluetoothDeviceManager mCachedDeviceManager; + @Mock + private CsipSetCoordinatorProfile mCsipSetCoordinatorProfile; private BluetoothDevice mBluetoothDevice; private BluetoothAdapter mBluetoothAdapter; private ShadowBluetoothAdapter mShadowBluetoothAdapter; @@ -136,6 +143,38 @@ public class HearingAidUtilsTest { assertThat(dialog).isNull(); } + @Test + public void launchHearingAidPairingDialog_deviceSupportsCsip_csipEnabled_noDialog() { + when(mCachedBluetoothDevice.isConnectedAshaHearingAidDevice()).thenReturn(true); + when(mCachedBluetoothDevice.getDeviceMode()).thenReturn( + HearingAidInfo.DeviceMode.MODE_BINAURAL); + when(mCachedBluetoothDevice.getDeviceSide()).thenReturn( + HearingAidInfo.DeviceSide.SIDE_LEFT); + makeDeviceSupportCsip(); + makeDeviceEnableCsip(true); + + HearingAidUtils.launchHearingAidPairingDialog(mFragmentManager, mCachedBluetoothDevice); + + final AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog(); + assertThat(dialog).isNull(); + } + + @Test + public void launchHearingAidPairingDialog_deviceSupportsCsip_csipDisabled_dialogShown() { + when(mCachedBluetoothDevice.isConnectedAshaHearingAidDevice()).thenReturn(true); + when(mCachedBluetoothDevice.getDeviceMode()).thenReturn( + HearingAidInfo.DeviceMode.MODE_BINAURAL); + when(mCachedBluetoothDevice.getDeviceSide()).thenReturn( + HearingAidInfo.DeviceSide.SIDE_LEFT); + makeDeviceSupportCsip(); + makeDeviceEnableCsip(false); + + HearingAidUtils.launchHearingAidPairingDialog(mFragmentManager, mCachedBluetoothDevice); + + final AlertDialog dialog = ShadowAlertDialogCompat.getLatestAlertDialog(); + assertThat(dialog.isShowing()).isTrue(); + } + @Test public void launchHearingAidPairingDialog_dialogShown() { when(mCachedBluetoothDevice.isConnectedAshaHearingAidDevice()).thenReturn(true); @@ -150,6 +189,17 @@ public class HearingAidUtilsTest { assertThat(dialog.isShowing()).isTrue(); } + private void makeDeviceSupportCsip() { + List uuids = new ArrayList<>(); + uuids.add(mCsipSetCoordinatorProfile); + when(mCachedBluetoothDevice.getProfiles()).thenReturn(uuids); + } + + private void makeDeviceEnableCsip(boolean enabled) { + when(mCsipSetCoordinatorProfile.isEnabled(mCachedBluetoothDevice.getDevice())) + .thenReturn(enabled); + } + private void setupEnvironment() { ShadowBluetoothUtils.sLocalBluetoothManager = mLocalBluetoothManager; mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); diff --git a/tests/robotests/src/com/android/settings/accounts/WorkModePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accounts/WorkModePreferenceControllerTest.java index e862d108c7c..d6be73d5481 100644 --- a/tests/robotests/src/com/android/settings/accounts/WorkModePreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/accounts/WorkModePreferenceControllerTest.java @@ -19,6 +19,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -27,7 +28,9 @@ import android.content.Context; import android.content.pm.UserInfo; import android.os.UserHandle; import android.os.UserManager; +import android.widget.Switch; +import androidx.preference.PreferenceScreen; import androidx.test.core.app.ApplicationProvider; import com.android.settingslib.widget.MainSwitchPreference; @@ -57,6 +60,10 @@ public class WorkModePreferenceControllerTest { private UserHandle mManagedUser; @Mock private UserInfo mUserInfo; + @Mock + private PreferenceScreen mScreen; + @Mock + Switch mSwitch; @Before public void setUp() { @@ -69,7 +76,9 @@ public class WorkModePreferenceControllerTest { when(mUserManager.getProcessUserId()).thenReturn(0); when(mUserManager.getUserProfiles()).thenReturn(Collections.singletonList(mManagedUser)); when(mManagedUser.getIdentifier()).thenReturn(MANAGED_USER_ID); + when(mScreen.findPreference(anyString())).thenReturn(mPreference); mController = new WorkModePreferenceController(mContext, PREF_KEY); + mController.displayPreference(mScreen); } @Test @@ -106,13 +115,11 @@ public class WorkModePreferenceControllerTest { @Test public void onPreferenceChange_shouldRequestQuietModeEnabled() { - mController.setPreference(mPreference); - - mController.onPreferenceChange(mPreference, true); + mController.onSwitchChanged(mSwitch, true); verify(mUserManager).requestQuietModeEnabled(false, mManagedUser); - mController.onPreferenceChange(mPreference, false); + mController.onSwitchChanged(mSwitch, false); verify(mUserManager).requestQuietModeEnabled(true, mManagedUser); } diff --git a/tests/robotests/src/com/android/settings/development/ShowKeyPressesPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/ShowKeyPressesPreferenceControllerTest.java new file mode 100644 index 00000000000..b7fb902a40a --- /dev/null +++ b/tests/robotests/src/com/android/settings/development/ShowKeyPressesPreferenceControllerTest.java @@ -0,0 +1,110 @@ +/* + * Copyright 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.development; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.provider.Settings; + +import androidx.preference.PreferenceScreen; +import androidx.preference.SwitchPreference; + +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; + +@RunWith(RobolectricTestRunner.class) +public class ShowKeyPressesPreferenceControllerTest { + + @Mock + private PreferenceScreen mScreen; + @Mock + private SwitchPreference mPreference; + + private Context mContext; + + private ShowKeyPressesPreferenceController mController; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = RuntimeEnvironment.application; + mController = new ShowKeyPressesPreferenceController(mContext); + when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference); + mController.displayPreference(mScreen); + } + + @Test + public void updateState_showKeyPressesEnabled_shouldCheckedPreference() { + Settings.System.putInt(mContext.getContentResolver(), + Settings.System.SHOW_KEY_PRESSES, ShowTapsPreferenceController.SETTING_VALUE_ON); + + mController.updateState(mPreference); + + verify(mPreference).setChecked(true); + } + + @Test + public void updateState_showKeyPressesDisabled_shouldUncheckedPreference() { + Settings.System.putInt(mContext.getContentResolver(), + Settings.System.SHOW_KEY_PRESSES, ShowTapsPreferenceController.SETTING_VALUE_OFF); + + mController.updateState(mPreference); + + verify(mPreference).setChecked(false); + } + + @Test + public void onPreferenceChange_preferenceChecked_shouldEnableShowKeyPresses() { + mController.onPreferenceChange(mPreference, true /* new value */); + + final int showKeyPresses = Settings.System.getInt(mContext.getContentResolver(), + Settings.System.SHOW_KEY_PRESSES, -1 /* default */); + + assertThat(showKeyPresses).isEqualTo(ShowTapsPreferenceController.SETTING_VALUE_ON); + } + + @Test + public void onPreferenceChange_preferenceUnchecked_shouldDisableShowKeyPresses() { + mController.onPreferenceChange(mPreference, false /* new value */); + + final int showTapsMode = Settings.System.getInt(mContext.getContentResolver(), + Settings.System.SHOW_KEY_PRESSES, -1 /* default */); + + assertThat(showTapsMode).isEqualTo(ShowTapsPreferenceController.SETTING_VALUE_OFF); + } + + @Test + public void onDeveloperOptionsSwitchDisabled_preferenceShouldBeEnabled() { + mController.onDeveloperOptionsSwitchDisabled(); + + final int showTapsMode = Settings.System.getInt(mContext.getContentResolver(), + Settings.System.SHOW_KEY_PRESSES, -1 /* default */); + + assertThat(showTapsMode).isEqualTo(ShowTapsPreferenceController.SETTING_VALUE_OFF); + verify(mPreference).setEnabled(false); + verify(mPreference).setChecked(false); + } +} diff --git a/tests/robotests/src/com/android/settings/network/tether/TetherSettingsTest.java b/tests/robotests/src/com/android/settings/network/tether/TetherSettingsTest.java index 23d9b825ad6..bf03e82657a 100644 --- a/tests/robotests/src/com/android/settings/network/tether/TetherSettingsTest.java +++ b/tests/robotests/src/com/android/settings/network/tether/TetherSettingsTest.java @@ -45,6 +45,7 @@ import android.hardware.usb.UsbManager; import android.net.ConnectivityManager; import android.net.TetheringManager; import android.net.wifi.WifiManager; +import android.os.Bundle; import android.os.UserHandle; import android.os.UserManager; import android.util.FeatureFlagUtils; @@ -54,6 +55,7 @@ import androidx.preference.Preference; import androidx.preference.SwitchPreference; import com.android.settings.R; +import com.android.settings.RestrictedSettingsFragment; import com.android.settings.core.FeatureFlags; import com.android.settings.wifi.tether.WifiTetherPreferenceController; import com.android.settingslib.RestrictedSwitchPreference; @@ -66,6 +68,9 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; +import org.robolectric.annotation.Config; +import org.robolectric.annotation.Implementation; +import org.robolectric.annotation.Implements; import java.util.ArrayList; import java.util.List; @@ -92,7 +97,7 @@ public class TetherSettingsTest { @Mock private Preference mDataSaverFooter; - TetherSettings mTetherSettings; + private MockTetherSettings mTetherSettings; @Before public void setUp() throws Exception { @@ -114,7 +119,7 @@ public class TetherSettingsTest { when(mTetheringManager.getTetherableUsbRegexs()).thenReturn(new String[0]); when(mTetheringManager.getTetherableBluetoothRegexs()).thenReturn(new String[0]); - mTetherSettings = spy(new TetherSettings()); + mTetherSettings = spy(new MockTetherSettings()); mTetherSettings.mContext = mContext; mTetherSettings.mWifiTetherPreferenceController = mWifiTetherPreferenceController; mTetherSettings.mUsbTether = mUsbTether; @@ -123,6 +128,16 @@ public class TetherSettingsTest { mTetherSettings.mDataSaverFooter = mDataSaverFooter; } + @Test + @Config(shadows = ShadowRestrictedSettingsFragment.class) + public void onCreate_isUiRestricted_doNotSetupViewModel() { + when(mTetherSettings.isUiRestricted()).thenReturn(true); + + mTetherSettings.onCreate(null); + + verify(mTetherSettings, never()).setupViewModel(); + } + @Test public void testTetherNonIndexableKeys_tetherAvailable_keysNotReturned() { FeatureFlagUtils.setEnabled(mContext, FeatureFlags.TETHER_ALL_IN_ONE, false); @@ -431,4 +446,19 @@ public class TetherSettingsTest { mTetherSettings.registerReceiver(); updateOnlyBluetoothState(mTetherSettings); } + + private static class MockTetherSettings extends TetherSettings { + @Override + public boolean isUiRestricted() { + return false; + } + } + + @Implements(RestrictedSettingsFragment.class) + public static final class ShadowRestrictedSettingsFragment { + @Implementation + public void onCreate(Bundle icicle) { + // do nothing + } + } }