Supports to share Wi-Fi networks of WPA3 security SAE & OWE via QR code generator

When scanned a no password ZXing QR code, add both open network &
enhanced open network to configured Wi-Fi network list because this kind
of QR code may refer to a open network or an enhanced open network.

Bug: 124131581
Test: manual
Change-Id: Id9f85ef8dcdf72347be8106938437aecd0eed9f5
diff --git a/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java b/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java
index 13905c8..cbb91a2 100644
--- a/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java
+++ b/src/com/android/settings/wifi/details/WifiDetailPreferenceController.java
@@ -409,7 +409,8 @@
                 .setButton4Text(R.string.share)
                 .setButton4Icon(R.drawable.ic_qrcode_24dp)
                 .setButton4OnClickListener(view -> shareNetwork())
-                .setButton4Visible(WifiDppUtils.isSupportConfiguratorQrCodeGenerator(mAccessPoint));
+                .setButton4Visible(
+                        WifiDppUtils.isSupportConfiguratorQrCodeGenerator(mContext, mAccessPoint));
 
         mSignalStrengthPref = screen.findPreference(KEY_SIGNAL_STRENGTH_PREF);
         mTxLinkSpeedPref = screen.findPreference(KEY_TX_LINK_SPEED);
diff --git a/src/com/android/settings/wifi/dpp/WifiDppQrCodeScannerFragment.java b/src/com/android/settings/wifi/dpp/WifiDppQrCodeScannerFragment.java
index 21920d2..fa17f07 100644
--- a/src/com/android/settings/wifi/dpp/WifiDppQrCodeScannerFragment.java
+++ b/src/com/android/settings/wifi/dpp/WifiDppQrCodeScannerFragment.java
@@ -46,6 +46,7 @@
 import android.widget.TextView;
 
 import androidx.annotation.StringRes;
+import androidx.annotation.UiThread;
 import androidx.lifecycle.ViewModelProviders;
 
 import com.android.settings.R;
@@ -57,6 +58,7 @@
 import com.android.settingslib.wifi.WifiTracker;
 import com.android.settingslib.wifi.WifiTrackerFactory;
 
+import java.util.ArrayList;
 import java.util.List;
 
 public class WifiDppQrCodeScannerFragment extends WifiDppQrCodeBaseFragment implements
@@ -104,7 +106,7 @@
     private WifiQrCode mWifiQrCode;
 
     /** The WifiConfiguration connecting for enrollee usage */
-    private WifiConfiguration mWifiConfiguration;
+    private WifiConfiguration mEnrolleeWifiConfiguration;
 
     private int mLatestStatusCode = WifiDppUtils.EASY_CONNECT_EVENT_FAILURE_NONE;
 
@@ -140,14 +142,8 @@
                     break;
 
                 case MESSAGE_SCAN_WIFI_DPP_SUCCESS:
-                    if (mCamera != null) {
-                        mCamera.stop();
-                    }
-
-                    mDecorateView.setFocused(true);
-                    mErrorMessage.setVisibility(View.INVISIBLE);
-
                     if (mScanWifiDppSuccessListener == null) {
+                        // mScanWifiDppSuccessListener may be null after onDetach(), do nothing here
                         return;
                     }
                     mScanWifiDppSuccessListener.onScanWifiDppSuccess((WifiQrCode)msg.obj);
@@ -160,23 +156,43 @@
                                 AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
                     }
 
-                    WifiDppUtils.triggerVibrationForQrCodeRecognition(getContext());
+                    notifyUserForQrCodeRecognition();
                     break;
 
                 case MESSAGE_SCAN_ZXING_WIFI_FORMAT_SUCCESS:
-                    if (mCamera != null) {
-                        mCamera.stop();
+                    // We may get 2 WifiConfiguration if the QR code has no password in it,
+                    // one for open network and one for enhanced open network.
+                    final WifiManager wifiManager =
+                            getContext().getSystemService(WifiManager.class);
+                    final WifiNetworkConfig qrCodeWifiNetworkConfig =
+                            (WifiNetworkConfig)msg.obj;
+                    final List<WifiConfiguration> qrCodeWifiConfigurations =
+                            qrCodeWifiNetworkConfig.getWifiConfigurations();
+
+                    // Adds all Wi-Fi networks in QR code to the set of configured networks and
+                    // connects to it if it's reachable.
+                    boolean hasReachableWifiNetwork = false;
+                    for (WifiConfiguration qrCodeWifiConfiguration : qrCodeWifiConfigurations) {
+                        final int id = wifiManager.addNetwork(qrCodeWifiConfiguration);
+                        if (id == -1) {
+                            continue;
+                        }
+                        wifiManager.enableNetwork(id, /* attemptConnect */ false);
+                        if (isReachableWifiNetwork(qrCodeWifiConfiguration)) {
+                            hasReachableWifiNetwork = true;
+                            mEnrolleeWifiConfiguration = qrCodeWifiConfiguration;
+                            wifiManager.connect(id,
+                                    /* listener */ WifiDppQrCodeScannerFragment.this);
+                        }
                     }
 
-                    mDecorateView.setFocused(true);
-                    mErrorMessage.setVisibility(View.INVISIBLE);
+                    if (hasReachableWifiNetwork == false) {
+                        showErrorMessageAndRestartCamera(
+                                R.string.wifi_dpp_check_connection_try_again);
+                        return;
+                    }
 
-                    final WifiNetworkConfig wifiNetworkConfig = (WifiNetworkConfig)msg.obj;
-                    mWifiConfiguration = wifiNetworkConfig.getWifiConfigurationOrNull();
-                    wifiNetworkConfig.connect(getContext(),
-                            /* listener */ WifiDppQrCodeScannerFragment.this);
-
-                    WifiDppUtils.triggerVibrationForQrCodeRecognition(getContext());
+                    notifyUserForQrCodeRecognition();
                     break;
 
                 default:
@@ -185,6 +201,30 @@
         }
     };
 
