Merge "VpnSettings stub unit tests"
This commit is contained in:
@@ -15,12 +15,14 @@
|
|||||||
*/
|
*/
|
||||||
package com.android.settings.vpn2;
|
package com.android.settings.vpn2;
|
||||||
|
|
||||||
|
import android.annotation.NonNull;
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.app.AppOpsManager;
|
import android.app.AppOpsManager;
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
import android.app.DialogFragment;
|
import android.app.DialogFragment;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
|
import android.content.pm.ApplicationInfo;
|
||||||
import android.content.pm.PackageInfo;
|
import android.content.pm.PackageInfo;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.pm.PackageManager.NameNotFoundException;
|
import android.content.pm.PackageManager.NameNotFoundException;
|
||||||
@@ -33,12 +35,13 @@ import android.provider.Settings;
|
|||||||
import android.support.v7.preference.Preference;
|
import android.support.v7.preference.Preference;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.android.internal.annotations.VisibleForTesting;
|
||||||
import com.android.internal.logging.MetricsProto.MetricsEvent;
|
import com.android.internal.logging.MetricsProto.MetricsEvent;
|
||||||
import com.android.internal.net.VpnConfig;
|
import com.android.internal.net.VpnConfig;
|
||||||
|
import com.android.internal.util.ArrayUtils;
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.SettingsPreferenceFragment;
|
import com.android.settings.SettingsPreferenceFragment;
|
||||||
import com.android.settings.Utils;
|
import com.android.settings.Utils;
|
||||||
import com.android.settingslib.RestrictedLockUtils;
|
|
||||||
import com.android.settingslib.RestrictedSwitchPreference;
|
import com.android.settingslib.RestrictedSwitchPreference;
|
||||||
import com.android.settingslib.RestrictedPreference;
|
import com.android.settingslib.RestrictedPreference;
|
||||||
|
|
||||||
@@ -57,13 +60,11 @@ public class AppManagementFragment extends SettingsPreferenceFragment
|
|||||||
private static final String KEY_ALWAYS_ON_VPN = "always_on_vpn";
|
private static final String KEY_ALWAYS_ON_VPN = "always_on_vpn";
|
||||||
private static final String KEY_FORGET_VPN = "forget_vpn";
|
private static final String KEY_FORGET_VPN = "forget_vpn";
|
||||||
|
|
||||||
private AppOpsManager mAppOpsManager;
|
|
||||||
private PackageManager mPackageManager;
|
private PackageManager mPackageManager;
|
||||||
private ConnectivityManager mConnectivityManager;
|
private ConnectivityManager mConnectivityManager;
|
||||||
|
|
||||||
// VPN app info
|
// VPN app info
|
||||||
private final int mUserId = UserHandle.myUserId();
|
private final int mUserId = UserHandle.myUserId();
|
||||||
private int mPackageUid;
|
|
||||||
private String mPackageName;
|
private String mPackageName;
|
||||||
private PackageInfo mPackageInfo;
|
private PackageInfo mPackageInfo;
|
||||||
private String mVpnLabel;
|
private String mVpnLabel;
|
||||||
@@ -105,7 +106,6 @@ public class AppManagementFragment extends SettingsPreferenceFragment
|
|||||||
addPreferencesFromResource(R.xml.vpn_app_management);
|
addPreferencesFromResource(R.xml.vpn_app_management);
|
||||||
|
|
||||||
mPackageManager = getContext().getPackageManager();
|
mPackageManager = getContext().getPackageManager();
|
||||||
mAppOpsManager = getContext().getSystemService(AppOpsManager.class);
|
|
||||||
mConnectivityManager = getContext().getSystemService(ConnectivityManager.class);
|
mConnectivityManager = getContext().getSystemService(ConnectivityManager.class);
|
||||||
|
|
||||||
mPreferenceVersion = findPreference(KEY_VERSION);
|
mPreferenceVersion = findPreference(KEY_VERSION);
|
||||||
@@ -199,20 +199,18 @@ public class AppManagementFragment extends SettingsPreferenceFragment
|
|||||||
isEnabled ? mPackageName : null, /* lockdownEnabled */ false);
|
isEnabled ? mPackageName : null, /* lockdownEnabled */ false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean checkTargetVersion() {
|
@VisibleForTesting
|
||||||
if (mPackageInfo == null || mPackageInfo.applicationInfo == null) {
|
static boolean isAlwaysOnSupportedByApp(@NonNull ApplicationInfo appInfo) {
|
||||||
return true;
|
final int targetSdk = appInfo.targetSdkVersion;
|
||||||
}
|
if (targetSdk < Build.VERSION_CODES.N) {
|
||||||
final int targetSdk = mPackageInfo.applicationInfo.targetSdkVersion;
|
|
||||||
if (targetSdk >= Build.VERSION_CODES.N) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (Log.isLoggable(TAG, Log.DEBUG)) {
|
if (Log.isLoggable(TAG, Log.DEBUG)) {
|
||||||
Log.d(TAG, "Package " + mPackageName + " targets SDK version " + targetSdk + "; must"
|
Log.d(TAG, "Package " + appInfo.packageName + " targets SDK version: " + targetSdk
|
||||||
+ " target at least " + Build.VERSION_CODES.N + " to use always-on.");
|
+ "; must target at least " + Build.VERSION_CODES.N + " to use always-on.");
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private void updateUI() {
|
private void updateUI() {
|
||||||
if (isAdded()) {
|
if (isAdded()) {
|
||||||
@@ -228,7 +226,7 @@ public class AppManagementFragment extends SettingsPreferenceFragment
|
|||||||
mPreferenceForget.checkRestrictionAndSetDisabled(UserManager.DISALLOW_CONFIG_VPN,
|
mPreferenceForget.checkRestrictionAndSetDisabled(UserManager.DISALLOW_CONFIG_VPN,
|
||||||
mUserId);
|
mUserId);
|
||||||
|
|
||||||
if (checkTargetVersion()) {
|
if (isAlwaysOnSupportedByApp(mPackageInfo.applicationInfo)) {
|
||||||
// setSummary doesn't override the admin message when user restriction is applied
|
// setSummary doesn't override the admin message when user restriction is applied
|
||||||
mPreferenceAlwaysOn.setSummary(null);
|
mPreferenceAlwaysOn.setSummary(null);
|
||||||
// setEnabled is not required here, as checkRestrictionAndSetDisabled
|
// setEnabled is not required here, as checkRestrictionAndSetDisabled
|
||||||
@@ -266,7 +264,6 @@ public class AppManagementFragment extends SettingsPreferenceFragment
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
mPackageUid = mPackageManager.getPackageUid(mPackageName, /* PackageInfoFlags */ 0);
|
|
||||||
mPackageInfo = mPackageManager.getPackageInfo(mPackageName, /* PackageInfoFlags */ 0);
|
mPackageInfo = mPackageManager.getPackageInfo(mPackageName, /* PackageInfoFlags */ 0);
|
||||||
mVpnLabel = VpnConfig.getVpnLabel(getPrefContext(), mPackageName).toString();
|
mVpnLabel = VpnConfig.getVpnLabel(getPrefContext(), mPackageName).toString();
|
||||||
} catch (NameNotFoundException nnfe) {
|
} catch (NameNotFoundException nnfe) {
|
||||||
@@ -274,7 +271,11 @@ public class AppManagementFragment extends SettingsPreferenceFragment
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isVpnActivated()) {
|
if (mPackageInfo.applicationInfo == null) {
|
||||||
|
Log.e(TAG, "package does not include an application");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!appHasVpnPermission(getContext(), mPackageInfo.applicationInfo)) {
|
||||||
Log.e(TAG, "package didn't register VPN profile");
|
Log.e(TAG, "package didn't register VPN profile");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -282,10 +283,13 @@ public class AppManagementFragment extends SettingsPreferenceFragment
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isVpnActivated() {
|
@VisibleForTesting
|
||||||
final List<AppOpsManager.PackageOps> apps = mAppOpsManager.getOpsForPackage(mPackageUid,
|
static boolean appHasVpnPermission(Context context, @NonNull ApplicationInfo application) {
|
||||||
mPackageName, new int[]{OP_ACTIVATE_VPN});
|
final AppOpsManager service =
|
||||||
return apps != null && apps.size() > 0 && apps.get(0) != null;
|
(AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
|
||||||
|
final List<AppOpsManager.PackageOps> ops = service.getOpsForPackage(application.uid,
|
||||||
|
application.packageName, new int[]{OP_ACTIVATE_VPN});
|
||||||
|
return !ArrayUtils.isEmpty(ops);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isLegacyVpnLockDownOrAnotherPackageAlwaysOn() {
|
private boolean isLegacyVpnLockDownOrAnotherPackageAlwaysOn() {
|
||||||
|
104
tests/unit/src/com/android/settings/vpn2/AppSettingsTest.java
Normal file
104
tests/unit/src/com/android/settings/vpn2/AppSettingsTest.java
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 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.vpn2;
|
||||||
|
|
||||||
|
import static com.android.settings.vpn2.AppManagementFragment.isAlwaysOnSupportedByApp;
|
||||||
|
import static com.android.settings.vpn2.AppManagementFragment.appHasVpnPermission;
|
||||||
|
import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
|
import android.app.AppOpsManager;
|
||||||
|
import android.content.pm.ApplicationInfo;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.os.Process;
|
||||||
|
import android.test.AndroidTestCase;
|
||||||
|
import android.test.suitebuilder.annotation.SmallTest;
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
|
public class AppSettingsTest extends AndroidTestCase {
|
||||||
|
private static final String TAG = AppSettingsTest.class.getSimpleName();
|
||||||
|
|
||||||
|
@Mock private Context mContext;
|
||||||
|
@Mock private AppOpsManager mAppOps;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setUp() throws Exception {
|
||||||
|
MockitoAnnotations.initMocks(this);
|
||||||
|
when(mContext.getSystemService(eq(Context.APP_OPS_SERVICE))).thenReturn(mAppOps);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
public void testAlwaysOnVersionRestriction() {
|
||||||
|
ApplicationInfo mockApp = createMockApp();
|
||||||
|
|
||||||
|
// API 23 (MNC) = not supported
|
||||||
|
mockApp.targetSdkVersion = Build.VERSION_CODES.M;
|
||||||
|
assertFalse(isAlwaysOnSupportedByApp(mockApp));
|
||||||
|
|
||||||
|
// API 24 (NYC) = supported
|
||||||
|
mockApp.targetSdkVersion = Build.VERSION_CODES.N;
|
||||||
|
assertTrue(isAlwaysOnSupportedByApp(mockApp));
|
||||||
|
|
||||||
|
// API 25 (NYC MR1) = supported
|
||||||
|
mockApp.targetSdkVersion = Build.VERSION_CODES.N_MR1;
|
||||||
|
assertTrue(isAlwaysOnSupportedByApp(mockApp));
|
||||||
|
}
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
public void testAppOpsRequiredToOpenFragment() {
|
||||||
|
ApplicationInfo mockApp = createMockApp();
|
||||||
|
|
||||||
|
final AppOpsManager.PackageOps[] blankOps = {
|
||||||
|
new AppOpsManager.PackageOps(mockApp.packageName, mockApp.uid, new ArrayList<>()),
|
||||||
|
new AppOpsManager.PackageOps(mockApp.packageName, mockApp.uid, new ArrayList<>())
|
||||||
|
};
|
||||||
|
|
||||||
|
// List with one package op
|
||||||
|
when(mAppOps.getOpsForPackage(eq(mockApp.uid), eq(mockApp.packageName), any()))
|
||||||
|
.thenReturn(Arrays.asList(new AppOpsManager.PackageOps[] {blankOps[0]}));
|
||||||
|
assertTrue(appHasVpnPermission(mContext, mockApp));
|
||||||
|
|
||||||
|
// List with more than one package op
|
||||||
|
when(mAppOps.getOpsForPackage(eq(mockApp.uid), eq(mockApp.packageName), any()))
|
||||||
|
.thenReturn(Arrays.asList(blankOps));
|
||||||
|
assertTrue(appHasVpnPermission(mContext, mockApp));
|
||||||
|
|
||||||
|
// Empty list
|
||||||
|
when(mAppOps.getOpsForPackage(eq(mockApp.uid), eq(mockApp.packageName), any()))
|
||||||
|
.thenReturn(Collections.emptyList());
|
||||||
|
assertFalse(appHasVpnPermission(mContext, mockApp));
|
||||||
|
|
||||||
|
// Null list (may be returned in place of an empty list)
|
||||||
|
when(mAppOps.getOpsForPackage(eq(mockApp.uid), eq(mockApp.packageName), any()))
|
||||||
|
.thenReturn(null);
|
||||||
|
assertFalse(appHasVpnPermission(mContext, mockApp));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ApplicationInfo createMockApp() {
|
||||||
|
final ApplicationInfo app = new ApplicationInfo();
|
||||||
|
app.packageName = "com.example.mockvpn";
|
||||||
|
app.uid = Process.FIRST_APPLICATION_UID;
|
||||||
|
return app;
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user