Merge "DO NOT MERGE" into pi-car-dev
diff --git a/res/layout/access_point_preference_widget.xml b/res/layout/access_point_preference_widget.xml
new file mode 100644
index 0000000..6e7f54c
--- /dev/null
+++ b/res/layout/access_point_preference_widget.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 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.
+-->
+
+<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/right_icon"
+    style="@style/ListIcon"
+    android:layout_marginEnd="@dimen/car_keyline_1"
+    android:layout_alignParentEnd="true"
+    android:layout_centerVertical="true"
+    android:src="@drawable/ic_chevron_right"
+    android:tint="@color/text_body_1"/>
diff --git a/res/values/preference_keys.xml b/res/values/preference_keys.xml
index 2845868..bb37235 100644
--- a/res/values/preference_keys.xml
+++ b/res/values/preference_keys.xml
@@ -51,6 +51,9 @@
     <string name="pk_wifi_subnet_mask" translatable="false">wifi_subnet_mask</string>
     <string name="pk_wifi_dns" translatable="false">wifi_dns</string>
     <string name="pk_wifi_link_speed" translatable="false">wifi_link_speed</string>
+    <string name="pk_wifi_list" translatable="false">wifi_list</string>
+    <string name="pk_add_wifi" translatable="false">add_wifi</string>
+    <string name="pk_wifi_status" translatable="false">wifi_status</string>
 
     <!-- Applications Settings -->
     <string name="pk_applications_settings_screen" translatable="false">
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 9be6e4f..1eb51ef 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -42,14 +42,16 @@
     <string name="wifi_starting">Turning Wi\u2011Fi on\u2026</string>
     <!-- Summary text when turning Wi-Fi or bluetooth off -->
     <string name="wifi_stopping">Turning off Wi\u2011Fi\u2026</string>
+    <!-- Summary text when loading Wi-Fi list -->
+    <string name="loading_wifi_list">Loading Wi\u2011Fi list</string>
+    <!-- Summary text shown in place of the Wi-Fi list when wifi is off -->
+    <string name="wifi_disabled">Wi\u2011Fi disabled</string>
     <!-- Failured notification for forget -->
     <string name="wifi_failed_forget_message">Failed to forget network</string>
     <!-- Failured notification for connect -->
     <string name="wifi_failed_connect_message">Failed to connect to network</string>
     <!-- Button message shown on the button adding manual setting. Used in Wifi Setup For Setup Wizard with XL screen. -->
     <string name="wifi_setup_add_network">Add network</string>
-    <!-- Summary text when Wi-Fi is turned off -->
-    <string name="wifi_disabled">Wi\u2011Fi disabled</string>
     <!-- Button label to connect to a Wi-Fi network. Used in SetupWizard for XLarge screen [CHAR LIMIT=10] -->
     <string name="wifi_setup_connect">Connect</string>
     <!-- Label for the password of the secured network -->
diff --git a/res/xml/wifi_list_fragment.xml b/res/xml/wifi_list_fragment.xml
new file mode 100644
index 0000000..e177b66
--- /dev/null
+++ b/res/xml/wifi_list_fragment.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 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.
+-->
+
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
+                  xmlns:settings="http://schemas.android.com/apk/res-auto"
+                  android:title="@string/wifi_settings">
+    <Preference
+        android:key="@string/pk_wifi_status"
+        settings:controller="com.android.car.settings.wifi.WifiStatusPreferenceController"/>
+    <com.android.car.settings.common.LogicalPreferenceGroup
+        android:key="@string/pk_wifi_list"
+        settings:controller="com.android.car.settings.wifi.AccessPointListPreferenceController"/>
+    <Preference
+        android:key="@string/pk_add_wifi"
+        android:title="@string/wifi_setup_add_network"
+        settings:controller="com.android.car.settings.wifi.AddWifiPreferenceController"/>
+</PreferenceScreen>
diff --git a/src/com/android/car/settings/quicksettings/WifiTile.java b/src/com/android/car/settings/quicksettings/WifiTile.java
index e2e222d..a6272f4 100644
--- a/src/com/android/car/settings/quicksettings/WifiTile.java
+++ b/src/com/android/car/settings/quicksettings/WifiTile.java
@@ -56,7 +56,8 @@
             fragmentController.launchFragment(new WifiSettingsFragment());
             return true;
         };
-        mCarWifiManager = new CarWifiManager(context, /* listener= */ this);
+        mCarWifiManager = new CarWifiManager(context);
+        mCarWifiManager.addListener(this);
         mCarWifiManager.start();
         mStateChangedListener = stateChangedListener;
         // init icon and text etc.
@@ -92,6 +93,7 @@
 
     @Override
     public void stop() {
+        mCarWifiManager.removeListener(this);
         mCarWifiManager.stop();
         mCarWifiManager.destroy();
     }
