Support displaying a dialog when wifi becomes unvalidated.

Bug: 31075769
Change-Id: I7a6e7580769365bea930f638bd44edcaa28df134
This commit is contained in:
Lorenzo Colitti
2016-09-15 14:02:29 +09:00
parent c9048bc556
commit 199ecfc79f
3 changed files with 76 additions and 14 deletions

View File

@@ -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)

View File

@@ -392,6 +392,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;
@@ -896,6 +901,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;
} }
@@ -2706,6 +2721,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(),
@@ -2713,6 +2732,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);
@@ -2724,18 +2768,16 @@ 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); private void handleNetworkUnvalidated(NetworkAgentInfo nai) {
intent.setData(Uri.fromParts("netId", Integer.toString(network.netId), null)); NetworkCapabilities nc = nai.networkCapabilities;
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); if (DBG) log("handleNetworkUnvalidated " + nai.name() + " cap=" + nc);
intent.setClassName("com.android.settings",
"com.android.settings.wifi.WifiNoInternetDialog");
PendingIntent pendingIntent = PendingIntent.getActivityAsUser( if (nc.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) && !avoidBadWifi()) {
mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT, null, UserHandle.CURRENT); showValidationNotification(nai, NotificationType.LOST_INTERNET);
}
mNotifier.showNotification(nai.network.netId, NotificationType.NO_INTERNET, nai, null,
pendingIntent, true);
} }
private class InternalHandler extends Handler { private class InternalHandler extends Handler {
@@ -2819,6 +2861,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;
@@ -4746,7 +4792,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
@@ -5280,6 +5326,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
} }
} }
} }
Settings.Global.putString(mContext.getContentResolver(),
Settings.Global.NETWORK_AVOID_BAD_WIFI, null);
} }
@VisibleForTesting @VisibleForTesting

View File

@@ -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: