Final UX for Wi-Fi assistant platform settings.

When one app is available, the toggle works as before. When multiple
apps are available, we allow the user to choose the app in a dialog
before turning on the setting.

Bug: 13780935
Change-Id: I1c4391bf97a53febe580fb2b896b4850372062e7
diff --git a/res/values/strings.xml b/res/values/strings.xml
index f6f4d5a..d8d442c 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1451,10 +1451,12 @@
     <string name="wifi_scan_always_available_title">Always allow scanning</string>
     <!-- Checkbox summary for option to toggle scan always available setting -->
     <string name="wifi_scan_always_available_summary">Let Google\'s location service and other apps scan for networks, even when Wi\u2011Fi is off</string>
-    <!-- Checkbox title for option to Automatically manage Wi\u2011Fi  [CHAR LIMIT=40] -->
-    <string name="wifi_automatically_manage_title">Automatically manage Wi\u2011Fi</string>
-    <!-- Checkbox summary for option to Automatically manage Wi\u2011Fi  [CHAR LIMIT=100] -->
-    <string name="wifi_automatically_manage_summary">Let <xliff:g id="wifi_assistant">%1$s</xliff:g> manage your Wi\u2011Fi connection</string>
+    <!-- Checkbox title for option to connect to open Wi-Fi automatically [CHAR LIMIT=40] -->
+    <string name="wifi_automatically_connect_title">Connect to open Wi\u2011Fi automatically</string>
+    <!-- Checkbox summary for option to connect to open Wi-Fi automatically  [CHAR LIMIT=100] -->
+    <string name="wifi_automatically_connect_summary">Allow a Wi\u2011Fi assistant to automatically rate and connect to open Wi\u2011Fi networks determined to be high quality</string>
+    <!-- Dialog title for option to select an app which connects to open Wi-Fi automatically [CHAR LIMIT=40] -->
+    <string name="wifi_select_assistant_dialog_title">Select a Wi\u2011Fi assistant</string>
     <!-- Preference title for option to install certificates -->
     <string name="wifi_install_credentials">Install certificates</string>
     <string name="wifi_scan_notify_text_location_on">To improve location accuracy and for other purposes, Google and other apps may scan for nearby networks, even when Wi-Fi is off. If you don\'t want this to happen, go to Advanced &gt; Scanning always available.</string>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 0e83d90..162dced 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -312,6 +312,10 @@
         <item name="android:layout">@layout/apn_preference_layout</item>
     </style>
 
+    <style name="AppListSwitchPreference" parent="@*android:style/Preference.Material.DialogPreference">
+        <item name="android:widgetLayout">@*android:layout/preference_widget_switch</item>
+    </style>
+
     <style name="TextAppearance.Medium" parent="@android:style/TextAppearance.Material.Medium">
     </style>
 
@@ -341,5 +345,4 @@
     <style name="Widget.TimePicker" parent="@*android:style/Widget.Material.Light.TimePicker">
         <item name="@android:numbersBackgroundColor">@android:color/white</item>
     </style>
-
 </resources>
diff --git a/res/xml/wifi_advanced_settings.xml b/res/xml/wifi_advanced_settings.xml
index 5b81d25..a7f47b1 100644
--- a/res/xml/wifi_advanced_settings.xml
+++ b/res/xml/wifi_advanced_settings.xml
@@ -30,11 +30,6 @@
             android:summary="@string/wifi_scan_always_available_summary"
             android:persistent="false" />
 
-    <SwitchPreference
-            android:key="wifi_assistant"
-            android:title="@string/wifi_automatically_manage_title"
-            android:persistent="false" />
-
     <ListPreference
             android:key="sleep_policy"
             android:title="@string/wifi_setting_sleep_policy_title"
@@ -42,6 +37,13 @@
             android:entries="@array/wifi_sleep_policy_entries"
             android:entryValues="@array/wifi_sleep_policy_values" />
 