diff --git a/src/com/android/car/settings/wifi/AccessPointListAdapter.java b/src/com/android/car/settings/wifi/AccessPointListAdapter.java
deleted file mode 100644
index 0424b89..0000000
--- a/src/com/android/car/settings/wifi/AccessPointListAdapter.java
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * Copyright (C) 2018 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.car.settings.wifi;
-
-import android.content.Context;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.StateListDrawable;
-import android.net.wifi.WifiManager;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.view.ViewGroup;
-import android.widget.ImageView;
-import android.widget.TextView;
-import android.widget.Toast;
-
-import androidx.annotation.NonNull;
-import androidx.car.widget.PagedListView;
-import androidx.recyclerview.widget.RecyclerView;
-
-import com.android.car.settings.R;
-import com.android.car.settings.common.FragmentController;
-import com.android.car.settings.wifi.details.WifiDetailFragment;
-import com.android.settingslib.wifi.AccessPoint;
-
-import java.util.List;
-
-/**
- * Renders {@link AccessPoint} to a view to be displayed as a row in a list.
- */
-public class AccessPointListAdapter
-        extends RecyclerView.Adapter<AccessPointListAdapter.ViewHolder>
-        implements PagedListView.ItemCap {
-    private static final int NETWORK_ROW_TYPE = 1;
-    private static final int ADD_NETWORK_ROW_TYPE = 2;
-
-    private static final int[] STATE_SECURED = {
-            com.android.settingslib.R.attr.state_encrypted
-    };
-    private static final int[] STATE_NONE = {};
-    private static int[] wifi_signal_attributes = {com.android.settingslib.R.attr.wifi_signal};
-
-    private final StateListDrawable mWifiSld;
-    private final Context mContext;
-    private final FragmentController mFragmentController;
-    private final CarWifiManager mCarWifiManager;
-    private final WifiManager.ActionListener mConnectionListener;
-    private boolean mShowAddNetworkRow;
-
-    private List<AccessPoint> mAccessPoints;
-
-    public AccessPointListAdapter(
-            @NonNull Context context,
-            CarWifiManager carWifiManager,
-            @NonNull List<AccessPoint> accesssPoints,
-            FragmentController fragmentController) {
-        mContext = context;
-        mFragmentController = fragmentController;
-        mCarWifiManager = carWifiManager;
-        mAccessPoints = accesssPoints;
-        mWifiSld = (StateListDrawable) context.getTheme()
-                .obtainStyledAttributes(wifi_signal_attributes).getDrawable(0);
-
-        mConnectionListener = new WifiManager.ActionListener() {
-            @Override
-            public void onSuccess() {
-            }
-
-            @Override
-            public void onFailure(int reason) {
-                Toast.makeText(mContext,
-                        R.string.wifi_failed_connect_message,
-                        Toast.LENGTH_SHORT).show();
-            }
-        };
-    }
-
-    /**
-     * Toggles the row that links to add a new network.
-     */
-    public AccessPointListAdapter showAddNetworkRow(boolean show) {
-        mShowAddNetworkRow = show;
-        return this;
-    }
-
-    public void updateAccessPoints(@NonNull List<AccessPoint> accesssPoints) {
-        mAccessPoints = accesssPoints;
-        notifyDataSetChanged();
-    }
-
-    public boolean isEmpty() {
-        return mAccessPoints.isEmpty();
-    }
-
-    public class ViewHolder extends RecyclerView.ViewHolder {
-        private final ImageView mIcon;
-        private final ImageView mRightChevron;
-        private final TextView mWifiName;
-        private final TextView mWifiDesc;
-
-        public ViewHolder(View view) {
-            super(view);
-            mWifiName = (TextView) view.findViewById(R.id.title);
-            mWifiDesc = (TextView) view.findViewById(R.id.desc);
-            mIcon = (ImageView) view.findViewById(R.id.icon);
-            mRightChevron = (ImageView) view.findViewById(R.id.right_chevron);
-        }
-    }
-
-    private class AccessPointClickListener implements OnClickListener {
-        private final AccessPoint mAccessPoint;
-
-        public AccessPointClickListener(AccessPoint accessPoint) {
-            mAccessPoint = accessPoint;
-        }
-
-        @Override
-        public void onClick(View v) {
-            // for new open unsecuried wifi network, connect to it right away
-            if (mAccessPoint.getSecurity() == AccessPoint.SECURITY_NONE &&
-                    !mAccessPoint.isSaved() && !mAccessPoint.isActive()) {
-                mCarWifiManager.connectToPublicWifi(mAccessPoint, mConnectionListener);
-            } else if (mAccessPoint.isSaved()) {
-                mFragmentController.launchFragment(WifiDetailFragment.getInstance(mAccessPoint));
-            } else {
-                mFragmentController.launchFragment(AddWifiFragment.getInstance(mAccessPoint));
-            }
-        }
-    }
-
-    @Override
-    public int getItemViewType(int position) {
-        // the last row is the add device row
-        if (position == mAccessPoints.size()) {
-            return ADD_NETWORK_ROW_TYPE;
-        }
-        return NETWORK_ROW_TYPE;
-    }
-
-    @Override
-    public AccessPointListAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
-            int viewType) {
-        ViewHolder viewHolder = new ViewHolder(LayoutInflater.from(parent.getContext())
-                .inflate(R.layout.icon_text_list_item, parent, false));
-        if (viewType == ADD_NETWORK_ROW_TYPE) {
-            viewHolder.mIcon.setImageResource(R.drawable.ic_add);
-            viewHolder.mWifiDesc.setVisibility(View.GONE);
-            viewHolder.mWifiName.setText(R.string.wifi_setup_add_network);
-            viewHolder.itemView.setOnClickListener(v -> {
-                mFragmentController.launchFragment(AddWifiFragment.getInstance(null));
-            });
-        }
-        return viewHolder;
-    }
-
-    @Override
-    public void onBindViewHolder(ViewHolder holder, int position) {
-        // for the last row, it's the "add network button", no more binding needed.
-        if (position >= mAccessPoints.size()) {
-            return;
-        }
-        AccessPoint accessPoint = mAccessPoints.get(position);
-        holder.itemView.setOnClickListener(new AccessPointClickListener(accessPoint));
-        holder.mWifiName.setText(accessPoint.getConfigName());
-        holder.mIcon.setImageDrawable(getIcon(accessPoint));
-        String summary = accessPoint.getSummary();
-        if (summary != null && !summary.isEmpty()) {
-            holder.mWifiDesc.setText(summary);
-            holder.mWifiDesc.setVisibility(View.VISIBLE);
-        } else {
-            holder.mWifiDesc.setVisibility(View.GONE);
-        }
-        if (accessPoint.getSecurity() == accessPoint.SECURITY_NONE &&
-                !accessPoint.isSaved() && !accessPoint.isActive()) {
-            holder.mRightChevron.setVisibility(View.GONE);
-        } else {
-            holder.mRightChevron.setVisibility(View.VISIBLE);
-        }
-    }
-
-    @Override
-    public int getItemCount() {
-        // number of rows include one per device and a row for add network.
-        return mShowAddNetworkRow ? mAccessPoints.size() + 1 : mAccessPoints.size();
-    }
-
-    @Override
-    public void setMaxItems(int maxItems) {
-        // no limit in this list.
-    }
-
-    private Drawable getIcon(AccessPoint accessPoint) {
-        mWifiSld.setState((accessPoint.getSecurity() != AccessPoint.SECURITY_NONE)
-                ? STATE_SECURED
-                : STATE_NONE);
-        Drawable drawable = mWifiSld.getCurrent();
-        drawable.setLevel(accessPoint.getLevel());
-        drawable.invalidateSelf();
-        return drawable;
-    }
-}
diff --git a/src/com/android/car/settings/wifi/AccessPointListPreferenceController.java b/src/com/android/car/settings/wifi/AccessPointListPreferenceController.java
new file mode 100644
index 0000000..3e7b5ca
--- /dev/null
+++ b/src/com/android/car/settings/wifi/AccessPointListPreferenceController.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2018 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.car.settings.wifi;
+
+import android.car.drivingstate.CarUxRestrictions;
+import android.content.Context;
+import android.net.wifi.WifiManager;
+import android.widget.Toast;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceGroup;
+import androidx.preference.PreferenceScreen;
+
+import com.android.car.settings.R;
+import com.android.car.settings.common.CarUxRestrictionsHelper;
+import com.android.car.settings.common.FragmentController;
+import com.android.car.settings.common.Logger;
+import com.android.car.settings.wifi.details.WifiDetailFragment;
+import com.android.settingslib.wifi.AccessPoint;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Renders a list of {@link AccessPoint} as a list of preference.
+ */
+public class AccessPointListPreferenceController extends WifiPreferenceControllerBase {
+    private static final Logger LOG = new Logger(AccessPointListPreferenceController.class);
+    private PreferenceGroup mPreferenceGroup;
+    private List<AccessPoint> mAccessPoints = new ArrayList<>();
+    private boolean mShowSavedApOnly;
+
+    private final WifiManager.ActionListener mConnectionListener =
+            new WifiManager.ActionListener() {
+                @Override
+                public void onSuccess() {
+                }
+
+                @Override
+                public void onFailure(int reason) {
+                    Toast.makeText(mContext,
+                            R.string.wifi_failed_connect_message,
+                            Toast.LENGTH_SHORT).show();
+                }
+            };
+
+    public AccessPointListPreferenceController(
+            @NonNull Context context,
+            String preferenceKey,
+            FragmentController fragmentController) {
+        super(context, preferenceKey, fragmentController);
+    }
+
+    @Override
+    public void updateState(Preference preference) {
+        refreshData();
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        return WifiUtil.isWifiAvailable(mContext) ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
+    }
+
+    @Override
+    public void onAccessPointsChanged() {
+        refreshData();
+    }
+
+    @Override
+    public void onWifiStateChanged(int state) {
+        // don't care
+    }
+
+    @Override
+    public void onUxRestrictionsChanged(CarUxRestrictions restrictionInfo) {
+        super.onUxRestrictionsChanged(restrictionInfo);
+        mShowSavedApOnly = CarUxRestrictionsHelper.isNoSetup(restrictionInfo);
+        refreshData();
+    }
+
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        mPreferenceGroup = (PreferenceGroup) screen.findPreference(getPreferenceKey());
+        updatePreferenceList();
+    }
+
+    @Override
+    public boolean handlePreferenceTreeClick(Preference preference) {
+        AccessPoint accessPoint = ((AccessPointPreference) preference).getAccessPoint();
+        // for new open unsecuried wifi network, connect to it right away
+        if (accessPoint.getSecurity() == AccessPoint.SECURITY_NONE
+                && !accessPoint.isSaved() && !accessPoint.isActive()) {
+            getCarWifiManager().connectToPublicWifi(accessPoint, mConnectionListener);
+        } else if (accessPoint.isSaved()) {
+            getFragmentController().launchFragment(WifiDetailFragment.getInstance(accessPoint));
+        } else {
+            getFragmentController().launchFragment(AddWifiFragment.getInstance(accessPoint));
+        }
+        return true;
+    }
+
+    @VisibleForTesting
+    void refreshData() {
+        if (mCarWifiManager == null) {
+            return;
+        }
+        mAccessPoints = mShowSavedApOnly
+            ? getCarWifiManager().getSavedAccessPoints()
+            : getCarWifiManager().getAllAccessPoints();
+        LOG.d("showing accessPoints: " + mAccessPoints.size());
+        updatePreferenceList();
+    }
+
+    private void updatePreferenceList() {
+        mPreferenceGroup.setVisible(!mAccessPoints.isEmpty());
+        mPreferenceGroup.removeAll();
+        for (AccessPoint accessPoint : mAccessPoints) {
+            LOG.d("Adding preference for " + WifiUtil.getKey(accessPoint));
+            AccessPointPreference accessPointPreference = new AccessPointPreference(
+                    mContext, accessPoint);
+            mPreferenceGroup.addPreference(accessPointPreference);
+        }
+    }
+}
diff --git a/src/com/android/car/settings/wifi/AccessPointPreference.java b/src/com/android/car/settings/wifi/AccessPointPreference.java
new file mode 100644
index 0000000..bf746b5
--- /dev/null
+++ b/src/com/android/car/settings/wifi/AccessPointPreference.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2018 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.car.settings.wifi;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.StateListDrawable;
+import android.text.TextUtils;
+
+import androidx.preference.Preference;
+
+import com.android.car.settings.R;
+import com.android.car.settings.common.Logger;
+import com.android.settingslib.wifi.AccessPoint;
+
+/**
+ * Renders a {@link AccessPoint} as a preference.
+ */
+public class AccessPointPreference extends Preference {
+    private static final Logger LOG = new Logger(AccessPointPreference.class);
+    private static final int[] STATE_SECURED = {
+            com.android.settingslib.R.attr.state_encrypted
+    };
+    private static final int[] STATE_NONE = {};
+    private static int[] sWifiSignalAttributes = {com.android.settingslib.R.attr.wifi_signal};
+
+    private final StateListDrawable mWifiSld;
+
+    private final AccessPoint mAccessPoint;
+
+    public AccessPointPreference(
+            Context context,
+            AccessPoint accessPoint) {
+        super(context);
+        mWifiSld = (StateListDrawable) context.getTheme()
+                .obtainStyledAttributes(sWifiSignalAttributes).getDrawable(0);
+        mAccessPoint = accessPoint;
+        LOG.d("creating preference for ap: " + mAccessPoint);
+        setKey(WifiUtil.getKey(accessPoint));
+        setIcon(getAccessPointIcon());
+        setTitle(accessPoint.getConfigName());
+        String summary = accessPoint.getSummary();
+        if (!TextUtils.isEmpty(summary)) {
+            setSummary(summary);
+        }
+        if (accessPoint.isSaved()) {
+            setWidgetLayoutResource(R.layout.access_point_preference_widget);
+        }
+    }
+
+    /**
+     * Returns the {@link AccessPoint}.
+     */
+    public AccessPoint getAccessPoint() {
+        return mAccessPoint;
+    }
+
+    private Drawable getAccessPointIcon() {
+        if (mWifiSld == null) {
+            LOG.w("wifiSld is null.");
+            return null;
+        }
+        mWifiSld.setState(
+                (mAccessPoint.getSecurity() != AccessPoint.SECURITY_NONE)
+                ? STATE_SECURED
+                : STATE_NONE);
+        Drawable drawable = mWifiSld.getCurrent();
+        LOG.d("Getting icon for ap level: " + mAccessPoint.getLevel());
+        drawable.setLevel(mAccessPoint.getLevel());
+        drawable.invalidateSelf();
+        return drawable;
+    }
+}
diff --git a/src/com/android/car/settings/wifi/AddWifiPreferenceController.java b/src/com/android/car/settings/wifi/AddWifiPreferenceController.java
new file mode 100644
index 0000000..6bc0016
--- /dev/null
+++ b/src/com/android/car/settings/wifi/AddWifiPreferenceController.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2018 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.car.settings.wifi;
+
+import android.content.Context;
+import android.net.wifi.WifiManager;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+import com.android.car.settings.common.FragmentController;
+
+/**
+ * Controls preference for adding wifi.
+ */
+public class AddWifiPreferenceController extends WifiPreferenceControllerBase {
+    private Preference mPreference;
+
+    public AddWifiPreferenceController(Context context, String preferenceKey,
+            FragmentController fragmentController) {
+        super(context, preferenceKey, fragmentController);
+    }
+
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        super.displayPreference(screen);
+
+        mPreference = screen.findPreference(getPreferenceKey());
+    }
+
+    @Override
+    public void onWifiStateChanged(int state) {
+        switch (state) {
+            case WifiManager.WIFI_STATE_DISABLED:
+                mPreference.setVisible(false);
+                break;
+            default:
+                mPreference.setVisible(true);
+        }
+    }
+}
diff --git a/src/com/android/car/settings/wifi/CarWifiManager.java b/src/com/android/car/settings/wifi/CarWifiManager.java
index ec448d3..98ca010 100644
--- a/src/com/android/car/settings/wifi/CarWifiManager.java
+++ b/src/com/android/car/settings/wifi/CarWifiManager.java
@@ -33,7 +33,7 @@
  */
 public class CarWifiManager implements WifiTracker.WifiListener {
     private final Context mContext;
-    private Listener mListener;
+    private final List<Listener> mListeners = new ArrayList<>();
     private boolean mStarted;
 
     private WifiTracker mWifiTracker;
@@ -60,14 +60,27 @@
         void onWifiStateChanged(int state);
     }
 
