Refactor ConfigureWifiSettings for better testing

Fix: 34205150
Test: make -j40 RunSettingsRoboTests
Change-Id: I7a8a0c89c087365fb50f3a9edd2cf64b2dda647c
diff --git a/src/com/android/settings/wifi/AllowRecommendationPreferenceController.java b/src/com/android/settings/wifi/AllowRecommendationPreferenceController.java
new file mode 100644
index 0000000..a58055d
--- /dev/null
+++ b/src/com/android/settings/wifi/AllowRecommendationPreferenceController.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.wifi;
+
+import android.content.Context;
+import android.provider.Settings;
+import android.support.v14.preference.SwitchPreference;
+import android.support.v7.preference.Preference;
+import android.text.TextUtils;
+
+import com.android.settings.core.PreferenceController;
+
+public class AllowRecommendationPreferenceController extends PreferenceController {
+
+    private static final String KEY_ALLOW_RECOMMENDATIONS = "allow_recommendations";
+
+    public AllowRecommendationPreferenceController(Context context) {
+        super(context);
+    }
+
+    @Override
+    public boolean isAvailable() {
+        return true;
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        ((SwitchPreference) preference).setChecked(Settings.Global.getInt(
+                mContext.getContentResolver(),
+                Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, 0) == 1);
+    }
+
+    @Override
+    public boolean handlePreferenceTreeClick(Preference preference) {
+        if (!TextUtils.equals(preference.getKey(), KEY_ALLOW_RECOMMENDATIONS)) {
+            return false;
+        }
+        if (!(preference instanceof SwitchPreference)) {
+            return false;
+        }
+        Settings.Global.putInt(mContext.getContentResolver(),
+                Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED,
+                ((SwitchPreference) preference).isChecked() ? 1 : 0);
+        return true;
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return KEY_ALLOW_RECOMMENDATIONS;
+    }
+}
diff --git a/src/com/android/settings/wifi/CellularFallbackPreferenceController.java b/src/com/android/settings/wifi/CellularFallbackPreferenceController.java
new file mode 100644
index 0000000..4e9174c
--- /dev/null
+++ b/src/com/android/settings/wifi/CellularFallbackPreferenceController.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.wifi;
+
+import android.content.Context;
+import android.provider.Settings;
+import android.support.v14.preference.SwitchPreference;
+import android.support.v7.preference.Preference;
+import android.text.TextUtils;
+
+import com.android.settings.core.PreferenceController;
+
+/**
+ * {@link PreferenceController} that controls whether we should fall back to celluar when wifi is
+ * bad.
+ */
+public class CellularFallbackPreferenceController extends PreferenceController {
+
+    private static final String KEY_CELLULAR_FALLBACK = "wifi_cellular_data_fallback";
+
+
+    public CellularFallbackPreferenceController(Context context) {
+        super(context);
+    }
+
+    @Override
+    public boolean isAvailable() {
+        return !avoidBadWifiConfig();
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return KEY_CELLULAR_FALLBACK;
+    }
+
+    @Override
+    public boolean handlePreferenceTreeClick(Preference preference) {
+        if (!TextUtils.equals(preference.getKey(), KEY_CELLULAR_FALLBACK)) {
+            return false;
+        }
+        if (!(preference instanceof SwitchPreference)) {
+            return false;
+        }
+        // On: avoid bad wifi. Off: prompt.
+        String settingName = Settings.Global.NETWORK_AVOID_BAD_WIFI;
+        Settings.Global.putString(mContext.getContentResolver(), settingName,
+                ((SwitchPreference) preference).isChecked() ? "1" : null);
+        return true;
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        final boolean currentSetting = avoidBadWifiCurrentSettings();
+        // TODO: can this ever be null? The return value of avoidBadWifiConfig() can only
+        // change if the resources change, but if that happens the activity will be recreated...
+        if (preference != null) {
+            SwitchPreference pref = (SwitchPreference) preference;
+            pref.setChecked(currentSetting);
+        }
+    }
+
+    private boolean avoidBadWifiConfig() {
+        return mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_networkAvoidBadWifi) == 1;
+    }
+
+    private boolean avoidBadWifiCurrentSettings() {
+        return "1".equals(Settings.Global.getString(mContext.getContentResolver(),
+                Settings.Global.NETWORK_AVOID_BAD_WIFI));
+    }
+}
diff --git a/src/com/android/settings/wifi/ConfigureWifiSettings.java b/src/com/android/settings/wifi/ConfigureWifiSettings.java
index 01ae99c..98f68ee 100644
--- a/src/com/android/settings/wifi/ConfigureWifiSettings.java
+++ b/src/com/android/settings/wifi/ConfigureWifiSettings.java
@@ -15,222 +15,56 @@
  */
 package com.android.settings.wifi;
 
