Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit da211285 authored by Les Lee's avatar Les Lee
Browse files

wifi: fix ADB URI doesn't work

Using old WifiQrCode parsing for ADB Uri.

Flag: EXEMPT bugfix
Bug: 355088188
Test: Manual test & TH
Change-Id: I54a12b03ed9be6dc49fb957df0f1f7b31647810d
parent 8a4a5f20
Loading
Loading
Loading
Loading
+7 −12
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@

package com.android.settings.development;

import android.annotation.Nullable;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
@@ -27,7 +26,6 @@ import android.debug.IAdbManager;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.SurfaceTexture;
import android.net.wifi.WifiConfiguration;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
@@ -49,6 +47,7 @@ import com.android.settings.R;
import com.android.settings.SetupWizardUtils;
import com.android.settings.wifi.dpp.AdbQrCode;
import com.android.settings.wifi.dpp.WifiDppQrCodeBaseFragment;
import com.android.settings.wifi.dpp.WifiNetworkConfig;
import com.android.settingslib.qrcode.QrCamera;
import com.android.settingslib.qrcode.QrDecorateView;

@@ -82,8 +81,7 @@ public class AdbQrcodeScannerFragment extends WifiDppQrCodeBaseFragment implemen

    /** QR code data scanned by camera */
    private AdbQrCode mAdbQrCode;
    @Nullable
    private WifiConfiguration mAdbConfig;
    private WifiNetworkConfig mAdbConfig;

    private IAdbManager mAdbManager;