-    public CarWifiManager(Context context, Listener listener) {
+    public CarWifiManager(Context context) {
         mContext = context;
-        mListener = listener;
         mWifiManager = (WifiManager) mContext.getSystemService(WifiManager.class);
         mWifiTracker = new WifiTracker(context, this, true, true);
     }
 
     /**
+     * Adds {@link Listener}.
+     */
+    public boolean addListener(Listener listener) {
+        return mListeners.add(listener);
+    }
+
+    /**
+     * Removes {@link Listener}.
+     */
+    public boolean removeListener(Listener listener) {
+        return mListeners.remove(listener);
+    }
+
+    /**
      * Starts {@link CarWifiManager}.
      * This should be called only from main thread.
      */
@@ -161,7 +174,9 @@
 
     @Override
     public void onWifiStateChanged(int state) {
-        mListener.onWifiStateChanged(state);
+        for (Listener listener : mListeners) {
+            listener.onWifiStateChanged(state);
+        }
     }
 
     @Override
@@ -170,6 +185,8 @@
 
     @Override
     public void onAccessPointsChanged() {
-        mListener.onAccessPointsChanged();
+        for (Listener listener : mListeners) {
+            listener.onAccessPointsChanged();
+        }
     }
 }
diff --git a/src/com/android/car/settings/wifi/WifiPreferenceControllerBase.java b/src/com/android/car/settings/wifi/WifiPreferenceControllerBase.java
new file mode 100644
index 0000000..7756967
--- /dev/null
+++ b/src/com/android/car/settings/wifi/WifiPreferenceControllerBase.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2018 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.car.settings.wifi;
+
+import android.content.Context;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.LifecycleObserver;
+import androidx.lifecycle.OnLifecycleEvent;
+
+import com.android.car.settings.common.BasePreferenceController;
+import com.android.car.settings.common.FragmentController;
+
+/**
+ * Abstract controls preference for Wifi.
+ */
+public abstract class WifiPreferenceControllerBase extends BasePreferenceController
+        implements CarWifiManager.Listener, LifecycleObserver {
+
+    @VisibleForTesting
+    CarWifiManager mCarWifiManager;
+
+    public WifiPreferenceControllerBase(Context context, String preferenceKey,
+            FragmentController fragmentController) {
+        super(context, preferenceKey, fragmentController);
+    }
+
+    /**
+     * Initializes {@link CarWifiManager}. Seprate this function out, so it's easier to test.
+     */
+    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
+    public void initCarWifiManager() {
+        mCarWifiManager = new CarWifiManager(mContext);
+    }
+
+    /**
+     * Starts listening on {@link CarWifiManager}. Called when Fragment is onStart.
+     */
+    @OnLifecycleEvent(Lifecycle.Event.ON_START)
+    public void startListening() {
+        mCarWifiManager.addListener(this);
+        mCarWifiManager.start();
+    }
+
+    /**
+     * Stops listening on {@link CarWifiManager}. Called when Fragment is onStop.
+     */
+    @OnLifecycleEvent(Lifecycle.Event.ON_STOP)
+    public void stopListening() {
+        mCarWifiManager.removeListener(this);
+        mCarWifiManager.stop();
+    }
+
+    /**
+     * Cleans up {@link CarWifiManager}. Called when Fragment is onDestroy.
+     */
+    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
+    public void destroyCarWifiManager() {
+        mCarWifiManager.destroy();
+    }
+
+    @Override
+    public int getAvailabilityStatus() {
+        return WifiUtil.isWifiAvailable(mContext) ? AVAILABLE : UNSUPPORTED_ON_DEVICE;
+    }
+
+    @Override
+    public void onAccessPointsChanged() {
+        // don't care
+    }
+
+    protected CarWifiManager getCarWifiManager() {
+        return mCarWifiManager;
+    }
+}
diff --git a/src/com/android/car/settings/wifi/WifiSettingsFragment.java b/src/com/android/car/settings/wifi/WifiSettingsFragment.java
index 62ba64f..2c2f07e 100644
--- a/src/com/android/car/settings/wifi/WifiSettingsFragment.java
+++ b/src/com/android/car/settings/wifi/WifiSettingsFragment.java
@@ -15,35 +15,26 @@
  */
 package com.android.car.settings.wifi;
 
