Merge "Move logic from SavedAccessPoint fragment to controller"
diff --git a/src/com/android/settings/utils/PreferenceGroupChildrenCache.java b/src/com/android/settings/utils/PreferenceGroupChildrenCache.java
new file mode 100644
index 0000000..dcbf4fd
--- /dev/null
+++ b/src/com/android/settings/utils/PreferenceGroupChildrenCache.java
@@ -0,0 +1,59 @@
+/*
+ * 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.settings.utils;
+
+import android.text.TextUtils;
+import android.util.ArrayMap;
+
+import androidx.preference.Preference;
+import androidx.preference.PreferenceGroup;
+
+/**
+ * Class that helps track which {@link Preference}s in a {@link PreferenceGroup} are still being
+ * used, and remove unused ones.
+ */
+public class PreferenceGroupChildrenCache {
+
+    private ArrayMap<String, Preference> mPreferenceCache;
+
+    public void cacheRemoveAllPrefs(PreferenceGroup group) {
+        mPreferenceCache = new ArrayMap<>();
+        final int N = group.getPreferenceCount();
+        for (int i = 0; i < N; i++) {
+            Preference p = group.getPreference(i);
+            if (TextUtils.isEmpty(p.getKey())) {
+                continue;
+            }
+            mPreferenceCache.put(p.getKey(), p);
+        }
+    }
+
+    public void removeCachedPrefs(PreferenceGroup group) {
+        for (Preference p : mPreferenceCache.values()) {
+            group.removePreference(p);
+        }
+        mPreferenceCache = null;
+    }
+
+    public Preference getCachedPreference(String key) {
+        return mPreferenceCache != null ? mPreferenceCache.remove(key) : null;
+    }
+
+    public int getCachedCount() {
+        return mPreferenceCache != null ? mPreferenceCache.size() : 0;
+    }
+}
diff --git a/src/com/android/settings/wifi/WifiDialog.java b/src/com/android/settings/wifi/WifiDialog.java
index 79500e0..8c2739f 100644
--- a/src/com/android/settings/wifi/WifiDialog.java
+++ b/src/com/android/settings/wifi/WifiDialog.java
@@ -27,11 +27,15 @@
 import com.android.settingslib.RestrictedLockUtils;
 import com.android.settingslib.wifi.AccessPoint;
 
-public class WifiDialog extends AlertDialog implements WifiConfigUiBase, DialogInterface.OnClickListener {
+public class WifiDialog extends AlertDialog implements WifiConfigUiBase,
+        DialogInterface.OnClickListener {
 
     public interface WifiDialogListener {
-        void onForget(WifiDialog dialog);
-        void onSubmit(WifiDialog dialog);
+        default void onForget(WifiDialog dialog) {
+        }
+
+        default void onSubmit(WifiDialog dialog) {
+        }
     }
 
     private static final int BUTTON_SUBMIT = DialogInterface.BUTTON_POSITIVE;
@@ -64,7 +68,7 @@
     }
 
     /* package */ WifiDialog(Context context, WifiDialogListener listener, AccessPoint accessPoint,
-        int mode, int style, boolean hideSubmitButton) {
+            int mode, int style, boolean hideSubmitButton) {
         super(context, style);
         mMode = mode;
         mListener = listener;
@@ -99,8 +103,8 @@
     }
 
     public void onRestoreInstanceState(Bundle savedInstanceState) {
-            super.onRestoreInstanceState(savedInstanceState);
-            mController.updatePassword();
+        super.onRestoreInstanceState(savedInstanceState);
+        mController.updatePassword();
     }
 
     @Override
diff --git a/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java b/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java
index d291f9c..bda3b76 100644
--- a/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java
+++ b/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java
@@ -542,11 +542,6 @@
     }
 
     @Override