-import android.content.BroadcastReceiver;
 import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.net.wifi.WifiConfiguration;
-import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
-import android.os.Bundle;
-import android.provider.Settings;
-import android.support.v14.preference.SwitchPreference;
-import android.support.v7.preference.ListPreference;
-import android.support.v7.preference.Preference;
-import android.text.TextUtils;
-import android.util.Log;
-import android.widget.Toast;
+
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.settings.R;
-import com.android.settings.SettingsPreferenceFragment;
-import com.android.settings.Utils;
+import com.android.settings.core.PreferenceController;
+import com.android.settings.dashboard.DashboardFragment;
+
+import java.util.ArrayList;
 import java.util.List;
 
-public class ConfigureWifiSettings extends SettingsPreferenceFragment
-        implements Preference.OnPreferenceChangeListener {
+import static android.content.Context.WIFI_SERVICE;
+
+public class ConfigureWifiSettings extends DashboardFragment {
+
     private static final String TAG = "ConfigureWifiSettings";
 
-    private static final String KEY_MAC_ADDRESS = "mac_address";
-    private static final String KEY_SAVED_NETWORKS = "saved_networks";
-    private static final String KEY_CURRENT_IP_ADDRESS = "current_ip_address";
-    private static final String KEY_NOTIFY_OPEN_NETWORKS = "notify_open_networks";
-    private static final String KEY_SLEEP_POLICY = "sleep_policy";
-    private static final String KEY_CELLULAR_FALLBACK = "wifi_cellular_data_fallback";
-    private static final String KEY_ALLOW_RECOMMENDATIONS = "allow_recommendations";
-
     private WifiManager mWifiManager;
-    private IntentFilter mFilter;
-
-    @Override
-    public void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-        addPreferencesFromResource(R.xml.wifi_configure_settings);
-    }
-
-    @Override
-    public void onActivityCreated(Bundle savedInstanceState) {
-        super.onActivityCreated(savedInstanceState);
-        mWifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
-        mFilter = new IntentFilter();
-        mFilter.addAction(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION);
-        mFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
-    }
-
-    @Override
-    public void onResume() {
-        super.onResume();
-        initPreferences();
-        getActivity().registerReceiver(mReceiver, mFilter);
-        refreshWifiInfo();
-    }
-
-    @Override
-    public void onPause() {
-        super.onPause();
-        getActivity().unregisterReceiver(mReceiver);
-    }
-
-    private void initPreferences() {
-        List<WifiConfiguration> configs = mWifiManager.getConfiguredNetworks();
-        if (configs == null || configs.size() == 0) {
-            removePreference(KEY_SAVED_NETWORKS);
-        }
-
-        SwitchPreference notifyOpenNetworks =
-                (SwitchPreference) findPreference(KEY_NOTIFY_OPEN_NETWORKS);
-        notifyOpenNetworks.setChecked(Settings.Global.getInt(getContentResolver(),
-                Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 0) == 1);
-        notifyOpenNetworks.setEnabled(mWifiManager.isWifiEnabled());
-
-        final Context context = getActivity();
-        if (avoidBadWifiConfig()) {
-            // Hide preference toggle, always avoid bad wifi networks.
-            removePreference(KEY_CELLULAR_FALLBACK);
-        } else {
-            // Show preference toggle, initialized based on current settings value.
-            boolean currentSetting = avoidBadWifiCurrentSettings();
-            SwitchPreference pref = (SwitchPreference) findPreference(KEY_CELLULAR_FALLBACK);
-            // TODO: can this ever be null? The return value of avoidBadWifiConfig() can only
-            // change if the resources change, but if that happens the activity will be recreated...
-            if (pref != null) {
-                pref.setChecked(currentSetting);
-            }
-        }
-
-        SwitchPreference allowRecommendations =
-            (SwitchPreference) findPreference(KEY_ALLOW_RECOMMENDATIONS);
-        allowRecommendations.setChecked(Settings.Global.getInt(getContentResolver(),
-            Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, 0) == 1);
-
-        ListPreference sleepPolicyPref = (ListPreference) findPreference(KEY_SLEEP_POLICY);
-        if (sleepPolicyPref != null) {
-            if (Utils.isWifiOnly(context)) {
-                sleepPolicyPref.setEntries(R.array.wifi_sleep_policy_entries_wifi_only);
-            }
-            sleepPolicyPref.setOnPreferenceChangeListener(this);
-            int value = Settings.Global.getInt(getContentResolver(),
-                    Settings.Global.WIFI_SLEEP_POLICY,
-                    Settings.Global.WIFI_SLEEP_POLICY_NEVER);
-            String stringValue = String.valueOf(value);
-            sleepPolicyPref.setValue(stringValue);
-            updateSleepPolicySummary(sleepPolicyPref, stringValue);
-        }
-    }
-
-    private void updateSleepPolicySummary(Preference sleepPolicyPref, String value) {
-        if (value != null) {
-            String[] values = getResources().getStringArray(R.array.wifi_sleep_policy_values);
-            final int summaryArrayResId = Utils.isWifiOnly(getActivity()) ?
-                    R.array.wifi_sleep_policy_entries_wifi_only : R.array.wifi_sleep_policy_entries;
-            String[] summaries = getResources().getStringArray(summaryArrayResId);
-            for (int i = 0; i < values.length; i++) {
-                if (value.equals(values[i])) {
-                    if (i < summaries.length) {
-                        sleepPolicyPref.setSummary(summaries[i]);
-                        return;
-                    }
-                }
-            }
-        }
-
-        sleepPolicyPref.setSummary("");
-        Log.e(TAG, "Invalid sleep policy value: " + value);
-    }
-
-    private boolean avoidBadWifiConfig() {
-        return getActivity().getResources().getInteger(
-                com.android.internal.R.integer.config_networkAvoidBadWifi) == 1;
-    }
-
-    private boolean avoidBadWifiCurrentSettings() {
-        return "1".equals(Settings.Global.getString(getContentResolver(),
-                Settings.Global.NETWORK_AVOID_BAD_WIFI));
-    }
-
-    @Override
-    public boolean onPreferenceTreeClick(Preference preference) {
-        String key = preference.getKey();
-
-        if (KEY_NOTIFY_OPEN_NETWORKS.equals(key)) {
-            Settings.Global.putInt(getContentResolver(),
-                    Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,
-                    ((SwitchPreference) preference).isChecked() ? 1 : 0);
-        } else if (KEY_CELLULAR_FALLBACK.equals(key)) {
-            // On: avoid bad wifi. Off: prompt.
-            String settingName = Settings.Global.NETWORK_AVOID_BAD_WIFI;
-            Settings.Global.putString(getContentResolver(), settingName,
-                    ((SwitchPreference) preference).isChecked() ? "1" : null);
-        } else if (KEY_ALLOW_RECOMMENDATIONS.equals(key)) {
-            Settings.Global.putInt(getActivity().getContentResolver(),
-                Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED,
-                ((SwitchPreference) preference).isChecked() ? 1 : 0);
-        } else {
-            return super.onPreferenceTreeClick(preference);
-        }
-        return true;
-    }
-
-    @Override
-    public boolean onPreferenceChange(Preference preference, Object newValue) {
-        final Context context = getActivity();
-        String key = preference.getKey();
-
-        if (KEY_SLEEP_POLICY.equals(key)) {
-            try {
-                String stringValue = (String) newValue;
-                Settings.Global.putInt(getContentResolver(), Settings.Global.WIFI_SLEEP_POLICY,
-                        Integer.parseInt(stringValue));
-                updateSleepPolicySummary(preference, stringValue);
-            } catch (NumberFormatException e) {
-                Toast.makeText(context, R.string.wifi_setting_sleep_policy_error,
-                        Toast.LENGTH_SHORT).show();
-                return false;
-            }
-        }
-
-        return true;
-    }
-
-    private void refreshWifiInfo() {
-        final Context context = getActivity();
-        WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
-
-        Preference wifiMacAddressPref = findPreference(KEY_MAC_ADDRESS);
-        String macAddress = wifiInfo == null ? null : wifiInfo.getMacAddress();
-        wifiMacAddressPref.setSummary(!TextUtils.isEmpty(macAddress) ? macAddress
-                : context.getString(R.string.status_unavailable));
-        wifiMacAddressPref.setSelectable(false);
-
-        Preference wifiIpAddressPref = findPreference(KEY_CURRENT_IP_ADDRESS);
-        String ipAddress = Utils.getWifiIpAddresses(context);
-        wifiIpAddressPref.setSummary(ipAddress == null ?
-                context.getString(R.string.status_unavailable) : ipAddress);
-        wifiIpAddressPref.setSelectable(false);
-    }
 
     @Override
     public int getMetricsCategory() {
         return MetricsEvent.CONFIGURE_WIFI;
     }
 
-    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            String action = intent.getAction();
-            if (action.equals(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION) ||
-                action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
-                refreshWifiInfo();
-            }
-        }
-    };
+    @Override
+    protected String getCategoryKey() {
+        // We don't want to inject any external settings into this screen.
+        return null;
+    }
+
+    @Override
+    protected String getLogTag() {
+        return TAG;
+    }
+
+    @Override
+    protected int getPreferenceScreenResId() {
+        return R.xml.wifi_configure_settings;
+    }
+
+    @Override
+    protected List<PreferenceController> getPreferenceControllers(Context context) {
+        mWifiManager = (WifiManager) getSystemService(WIFI_SERVICE);
+        final List<PreferenceController> controllers = new ArrayList<>();
+        controllers.add(new WifiInfoPreferenceController(context, getLifecycle(), mWifiManager));
+        controllers.add(new SavedNetworkPreferenceController(context, mWifiManager));
+        controllers.add(new NotifyOpenNetworksPreferenceController(context, mWifiManager));
+        controllers.add(new CellularFallbackPreferenceController(context));
+        controllers.add(new AllowRecommendationPreferenceController(context));
+        controllers.add(new WifiSleepPolicyPreferenceController(context));
+        return controllers;
+    }
 }
