Merge "Notify the user and turn off tethering when the service is disallowed."
This commit is contained in:
committed by
Android (Google) Code Review
commit
be09d8d39b
@@ -3471,6 +3471,13 @@
|
||||
<string name="tethered_notification_title">Tethering or hotspot active</string>
|
||||
<string name="tethered_notification_message">Tap to set up.</string>
|
||||
|
||||
<!-- Strings for tether disabling notification -->
|
||||
<!-- This notification is shown when tethering has been disabled on a user's device.
|
||||
The device is managed by the user's employer. Tethering can't be turned on unless the
|
||||
IT administrator allows it. The noun "admin" is another reference for "IT administrator." -->
|
||||
<string name="disable_tether_notification_title">Tethering is disabled</string>
|
||||
<string name="disable_tether_notification_message">Contact your admin for details</string>
|
||||
|
||||
<!-- Strings for possible PreferenceActivity Back/Next buttons -->
|
||||
<string name="back_button_label">Back</string>
|
||||
<string name="next_button_label">Next</string>
|
||||
|
||||
@@ -1954,6 +1954,8 @@
|
||||
<java-symbol type="string" name="smv_process" />
|
||||
<java-symbol type="string" name="tethered_notification_message" />
|
||||
<java-symbol type="string" name="tethered_notification_title" />
|
||||
<java-symbol type="string" name="disable_tether_notification_message" />
|
||||
<java-symbol type="string" name="disable_tether_notification_title" />
|
||||
<java-symbol type="string" name="adb_debugging_notification_channel_tv" />
|
||||
<java-symbol type="string" name="usb_accessory_notification_title" />
|
||||
<java-symbol type="string" name="usb_mtp_notification_title" />
|
||||
|
||||
@@ -70,6 +70,9 @@ import android.os.Parcel;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ResultReceiver;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.os.UserManagerInternal;
|
||||
import android.os.UserManagerInternal.UserRestrictionsListener;
|
||||
import android.provider.Settings;
|
||||
import android.telephony.CarrierConfigManager;
|
||||
import android.telephony.TelephonyManager;
|
||||
@@ -89,6 +92,7 @@ import com.android.internal.util.MessageUtils;
|
||||
import com.android.internal.util.Protocol;
|
||||
import com.android.internal.util.State;
|
||||
import com.android.internal.util.StateMachine;
|
||||
import com.android.server.LocalServices;
|
||||
import com.android.server.connectivity.tethering.IControlsTethering;
|
||||
import com.android.server.connectivity.tethering.IPv6TetheringCoordinator;
|
||||
import com.android.server.connectivity.tethering.OffloadController;
|
||||
@@ -236,6 +240,13 @@ public class Tethering extends BaseNetworkObserver {
|
||||
filter.addDataScheme("file");
|
||||
mContext.registerReceiver(mStateReceiver, filter, null, smHandler);
|
||||
|
||||
UserManagerInternal userManager = LocalServices.getService(UserManagerInternal.class);
|
||||
|
||||
// this check is useful only for some unit tests; example: ConnectivityServiceTest
|
||||
if (userManager != null) {
|
||||
userManager.addUserRestrictionsListener(new TetheringUserRestrictionListener(this));
|
||||
}
|
||||
|
||||
// load device config info
|
||||
updateConfiguration();
|
||||
}
|
||||
@@ -710,6 +721,11 @@ public class Tethering extends BaseNetworkObserver {
|
||||
}
|
||||
|
||||
private void showTetheredNotification(int id) {
|
||||
showTetheredNotification(id, true);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
protected void showTetheredNotification(int id, boolean tetheringOn) {
|
||||
NotificationManager notificationManager =
|
||||
(NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
if (notificationManager == null) {
|
||||
@@ -746,9 +762,16 @@ public class Tethering extends BaseNetworkObserver {
|
||||
null, UserHandle.CURRENT);
|
||||
|
||||
Resources r = Resources.getSystem();
|
||||
CharSequence title = r.getText(com.android.internal.R.string.tethered_notification_title);
|
||||
CharSequence message = r.getText(com.android.internal.R.string.
|
||||
tethered_notification_message);
|
||||
final CharSequence title;
|
||||
final CharSequence message;
|
||||
|
||||
if (tetheringOn) {
|
||||
title = r.getText(com.android.internal.R.string.tethered_notification_title);
|
||||
message = r.getText(com.android.internal.R.string.tethered_notification_message);
|
||||
} else {
|
||||
title = r.getText(com.android.internal.R.string.disable_tether_notification_title);
|
||||
message = r.getText(com.android.internal.R.string.disable_tether_notification_message);
|
||||
}
|
||||
|
||||
if (mTetheredNotificationBuilder == null) {
|
||||
mTetheredNotificationBuilder =
|
||||
@@ -770,7 +793,8 @@ public class Tethering extends BaseNetworkObserver {
|
||||
mTetheredNotificationBuilder.buildInto(new Notification()), UserHandle.ALL);
|
||||
}
|
||||
|
||||
private void clearTetheredNotification() {
|
||||
@VisibleForTesting
|
||||
protected void clearTetheredNotification() {
|
||||
NotificationManager notificationManager =
|
||||
(NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
if (notificationManager != null && mLastNotificationId != 0) {
|
||||
@@ -874,6 +898,38 @@ public class Tethering extends BaseNetworkObserver {
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
protected static class TetheringUserRestrictionListener implements UserRestrictionsListener {
|
||||
private final Tethering mWrapper;
|
||||
|
||||
public TetheringUserRestrictionListener(Tethering wrapper) {
|
||||
mWrapper = wrapper;
|
||||
}
|
||||
|
||||
public void onUserRestrictionsChanged(int userId,
|
||||
Bundle newRestrictions,
|
||||
Bundle prevRestrictions) {
|
||||
final boolean newlyDisallowed =
|
||||
newRestrictions.getBoolean(UserManager.DISALLOW_CONFIG_TETHERING);
|
||||
final boolean previouslyDisallowed =
|
||||
prevRestrictions.getBoolean(UserManager.DISALLOW_CONFIG_TETHERING);
|
||||
final boolean tetheringDisallowedChanged = (newlyDisallowed != previouslyDisallowed);
|
||||
|
||||
if (!tetheringDisallowedChanged) {
|
||||
return;
|
||||
}
|
||||
|
||||
mWrapper.clearTetheredNotification();
|
||||
final boolean isTetheringActiveOnDevice = (mWrapper.getTetheredIfaces().length != 0);
|
||||
|
||||
if (newlyDisallowed && isTetheringActiveOnDevice) {
|
||||
mWrapper.showTetheredNotification(
|
||||
com.android.internal.R.drawable.stat_sys_tether_general, false);
|
||||
mWrapper.untetherAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void disableWifiIpServingLocked(String ifname, int apState) {
|
||||
mLog.log("Canceling WiFi tethering request - AP_STATE=" + apState);
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@ import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.ContentResolver;
|
||||
@@ -59,12 +60,14 @@ import android.net.NetworkRequest;
|
||||
import android.net.util.SharedLog;
|
||||
import android.net.wifi.WifiConfiguration;
|
||||
import android.net.wifi.WifiManager;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.INetworkManagementService;
|
||||
import android.os.PersistableBundle;
|
||||
import android.os.RemoteException;
|
||||
import android.os.test.TestLooper;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.provider.Settings;
|
||||
import android.support.test.filters.SmallTest;
|
||||
import android.support.test.runner.AndroidJUnit4;
|
||||
@@ -558,6 +561,90 @@ public class TetheringTest {
|
||||
verifyNoMoreInteractions(mNMService);
|
||||
}
|
||||
|
||||
private void userRestrictionsListenerBehaviour(
|
||||
boolean currentDisallow, boolean nextDisallow, String[] activeTetheringIfacesList,
|
||||
int expectedInteractionsWithShowNotification) throws Exception {
|
||||
final int userId = 0;
|
||||
final Bundle currRestrictions = new Bundle();
|
||||
final Bundle newRestrictions = new Bundle();
|
||||
Tethering tethering = mock(Tethering.class);
|
||||
Tethering.TetheringUserRestrictionListener turl =
|
||||
new Tethering.TetheringUserRestrictionListener(tethering);
|
||||
|
||||
currRestrictions.putBoolean(UserManager.DISALLOW_CONFIG_TETHERING, currentDisallow);
|
||||
newRestrictions.putBoolean(UserManager.DISALLOW_CONFIG_TETHERING, nextDisallow);
|
||||
when(tethering.getTetheredIfaces()).thenReturn(activeTetheringIfacesList);
|
||||
|
||||
turl.onUserRestrictionsChanged(userId, newRestrictions, currRestrictions);
|
||||
|
||||
verify(tethering, times(expectedInteractionsWithShowNotification))
|
||||
.showTetheredNotification(anyInt(), eq(false));
|
||||
|
||||
verify(tethering, times(expectedInteractionsWithShowNotification)).untetherAll();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDisallowTetheringWhenNoTetheringInterfaceIsActive() throws Exception {
|
||||
final String[] emptyActiveIfacesList = new String[]{};
|
||||
final boolean currDisallow = false;
|
||||
final boolean nextDisallow = true;
|
||||
final int expectedInteractionsWithShowNotification = 0;
|
||||
|
||||
userRestrictionsListenerBehaviour(currDisallow, nextDisallow, emptyActiveIfacesList,
|
||||
expectedInteractionsWithShowNotification);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDisallowTetheringWhenAtLeastOneTetheringInterfaceIsActive() throws Exception {
|
||||
final String[] nonEmptyActiveIfacesList = new String[]{mTestIfname};
|
||||
final boolean currDisallow = false;
|
||||
final boolean nextDisallow = true;
|
||||
final int expectedInteractionsWithShowNotification = 1;
|
||||
|
||||
userRestrictionsListenerBehaviour(currDisallow, nextDisallow, nonEmptyActiveIfacesList,
|
||||
expectedInteractionsWithShowNotification);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAllowTetheringWhenNoTetheringInterfaceIsActive() throws Exception {
|
||||
final String[] nonEmptyActiveIfacesList = new String[]{};
|
||||
final boolean currDisallow = true;
|
||||
final boolean nextDisallow = false;
|
||||
final int expectedInteractionsWithShowNotification = 0;
|
||||
|
||||
userRestrictionsListenerBehaviour(currDisallow, nextDisallow, nonEmptyActiveIfacesList,
|
||||
expectedInteractionsWithShowNotification);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAllowTetheringWhenAtLeastOneTetheringInterfaceIsActive() throws Exception {
|
||||
final String[] nonEmptyActiveIfacesList = new String[]{mTestIfname};
|
||||
final boolean currDisallow = true;
|
||||
final boolean nextDisallow = false;
|
||||
final int expectedInteractionsWithShowNotification = 0;
|
||||
|
||||
userRestrictionsListenerBehaviour(currDisallow, nextDisallow, nonEmptyActiveIfacesList,
|
||||
expectedInteractionsWithShowNotification);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDisallowTetheringUnchanged() throws Exception {
|
||||
final String[] nonEmptyActiveIfacesList = new String[]{mTestIfname};
|
||||
final int expectedInteractionsWithShowNotification = 0;
|
||||
boolean currDisallow = true;
|
||||
boolean nextDisallow = true;
|
||||
|
||||
userRestrictionsListenerBehaviour(currDisallow, nextDisallow, nonEmptyActiveIfacesList,
|
||||
expectedInteractionsWithShowNotification);
|
||||
|
||||
currDisallow = false;
|
||||
nextDisallow = false;
|
||||
|
||||
userRestrictionsListenerBehaviour(currDisallow, nextDisallow, nonEmptyActiveIfacesList,
|
||||
expectedInteractionsWithShowNotification);
|
||||
}
|
||||
|
||||
|
||||
// TODO: Test that a request for hotspot mode doesn't interfere with an
|
||||
// already operating tethering mode interface.
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user