@@ -289,17 +287,14 @@ public class AdbQrcodeScannerFragment extends WifiDppQrCodeBaseFragment implemen
        AdbQrCode.triggerVibrationForQrCodeRecognition(getContext());
        mVerifyingTextView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
        try {
            if (mAdbConfig != null) {
                mAdbManager.enablePairingByQrCode(mAdbConfig.SSID,
                        mAdbConfig.preSharedKey);
                return;
            }
            mAdbManager.enablePairingByQrCode(mAdbConfig.getSsid(),
                    mAdbConfig.getPreSharedKey());
        } catch (RemoteException e) {
            Log.e(TAG, "Unable to enable QR code pairing" + e);
        }
            Log.e(TAG, "Unable to enable QR code pairing");
            getActivity().setResult(Activity.RESULT_CANCELED);
            getActivity().finish();
        }
    }

    @Override
    public void handleCameraFailure() {
+169 −13
Original line number Diff line number Diff line
@@ -16,11 +16,14 @@
package com.android.settings.wifi.dpp;

import android.content.Context;
import android.net.wifi.UriParserResults;
import android.net.wifi.WifiConfiguration;
import android.text.TextUtils;

import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;

import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;

/**
 * Extension of WifiQrCode to support ADB QR code format.
@@ -28,34 +31,74 @@ import androidx.annotation.NonNull;
 *
 * WIFI:T:ADB;S:myname;P:mypassword;;
 */
public class AdbQrCode extends WifiQrCode {
public class AdbQrCode {
    static final String SECURITY_ADB = "ADB";
    static final String SCHEME_DPP = "DPP";
    static final String SCHEME_ZXING_WIFI_NETWORK_CONFIG = "WIFI";
    static final String PREFIX_DPP = "DPP:";
    static final String PREFIX_ZXING_WIFI_NETWORK_CONFIG = "WIFI:";

    static final String PREFIX_DPP_PUBLIC_KEY = "K:";
    static final String PREFIX_DPP_INFORMATION = "I:";

    private WifiConfiguration mAdbConfig;
    static final String PREFIX_ZXING_SECURITY = "T:";
    static final String PREFIX_ZXING_SSID = "S:";
    static final String PREFIX_ZXING_PASSWORD = "P:";
    static final String PREFIX_ZXING_HIDDEN_SSID = "H:";
    static final String DELIMITER_QR_CODE = ";";
    // Ignores password if security is SECURITY_NO_PASSWORD or absent
    static final String SECURITY_NO_PASSWORD = "nopass"; //open network or OWE
    static final String SECURITY_WEP = "WEP";
    static final String SECURITY_WPA_PSK = "WPA";
    static final String SECURITY_SAE = "SAE";
    private String mQrCode;
    /**
     * SCHEME_DPP for standard Wi-Fi device provision protocol; SCHEME_ZXING_WIFI_NETWORK_CONFIG
     * for ZXing reader library' Wi-Fi Network config format
     */
    private String mScheme;
    // Data from parsed Wi-Fi DPP QR code
    private String mPublicKey;
    private String mInformation;
    // Data from parsed ZXing reader library's Wi-Fi Network config format
    private WifiNetworkConfig mAdbConfig;

    public AdbQrCode(String qrCode) throws IllegalArgumentException {
        super(qrCode);
        if (TextUtils.isEmpty(qrCode)) {
            throw new IllegalArgumentException("Empty QR code");
        }

        mQrCode = qrCode;
        if (qrCode.startsWith(PREFIX_DPP)) {
            mScheme = SCHEME_DPP;
            parseWifiDppQrCode(qrCode);
        } else if (qrCode.startsWith(PREFIX_ZXING_WIFI_NETWORK_CONFIG)) {
            mScheme = SCHEME_ZXING_WIFI_NETWORK_CONFIG;
            parseZxingWifiQrCode(qrCode);
        } else {
            throw new IllegalArgumentException("Invalid scheme");
        }

        // Only accept the zxing format.
        if (getScheme() != UriParserResults.URI_SCHEME_ZXING_WIFI_NETWORK_CONFIG) {
        if (!SCHEME_ZXING_WIFI_NETWORK_CONFIG.equals(getScheme())) {
            throw new IllegalArgumentException("DPP format not supported for ADB QR code");
        }
        mAdbConfig = getWifiConfiguration();
        mAdbConfig = getWifiNetworkConfig();

        if (mAdbConfig == null) {
            throw new IllegalArgumentException("Null config when parsing ADB QR code");
        if (!SECURITY_ADB.equals(mAdbConfig.getSecurity())) {
            throw new IllegalArgumentException("Invalid security type");
        }
        if (TextUtils.isEmpty(mAdbConfig.SSID)) {

        if (TextUtils.isEmpty(mAdbConfig.getSsid())) {
            throw new IllegalArgumentException("Empty service name");
        }

        if (TextUtils.isEmpty(mAdbConfig.preSharedKey)) {
        if (TextUtils.isEmpty(mAdbConfig.getPreSharedKey())) {
            throw new IllegalArgumentException("Empty password");
        }
    }

    @NonNull
    public WifiConfiguration getAdbNetworkConfig() {
    public WifiNetworkConfig getAdbNetworkConfig() {
        return mAdbConfig;
    }

@@ -67,4 +110,117 @@ public class AdbQrCode extends WifiQrCode {
    public static void triggerVibrationForQrCodeRecognition(Context context) {
        WifiDppUtils.triggerVibrationForQrCodeRecognition(context);
    }

    /** Parses Wi-Fi DPP QR code string */
    private void parseWifiDppQrCode(String qrCode) throws IllegalArgumentException {
        List<String> keyValueList = getKeyValueList(qrCode, PREFIX_DPP, DELIMITER_QR_CODE);
        String publicKey = getValueOrNull(keyValueList, PREFIX_DPP_PUBLIC_KEY);
        if (TextUtils.isEmpty(publicKey)) {
            throw new IllegalArgumentException("Invalid format");
        }
        mPublicKey = publicKey;
        mInformation = getValueOrNull(keyValueList, PREFIX_DPP_INFORMATION);
    }

    /** Parses ZXing reader library's Wi-Fi Network config format */
    private void parseZxingWifiQrCode(String qrCode) throws IllegalArgumentException {
        List<String> keyValueList = getKeyValueList(qrCode, PREFIX_ZXING_WIFI_NETWORK_CONFIG,
                DELIMITER_QR_CODE);
        String security = getValueOrNull(keyValueList, PREFIX_ZXING_SECURITY);
        String ssid = getValueOrNull(keyValueList, PREFIX_ZXING_SSID);
        String password = getValueOrNull(keyValueList, PREFIX_ZXING_PASSWORD);
        String hiddenSsidString = getValueOrNull(keyValueList, PREFIX_ZXING_HIDDEN_SSID);
        boolean hiddenSsid = "true".equalsIgnoreCase(hiddenSsidString);
        //"\", ";", "," and ":" are escaped with a backslash "\", should remove at first
        security = removeBackSlash(security);
        ssid = removeBackSlash(ssid);
        password = removeBackSlash(password);
        mAdbConfig = WifiNetworkConfig.getValidConfigOrNull(security, ssid, password,
                hiddenSsid, WifiConfiguration.INVALID_NETWORK_ID, /* isHotspot */ false);
        if (mAdbConfig == null) {
            throw new IllegalArgumentException("Invalid format");
        }
    }

    /**
     * Splits key/value pairs from qrCode
     *
     * @param qrCode the QR code raw string
     * @param prefixQrCode the string before all key/value pairs in qrCode
     * @param delimiter the string to split key/value pairs, can't contain a backslash
     * @return a list contains string of key/value (e.g. K:key1)
     */
    private List<String> getKeyValueList(String qrCode, String prefixQrCode,
                String delimiter) {
        String keyValueString = qrCode.substring(prefixQrCode.length());
        // Should not treat \delimiter as a delimiter
        String regex = "(?<!\\\\)" + Pattern.quote(delimiter);
        return Arrays.asList(keyValueString.split(regex));
    }

    private String getValueOrNull(List<String> keyValueList, String prefix) {
        for (String keyValue : keyValueList) {
            String strippedKeyValue = keyValue.stripLeading();
            if (strippedKeyValue.startsWith(prefix)) {
                return strippedKeyValue.substring(prefix.length());
            }
        }
        return null;
    }

    @VisibleForTesting
    String removeBackSlash(String input) {
        if (input == null) {
            return null;
        }
        StringBuilder sb = new StringBuilder();
        boolean backSlash = false;
        for (char ch : input.toCharArray()) {
            if (ch != '\\') {
                sb.append(ch);
                backSlash = false;
            } else {
                if (backSlash) {
                    sb.append(ch);
                    backSlash = false;
                    continue;
                }
                backSlash = true;
            }
        }
        return sb.toString();
    }

    String getQrCode() {
        return mQrCode;
    }

    /**
     * Uses to check type of QR code
     *
     * SCHEME_DPP for standard Wi-Fi device provision protocol; SCHEME_ZXING_WIFI_NETWORK_CONFIG
     * for ZXing reader library' Wi-Fi Network config format
     */
    public String getScheme() {
        return mScheme;
    }

    /** Available when {@code getScheme()} returns SCHEME_DPP */
    @VisibleForTesting
    String getPublicKey() {
        return mPublicKey;
    }

    /** May be available when {@code getScheme()} returns SCHEME_DPP */
    public String getInformation() {
        return mInformation;
    }

    /** Available when {@code getScheme()} returns SCHEME_ZXING_WIFI_NETWORK_CONFIG */
    WifiNetworkConfig getWifiNetworkConfig() {
        if (mAdbConfig == null) {
            return null;
        }
        return new WifiNetworkConfig(mAdbConfig);
    }
}
+65 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.dpp;

import static com.google.common.truth.Truth.assertThat;

import androidx.test.ext.junit.runners.AndroidJUnit4;

import org.junit.Test;
import org.junit.runner.RunWith;

@RunWith(AndroidJUnit4.class)
public class AdbQrCodeTest {
    @Test
    public void testZxParsing_validCode() {
        WifiNetworkConfig config = new AdbQrCode(
                "WIFI:S:reallyLONGone;T:ADB;P:somepasswo#%^**123rd").getWifiNetworkConfig();
        assertThat(config.getSsid()).isEqualTo("reallyLONGone");
        assertThat(config.getSecurity()).isEqualTo("ADB");
        assertThat(config.getPreSharedKey()).isEqualTo("somepasswo#%^**123rd");

        config = new AdbQrCode("WIFI:S:anotherone;T:ADB;P:3#=3j9asicla").getWifiNetworkConfig();
        assertThat(config.getSsid()).isEqualTo("anotherone");
        assertThat(config.getSecurity()).isEqualTo("ADB");
        assertThat(config.getPreSharedKey()).isEqualTo("3#=3j9asicla");

        config = new AdbQrCode("WIFI:S:xx;T:ADB;P:a").getWifiNetworkConfig();
        assertThat(config.getSsid()).isEqualTo("xx");
        assertThat(config.getSecurity()).isEqualTo("ADB");
        assertThat(config.getPreSharedKey()).isEqualTo("a");
    }

    @Test
    public void testZxParsing_invalidCodeButShouldWork() {
        WifiNetworkConfig config = new AdbQrCode(
                "WIFI:S:reallyLONGone;T:ADB; P:somepassword").getWifiNetworkConfig();
        assertThat(config.getSsid()).isEqualTo("reallyLONGone");
        assertThat(config.getSecurity()).isEqualTo("ADB");
        assertThat(config.getPreSharedKey()).isEqualTo("somepassword");

        config = new AdbQrCode("WIFI: S:anotherone;T:ADB;P:abcdefghihklmn").getWifiNetworkConfig();
        assertThat(config.getSsid()).isEqualTo("anotherone");
        assertThat(config.getSecurity()).isEqualTo("ADB");
        assertThat(config.getPreSharedKey()).isEqualTo("abcdefghihklmn");

        config = new AdbQrCode("WIFI: S:xx; T:ADB;   P:a").getWifiNetworkConfig();
        assertThat(config.getSsid()).isEqualTo("xx");
        assertThat(config.getSecurity()).isEqualTo("ADB");
        assertThat(config.getPreSharedKey()).isEqualTo("a");
    }
}