diff --git a/src/com/android/settings/wifi/NotifyOpenNetworksPreferenceController.java b/src/com/android/settings/wifi/NotifyOpenNetworksPreferenceController.java
new file mode 100644
index 0000000..df3aa26
--- /dev/null
+++ b/src/com/android/settings/wifi/NotifyOpenNetworksPreferenceController.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.wifi;
+
+import android.content.Context;
+import android.net.wifi.WifiManager;
+import android.provider.Settings;
+import android.support.v14.preference.SwitchPreference;
+import android.support.v7.preference.Preference;
+import android.text.TextUtils;
+
+import com.android.settings.core.PreferenceController;
+
+/**
+ * {@link PreferenceController} that controls whether we should notify user when open network is
+ * available.
+ */
+public class NotifyOpenNetworksPreferenceController extends PreferenceController {
+
+    private static final String KEY_NOTIFY_OPEN_NETWORKS = "notify_open_networks";
+    private final WifiManager mWifiManager;
+
+    public NotifyOpenNetworksPreferenceController(Context context, WifiManager wifiManager) {
+        super(context);
+        mWifiManager = wifiManager;
+    }
+
+    @Override
+    public boolean isAvailable() {
+        return true;
+    }
+
+    @Override
+    public boolean handlePreferenceTreeClick(Preference preference) {
+        if (!TextUtils.equals(preference.getKey(), KEY_NOTIFY_OPEN_NETWORKS)) {
+            return false;
+        }
+        if (!(preference instanceof SwitchPreference)) {
+            return false;
+        }
+        Settings.Global.putInt(mContext.getContentResolver(),
+                Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,
+                ((SwitchPreference) preference).isChecked() ? 1 : 0);
+        return true;
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return KEY_NOTIFY_OPEN_NETWORKS;
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        if (!(preference instanceof SwitchPreference)) {
+            return;
+        }
+        final SwitchPreference notifyOpenNetworks = (SwitchPreference) preference;
+        notifyOpenNetworks.setChecked(Settings.Global.getInt(mContext.getContentResolver(),
+                Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 0) == 1);
+        notifyOpenNetworks.setEnabled(mWifiManager.isWifiEnabled());
+    }
+}
diff --git a/src/com/android/settings/wifi/SavedNetworkPreferenceController.java b/src/com/android/settings/wifi/SavedNetworkPreferenceController.java
new file mode 100644
index 0000000..c3ad355
--- /dev/null
+++ b/src/com/android/settings/wifi/SavedNetworkPreferenceController.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.wifi;
+
+import android.content.Context;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiManager;
+
+import com.android.settings.core.PreferenceController;
+
+import java.util.List;
+
+/**
+ * {@link PreferenceController} that opens saved network subsetting.
+ */
+public class SavedNetworkPreferenceController extends PreferenceController {
+
+    private static final String KEY_SAVED_NETWORKS = "saved_networks";
+
+    private final WifiManager mWifiManager;
+
+    public SavedNetworkPreferenceController(Context context, WifiManager wifiManager) {
+        super(context);
+        mWifiManager = wifiManager;
+    }
+
+    @Override
+    public boolean isAvailable() {
+        final List<WifiConfiguration> config = mWifiManager.getConfiguredNetworks();
+        return config != null && !config.isEmpty();
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return KEY_SAVED_NETWORKS;
+    }
+}
diff --git a/src/com/android/settings/wifi/WifiInfoPreferenceController.java b/src/com/android/settings/wifi/WifiInfoPreferenceController.java
new file mode 100644
index 0000000..f88e38b
--- /dev/null
+++ b/src/com/android/settings/wifi/WifiInfoPreferenceController.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.wifi;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.wifi.WifiInfo;
+import android.net.wifi.WifiManager;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceScreen;
+import android.text.TextUtils;
+
+import com.android.settings.R;
+import com.android.settings.Utils;
+import com.android.settings.core.PreferenceController;
+import com.android.settings.core.lifecycle.Lifecycle;
+import com.android.settings.core.lifecycle.LifecycleObserver;
+import com.android.settings.core.lifecycle.events.OnPause;
+import com.android.settings.core.lifecycle.events.OnResume;
+
+/**
+ * {@link PreferenceController} that updates MAC/IP address.
+ */
+public class WifiInfoPreferenceController extends PreferenceController implements
+        LifecycleObserver, OnResume, OnPause {
+
+    private static final String KEY_CURRENT_IP_ADDRESS = "current_ip_address";
+    private static final String KEY_MAC_ADDRESS = "mac_address";
+
+    private final IntentFilter mFilter;
+    private final WifiManager mWifiManager;
+
+    private Preference mWifiMacAddressPref;
+    private Preference mWifiIpAddressPref;
+
+    public WifiInfoPreferenceController(Context context, Lifecycle lifecycle,
+            WifiManager wifiManager) {
+        super(context);
+        mWifiManager = wifiManager;
+        mFilter = new IntentFilter();
+        mFilter.addAction(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION);
+        mFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
+
+        lifecycle.addObserver(this);
+    }
+
+    @Override
+    public boolean isAvailable() {
+        return true;
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        // Returns null because this controller contains more than 1 preference.
+        return null;
+    }
+
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        super.displayPreference(screen);
+        mWifiMacAddressPref = screen.findPreference(KEY_MAC_ADDRESS);
+        mWifiMacAddressPref.setSelectable(false);
+        mWifiIpAddressPref = screen.findPreference(KEY_CURRENT_IP_ADDRESS);
+        mWifiIpAddressPref.setSelectable(false);
+    }
+
+    @Override
+    public void onResume() {
+        mContext.registerReceiver(mReceiver, mFilter);
+        updateWifiInfo();
+    }
+
+    @Override
+    public void onPause() {
+        mContext.unregisterReceiver(mReceiver);
+    }
+
+    public void updateWifiInfo() {
+        if (mWifiMacAddressPref != null) {
+            final WifiInfo wifiInfo = mWifiManager.getConnectionInfo();
+            final String macAddress = wifiInfo == null ? null : wifiInfo.getMacAddress();
+            mWifiMacAddressPref.setSummary(!TextUtils.isEmpty(macAddress)
+                    ? macAddress
+                    : mContext.getString(R.string.status_unavailable));
+        }
+        if (mWifiIpAddressPref != null) {
+            final String ipAddress = Utils.getWifiIpAddresses(mContext);
+            mWifiIpAddressPref.setSummary(ipAddress == null
+                    ? mContext.getString(R.string.status_unavailable)
+                    : ipAddress);
+        }
+    }
+
+    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (action.equals(WifiManager.LINK_CONFIGURATION_CHANGED_ACTION) ||
+                    action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
+                updateWifiInfo();
+            }
+        }
+    };
+}
diff --git a/src/com/android/settings/wifi/WifiSleepPolicyPreferenceController.java b/src/com/android/settings/wifi/WifiSleepPolicyPreferenceController.java
new file mode 100644
index 0000000..3e7911b
--- /dev/null
+++ b/src/com/android/settings/wifi/WifiSleepPolicyPreferenceController.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.wifi;
+
+import android.content.Context;
+import android.provider.Settings;
+import android.support.v7.preference.ListPreference;
+import android.support.v7.preference.Preference;
+import android.util.Log;
+import android.widget.Toast;
+
+import com.android.settings.R;
+import com.android.settings.Utils;
+import com.android.settings.core.PreferenceController;
+
+import static com.android.internal.os.MemoryPowerCalculator.TAG;
+
+public class WifiSleepPolicyPreferenceController extends PreferenceController implements
+        Preference.OnPreferenceChangeListener {
+
+    private static final String KEY_SLEEP_POLICY = "sleep_policy";
+
+    public WifiSleepPolicyPreferenceController(Context context) {
+        super(context);
+    }
+
+    @Override
+    public boolean isAvailable() {
+        return true;
+    }
+
+    @Override
+    public String getPreferenceKey() {
+        return KEY_SLEEP_POLICY;
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        ListPreference sleepPolicyPref = (ListPreference) preference;
+        if (sleepPolicyPref != null) {
+            if (Utils.isWifiOnly(mContext)) {
+                sleepPolicyPref.setEntries(R.array.wifi_sleep_policy_entries_wifi_only);
+            }
+            int value = Settings.Global.getInt(mContext.getContentResolver(),
+                    Settings.Global.WIFI_SLEEP_POLICY,
+                    Settings.Global.WIFI_SLEEP_POLICY_NEVER);
+            String stringValue = String.valueOf(value);
+            sleepPolicyPref.setValue(stringValue);
+            updateSleepPolicySummary(sleepPolicyPref, stringValue);
+        }
+    }
+
+    @Override
+    public boolean onPreferenceChange(Preference preference, Object newValue) {
+        try {
+            String stringValue = (String) newValue;
+            Settings.Global.putInt(mContext.getContentResolver(), Settings.Global.WIFI_SLEEP_POLICY,
+                    Integer.parseInt(stringValue));
+            updateSleepPolicySummary(preference, stringValue);
+        } catch (NumberFormatException e) {
+            Toast.makeText(mContext, R.string.wifi_setting_sleep_policy_error,
+                    Toast.LENGTH_SHORT).show();
+            return false;
+        }
+        return true;
+    }
+
+    private void updateSleepPolicySummary(Preference sleepPolicyPref, String value) {
+        if (value != null) {
+            String[] values = mContext.getResources().getStringArray(R.array
+                    .wifi_sleep_policy_values);
+            final int summaryArrayResId = Utils.isWifiOnly(mContext)
+                    ? R.array.wifi_sleep_policy_entries_wifi_only
+                    : R.array.wifi_sleep_policy_entries;
+            String[] summaries = mContext.getResources().getStringArray(summaryArrayResId);
+            for (int i = 0; i < values.length; i++) {
+                if (value.equals(values[i])) {
+                    if (i < summaries.length) {
+                        sleepPolicyPref.setSummary(summaries[i]);
+                        return;
+                    }
+                }
+            }
+        }
+
+        sleepPolicyPref.setSummary("");
+        Log.e(TAG, "Invalid sleep policy value: " + value);
+    }
+
+}
diff --git a/tests/robotests/assets/grandfather_not_implementing_index_provider b/tests/robotests/assets/grandfather_not_implementing_index_provider
index 05cd93b..ffaf615 100644
--- a/tests/robotests/assets/grandfather_not_implementing_index_provider
+++ b/tests/robotests/assets/grandfather_not_implementing_index_provider
@@ -2,4 +2,5 @@
 com.android.settings.language.LanguageAndRegionSettings
 com.android.settings.notification.ZenModePrioritySettings
 com.android.settings.inputmethod.InputAndGestureSettings
