Show notification for always-on app VPN
This is the same notification as the one shown during legacy lockdown mode, sans the 'reset' button. The notification is only shown during times when VPN has not yet established or has failed, for example during boot or after a crash. Bug: 29123115 Change-Id: If0e2eb4f8fb220a21d6d462363a05869e27c7b6e
This commit is contained in:
@@ -25,9 +25,11 @@ import static org.mockito.Mockito.*;
|
|||||||
|
|
||||||
import android.annotation.UserIdInt;
|
import android.annotation.UserIdInt;
|
||||||
import android.app.AppOpsManager;
|
import android.app.AppOpsManager;
|
||||||
|
import android.app.NotificationManager;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.content.pm.UserInfo;
|
import android.content.pm.UserInfo;
|
||||||
|
import android.net.NetworkInfo.DetailedState;
|
||||||
import android.net.UidRange;
|
import android.net.UidRange;
|
||||||
import android.os.INetworkManagementService;
|
import android.os.INetworkManagementService;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
@@ -43,6 +45,8 @@ import java.util.Arrays;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.mockito.ArgumentCaptor;
|
||||||
|
import org.mockito.InOrder;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.MockitoAnnotations;
|
import org.mockito.MockitoAnnotations;
|
||||||
|
|
||||||
@@ -88,14 +92,18 @@ public class VpnTest extends AndroidTestCase {
|
|||||||
@Mock private PackageManager mPackageManager;
|
@Mock private PackageManager mPackageManager;
|
||||||
@Mock private INetworkManagementService mNetService;
|
@Mock private INetworkManagementService mNetService;
|
||||||
@Mock private AppOpsManager mAppOps;
|
@Mock private AppOpsManager mAppOps;
|
||||||
|
@Mock private NotificationManager mNotificationManager;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
MockitoAnnotations.initMocks(this);
|
MockitoAnnotations.initMocks(this);
|
||||||
when(mContext.getPackageManager()).thenReturn(mPackageManager);
|
when(mContext.getPackageManager()).thenReturn(mPackageManager);
|
||||||
setMockedPackages(mPackages);
|
setMockedPackages(mPackages);
|
||||||
|
when(mContext.getPackageName()).thenReturn(Vpn.class.getPackage().getName());
|
||||||
when(mContext.getSystemService(eq(Context.USER_SERVICE))).thenReturn(mUserManager);
|
when(mContext.getSystemService(eq(Context.USER_SERVICE))).thenReturn(mUserManager);
|
||||||
when(mContext.getSystemService(eq(Context.APP_OPS_SERVICE))).thenReturn(mAppOps);
|
when(mContext.getSystemService(eq(Context.APP_OPS_SERVICE))).thenReturn(mAppOps);
|
||||||
|
when(mContext.getSystemService(eq(Context.NOTIFICATION_SERVICE)))
|
||||||
|
.thenReturn(mNotificationManager);
|
||||||
doNothing().when(mNetService).registerObserver(any());
|
doNothing().when(mNetService).registerObserver(any());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,7 +111,7 @@ public class VpnTest extends AndroidTestCase {
|
|||||||
public void testRestrictedProfilesAreAddedToVpn() {
|
public void testRestrictedProfilesAreAddedToVpn() {
|
||||||
setMockedUsers(primaryUser, secondaryUser, restrictedProfileA, restrictedProfileB);
|
setMockedUsers(primaryUser, secondaryUser, restrictedProfileA, restrictedProfileB);
|
||||||
|
|
||||||
final Vpn vpn = new MockVpn(primaryUser.id);
|
final Vpn vpn = spyVpn(primaryUser.id);
|
||||||
final Set<UidRange> ranges = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
|
final Set<UidRange> ranges = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
|
||||||
null, null);
|
null, null);
|
||||||
|
|
||||||
@@ -117,7 +125,7 @@ public class VpnTest extends AndroidTestCase {
|
|||||||
public void testManagedProfilesAreNotAddedToVpn() {
|
public void testManagedProfilesAreNotAddedToVpn() {
|
||||||
setMockedUsers(primaryUser, managedProfileA);
|
setMockedUsers(primaryUser, managedProfileA);
|
||||||
|
|
||||||
final Vpn vpn = new MockVpn(primaryUser.id);
|
final Vpn vpn = spyVpn(primaryUser.id);
|
||||||
final Set<UidRange> ranges = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
|
final Set<UidRange> ranges = vpn.createUserAndRestrictedProfilesRanges(primaryUser.id,
|
||||||
null, null);
|
null, null);
|
||||||
|
|
||||||
@@ -130,7 +138,7 @@ public class VpnTest extends AndroidTestCase {
|
|||||||
public void testAddUserToVpnOnlyAddsOneUser() {
|
public void testAddUserToVpnOnlyAddsOneUser() {
|
||||||
setMockedUsers(primaryUser, restrictedProfileA, managedProfileA);
|
setMockedUsers(primaryUser, restrictedProfileA, managedProfileA);
|
||||||
|
|
||||||
final Vpn vpn = new MockVpn(primaryUser.id);
|
final Vpn vpn = spyVpn(primaryUser.id);
|
||||||
final Set<UidRange> ranges = new ArraySet<>();
|
final Set<UidRange> ranges = new ArraySet<>();
|
||||||
vpn.addUserToRanges(ranges, primaryUser.id, null, null);
|
vpn.addUserToRanges(ranges, primaryUser.id, null, null);
|
||||||
|
|
||||||
@@ -141,7 +149,7 @@ public class VpnTest extends AndroidTestCase {
|
|||||||
|
|
||||||
@SmallTest
|
@SmallTest
|
||||||
public void testUidWhiteAndBlacklist() throws Exception {
|
public void testUidWhiteAndBlacklist() throws Exception {
|
||||||
final Vpn vpn = new MockVpn(primaryUser.id);
|
final Vpn vpn = spyVpn(primaryUser.id);
|
||||||
final UidRange user = UidRange.createForUser(primaryUser.id);
|
final UidRange user = UidRange.createForUser(primaryUser.id);
|
||||||
final String[] packages = {PKGS[0], PKGS[1], PKGS[2]};
|
final String[] packages = {PKGS[0], PKGS[1], PKGS[2]};
|
||||||
|
|
||||||
@@ -166,15 +174,15 @@ public class VpnTest extends AndroidTestCase {
|
|||||||
|
|
||||||
@SmallTest
|
@SmallTest
|
||||||
public void testLockdownChangingPackage() throws Exception {
|
public void testLockdownChangingPackage() throws Exception {
|
||||||
final MockVpn vpn = new MockVpn(primaryUser.id);
|
final Vpn vpn = spyVpn(primaryUser.id);
|
||||||
final UidRange user = UidRange.createForUser(primaryUser.id);
|
final UidRange user = UidRange.createForUser(primaryUser.id);
|
||||||
|
|
||||||
// Default state.
|
// Default state.
|
||||||
vpn.assertUnblocked(user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
|
assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
|
||||||
|
|
||||||
// Set always-on without lockdown.
|
// Set always-on without lockdown.
|
||||||
assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false));
|
assertTrue(vpn.setAlwaysOnPackage(PKGS[1], false));
|
||||||
vpn.assertUnblocked(user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
|
assertUnblocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
|
||||||
|
|
||||||
// Set always-on with lockdown.
|
// Set always-on with lockdown.
|
||||||
assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true));
|
assertTrue(vpn.setAlwaysOnPackage(PKGS[1], true));
|
||||||
@@ -182,8 +190,8 @@ public class VpnTest extends AndroidTestCase {
|
|||||||
new UidRange(user.start, user.start + PKG_UIDS[1] - 1),
|
new UidRange(user.start, user.start + PKG_UIDS[1] - 1),
|
||||||
new UidRange(user.start + PKG_UIDS[1] + 1, user.stop)
|
new UidRange(user.start + PKG_UIDS[1] + 1, user.stop)
|
||||||
}));
|
}));
|
||||||
vpn.assertBlocked(user.start + PKG_UIDS[0], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
|
assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[2], user.start + PKG_UIDS[3]);
|
||||||
vpn.assertUnblocked(user.start + PKG_UIDS[1]);
|
assertUnblocked(vpn, user.start + PKG_UIDS[1]);
|
||||||
|
|
||||||
// Switch to another app.
|
// Switch to another app.
|
||||||
assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true));
|
assertTrue(vpn.setAlwaysOnPackage(PKGS[3], true));
|
||||||
@@ -195,13 +203,13 @@ public class VpnTest extends AndroidTestCase {
|
|||||||
new UidRange(user.start, user.start + PKG_UIDS[3] - 1),
|
new UidRange(user.start, user.start + PKG_UIDS[3] - 1),
|
||||||
new UidRange(user.start + PKG_UIDS[3] + 1, user.stop)
|
new UidRange(user.start + PKG_UIDS[3] + 1, user.stop)
|
||||||
}));
|
}));
|
||||||
vpn.assertBlocked(user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2]);
|
assertBlocked(vpn, user.start + PKG_UIDS[0], user.start + PKG_UIDS[1], user.start + PKG_UIDS[2]);
|
||||||
vpn.assertUnblocked(user.start + PKG_UIDS[3]);
|
assertUnblocked(vpn, user.start + PKG_UIDS[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SmallTest
|
@SmallTest
|
||||||
public void testLockdownAddingAProfile() throws Exception {
|
public void testLockdownAddingAProfile() throws Exception {
|
||||||
final MockVpn vpn = new MockVpn(primaryUser.id);
|
final Vpn vpn = spyVpn(primaryUser.id);
|
||||||
setMockedUsers(primaryUser);
|
setMockedUsers(primaryUser);
|
||||||
|
|
||||||
// Make a copy of the restricted profile, as we're going to mark it deleted halfway through.
|
// Make a copy of the restricted profile, as we're going to mark it deleted halfway through.
|
||||||
@@ -220,7 +228,7 @@ public class VpnTest extends AndroidTestCase {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
// Verify restricted user isn't affected at first.
|
// Verify restricted user isn't affected at first.
|
||||||
vpn.assertUnblocked(profile.start + PKG_UIDS[0]);
|
assertUnblocked(vpn, profile.start + PKG_UIDS[0]);
|
||||||
|
|
||||||
// Add the restricted user.
|
// Add the restricted user.
|
||||||
setMockedUsers(primaryUser, tempProfile);
|
setMockedUsers(primaryUser, tempProfile);
|
||||||
@@ -239,24 +247,53 @@ public class VpnTest extends AndroidTestCase {
|
|||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
public void testNotificationShownForAlwaysOnApp() {
|
||||||
|
final Vpn vpn = spyVpn(primaryUser.id);
|
||||||
|
final InOrder order = inOrder(vpn);
|
||||||
|
setMockedUsers(primaryUser);
|
||||||
|
|
||||||
|
// Don't show a notification for regular disconnected states.
|
||||||
|
vpn.updateState(DetailedState.DISCONNECTED, TAG);
|
||||||
|
order.verify(vpn).updateAlwaysOnNotificationInternal(false);
|
||||||
|
|
||||||
|
// Start showing a notification for disconnected once always-on.
|
||||||
|
vpn.setAlwaysOnPackage(PKGS[0], false);
|
||||||
|
order.verify(vpn).updateAlwaysOnNotificationInternal(true);
|
||||||
|
|
||||||
|
// Stop showing the notification once connected.
|
||||||
|
vpn.updateState(DetailedState.CONNECTED, TAG);
|
||||||
|
order.verify(vpn).updateAlwaysOnNotificationInternal(false);
|
||||||
|
|
||||||
|
// Show the notification if we disconnect again.
|
||||||
|
vpn.updateState(DetailedState.DISCONNECTED, TAG);
|
||||||
|
order.verify(vpn).updateAlwaysOnNotificationInternal(true);
|
||||||
|
|
||||||
|
// Notification should be cleared after unsetting always-on package.
|
||||||
|
vpn.setAlwaysOnPackage(null, false);
|
||||||
|
order.verify(vpn).updateAlwaysOnNotificationInternal(false);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A subclass of {@link Vpn} with some of the fields pre-mocked.
|
* Mock some methods of vpn object.
|
||||||
*/
|
*/
|
||||||
private class MockVpn extends Vpn {
|
private Vpn spyVpn(@UserIdInt int userId) {
|
||||||
public MockVpn(@UserIdInt int userId) {
|
final Vpn vpn = spy(new Vpn(Looper.myLooper(), mContext, mNetService, userId));
|
||||||
super(Looper.myLooper(), mContext, mNetService, userId);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void assertBlocked(int... uids) {
|
// Block calls to the NotificationManager or PendingIntent#getActivity.
|
||||||
for (int uid : uids) {
|
doNothing().when(vpn).updateAlwaysOnNotificationInternal(anyBoolean());
|
||||||
assertTrue("Uid " + uid + " should be blocked", isBlockingUid(uid));
|
return vpn;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public void assertUnblocked(int... uids) {
|
private static void assertBlocked(Vpn vpn, int... uids) {
|
||||||
for (int uid : uids) {
|
for (int uid : uids) {
|
||||||
assertFalse("Uid " + uid + " should not be blocked", isBlockingUid(uid));
|
assertTrue("Uid " + uid + " should be blocked", vpn.isBlockingUid(uid));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void assertUnblocked(Vpn vpn, int... uids) {
|
||||||
|
for (int uid : uids) {
|
||||||
|
assertFalse("Uid " + uid + " should not be blocked", vpn.isBlockingUid(uid));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user