Final platform settings UX for ephemeral networks.

Show "Connected via Wi-Fi assistant" instead of just "Connected" when
a Wi-Fi connection is ephemeral. Otherwise, treat ephemeral
connections just like saved ones - show (read-only) connection stats
when you click the network, and offer the ability to "forget" the
network, which prevents further ephemeral connections.

Bug: 18525241
Change-Id: I0d2146ab47b82d32c50b2ef883f176a6b6066713
diff --git a/src/com/android/settings/wifi/AccessPoint.java b/src/com/android/settings/wifi/AccessPoint.java
index 45c3a5b..1bf1a5c 100644
--- a/src/com/android/settings/wifi/AccessPoint.java
+++ b/src/com/android/settings/wifi/AccessPoint.java
@@ -595,7 +595,7 @@
      * For ephemeral connections (networkId is invalid), this returns false if the network is
      * disconnected.
      */
-    private boolean isActive() {
+    boolean isActive() {
         return mNetworkInfo != null &&
                 (networkId != WifiConfiguration.INVALID_NETWORK_ID ||
                  mNetworkInfo.getState() != State.DISCONNECTED);
@@ -617,7 +617,8 @@
         StringBuilder summary = new StringBuilder();
 
         if (isActive()) { // This is the active connection
-            summary.append(Summary.get(context, getState()));
+            summary.append(Summary.get(context, getState(),
+                    networkId == WifiConfiguration.INVALID_NETWORK_ID));
         } else if (mConfig != null
                 && mConfig.hasNoInternetAccess()) {
             summary.append(context.getString(R.string.wifi_no_internet));
diff --git a/src/com/android/settings/wifi/Summary.java b/src/com/android/settings/wifi/Summary.java
index d96d23e..123f64a 100644
--- a/src/com/android/settings/wifi/Summary.java
+++ b/src/com/android/settings/wifi/Summary.java
@@ -22,7 +22,12 @@
 import android.net.NetworkInfo.DetailedState;
 
 class Summary {
-    static String get(Context context, String ssid, DetailedState state) {
+    static String get(Context context, String ssid, DetailedState state, boolean isEphemeral) {
+        if (state == DetailedState.CONNECTED && isEphemeral && ssid == null) {
+            // Special case for connected + ephemeral networks.
+            return context.getString(R.string.connected_via_wfa);
+        }
+
         String[] formats = context.getResources().getStringArray((ssid == null)
                 ? R.array.wifi_status : R.array.wifi_status_with_ssid);
         int index = state.ordinal();
@@ -33,7 +38,7 @@
         return String.format(formats[index], ssid);
     }
 
-    static String get(Context context, DetailedState state) {
-        return get(context, null, state);
+    static String get(Context context, DetailedState state, boolean isEphemeral) {
+        return get(context, null, state, isEphemeral);
     }
 }
diff --git a/src/com/android/settings/wifi/WifiConfigController.java b/src/com/android/settings/wifi/WifiConfigController.java
index b00faf1..5462d26 100644
--- a/src/com/android/settings/wifi/WifiConfigController.java
+++ b/src/com/android/settings/wifi/WifiConfigController.java
@@ -242,7 +242,8 @@
                 }
             }
 
-            if (mAccessPoint.networkId == INVALID_NETWORK_ID || mEdit) {
+            if ((mAccessPoint.networkId == INVALID_NETWORK_ID && !mAccessPoint.isActive())
+                    || mEdit) {
                 showSecurityFields();
                 showIpConfigFields();
                 showProxyFields();
@@ -266,7 +267,8 @@
                 } else {
                     if (state != null) {
                         addRow(group, R.string.wifi_status, Summary.get(mConfigUi.getContext(),
-                                state));
+                                state, mAccessPoint.networkId ==
+                                WifiConfiguration.INVALID_NETWORK_ID));
                     }
 
                     if (signalLevel != null) {
@@ -300,7 +302,7 @@
                     addRow(group, R.string.wifi_security, mAccessPoint.getSecurityString(false));
                     mView.findViewById(R.id.ip_fields).setVisibility(View.GONE);
                 }
-                if (mAccessPoint.networkId != INVALID_NETWORK_ID
+                if ((mAccessPoint.networkId != INVALID_NETWORK_ID || mAccessPoint.isActive())
                         && ActivityManager.getCurrentUser() == UserHandle.USER_OWNER) {
                     mConfigUi.setForgetButton(res.getString(R.string.wifi_forget));
                 }
diff --git a/src/com/android/settings/wifi/WifiSettings.java b/src/com/android/settings/wifi/WifiSettings.java
index 9dfd201..8eab1c7 100644
--- a/src/com/android/settings/wifi/WifiSettings.java
+++ b/src/com/android/settings/wifi/WifiSettings.java
@@ -502,26 +502,21 @@
                 mSelectedAccessPoint = (AccessPoint) preference;
                 menu.setHeaderTitle(mSelectedAccessPoint.ssid);
                 if (mSelectedAccessPoint.getLevel() != -1) {
-                    int connectStringRes = 0;
                     if (mSelectedAccessPoint.getState() == null) {
-                        connectStringRes = R.string.wifi_menu_connect;
-                    } else if (mSelectedAccessPoint.networkId == INVALID_NETWORK_ID &&
-                            mSelectedAccessPoint.getNetworkInfo().getState()
-                                != State.DISCONNECTED) {
-                        // State is non-null (and not disconnected) but this network has no
-                        // configuration, which means it is ephemeral. Allow the user to save the
-                        // configuration permanently (but still issue this as a CONNECT command).
-                        connectStringRes = R.string.wifi_menu_remember;
-                    }
-
-                    if (connectStringRes != 0) {
-                        menu.add(Menu.NONE, MENU_ID_CONNECT, 0, connectStringRes);
+                        menu.add(Menu.NONE, MENU_ID_CONNECT, 0, R.string.wifi_menu_connect);
                     }
                 }
+
+                if (ActivityManager.getCurrentUser() == UserHandle.USER_OWNER &&
+                        (mSelectedAccessPoint.networkId != INVALID_NETWORK_ID ||
+                        (mSelectedAccessPoint.getNetworkInfo() != null &&
+                        mSelectedAccessPoint.getNetworkInfo().getState() != State.DISCONNECTED))) {
+                    // Allow forgetting a network if the current user is the owner and either the
+                    // network is saved or ephemerally connected. (In the latter case, "forget"
+                    // blacklists the network so it won't be used again, ephemerally).
+                    menu.add(Menu.NONE, MENU_ID_FORGET, 0, R.string.wifi_menu_forget);
+                }
                 if (mSelectedAccessPoint.networkId != INVALID_NETWORK_ID) {
-                    if (ActivityManager.getCurrentUser() == UserHandle.USER_OWNER) {
-                        menu.add(Menu.NONE, MENU_ID_FORGET, 0, R.string.wifi_menu_forget);
-                    }
                     menu.add(Menu.NONE, MENU_ID_MODIFY, 0, R.string.wifi_menu_modify);
 
                     if (mSelectedAccessPoint.security != AccessPoint.SECURITY_NONE) {
@@ -552,7 +547,7 @@
                 return true;
             }
             case MENU_ID_FORGET: {
-                mWifiManager.forget(mSelectedAccessPoint.networkId, mForgetListener);
+                forget();
                 return true;
             }
             case MENU_ID_MODIFY: {
@@ -571,9 +566,10 @@
     public boolean onPreferenceTreeClick(PreferenceScreen screen, Preference preference) {
         if (preference instanceof AccessPoint) {
             mSelectedAccessPoint = (AccessPoint) preference;
-            /** Bypass dialog for unsecured, unsaved networks */
+            /** Bypass dialog for unsecured, unsaved, and inactive networks */
             if (mSelectedAccessPoint.security == AccessPoint.SECURITY_NONE &&
-                    mSelectedAccessPoint.networkId == INVALID_NETWORK_ID) {
+                    mSelectedAccessPoint.networkId == INVALID_NETWORK_ID &&
+                    !mSelectedAccessPoint.isActive()) {
                 mSelectedAccessPoint.generateOpenNetworkConfig();
                 if (!savedNetworksExist) {
                     savedNetworksExist = true;
@@ -903,12 +899,19 @@
 
     /* package */ void forget() {
         if (mSelectedAccessPoint.networkId == INVALID_NETWORK_ID) {
-            // Should not happen, but a monkey seems to trigger it
-            Log.e(TAG, "Failed to forget invalid network " + mSelectedAccessPoint.getConfig());
-            return;
+            if (mSelectedAccessPoint.getNetworkInfo().getState() != State.DISCONNECTED) {
+                // Network is active but has no network ID - must be ephemeral.
+                mWifiManager.disableEphemeralNetwork(
+                        AccessPoint.convertToQuotedString(mSelectedAccessPoint.ssid));
+            } else {
+                // Should not happen, but a monkey seems to trigger it
+                Log.e(TAG, "Failed to forget invalid network " + mSelectedAccessPoint.getConfig());
+                return;
+            }
+        } else {
+            mWifiManager.forget(mSelectedAccessPoint.networkId, mForgetListener);
         }
 
-        mWifiManager.forget(mSelectedAccessPoint.networkId, mForgetListener);
 
         if (mWifiManager.isWifiEnabled()) {
             mScanner.resume();
diff --git a/src/com/android/settings/wifi/WifiSettingsForSetupWizardXL.java b/src/com/android/settings/wifi/WifiSettingsForSetupWizardXL.java
index bc387cb..2588309 100644
--- a/src/com/android/settings/wifi/WifiSettingsForSetupWizardXL.java
+++ b/src/com/android/settings/wifi/WifiSettingsForSetupWizardXL.java
@@ -285,7 +285,7 @@
         default:  // DISCONNECTED, FAILED
             if (mScreenState != SCREEN_STATE_CONNECTED &&
                     mWifiSettings.getAccessPointsCount() > 0) {
-                showDisconnectedState(Summary.get(this, state));
+                showDisconnectedState(Summary.get(this, state, false /* isEphemeral */));
             }
             break;
         }
diff --git a/src/com/android/settings/wifi/WifiStatusTest.java b/src/com/android/settings/wifi/WifiStatusTest.java
index 1b23834..dbd8eec 100644
--- a/src/com/android/settings/wifi/WifiStatusTest.java
+++ b/src/com/android/settings/wifi/WifiStatusTest.java
@@ -17,12 +17,16 @@
 package com.android.settings.wifi;
 
 import com.android.settings.R;
+
 import android.net.wifi.ScanResult;
+
 import org.apache.http.HttpResponse;
 import org.apache.http.client.HttpClient;
 import org.apache.http.client.methods.HttpGet;
 import org.apache.http.impl.client.DefaultHttpClient;
+
 import java.util.List;
+
 import android.app.Activity;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -30,6 +34,7 @@
 import android.content.IntentFilter;
 import android.net.NetworkInfo;
 import android.net.wifi.SupplicantState;
+import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
 import android.os.Bundle;
@@ -40,6 +45,7 @@
 import android.view.View.OnClickListener;
 import android.widget.Button;
 import android.widget.TextView;
+
 import java.io.IOException;
 import java.net.UnknownHostException;
 
@@ -294,8 +300,9 @@
 
     private void handleNetworkStateChanged(NetworkInfo networkInfo) {
         if (mWifiManager.isWifiEnabled()) {
-            String summary = Summary.get(this, mWifiManager.getConnectionInfo().getSSID(),
-                    networkInfo.getDetailedState());
+            WifiInfo info = mWifiManager.getConnectionInfo();
+            String summary = Summary.get(this, info.getSSID(), networkInfo.getDetailedState(),
+                    info.getNetworkId() == WifiConfiguration.INVALID_NETWORK_ID);
             mNetworkState.setText(summary);
         }
     }