-import android.car.drivingstate.CarUxRestrictions;
 import android.net.wifi.WifiManager;
 import android.os.Bundle;
 import android.view.View;
 import android.widget.ProgressBar;
 import android.widget.Switch;
-import android.widget.TextView;
-import android.widget.ViewSwitcher;
 
 import androidx.annotation.LayoutRes;
-import androidx.annotation.StringRes;
-import androidx.car.widget.PagedListView;
+import androidx.annotation.XmlRes;
 
 import com.android.car.settings.R;
-import com.android.car.settings.common.BaseFragment;
-import com.android.car.settings.common.CarUxRestrictionsHelper;
+import com.android.car.settings.common.BasePreferenceFragment;
 
 /**
  * Main page to host Wifi related preferences.
  */
-public class WifiSettingsFragment extends BaseFragment implements CarWifiManager.Listener {
+public class WifiSettingsFragment extends BasePreferenceFragment
+        implements CarWifiManager.Listener {
     private CarWifiManager mCarWifiManager;
-    private AccessPointListAdapter mAdapter;
-    private Switch mWifiSwitch;
     private ProgressBar mProgressBar;
-    private PagedListView mListView;
-    private TextView mMessageView;
-    private ViewSwitcher mViewSwitcher;
-    private boolean mShowSavedApOnly;
+    private Switch mWifiSwitch;
 
     @Override
     @LayoutRes
@@ -52,47 +43,24 @@
     }
 
     @Override
-    @LayoutRes
-    protected int getLayoutId() {
-        return R.layout.wifi_list;
-    }
-
-    @Override
-    @StringRes
-    protected int getTitleId() {
-        return R.string.wifi_settings;
+    @XmlRes
+    protected int getPreferenceScreenResId() {
+        return R.xml.wifi_list_fragment;
     }
 
     @Override
     public void onActivityCreated(Bundle savedInstanceState) {
         super.onActivityCreated(savedInstanceState);
-        mCarWifiManager = new CarWifiManager(getContext(), /* listener= */ this);
+        mCarWifiManager = new CarWifiManager(getContext());
 
         mProgressBar = requireActivity().findViewById(R.id.progress_bar);
-        mListView = getView().findViewById(R.id.list);
-        mMessageView = getView().findViewById(R.id.message);
-        mViewSwitcher = getView().findViewById(R.id.view_switcher);
         setupWifiSwitch();
-        if (mCarWifiManager.isWifiEnabled()) {
-            showList();
-            setProgressBarVisible(true);
-        } else {
-            showMessage(R.string.wifi_disabled);
-        }
-        mAdapter = new AccessPointListAdapter(
-                getContext(),
-                mCarWifiManager,
-                mShowSavedApOnly
-                        ? mCarWifiManager.getSavedAccessPoints()
-                        : mCarWifiManager.getAllAccessPoints(),
-                getFragmentController());
-        mAdapter.showAddNetworkRow(!mShowSavedApOnly);
-        mListView.setAdapter(mAdapter);
     }
 
     @Override
     public void onStart() {
         super.onStart();
+        mCarWifiManager.addListener(this);
         mCarWifiManager.start();
         onWifiStateChanged(mCarWifiManager.getWifiState());
     }
@@ -100,8 +68,9 @@
     @Override
     public void onStop() {
         super.onStop();
+        mCarWifiManager.removeListener(this);
         mCarWifiManager.stop();
-        setProgressBarVisible(false);
+        mProgressBar.setVisibility(View.GONE);
     }
 
     @Override
@@ -112,7 +81,7 @@
 
     @Override
     public void onAccessPointsChanged() {
-        refreshData();
+        // don't care
     }
 
     @Override
@@ -120,66 +89,10 @@
         mWifiSwitch.setChecked(mCarWifiManager.isWifiEnabled());
         switch (state) {
             case WifiManager.WIFI_STATE_ENABLING:
-                showList();
-                setProgressBarVisible(true);
-                break;
-            case WifiManager.WIFI_STATE_DISABLED:
-                setProgressBarVisible(false);
-                showMessage(R.string.wifi_disabled);
+                mProgressBar.setVisibility(View.VISIBLE);
                 break;
             default:
-                showList();
-        }
-    }
-
-    /**
-     * This fragment will adapt to restriction, so can always be shown.
-     */
-    @Override
-    public boolean canBeShown(CarUxRestrictions carUxRestrictions) {
-        return true;
-    }
-
-    @Override
-    public void onUxRestrictionsChanged(CarUxRestrictions restrictionInfo) {
-        mShowSavedApOnly = CarUxRestrictionsHelper.isNoSetup(restrictionInfo);
-        refreshData();
-    }
-
-    private void setProgressBarVisible(boolean visible) {
-        if (mProgressBar != null) {
-            mProgressBar.setVisibility(visible ? View.VISIBLE : View.GONE);
-        }
-    }
-
-    private void refreshData() {
-        if (mAdapter != null) {
-            mAdapter.showAddNetworkRow(!mShowSavedApOnly);
-            mAdapter.updateAccessPoints(mShowSavedApOnly
-                    ? mCarWifiManager.getSavedAccessPoints()
-                    : mCarWifiManager.getAllAccessPoints());
-            // if the list is empty, keep showing the progress bar, the list should reset
-            // every couple seconds.
-            // TODO: Consider show a message in the list view place.
-            if (!mAdapter.isEmpty()) {
-                setProgressBarVisible(false);
-            }
-        }
-        if (mCarWifiManager != null) {
-            mWifiSwitch.setChecked(mCarWifiManager.isWifiEnabled());
-        }
-    }
-
-    private void showMessage(@StringRes int resId) {
-        if (mViewSwitcher.getCurrentView() != mMessageView) {
-            mViewSwitcher.showNext();
-        }
-        mMessageView.setText(getResources().getString(resId));
-    }
-
-    private void showList() {
-        if (mViewSwitcher.getCurrentView() != mListView) {
-            mViewSwitcher.showPrevious();
+                mProgressBar.setVisibility(View.GONE);
         }
     }
 
@@ -187,8 +100,8 @@
         mWifiSwitch = (Switch) getActivity().findViewById(R.id.toggle_switch);
         mWifiSwitch.setChecked(mCarWifiManager.isWifiEnabled());
         mWifiSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> {
-            if (mWifiSwitch.isChecked() != mCarWifiManager.isWifiEnabled()) {
-                mCarWifiManager.setWifiEnabled(mWifiSwitch.isChecked());
+            if (isChecked != mCarWifiManager.isWifiEnabled()) {
+                mCarWifiManager.setWifiEnabled(isChecked);
             }
         });
     }
