From d6ec2ac7be6f4bcdfac0e0ca8afb16d01c40c86b Mon Sep 17 00:00:00 2001 From: hughchen Date: Wed, 31 Jul 2019 06:14:54 +0800 Subject: [PATCH] Tethering shouldn't indicates on when SIM without tethering option Before this CL, If SIM doesn't have tethering option then UI will not back to previous option when press "USB tethering" in [Default USB configuration]. This CL added receiver to observe USB state that get correct state from UsbManager. Bug: 138630479 Test: make -j42 RunSettingsRoboTests Change-Id: I6cc8da508f6ab142142ca8c28460125bad93925b --- .../usb/UsbConnectionBroadcastReceiver.java | 36 ++++----- .../usb/UsbDefaultFragment.java | 46 +++++++++++ .../usb/UsbDefaultFragmentTest.java | 80 ++++++++++++++++++- 3 files changed, 142 insertions(+), 20 deletions(-) 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; + } + } }