diff --git a/aconfig/settings_connecteddevice_flag_declarations.aconfig b/aconfig/settings_connecteddevice_flag_declarations.aconfig index 07aaecc93b0..1a3afed0a1e 100644 --- a/aconfig/settings_connecteddevice_flag_declarations.aconfig +++ b/aconfig/settings_connecteddevice_flag_declarations.aconfig @@ -20,3 +20,10 @@ flag { description: "Gates whether to enable LE audio private broadcast sharing via QR code" bug: "308368124" } + +flag { + name: "enable_auth_challenge_for_usb_preferences" + namespace: "safety_center" + description: "Gates whether to require an auth challenge for changing USB preferences" + bug: "317367746" +} diff --git a/src/com/android/settings/connecteddevice/usb/UsbDetailsController.java b/src/com/android/settings/connecteddevice/usb/UsbDetailsController.java index 1219211a3ab..488de199d98 100644 --- a/src/com/android/settings/connecteddevice/usb/UsbDetailsController.java +++ b/src/com/android/settings/connecteddevice/usb/UsbDetailsController.java @@ -23,6 +23,8 @@ import androidx.annotation.UiThread; import androidx.annotation.VisibleForTesting; import com.android.settings.core.PreferenceControllerMixin; +import com.android.settings.flags.Flags; +import com.android.settings.wifi.dpp.WifiDppUtils; import com.android.settingslib.core.AbstractPreferenceController; /** @@ -61,4 +63,16 @@ public abstract class UsbDetailsController extends AbstractPreferenceController */ @UiThread protected abstract void refresh(boolean connected, long functions, int powerRole, int dataRole); + + /** Protects given action with an auth challenge. */ + protected final void requireAuthAndExecute(Runnable action) { + if (Flags.enableAuthChallengeForUsbPreferences() && !mFragment.isUserAuthenticated()) { + WifiDppUtils.showLockScreen(mContext, () -> { + mFragment.setUserAuthenticated(true); + action.run(); + }); + } else { + action.run(); + } + } } diff --git a/src/com/android/settings/connecteddevice/usb/UsbDetailsDataRoleController.java b/src/com/android/settings/connecteddevice/usb/UsbDetailsDataRoleController.java index 6d455a69ebd..8782c796140 100644 --- a/src/com/android/settings/connecteddevice/usb/UsbDetailsDataRoleController.java +++ b/src/com/android/settings/connecteddevice/usb/UsbDetailsDataRoleController.java @@ -98,17 +98,19 @@ public class UsbDetailsDataRoleController extends UsbDetailsController @Override public void onRadioButtonClicked(SelectorWithWidgetPreference preference) { - int role = UsbBackend.dataRoleFromString(preference.getKey()); - if (role != mUsbBackend.getDataRole() && mNextRolePref == null - && !Utils.isMonkeyRunning()) { - mUsbBackend.setDataRole(role); - mNextRolePref = preference; - preference.setSummary(R.string.usb_switching); + requireAuthAndExecute(() -> { + int role = UsbBackend.dataRoleFromString(preference.getKey()); + if (role != mUsbBackend.getDataRole() && mNextRolePref == null + && !Utils.isMonkeyRunning()) { + mUsbBackend.setDataRole(role); + mNextRolePref = preference; + preference.setSummary(R.string.usb_switching); - mHandler.postDelayed(mFailureCallback, - mUsbBackend.areAllRolesSupported() ? UsbBackend.PD_ROLE_SWAP_TIMEOUT_MS - : UsbBackend.NONPD_ROLE_SWAP_TIMEOUT_MS); - } + mHandler.postDelayed(mFailureCallback, + mUsbBackend.areAllRolesSupported() ? UsbBackend.PD_ROLE_SWAP_TIMEOUT_MS + : UsbBackend.NONPD_ROLE_SWAP_TIMEOUT_MS); + } + }); } @Override diff --git a/src/com/android/settings/connecteddevice/usb/UsbDetailsFragment.java b/src/com/android/settings/connecteddevice/usb/UsbDetailsFragment.java index 0c94d192f61..f8cabbc08fb 100644 --- a/src/com/android/settings/connecteddevice/usb/UsbDetailsFragment.java +++ b/src/com/android/settings/connecteddevice/usb/UsbDetailsFragment.java @@ -45,6 +45,7 @@ public class UsbDetailsFragment extends DashboardFragment { private List mControllers; private UsbBackend mUsbBackend; + private boolean mUserAuthenticated = false; @VisibleForTesting UsbConnectionBroadcastReceiver mUsbReceiver; @@ -56,6 +57,20 @@ public class UsbDetailsFragment extends DashboardFragment { } }; + boolean isUserAuthenticated() { + return mUserAuthenticated; + } + + void setUserAuthenticated(boolean userAuthenticated) { + mUserAuthenticated = userAuthenticated; + } + + @Override + public void onStart() { + super.onStart(); + mUserAuthenticated = false; + } + @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); diff --git a/src/com/android/settings/connecteddevice/usb/UsbDetailsFunctionsController.java b/src/com/android/settings/connecteddevice/usb/UsbDetailsFunctionsController.java index 88e20b60dd0..04fab7d7d57 100644 --- a/src/com/android/settings/connecteddevice/usb/UsbDetailsFunctionsController.java +++ b/src/com/android/settings/connecteddevice/usb/UsbDetailsFunctionsController.java @@ -130,37 +130,39 @@ public class UsbDetailsFunctionsController extends UsbDetailsController @Override public void onRadioButtonClicked(SelectorWithWidgetPreference preference) { - final long function = UsbBackend.usbFunctionsFromString(preference.getKey()); - final long previousFunction = mUsbBackend.getCurrentFunctions(); - if (DEBUG) { - Log.d(TAG, "onRadioButtonClicked() function : " + function + ", toString() : " - + UsbManager.usbFunctionsToString(function) + ", previousFunction : " - + previousFunction + ", toString() : " - + UsbManager.usbFunctionsToString(previousFunction)); - } - if (function != previousFunction && !Utils.isMonkeyRunning() - && !isClickEventIgnored(function, previousFunction)) { - mPreviousFunction = previousFunction; - - //Update the UI in advance to make it looks smooth - final SelectorWithWidgetPreference prevPref = - (SelectorWithWidgetPreference) mProfilesContainer.findPreference( - UsbBackend.usbFunctionsToString(mPreviousFunction)); - if (prevPref != null) { - prevPref.setChecked(false); - preference.setChecked(true); + requireAuthAndExecute(() -> { + final long function = UsbBackend.usbFunctionsFromString(preference.getKey()); + final long previousFunction = mUsbBackend.getCurrentFunctions(); + if (DEBUG) { + Log.d(TAG, "onRadioButtonClicked() function : " + function + ", toString() : " + + UsbManager.usbFunctionsToString(function) + ", previousFunction : " + + previousFunction + ", toString() : " + + UsbManager.usbFunctionsToString(previousFunction)); } + if (function != previousFunction && !Utils.isMonkeyRunning() + && !isClickEventIgnored(function, previousFunction)) { + mPreviousFunction = previousFunction; - if (function == UsbManager.FUNCTION_RNDIS || function == UsbManager.FUNCTION_NCM) { - // We need to have entitlement check for usb tethering, so use API in - // TetheringManager. - mTetheringManager.startTethering( - TetheringManager.TETHERING_USB, new HandlerExecutor(mHandler), - mOnStartTetheringCallback); - } else { - mUsbBackend.setCurrentFunctions(function); + //Update the UI in advance to make it looks smooth + final SelectorWithWidgetPreference prevPref = + (SelectorWithWidgetPreference) mProfilesContainer.findPreference( + UsbBackend.usbFunctionsToString(mPreviousFunction)); + if (prevPref != null) { + prevPref.setChecked(false); + preference.setChecked(true); + } + + if (function == UsbManager.FUNCTION_RNDIS || function == UsbManager.FUNCTION_NCM) { + // We need to have entitlement check for usb tethering, so use API in + // TetheringManager. + mTetheringManager.startTethering( + TetheringManager.TETHERING_USB, new HandlerExecutor(mHandler), + mOnStartTetheringCallback); + } else { + mUsbBackend.setCurrentFunctions(function); + } } - } + }); } private boolean isClickEventIgnored(long function, long previousFunction) { diff --git a/src/com/android/settings/connecteddevice/usb/UsbDetailsTranscodeMtpController.java b/src/com/android/settings/connecteddevice/usb/UsbDetailsTranscodeMtpController.java index 192ae742f23..a0231712e34 100644 --- a/src/com/android/settings/connecteddevice/usb/UsbDetailsTranscodeMtpController.java +++ b/src/com/android/settings/connecteddevice/usb/UsbDetailsTranscodeMtpController.java @@ -78,13 +78,15 @@ public class UsbDetailsTranscodeMtpController extends UsbDetailsController @Override public boolean onPreferenceClick(Preference preference) { - SystemProperties.set(TRANSCODE_MTP_SYS_PROP_KEY, - Boolean.toString(mSwitchPreference.isChecked())); + requireAuthAndExecute(() -> { + SystemProperties.set(TRANSCODE_MTP_SYS_PROP_KEY, + Boolean.toString(mSwitchPreference.isChecked())); - final long previousFunctions = mUsbBackend.getCurrentFunctions(); - // Toggle the MTP connection to reload file sizes for files shared via MTP clients - mUsbBackend.setCurrentFunctions(previousFunctions & ~UsbManager.FUNCTION_MTP); - mUsbBackend.setCurrentFunctions(previousFunctions); + final long previousFunctions = mUsbBackend.getCurrentFunctions(); + // Toggle the MTP connection to reload file sizes for files shared via MTP clients + mUsbBackend.setCurrentFunctions(previousFunctions & ~UsbManager.FUNCTION_MTP); + mUsbBackend.setCurrentFunctions(previousFunctions); + }); return true; } diff --git a/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbDetailsControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbDetailsControllerTest.java new file mode 100644 index 00000000000..b8d31ed9acf --- /dev/null +++ b/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbDetailsControllerTest.java @@ -0,0 +1,113 @@ +/* + * 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.connecteddevice.usb; + +import static androidx.test.core.app.ApplicationProvider.getApplicationContext; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.verify; + +import android.app.KeyguardManager; +import android.content.Context; +import android.hardware.usb.UsbPortStatus; +import android.platform.test.annotations.RequiresFlagsEnabled; +import android.platform.test.flag.junit.CheckFlagsRule; +import android.platform.test.flag.junit.DeviceFlagsValueProvider; + +import com.android.settings.flags.Flags; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.robolectric.RobolectricTestRunner; +import org.robolectric.Shadows; +import org.robolectric.annotation.Config; +import org.robolectric.shadows.ShadowKeyguardManager; + +@RunWith(RobolectricTestRunner.class) +@Config(shadows = { + ShadowKeyguardManager.class +}) +public class UsbDetailsControllerTest { + + @Rule + public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); + + @Mock + private UsbBackend mUsbBackend; + + private Context mContext; + private UsbDetailsController mUsbDetailsController; + private UsbDetailsFragment mUsbDetailsFragment; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mContext = getApplicationContext(); + mUsbDetailsFragment = new UsbDetailsFragment(); + mUsbDetailsController = new UsbDetailsController( + mContext, mUsbDetailsFragment, mUsbBackend) { + @Override + protected void refresh(boolean connected, long functions, int powerRole, int dataRole) { + } + + @Override + public String getPreferenceKey() { + return null; + } + }; + } + + @Test + public void isAvailable_returnsTrue() { + assertThat(mUsbDetailsController.isAvailable()).isTrue(); + } + + @Test + @RequiresFlagsEnabled(Flags.FLAG_ENABLE_AUTH_CHALLENGE_FOR_USB_PREFERENCES) + public void requireAuthAndExecute_whenAlreadyAuthenticated_executes() { + mUsbDetailsFragment.setUserAuthenticated(true); + Runnable action = () -> mUsbBackend.setDataRole(UsbPortStatus.DATA_ROLE_HOST); + + mUsbDetailsController.requireAuthAndExecute(action); + + verify(mUsbBackend).setDataRole(anyInt()); + } + + @Test + @RequiresFlagsEnabled(Flags.FLAG_ENABLE_AUTH_CHALLENGE_FOR_USB_PREFERENCES) + public void requireAuthAndExecute_authenticatesAndExecutes() { + mUsbDetailsFragment.setUserAuthenticated(false); + setAuthPassesAutomatically(); + Runnable action = () -> mUsbBackend.setDataRole(UsbPortStatus.DATA_ROLE_HOST); + + mUsbDetailsController.requireAuthAndExecute(action); + + assertThat(mUsbDetailsFragment.isUserAuthenticated()).isTrue(); + verify(mUsbBackend).setDataRole(anyInt()); + } + + private void setAuthPassesAutomatically() { + Shadows.shadowOf(mContext.getSystemService(KeyguardManager.class)) + .setIsKeyguardSecure(false); + } +} diff --git a/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbDetailsDataRoleControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbDetailsDataRoleControllerTest.java index 9e24387c3d9..3324843f582 100644 --- a/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbDetailsDataRoleControllerTest.java +++ b/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbDetailsDataRoleControllerTest.java @@ -25,12 +25,15 @@ import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SINK; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.app.KeyguardManager; import android.content.Context; import android.hardware.usb.UsbManager; import android.os.Handler; +import android.platform.test.annotations.RequiresFlagsEnabled; import androidx.fragment.app.FragmentActivity; import androidx.preference.PreferenceCategory; @@ -38,6 +41,7 @@ import androidx.preference.PreferenceManager; import androidx.preference.PreferenceScreen; import com.android.settings.R; +import com.android.settings.flags.Flags; import com.android.settingslib.core.lifecycle.Lifecycle; import com.android.settingslib.widget.SelectorWithWidgetPreference; @@ -49,6 +53,7 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; +import org.robolectric.Shadows; import org.robolectric.annotation.Config; @RunWith(RobolectricTestRunner.class) @@ -63,12 +68,11 @@ public class UsbDetailsDataRoleControllerTest { private PreferenceCategory mPreference; private PreferenceManager mPreferenceManager; private PreferenceScreen mScreen; + private UsbDetailsFragment mFragment; @Mock private UsbBackend mUsbBackend; @Mock - private UsbDetailsFragment mFragment; - @Mock private FragmentActivity mActivity; @Mock private Handler mHandler; @@ -76,7 +80,7 @@ public class UsbDetailsDataRoleControllerTest { @Before public void setUp() { MockitoAnnotations.initMocks(this); - + mFragment = spy(new UsbDetailsFragment()); mContext = RuntimeEnvironment.application; mLifecycle = new Lifecycle(() -> mLifecycle); mPreferenceManager = new PreferenceManager(mContext); @@ -95,12 +99,12 @@ public class UsbDetailsDataRoleControllerTest { mScreen.addPreference(mPreference); mDetailsDataRoleController.mHandler = mHandler; + + mDetailsDataRoleController.displayPreference(mScreen); } @Test public void displayRefresh_deviceRole_shouldCheckDevice() { - mDetailsDataRoleController.displayPreference(mScreen); - mDetailsDataRoleController.refresh(true, UsbManager.FUNCTION_NONE, POWER_ROLE_SINK, DATA_ROLE_DEVICE); @@ -112,8 +116,6 @@ public class UsbDetailsDataRoleControllerTest { @Test public void displayRefresh_hostRole_shouldCheckHost() { - mDetailsDataRoleController.displayPreference(mScreen); - mDetailsDataRoleController.refresh(true, UsbManager.FUNCTION_NONE, POWER_ROLE_SINK, DATA_ROLE_HOST); @@ -125,8 +127,6 @@ public class UsbDetailsDataRoleControllerTest { @Test public void displayRefresh_disconnected_shouldDisable() { - mDetailsDataRoleController.displayPreference(mScreen); - mDetailsDataRoleController.refresh(false, UsbManager.FUNCTION_NONE, POWER_ROLE_SINK, DATA_ROLE_DEVICE); @@ -135,7 +135,6 @@ public class UsbDetailsDataRoleControllerTest { @Test public void onClickDevice_hostEnabled_shouldSetDevice() { - mDetailsDataRoleController.displayPreference(mScreen); when(mUsbBackend.getDataRole()).thenReturn(DATA_ROLE_HOST); final SelectorWithWidgetPreference devicePref = getRadioPreference(DATA_ROLE_DEVICE); @@ -148,7 +147,6 @@ public class UsbDetailsDataRoleControllerTest { @Test public void onClickDeviceTwice_hostEnabled_shouldSetDeviceOnce() { - mDetailsDataRoleController.displayPreference(mScreen); when(mUsbBackend.getDataRole()).thenReturn(DATA_ROLE_HOST); final SelectorWithWidgetPreference devicePref = getRadioPreference(DATA_ROLE_DEVICE); @@ -162,7 +160,6 @@ public class UsbDetailsDataRoleControllerTest { @Test public void onClickDeviceAndRefresh_success_shouldClearSubtext() { - mDetailsDataRoleController.displayPreference(mScreen); when(mUsbBackend.getDataRole()).thenReturn(DATA_ROLE_HOST); final SelectorWithWidgetPreference devicePref = getRadioPreference(DATA_ROLE_DEVICE); @@ -180,7 +177,6 @@ public class UsbDetailsDataRoleControllerTest { @Test public void onClickDeviceAndRefresh_failed_shouldShowFailureText() { - mDetailsDataRoleController.displayPreference(mScreen); when(mUsbBackend.getDataRole()).thenReturn(DATA_ROLE_HOST); final SelectorWithWidgetPreference devicePref = getRadioPreference(DATA_ROLE_DEVICE); @@ -199,7 +195,6 @@ public class UsbDetailsDataRoleControllerTest { @Test public void onClickDevice_timedOut_shouldShowFailureText() { - mDetailsDataRoleController.displayPreference(mScreen); when(mUsbBackend.getDataRole()).thenReturn(DATA_ROLE_HOST); final SelectorWithWidgetPreference devicePref = getRadioPreference(DATA_ROLE_DEVICE); @@ -218,6 +213,22 @@ public class UsbDetailsDataRoleControllerTest { .isEqualTo(mContext.getString(R.string.usb_switching_failed)); } + @Test + @RequiresFlagsEnabled(Flags.FLAG_ENABLE_AUTH_CHALLENGE_FOR_USB_PREFERENCES) + public void onRadioButtonClicked_userAuthenticated() { + SelectorWithWidgetPreference preference = getRadioPreference(DATA_ROLE_DEVICE); + setAuthPassesAutomatically(); + + mDetailsDataRoleController.onRadioButtonClicked(preference); + + assertThat(mFragment.isUserAuthenticated()).isTrue(); + } + + private void setAuthPassesAutomatically() { + Shadows.shadowOf(mContext.getSystemService(KeyguardManager.class)) + .setIsKeyguardSecure(false); + } + private SelectorWithWidgetPreference getRadioPreference(int role) { return (SelectorWithWidgetPreference) mPreference.findPreference(UsbBackend.dataRoleToString(role)); diff --git a/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbDetailsFunctionsControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbDetailsFunctionsControllerTest.java index 091abde3748..eea4f52388b 100644 --- a/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbDetailsFunctionsControllerTest.java +++ b/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbDetailsFunctionsControllerTest.java @@ -30,15 +30,18 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.app.KeyguardManager; import android.content.Context; import android.hardware.usb.UsbManager; import android.net.TetheringManager; +import android.platform.test.annotations.RequiresFlagsEnabled; import androidx.fragment.app.FragmentActivity; import androidx.preference.PreferenceCategory; import androidx.preference.PreferenceManager; import androidx.preference.PreferenceScreen; +import com.android.settings.flags.Flags; import com.android.settings.testutils.shadow.ShadowUtils; import com.android.settingslib.core.lifecycle.Lifecycle; import com.android.settingslib.widget.SelectorWithWidgetPreference; @@ -51,6 +54,7 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; +import org.robolectric.Shadows; import org.robolectric.annotation.Config; import java.util.ArrayList; @@ -70,12 +74,11 @@ public class UsbDetailsFunctionsControllerTest { private PreferenceManager mPreferenceManager; private PreferenceScreen mScreen; private SelectorWithWidgetPreference mRadioButtonPreference; + private UsbDetailsFragment mFragment; @Mock private UsbBackend mUsbBackend; @Mock - private UsbDetailsFragment mFragment; - @Mock private FragmentActivity mActivity; @Mock private TetheringManager mTetheringManager; @@ -83,7 +86,7 @@ public class UsbDetailsFunctionsControllerTest { @Before public void setUp() { MockitoAnnotations.initMocks(this); - + mFragment = spy(new UsbDetailsFragment()); mContext = spy(RuntimeEnvironment.application); mLifecycle = new Lifecycle(() -> mLifecycle); mPreferenceManager = new PreferenceManager(mContext); @@ -334,6 +337,23 @@ public class UsbDetailsFunctionsControllerTest { eq(mDetailsFunctionsController.mOnStartTetheringCallback)); } + @Test + @RequiresFlagsEnabled(Flags.FLAG_ENABLE_AUTH_CHALLENGE_FOR_USB_PREFERENCES) + public void onRadioButtonClicked_userAuthenticated() { + mRadioButtonPreference.setKey(UsbBackend.usbFunctionsToString(UsbManager.FUNCTION_PTP)); + doReturn(UsbManager.FUNCTION_MTP).when(mUsbBackend).getCurrentFunctions(); + setAuthPassesAutomatically(); + + mDetailsFunctionsController.onRadioButtonClicked(mRadioButtonPreference); + + assertThat(mFragment.isUserAuthenticated()).isTrue(); + } + + private void setAuthPassesAutomatically() { + Shadows.shadowOf(mContext.getSystemService(KeyguardManager.class)) + .setIsKeyguardSecure(false); + } + @Test public void onTetheringFailed_resetPreviousFunctions() { mDetailsFunctionsController.mPreviousFunction = UsbManager.FUNCTION_PTP; diff --git a/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbDetailsTranscodeMtpControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbDetailsTranscodeMtpControllerTest.java index 51d2c1664f2..07d14ec9935 100644 --- a/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbDetailsTranscodeMtpControllerTest.java +++ b/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbDetailsTranscodeMtpControllerTest.java @@ -21,11 +21,14 @@ import static android.hardware.usb.UsbPortStatus.POWER_ROLE_NONE; import static com.google.common.truth.Truth.assertThat; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.when; +import android.app.KeyguardManager; import android.content.Context; import android.hardware.usb.UsbManager; import android.os.SystemProperties; +import android.platform.test.annotations.RequiresFlagsEnabled; import androidx.fragment.app.FragmentActivity; import androidx.preference.PreferenceCategory; @@ -33,6 +36,7 @@ import androidx.preference.PreferenceManager; import androidx.preference.PreferenceScreen; import androidx.preference.SwitchPreference; +import com.android.settings.flags.Flags; import com.android.settings.testutils.shadow.ShadowUtils; import org.junit.Before; @@ -43,6 +47,7 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; import org.robolectric.RuntimeEnvironment; +import org.robolectric.Shadows; import org.robolectric.annotation.Config; @RunWith(RobolectricTestRunner.class) @@ -57,18 +62,18 @@ public class UsbDetailsTranscodeMtpControllerTest { private PreferenceManager mPreferenceManager; private PreferenceScreen mScreen; private UsbDetailsTranscodeMtpController mUnderTest; + private UsbDetailsFragment mFragment; @Mock private UsbBackend mUsbBackend; @Mock - private UsbDetailsFragment mFragment; - @Mock private FragmentActivity mActivity; @Before public void setUp() { MockitoAnnotations.initMocks(this); + mFragment = spy(new UsbDetailsFragment()); mContext = RuntimeEnvironment.application; mPreferenceManager = new PreferenceManager(mContext); mScreen = mPreferenceManager.createPreferenceScreen(mContext); @@ -84,11 +89,12 @@ public class UsbDetailsTranscodeMtpControllerTest { mPreference = new PreferenceCategory(mContext); mPreference.setKey(mUnderTest.getPreferenceKey()); mScreen.addPreference(mPreference); + + mUnderTest.displayPreference(mScreen); } @Test public void displayRefresh_noUsbConnection_shouldDisablePrefCategory() { - mUnderTest.displayPreference(mScreen); when(mUsbBackend.areAllRolesSupported()).thenReturn(true); mUnderTest.refresh(false /* connected */, UsbManager.FUNCTION_MTP, POWER_ROLE_NONE, @@ -99,7 +105,6 @@ public class UsbDetailsTranscodeMtpControllerTest { @Test public void displayRefresh_noDataTransfer_shouldDisablePrefCategory() { - mUnderTest.displayPreference(mScreen); when(mUsbBackend.areAllRolesSupported()).thenReturn(true); mUnderTest.refresh(true /* connected */, UsbManager.FUNCTION_NONE, POWER_ROLE_NONE, @@ -110,7 +115,6 @@ public class UsbDetailsTranscodeMtpControllerTest { @Test public void displayRefresh_noDataRole_shouldDisablePrefCategory() throws InterruptedException { - mUnderTest.displayPreference(mScreen); when(mUsbBackend.areAllRolesSupported()).thenReturn(true); mUnderTest.refresh(true /* connected */, UsbManager.FUNCTION_MTP, POWER_ROLE_NONE, @@ -122,7 +126,6 @@ public class UsbDetailsTranscodeMtpControllerTest { @Ignore("b/313362757") @Test public void displayRefresh_fileTransfer_withAbsentProp_shouldCheck() { - mUnderTest.displayPreference(mScreen); when(mUsbBackend.areAllRolesSupported()).thenReturn(true); mUnderTest.refresh(true /* connected */, UsbManager.FUNCTION_MTP, POWER_ROLE_NONE, @@ -134,7 +137,6 @@ public class UsbDetailsTranscodeMtpControllerTest { @Ignore("b/313362757") @Test public void displayRefresh_fileTransfer_withUnsetProp_shouldUncheck() { - mUnderTest.displayPreference(mScreen); SystemProperties.set(TRANSCODE_MTP_SYS_PROP_KEY, Boolean.toString(false)); when(mUsbBackend.areAllRolesSupported()).thenReturn(true); @@ -147,7 +149,6 @@ public class UsbDetailsTranscodeMtpControllerTest { @Ignore("b/313362757") @Test public void displayRefresh_fileTransfer_withSetProp_shouldCheck() { - mUnderTest.displayPreference(mScreen); SystemProperties.set(TRANSCODE_MTP_SYS_PROP_KEY, Boolean.toString(true)); when(mUsbBackend.areAllRolesSupported()).thenReturn(true); @@ -160,7 +161,6 @@ public class UsbDetailsTranscodeMtpControllerTest { @Ignore("b/313362757") @Test public void click_checked_shouldSetSystemProperty() { - mUnderTest.displayPreference(mScreen); getSwitchPreference().performClick(); assertThat(SystemProperties.getBoolean(TRANSCODE_MTP_SYS_PROP_KEY, false)).isTrue(); } @@ -168,7 +168,6 @@ public class UsbDetailsTranscodeMtpControllerTest { @Ignore("b/313362757") @Test public void click_unChecked_shouldUnsetSystemProperty() { - mUnderTest.displayPreference(mScreen); getSwitchPreference().performClick(); getSwitchPreference().performClick(); assertThat(SystemProperties.getBoolean(TRANSCODE_MTP_SYS_PROP_KEY, true)).isFalse(); @@ -181,6 +180,21 @@ public class UsbDetailsTranscodeMtpControllerTest { assertThat(mUnderTest.isAvailable()).isFalse(); } + @Test + @RequiresFlagsEnabled(Flags.FLAG_ENABLE_AUTH_CHALLENGE_FOR_USB_PREFERENCES) + public void onClick_userAuthenticated() { + setAuthPassesAutomatically(); + + mUnderTest.onPreferenceClick(null); + + assertThat(mFragment.isUserAuthenticated()).isTrue(); + } + + private void setAuthPassesAutomatically() { + Shadows.shadowOf(mContext.getSystemService(KeyguardManager.class)) + .setIsKeyguardSecure(false); + } + private SwitchPreference getSwitchPreference() { return (SwitchPreference) mPreference.getPreference(0); }