diff --git a/src/com/android/settings/connecteddevice/usb/UsbConnectionBroadcastReceiver.java b/src/com/android/settings/connecteddevice/usb/UsbConnectionBroadcastReceiver.java index 695a714528a..e557847d06e 100644 --- a/src/com/android/settings/connecteddevice/usb/UsbConnectionBroadcastReceiver.java +++ b/src/com/android/settings/connecteddevice/usb/UsbConnectionBroadcastReceiver.java @@ -57,26 +57,24 @@ public class UsbConnectionBroadcastReceiver extends BroadcastReceiver implements if (UsbManager.ACTION_USB_STATE.equals(intent.getAction())) { mConnected = intent.getExtras().getBoolean(UsbManager.USB_CONNECTED) || intent.getExtras().getBoolean(UsbManager.USB_HOST_CONNECTED); - if (mConnected) { - long functions = UsbManager.FUNCTION_NONE; - if (intent.getExtras().getBoolean(UsbManager.USB_FUNCTION_MTP) - && intent.getExtras().getBoolean(UsbManager.USB_DATA_UNLOCKED, false)) { - functions |= UsbManager.FUNCTION_MTP; - } - if (intent.getExtras().getBoolean(UsbManager.USB_FUNCTION_PTP) - && intent.getExtras().getBoolean(UsbManager.USB_DATA_UNLOCKED, false)) { - functions |= UsbManager.FUNCTION_PTP; - } - if (intent.getExtras().getBoolean(UsbManager.USB_FUNCTION_MIDI)) { - functions |= UsbManager.FUNCTION_MIDI; - } - if (intent.getExtras().getBoolean(UsbManager.USB_FUNCTION_RNDIS)) { - functions |= UsbManager.FUNCTION_RNDIS; - } - mFunctions = functions; - mDataRole = mUsbBackend.getDataRole(); - mPowerRole = mUsbBackend.getPowerRole(); + long functions = UsbManager.FUNCTION_NONE; + if (intent.getExtras().getBoolean(UsbManager.USB_FUNCTION_MTP) + && intent.getExtras().getBoolean(UsbManager.USB_DATA_UNLOCKED, false)) { + functions |= UsbManager.FUNCTION_MTP; } + if (intent.getExtras().getBoolean(UsbManager.USB_FUNCTION_PTP) + && intent.getExtras().getBoolean(UsbManager.USB_DATA_UNLOCKED, false)) { + functions |= UsbManager.FUNCTION_PTP; + } + if (intent.getExtras().getBoolean(UsbManager.USB_FUNCTION_MIDI)) { + functions |= UsbManager.FUNCTION_MIDI; + } + if (intent.getExtras().getBoolean(UsbManager.USB_FUNCTION_RNDIS)) { + functions |= UsbManager.FUNCTION_RNDIS; + } + mFunctions = functions; + mDataRole = mUsbBackend.getDataRole(); + mPowerRole = mUsbBackend.getPowerRole(); } else if (UsbManager.ACTION_USB_PORT_CHANGED.equals(intent.getAction())) { UsbPortStatus portStatus = intent.getExtras() .getParcelable(UsbManager.EXTRA_PORT_STATUS); diff --git a/src/com/android/settings/connecteddevice/usb/UsbDefaultFragment.java b/src/com/android/settings/connecteddevice/usb/UsbDefaultFragment.java index d4f12837391..12e978ff349 100644 --- a/src/com/android/settings/connecteddevice/usb/UsbDefaultFragment.java +++ b/src/com/android/settings/connecteddevice/usb/UsbDefaultFragment.java @@ -26,12 +26,14 @@ import android.net.ConnectivityManager; import android.os.Bundle; import androidx.annotation.VisibleForTesting; +import androidx.preference.PreferenceScreen; import com.android.settings.R; import com.android.settings.Utils; import com.android.settings.widget.RadioButtonPickerFragment; import com.android.settingslib.widget.CandidateInfo; import com.android.settingslib.widget.FooterPreference; +import com.android.settingslib.widget.RadioButtonPreference; import com.google.android.collect.Lists; @@ -49,12 +51,31 @@ public class UsbDefaultFragment extends RadioButtonPickerFragment { OnStartTetheringCallback mOnStartTetheringCallback = new OnStartTetheringCallback(); @VisibleForTesting long mPreviousFunctions; + @VisibleForTesting + long mCurrentFunctions; + @VisibleForTesting + boolean mIsStartTethering = false; + + private UsbConnectionBroadcastReceiver mUsbReceiver; + + @VisibleForTesting + UsbConnectionBroadcastReceiver.UsbConnectionListener mUsbConnectionListener = + (connected, functions, powerRole, dataRole) -> { + if (mIsStartTethering) { + mCurrentFunctions = functions; + refresh(functions); + } + }; @Override public void onAttach(Context context) { super.onAttach(context); mUsbBackend = new UsbBackend(context); mConnectivityManager = context.getSystemService(ConnectivityManager.class); + mUsbReceiver = new UsbConnectionBroadcastReceiver(context, mUsbConnectionListener, + mUsbBackend); + getSettingsLifecycle().addObserver(mUsbReceiver); + mCurrentFunctions = mUsbBackend.getDefaultUsbFunctions(); } @Override @@ -118,9 +139,12 @@ public class UsbDefaultFragment extends RadioButtonPickerFragment { if (functions == UsbManager.FUNCTION_RNDIS) { // We need to have entitlement check for usb tethering, so use API in // ConnectivityManager. + mIsStartTethering = true; mConnectivityManager.startTethering(TETHERING_USB, true /* showProvisioningUi */, mOnStartTetheringCallback); } else { + mIsStartTethering = false; + mCurrentFunctions = functions; mUsbBackend.setDefaultUsbFunctions(functions); } @@ -128,6 +152,12 @@ public class UsbDefaultFragment extends RadioButtonPickerFragment { return true; } + @Override + public void onPause() { + super.onPause(); + mUsbBackend.setDefaultUsbFunctions(mCurrentFunctions); + } + @VisibleForTesting final class OnStartTetheringCallback extends ConnectivityManager.OnStartTetheringCallback { @@ -136,6 +166,7 @@ public class UsbDefaultFragment extends RadioButtonPickerFragment { public void onTetheringStarted() { super.onTetheringStarted(); // Set default usb functions again to make internal data persistent + mCurrentFunctions = UsbManager.FUNCTION_RNDIS; mUsbBackend.setDefaultUsbFunctions(UsbManager.FUNCTION_RNDIS); } @@ -146,4 +177,19 @@ public class UsbDefaultFragment extends RadioButtonPickerFragment { updateCandidates(); } } + + private void refresh(long functions) { + final PreferenceScreen screen = getPreferenceScreen(); + for (long option : UsbDetailsFunctionsController.FUNCTIONS_MAP.keySet()) { + final RadioButtonPreference pref = + screen.findPreference(UsbBackend.usbFunctionsToString(option)); + if (pref != null) { + final boolean isSupported = mUsbBackend.areFunctionsSupported(option); + pref.setEnabled(isSupported); + if (isSupported) { + pref.setChecked(functions == option); + } + } + } + } } \ No newline at end of file diff --git a/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbDefaultFragmentTest.java b/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbDefaultFragmentTest.java index d8663fcde93..4afe22a7a8d 100644 --- a/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbDefaultFragmentTest.java +++ b/tests/robotests/src/com/android/settings/connecteddevice/usb/UsbDefaultFragmentTest.java @@ -16,12 +16,15 @@ package com.android.settings.connecteddevice.usb; +import static android.hardware.usb.UsbPortStatus.DATA_ROLE_DEVICE; +import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SINK; import static android.net.ConnectivityManager.TETHERING_USB; import static com.google.common.truth.Truth.assertThat; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -29,6 +32,8 @@ import static org.mockito.Mockito.when; import android.hardware.usb.UsbManager; import android.net.ConnectivityManager; +import androidx.preference.PreferenceScreen; + import com.android.settings.testutils.shadow.ShadowUtils; import org.junit.Before; @@ -52,7 +57,7 @@ public class UsbDefaultFragmentTest { @Before public void setUp() { MockitoAnnotations.initMocks(this); - mFragment = new UsbDefaultFragment(); + mFragment = new TestFragment(); mFragment.mUsbBackend = mUsbBackend; mFragment.mConnectivityManager = mConnectivityManager; } @@ -156,4 +161,77 @@ public class UsbDefaultFragmentTest { verify(mUsbBackend).setDefaultUsbFunctions(UsbManager.FUNCTION_RNDIS); } + + @Test + public void onPause_receivedRndis_shouldSetRndis() { + mFragment.mIsStartTethering = true; + mFragment.mUsbConnectionListener.onUsbConnectionChanged(true /* connected */, + UsbManager.FUNCTION_RNDIS, POWER_ROLE_SINK, DATA_ROLE_DEVICE); + + mFragment.onPause(); + + verify(mUsbBackend).setDefaultUsbFunctions(UsbManager.FUNCTION_RNDIS); + assertThat(mFragment.mCurrentFunctions).isEqualTo(UsbManager.FUNCTION_RNDIS); + } + + @Test + public void onPause_receivedNone_shouldSetNone() { + mFragment.mIsStartTethering = true; + mFragment.mUsbConnectionListener.onUsbConnectionChanged(true /* connected */, + UsbManager.FUNCTION_NONE, POWER_ROLE_SINK, DATA_ROLE_DEVICE); + + mFragment.onPause(); + + verify(mUsbBackend).setDefaultUsbFunctions(UsbManager.FUNCTION_NONE); + assertThat(mFragment.mCurrentFunctions).isEqualTo(UsbManager.FUNCTION_NONE); + } + + @Test + public void onPause_receivedMtp_shouldSetMtp() { + mFragment.mIsStartTethering = true; + mFragment.mUsbConnectionListener.onUsbConnectionChanged(true /* connected */, + UsbManager.FUNCTION_MTP, POWER_ROLE_SINK, DATA_ROLE_DEVICE); + + mFragment.onPause(); + + verify(mUsbBackend).setDefaultUsbFunctions(UsbManager.FUNCTION_MTP); + assertThat(mFragment.mCurrentFunctions).isEqualTo(UsbManager.FUNCTION_MTP); + } + + @Test + public void onPause_receivedPtp_shouldSetPtp() { + mFragment.mIsStartTethering = true; + mFragment.mUsbConnectionListener.onUsbConnectionChanged(true /* connected */, + UsbManager.FUNCTION_PTP, POWER_ROLE_SINK, DATA_ROLE_DEVICE); + + mFragment.onPause(); + + verify(mUsbBackend).setDefaultUsbFunctions(UsbManager.FUNCTION_PTP); + assertThat(mFragment.mCurrentFunctions).isEqualTo(UsbManager.FUNCTION_PTP); + } + + @Test + public void onPause_receivedMidi_shouldSetMidi() { + mFragment.mIsStartTethering = true; + mFragment.mUsbConnectionListener.onUsbConnectionChanged(true /* connected */, + UsbManager.FUNCTION_MIDI, POWER_ROLE_SINK, DATA_ROLE_DEVICE); + + mFragment.onPause(); + + verify(mUsbBackend).setDefaultUsbFunctions(UsbManager.FUNCTION_MIDI); + assertThat(mFragment.mCurrentFunctions).isEqualTo(UsbManager.FUNCTION_MIDI); + } + + public static class TestFragment extends UsbDefaultFragment { + public final PreferenceScreen mScreen; + + public TestFragment() { + mScreen = mock(PreferenceScreen.class); + } + + @Override + public PreferenceScreen getPreferenceScreen() { + return mScreen; + } + } }