Merge "[TNU04] Add tethering restricted notification" am: 255565e839
Change-Id: I6276b1a2d55c536bf7b9f03407c967636b521870
This commit is contained in:
@@ -303,7 +303,8 @@ public class Tethering {
|
|||||||
|
|
||||||
final UserManager userManager = (UserManager) mContext.getSystemService(
|
final UserManager userManager = (UserManager) mContext.getSystemService(
|
||||||
Context.USER_SERVICE);
|
Context.USER_SERVICE);
|
||||||
mTetheringRestriction = new UserRestrictionActionListener(userManager, this);
|
mTetheringRestriction = new UserRestrictionActionListener(
|
||||||
|
userManager, this, mNotificationUpdater);
|
||||||
mExecutor = new TetheringThreadExecutor(mHandler);
|
mExecutor = new TetheringThreadExecutor(mHandler);
|
||||||
mActiveDataSubIdListener = new ActiveDataSubIdListener(mExecutor);
|
mActiveDataSubIdListener = new ActiveDataSubIdListener(mExecutor);
|
||||||
|
|
||||||
@@ -1000,11 +1001,14 @@ public class Tethering {
|
|||||||
protected static class UserRestrictionActionListener {
|
protected static class UserRestrictionActionListener {
|
||||||
private final UserManager mUserManager;
|
private final UserManager mUserManager;
|
||||||
private final Tethering mWrapper;
|
private final Tethering mWrapper;
|
||||||
|
private final TetheringNotificationUpdater mNotificationUpdater;
|
||||||
public boolean mDisallowTethering;
|
public boolean mDisallowTethering;
|
||||||
|
|
||||||
public UserRestrictionActionListener(UserManager um, Tethering wrapper) {
|
public UserRestrictionActionListener(@NonNull UserManager um, @NonNull Tethering wrapper,
|
||||||
|
@NonNull TetheringNotificationUpdater updater) {
|
||||||
mUserManager = um;
|
mUserManager = um;
|
||||||
mWrapper = wrapper;
|
mWrapper = wrapper;
|
||||||
|
mNotificationUpdater = updater;
|
||||||
mDisallowTethering = false;
|
mDisallowTethering = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1023,13 +1027,21 @@ public class Tethering {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Add user restrictions notification.
|
if (!newlyDisallowed) {
|
||||||
final boolean isTetheringActiveOnDevice = (mWrapper.getTetheredIfaces().length != 0);
|
// Clear the restricted notification when user is allowed to have tethering
|
||||||
|
// function.
|
||||||
if (newlyDisallowed && isTetheringActiveOnDevice) {
|
mNotificationUpdater.tetheringRestrictionLifted();
|
||||||
mWrapper.untetherAll();
|
return;
|
||||||
// TODO(b/148139325): send tetheringSupported on restriction change
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Restricted notification is shown when tethering function is disallowed on
|
||||||
|
// user's device.
|
||||||
|
mNotificationUpdater.notifyTetheringDisabledByRestriction();
|
||||||
|
|
||||||
|
// Untether from all downstreams since tethering is disallowed.
|
||||||
|
mWrapper.untetherAll();
|
||||||
|
|
||||||
|
// TODO(b/148139325): send tetheringSupported on restriction change
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import android.util.SparseArray;
|
|||||||
|
|
||||||
import androidx.annotation.ArrayRes;
|
import androidx.annotation.ArrayRes;
|
||||||
import androidx.annotation.DrawableRes;
|
import androidx.annotation.DrawableRes;
|
||||||
|
import androidx.annotation.IntDef;
|
||||||
import androidx.annotation.IntRange;
|
import androidx.annotation.IntRange;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
@@ -61,7 +62,9 @@ public class TetheringNotificationUpdater {
|
|||||||
private static final boolean NOTIFY_DONE = true;
|
private static final boolean NOTIFY_DONE = true;
|
||||||
private static final boolean NO_NOTIFY = false;
|
private static final boolean NO_NOTIFY = false;
|
||||||
// Id to update and cancel tethering notification. Must be unique within the tethering app.
|
// Id to update and cancel tethering notification. Must be unique within the tethering app.
|
||||||
private static final int NOTIFY_ID = 20191115;
|
private static final int ENABLE_NOTIFICATION_ID = 1000;
|
||||||
|
// Id to update and cancel restricted notification. Must be unique within the tethering app.
|
||||||
|
private static final int RESTRICTED_NOTIFICATION_ID = 1001;
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
static final int NO_ICON_ID = 0;
|
static final int NO_ICON_ID = 0;
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
@@ -85,6 +88,9 @@ public class TetheringNotificationUpdater {
|
|||||||
// INVALID_SUBSCRIPTION_ID.
|
// INVALID_SUBSCRIPTION_ID.
|
||||||
private volatile int mActiveDataSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
|
private volatile int mActiveDataSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
|
||||||
|
|
||||||
|
@IntDef({ENABLE_NOTIFICATION_ID, RESTRICTED_NOTIFICATION_ID})
|
||||||
|
@interface NotificationId {}
|
||||||
|
|
||||||
public TetheringNotificationUpdater(@NonNull final Context context) {
|
public TetheringNotificationUpdater(@NonNull final Context context) {
|
||||||
mContext = context;
|
mContext = context;
|
||||||
mNotificationManager = (NotificationManager) context.createContextAsUser(UserHandle.ALL, 0)
|
mNotificationManager = (NotificationManager) context.createContextAsUser(UserHandle.ALL, 0)
|
||||||
@@ -100,14 +106,14 @@ public class TetheringNotificationUpdater {
|
|||||||
public void onDownstreamChanged(@IntRange(from = 0, to = 7) final int downstreamTypesMask) {
|
public void onDownstreamChanged(@IntRange(from = 0, to = 7) final int downstreamTypesMask) {
|
||||||
if (mDownstreamTypesMask == downstreamTypesMask) return;
|
if (mDownstreamTypesMask == downstreamTypesMask) return;
|
||||||
mDownstreamTypesMask = downstreamTypesMask;
|
mDownstreamTypesMask = downstreamTypesMask;
|
||||||
updateNotification();
|
updateEnableNotification();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Called when active data subscription id changed */
|
/** Called when active data subscription id changed */
|
||||||
public void onActiveDataSubscriptionIdChanged(final int subId) {
|
public void onActiveDataSubscriptionIdChanged(final int subId) {
|
||||||
if (mActiveDataSubId == subId) return;
|
if (mActiveDataSubId == subId) return;
|
||||||
mActiveDataSubId = subId;
|
mActiveDataSubId = subId;
|
||||||
updateNotification();
|
updateEnableNotification();
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
@@ -115,16 +121,31 @@ public class TetheringNotificationUpdater {
|
|||||||
return SubscriptionManager.getResourcesForSubId(c, subId);
|
return SubscriptionManager.getResourcesForSubId(c, subId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateNotification() {
|
private void updateEnableNotification() {
|
||||||
final boolean tetheringInactive = mDownstreamTypesMask <= DOWNSTREAM_NONE;
|
final boolean tetheringInactive = mDownstreamTypesMask <= DOWNSTREAM_NONE;
|
||||||
|
|
||||||
if (tetheringInactive || setupNotification() == NO_NOTIFY) {
|
if (tetheringInactive || setupNotification() == NO_NOTIFY) {
|
||||||
clearNotification();
|
clearNotification(ENABLE_NOTIFICATION_ID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void clearNotification() {
|
@VisibleForTesting
|
||||||
mNotificationManager.cancel(null /* tag */, NOTIFY_ID);
|
void tetheringRestrictionLifted() {
|
||||||
|
clearNotification(RESTRICTED_NOTIFICATION_ID);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clearNotification(@NotificationId final int id) {
|
||||||
|
mNotificationManager.cancel(null /* tag */, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
void notifyTetheringDisabledByRestriction() {
|
||||||
|
final Resources res = getResourcesForSubId(mContext, mActiveDataSubId);
|
||||||
|
final String title = res.getString(R.string.disable_tether_notification_title);
|
||||||
|
final String message = res.getString(R.string.disable_tether_notification_message);
|
||||||
|
|
||||||
|
showNotification(R.drawable.stat_sys_tether_general, title, message,
|
||||||
|
RESTRICTED_NOTIFICATION_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -195,12 +216,12 @@ public class TetheringNotificationUpdater {
|
|||||||
final String title = res.getString(R.string.tethering_notification_title);
|
final String title = res.getString(R.string.tethering_notification_title);
|
||||||
final String message = res.getString(R.string.tethering_notification_message);
|
final String message = res.getString(R.string.tethering_notification_message);
|
||||||
|
|
||||||
showNotification(iconId, title, message);
|
showNotification(iconId, title, message, ENABLE_NOTIFICATION_ID);
|
||||||
return NOTIFY_DONE;
|
return NOTIFY_DONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showNotification(@DrawableRes final int iconId, @NonNull final String title,
|
private void showNotification(@DrawableRes final int iconId, @NonNull final String title,
|
||||||
@NonNull final String message) {
|
@NonNull final String message, @NotificationId final int id) {
|
||||||
final Intent intent = new Intent(Settings.ACTION_TETHER_SETTINGS);
|
final Intent intent = new Intent(Settings.ACTION_TETHER_SETTINGS);
|
||||||
final PendingIntent pi = PendingIntent.getActivity(
|
final PendingIntent pi = PendingIntent.getActivity(
|
||||||
mContext.createContextAsUser(UserHandle.CURRENT, 0),
|
mContext.createContextAsUser(UserHandle.CURRENT, 0),
|
||||||
@@ -218,6 +239,6 @@ public class TetheringNotificationUpdater {
|
|||||||
.setContentIntent(pi)
|
.setContentIntent(pi)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
mNotificationManager.notify(null /* tag */, NOTIFY_ID, notification);
|
mNotificationManager.notify(null /* tag */, id, notification);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ import android.net.ConnectivityManager.TETHERING_USB
|
|||||||
import android.net.ConnectivityManager.TETHERING_WIFI
|
import android.net.ConnectivityManager.TETHERING_WIFI
|
||||||
import android.os.UserHandle
|
import android.os.UserHandle
|
||||||
import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
|
import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
|
||||||
import androidx.test.InstrumentationRegistry
|
import androidx.test.platform.app.InstrumentationRegistry
|
||||||
import androidx.test.filters.SmallTest
|
import androidx.test.filters.SmallTest
|
||||||
import androidx.test.runner.AndroidJUnit4
|
import androidx.test.runner.AndroidJUnit4
|
||||||
import com.android.internal.util.test.BroadcastInterceptingContext
|
import com.android.internal.util.test.BroadcastInterceptingContext
|
||||||
@@ -114,7 +114,7 @@ class TetheringNotificationUpdaterTest {
|
|||||||
@Before
|
@Before
|
||||||
fun setUp() {
|
fun setUp() {
|
||||||
MockitoAnnotations.initMocks(this)
|
MockitoAnnotations.initMocks(this)
|
||||||
val context = TestContext(InstrumentationRegistry.getContext())
|
val context = TestContext(InstrumentationRegistry.getInstrumentation().context)
|
||||||
doReturn(notificationManager).`when`(mockContext)
|
doReturn(notificationManager).`when`(mockContext)
|
||||||
.getSystemService(Context.NOTIFICATION_SERVICE)
|
.getSystemService(Context.NOTIFICATION_SERVICE)
|
||||||
notificationUpdater = WrappedNotificationUpdater(context)
|
notificationUpdater = WrappedNotificationUpdater(context)
|
||||||
@@ -128,7 +128,8 @@ class TetheringNotificationUpdaterTest {
|
|||||||
verify(notificationManager, never()).cancel(any(), anyInt())
|
verify(notificationManager, never()).cancel(any(), anyInt())
|
||||||
|
|
||||||
val notificationCaptor = ArgumentCaptor.forClass(Notification::class.java)
|
val notificationCaptor = ArgumentCaptor.forClass(Notification::class.java)
|
||||||
verify(notificationManager, times(1)).notify(any(), anyInt(), notificationCaptor.capture())
|
verify(notificationManager, times(1))
|
||||||
|
.notify(any(), anyInt(), notificationCaptor.capture())
|
||||||
|
|
||||||
val notification = notificationCaptor.getValue()
|
val notification = notificationCaptor.getValue()
|
||||||
assertEquals(iconId, notification.smallIcon.resId)
|
assertEquals(iconId, notification.smallIcon.resId)
|
||||||
@@ -224,4 +225,38 @@ class TetheringNotificationUpdaterTest {
|
|||||||
assertEquals(WIFI_MASK or USB_MASK,
|
assertEquals(WIFI_MASK or USB_MASK,
|
||||||
notificationUpdater.getDownstreamTypesMask("1|2|USB|WIFI|BLUETOOTH||"))
|
notificationUpdater.getDownstreamTypesMask("1|2|USB|WIFI|BLUETOOTH||"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testSetupRestrictedNotification() {
|
||||||
|
val title = InstrumentationRegistry.getInstrumentation().context.resources
|
||||||
|
.getString(R.string.disable_tether_notification_title)
|
||||||
|
val message = InstrumentationRegistry.getInstrumentation().context.resources
|
||||||
|
.getString(R.string.disable_tether_notification_message)
|
||||||
|
val disallowTitle = "Tether function is disallowed"
|
||||||
|
val disallowMessage = "Please contact your admin"
|
||||||
|
doReturn(title).`when`(defaultResources)
|
||||||
|
.getString(R.string.disable_tether_notification_title)
|
||||||
|
doReturn(message).`when`(defaultResources)
|
||||||
|
.getString(R.string.disable_tether_notification_message)
|
||||||
|
doReturn(disallowTitle).`when`(testResources)
|
||||||
|
.getString(R.string.disable_tether_notification_title)
|
||||||
|
doReturn(disallowMessage).`when`(testResources)
|
||||||
|
.getString(R.string.disable_tether_notification_message)
|
||||||
|
|
||||||
|
// User restrictions on. Show restricted notification.
|
||||||
|
notificationUpdater.notifyTetheringDisabledByRestriction()
|
||||||
|
verifyNotification(R.drawable.stat_sys_tether_general, title, message)
|
||||||
|
|
||||||
|
// User restrictions off. Clear notification.
|
||||||
|
notificationUpdater.tetheringRestrictionLifted()
|
||||||
|
verifyNoNotification()
|
||||||
|
|
||||||
|
// Set test sub id. No notification.
|
||||||
|
notificationUpdater.onActiveDataSubscriptionIdChanged(TEST_SUBID)
|
||||||
|
verifyNoNotification()
|
||||||
|
|
||||||
|
// User restrictions on again. Show restricted notification with test resource.
|
||||||
|
notificationUpdater.notifyTetheringDisabledByRestriction()
|
||||||
|
verifyNotification(R.drawable.stat_sys_tether_general, disallowTitle, disallowMessage)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1072,13 +1072,15 @@ public class TetheringTest {
|
|||||||
when(mUserManager.getUserRestrictions()).thenReturn(newRestrictions);
|
when(mUserManager.getUserRestrictions()).thenReturn(newRestrictions);
|
||||||
|
|
||||||
final Tethering.UserRestrictionActionListener ural =
|
final Tethering.UserRestrictionActionListener ural =
|
||||||
new Tethering.UserRestrictionActionListener(mUserManager, mockTethering);
|
new Tethering.UserRestrictionActionListener(
|
||||||
|
mUserManager, mockTethering, mNotificationUpdater);
|
||||||
ural.mDisallowTethering = currentDisallow;
|
ural.mDisallowTethering = currentDisallow;
|
||||||
|
|
||||||
ural.onUserRestrictionsChanged();
|
ural.onUserRestrictionsChanged();
|
||||||
|
|
||||||
verify(mockTethering, times(expectedInteractionsWithShowNotification))
|
verify(mNotificationUpdater, times(expectedInteractionsWithShowNotification))
|
||||||
.untetherAll();
|
.notifyTetheringDisabledByRestriction();
|
||||||
|
verify(mockTethering, times(expectedInteractionsWithShowNotification)).untetherAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -1086,7 +1088,7 @@ public class TetheringTest {
|
|||||||
final String[] emptyActiveIfacesList = new String[]{};
|
final String[] emptyActiveIfacesList = new String[]{};
|
||||||
final boolean currDisallow = false;
|
final boolean currDisallow = false;
|
||||||
final boolean nextDisallow = true;
|
final boolean nextDisallow = true;
|
||||||
final int expectedInteractionsWithShowNotification = 0;
|
final int expectedInteractionsWithShowNotification = 1;
|
||||||
|
|
||||||
runUserRestrictionsChange(currDisallow, nextDisallow, emptyActiveIfacesList,
|
runUserRestrictionsChange(currDisallow, nextDisallow, emptyActiveIfacesList,
|
||||||
expectedInteractionsWithShowNotification);
|
expectedInteractionsWithShowNotification);
|
||||||
|
|||||||
Reference in New Issue
Block a user