Add entitlement check for usb tethering

Before this CL, usb tethering in detail page doesn't have entitlement
check. This CL fix it by using the correct API

Also polish it by updating the UI before entitlement check to align
hotspot page. So in UI it will first check "usb tethering". If
entitlement check fail, it will revoke and go back to previous selection.

Bug: 115707279
Test: RunSettingsRoboTests
Change-Id: I3d2ebad2879479a870bcdfe596bb88b83c424389
This commit is contained in:
jackqdyulei
2018-10-02 14:19:27 -07:00
parent 092f66b279
commit 184b3a4c68
4 changed files with 205 additions and 30 deletions

View File

@@ -16,9 +16,14 @@
package com.android.settings.connecteddevice.usb;
import static android.net.ConnectivityManager.TETHERING_USB;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.hardware.usb.UsbManager;
import android.net.ConnectivityManager;
import android.os.Bundle;
import android.util.Log;
import androidx.annotation.VisibleForTesting;
@@ -40,11 +45,18 @@ import java.util.List;
public class UsbDefaultFragment extends RadioButtonPickerFragment {
@VisibleForTesting
UsbBackend mUsbBackend;
@VisibleForTesting
ConnectivityManager mConnectivityManager;
@VisibleForTesting
OnStartTetheringCallback mOnStartTetheringCallback = new OnStartTetheringCallback();
@VisibleForTesting
long mPreviousFunctions;
@Override
public void onAttach(Context context) {
super.onAttach(context);
mUsbBackend = new UsbBackend(context);
mConnectivityManager = context.getSystemService(ConnectivityManager.class);
}
@Override
@@ -105,9 +117,37 @@ public class UsbDefaultFragment extends RadioButtonPickerFragment {
@Override
protected boolean setDefaultKey(String key) {
long functions = UsbBackend.usbFunctionsFromString(key);
mPreviousFunctions = mUsbBackend.getCurrentFunctions();
if (!Utils.isMonkeyRunning()) {
if (functions == UsbManager.FUNCTION_RNDIS) {
// We need to have entitlement check for usb tethering, so use API in
// ConnectivityManager.
mConnectivityManager.startTethering(TETHERING_USB, true /* showProvisioningUi */,
mOnStartTetheringCallback);
} else {
mUsbBackend.setDefaultUsbFunctions(functions);
}
}
return true;
}
@VisibleForTesting
final class OnStartTetheringCallback extends
ConnectivityManager.OnStartTetheringCallback {
@Override
public void onTetheringStarted() {
super.onTetheringStarted();
// Set default usb functions again to make internal data persistent
mUsbBackend.setDefaultUsbFunctions(UsbManager.FUNCTION_RNDIS);
}
@Override
public void onTetheringFailed() {
super.onTetheringFailed();
mUsbBackend.setDefaultUsbFunctions(mPreviousFunctions);
updateCandidates();
}
}
}

View File

@@ -16,10 +16,14 @@
package com.android.settings.connecteddevice.usb;
import static android.net.ConnectivityManager.TETHERING_USB;
import android.content.Context;
import android.hardware.usb.UsbManager;
import android.hardware.usb.UsbPort;
import android.net.ConnectivityManager;
import androidx.annotation.VisibleForTesting;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceScreen;
@@ -47,10 +51,18 @@ public class UsbDetailsFunctionsController extends UsbDetailsController
}
private PreferenceCategory mProfilesContainer;
private ConnectivityManager mConnectivityManager;
@VisibleForTesting
OnStartTetheringCallback mOnStartTetheringCallback;
@VisibleForTesting
long mPreviousFunction;
public UsbDetailsFunctionsController(Context context, UsbDetailsFragment fragment,
UsbBackend backend) {
super(context, fragment, backend);
mConnectivityManager = context.getSystemService(ConnectivityManager.class);
mOnStartTetheringCallback = new OnStartTetheringCallback();
mPreviousFunction = mUsbBackend.getCurrentFunctions();
}
@Override
@@ -97,11 +109,30 @@ public class UsbDetailsFunctionsController extends UsbDetailsController
@Override
public void onRadioButtonClicked(RadioButtonPreference preference) {
long function = UsbBackend.usbFunctionsFromString(preference.getKey());
if (function != mUsbBackend.getCurrentFunctions() && !Utils.isMonkeyRunning()) {
final long function = UsbBackend.usbFunctionsFromString(preference.getKey());
final long previousFunction = mUsbBackend.getCurrentFunctions();
if (function != previousFunction && !Utils.isMonkeyRunning()) {
mPreviousFunction = previousFunction;
if (function == UsbManager.FUNCTION_RNDIS) {
//Update the UI in advance to make it looks smooth
final RadioButtonPreference prevPref =
(RadioButtonPreference) mProfilesContainer.findPreference(
UsbBackend.usbFunctionsToString(mPreviousFunction));
if (prevPref != null) {
prevPref.setChecked(false);
preference.setChecked(true);
}
// We need to have entitlement check for usb tethering, so use API in
// ConnectivityManager.
mConnectivityManager.startTethering(TETHERING_USB, true /* showProvisioningUi */,
mOnStartTetheringCallback);
} else {
mUsbBackend.setCurrentFunctions(function);
}
}
}
@Override
public boolean isAvailable() {
@@ -112,4 +143,15 @@ public class UsbDetailsFunctionsController extends UsbDetailsController
public String getPreferenceKey() {
return "usb_details_functions";
}
@VisibleForTesting
final class OnStartTetheringCallback extends
ConnectivityManager.OnStartTetheringCallback {
@Override
public void onTetheringFailed() {
super.onTetheringFailed();
mUsbBackend.setCurrentFunctions(mPreviousFunction);
}
}
}

View File

@@ -16,13 +16,21 @@
package com.android.settings.connecteddevice.usb;
import static android.net.ConnectivityManager.TETHERING_USB;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Matchers.anyLong;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
import android.hardware.usb.UsbManager;
import android.net.ConnectivityManager;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.testutils.shadow.ShadowUtils;
@@ -32,13 +40,17 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.robolectric.Robolectric;
import org.robolectric.annotation.Config;
import org.robolectric.util.FragmentTestUtil;
@RunWith(SettingsRobolectricTestRunner.class)
public class UsbDefaultFragmentTest {
@Mock
private UsbBackend mUsbBackend;
@Mock
private ConnectivityManager mConnectivityManager;
private UsbDefaultFragment mFragment;
@@ -47,6 +59,7 @@ public class UsbDefaultFragmentTest {
MockitoAnnotations.initMocks(this);
mFragment = new UsbDefaultFragment();
mFragment.mUsbBackend = mUsbBackend;
mFragment.mConnectivityManager = mConnectivityManager;
}
@Test
@@ -102,12 +115,6 @@ public class UsbDefaultFragmentTest {
verify(mUsbBackend).setDefaultUsbFunctions(UsbManager.FUNCTION_PTP);
}
@Test
public void setDefaultKey_isRndis_shouldSetRndis() {
mFragment.setDefaultKey(UsbBackend.usbFunctionsToString(UsbManager.FUNCTION_RNDIS));
verify(mUsbBackend).setDefaultUsbFunctions(UsbManager.FUNCTION_RNDIS);
}
@Test
public void setDefaultKey_isMidi_shouldSetMidi() {
mFragment.setDefaultKey(UsbBackend.usbFunctionsToString(UsbManager.FUNCTION_MIDI));
@@ -119,6 +126,39 @@ public class UsbDefaultFragmentTest {
public void setDefaultKey_isMonkey_shouldDoNothing() {
ShadowUtils.setIsUserAMonkey(true);
mFragment.setDefaultKey(UsbBackend.usbFunctionsToString(UsbManager.FUNCTION_MTP));
verifyZeroInteractions(mUsbBackend);
verify(mUsbBackend, never()).setDefaultUsbFunctions(anyLong());
}
@Test
public void setDefaultKey_functionRndis_startTetheringInvoked() {
doReturn(UsbManager.FUNCTION_MTP).when(mUsbBackend).getCurrentFunctions();
mFragment.setDefaultKey(UsbBackend.usbFunctionsToString(UsbManager.FUNCTION_RNDIS));
verify(mConnectivityManager).startTethering(TETHERING_USB, true,
mFragment.mOnStartTetheringCallback);
assertThat(mFragment.mPreviousFunctions).isEqualTo(
UsbManager.FUNCTION_MTP);
}
@Test
public void setDefaultKey_functionOther_setCurrentFunctionInvoked() {
doReturn(UsbManager.FUNCTION_MTP).when(mUsbBackend).getCurrentFunctions();
mFragment.setDefaultKey(UsbBackend.usbFunctionsToString(UsbManager.FUNCTION_PTP));
verify(mUsbBackend).setDefaultUsbFunctions(UsbManager.FUNCTION_PTP);
assertThat(mFragment.mPreviousFunctions).isEqualTo(
UsbManager.FUNCTION_MTP);
}
@Test
public void onTetheringStarted_setDefaultUsbFunctions() {
mFragment.mPreviousFunctions = UsbManager.FUNCTION_PTP;
mFragment.mOnStartTetheringCallback.onTetheringStarted();
verify(mUsbBackend).setDefaultUsbFunctions(UsbManager.FUNCTION_RNDIS);
}
}

View File

@@ -16,20 +16,21 @@
package com.android.settings.connecteddevice.usb;
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.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
import android.hardware.usb.UsbManager;
import android.hardware.usb.UsbPort;
import androidx.fragment.app.FragmentActivity;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
import android.net.ConnectivityManager;
import com.android.settings.testutils.SettingsRobolectricTestRunner;
import com.android.settings.testutils.shadow.ShadowUtils;
@@ -48,15 +49,21 @@ import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import androidx.fragment.app.FragmentActivity;
import androidx.preference.PreferenceCategory;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceScreen;
@RunWith(SettingsRobolectricTestRunner.class)
public class UsbDetailsFunctionsControllerTest {
private UsbDetailsFunctionsController mDetailsFunctionsController;
private Context mContext;
private Lifecycle mLifecycle;
private PreferenceCategory mPreference;
private PreferenceCategory mPreferenceCategory;
private PreferenceManager mPreferenceManager;
private PreferenceScreen mScreen;
private RadioButtonPreference mRadioButtonPreference;
@Mock
private UsbBackend mUsbBackend;
@@ -64,12 +71,14 @@ public class UsbDetailsFunctionsControllerTest {
private UsbDetailsFragment mFragment;
@Mock
private FragmentActivity mActivity;
@Mock
private ConnectivityManager mConnectivityManager;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = RuntimeEnvironment.application;
mContext = spy(RuntimeEnvironment.application);
mLifecycle = new Lifecycle(() -> mLifecycle);
mPreferenceManager = new PreferenceManager(mContext);
mScreen = mPreferenceManager.createPreferenceScreen(mContext);
@@ -79,12 +88,16 @@ public class UsbDetailsFunctionsControllerTest {
when(mFragment.getContext()).thenReturn(mContext);
when(mFragment.getPreferenceManager()).thenReturn(mPreferenceManager);
when(mFragment.getPreferenceScreen()).thenReturn(mScreen);
when(mContext.getSystemService(ConnectivityManager.class)).thenReturn(mConnectivityManager);
mDetailsFunctionsController = new UsbDetailsFunctionsController(mContext, mFragment,
mUsbBackend);
mPreference = new PreferenceCategory(mContext);
mPreference.setKey(mDetailsFunctionsController.getPreferenceKey());
mScreen.addPreference(mPreference);
mPreferenceCategory = new PreferenceCategory(mContext);
mPreferenceCategory.setKey(mDetailsFunctionsController.getPreferenceKey());
mScreen.addPreference(mPreferenceCategory);
mDetailsFunctionsController.displayPreference(mScreen);
mRadioButtonPreference = new RadioButtonPreference(mContext);
}
@Test
@@ -106,10 +119,9 @@ public class UsbDetailsFunctionsControllerTest {
public void displayRefresh_disconnected_shouldDisable() {
when(mUsbBackend.areFunctionsSupported(anyLong())).thenReturn(true);
mDetailsFunctionsController.displayPreference(mScreen);
mDetailsFunctionsController.refresh(false, UsbManager.FUNCTION_NONE,
UsbPort.POWER_ROLE_SINK, UsbPort.DATA_ROLE_DEVICE);
assertThat(mPreference.isEnabled()).isFalse();
assertThat(mPreferenceCategory.isEnabled()).isFalse();
}
@Test
@@ -119,7 +131,6 @@ public class UsbDetailsFunctionsControllerTest {
when(mUsbBackend.areFunctionsSupported(UsbManager.FUNCTION_PTP)).thenReturn(false);
when(mUsbBackend.areFunctionsSupported(UsbManager.FUNCTION_RNDIS)).thenReturn(false);
mDetailsFunctionsController.displayPreference(mScreen);
mDetailsFunctionsController.refresh(true, UsbManager.FUNCTION_NONE, UsbPort.POWER_ROLE_SINK,
UsbPort.DATA_ROLE_DEVICE);
List<RadioButtonPreference> prefs = getRadioPreferences();
@@ -132,7 +143,6 @@ public class UsbDetailsFunctionsControllerTest {
public void displayRefresh_mtpEnabled_shouldCheckSwitches() {
when(mUsbBackend.areFunctionsSupported(anyLong())).thenReturn(true);
mDetailsFunctionsController.displayPreference(mScreen);
mDetailsFunctionsController.refresh(true, UsbManager.FUNCTION_MTP, UsbPort.POWER_ROLE_SINK,
UsbPort.DATA_ROLE_DEVICE);
List<RadioButtonPreference> prefs = getRadioPreferences();
@@ -146,7 +156,6 @@ public class UsbDetailsFunctionsControllerTest {
public void onClickMtp_noneEnabled_shouldEnableMtp() {
when(mUsbBackend.areFunctionsSupported(anyLong())).thenReturn(true);
mDetailsFunctionsController.displayPreference(mScreen);
mDetailsFunctionsController.refresh(true, UsbManager.FUNCTION_NONE, UsbPort.POWER_ROLE_SINK,
UsbPort.DATA_ROLE_DEVICE);
when(mUsbBackend.getCurrentFunctions()).thenReturn(UsbManager.FUNCTION_NONE);
@@ -165,7 +174,6 @@ public class UsbDetailsFunctionsControllerTest {
public void onClickMtp_ptpEnabled_shouldEnableMtp() {
when(mUsbBackend.areFunctionsSupported(anyLong())).thenReturn(true);
mDetailsFunctionsController.displayPreference(mScreen);
mDetailsFunctionsController.refresh(true, UsbManager.FUNCTION_PTP, UsbPort.POWER_ROLE_SINK,
UsbPort.DATA_ROLE_DEVICE);
when(mUsbBackend.getCurrentFunctions()).thenReturn(UsbManager.FUNCTION_PTP);
@@ -187,7 +195,6 @@ public class UsbDetailsFunctionsControllerTest {
public void onClickNone_mtpEnabled_shouldDisableMtp() {
when(mUsbBackend.areFunctionsSupported(anyLong())).thenReturn(true);
mDetailsFunctionsController.displayPreference(mScreen);
mDetailsFunctionsController.refresh(true, UsbManager.FUNCTION_MTP, UsbPort.POWER_ROLE_SINK,
UsbPort.DATA_ROLE_DEVICE);
when(mUsbBackend.getCurrentFunctions()).thenReturn(UsbManager.FUNCTION_MTP);
@@ -211,9 +218,55 @@ public class UsbDetailsFunctionsControllerTest {
private List<RadioButtonPreference> getRadioPreferences() {
ArrayList<RadioButtonPreference> result = new ArrayList<>();
for (int i = 0; i < mPreference.getPreferenceCount(); i++) {
result.add((RadioButtonPreference) mPreference.getPreference(i));
for (int i = 0; i < mPreferenceCategory.getPreferenceCount(); i++) {
result.add((RadioButtonPreference) mPreferenceCategory.getPreference(i));
}
return result;
}
@Test
public void onRadioButtonClicked_functionRndis_startTetheringInvoked() {
mRadioButtonPreference.setKey(UsbBackend.usbFunctionsToString(UsbManager.FUNCTION_RNDIS));
doReturn(UsbManager.FUNCTION_MTP).when(mUsbBackend).getCurrentFunctions();
mDetailsFunctionsController.onRadioButtonClicked(mRadioButtonPreference);
verify(mConnectivityManager).startTethering(TETHERING_USB, true,
mDetailsFunctionsController.mOnStartTetheringCallback);
assertThat(mDetailsFunctionsController.mPreviousFunction).isEqualTo(
UsbManager.FUNCTION_MTP);
}
@Test
public void onRadioButtonClicked_functionOther_setCurrentFunctionInvoked() {
mRadioButtonPreference.setKey(UsbBackend.usbFunctionsToString(UsbManager.FUNCTION_PTP));
doReturn(UsbManager.FUNCTION_MTP).when(mUsbBackend).getCurrentFunctions();
mDetailsFunctionsController.onRadioButtonClicked(mRadioButtonPreference);
verify(mUsbBackend).setCurrentFunctions(UsbManager.FUNCTION_PTP);
assertThat(mDetailsFunctionsController.mPreviousFunction).isEqualTo(
UsbManager.FUNCTION_MTP);
}
@Test
public void onRadioButtonClicked_clickSameButton_doNothing() {
mRadioButtonPreference.setKey(UsbBackend.usbFunctionsToString(UsbManager.FUNCTION_PTP));
doReturn(UsbManager.FUNCTION_PTP).when(mUsbBackend).getCurrentFunctions();
mDetailsFunctionsController.onRadioButtonClicked(mRadioButtonPreference);
verify(mUsbBackend, never()).setCurrentFunctions(UsbManager.FUNCTION_PTP);
verify(mConnectivityManager, never()).startTethering(TETHERING_USB, true,
mDetailsFunctionsController.mOnStartTetheringCallback);
}
@Test
public void onTetheringFailed_resetPreviousFunctions() {
mDetailsFunctionsController.mPreviousFunction = UsbManager.FUNCTION_PTP;
mDetailsFunctionsController.mOnStartTetheringCallback.onTetheringFailed();
verify(mUsbBackend).setCurrentFunctions(UsbManager.FUNCTION_PTP);
}
}