2 * Copyright (C) 2018 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package com.android.settings.wifi.dpp;
19 import static com.android.settings.wifi.dpp.WifiQrCode.SECURITY_NO_PASSWORD;
20 import static com.android.settings.wifi.dpp.WifiQrCode.SECURITY_SAE;
21 import static com.android.settings.wifi.dpp.WifiQrCode.SECURITY_WEP;
22 import static com.android.settings.wifi.dpp.WifiQrCode.SECURITY_WPA_PSK;
24 import android.content.Context;
25 import android.content.Intent;
26 import android.net.wifi.WifiConfiguration;
27 import android.net.wifi.WifiConfiguration.AuthAlgorithm;
28 import android.net.wifi.WifiConfiguration.KeyMgmt;
29 import android.net.wifi.WifiManager;
30 import android.text.TextUtils;
31 import android.util.Log;
33 import androidx.annotation.Keep;
34 import androidx.annotation.VisibleForTesting;
37 * Wraps the parameters of ZXing reader library's Wi-Fi Network config format.
38 * Please check {@code WifiQrCode} for detail of the format.
40 * Checks below members of {@code WifiDppUtils} for more information.
41 * EXTRA_WIFI_SECURITY / EXTRA_WIFI_SSID / EXTRA_WIFI_PRE_SHARED_KEY / EXTRA_WIFI_HIDDEN_SSID /
44 public class WifiNetworkConfig {
46 static final String FAKE_SSID = "fake network";
47 static final String FAKE_PASSWORD = "password";
48 private static final String TAG = "WifiNetworkConfig";
50 private String mSecurity;
52 private String mPreSharedKey;
53 private boolean mHiddenSsid;
54 private int mNetworkId;
57 WifiNetworkConfig(String security, String ssid, String preSharedKey,
58 boolean hiddenSsid, int networkId) {
61 mPreSharedKey = preSharedKey;
62 mHiddenSsid = hiddenSsid;
63 mNetworkId = networkId;
66 public WifiNetworkConfig(WifiNetworkConfig config) {
67 mSecurity = config.mSecurity;
69 mPreSharedKey = config.mPreSharedKey;
70 mHiddenSsid = config.mHiddenSsid;
71 mNetworkId = config.mNetworkId;
75 * Wi-Fi DPP activities should implement this interface for fragments to retrieve the
76 * WifiNetworkConfig for configuration
78 public interface Retriever {
79 public WifiNetworkConfig getWifiNetworkConfig();
83 * Retrieve WifiNetworkConfig from below 2 intents
85 * android.settings.WIFI_DPP_CONFIGURATOR_QR_CODE_GENERATOR
86 * android.settings.WIFI_DPP_CONFIGURATOR_QR_CODE_SCANNER
88 public static WifiNetworkConfig getValidConfigOrNull(Intent intent) {
89 String security = intent.getStringExtra(WifiDppUtils.EXTRA_WIFI_SECURITY);
90 String ssid = intent.getStringExtra(WifiDppUtils.EXTRA_WIFI_SSID);
91 String preSharedKey = intent.getStringExtra(WifiDppUtils.EXTRA_WIFI_PRE_SHARED_KEY);
92 boolean hiddenSsid = intent.getBooleanExtra(WifiDppUtils.EXTRA_WIFI_HIDDEN_SSID, false);
93 int networkId = intent.getIntExtra(WifiDppUtils.EXTRA_WIFI_NETWORK_ID,
94 WifiConfiguration.INVALID_NETWORK_ID);
96 return getValidConfigOrNull(security, ssid, preSharedKey, hiddenSsid, networkId);
99 public static WifiNetworkConfig getValidConfigOrNull(String security, String ssid,
100 String preSharedKey, boolean hiddenSsid, int networkId) {
101 if (!isValidConfig(security, ssid, preSharedKey, hiddenSsid)) {
105 return new WifiNetworkConfig(security, ssid, preSharedKey, hiddenSsid, networkId);
108 public static boolean isValidConfig(WifiNetworkConfig config) {
109 if (config == null) {
112 return isValidConfig(config.mSecurity, config.mSsid, config.mPreSharedKey,
117 public static boolean isValidConfig(String security, String ssid, String preSharedKey,
118 boolean hiddenSsid) {
119 if (!TextUtils.isEmpty(security) && !SECURITY_NO_PASSWORD.equals(security)) {
120 if (TextUtils.isEmpty(preSharedKey)) {
125 if (!hiddenSsid && TextUtils.isEmpty(ssid)) {
133 * Escaped special characters "\", ";", ":", "," with a backslash
134 * See https://github.com/zxing/zxing/wiki/Barcode-Contents
136 private String escapeSpecialCharacters(String str) {
137 if (TextUtils.isEmpty(str)) {
141 StringBuilder buf = new StringBuilder();
142 for (int i = 0; i < str.length(); i++) {
143 char ch = str.charAt(i);
144 if (ch =='\\' || ch == ',' || ch == ';' || ch == ':') {
150 return buf.toString();
154 * Construct a barcode string for WiFi network login.
155 * See https://en.wikipedia.org/wiki/QR_code#WiFi_network_login
157 public String getQrCode() {
158 final String empty = "";
159 String barcode = new StringBuilder("WIFI:")
161 .append(escapeSpecialCharacters(mSsid))
164 .append(TextUtils.isEmpty(mSecurity) ? empty : mSecurity)
167 .append(TextUtils.isEmpty(mPreSharedKey) ? empty
168 : escapeSpecialCharacters(mPreSharedKey))
178 public String getSecurity() {
183 public String getSsid() {
188 public String getPreSharedKey() {
189 return mPreSharedKey;
193 public boolean getHiddenSsid() {
198 public int getNetworkId() {
202 public void connect(Context context, WifiManager.ActionListener listener) {
203 WifiConfiguration wifiConfiguration = getWifiConfigurationOrNull();
204 if (wifiConfiguration == null) {
205 if (listener != null) {
206 listener.onFailure(WifiManager.ERROR);
211 WifiManager wifiManager = (WifiManager)context.getSystemService(Context.WIFI_SERVICE);
212 wifiManager.connect(wifiConfiguration, listener);
215 public boolean isSupportWifiDpp(Context context) {
216 if (!WifiDppUtils.isWifiDppEnabled(context)) {
220 // DPP 1.0 only supports SAE and PSK.
221 if (SECURITY_SAE.equals(mSecurity) || SECURITY_WPA_PSK.equals(mSecurity)) {
229 * This is a simplified method from {@code WifiConfigController.getConfig()}
231 private WifiConfiguration getWifiConfigurationOrNull() {
232 if (!isValidConfig(this)) {
236 final WifiConfiguration wifiConfiguration = new WifiConfiguration();
237 wifiConfiguration.SSID = addQuotationIfNeeded(mSsid);
238 wifiConfiguration.hiddenSSID = mHiddenSsid;
239 wifiConfiguration.networkId = mNetworkId;
241 if (TextUtils.isEmpty(mSecurity) || SECURITY_NO_PASSWORD.equals(mSecurity)) {
242 wifiConfiguration.allowedKeyManagement.set(KeyMgmt.NONE);
243 return wifiConfiguration;
246 if (mSecurity.startsWith(SECURITY_WEP)) {
247 wifiConfiguration.allowedKeyManagement.set(KeyMgmt.NONE);
248 wifiConfiguration.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN);
249 wifiConfiguration.allowedAuthAlgorithms.set(AuthAlgorithm.SHARED);
251 // WEP-40, WEP-104, and 256-bit WEP (WEP-232?)
252 final int length = mPreSharedKey.length();
253 if ((length == 10 || length == 26 || length == 58)
254 && mPreSharedKey.matches("[0-9A-Fa-f]*")) {
255 wifiConfiguration.wepKeys[0] = mPreSharedKey;
257 wifiConfiguration.wepKeys[0] = addQuotationIfNeeded(mPreSharedKey);
259 } else if (mSecurity.startsWith(SECURITY_WPA_PSK)) {
260 wifiConfiguration.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
262 if (mPreSharedKey.matches("[0-9A-Fa-f]{64}")) {
263 wifiConfiguration.preSharedKey = mPreSharedKey;
265 wifiConfiguration.preSharedKey = addQuotationIfNeeded(mPreSharedKey);
268 Log.w(TAG, "Unsupported security");
272 return wifiConfiguration;
275 private String addQuotationIfNeeded(String input) {
276 if (TextUtils.isEmpty(input)) {
280 if (input.length() >= 2 && input.startsWith("\"") && input.endsWith("\"")) {
284 StringBuilder sb = new StringBuilder();
285 sb.append("\"").append(input).append("\"");
286 return sb.toString();