-com.android.settings.accounts.AccountDetailDashboardFragment
\ No newline at end of file
+com.android.settings.accounts.AccountDetailDashboardFragment
+com.android.settings.wifi.ConfigureWifiSettings
\ No newline at end of file
diff --git a/tests/robotests/src/com/android/settings/wifi/AllowRecommendationPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/wifi/AllowRecommendationPreferenceControllerTest.java
new file mode 100644
index 0000000..d33854a
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/wifi/AllowRecommendationPreferenceControllerTest.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.wifi;
+
+import android.content.Context;
+import android.provider.Settings;
+import android.support.v14.preference.SwitchPreference;
+import android.support.v7.preference.Preference;
+
+import com.android.settings.SettingsRobolectricTestRunner;
+import com.android.settings.TestConfig;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+import static com.google.common.truth.Truth.assertThat;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class AllowRecommendationPreferenceControllerTest {
+
+    private Context mContext;
+    private AllowRecommendationPreferenceController mController;
+
+
+    @Before
+    public void setUp() {
+        mContext = RuntimeEnvironment.application;
+        mController = new AllowRecommendationPreferenceController(mContext);
+    }
+
+    @Test
+    public void testIsAvailable_shouldAlwaysReturnTrue() {
+        assertThat(mController.isAvailable()).isTrue();
+    }
+
+    @Test
+    public void handlePreferenceTreeClick_nonMatchingKey_shouldDoNothing() {
+        final SwitchPreference pref = new SwitchPreference(mContext);
+
+        assertThat(mController.handlePreferenceTreeClick(pref)).isFalse();
+    }
+
+    @Test
+    public void handlePreferenceTreeClick_nonMatchingType_shouldDoNothing() {
+        final Preference pref = new Preference(mContext);
+        pref.setKey(mController.getPreferenceKey());
+
+        assertThat(mController.handlePreferenceTreeClick(pref)).isFalse();
+    }
+
+
+    @Test
+    public void handlePreferenceTreeClick_matchingKeyAndType_shouldUpdateSetting() {
+        final SwitchPreference pref = new SwitchPreference(mContext);
+        pref.setKey(mController.getPreferenceKey());
+
+        // Turn on
+        pref.setChecked(true);
+        assertThat(mController.handlePreferenceTreeClick(pref)).isTrue();
+        assertThat(Settings.Global.getInt(mContext.getContentResolver(),
+                Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, 0))
+                .isEqualTo(1);
+
+        // Turn off
+        pref.setChecked(false);
+        assertThat(mController.handlePreferenceTreeClick(pref)).isTrue();
+        assertThat(Settings.Global.getInt(mContext.getContentResolver(),
+                Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED, 0))
+                .isEqualTo(0);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/wifi/CellularFallbackPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/wifi/CellularFallbackPreferenceControllerTest.java
new file mode 100644
index 0000000..bf564a5
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/wifi/CellularFallbackPreferenceControllerTest.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.wifi;
+
+import android.content.Context;
+import android.net.wifi.WifiManager;
+
+import com.android.settings.SettingsRobolectricTestRunner;
+import com.android.settings.TestConfig;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Answers;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.when;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class CellularFallbackPreferenceControllerTest {
+
+    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+    private Context mContext;
+    @Mock
+    private WifiManager mWifiManager;
+
+    private CellularFallbackPreferenceController mController;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mController = new CellularFallbackPreferenceController(mContext);
+    }
+
+    @Test
+    public void isAvailable_avoidBadWifiConfigIsFalse_shouldReturnTrue() {
+        when(mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_networkAvoidBadWifi))
+                .thenReturn(0);
+
+        assertThat(mController.isAvailable()).isTrue();
+    }
+
+    @Test
+    public void isAvailable_avoidBadWifiConfigIsTrue_shouldReturnFalse() {
+        when(mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_networkAvoidBadWifi))
+                .thenReturn(1);
+
+        assertThat(mController.isAvailable()).isFalse();
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/wifi/NotifyOpenNetworkPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/wifi/NotifyOpenNetworkPreferenceControllerTest.java
new file mode 100644
index 0000000..aa12787
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/wifi/NotifyOpenNetworkPreferenceControllerTest.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.wifi;
+
+import android.content.Context;
+import android.net.wifi.WifiManager;
+import android.provider.Settings;
+import android.support.v14.preference.SwitchPreference;
+import android.support.v7.preference.Preference;
+
+import com.android.settings.SettingsRobolectricTestRunner;
+import com.android.settings.TestConfig;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+import static com.google.common.truth.Truth.assertThat;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class NotifyOpenNetworkPreferenceControllerTest {
+
+    @Mock
+    private WifiManager mWifiManager;
+    private Context mContext;
+    private NotifyOpenNetworksPreferenceController mController;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = RuntimeEnvironment.application;
+        mController = new NotifyOpenNetworksPreferenceController(mContext, mWifiManager);
+    }
+
+    @Test
+    public void testIsAvailable_shouldAlwaysReturnTrue() {
+        assertThat(mController.isAvailable()).isTrue();
+    }
+
+    @Test
+    public void handlePreferenceTreeClick_nonMatchingKey_shouldDoNothing() {
+        final SwitchPreference pref = new SwitchPreference(mContext);
+
+        assertThat(mController.handlePreferenceTreeClick(pref)).isFalse();
+    }
+
+    @Test
+    public void handlePreferenceTreeClick_nonMatchingType_shouldDoNothing() {
+        final Preference pref = new Preference(mContext);
+        pref.setKey(mController.getPreferenceKey());
+
+        assertThat(mController.handlePreferenceTreeClick(pref)).isFalse();
+    }
+
+
+    @Test
+    public void handlePreferenceTreeClick_matchingKeyAndType_shouldUpdateSetting() {
+        final SwitchPreference pref = new SwitchPreference(mContext);
+        pref.setChecked(true);
+        pref.setKey(mController.getPreferenceKey());
+
+        assertThat(mController.handlePreferenceTreeClick(pref)).isTrue();
+        assertThat(Settings.Global.getInt(mContext.getContentResolver(),
+                Settings.Global.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 0))
+                .isEqualTo(1);
+    }
+
+}
diff --git a/tests/robotests/src/com/android/settings/wifi/SavedNetworkPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/wifi/SavedNetworkPreferenceControllerTest.java
new file mode 100644
index 0000000..657c21e
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/wifi/SavedNetworkPreferenceControllerTest.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.wifi;
+
+import android.content.Context;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiManager;
+
+import com.android.settings.SettingsRobolectricTestRunner;
+import com.android.settings.TestConfig;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+
+import java.util.List;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class SavedNetworkPreferenceControllerTest {
+
+    @Mock
+    private Context mContext;
+    @Mock
+    private WifiManager mWifiManager;
+
+    private SavedNetworkPreferenceController mController;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        mController = new SavedNetworkPreferenceController(mContext, mWifiManager);
+    }
+
+    @Test
+    public void isAvailable_noSavedNetwork_shouldReturnFalse() {
+        when(mWifiManager.getConfiguredNetworks()).thenReturn(null);
+        assertThat(mController.isAvailable()).isFalse();
+    }
+
+    @Test
+    public void isAvailable_hasSavedNetwork_shouldReturnTrue() {
+        List<WifiConfiguration> configs = mock(List.class);
+        when(configs.isEmpty()).thenReturn(false);
+        when(mWifiManager.getConfiguredNetworks()).thenReturn(configs);
+
+        assertThat(mController.isAvailable()).isTrue();
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/wifi/WifiInfoPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/wifi/WifiInfoPreferenceControllerTest.java
new file mode 100644
index 0000000..40c480f
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/wifi/WifiInfoPreferenceControllerTest.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settings.wifi;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.IntentFilter;
+import android.net.wifi.WifiManager;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceScreen;
+
+import com.android.settings.SettingsRobolectricTestRunner;
+import com.android.settings.TestConfig;
+import com.android.settings.core.lifecycle.Lifecycle;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Answers;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class WifiInfoPreferenceControllerTest {
+
+    @Mock
+    private Context mContext;
+    @Mock(answer = Answers.RETURNS_DEEP_STUBS)
+    private WifiManager mWifiManager;
+    @Mock
+    private PreferenceScreen mScreen;
+    @Mock
+    private Preference mIpPreference;
+    @Mock
+    private Preference mMacPreference;
+
+    private Lifecycle mLifecycle;
+    private WifiInfoPreferenceController mController;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mLifecycle = new Lifecycle();
+        when(mContext.getSystemService(WifiManager.class))
+                .thenReturn(mWifiManager);
+        when(mScreen.findPreference(anyString()))
+                .thenReturn(mMacPreference)
+                .thenReturn(mIpPreference);
+        mController = new WifiInfoPreferenceController(mContext, mLifecycle, mWifiManager);
+    }
+
+    @Test
+    public void testIsAvailable_shouldAlwaysReturnTrue() {
+        assertThat(mController.isAvailable()).isTrue();
+    }
+
+    @Test
+    public void getPreferenceKey_shouldReturnNull() {
+        assertThat(mController.getPreferenceKey()).isNull();
+    }
+
+    @Test
+    public void runThroughLifecycle_shouldInstallListenerOnResume() {
+        mLifecycle.onResume();
+        verify(mContext).registerReceiver(any(BroadcastReceiver.class), any(IntentFilter.class));
+
+        mLifecycle.onPause();
+        verify(mContext).unregisterReceiver(any(BroadcastReceiver.class));
+    }
+
+    @Test
+    public void onResume_shouldUpdateWifiInfo() {
+        when(mWifiManager.getCurrentNetwork()).thenReturn(null);
+
+        mController.displayPreference(mScreen);
+        mController.onResume();
+
+        verify(mMacPreference).setSummary(any());
+        verify(mIpPreference).setSummary(any());
+    }
+}