[Wi-Fi] Add multiple networks request case for adding Wi-Fi for apps feature.

Handle adding multiple networks case, add UI components and process saving flow.

Bug: 136472483
Test: Add unit test cases to test filterSavedNetworks API.
Change-Id: I222e2f8294793796e293de49acdb96ecd6a57b0d
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 3f66cb8..03be75f 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -3058,6 +3058,7 @@
                   android:theme="@style/Theme.Panel"
                   android:launchMode="singleInstance"
                   android:excludeFromRecents="true"
+                  android:configChanges="orientation|keyboardHidden|screenSize"
                   android:permission="android.permission.CHANGE_WIFI_STATE">
             <intent-filter>
                 <action android:name="android.settings.WIFI_ADD_NETWORKS" />
diff --git a/res/layout/wifi_add_app_networks.xml b/res/layout/wifi_add_app_networks.xml
index 8696e04..6f7de20 100644
--- a/res/layout/wifi_add_app_networks.xml
+++ b/res/layout/wifi_add_app_networks.xml
@@ -118,6 +118,19 @@
                 android:textColor="?android:attr/textColorSecondary"/>
         </LinearLayout>
 
+        <LinearLayout
+            android:id="@+id/multiple_networks"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical">
+            <ListView
+                android:id="@+id/config_list"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:divider="@null"
+                android:scrollbarStyle="insideOverlay"/>
+        </LinearLayout>
+
         <include layout="@layout/horizontal_divider"/>
 
         <LinearLayout
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 63dee46..b8d73f2 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -2345,7 +2345,15 @@
     <!-- Summary for saved status when saving single network   [CHAR LIMIT=30] -->
     <string name="wifi_add_app_single_network_saved_summary">Saved</string>
     <!-- Summary for save failed status when saving single network [CHAR LIMIT=50] -->
-    <string name="wifi_add_app_single_network_save_failed_summary">Couldn\u2019t save. Try again.</string>
+    <string name="wifi_add_app_network_save_failed_summary">Couldn\u2019t save. Try again.</string>
+    <!--  Title for the panel of add multiple Wi-Fi networks from APP [CHAR LIMIT=50] -->
+    <string name="wifi_add_app_networks_title">Save networks?</string>
+    <!-- Summary for the panel of add multiple Wi-Fi networks from APP [CHAR LIMIT=NONE] -->
+    <string name="wifi_add_app_networks_summary"><xliff:g id="appName" example="ThirdPartyAppName">%1$s</xliff:g> would like to save these networks to your phone</string>
+    <!-- Summary for the panel of add Wi-Fi networks from APP [CHAR LIMIT=NONE] -->
+    <string name="wifi_add_app_networks_saving_summary">Saving <xliff:g id="number" example="3">%d</xliff:g> networks\u2026</string>
+    <!-- Summary for saved status when saving multiple networks   [CHAR LIMIT=NONE] -->
+    <string name="wifi_add_app_networks_saved_summary">Networks saved</string>
 
     <!-- Do not translate. Used for diagnostic screens, precise translation is not necessary
          Wi-Fi Testing on the diagnostic screen-->
diff --git a/src/com/android/settings/wifi/addappnetworks/AddAppNetworksFragment.java b/src/com/android/settings/wifi/addappnetworks/AddAppNetworksFragment.java
index eeec166..93f73db 100644
--- a/src/com/android/settings/wifi/addappnetworks/AddAppNetworksFragment.java
+++ b/src/com/android/settings/wifi/addappnetworks/AddAppNetworksFragment.java
@@ -36,13 +36,16 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
 import android.widget.Button;
 import android.widget.ImageView;
+import android.widget.ListView;
 import android.widget.TextView;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.fragment.app.FragmentActivity;
+import androidx.preference.internal.PreferenceImageView;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.settings.R;
@@ -67,10 +70,12 @@
 
     // Possible result values in each item of the returned result list, which is used
     // to inform the caller APP the processed result of each specified network.
-    private static final int RESULT_NETWORK_INITIAL = -1;  //initial value
+    @VisibleForTesting
+    static final int RESULT_NETWORK_INITIAL = -1;  //initial value
     private static final int RESULT_NETWORK_SUCCESS = 0;
     private static final int RESULT_NETWORK_ADD_ERROR = 1;
-    private static final int RESULT_NETWORK_ALREADY_EXISTS = 2;
+    @VisibleForTesting
+    static final int RESULT_NETWORK_ALREADY_EXISTS = 2;
 
     // Handler messages for controlling different state and delay showing the status message.
     private static final int MESSAGE_START_SAVING_NETWORK = 1;
@@ -80,6 +85,8 @@
 
     // Signal level for the constant signal icon.
     private static final int MAX_RSSI_SIGNAL_LEVEL = 4;
+    // Max networks count within one request
+    private static final int MAX_SPECIFIC_NETWORKS_COUNT = 5;
 
     // Duration for showing different status message.
     private static final long SHOW_SAVING_INTERVAL_MILLIS = 500L;
@@ -95,51 +102,44 @@
     Button mSaveButton;
     @VisibleForTesting
     String mCallingPackageName;
+    @VisibleForTesting
+    List<WifiConfiguration> mAllSpecifiedNetworksList;
+    @VisibleForTesting
+    List<UiConfigurationItem> mUiToRequestedList;
+    @VisibleForTesting
+    List<Integer> mResultCodeArrayList;
 
+    private boolean mIsSingleNetwork;
+    private boolean mAnyNetworkSavedSuccess;
     private TextView mSummaryView;
     private TextView mSingleNetworkProcessingStatusView;
     private int mSavingIndex;
-    private List<WifiConfiguration> mAllSpecifiedNetworksList;
-    private ArrayList<Integer> mResultCodeArrayList;
+    private UiConfigurationItemAdapter mUiConfigurationItemAdapter;
     private WifiManager.ActionListener mSaveListener;
     private WifiManager mWifiManager;
 
     private final Handler mHandler = new Handler() {
         @Override
         public void handleMessage(Message msg) {
+            showSaveStatusByState(msg.what);
+
             switch (msg.what) {
                 case MESSAGE_START_SAVING_NETWORK:
                     mSaveButton.setEnabled(false);
-                    // Set the initial text color for status message.
-                    mSingleNetworkProcessingStatusView.setTextColor(
-                            com.android.settingslib.Utils.getColorAttr(mActivity,
-                                    android.R.attr.textColorSecondary));
-                    mSingleNetworkProcessingStatusView.setText(
-                            getString(R.string.wifi_add_app_single_network_saving_summary));
-                    mSingleNetworkProcessingStatusView.setVisibility(View.VISIBLE);
-
-                    // Save the proposed network.
-                    saveNetworks();
+                    // Save the proposed networks, start from first one.
+                    saveNetwork(0);
                     break;
 
                 case MESSAGE_SHOW_SAVED_AND_CONNECT_NETWORK:
-                    mSingleNetworkProcessingStatusView.setText(
-                            getString(R.string.wifi_add_app_single_network_saved_summary));
-
                     // For the single network case, we need to call connection after saved.
-                    connectNetwork();
-
+                    if (mIsSingleNetwork) {
+                        connectNetwork(0);
+                    }
                     sendEmptyMessageDelayed(MESSAGE_FINISH,
                             SHOW_SAVED_INTERVAL_MILLIS);
                     break;
 
                 case MESSAGE_SHOW_SAVE_FAILED:
-                    mSingleNetworkProcessingStatusView.setText(
-                            getString(R.string.wifi_add_app_single_network_save_failed_summary));
-                    // Error message need to use colorError attribute to show.
-                    mSingleNetworkProcessingStatusView.setTextColor(
-                            com.android.settingslib.Utils.getColorAttr(mActivity,
-                                    android.R.attr.colorError));
                     mSaveButton.setEnabled(true);
                     break;
 
@@ -169,15 +169,15 @@
     public void onViewCreated(View view, Bundle savedInstanceState) {
         super.onViewCreated(view, savedInstanceState);
 
-        // Initial UI variable.
+        // Initial UI variables.
         mLayoutView = view;
         mCancelButton = view.findViewById(R.id.cancel);
         mSaveButton = view.findViewById(R.id.save);
         mSummaryView = view.findViewById(R.id.app_summary);
         mSingleNetworkProcessingStatusView = view.findViewById(R.id.single_status);
         // Assigns button listeners and network save listener.
-        mCancelButton.setOnClickListener(getCancelListener());
-        mSaveButton.setOnClickListener(getSaveListener());
+        mCancelButton.setOnClickListener(getCancelClickListener());
+        mSaveButton.setOnClickListener(getSaveClickListener());
         prepareSaveResultListener();
 
         // Prepare the non-UI variables.
@@ -189,25 +189,29 @@
         mAllSpecifiedNetworksList =
                 bundle.getParcelableArrayList(Settings.EXTRA_WIFI_CONFIGURATION_LIST);
 
-        // If there is no networks in the request intent, then just finish activity.
-        if (mAllSpecifiedNetworksList == null || mAllSpecifiedNetworksList.isEmpty()) {
+        // If there is no network in the request intent or the requested networks exceed the
+        // maximum limit, then just finish activity.
+        if (mAllSpecifiedNetworksList == null || mAllSpecifiedNetworksList.isEmpty()
+                || mAllSpecifiedNetworksList.size() > MAX_SPECIFIC_NETWORKS_COUNT) {
             finishWithResult(RESULT_CANCELED, null /* resultArrayList */);
             return;
         }
 
         // Initial the result arry.
         initializeResultCodeArray();
+        // Filter the saved networks, and prepare a not saved networks list for UI to present.
+        mUiToRequestedList = filterSavedNetworks(mWifiManager.getPrivilegedConfiguredNetworks());
 
-        // Filter out the saved networks, don't show saved networks to user.
-        checkSavedNetworks();
+        // If all the specific networks are all exist, we just need to finish with result.
+        if (mUiToRequestedList.size() == 0) {
+            finishWithResult(RESULT_OK, mResultCodeArrayList);
+            return;
+        }
 
         if (mAllSpecifiedNetworksList.size() == 1) {
-            // If the only one requested network is already saved, just return with existence.
-            if (mResultCodeArrayList.get(0) == RESULT_NETWORK_ALREADY_EXISTS) {
-                finishWithResult(RESULT_OK, mResultCodeArrayList);
-                return;
-            }
-
+            mIsSingleNetwork = true;
+            // Set the multiple networks related layout as GONE.
+            mLayoutView.findViewById(R.id.multiple_networks).setVisibility(View.GONE);
             // Show signal icon for single network case.
             setSingleNetworkSignalIcon();
             // Show the SSID of the proposed network.
@@ -216,7 +220,15 @@
             // Set the status view as gone when UI is initialized.
             mSingleNetworkProcessingStatusView.setVisibility(View.GONE);
         } else {
-            // TODO: Add code for processing multiple networks case.
+            // Multiple networks request case.
+            mIsSingleNetwork = false;
+            // Set the single network related layout as GONE.
+            mLayoutView.findViewById(R.id.single_network).setVisibility(View.GONE);
+            // Prepare a UI adapter and set to UI listview.
+            final ListView uiNetworkListView = mLayoutView.findViewById(R.id.config_list);
+            mUiConfigurationItemAdapter = new UiConfigurationItemAdapter(mActivity,
+                    com.android.settingslib.R.layout.preference_access_point, mUiToRequestedList);
+            uiNetworkListView.setAdapter(mUiConfigurationItemAdapter);
         }
 
         // Assigns caller app icon, title, and summary.
@@ -257,23 +269,28 @@
     }
 
     /**
-     * For the APP specified networks, need to filter out those saved ones and mark them as existed.
+     * For the APP specified networks, filter saved ones and mark those saved as existed. And
+     * finally return a new UiConfigurationItem list, which contains those new or need to be
+     * updated networks, back to caller for creating UI to user.
      */
-    private void checkSavedNetworks() {
-        final List<WifiConfiguration> privilegedWifiConfigurations =
-                mWifiManager.getPrivilegedConfiguredNetworks();
+    @VisibleForTesting
+    ArrayList<UiConfigurationItem> filterSavedNetworks(
+            List<WifiConfiguration> savedWifiConfigurations) {
+        ArrayList<UiConfigurationItem> uiToRequestedList = new ArrayList<>();
+
         boolean foundInSavedList;
         int networkPositionInBundle = 0;
         for (WifiConfiguration specifiecConfig : mAllSpecifiedNetworksList) {
             foundInSavedList = false;
+            final String displayedSsid = removeDoubleQuotes(specifiecConfig.SSID);
             final String ssidWithQuotation = addQuotationIfNeeded(specifiecConfig.SSID);
             final String securityType = getSecurityType(specifiecConfig);
 
-            for (WifiConfiguration privilegedWifiConfiguration : privilegedWifiConfigurations) {
+            for (WifiConfiguration privilegedWifiConfiguration : savedWifiConfigurations) {
                 final String savedSecurityType = getSecurityType(privilegedWifiConfiguration);
 
-                // If SSID or security type is different, should be new network or need to updated
-                // network.
+                // If SSID or security type is different, should be new network or need to be
+                // updated network.
                 if (!ssidWithQuotation.equals(privilegedWifiConfiguration.SSID)
                         || !securityType.equals(savedSecurityType)) {
                     continue;
@@ -308,10 +325,15 @@
                 // result code list as existed.
                 mResultCodeArrayList.set(networkPositionInBundle, RESULT_NETWORK_ALREADY_EXISTS);
             } else {
-                // TODO: for multiple networks case, need to add to adapter for present list to user
+                // Prepare to add to UI list to show to user
+                UiConfigurationItem uiConfigurationIcon = new UiConfigurationItem(displayedSsid,
+                        specifiecConfig, networkPositionInBundle);
+                uiToRequestedList.add(uiConfigurationIcon);
             }
             networkPositionInBundle++;
         }
+
+        return uiToRequestedList;
     }
 
     private void setSingleNetworkSignalIcon() {
@@ -335,9 +357,22 @@
 
         StringBuilder sb = new StringBuilder();
         sb.append("\"").append(input).append("\"");
+
         return sb.toString();
     }
 
+    static String removeDoubleQuotes(String string) {
+        if (TextUtils.isEmpty(string)) {
+            return "";
+        }
+        int length = string.length();
+        if ((length > 1) && (string.charAt(0) == '"')
+                && (string.charAt(length - 1) == '"')) {
+            return string.substring(1, length - 1);
+        }
+        return string;
+    }
+
     private void assignAppIcon(Context context, String callingPackageName) {
         final Drawable drawable = loadPackageIconDrawable(context, callingPackageName);
         ((ImageView) mLayoutView.findViewById(R.id.app_icon)).setImageDrawable(drawable);
@@ -364,21 +399,23 @@
     }
 
     private CharSequence getAddNetworkRequesterSummary(CharSequence appName) {
-        return getString(R.string.wifi_add_app_single_network_summary, appName);
+        return getString(mIsSingleNetwork ? R.string.wifi_add_app_single_network_summary
+                : R.string.wifi_add_app_networks_summary, appName);
     }
 
     private CharSequence getTitle() {
-        return getString(R.string.wifi_add_app_single_network_title);
+        return getString(mIsSingleNetwork ? R.string.wifi_add_app_single_network_title
+                : R.string.wifi_add_app_networks_title);
     }
 
-    View.OnClickListener getCancelListener() {
+    View.OnClickListener getCancelClickListener() {
         return (v) -> {
             Log.d(TAG, "User rejected to add network");
             finishWithResult(RESULT_CANCELED, null /* resultArrayList */);
         };
     }
 
-    View.OnClickListener getSaveListener() {
+    View.OnClickListener getSaveClickListener() {
         return (v) -> {
             Log.d(TAG, "User agree to add networks");
             // Start to process saving networks.
@@ -387,44 +424,160 @@
         };
     }
 
+    /**
+     * This class used to show network items to user, each item contains one specific (@Code
+     * WifiConfiguration} and one index to mapping this UI item to the item in the APP request
+     * network list.
+     */
+    @VisibleForTesting
+    static class UiConfigurationItem {
+        public final String mDisplayedSsid;
+        public final WifiConfiguration mWifiConfiguration;
+        public final int mIndex;
+
+        UiConfigurationItem(String displayedSsid, WifiConfiguration wifiConfiguration, int index) {
+            mDisplayedSsid = displayedSsid;
+            mWifiConfiguration = wifiConfiguration;
+            mIndex = index;
+        }
+    }
+
+    private class UiConfigurationItemAdapter extends ArrayAdapter<UiConfigurationItem> {
+        private final int mResourceId;
+        private final LayoutInflater mInflater;
+
+        UiConfigurationItemAdapter(Context context, int resourceId,
+                List<UiConfigurationItem> objects) {
+            super(context, resourceId, objects);
+            mResourceId = resourceId;
+            mInflater = LayoutInflater.from(context);
+        }
+
+        @Override
+        public View getView(int position, View view, ViewGroup parent) {
+            if (view == null) {
+                view = mInflater.inflate(mResourceId, parent, false /* attachToRoot */);
+            }
+
+            final View divider = view.findViewById(
+                    com.android.settingslib.R.id.two_target_divider);
+            if (divider != null) {
+                divider.setVisibility(View.GONE);
+            }
+
+            final UiConfigurationItem uiConfigurationItem = getItem(position);
+            final TextView titleView = view.findViewById(android.R.id.title);
+            if (titleView != null) {
+                // Shows whole SSID for better UX.
+                titleView.setSingleLine(false);
+                titleView.setText(uiConfigurationItem.mDisplayedSsid);
+            }
+
+            final PreferenceImageView imageView = view.findViewById(android.R.id.icon);
+            if (imageView != null) {
+                final Drawable drawable = getContext().getDrawable(
+                        com.android.settingslib.Utils.getWifiIconResource(MAX_RSSI_SIGNAL_LEVEL));
+                drawable.setTintList(
+                        com.android.settingslib.Utils.getColorAttr(getContext(),
+                                android.R.attr.colorControlNormal));
+                imageView.setImageDrawable(drawable);
+            }
+
+            final TextView summaryView = view.findViewById(android.R.id.summary);
+            if (summaryView != null) {
+                summaryView.setVisibility(View.GONE);
+            }
+
+            return view;
+        }
+    }
+
     private void prepareSaveResultListener() {
         mSaveListener = new WifiManager.ActionListener() {
             @Override
             public void onSuccess() {
-                mResultCodeArrayList.set(mSavingIndex, RESULT_NETWORK_SUCCESS);
-                Message nextState_Message = mHandler.obtainMessage(
-                        MESSAGE_SHOW_SAVED_AND_CONNECT_NETWORK);
-                // Delay to change to next state for showing saving mesage for a period.
-                mHandler.sendMessageDelayed(nextState_Message, SHOW_SAVING_INTERVAL_MILLIS);
+                // Set success into result list.
+                mResultCodeArrayList.set(mUiToRequestedList.get(mSavingIndex).mIndex,
+                        RESULT_NETWORK_SUCCESS);
+                mAnyNetworkSavedSuccess = true;
+
+                if (saveNextNetwork()) {
+                    return;
+                }
+
+                // Show saved or failed according to all results
+                showSavedOrFail();
             }
 
             @Override
             public void onFailure(int reason) {
-                mResultCodeArrayList.set(mSavingIndex, RESULT_NETWORK_ADD_ERROR);
-                Message nextState_Message = mHandler.obtainMessage(MESSAGE_SHOW_SAVE_FAILED);
-                // Delay to change to next state for showing saving mesage for a period.
-                mHandler.sendMessageDelayed(nextState_Message, SHOW_SAVING_INTERVAL_MILLIS);
+                // Set result code of this network to be failed in the return list.
+                mResultCodeArrayList.set(mUiToRequestedList.get(mSavingIndex).mIndex,
+                        RESULT_NETWORK_ADD_ERROR);
+
+                if (saveNextNetwork()) {
+                    return;
+                }
+
+                // Show saved or failed according to all results
+                showSavedOrFail();
             }
         };
     }
 
-    private void saveNetworks() {
-        final WifiConfiguration wifiConfiguration = mAllSpecifiedNetworksList.get(0);
+    /**
+     * For multiple networks case, we need to check if there is other network need to save.
+     */
+    private boolean saveNextNetwork() {
+        // Save the next network if have.
+        if (!mIsSingleNetwork && mSavingIndex < (mUiToRequestedList.size() - 1)) {
+            mSavingIndex++;
+            saveNetwork(mSavingIndex);
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * If any one of the specified networks is success, then we show saved and return all results
+     * list back to caller APP, otherwise we show failed to indicate all networks saved failed.
+     */
+    private void showSavedOrFail() {
+        Message nextStateMessage;
+        if (mAnyNetworkSavedSuccess) {
+            // Enter next state after all networks are saved.
+            nextStateMessage = mHandler.obtainMessage(
+                    MESSAGE_SHOW_SAVED_AND_CONNECT_NETWORK);
+        } else {
+            nextStateMessage = mHandler.obtainMessage(MESSAGE_SHOW_SAVE_FAILED);
+        }
+        // Delay to change to next state for showing saving mesage for a period.
+        mHandler.sendMessageDelayed(nextStateMessage, SHOW_SAVING_INTERVAL_MILLIS);
+    }
+
+    /**
+     * Call framework API to save single network.
+     */
+    private void saveNetwork(int index) {
+        final WifiConfiguration wifiConfiguration = mUiToRequestedList.get(
+                index).mWifiConfiguration;
         wifiConfiguration.SSID = addQuotationIfNeeded(wifiConfiguration.SSID);
+        mSavingIndex = index;
         mWifiManager.save(wifiConfiguration, mSaveListener);
     }
 
-    private void connectNetwork() {
-        final WifiConfiguration wifiConfiguration = mAllSpecifiedNetworksList.get(0);
-        // Don't need to handle the connect result.
+    private void connectNetwork(int index) {
+        final WifiConfiguration wifiConfiguration = mUiToRequestedList.get(
+                index).mWifiConfiguration;
         mWifiManager.connect(wifiConfiguration, null /* ActionListener */);
     }
 
-    private void finishWithResult(int resultCode, ArrayList<Integer> resultArrayList) {
+    private void finishWithResult(int resultCode, List<Integer> resultArrayList) {
         if (resultArrayList != null) {
             Intent intent = new Intent();
             intent.putIntegerArrayListExtra(Settings.EXTRA_WIFI_CONFIGURATION_RESULT_LIST,
-                    resultArrayList);
+                    (ArrayList<Integer>) resultArrayList);
             mActivity.setResult(resultCode, intent);
         }
         mActivity.finish();
@@ -435,4 +588,59 @@
         // TODO(b/144891278): Need to define a new metric for this page, use the WIFI item first.
         return SettingsEnums.WIFI;
     }
+
+    private void showSaveStatusByState(int status) {
+        switch (status) {
+            case MESSAGE_START_SAVING_NETWORK:
+                if (mIsSingleNetwork) {
+                    // Set the initial text color for status message.
+                    mSingleNetworkProcessingStatusView.setTextColor(
+                            com.android.settingslib.Utils.getColorAttr(mActivity,
+                                    android.R.attr.textColorSecondary));
+                    mSingleNetworkProcessingStatusView.setText(
+                            getString(R.string.wifi_add_app_single_network_saving_summary));
+                    mSingleNetworkProcessingStatusView.setVisibility(View.VISIBLE);
+                } else {
+                    mSummaryView.setTextColor(
+                            com.android.settingslib.Utils.getColorAttr(mActivity,
+                                    android.R.attr.textColorSecondary));
+                    mSummaryView.setText(
+                            getString(R.string.wifi_add_app_networks_saving_summary,
+                                    mUiToRequestedList.size()));
+                }
+                break;
+
+            case MESSAGE_SHOW_SAVED_AND_CONNECT_NETWORK:
+                if (mIsSingleNetwork) {
+                    mSingleNetworkProcessingStatusView.setText(
+                            getString(R.string.wifi_add_app_single_network_saved_summary));
+                } else {
+                    mSummaryView.setText(
+                            getString(R.string.wifi_add_app_networks_saved_summary));
+                }
+                break;
+
+            case MESSAGE_SHOW_SAVE_FAILED:
+                if (mIsSingleNetwork) {
+                    // Error message need to use colorError attribute to show.
+                    mSingleNetworkProcessingStatusView.setTextColor(
+                            com.android.settingslib.Utils.getColorAttr(mActivity,
+                                    android.R.attr.colorError));
+                    mSingleNetworkProcessingStatusView.setText(
+                            getString(R.string.wifi_add_app_network_save_failed_summary));
+                } else {
+                    // Error message need to use colorError attribute to show.
+                    mSummaryView.setTextColor(
+                            com.android.settingslib.Utils.getColorAttr(mActivity,
+                                    android.R.attr.colorError));
+                    mSummaryView.setText(
+                            getString(R.string.wifi_add_app_network_save_failed_summary));
+                }
+                break;
+
+            default:
+                // Do nothing.
+                break;
+        }
+    }
 }
diff --git a/tests/robotests/src/com/android/settings/wifi/addappnetworks/AddAppNetworksFragmentTest.java b/tests/robotests/src/com/android/settings/wifi/addappnetworks/AddAppNetworksFragmentTest.java
index 999d44e..765f14d 100644
--- a/tests/robotests/src/com/android/settings/wifi/addappnetworks/AddAppNetworksFragmentTest.java
+++ b/tests/robotests/src/com/android/settings/wifi/addappnetworks/AddAppNetworksFragmentTest.java
@@ -21,13 +21,14 @@
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.spy;
 
-import android.content.Context;
 import android.net.wifi.WifiConfiguration;
 import android.os.Bundle;
 import android.os.Parcelable;
 import android.provider.Settings;
 import android.widget.TextView;
 
+import androidx.annotation.NonNull;
+
 import com.android.settings.R;
 
 import org.junit.Before;
@@ -42,18 +43,34 @@
 @RunWith(RobolectricTestRunner.class)
 public class AddAppNetworksFragmentTest {
     private static final String FAKE_APP_NAME = "fake_app_name";
-    private static final String FAKE_SSID = "fake_ssid";
+    private static final String FAKE_NEW_WPA_SSID = "fake_new_wpa_ssid";
+    private static final String FAKE_NEW_OPEN_SSID = "fake_new_open_ssid";
+    private static final String FAKE_NEW_SAVED_WPA_SSID = "\"fake_new_wpa_ssid\"";
+
     private AddAppNetworksFragment mAddAppNetworksFragment;
-    private Context mContext;
+    private List<WifiConfiguration> mFakedSpecifiedNetworksList;
+    private List<WifiConfiguration> mFakeSavedNetworksList;
+    private WifiConfiguration mNewWpaConfigEntry;
+    private WifiConfiguration mNewOpenConfigEntry;
+    private WifiConfiguration mSavedWpaConfigEntry;
+    private Bundle mBundle;
+    private ArrayList<Integer> mFakedResultArrayList = new ArrayList<>();
 
     @Before
     public void setUp() {
         mAddAppNetworksFragment = spy(new AddAppNetworksFragment());
+        mNewWpaConfigEntry = generateWifiConfig(FAKE_NEW_WPA_SSID,
+                WifiConfiguration.KeyMgmt.WPA_PSK, "\"1234567890\"");
+        mNewOpenConfigEntry = generateWifiConfig(FAKE_NEW_OPEN_SSID,
+                WifiConfiguration.KeyMgmt.NONE, null);
+        mSavedWpaConfigEntry = generateWifiConfig(FAKE_NEW_SAVED_WPA_SSID,
+                WifiConfiguration.KeyMgmt.WPA_PSK, "\"1234567890\"");
     }
 
     @Test
     public void callingPackageName_onCreateView_shouldBeCorrect() {
-        setUpOneNetworkBundle();
+        addOneSpecifiedNetworkConfig(mNewWpaConfigEntry);
+        setUpBundle(mFakedSpecifiedNetworksList);
         setupFragment();
 
         assertThat(mAddAppNetworksFragment.mCallingPackageName).isEqualTo(FAKE_APP_NAME);
@@ -61,7 +78,8 @@
 
     @Test
     public void launchFragment_shouldShowSaveButton() {
-        setUpOneNetworkBundle();
+        addOneSpecifiedNetworkConfig(mNewWpaConfigEntry);
+        setUpBundle(mFakedSpecifiedNetworksList);
         setupFragment();
 
         assertThat(mAddAppNetworksFragment.mSaveButton).isNotNull();
@@ -69,7 +87,8 @@
 
     @Test
     public void launchFragment_shouldShowCancelButton() {
-        setUpOneNetworkBundle();
+        addOneSpecifiedNetworkConfig(mNewWpaConfigEntry);
+        setUpBundle(mFakedSpecifiedNetworksList);
         setupFragment();
 
         assertThat(mAddAppNetworksFragment.mCancelButton).isNotNull();
@@ -77,40 +96,72 @@
 
     @Test
     public void requestOneNetwork_shouldShowCorrectSSID() {
-        setUpOneNetworkBundle();
+        addOneSpecifiedNetworkConfig(mNewWpaConfigEntry);
+        setUpBundle(mFakedSpecifiedNetworksList);
         setupFragment();
         TextView ssidView = (TextView) mAddAppNetworksFragment.mLayoutView.findViewById(
                 R.id.single_ssid);
 
-        assertThat(ssidView.getText()).isEqualTo(FAKE_SSID);
+        assertThat(ssidView.getText()).isEqualTo(FAKE_NEW_WPA_SSID);
     }
 
     @Test
     public void withNoExtra_requestNetwork_shouldFinished() {
-        setUpNoNetworkBundle();
+        addOneSpecifiedNetworkConfig(null);
+        setUpBundle(mFakedSpecifiedNetworksList);
         setupFragment();
 
         assertThat(mAddAppNetworksFragment.mActivity.isFinishing()).isTrue();
     }
 
-    private void setUpOneNetworkBundle() {
-        // Setup one network.
-        List<WifiConfiguration> wifiConfigurationList = new ArrayList<>();
-        wifiConfigurationList.add(
-                generateWifiConfig(FAKE_SSID, WifiConfiguration.KeyMgmt.WPA_PSK, "\"1234567890\""));
+    @Test
+    public void withOneHalfSavedNetworks_uiListAndResultListShouldBeCorrect() {
+        // Arrange
+        // Setup a fake saved network list and assign to fragment.
+        addOneSavedNetworkConfig(mSavedWpaConfigEntry);
+        // Setup two specified networks and their results and assign to fragment.
+        addOneSpecifiedNetworkConfig(mNewWpaConfigEntry);
+        addOneSpecifiedNetworkConfig(mNewOpenConfigEntry);
+        mAddAppNetworksFragment.mAllSpecifiedNetworksList = mFakedSpecifiedNetworksList;
+        mFakedResultArrayList.add(mAddAppNetworksFragment.RESULT_NETWORK_INITIAL);
+        mFakedResultArrayList.add(mAddAppNetworksFragment.RESULT_NETWORK_INITIAL);
+        mAddAppNetworksFragment.mResultCodeArrayList = mFakedResultArrayList;
+
+        // Act
+        mAddAppNetworksFragment.mUiToRequestedList = mAddAppNetworksFragment.filterSavedNetworks(
+                mFakeSavedNetworksList);
+
+        // Assert
+        assertThat(mAddAppNetworksFragment.mUiToRequestedList).hasSize(1);
+        assertThat(mAddAppNetworksFragment.mResultCodeArrayList.get(0)).isEqualTo(
+                mAddAppNetworksFragment.RESULT_NETWORK_ALREADY_EXISTS);
+        assertThat(mAddAppNetworksFragment.mUiToRequestedList.get(
+                0).mWifiConfiguration.SSID).isEqualTo(FAKE_NEW_OPEN_SSID);
+    }
+
+    private void addOneSavedNetworkConfig(@NonNull WifiConfiguration wifiConfiguration) {
+        if (mFakeSavedNetworksList == null) {
+            mFakeSavedNetworksList = new ArrayList<>();
+        }
+
+        mFakeSavedNetworksList.add(wifiConfiguration);
+    }
+
+    private void addOneSpecifiedNetworkConfig(@NonNull WifiConfiguration wifiConfiguration) {
+        if (wifiConfiguration != null) {
+            if (mFakedSpecifiedNetworksList == null) {
+                mFakedSpecifiedNetworksList = new ArrayList<>();
+            }
+            mFakedSpecifiedNetworksList.add(wifiConfiguration);
+        }
+    }
+
+    private void setUpBundle(List<WifiConfiguration> allFakedNetworksList) {
         // Set up bundle.
         final Bundle bundle = new Bundle();
         bundle.putString(AddAppNetworksActivity.KEY_CALLING_PACKAGE_NAME, FAKE_APP_NAME);
         bundle.putParcelableArrayList(Settings.EXTRA_WIFI_CONFIGURATION_LIST,
-                (ArrayList<? extends Parcelable>) wifiConfigurationList);
-        doReturn(bundle).when(mAddAppNetworksFragment).getArguments();
-    }
-
-    private void setUpNoNetworkBundle() {
-        // Set up bundle.
-        final Bundle bundle = new Bundle();
-        bundle.putString(AddAppNetworksActivity.KEY_CALLING_PACKAGE_NAME, FAKE_APP_NAME);
-        bundle.putParcelableArrayList(Settings.EXTRA_WIFI_CONFIGURATION_LIST, null);
+                (ArrayList<? extends Parcelable>) allFakedNetworksList);
         doReturn(bundle).when(mAddAppNetworksFragment).getArguments();
     }