+    <com.android.settings.AppListSwitchPreference
+            android:key="wifi_assistant"
+            android:title="@string/wifi_automatically_connect_title"
+            android:summary="@string/wifi_automatically_connect_summary"
+            android:dialogTitle="@string/wifi_select_assistant_dialog_title"
+            android:persistent="false" />
+
     <ListPreference
             android:key="frequency_band"
             android:title="@string/wifi_setting_frequency_band_title"
diff --git a/src/com/android/settings/AppListPreference.java b/src/com/android/settings/AppListPreference.java
index 2180983..96897ae 100644
--- a/src/com/android/settings/AppListPreference.java
+++ b/src/com/android/settings/AppListPreference.java
@@ -67,6 +67,11 @@
         }
     }
 
+    public AppListPreference(Context context, AttributeSet attrs,
+            int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+    }
+
     public AppListPreference(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
@@ -105,6 +110,8 @@
         setEntryValues(packageNames);
         if (selectedIndex != -1) {
             setValueIndex(selectedIndex);
+        } else {
+            setValue(null);
         }
     }
 
diff --git a/src/com/android/settings/AppListSwitchPreference.java b/src/com/android/settings/AppListSwitchPreference.java
new file mode 100644
index 0000000..f9f1ba0
--- /dev/null
+++ b/src/com/android/settings/AppListSwitchPreference.java
@@ -0,0 +1,59 @@
+package com.android.settings;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+import android.widget.Checkable;
+
+/**
+ * A hybrid of AppListPreference and SwitchPreference, representing a preference which can be on or
+ * off but must have a selected value when turned on.
+ *
+ * It is invalid to show this preference when zero valid apps are present.
+ */
+public class AppListSwitchPreference extends AppListPreference {
+    private static final String TAG = "AppListSwitchPref";
+
+    private Checkable mSwitch;
+
+    public AppListSwitchPreference(Context context, AttributeSet attrs) {
+        super(context, attrs, 0, R.style.AppListSwitchPreference);
+    }
+
+    @Override
+    protected void onBindView(View view) {
+        super.onBindView(view);
+        mSwitch = (Checkable) view.findViewById(com.android.internal.R.id.switchWidget);
+        mSwitch.setChecked(getValue() != null);
+    }
+
+    @Override
+    protected void showDialog(Bundle state) {
+        if (getValue() != null) {
+            // Turning off the current value.
+            if (callChangeListener(null)) {
+                setValue(null);
+            }
+        } else if (getEntryValues() == null || getEntryValues().length == 0) {
+            Log.e(TAG, "Attempting to show dialog with zero entries: " + getKey());
+        } else if (getEntryValues().length == 1) {
+            // Suppress the dialog and just toggle the preference with the only choice.
+            String value = getEntryValues()[0].toString();
+            if (callChangeListener(value)) {
+                setValue(value);
+            }
+        } else {
+            super.showDialog(state);
+        }
+    }
+
+    @Override
+    public void setValue(String value) {
+        super.setValue(value);
+        if (mSwitch != null) {
+            mSwitch.setChecked(value != null);
+        }
+    }
+}
diff --git a/src/com/android/settings/wifi/AdvancedWifiSettings.java b/src/com/android/settings/wifi/AdvancedWifiSettings.java
index 7d06fdb..ac93c2e 100644
--- a/src/com/android/settings/wifi/AdvancedWifiSettings.java
+++ b/src/com/android/settings/wifi/AdvancedWifiSettings.java
@@ -42,6 +42,7 @@
 import android.util.Log;
 import android.widget.Toast;
 
+import com.android.settings.AppListSwitchPreference;
 import com.android.settings.R;
 import com.android.settings.SettingsPreferenceFragment;
 import com.android.settings.Utils;
@@ -66,6 +67,7 @@
 
     private WifiManager mWifiManager;
     private NetworkScoreManager mNetworkScoreManager;
+    private AppListSwitchPreference mWifiAssistantPreference;
 
     private IntentFilter mFilter;
     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@@ -130,18 +132,14 @@
         pref.setIntent(intent);
 
         final Context context = getActivity();
