OSDN Git Service

Support displaying a dialog when wifi becomes unvalidated.
authorLorenzo Colitti <lorenzo@google.com>
Thu, 15 Sep 2016 05:02:29 +0000 (14:02 +0900)
committerLorenzo Colitti <lorenzo@google.com>
Thu, 15 Sep 2016 14:33:34 +0000 (23:33 +0900)
Bug: 31075769
Change-Id: I7a6e7580769365bea930f638bd44edcaa28df134

core/java/android/net/ConnectivityManager.java
services/core/java/com/android/server/ConnectivityService.java
services/core/java/com/android/server/connectivity/NetworkNotificationManager.java

index 3c2ac67..52d6b56 100644 (file)
@@ -343,6 +343,15 @@ public class ConnectivityManager {
     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.
      * @see #startTethering(int, OnStartTetheringCallback, boolean)
      * @hide
index 4c30dc2..8b1be3b 100644 (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_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. */
     @VisibleForTesting
     protected final HandlerThread mHandlerThread;
@@ -896,6 +901,12 @@ public class ConnectivityService extends IConnectivityManager.Stub
         mSettingsObserver.observe(
                 Settings.Global.getUriFor(Settings.Global.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() {
@@ -2209,6 +2220,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
                     if (nai != null) {
                         final boolean valid =
                                 (msg.arg1 == NetworkMonitor.NETWORK_TEST_RESULT_VALID);
+                        final boolean wasValidated = nai.lastValidated;
                         if (DBG) log(nai.name() + " validation " + (valid ? "passed" : "failed") +
                                 (msg.obj == null ? "" : " with redirect to " + (String)msg.obj));
                         if (valid != nai.lastValidated) {
@@ -2227,6 +2239,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
                                 NetworkAgent.CMD_REPORT_NETWORK_STATUS,
                                 (valid ? NetworkAgent.VALID_NETWORK : NetworkAgent.INVALID_NETWORK),
                                 0, redirectUrlBundle);
+                         if (wasValidated && !nai.lastValidated) {
+                             handleNetworkUnvalidated(nai);
+                         }
                     }
                     break;
                 }
@@ -2706,6 +2721,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
 
     @VisibleForTesting
     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 =
             mContext.getResources().getInteger(R.integer.config_networkAvoidBadWifi);
         int avoid = Settings.Global.getInt(mContext.getContentResolver(),
@@ -2713,6 +2732,31 @@ public class ConnectivityService extends IConnectivityManager.Stub
         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) {
         if (VDBG) log("handlePromptUnvalidated " + network);
         NetworkAgentInfo nai = getNetworkAgentInfoForNetwork(network);
@@ -2724,18 +2768,16 @@ public class ConnectivityService extends IConnectivityManager.Stub
                 !nai.networkMisc.explicitlySelected || nai.networkMisc.acceptUnvalidated) {
             return;
         }
+        showValidationNotification(nai, NotificationType.NO_INTERNET);
+    }
 
-        Intent intent = new Intent(ConnectivityManager.ACTION_PROMPT_UNVALIDATED);
-        intent.setData(Uri.fromParts("netId", Integer.toString(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);
+    private void handleNetworkUnvalidated(NetworkAgentInfo nai) {
+        NetworkCapabilities nc = nai.networkCapabilities;
+        if (DBG) log("handleNetworkUnvalidated " + nai.name() + " cap=" + nc);
 
-        mNotifier.showNotification(nai.network.netId, NotificationType.NO_INTERNET, nai, null,
-                pendingIntent, true);
+        if (nc.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) && !avoidBadWifi()) {
+            showValidationNotification(nai, NotificationType.LOST_INTERNET);
+        }
     }
 
     private class InternalHandler extends Handler {
@@ -2819,6 +2861,10 @@ public class ConnectivityService extends IConnectivityManager.Stub
                     handleMobileDataAlwaysOn();
                     break;
                 }
+                case EVENT_CONFIGURE_NETWORK_AVOID_BAD_WIFI: {
+                    rematchAllNetworksAndRequests(null, 0);
+                    break;
+                }
                 case EVENT_REQUEST_LINKPROPERTIES:
                     handleRequestLinkProperties((NetworkRequest) msg.obj, msg.arg1);
                     break;
@@ -4746,7 +4792,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
             } else if (newNetwork.isSatisfyingRequest(nri.request.requestId)) {
                 // If "newNetwork" is listed as satisfying "nri" but no longer satisfies "nri",
                 // 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
                 // score than "newNetwork" and where "currentNetwork" no longer satisfies "nri".
                 // 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
index 99926a9..f7b01be 100644 (file)
@@ -35,7 +35,7 @@ import static android.net.NetworkCapabilities.*;
 
 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";
 
@@ -91,8 +91,8 @@ public class NetworkNotificationManager {
      * @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
      *         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
-     *         NO_INTERNET notification, this is the network we're connecting to. For a
+     * @param nai the network with which the notification is associated. For a SIGN_IN, NO_INTERNET,
+     *         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
      *         disconnects the notification is removed.
      * @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) {
             title = r.getString(R.string.wifi_no_internet, 0);
             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) {
             switch (transportType) {
                 case TRANSPORT_WIFI: