resolve merge conflicts of b62007a to master
Change-Id: Ib09134090aa135d88bb807034b262a23c8b40e5f
This commit is contained in:
@@ -342,6 +342,15 @@ public class ConnectivityManager {
|
|||||||
*/
|
*/
|
||||||
public static final String ACTION_PROMPT_UNVALIDATED = "android.net.conn.PROMPT_UNVALIDATED";
|
public static final String ACTION_PROMPT_UNVALIDATED = "android.net.conn.PROMPT_UNVALIDATED";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Action used to display a dialog that asks the user whether to avoid a network that is no
|
||||||
|
* longer validated. This intent is used to start the dialog in settings via startActivity.
|
||||||
|
*
|
||||||
|
* @hide
|
||||||
|
*/
|
||||||
|
public static final String ACTION_PROMPT_LOST_VALIDATION =
|
||||||
|
"android.net.conn.PROMPT_LOST_VALIDATION";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invalid tethering type.
|
* Invalid tethering type.
|
||||||
* @see #startTethering(int, OnStartTetheringCallback, boolean)
|
* @see #startTethering(int, OnStartTetheringCallback, boolean)
|
||||||
|
|||||||
@@ -398,6 +398,11 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
private static final int EVENT_REQUEST_LINKPROPERTIES = 32;
|
private static final int EVENT_REQUEST_LINKPROPERTIES = 32;
|
||||||
private static final int EVENT_REQUEST_NETCAPABILITIES = 33;
|
private static final int EVENT_REQUEST_NETCAPABILITIES = 33;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used internally to (re)configure avoid bad wifi setting.
|
||||||
|
*/
|
||||||
|
private static final int EVENT_CONFIGURE_NETWORK_AVOID_BAD_WIFI = 34;
|
||||||
|
|
||||||
/** Handler thread used for both of the handlers below. */
|
/** Handler thread used for both of the handlers below. */
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
protected final HandlerThread mHandlerThread;
|
protected final HandlerThread mHandlerThread;
|
||||||
@@ -902,6 +907,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
mSettingsObserver.observe(
|
mSettingsObserver.observe(
|
||||||
Settings.Global.getUriFor(Settings.Global.MOBILE_DATA_ALWAYS_ON),
|
Settings.Global.getUriFor(Settings.Global.MOBILE_DATA_ALWAYS_ON),
|
||||||
EVENT_CONFIGURE_MOBILE_DATA_ALWAYS_ON);
|
EVENT_CONFIGURE_MOBILE_DATA_ALWAYS_ON);
|
||||||
|
|
||||||
|
// Watch for whether to automatically switch away from wifi networks that lose Internet
|
||||||
|
// access.
|
||||||
|
mSettingsObserver.observe(
|
||||||
|
Settings.Global.getUriFor(Settings.Global.NETWORK_AVOID_BAD_WIFI),
|
||||||
|
EVENT_CONFIGURE_NETWORK_AVOID_BAD_WIFI);
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized int nextNetworkRequestId() {
|
private synchronized int nextNetworkRequestId() {
|
||||||
@@ -2209,6 +2220,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
if (nai != null) {
|
if (nai != null) {
|
||||||
final boolean valid =
|
final boolean valid =
|
||||||
(msg.arg1 == NetworkMonitor.NETWORK_TEST_RESULT_VALID);
|
(msg.arg1 == NetworkMonitor.NETWORK_TEST_RESULT_VALID);
|
||||||
|
final boolean wasValidated = nai.lastValidated;
|
||||||
if (DBG) log(nai.name() + " validation " + (valid ? "passed" : "failed") +
|
if (DBG) log(nai.name() + " validation " + (valid ? "passed" : "failed") +
|
||||||
(msg.obj == null ? "" : " with redirect to " + (String)msg.obj));
|
(msg.obj == null ? "" : " with redirect to " + (String)msg.obj));
|
||||||
if (valid != nai.lastValidated) {
|
if (valid != nai.lastValidated) {
|
||||||
@@ -2227,6 +2239,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
NetworkAgent.CMD_REPORT_NETWORK_STATUS,
|
NetworkAgent.CMD_REPORT_NETWORK_STATUS,
|
||||||
(valid ? NetworkAgent.VALID_NETWORK : NetworkAgent.INVALID_NETWORK),
|
(valid ? NetworkAgent.VALID_NETWORK : NetworkAgent.INVALID_NETWORK),
|
||||||
0, redirectUrlBundle);
|
0, redirectUrlBundle);
|
||||||
|
if (wasValidated && !nai.lastValidated) {
|
||||||
|
handleNetworkUnvalidated(nai);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -2745,6 +2760,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public boolean avoidBadWifi() {
|
public boolean avoidBadWifi() {
|
||||||
|
// There are two modes: either we always automatically avoid unvalidated wifi, or we show a
|
||||||
|
// dialog and don't switch to it. The behaviour is controlled by the NETWORK_AVOID_BAD_WIFI
|
||||||
|
// setting. If the setting has no value, then the value is taken from the config value,
|
||||||
|
// which can be changed via OEM/carrier overlays.
|
||||||
int defaultAvoidBadWifi =
|
int defaultAvoidBadWifi =
|
||||||
mContext.getResources().getInteger(R.integer.config_networkAvoidBadWifi);
|
mContext.getResources().getInteger(R.integer.config_networkAvoidBadWifi);
|
||||||
int avoid = Settings.Global.getInt(mContext.getContentResolver(),
|
int avoid = Settings.Global.getInt(mContext.getContentResolver(),
|
||||||
@@ -2752,6 +2771,31 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
return avoid == 1;
|
return avoid == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void showValidationNotification(NetworkAgentInfo nai, NotificationType type) {
|
||||||
|
final String action;
|
||||||
|
switch (type) {
|
||||||
|
case NO_INTERNET:
|
||||||
|
action = ConnectivityManager.ACTION_PROMPT_UNVALIDATED;
|
||||||
|
break;
|
||||||
|
case LOST_INTERNET:
|
||||||
|
action = ConnectivityManager.ACTION_PROMPT_LOST_VALIDATION;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Slog.wtf(TAG, "Unknown notification type " + type);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Intent intent = new Intent(action);
|
||||||
|
intent.setData(Uri.fromParts("netId", Integer.toString(nai.network.netId), null));
|
||||||
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
|
intent.setClassName("com.android.settings",
|
||||||
|
"com.android.settings.wifi.WifiNoInternetDialog");
|
||||||
|
|
||||||
|
PendingIntent pendingIntent = PendingIntent.getActivityAsUser(
|
||||||
|
mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT);
|
||||||
|
mNotifier.showNotification(nai.network.netId, type, nai, null, pendingIntent, true);
|
||||||
|
}
|
||||||
|
|
||||||
private void handlePromptUnvalidated(Network network) {
|
private void handlePromptUnvalidated(Network network) {
|
||||||
if (VDBG) log("handlePromptUnvalidated " + network);
|
if (VDBG) log("handlePromptUnvalidated " + network);
|
||||||
NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
|
NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
|
||||||
@@ -2763,18 +2807,22 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
!nai.networkMisc.explicitlySelected || nai.networkMisc.acceptUnvalidated) {
|
!nai.networkMisc.explicitlySelected || nai.networkMisc.acceptUnvalidated) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
showValidationNotification(nai, NotificationType.NO_INTERNET);
|
||||||
|
}
|
||||||
|
|
||||||
Intent intent = new Intent(ConnectivityManager.ACTION_PROMPT_UNVALIDATED);
|
// TODO: Delete this like updateMobileDataAlwaysOn above.
|
||||||
intent.setData(Uri.fromParts("netId", Integer.toString(network.netId), null));
|
@VisibleForTesting
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
void updateNetworkAvoidBadWifi() {
|
||||||
intent.setClassName("com.android.settings",
|
mHandler.sendEmptyMessage(EVENT_CONFIGURE_NETWORK_AVOID_BAD_WIFI);
|
||||||
"com.android.settings.wifi.WifiNoInternetDialog");
|
}
|
||||||
|
|
||||||
PendingIntent pendingIntent = PendingIntent.getActivityAsUser(
|
private void handleNetworkUnvalidated(NetworkAgentInfo nai) {
|
||||||
mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT);
|
NetworkCapabilities nc = nai.networkCapabilities;
|
||||||
|
if (DBG) log("handleNetworkUnvalidated " + nai.name() + " cap=" + nc);
|
||||||
|
|
||||||
mNotifier.showNotification(nai.network.netId, NotificationType.NO_INTERNET, nai, null,
|
if (nc.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) && !avoidBadWifi()) {
|
||||||
pendingIntent, true);
|
showValidationNotification(nai, NotificationType.LOST_INTERNET);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class InternalHandler extends Handler {
|
private class InternalHandler extends Handler {
|
||||||
@@ -2863,6 +2911,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
handleMobileDataAlwaysOn();
|
handleMobileDataAlwaysOn();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case EVENT_CONFIGURE_NETWORK_AVOID_BAD_WIFI: {
|
||||||
|
rematchAllNetworksAndRequests(null, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case EVENT_REQUEST_LINKPROPERTIES:
|
case EVENT_REQUEST_LINKPROPERTIES:
|
||||||
handleRequestLinkProperties((NetworkRequest) msg.obj, msg.arg1);
|
handleRequestLinkProperties((NetworkRequest) msg.obj, msg.arg1);
|
||||||
break;
|
break;
|
||||||
@@ -4849,7 +4901,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
} else if (newNetwork.isSatisfyingRequest(nri.request.requestId)) {
|
} else if (newNetwork.isSatisfyingRequest(nri.request.requestId)) {
|
||||||
// If "newNetwork" is listed as satisfying "nri" but no longer satisfies "nri",
|
// If "newNetwork" is listed as satisfying "nri" but no longer satisfies "nri",
|
||||||
// mark it as no longer satisfying "nri". Because networks are processed by
|
// mark it as no longer satisfying "nri". Because networks are processed by
|
||||||
// rematchAllNetworkAndRequests() in descending score order, "currentNetwork" will
|
// rematchAllNetworksAndRequests() in descending score order, "currentNetwork" will
|
||||||
// match "newNetwork" before this loop will encounter a "currentNetwork" with higher
|
// match "newNetwork" before this loop will encounter a "currentNetwork" with higher
|
||||||
// score than "newNetwork" and where "currentNetwork" no longer satisfies "nri".
|
// score than "newNetwork" and where "currentNetwork" no longer satisfies "nri".
|
||||||
// This means this code doesn't have to handle the case where "currentNetwork" no
|
// This means this code doesn't have to handle the case where "currentNetwork" no
|
||||||
@@ -5409,6 +5461,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Settings.Global.putString(mContext.getContentResolver(),
|
||||||
|
Settings.Global.NETWORK_AVOID_BAD_WIFI, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ import static android.net.NetworkCapabilities.*;
|
|||||||
|
|
||||||
public class NetworkNotificationManager {
|
public class NetworkNotificationManager {
|
||||||
|
|
||||||
public static enum NotificationType { SIGN_IN, NO_INTERNET, NETWORK_SWITCH };
|
public static enum NotificationType { SIGN_IN, NO_INTERNET, LOST_INTERNET, NETWORK_SWITCH };
|
||||||
|
|
||||||
private static final String NOTIFICATION_ID = "Connectivity.Notification";
|
private static final String NOTIFICATION_ID = "Connectivity.Notification";
|
||||||
|
|
||||||
@@ -91,8 +91,8 @@ public class NetworkNotificationManager {
|
|||||||
* @param id an identifier that uniquely identifies this notification. This must match
|
* @param id an identifier that uniquely identifies this notification. This must match
|
||||||
* between show and hide calls. We use the NetID value but for legacy callers
|
* between show and hide calls. We use the NetID value but for legacy callers
|
||||||
* we concatenate the range of types with the range of NetIDs.
|
* we concatenate the range of types with the range of NetIDs.
|
||||||
* @param nai the network with which the notification is associated. For a SIGN_IN or
|
* @param nai the network with which the notification is associated. For a SIGN_IN, NO_INTERNET,
|
||||||
* NO_INTERNET notification, this is the network we're connecting to. For a
|
* or LOST_INTERNET notification, this is the network we're connecting to. For a
|
||||||
* NETWORK_SWITCH notification it's the network that we switched from. When this network
|
* NETWORK_SWITCH notification it's the network that we switched from. When this network
|
||||||
* disconnects the notification is removed.
|
* disconnects the notification is removed.
|
||||||
* @param switchToNai for a NETWORK_SWITCH notification, the network we are switching to. Null
|
* @param switchToNai for a NETWORK_SWITCH notification, the network we are switching to. Null
|
||||||
@@ -126,6 +126,10 @@ public class NetworkNotificationManager {
|
|||||||
if (notifyType == NotificationType.NO_INTERNET && transportType == TRANSPORT_WIFI) {
|
if (notifyType == NotificationType.NO_INTERNET && transportType == TRANSPORT_WIFI) {
|
||||||
title = r.getString(R.string.wifi_no_internet, 0);
|
title = r.getString(R.string.wifi_no_internet, 0);
|
||||||
details = r.getString(R.string.wifi_no_internet_detailed);
|
details = r.getString(R.string.wifi_no_internet_detailed);
|
||||||
|
} else if (notifyType == NotificationType.LOST_INTERNET &&
|
||||||
|
transportType == TRANSPORT_WIFI) {
|
||||||
|
title = r.getString(R.string.wifi_no_internet, 0);
|
||||||
|
details = r.getString(R.string.wifi_no_internet_detailed);
|
||||||
} else if (notifyType == NotificationType.SIGN_IN) {
|
} else if (notifyType == NotificationType.SIGN_IN) {
|
||||||
switch (transportType) {
|
switch (transportType) {
|
||||||
case TRANSPORT_WIFI:
|
case TRANSPORT_WIFI:
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import static android.net.NetworkCapabilities.*;
|
|||||||
|
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
|
|
||||||
|
import android.app.NotificationManager;
|
||||||
import android.app.PendingIntent;
|
import android.app.PendingIntent;
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.ContentResolver;
|
import android.content.ContentResolver;
|
||||||
@@ -137,7 +138,8 @@ public class ConnectivityServiceTest extends AndroidTestCase {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object getSystemService(String name) {
|
public Object getSystemService(String name) {
|
||||||
if (name == Context.CONNECTIVITY_SERVICE) return mCm;
|
if (Context.CONNECTIVITY_SERVICE.equals(name)) return mCm;
|
||||||
|
if (Context.NOTIFICATION_SERVICE.equals(name)) return mock(NotificationManager.class);
|
||||||
return super.getSystemService(name);
|
return super.getSystemService(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2037,6 +2039,79 @@ public class ConnectivityServiceTest extends AndroidTestCase {
|
|||||||
handlerThread.quit();
|
handlerThread.quit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
public void testAvoidBadWifiSetting() throws Exception {
|
||||||
|
ContentResolver cr = mServiceContext.getContentResolver();
|
||||||
|
|
||||||
|
// File a request for cell to ensure it doesn't go down.
|
||||||
|
final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
|
||||||
|
final NetworkRequest cellRequest = new NetworkRequest.Builder()
|
||||||
|
.addTransportType(TRANSPORT_CELLULAR).build();
|
||||||
|
mCm.requestNetwork(cellRequest, cellNetworkCallback);
|
||||||
|
|
||||||
|
TestNetworkCallback defaultCallback = new TestNetworkCallback();
|
||||||
|
mCm.registerDefaultNetworkCallback(defaultCallback);
|
||||||
|
|
||||||
|
NetworkRequest validatedWifiRequest = new NetworkRequest.Builder()
|
||||||
|
.addTransportType(TRANSPORT_WIFI)
|
||||||
|
.addCapability(NET_CAPABILITY_VALIDATED)
|
||||||
|
.build();
|
||||||
|
TestNetworkCallback validatedWifiCallback = new TestNetworkCallback();
|
||||||
|
mCm.registerNetworkCallback(validatedWifiRequest, validatedWifiCallback);
|
||||||
|
|
||||||
|
// Takes effect on every rematch.
|
||||||
|
Settings.Global.putInt(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, 0);
|
||||||
|
|
||||||
|
// Bring up validated cell.
|
||||||
|
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
|
||||||
|
mCellNetworkAgent.connect(true);
|
||||||
|
cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
|
||||||
|
defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
|
||||||
|
Network cellNetwork = mCellNetworkAgent.getNetwork();
|
||||||
|
|
||||||
|
// Bring up validated wifi.
|
||||||
|
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
|
||||||
|
mWiFiNetworkAgent.connect(true);
|
||||||
|
defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
|
||||||
|
validatedWifiCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
|
||||||
|
Network wifiNetwork = mWiFiNetworkAgent.getNetwork();
|
||||||
|
|
||||||
|
// Fail validation on wifi.
|
||||||
|
mWiFiNetworkAgent.getWrappedNetworkMonitor().gen204ProbeResult = 599;
|
||||||
|
mCm.reportNetworkConnectivity(wifiNetwork, false);
|
||||||
|
validatedWifiCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
|
||||||
|
|
||||||
|
// Because avoid bad wifi is off, we don't switch to cellular.
|
||||||
|
defaultCallback.assertNoCallback();
|
||||||
|
assertFalse(mCm.getNetworkCapabilities(wifiNetwork).hasCapability(
|
||||||
|
NET_CAPABILITY_VALIDATED));
|
||||||
|
assertTrue(mCm.getNetworkCapabilities(cellNetwork).hasCapability(
|
||||||
|
NET_CAPABILITY_VALIDATED));
|
||||||
|
assertEquals(mCm.getActiveNetwork(), wifiNetwork);
|
||||||
|
|
||||||
|
// Simulate the user selecting "switch" on the dialog.
|
||||||
|
Settings.Global.putInt(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, 1);
|
||||||
|
mService.updateNetworkAvoidBadWifi();
|
||||||
|
|
||||||
|
// We now switch to cell.
|
||||||
|
defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
|
||||||
|
assertFalse(mCm.getNetworkCapabilities(wifiNetwork).hasCapability(
|
||||||
|
NET_CAPABILITY_VALIDATED));
|
||||||
|
assertTrue(mCm.getNetworkCapabilities(cellNetwork).hasCapability(
|
||||||
|
NET_CAPABILITY_VALIDATED));
|
||||||
|
assertEquals(mCm.getActiveNetwork(), cellNetwork);
|
||||||
|
|
||||||
|
// If cell goes down, we switch to wifi.
|
||||||
|
mCellNetworkAgent.disconnect();
|
||||||
|
defaultCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
|
||||||
|
defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
|
||||||
|
validatedWifiCallback.assertNoCallback();
|
||||||
|
|
||||||
|
mCm.unregisterNetworkCallback(cellNetworkCallback);
|
||||||
|
mCm.unregisterNetworkCallback(validatedWifiCallback);
|
||||||
|
mCm.unregisterNetworkCallback(defaultCallback);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate that a satisfied network request does not trigger onUnavailable() once the
|
* Validate that a satisfied network request does not trigger onUnavailable() once the
|
||||||
* time-out period expires.
|
* time-out period expires.
|
||||||
|
|||||||
Reference in New Issue
Block a user