-        SwitchPreference wifiAssistant = (SwitchPreference)findPreference(KEY_WIFI_ASSISTANT);
-        NetworkScorerAppData scorer = getWifiAssistantApp(context);
-        if (UserHandle.myUserId() == UserHandle.USER_OWNER && scorer != null) {
-            final boolean checked = NetworkScorerAppManager.getActiveScorer(context) != null;
-            wifiAssistant.setSummary(getResources().getString(
-                    R.string.wifi_automatically_manage_summary, scorer.mScorerName));
-            wifiAssistant.setOnPreferenceChangeListener(this);
-            wifiAssistant.setChecked(checked);
-        } else {
-            if (wifiAssistant != null) {
-                getPreferenceScreen().removePreference(wifiAssistant);
-            }
+        mWifiAssistantPreference = (AppListSwitchPreference) findPreference(KEY_WIFI_ASSISTANT);
+        Collection<NetworkScorerAppData> scorers =
+                NetworkScorerAppManager.getAllValidScorers(context);
+        if (UserHandle.myUserId() == UserHandle.USER_OWNER && !scorers.isEmpty()) {
+            mWifiAssistantPreference.setOnPreferenceChangeListener(this);
+            initWifiAssistantPreference(scorers);
+        } else if (mWifiAssistantPreference != null) {
+            getPreferenceScreen().removePreference(mWifiAssistantPreference);
         }
 
         Intent wifiDirectIntent = new Intent(context,
@@ -202,6 +200,18 @@
         }
     }
 
+    private void initWifiAssistantPreference(Collection<NetworkScorerAppData> scorers) {
+        int count = scorers.size();
+        String[] packageNames = new String[count];
+        int i = 0;
+        for (NetworkScorerAppData scorer : scorers) {
+            packageNames[i] = scorer.mPackageName;
+            i++;
+        }
+        mWifiAssistantPreference.setPackageNames(packageNames,
+                mNetworkScoreManager.getActiveScorerPackage());
+    }
+
     private void updateSleepPolicySummary(Preference sleepPolicyPref, String value) {
         if (value != null) {
             String[] values = getResources().getStringArray(R.array.wifi_sleep_policy_values);
@@ -261,12 +271,13 @@
                 return false;
             }
         } else if (KEY_WIFI_ASSISTANT.equals(key)) {
-            if (((Boolean)newValue).booleanValue() == false) {
+            NetworkScorerAppData wifiAssistant =
+                    NetworkScorerAppManager.getScorer(context, (String) newValue);
+            if (wifiAssistant == null) {
                 mNetworkScoreManager.setActiveScorer(null);
                 return true;
             }
 
-            NetworkScorerAppData wifiAssistant = getWifiAssistantApp(context);
             Intent intent = new Intent();
             if (wifiAssistant.mConfigurationActivityClassName != null) {
                 // App has a custom configuration activity; launch that.
@@ -282,6 +293,9 @@
             }
 
             startActivity(intent);
+            // Don't update the preference widget state until the child activity returns.
+            // It will be updated in onResume after the activity finishes.
+            return false;
         }
 
         if (KEY_SLEEP_POLICY.equals(key)) {
@@ -317,22 +331,6 @@
         wifiIpAddressPref.setSelectable(false);
     }
 
-    /**
-     * Returns the Network Scorer for the Wifi Assistant App.
-     */
-    public static NetworkScorerAppData getWifiAssistantApp(Context context) {
-        Collection<NetworkScorerAppData> scorers =
-                NetworkScorerAppManager.getAllValidScorers(context);
-
-        if (scorers.isEmpty()) {
-            return null;
-        }
-
-        // TODO: b/13780935 - Implement proper scorer selection. Rather than pick the first
-        // scorer on the system, we should allow the user to select one.
-        return scorers.iterator().next();
-    }
-
     /* Wrapper class for the WPS dialog to properly handle life cycle events like rotation. */
     public static class WpsFragment extends DialogFragment {
         private static int mWpsSetup;