-    public void onForget(WifiDialog dialog) {
-        // can't forget network from a 'modify' dialog
-    }
-
-    @Override
     public void onSubmit(WifiDialog dialog) {
         if (dialog.getController() != null) {
             mWifiManager.save(dialog.getController().getConfig(), new WifiManager.ActionListener() {
diff --git a/src/com/android/settings/wifi/savedaccesspoints/SavedAccessPointsPreferenceController.java b/src/com/android/settings/wifi/savedaccesspoints/SavedAccessPointsPreferenceController.java
index a7c4038..dea4443 100644
--- a/src/com/android/settings/wifi/savedaccesspoints/SavedAccessPointsPreferenceController.java
+++ b/src/com/android/settings/wifi/savedaccesspoints/SavedAccessPointsPreferenceController.java
@@ -18,21 +18,127 @@
 
 
 import android.content.Context;
+import android.net.wifi.WifiManager;
+import android.util.Log;
+
+import androidx.annotation.VisibleForTesting;
+import androidx.preference.Preference;
+import androidx.preference.PreferenceGroup;
+import androidx.preference.PreferenceScreen;
 
 import com.android.settings.core.BasePreferenceController;
+import com.android.settings.utils.PreferenceGroupChildrenCache;
+import com.android.settingslib.core.lifecycle.LifecycleObserver;
+import com.android.settingslib.core.lifecycle.events.OnStart;
+import com.android.settingslib.utils.ThreadUtils;
+import com.android.settingslib.wifi.AccessPoint;
+import com.android.settingslib.wifi.AccessPointPreference;
+import com.android.settingslib.wifi.AccessPointPreference.UserBadgeCache;
+import com.android.settingslib.wifi.WifiSavedConfigUtils;
+
+import java.util.Collections;
+import java.util.List;
 
 /**
- * Controller that manages a PrferenceGroup, which contains a list of saved access points.
+ * Controller that manages a PreferenceGroup, which contains a list of saved access points.
  */
-public class SavedAccessPointsPreferenceController extends BasePreferenceController {
+public class SavedAccessPointsPreferenceController extends BasePreferenceController implements
+        LifecycleObserver, OnStart, Preference.OnPreferenceClickListener,
+        WifiManager.ActionListener {
+
+    private static final String TAG = "SavedAPPrefCtrl";
+
+    private final WifiManager mWifiManager;
+    private final PreferenceGroupChildrenCache mChildrenCache;
+
+    private final UserBadgeCache mUserBadgeCache;
+    private PreferenceGroup mPreferenceGroup;
+    private SavedAccessPointsWifiSettings mHost;
 
     public SavedAccessPointsPreferenceController(Context context,
             String preferenceKey) {
         super(context, preferenceKey);
+        mUserBadgeCache = new AccessPointPreference.UserBadgeCache(context.getPackageManager());
+        mWifiManager = context.getSystemService(WifiManager.class);
+        mChildrenCache = new PreferenceGroupChildrenCache();
+    }
+
+    public SavedAccessPointsPreferenceController setHost(SavedAccessPointsWifiSettings host) {
+        mHost = host;
+        return this;
     }
 
     @Override
     public int getAvailabilityStatus() {
         return AVAILABLE;
     }
+
+    @Override
+    public void displayPreference(PreferenceScreen screen) {
+        super.displayPreference(screen);
+        mPreferenceGroup = (PreferenceGroup) screen.findPreference(getPreferenceKey());
+    }
+
+    @Override
+    public void onStart() {
+        refreshSavedAccessPoints();
+    }
+
+    public void postRefreshSavedAccessPoints() {
+        ThreadUtils.postOnMainThread(() -> refreshSavedAccessPoints());
+    }
+
+    @Override
+    public boolean onPreferenceClick(Preference preference) {
+        if (mHost != null) {
+            mHost.showWifiDialog((AccessPointPreference) preference);
+        }
+        return false;
+    }
+
+    @Override
+    public void onSuccess() {
+        postRefreshSavedAccessPoints();
+    }
+
+    @Override
+    public void onFailure(int reason) {
+        postRefreshSavedAccessPoints();
+    }
+
+    @VisibleForTesting
+    void refreshSavedAccessPoints() {
+        if (mPreferenceGroup == null) {
+            Log.w(TAG, "PreferenceGroup is null, skipping.");
+            return;
+        }
+        final Context prefContext = mPreferenceGroup.getContext();
+
+        final List<AccessPoint> accessPoints =
+                WifiSavedConfigUtils.getAllConfigs(mContext, mWifiManager);
+        Collections.sort(accessPoints, SavedNetworkComparator.INSTANCE);
+        mChildrenCache.cacheRemoveAllPrefs(mPreferenceGroup);
+
+        final int accessPointsSize = accessPoints.size();
+        for (int i = 0; i < accessPointsSize; ++i) {
+            AccessPoint ap = accessPoints.get(i);
+            String key = ap.getKey();
+            AccessPointPreference preference =
+                    (AccessPointPreference) mChildrenCache.getCachedPreference(key);
+            if (preference == null) {
+                preference = new AccessPointPreference(ap, prefContext, mUserBadgeCache, true);
+                preference.setKey(key);
+                preference.setIcon(null);
+                preference.setOnPreferenceClickListener(this);
+                mPreferenceGroup.addPreference(preference);
+            }
+            preference.setOrder(i);
+        }
+
+        mChildrenCache.removeCachedPrefs(mPreferenceGroup);
+
+        if (mPreferenceGroup.getPreferenceCount() < 1) {
+            Log.w(TAG, "Saved networks activity loaded, but there are no saved networks!");
+        }
+    }
 }
diff --git a/src/com/android/settings/wifi/savedaccesspoints/SavedAccessPointsWifiSettings.java b/src/com/android/settings/wifi/savedaccesspoints/SavedAccessPointsWifiSettings.java
index 930cd85..8f14ec2 100644
--- a/src/com/android/settings/wifi/savedaccesspoints/SavedAccessPointsWifiSettings.java
+++ b/src/com/android/settings/wifi/savedaccesspoints/SavedAccessPointsWifiSettings.java
@@ -17,18 +17,12 @@
 package com.android.settings.wifi.savedaccesspoints;
 
 import android.annotation.Nullable;
-import android.app.Activity;
 import android.app.Dialog;
 import android.content.Context;
+import android.content.DialogInterface;
 import android.net.wifi.WifiManager;
 import android.os.Bundle;
-import android.os.Handler;
 import android.util.Log;
-import android.widget.Toast;
-
-import androidx.annotation.VisibleForTesting;
-import androidx.preference.Preference;
-import androidx.preference.PreferenceScreen;
 
 import com.android.internal.logging.nano.MetricsProto;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -39,68 +33,19 @@
 import com.android.settings.wifi.WifiSettings;
 import com.android.settingslib.wifi.AccessPoint;
 import com.android.settingslib.wifi.AccessPointPreference;
-import com.android.settingslib.wifi.WifiSavedConfigUtils;
-
-import java.util.Collections;
-import java.util.List;
 
 /**
  * UI to manage saved networks/access points.
  */
 public class SavedAccessPointsWifiSettings extends DashboardFragment
-        implements WifiDialog.WifiDialogListener {
+        implements WifiDialog.WifiDialogListener, DialogInterface.OnCancelListener {
+
     private static final String TAG = "SavedAccessPoints";
-    @VisibleForTesting
-    static final int MSG_UPDATE_PREFERENCES = 1;
 
-    @VisibleForTesting
-    final WifiManager.ActionListener mForgetListener = new WifiManager.ActionListener() {
-        @Override
-        public void onSuccess() {
-            postUpdatePreference();
-        }
-
-        @Override
-        public void onFailure(int reason) {
-            postUpdatePreference();
-        }
-    };
-
-    @VisibleForTesting
-    final Handler mHandler = new Handler() {
-        @Override
-        public void handleMessage(android.os.Message msg) {
-            if (msg.what == MSG_UPDATE_PREFERENCES) {
-                initPreferences();
-            }
-        }
-    };
-
-    private final WifiManager.ActionListener mSaveListener = new WifiManager.ActionListener() {
-        @Override
-        public void onSuccess() {
-            postUpdatePreference();
-        }
-
-        @Override
-        public void onFailure(int reason) {
-            Activity activity = getActivity();
-            if (activity != null) {
-                Toast.makeText(activity,
-                        R.string.wifi_failed_save_message,
-                        Toast.LENGTH_SHORT).show();
-            }
-        }
-    };
-
-    private WifiDialog mDialog;
     private WifiManager mWifiManager;
-    private AccessPoint mDlgAccessPoint;
     private Bundle mAccessPointSavedState;
     private AccessPoint mSelectedAccessPoint;
 
-    private AccessPointPreference.UserBadgeCache mUserBadgeCache;
-
     // Instance state key
     private static final String SAVE_DIALOG_ACCESS_POINT_STATE = "wifi_ap_state";
 
@@ -122,21 +67,15 @@
     @Override
     public void onAttach(Context context) {
         super.onAttach(context);
-        mUserBadgeCache = new AccessPointPreference.UserBadgeCache(getPackageManager());
-    }
-
-    @Override
-    public void onResume() {
-        super.onResume();
-        initPreferences();
-    }
-
-    @Override
-    public void onActivityCreated(Bundle savedInstanceState) {
-        super.onActivityCreated(savedInstanceState);
         mWifiManager = (WifiManager) getContext()
                 .getApplicationContext().getSystemService(Context.WIFI_SERVICE);
+        use(SavedAccessPointsPreferenceController.class)
+                .setHost(this);
+    }
 
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
         if (savedInstanceState != null) {
             if (savedInstanceState.containsKey(SAVE_DIALOG_ACCESS_POINT_STATE)) {
                 mAccessPointSavedState =
@@ -145,55 +84,15 @@
         }
     }
 
-    private void initPreferences() {
-        PreferenceScreen preferenceScreen = getPreferenceScreen();
-        final Context context = getPrefContext();
-
-        final List<AccessPoint> accessPoints =
-                WifiSavedConfigUtils.getAllConfigs(context, mWifiManager);
-        Collections.sort(accessPoints, SavedNetworkComparator.INSTANCE);
-        cacheRemoveAllPrefs(preferenceScreen);
-
-        final int accessPointsSize = accessPoints.size();
-        for (int i = 0; i < accessPointsSize; ++i) {
-            AccessPoint ap = accessPoints.get(i);
-            String key = ap.getKey();
-            AccessPointPreference preference =
-                    (AccessPointPreference) getCachedPreference(key);
-            if (preference == null) {
-                preference = new AccessPointPreference(ap, context, mUserBadgeCache, true);
-                preference.setKey(key);
-                preference.setIcon(null);
-                preferenceScreen.addPreference(preference);
-            }
-            preference.setOrder(i);
-        }
-
-        removeCachedPrefs(preferenceScreen);
-
-        if (getPreferenceScreen().getPreferenceCount() < 1) {
-            Log.w(TAG, "Saved networks activity loaded, but there are no saved networks!");
-        }
-    }
-
-    private void postUpdatePreference() {
-        if (!mHandler.hasMessages(MSG_UPDATE_PREFERENCES)) {
-            mHandler.sendEmptyMessage(MSG_UPDATE_PREFERENCES);
-        }
-    }
-
-    private void showWifiDialog(@Nullable AccessPointPreference accessPoint) {
-        if (mDialog != null) {
-            removeDialog(WifiSettings.WIFI_DIALOG_ID);
-            mDialog = null;
-        }
+    public void showWifiDialog(@Nullable AccessPointPreference accessPoint) {
+        removeDialog(WifiSettings.WIFI_DIALOG_ID);
 
         if (accessPoint != null) {
             // Save the access point and edit mode
-            mDlgAccessPoint = accessPoint.getAccessPoint();
+            mSelectedAccessPoint = accessPoint.getAccessPoint();
         } else {
             // No access point is selected. Clear saved state.
-            mDlgAccessPoint = null;
+            mSelectedAccessPoint = null;
             mAccessPointSavedState = null;
         }
 
@@ -204,24 +103,18 @@
     public Dialog onCreateDialog(int dialogId) {
         switch (dialogId) {
             case WifiSettings.WIFI_DIALOG_ID:
-                if (mDlgAccessPoint == null && mAccessPointSavedState == null) {
-                    // Add new network
-                    mDialog = WifiDialog.createFullscreen(getActivity(), this, null,
-                            WifiConfigUiBase.MODE_CONNECT);
-                } else {
-                    // Modify network
-                    if (mDlgAccessPoint == null) {
-                        // Restore AP from save state
-                        mDlgAccessPoint = new AccessPoint(getActivity(), mAccessPointSavedState);
-                        // Reset the saved access point data
-                        mAccessPointSavedState = null;
-                    }
-                    mDialog = WifiDialog.createModal(getActivity(), this, mDlgAccessPoint,
-                            WifiConfigUiBase.MODE_VIEW);
+                // Modify network
+                if (mSelectedAccessPoint == null) {
+                    // Restore AP from save state
+                    mSelectedAccessPoint = new AccessPoint(getActivity(), mAccessPointSavedState);
+                    // Reset the saved access point data
+                    mAccessPointSavedState = null;
                 }
-                mSelectedAccessPoint = mDlgAccessPoint;
+                final WifiDialog dialog = WifiDialog.createModal(
+                        getActivity(), this, mSelectedAccessPoint, WifiConfigUiBase.MODE_VIEW);
+                dialog.setOnCancelListener(this);
 
-                return mDialog;
+                return dialog;
         }
         return super.onCreateDialog(dialogId);
     }
@@ -239,14 +132,12 @@
     @Override
     public void onSaveInstanceState(Bundle outState) {
         super.onSaveInstanceState(outState);
-
-        // If the dialog is showing, save its state.
-        if (mDialog != null && mDialog.isShowing()) {
-            if (mDlgAccessPoint != null) {
-                mAccessPointSavedState = new Bundle();
-                mDlgAccessPoint.saveWifiState(mAccessPointSavedState);
-                outState.putBundle(SAVE_DIALOG_ACCESS_POINT_STATE, mAccessPointSavedState);
-            }
+        // If the dialog is showing (indicated by the existence of mSelectedAccessPoint), then we
+        // save its state.
+        if (mSelectedAccessPoint != null) {
+            mAccessPointSavedState = new Bundle();
+            mSelectedAccessPoint.saveWifiState(mAccessPointSavedState);
+            outState.putBundle(SAVE_DIALOG_ACCESS_POINT_STATE, mAccessPointSavedState);
         }
     }
 
@@ -261,27 +152,19 @@
                     Log.e(TAG, "Failed to remove Passpoint configuration for "
                             + mSelectedAccessPoint.getConfigName());
                 }
-                postUpdatePreference();
+                use(SavedAccessPointsPreferenceController.class)
+                        .postRefreshSavedAccessPoints();
             } else {
                 // mForgetListener will call initPreferences upon completion
-                mWifiManager.forget(mSelectedAccessPoint.getConfig().networkId, mForgetListener);
+                mWifiManager.forget(mSelectedAccessPoint.getConfig().networkId,
+                        use(SavedAccessPointsPreferenceController.class));
             }
             mSelectedAccessPoint = null;
         }
     }
 
     @Override
-    public void onSubmit(WifiDialog dialog) {
-        mWifiManager.save(dialog.getController().getConfig(), mSaveListener);
-    }
-
-    @Override
-    public boolean onPreferenceTreeClick(Preference preference) {
-        if (preference instanceof AccessPointPreference) {
-            showWifiDialog((AccessPointPreference) preference);
-            return true;
-        } else {
-            return super.onPreferenceTreeClick(preference);
-        }
+    public void onCancel(DialogInterface dialog) {
+        mSelectedAccessPoint = null;
     }
 }
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowAccessPoint.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowAccessPoint.java
new file mode 100644
index 0000000..2cb6964
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowAccessPoint.java
@@ -0,0 +1,31 @@
+/*
+ * 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.settings.testutils.shadow;
+
+import com.android.settingslib.wifi.AccessPoint;
+
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+
+@Implements(AccessPoint.class)
+public class ShadowAccessPoint {
+
+    @Implementation
+    public String getSavedNetworkSummary() {
+        return "saved";
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowWifiManager.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowWifiManager.java
index e5304da..65f92a3 100644
--- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowWifiManager.java
+++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowWifiManager.java
@@ -20,13 +20,17 @@
 
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiManager;
+import android.net.wifi.hotspot2.PasspointConfiguration;
 
 import org.robolectric.annotation.HiddenApi;
 import org.robolectric.annotation.Implementation;
 import org.robolectric.annotation.Implements;
 import org.robolectric.shadow.api.Shadow;
 
-@Implements(WifiManager.class)
+import java.util.Collections;
+import java.util.List;
+
+@Implements(value = WifiManager.class, inheritImplementationMethods = true)
 public class ShadowWifiManager extends org.robolectric.shadows.ShadowWifiManager {
 
     public WifiConfiguration savedWifiConfig;
@@ -43,6 +47,11 @@
         savedWifiConfig = config;
     }
 
+    @Implementation
+    public List<PasspointConfiguration> getPasspointConfigurations() {
+        return Collections.emptyList();
+    }
+
     public static ShadowWifiManager get() {
         return Shadow.extract(application.getSystemService(WifiManager.class));
     }
diff --git a/tests/robotests/src/com/android/settings/wifi/WifiDialogTest.java b/tests/robotests/src/com/android/settings/wifi/WifiDialogTest.java
index 7025100..7a88131 100644
--- a/tests/robotests/src/com/android/settings/wifi/WifiDialogTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/WifiDialogTest.java
@@ -25,15 +25,7 @@
 
     private Context mContext = RuntimeEnvironment.application;
 
-    private WifiDialogListener mListener = new WifiDialogListener() {
-        @Override
-        public void onForget(WifiDialog dialog) {
-        }
-
-        @Override
-        public void onSubmit(WifiDialog dialog) {
-        }
-    };
+    private WifiDialogListener mListener = new WifiDialogListener() {};
 
     @Before
     public void setUp() {
diff --git a/tests/robotests/src/com/android/settings/wifi/savedaccesspoints/SavedAccessPointsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/wifi/savedaccesspoints/SavedAccessPointsPreferenceControllerTest.java
new file mode 100644
index 0000000..790739a
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/wifi/savedaccesspoints/SavedAccessPointsPreferenceControllerTest.java
@@ -0,0 +1,135 @@
+/*
+ * 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.settings.wifi.savedaccesspoints;
+
+import static com.android.settings.core.BasePreferenceController.AVAILABLE;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.net.wifi.WifiConfiguration;
+
+import androidx.preference.PreferenceCategory;
+import androidx.preference.PreferenceScreen;
+
+import com.android.settings.testutils.SettingsRobolectricTestRunner;
+import com.android.settings.testutils.shadow.ShadowAccessPoint;
+import com.android.settings.testutils.shadow.ShadowThreadUtils;
+import com.android.settings.testutils.shadow.ShadowWifiManager;
+import com.android.settingslib.wifi.AccessPointPreference;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+@RunWith(SettingsRobolectricTestRunner.class)
+@Config(shadows = {ShadowThreadUtils.class, ShadowWifiManager.class})
+public class SavedAccessPointsPreferenceControllerTest {
+
+    @Mock
+    private PreferenceScreen mPreferenceScreen;
+    @Mock
+    private PreferenceCategory mPreferenceCategory;
+
+    private Context mContext;
+    private ShadowWifiManager mWifiManager;
+    private SavedAccessPointsPreferenceController mController;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = RuntimeEnvironment.application;
+        mWifiManager = ShadowWifiManager.get();
+        mController = spy(new SavedAccessPointsPreferenceController(mContext, "test_key"));
+
+        when(mPreferenceScreen.findPreference(mController.getPreferenceKey()))
+                .thenReturn(mPreferenceCategory);
+        when(mPreferenceCategory.getContext()).thenReturn(mContext);
+    }
+
+    @Test
+    public void getAvailability_alwaysAvailable() {
+        assertThat(mController.getAvailabilityStatus()).isEqualTo(AVAILABLE);
+    }
+
+    @Test
+    public void onStart_shouldRefreshApList() {
+        doNothing().when(mController).refreshSavedAccessPoints();
+
+        mController.onStart();
+
+        verify(mController).refreshSavedAccessPoints();
+    }
+
+
+    @Test
+    public void postRefresh_shouldRefreshApList() {
+        doNothing().when(mController).refreshSavedAccessPoints();
+
+        mController.postRefreshSavedAccessPoints();
+
+        verify(mController).refreshSavedAccessPoints();
+    }
+
+    @Test
+    public void forget_onSuccess_shouldRefreshApList() {
+        doNothing().when(mController).refreshSavedAccessPoints();
+
+        mController.onSuccess();
+
+        verify(mController).refreshSavedAccessPoints();
+    }
+
+    @Test
+    public void forget_onFailure_shouldRefreshApList() {
+        doNothing().when(mController).refreshSavedAccessPoints();
+
+        mController.onFailure(0 /* reason */);
+
+        verify(mController).refreshSavedAccessPoints();
+    }
+
+    @Test
+    @Config(shadows = ShadowAccessPoint.class)
+    public void refreshSavedAccessPoints_shouldListAllAPs() {
+        final WifiConfiguration config = new WifiConfiguration();
+        config.SSID = "SSID";
+        config.BSSID = "BSSID";
+        config.networkId = 2;
+        mWifiManager.addNetwork(config);
+
+        final ArgumentCaptor<AccessPointPreference> captor =
+                ArgumentCaptor.forClass(AccessPointPreference.class);
+        mController.displayPreference(mPreferenceScreen);
+        mController.refreshSavedAccessPoints();
+
+        verify(mPreferenceCategory).addPreference(captor.capture());
+
+        final AccessPointPreference pref = captor.getValue();
+        assertThat(pref.getTitle()).isEqualTo(config.SSID);
+    }
+}
diff --git a/tests/robotests/src/com/android/settings/wifi/savedaccesspoints/SavedAccessPointsWifiSettingsTest.java b/tests/robotests/src/com/android/settings/wifi/savedaccesspoints/SavedAccessPointsWifiSettingsTest.java
index a988390..97ad7d9 100644
--- a/tests/robotests/src/com/android/settings/wifi/savedaccesspoints/SavedAccessPointsWifiSettingsTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/savedaccesspoints/SavedAccessPointsWifiSettingsTest.java
@@ -18,22 +18,20 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiManager;
-import android.net.wifi.WifiManager.ActionListener;
-import android.os.Handler;
 
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.settings.R;
 import com.android.settings.testutils.SettingsRobolectricTestRunner;
 import com.android.settings.wifi.WifiConfigController;
 import com.android.settings.wifi.WifiDialog;
+import com.android.settingslib.core.AbstractPreferenceController;
 import com.android.settingslib.wifi.AccessPoint;
 
 import org.junit.Before;
@@ -47,69 +45,53 @@
 public class SavedAccessPointsWifiSettingsTest {
 
     @Mock
-    private WifiManager mockWifiManager;
+    private WifiManager mWifiManager;
     @Mock
-    private WifiDialog mockWifiDialog;
+    private WifiDialog mWifiDialog;
     @Mock
-    private WifiConfigController mockConfigController;
+    private WifiConfigController mConfigController;
     @Mock
-    private WifiConfiguration mockWifiConfiguration;
+    private WifiConfiguration mWifiConfiguration;
     @Mock
-    private AccessPoint mockAccessPoint;
+    private AccessPoint mAccessPoint;
     @Mock
-    private Handler mHandler;
+    private SavedAccessPointsPreferenceController mSavedApController;
 
-    private SavedAccessPointsWifiSettings mSettings;
+    private TestFragment mSettings;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        mSettings = new SavedAccessPointsWifiSettings();
-        ReflectionHelpers.setField(mSettings, "mHandler", mHandler);
-        ReflectionHelpers.setField(mSettings, "mWifiManager", mockWifiManager);
+        mSettings = spy(new TestFragment());
 
-        when(mockWifiDialog.getController()).thenReturn(mockConfigController);
-        when(mockConfigController.getConfig()).thenReturn(mockWifiConfiguration);
+        doReturn(mSavedApController).when(mSettings)
+                .use(SavedAccessPointsPreferenceController.class);
+
+        ReflectionHelpers.setField(mSettings, "mWifiManager", mWifiManager);
+
+        when(mWifiDialog.getController()).thenReturn(mConfigController);
+        when(mConfigController.getConfig()).thenReturn(mWifiConfiguration);
     }
 
     @Test
-    public void onForget_isPasspointConfig_shouldSendMessageToHandler() {
-        final AccessPoint accessPoint = mock(AccessPoint.class);
-        when(accessPoint.isPasspointConfig()).thenReturn(true);
-        ReflectionHelpers.setField(mSettings, "mSelectedAccessPoint", accessPoint);
+    public void onForget_isPasspointConfig_shouldRefreshAPList() {
+        when(mAccessPoint.isPasspointConfig()).thenReturn(true);
+        ReflectionHelpers.setField(mSettings, "mSelectedAccessPoint", mAccessPoint);
 
         mSettings.onForget(null);
 
-        verify(mHandler).sendEmptyMessage(SavedAccessPointsWifiSettings.MSG_UPDATE_PREFERENCES);
-    }
-
-    @Test
-    public void onForget_onSuccess_shouldSendMessageToHandler() {
-        mSettings.mForgetListener.onSuccess();
-
-        verify(mHandler).sendEmptyMessage(SavedAccessPointsWifiSettings.MSG_UPDATE_PREFERENCES);
-    }
-
-    @Test
-    public void onForget_onFailure_shouldSendMessageToHandler() {
-        mSettings.mForgetListener.onFailure(0);
-
-        verify(mHandler).sendEmptyMessage(SavedAccessPointsWifiSettings.MSG_UPDATE_PREFERENCES);
-    }
-
-    @Test
-    public void onSubmit_shouldInvokeSaveApi() {
-        mSettings.onSubmit(mockWifiDialog);
-        verify(mockWifiManager).save(eq(mockWifiConfiguration), any(ActionListener.class));
+        verify(mSavedApController).postRefreshSavedAccessPoints();
     }
 
     @Test
     public void onForget_shouldInvokeForgetApi() {
-        ReflectionHelpers.setField(mSettings, "mSelectedAccessPoint", mockAccessPoint);
-        when(mockAccessPoint.getConfig()).thenReturn(mockWifiConfiguration);
-        mSettings.onForget(mockWifiDialog);
-        verify(mockWifiManager)
-                .forget(eq(mockWifiConfiguration.networkId), any(ActionListener.class));
+        ReflectionHelpers.setField(mSettings, "mSelectedAccessPoint", mAccessPoint);
+        when(mAccessPoint.getConfig()).thenReturn(mWifiConfiguration);
+
+        mSettings.onForget(mWifiDialog);
+
+        verify(mWifiManager)
+                .forget(mWifiConfiguration.networkId, mSavedApController);
     }
 
     @Test
@@ -118,4 +100,11 @@
         assertThat(mSettings.getPreferenceScreenResId())
                 .isEqualTo(R.xml.wifi_display_saved_access_points);
     }
+
+    public static class TestFragment extends SavedAccessPointsWifiSettings {
+
+        public <T extends AbstractPreferenceController> T use(Class<T> clazz) {
+            return super.use(clazz);
+        }
+    }
 }