+    @UiThread
+    private void notifyUserForQrCodeRecognition() {
+        if (mCamera != null) {
+            mCamera.stop();
+        }
+
+        mDecorateView.setFocused(true);
+        mErrorMessage.setVisibility(View.INVISIBLE);
+
+        WifiDppUtils.triggerVibrationForQrCodeRecognition(getContext());
+    }
+
+    private boolean isReachableWifiNetwork(WifiConfiguration wifiConfiguration) {
+        final List<AccessPoint> scannedAccessPoints = mWifiTracker.getAccessPoints();
+
+        for (AccessPoint scannedAccessPoint : scannedAccessPoints) {
+            if (scannedAccessPoint.matches(wifiConfiguration) &&
+                    scannedAccessPoint.isReachable()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -192,7 +232,7 @@
         if (savedInstanceState != null) {
             mIsConfiguratorMode = savedInstanceState.getBoolean(KEY_IS_CONFIGURATOR_MODE);
             mLatestStatusCode = savedInstanceState.getInt(KEY_LATEST_ERROR_CODE);
-            mWifiConfiguration = savedInstanceState.getParcelable(KEY_WIFI_CONFIGURATION);
+            mEnrolleeWifiConfiguration = savedInstanceState.getParcelable(KEY_WIFI_CONFIGURATION);
         }
 
         final WifiDppInitiatorViewModel model =
@@ -480,7 +520,7 @@
     public void onSaveInstanceState(Bundle outState) {
         outState.putBoolean(KEY_IS_CONFIGURATOR_MODE, mIsConfiguratorMode);
         outState.putInt(KEY_LATEST_ERROR_CODE, mLatestStatusCode);
-        outState.putParcelable(KEY_WIFI_CONFIGURATION, mWifiConfiguration);
+        outState.putParcelable(KEY_WIFI_CONFIGURATION, mEnrolleeWifiConfiguration);
 
         super.onSaveInstanceState(outState);
     }
@@ -496,7 +536,7 @@
             for (WifiConfiguration wifiConfig : wifiConfigs) {
                 if (wifiConfig.networkId == newNetworkId) {
                     mLatestStatusCode = WifiDppUtils.EASY_CONNECT_EVENT_SUCCESS;
-                    mWifiConfiguration = wifiConfig;
+                    mEnrolleeWifiConfiguration = wifiConfig;
                     wifiManager.connect(wifiConfig, WifiDppQrCodeScannerFragment.this);
                     return;
                 }
@@ -588,17 +628,13 @@
 
     @Override
     public void onSuccess() {
-        if (isEnrollingWifiNetworkReachable()) {
-            final Intent resultIntent = new Intent();
-            resultIntent.putExtra(WifiDialogActivity.KEY_WIFI_CONFIGURATION, mWifiConfiguration);
+        final Intent resultIntent = new Intent();
+        resultIntent.putExtra(WifiDialogActivity.KEY_WIFI_CONFIGURATION,
+                mEnrolleeWifiConfiguration);
 
-            final Activity hostActivity = getActivity();
-            hostActivity.setResult(Activity.RESULT_OK, resultIntent);
-            hostActivity.finish();
-        } else {
-            Log.d(TAG, "Enroll Wi-Fi network succeeded but it's not reachable");
-            showErrorMessageAndRestartCamera(R.string.wifi_dpp_check_connection_try_again);
-        }
+        final Activity hostActivity = getActivity();
+        hostActivity.setResult(Activity.RESULT_OK, resultIntent);
+        hostActivity.finish();
     }
 
     @Override
@@ -607,22 +643,6 @@
         showErrorMessageAndRestartCamera(R.string.wifi_dpp_check_connection_try_again);
     }
 
-    private boolean isEnrollingWifiNetworkReachable() {
-        if (mWifiConfiguration == null) {
-            Log.e(TAG, "Connect succeeded but lost WifiConfiguration");
-            return false;
-        }
-
-        final List<AccessPoint> scannedAccessPoints = mWifiTracker.getAccessPoints();
-        for (AccessPoint accessPoint : scannedAccessPoints) {
-            if (accessPoint.matches(mWifiConfiguration) &&
-                    accessPoint.isReachable()) {
-                return true;
-            }
-        }
-        return false;
-    }
-
     // Check is Easy Connect handshaking or not
     private boolean isGoingInitiator() {
         final WifiDppInitiatorViewModel model =
diff --git a/src/com/android/settings/wifi/dpp/WifiDppUtils.java b/src/com/android/settings/wifi/dpp/WifiDppUtils.java
index 2ec3137..695de76 100644
--- a/src/com/android/settings/wifi/dpp/WifiDppUtils.java
+++ b/src/com/android/settings/wifi/dpp/WifiDppUtils.java
@@ -162,6 +162,9 @@
         if (config.allowedKeyManagement.get(KeyMgmt.SAE)) {
             return WifiQrCode.SECURITY_SAE;
         }
+        if (config.allowedKeyManagement.get(KeyMgmt.OWE)) {
+            return WifiQrCode.SECURITY_NO_PASSWORD;
+        }
         if (config.allowedKeyManagement.get(KeyMgmt.WPA_PSK) ||
                 config.allowedKeyManagement.get(KeyMgmt.WPA2_PSK)) {
             return WifiQrCode.SECURITY_WPA_PSK;
@@ -185,7 +188,7 @@
     public static Intent getConfiguratorQrCodeGeneratorIntentOrNull(Context context,
             WifiManager wifiManager, AccessPoint accessPoint) {
         final Intent intent = new Intent(context, WifiDppConfiguratorActivity.class);
-        if (isSupportConfiguratorQrCodeGenerator(accessPoint)) {
+        if (isSupportConfiguratorQrCodeGenerator(context, accessPoint)) {
             intent.setAction(WifiDppConfiguratorActivity.ACTION_CONFIGURATOR_QR_CODE_GENERATOR);
         } else {
             return null;
@@ -343,22 +346,24 @@
     /**
      * Checks if QR code generator supports to config other devices with the Wi-Fi network
      *
+     * @param context The context to use for {@code WifiManager}
      * @param accessPoint The {@link AccessPoint} of the Wi-Fi network
      */
-    public static boolean isSupportConfiguratorQrCodeGenerator(AccessPoint accessPoint) {
-        return isSupportZxing(accessPoint.getSecurity());
+    public static boolean isSupportConfiguratorQrCodeGenerator(Context context,
+            AccessPoint accessPoint) {
+        return isSupportZxing(context, accessPoint.getSecurity());
     }
 
     /**
      * Checks if this device supports to be configured by the Wi-Fi network of the security
      *
-     * @param context The context to use for {@link WifiManager#isEasyConnectSupported()}
+     * @param context The context to use for {@code WifiManager}
      * @param accesspointSecurity The security constants defined in {@link AccessPoint}
      */
     public static boolean isSupportEnrolleeQrCodeScanner(Context context,
             int accesspointSecurity) {
         return isSupportWifiDpp(context, accesspointSecurity) ||
-                isSupportZxing(accesspointSecurity);
+                isSupportZxing(context, accesspointSecurity);
     }
 
     private static boolean isSupportHotspotConfiguratorQrCodeGenerator(
@@ -376,19 +381,38 @@
         }
 
         // DPP 1.0 only supports SAE and PSK.
-        if (accesspointSecurity == AccessPoint.SECURITY_SAE ||
-                accesspointSecurity == AccessPoint.SECURITY_PSK) {
-            return true;
+        final WifiManager wifiManager = context.getSystemService(WifiManager.class);
+        switch (accesspointSecurity) {
+            case AccessPoint.SECURITY_SAE:
+                if (wifiManager.isWpa3SaeSupported()) {
+                    return true;
+                }
+                break;
+            case AccessPoint.SECURITY_PSK:
+                return true;
+            default:
         }
         return false;
     }
 
-    // TODO (b/124131581 b/129396816): TO support WPA3 securities (SAE & OWE), change here at first
-    private static boolean isSupportZxing(int accesspointSecurity) {
-        if (accesspointSecurity == AccessPoint.SECURITY_PSK ||
-                accesspointSecurity == AccessPoint.SECURITY_WEP ||
-                accesspointSecurity == AccessPoint.SECURITY_NONE) {
-            return true;
+    private static boolean isSupportZxing(Context context, int accesspointSecurity) {
+        final WifiManager wifiManager = context.getSystemService(WifiManager.class);
+        switch (accesspointSecurity) {
+            case AccessPoint.SECURITY_PSK:
+            case AccessPoint.SECURITY_WEP:
+            case AccessPoint.SECURITY_NONE:
+                return true;
+            case AccessPoint.SECURITY_SAE:
+                if (wifiManager.isWpa3SaeSupported()) {
+                    return true;
+                }
+                break;
+            case AccessPoint.SECURITY_OWE:
+                if (wifiManager.isEnhancedOpenSupported()) {
+                    return true;
+                }
+                break;
+            default:
         }
         return false;
     }
diff --git a/src/com/android/settings/wifi/dpp/WifiNetworkConfig.java b/src/com/android/settings/wifi/dpp/WifiNetworkConfig.java
index fdc74d8..7423561 100644
--- a/src/com/android/settings/wifi/dpp/WifiNetworkConfig.java
+++ b/src/com/android/settings/wifi/dpp/WifiNetworkConfig.java
@@ -32,6 +32,9 @@
 
 import androidx.annotation.VisibleForTesting;
 
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * Wraps the parameters of ZXing reader library's Wi-Fi Network config format.
  * Please check {@code WifiQrCode} for detail of the format.
@@ -203,50 +206,63 @@
         return mIsHotspot;
     }
 
-    public void connect(Context context, WifiManager.ActionListener listener) {
-        WifiConfiguration wifiConfiguration = getWifiConfigurationOrNull();
-        if (wifiConfiguration == null) {
-            if (listener != null) {
-                listener.onFailure(WifiManager.ERROR);
-            }
-            return;
-        }
-
-        WifiManager wifiManager = (WifiManager)context.getSystemService(Context.WIFI_SERVICE);
-        wifiManager.connect(wifiConfiguration, listener);
-    }
-
     public boolean isSupportWifiDpp(Context context) {
         if (!WifiDppUtils.isWifiDppEnabled(context)) {
             return false;
         }
 
-        // DPP 1.0 only supports SAE and PSK.
-        if (SECURITY_SAE.equals(mSecurity) || SECURITY_WPA_PSK.equals(mSecurity)) {
-            return true;
+        if (TextUtils.isEmpty(mSecurity)) {
+            return false;
         }
 
+        // DPP 1.0 only supports SAE and PSK.
+        final WifiManager wifiManager = context.getSystemService(WifiManager.class);
+        switch (mSecurity) {
+            case SECURITY_SAE:
+                if (wifiManager.isWpa3SaeSupported()) {
+                    return true;
+                }
+                break;
+            case SECURITY_WPA_PSK:
+                return true;
+            default:
+        }
         return false;
     }
 
     /**
      * This is a simplified method from {@code WifiConfigController.getConfig()}
+     *
+     * TODO (b/129021867): WifiConfiguration is a deprecated class, should replace it with
+     *       {@code android.net.wifi.WifiNetworkSuggestion}
+     *
+     * @return When it's a open network, returns 2 WifiConfiguration in the List, the 1st is
+     *         open network and the 2nd is enhanced open network. Returns 1 WifiConfiguration in the
+     *         List for all other supported Wi-Fi securities.
      */
-    WifiConfiguration getWifiConfigurationOrNull() {
-        if (!isValidConfig(this)) {
-            return null;
-        }
+    List<WifiConfiguration> getWifiConfigurations() {
+        final List<WifiConfiguration> wifiConfigurations = new ArrayList<>();
 
-        final WifiConfiguration wifiConfiguration = new WifiConfiguration();
-        wifiConfiguration.SSID = addQuotationIfNeeded(mSsid);
-        wifiConfiguration.hiddenSSID = mHiddenSsid;
-        wifiConfiguration.networkId = mNetworkId;
+        if (!isValidConfig(this)) {
+            return wifiConfigurations;
+        }
 
         if (TextUtils.isEmpty(mSecurity) || SECURITY_NO_PASSWORD.equals(mSecurity)) {
-            wifiConfiguration.allowedKeyManagement.set(KeyMgmt.NONE);
-            return wifiConfiguration;
+            // TODO (b/129835824): we add both open network and enhanced open network to WifiManager
+            //                     for android Q, should improve it in the future.
+            final WifiConfiguration openNetworkWifiConfiguration = getBasicWifiConfiguration();
+            openNetworkWifiConfiguration.allowedKeyManagement.set(KeyMgmt.NONE);
+            wifiConfigurations.add(openNetworkWifiConfiguration);
+
+            final WifiConfiguration enhancedOpenNetworkWifiConfiguration =
+                    getBasicWifiConfiguration();
+            enhancedOpenNetworkWifiConfiguration.allowedKeyManagement.set(KeyMgmt.OWE);
+            enhancedOpenNetworkWifiConfiguration.requirePMF = true;
+            wifiConfigurations.add(enhancedOpenNetworkWifiConfiguration);
+            return wifiConfigurations;
         }
 
+        final WifiConfiguration wifiConfiguration = getBasicWifiConfiguration();
         if (mSecurity.startsWith(SECURITY_WEP)) {
             wifiConfiguration.allowedKeyManagement.set(KeyMgmt.NONE);
             wifiConfiguration.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN);
@@ -268,11 +284,27 @@
             } else {
                 wifiConfiguration.preSharedKey = addQuotationIfNeeded(mPreSharedKey);
             }
+        } else if (mSecurity.startsWith(SECURITY_SAE)) {
+            wifiConfiguration.allowedKeyManagement.set(KeyMgmt.SAE);
+            wifiConfiguration.requirePMF = true;
+            if (mPreSharedKey.length() != 0) {
+                wifiConfiguration.preSharedKey = addQuotationIfNeeded(mPreSharedKey);
+            }
         } else {
             Log.w(TAG, "Unsupported security");
-            return null;
+            return wifiConfigurations;
         }
 
+        wifiConfigurations.add(wifiConfiguration);
+        return wifiConfigurations;
+    }
+
+    private WifiConfiguration getBasicWifiConfiguration() {
+        final WifiConfiguration wifiConfiguration = new WifiConfiguration();
+
+        wifiConfiguration.SSID = addQuotationIfNeeded(mSsid);
+        wifiConfiguration.hiddenSSID = mHiddenSsid;
+        wifiConfiguration.networkId = mNetworkId;
         return wifiConfiguration;
     }
 
diff --git a/src/com/android/settings/wifi/dpp/WifiQrCode.java b/src/com/android/settings/wifi/dpp/WifiQrCode.java
index 8296a62..40ae111 100644
--- a/src/com/android/settings/wifi/dpp/WifiQrCode.java
+++ b/src/com/android/settings/wifi/dpp/WifiQrCode.java
@@ -64,10 +64,10 @@
     public static final String DELIMITER_QR_CODE = ";";
 
     // Ignores password if security is SECURITY_NO_PASSWORD or absent
-    public static final String SECURITY_NO_PASSWORD = "nopass";
+    public static final String SECURITY_NO_PASSWORD = "nopass"; //open network or OWE
     public static final String SECURITY_WEP = "WEP";
     public static final String SECURITY_WPA_PSK = "WPA";
-    public static final String SECURITY_SAE = "WPA3";
+    public static final String SECURITY_SAE = "SAE";
 
     private String mQrCode;
 
diff --git a/tests/unit/src/com/android/settings/wifi/dpp/WifiQrCodeTest.java b/tests/unit/src/com/android/settings/wifi/dpp/WifiQrCodeTest.java
index 3595597..e4d3a7b 100644
--- a/tests/unit/src/com/android/settings/wifi/dpp/WifiQrCodeTest.java
+++ b/tests/unit/src/com/android/settings/wifi/dpp/WifiQrCodeTest.java
@@ -41,9 +41,13 @@
             "SN=4774LH2b4044";
 
     // Valid ZXing reader library's Wi-Fi Network config format & it's parameters
-    private static final String VALID_ZXING_WIFI_QR_CODE =
+    private static final String VALID_ZXING_WIFI_QR_CODE_WPA =
             "WIFI:T:WPA;S:mynetwork;P:mypass;H:true;;";
 
+     // Valid ZXing reader library's Wi-Fi Network config format - security type SAE
+    private static final String VALID_ZXING_WIFI_QR_CODE_SAE =
+            "WIFI:T:SAE;S:mynetwork;P:mypass;H:true;;";
+
     // Valid ZXing reader library's Wi-Fi Network config format - security type nopass and no password
     private static final String VALID_ZXING_WIFI_QR_CODE_NOPASS_AND_NO_PASSWORD =
             "WIFI:T:nopass;S:mynetwork;;";
@@ -52,7 +56,8 @@
     private static final String VALID_ZXING_WIFI_QR_CODE_NO_SECURITY_AND_NO_PASSWORD =
             "WIFI:T:;S:mynetwork;P:;H:false;;";
 
-    private static final String SECURITY_OF_VALID_ZXING_WIFI_QR_CODE = "WPA";
+    private static final String SECURITY_OF_VALID_ZXING_WIFI_QR_CODE_WPA = "WPA";
+    private static final String SECURITY_OF_VALID_ZXING_WIFI_QR_CODE_SAE = "SAE";
     private static final String SECURITY_OF_VALID_ZXING_WIFI_QR_CODE_NOPASS = "nopass";
     private static final String SSID_OF_VALID_ZXING_WIFI_QR_CODE = "mynetwork";
     private static final String PASSWORD_OF_VALID_ZXING_WIFI_QR_CODE = "mypass";
@@ -94,12 +99,25 @@
 
     @Test
     public void parseValidZxingWifiQrCode() {
-        WifiQrCode wifiQrCode = new WifiQrCode(VALID_ZXING_WIFI_QR_CODE);
+        WifiQrCode wifiQrCode = new WifiQrCode(VALID_ZXING_WIFI_QR_CODE_WPA);
         WifiNetworkConfig config = wifiQrCode.getWifiNetworkConfig();
 
         assertEquals(WifiQrCode.SCHEME_ZXING_WIFI_NETWORK_CONFIG, wifiQrCode.getScheme());
         assertNotNull(config);
-        assertEquals(SECURITY_OF_VALID_ZXING_WIFI_QR_CODE, config.getSecurity());
+        assertEquals(SECURITY_OF_VALID_ZXING_WIFI_QR_CODE_WPA, config.getSecurity());
+        assertEquals(SSID_OF_VALID_ZXING_WIFI_QR_CODE, config.getSsid());
+        assertEquals(PASSWORD_OF_VALID_ZXING_WIFI_QR_CODE, config.getPreSharedKey());
+        assertEquals(true, config.getHiddenSsid());
+    }
+
+    @Test
+    public void parseValidZxingWifiQrCodeSae() {
+        WifiQrCode wifiQrCode = new WifiQrCode(VALID_ZXING_WIFI_QR_CODE_SAE);
+        WifiNetworkConfig config = wifiQrCode.getWifiNetworkConfig();
+
+        assertEquals(WifiQrCode.SCHEME_ZXING_WIFI_NETWORK_CONFIG, wifiQrCode.getScheme());
+        assertNotNull(config);
+        assertEquals(SECURITY_OF_VALID_ZXING_WIFI_QR_CODE_SAE, config.getSecurity());
         assertEquals(SSID_OF_VALID_ZXING_WIFI_QR_CODE, config.getSsid());
         assertEquals(PASSWORD_OF_VALID_ZXING_WIFI_QR_CODE, config.getPreSharedKey());
         assertEquals(true, config.getHiddenSsid());
@@ -138,7 +156,7 @@
 
         assertEquals(WifiQrCode.SCHEME_ZXING_WIFI_NETWORK_CONFIG, wifiQrCode.getScheme());
         assertNotNull(config);
-        assertEquals(SECURITY_OF_VALID_ZXING_WIFI_QR_CODE, config.getSecurity());
+        assertEquals(SECURITY_OF_VALID_ZXING_WIFI_QR_CODE_WPA, config.getSecurity());
         assertEquals(SSID_OF_VALID_ZXING_WIFI_QR_CODE, config.getSsid());
         assertEquals(PASSWORD_OF_VALID_ZXING_WIFI_QR_CODE_SPECIAL_CHARACTERS,
                 config.getPreSharedKey());