diff --git a/src/com/android/car/settings/wifi/WifiStatusPreferenceController.java b/src/com/android/car/settings/wifi/WifiStatusPreferenceController.java
new file mode 100644
index 0000000..81e84ee
--- /dev/null
+++ b/src/com/android/car/settings/wifi/WifiStatusPreferenceController.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2018 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.car.settings.wifi;
+
+import android.content.Context;
+import android.net.wifi.WifiManager;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceScreen;
+
+import com.android.car.settings.R;
+import com.android.car.settings.common.FragmentController;
+
+/**
+ * Controls preference when Wifi is in disabled or enabling state
+ */
+public class WifiStatusPreferenceController extends WifiPreferenceControllerBase {
+    private Preference mPreference;
+
+    public WifiStatusPreferenceController(Context context, String preferenceKey,
+            FragmentController fragmentController) {
+        super(context, preferenceKey, fragmentController);
+    }
+
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        super.displayPreference(screen);
+
+        mPreference = screen.findPreference(getPreferenceKey());
+    }
+
+    @Override
+    public void onWifiStateChanged(int state) {
+        switch (state) {
+            case WifiManager.WIFI_STATE_DISABLED:
+                mPreference.setVisible(true);
+                mPreference.setTitle(R.string.wifi_disabled);
+                break;
+            case WifiManager.WIFI_STATE_ENABLING:
+                mPreference.setVisible(true);
+                mPreference.setTitle(R.string.loading_wifi_list);
+                break;
+            default:
+                mPreference.setVisible(false);
+        }
+    }
+}
diff --git a/src/com/android/car/settings/wifi/WifiUtil.java b/src/com/android/car/settings/wifi/WifiUtil.java
index 36df13a..49ec87d 100644
--- a/src/com/android/car/settings/wifi/WifiUtil.java
+++ b/src/com/android/car/settings/wifi/WifiUtil.java
@@ -29,6 +29,7 @@
 import androidx.annotation.StringRes;
 
 import com.android.car.settings.R;
