From 36d320a8de709ee61790e8c1dcafd5b368614a21 Mon Sep 17 00:00:00 2001 From: Robert Luo Date: Fri, 29 Jul 2022 16:59:44 +0800 Subject: [PATCH] Allow advanced VPN to manage connection status via its UI Bug: 238641532 Test: atest -c VpnSettingsTest Change-Id: Ia6f1d84bba38bab7f13f46dc8a4fdb4eb0505f8f Merged-In: Ia6f1d84bba38bab7f13f46dc8a4fdb4eb0505f8f --- .../vpn2/AdvancedVpnFeatureProvider.java | 5 + .../vpn2/AdvancedVpnFeatureProviderImpl.java | 5 + .../android/settings/vpn2/VpnSettings.java | 12 +- .../settings/vpn2/VpnSettingsTest.java | 117 ++++++++++++++++-- 4 files changed, 124 insertions(+), 15 deletions(-) diff --git a/src/com/android/settings/vpn2/AdvancedVpnFeatureProvider.java b/src/com/android/settings/vpn2/AdvancedVpnFeatureProvider.java index cb56c351448..962b6c2e53b 100644 --- a/src/com/android/settings/vpn2/AdvancedVpnFeatureProvider.java +++ b/src/com/android/settings/vpn2/AdvancedVpnFeatureProvider.java @@ -47,4 +47,9 @@ public interface AdvancedVpnFeatureProvider { * Returns {@code true} advanced vpn is removable. */ boolean isAdvancedVpnRemovable(); + + /** + * Returns {@code true} if the disconnect dialog is enabled when advanced vpn is connected. + */ + boolean isDisconnectDialogEnabled(); } diff --git a/src/com/android/settings/vpn2/AdvancedVpnFeatureProviderImpl.java b/src/com/android/settings/vpn2/AdvancedVpnFeatureProviderImpl.java index c5bc69c042d..b8f58a9fde7 100644 --- a/src/com/android/settings/vpn2/AdvancedVpnFeatureProviderImpl.java +++ b/src/com/android/settings/vpn2/AdvancedVpnFeatureProviderImpl.java @@ -46,4 +46,9 @@ public class AdvancedVpnFeatureProviderImpl implements AdvancedVpnFeatureProvide public boolean isAdvancedVpnRemovable() { return true; } + + @Override + public boolean isDisconnectDialogEnabled() { + return true; + } } diff --git a/src/com/android/settings/vpn2/VpnSettings.java b/src/com/android/settings/vpn2/VpnSettings.java index 3b875eb1293..a91bb6c7e66 100644 --- a/src/com/android/settings/vpn2/VpnSettings.java +++ b/src/com/android/settings/vpn2/VpnSettings.java @@ -366,7 +366,7 @@ public class VpnSettings extends RestrictedSettingsFragment implements public void setShownPreferences(final Collection updates) { retainAllPreference(updates); - final PreferenceGroup vpnGroup = getPreferenceScreen(); + final PreferenceGroup vpnGroup = mPreferenceScreen; updatePreferenceGroup(vpnGroup, updates); // Show all new preferences on the screen @@ -448,14 +448,16 @@ public class VpnSettings extends RestrictedSettingsFragment implements } else if (preference instanceof AppPreference) { AppPreference pref = (AppPreference) preference; boolean connected = (pref.getState() == AppPreference.STATE_CONNECTED); + String vpnPackageName = pref.getPackageName(); - if (!connected) { + if ((!connected) || (isAdvancedVpn(mFeatureProvider, vpnPackageName, getContext()) + && !mFeatureProvider.isDisconnectDialogEnabled())) { try { UserHandle user = UserHandle.of(pref.getUserId()); - Context userContext = getActivity().createPackageContextAsUser( - getActivity().getPackageName(), 0 /* flags */, user); + Context userContext = getContext().createPackageContextAsUser( + getContext().getPackageName(), 0 /* flags */, user); PackageManager pm = userContext.getPackageManager(); - Intent appIntent = pm.getLaunchIntentForPackage(pref.getPackageName()); + Intent appIntent = pm.getLaunchIntentForPackage(vpnPackageName); if (appIntent != null) { userContext.startActivityAsUser(appIntent, user); return true; diff --git a/tests/unit/src/com/android/settings/vpn2/VpnSettingsTest.java b/tests/unit/src/com/android/settings/vpn2/VpnSettingsTest.java index d6ba33a3bc2..953a524750d 100644 --- a/tests/unit/src/com/android/settings/vpn2/VpnSettingsTest.java +++ b/tests/unit/src/com/android/settings/vpn2/VpnSettingsTest.java @@ -21,16 +21,21 @@ 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.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.when; import android.app.AppOpsManager; import android.content.Context; +import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.os.Looper; import android.os.UserHandle; +import android.text.TextUtils; import android.util.ArraySet; import androidx.preference.Preference; @@ -48,6 +53,7 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; @@ -58,13 +64,18 @@ import java.util.Set; @RunWith(AndroidJUnit4.class) public class VpnSettingsTest { - private static final String ADVANCED_VPN_GROUP_KEY = "advanced_vpn_group"; - private static final String VPN_GROUP_KEY = "vpn_group"; - private static final String ADVANCED_VPN_GROUP_TITLE = "advanced_vpn_group_title"; - private static final String VPN_GROUP_TITLE = "vpn_group_title"; - private static final String FAKE_PACKAGE_NAME = "com.fake.package.name"; - private static final String ADVANCED_VPN_GROUP_PACKAGE_NAME = "com.advanced.package.name"; private static final int USER_ID_1 = UserHandle.USER_NULL; + private static final String VPN_GROUP_KEY = "vpn_group"; + private static final String VPN_GROUP_TITLE = "vpn_group_title"; + private static final String VPN_PACKAGE_NAME = "vpn.package.name"; + private static final String VPN_LAUNCH_INTENT = "vpn.action"; + private static final String ADVANCED_VPN_GROUP_KEY = "advanced_vpn_group"; + private static final String ADVANCED_VPN_GROUP_TITLE = "advanced_vpn_group_title"; + private static final String ADVANCED_VPN_PACKAGE_NAME = "advanced.vpn.package.name"; + private static final String ADVANCED_VPN_LAUNCH_INTENT = "advanced.vpn.action"; + + private final Intent mVpnIntent = new Intent().setAction(VPN_LAUNCH_INTENT); + private final Intent mAdvancedVpnIntent = new Intent().setAction(ADVANCED_VPN_LAUNCH_INTENT); @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule(); @@ -108,7 +119,7 @@ public class VpnSettingsTest { when(mFakeFeatureFactory.mAdvancedVpnFeatureProvider.getVpnPreferenceGroupTitle(mContext)) .thenReturn(VPN_GROUP_TITLE); when(mFakeFeatureFactory.mAdvancedVpnFeatureProvider.getAdvancedVpnPackageName()) - .thenReturn(ADVANCED_VPN_GROUP_PACKAGE_NAME); + .thenReturn(ADVANCED_VPN_PACKAGE_NAME); when(mFakeFeatureFactory.mAdvancedVpnFeatureProvider.isAdvancedVpnSupported(any())) .thenReturn(true); when(mContext.getPackageManager()).thenReturn(mPackageManager); @@ -122,7 +133,7 @@ public class VpnSettingsTest { public void setShownAdvancedPreferences_hasGeneralVpn_returnsVpnCountAs1() { Set updates = new ArraySet<>(); AppPreference pref = - spy(new AppPreference(mContext, USER_ID_1, FAKE_PACKAGE_NAME)); + spy(new AppPreference(mContext, USER_ID_1, VPN_PACKAGE_NAME)); updates.add(pref); mVpnSettings.setShownAdvancedPreferences(updates); @@ -136,7 +147,7 @@ public class VpnSettingsTest { public void setShownAdvancedPreferences_hasAdvancedVpn_returnsAdvancedVpnCountAs1() { Set updates = new ArraySet<>(); AppPreference pref = - spy(new AppPreference(mContext, USER_ID_1, ADVANCED_VPN_GROUP_PACKAGE_NAME)); + spy(new AppPreference(mContext, USER_ID_1, ADVANCED_VPN_PACKAGE_NAME)); updates.add(pref); mVpnSettings.setShownAdvancedPreferences(updates); @@ -175,7 +186,7 @@ public class VpnSettingsTest { List opEntries = new ArrayList<>(); List apps = new ArrayList<>(); AppOpsManager.PackageOps packageOps = - new AppOpsManager.PackageOps(FAKE_PACKAGE_NAME, uid, opEntries); + new AppOpsManager.PackageOps(VPN_PACKAGE_NAME, uid, opEntries); apps.add(packageOps); when(mAppOpsManager.getPackagesForOps((int[]) any())).thenReturn(apps); when(mFakeFeatureFactory.mAdvancedVpnFeatureProvider.isAdvancedVpnSupported(any())) @@ -185,4 +196,90 @@ public class VpnSettingsTest { mFakeFeatureFactory.getAdvancedVpnFeatureProvider(), mAppOpsManager)).isEmpty(); } + + @Test + public void clickVpn_VpnConnected_doesNotStartVpnLaunchIntent() + throws PackageManager.NameNotFoundException { + Set updates = new ArraySet<>(); + AppPreference pref = spy(new AppPreference(mContext, USER_ID_1, VPN_PACKAGE_NAME)); + pref.setState(AppPreference.STATE_CONNECTED); + updates.add(pref); + when(mContext.createPackageContextAsUser(any(), anyInt(), any())).thenReturn(mContext); + when(mContext.getPackageManager()).thenReturn(mPackageManager); + when(mPackageManager.getLaunchIntentForPackage(any())).thenReturn(mVpnIntent); + ArgumentCaptor captor = ArgumentCaptor.forClass(Intent.class); + doNothing().when(mContext).startActivityAsUser(captor.capture(), any()); + mVpnSettings.setShownPreferences(updates); + + mVpnSettings.onPreferenceClick(pref); + + verify(mContext, never()).startActivityAsUser(any(), any()); + } + + @Test + public void clickVpn_VpnDisconnected_startsVpnLaunchIntent() + throws PackageManager.NameNotFoundException { + Set updates = new ArraySet<>(); + AppPreference pref = spy(new AppPreference(mContext, USER_ID_1, VPN_PACKAGE_NAME)); + pref.setState(AppPreference.STATE_DISCONNECTED); + updates.add(pref); + when(mContext.createPackageContextAsUser(any(), anyInt(), any())).thenReturn(mContext); + when(mContext.getPackageManager()).thenReturn(mPackageManager); + when(mPackageManager.getLaunchIntentForPackage(any())).thenReturn(mVpnIntent); + ArgumentCaptor captor = ArgumentCaptor.forClass(Intent.class); + doNothing().when(mContext).startActivityAsUser(captor.capture(), any()); + mVpnSettings.setShownPreferences(updates); + + mVpnSettings.onPreferenceClick(pref); + + verify(mContext).startActivityAsUser(captor.capture(), any()); + assertThat(TextUtils.equals(captor.getValue().getAction(), + VPN_LAUNCH_INTENT)).isTrue(); + } + + @Test + public void clickAdvancedVpn_VpnConnectedDisconnectDialogDisabled_startsAppLaunchIntent() + throws PackageManager.NameNotFoundException { + Set updates = new ArraySet<>(); + AppPreference pref = + spy(new AppPreference(mContext, USER_ID_1, ADVANCED_VPN_PACKAGE_NAME)); + pref.setState(AppPreference.STATE_CONNECTED); + updates.add(pref); + when(mFakeFeatureFactory.mAdvancedVpnFeatureProvider.isDisconnectDialogEnabled()) + .thenReturn(false); + when(mContext.createPackageContextAsUser(any(), anyInt(), any())).thenReturn(mContext); + when(mContext.getPackageManager()).thenReturn(mPackageManager); + when(mPackageManager.getLaunchIntentForPackage(any())).thenReturn(mAdvancedVpnIntent); + ArgumentCaptor captor = ArgumentCaptor.forClass(Intent.class); + doNothing().when(mContext).startActivityAsUser(captor.capture(), any()); + mVpnSettings.setShownAdvancedPreferences(updates); + + mVpnSettings.onPreferenceClick(pref); + + verify(mContext).startActivityAsUser(captor.capture(), any()); + assertThat(TextUtils.equals(captor.getValue().getAction(), + ADVANCED_VPN_LAUNCH_INTENT)).isTrue(); + } + + @Test + public void clickAdvancedVpn_VpnConnectedDisconnectDialogEnabled_doesNotStartAppLaunchIntent() + throws PackageManager.NameNotFoundException { + Set updates = new ArraySet<>(); + AppPreference pref = + spy(new AppPreference(mContext, USER_ID_1, ADVANCED_VPN_PACKAGE_NAME)); + pref.setState(AppPreference.STATE_CONNECTED); + updates.add(pref); + when(mFakeFeatureFactory.mAdvancedVpnFeatureProvider.isDisconnectDialogEnabled()) + .thenReturn(true); + when(mContext.createPackageContextAsUser(any(), anyInt(), any())).thenReturn(mContext); + when(mContext.getPackageManager()).thenReturn(mPackageManager); + when(mPackageManager.getLaunchIntentForPackage(any())).thenReturn(mAdvancedVpnIntent); + ArgumentCaptor captor = ArgumentCaptor.forClass(Intent.class); + doNothing().when(mContext).startActivityAsUser(captor.capture(), any()); + mVpnSettings.setShownAdvancedPreferences(updates); + + mVpnSettings.onPreferenceClick(pref); + + verify(mContext, never()).startActivityAsUser(any(), any()); + } }