+import com.android.settingslib.wifi.AccessPoint;
 
 /**
  * A collections of util functions for WIFI.
@@ -80,6 +81,13 @@
     }
 
     /**
+     * Gets a unique key for a {@link AccessPoint}.
+     */
+    public static String getKey(AccessPoint accessPoint) {
+        return String.valueOf(accessPoint.hashCode());
+    }
+
+    /**
      * This method is a stripped and negated version of WifiConfigStore.canModifyNetwork.
      *
      * @param context Context of caller
diff --git a/tests/robotests/src/com/android/car/settings/wifi/AccessPointListPreferenceControllerTest.java b/tests/robotests/src/com/android/car/settings/wifi/AccessPointListPreferenceControllerTest.java
new file mode 100644
index 0000000..4dcc3d2
--- /dev/null
+++ b/tests/robotests/src/com/android/car/settings/wifi/AccessPointListPreferenceControllerTest.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2018 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.car.settings.wifi;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.when;
+
+import android.car.drivingstate.CarUxRestrictions;
+import android.content.Context;
+
+import androidx.preference.PreferenceCategory;
+import androidx.preference.PreferenceManager;
+import androidx.preference.PreferenceScreen;
+
+import com.android.car.settings.CarSettingsRobolectricTestRunner;
+import com.android.car.settings.common.FragmentController;
+import com.android.settingslib.wifi.AccessPoint;
+
+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 java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+@RunWith(CarSettingsRobolectricTestRunner.class)
+public class AccessPointListPreferenceControllerTest {
+    private static final String PREFERENCE_KEY = "somePreferenceKey";
+    private static final int SIGNAL_LEVEL = 1;
+
+    @Mock
+    private FragmentController mMockFragmentController;
+    @Mock
+    private AccessPoint mMockAccessPoint;
+    @Mock
+    private CarWifiManager mMockCarWifiManager;
+
+    private PreferenceScreen mPreferenceScreen;
+    private PreferenceCategory mPreferenceCategory;
+    private Context mContext;
+    private AccessPointListPreferenceController mController;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = RuntimeEnvironment.application;
+        mPreferenceScreen = new PreferenceManager(mContext).createPreferenceScreen(mContext);
+        mPreferenceCategory = new PreferenceCategory(mContext);
+        mPreferenceCategory.setKey(PREFERENCE_KEY);
+        mPreferenceScreen.addPreference(mPreferenceCategory);
+        mController = new AccessPointListPreferenceController(
+                mContext, PREFERENCE_KEY, mMockFragmentController);
+        mController.mCarWifiManager = mMockCarWifiManager;
+
+        when(mMockAccessPoint.getSecurity()).thenReturn(AccessPoint.SECURITY_NONE);
+        when(mMockAccessPoint.getLevel()).thenReturn(SIGNAL_LEVEL);
+    }
+
+    @Test
+    public void updateAccessPoints_emptyList_notVisible() {
+        mController.displayPreference(mPreferenceScreen);
+        when(mMockCarWifiManager.getAllAccessPoints()).thenReturn(new ArrayList<>());
+        mController.refreshData();
+
+        assertThat(mPreferenceCategory.isVisible()).isEqualTo(false);
+    }
+
+    @Test
+    public void updateAccessPoints_notEmpty_visible() {
+        mController.displayPreference(mPreferenceScreen);
+        List<AccessPoint> accessPointList = Arrays.asList(mMockAccessPoint);
+        when(mMockCarWifiManager.getAllAccessPoints()).thenReturn(accessPointList);
+        mController.refreshData();
+
+        assertThat(mPreferenceCategory.isVisible()).isEqualTo(true);
+    }
+
+    @Test
+    public void updateAccessPoints_notEmpty_listCount() {
+        mController.displayPreference(mPreferenceScreen);
+        List<AccessPoint> accessPointList = Arrays.asList(mMockAccessPoint);
+        when(mMockCarWifiManager.getAllAccessPoints()).thenReturn(accessPointList);
+        mController.refreshData();
+
+        assertThat(mPreferenceCategory.getPreferenceCount()).isEqualTo(accessPointList.size());
+    }
+
+    @Test
+    public void onUxRestrictionsChanged_switchToSavedApOnly() {
+        mController.displayPreference(mPreferenceScreen);
+        List<AccessPoint> allAccessPointList = Arrays.asList(mMockAccessPoint, mMockAccessPoint);
+        when(mMockCarWifiManager.getAllAccessPoints()).thenReturn(allAccessPointList);
+        List<AccessPoint> savedAccessPointList = Arrays.asList(mMockAccessPoint);
+        when(mMockCarWifiManager.getSavedAccessPoints()).thenReturn(savedAccessPointList);
+        mController.refreshData();
+
+        assertThat(mPreferenceCategory.getPreferenceCount()).isEqualTo(allAccessPointList.size());
+
+        CarUxRestrictions noSetupRestrictions = new CarUxRestrictions.Builder(
+                true, CarUxRestrictions.UX_RESTRICTIONS_NO_SETUP, 0).build();
+        mController.onUxRestrictionsChanged(noSetupRestrictions);
+        assertThat(mPreferenceCategory.getPreferenceCount()).isEqualTo(savedAccessPointList.size());
+    }
+}
diff --git a/tests/robotests/src/com/android/car/settings/wifi/AddWifiPreferenceControllerTest.java b/tests/robotests/src/com/android/car/settings/wifi/AddWifiPreferenceControllerTest.java
new file mode 100644
index 0000000..3d261cd
--- /dev/null
+++ b/tests/robotests/src/com/android/car/settings/wifi/AddWifiPreferenceControllerTest.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2018 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.car.settings.wifi;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.net.wifi.WifiManager;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceManager;
+import androidx.preference.PreferenceScreen;
+
+import com.android.car.settings.CarSettingsRobolectricTestRunner;
+import com.android.car.settings.common.FragmentController;
+
+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 java.util.Arrays;
+import java.util.List;
+
+@RunWith(CarSettingsRobolectricTestRunner.class)
+public class AddWifiPreferenceControllerTest {
+    private static final String PREFERENCE_KEY = "somePreferenceKey";
+    private static final List<Integer> VISIBLE_STATES = Arrays.asList(
+            WifiManager.WIFI_STATE_ENABLED,
+            WifiManager.WIFI_STATE_DISABLING,
+            WifiManager.WIFI_STATE_ENABLING,
+            WifiManager.WIFI_STATE_UNKNOWN);
+    private static final List<Integer> INVISIBLE_STATES = Arrays.asList(
+            WifiManager.WIFI_STATE_DISABLED);
+
+    @Mock
+    private FragmentController mMockFragmentController;
+
+    private PreferenceScreen mPreferenceScreen;
+    private Preference mPreference;
+    private Context mContext;
+    private AddWifiPreferenceController mController;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = RuntimeEnvironment.application;
+        mPreferenceScreen = new PreferenceManager(mContext).createPreferenceScreen(mContext);
+        mPreference = new Preference(mContext);
+        mPreference.setKey(PREFERENCE_KEY);
+        mPreferenceScreen.addPreference(mPreference);
+        mController = new AddWifiPreferenceController(
+                mContext, PREFERENCE_KEY, mMockFragmentController);
+        mController.displayPreference(mPreferenceScreen);
+    }
+
+    @Test
+    public void onWifiStateChanged_invisible() {
+        for (int state : INVISIBLE_STATES) {
+            mController.onWifiStateChanged(state);
+            assertThat(mPreference.isVisible()).isEqualTo(false);
+        }
+    }
+
+    @Test
+    public void onWifiStateChanged_visible() {
+        for (int state : VISIBLE_STATES) {
+            mController.onWifiStateChanged(state);
+            assertThat(mPreference.isVisible()).isEqualTo(true);
+        }
+    }
+}
diff --git a/tests/robotests/src/com/android/car/settings/wifi/WifiStatusPreferenceControllerTest.java b/tests/robotests/src/com/android/car/settings/wifi/WifiStatusPreferenceControllerTest.java
new file mode 100644
index 0000000..6bda6b1
--- /dev/null
+++ b/tests/robotests/src/com/android/car/settings/wifi/WifiStatusPreferenceControllerTest.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2018 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.car.settings.wifi;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+import android.net.wifi.WifiManager;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceManager;
+import androidx.preference.PreferenceScreen;
+
+import com.android.car.settings.CarSettingsRobolectricTestRunner;
+import com.android.car.settings.R;
+import com.android.car.settings.common.FragmentController;
+
+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 java.util.Arrays;
+import java.util.List;
+
+@RunWith(CarSettingsRobolectricTestRunner.class)
+public class WifiStatusPreferenceControllerTest {
+    private static final String PREFERENCE_KEY = "somePreferenceKey";
+    private static final List<Integer> VISIBLE_STATES = Arrays.asList(
+            WifiManager.WIFI_STATE_DISABLED,
+            WifiManager.WIFI_STATE_ENABLING);
+    private static final List<Integer> INVISIBLE_STATES = Arrays.asList(
+            WifiManager.WIFI_STATE_ENABLED,
+            WifiManager.WIFI_STATE_DISABLING,
+            WifiManager.WIFI_STATE_UNKNOWN);
+
+    @Mock
+    private FragmentController mMockFragmentController;
+
+    private PreferenceScreen mPreferenceScreen;
+    private Preference mPreference;
+    private Context mContext;
+    private WifiStatusPreferenceController mController;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = RuntimeEnvironment.application;
+        mPreferenceScreen = new PreferenceManager(mContext).createPreferenceScreen(mContext);
+        mPreference = new Preference(mContext);
+        mPreference.setKey(PREFERENCE_KEY);
+        mPreferenceScreen.addPreference(mPreference);
+        mController = new WifiStatusPreferenceController(
+                mContext, PREFERENCE_KEY, mMockFragmentController);
+        mController.displayPreference(mPreferenceScreen);
+    }
+
+    @Test
+    public void onWifiStateChanged_invisible() {
+        for (int state : INVISIBLE_STATES) {
+            mController.onWifiStateChanged(state);
+            assertThat(mPreference.isVisible()).isEqualTo(false);
+        }
+    }
+
+    @Test
+    public void onWifiStateChanged_visible() {
+        for (int state : VISIBLE_STATES) {
+            mController.onWifiStateChanged(state);
+            assertThat(mPreference.isVisible()).isEqualTo(true);
+        }
+    }
+
+    @Test
+    public void onWifiStateChanged_disabled() {
+        mController.onWifiStateChanged(WifiManager.WIFI_STATE_DISABLED);
+        assertThat(mPreference.getTitle())
+                .isEqualTo(mContext.getResources().getString(R.string.wifi_disabled));
+    }
+
+    @Test
+    public void onWifiStateChanged_enabling() {
+        mController.onWifiStateChanged(WifiManager.WIFI_STATE_ENABLING);
+        assertThat(mPreference.getTitle())
+                .isEqualTo(mContext.getResources().getString(R.string.loading_wifi_list));
+    }
+}