OSDN Git Service

Fix Settings crash after clicking 'Share Wi-Fi' button
[android-x86/packages-apps-Settings.git] / src / com / android / settings / wifi / dpp / WifiNetworkConfig.java
1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
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
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 package com.android.settings.wifi.dpp;
18
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;
23
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;
32
33 import androidx.annotation.Keep;
34 import androidx.annotation.VisibleForTesting;
35
36 /**
37  * Wraps the parameters of ZXing reader library's Wi-Fi Network config format.
38  * Please check {@code WifiQrCode} for detail of the format.
39  *
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 /
42  * EXTRA_QR_CODE
43  */
44 public class WifiNetworkConfig {
45
46     static final String FAKE_SSID = "fake network";
47     static final String FAKE_PASSWORD = "password";
48     private static final String TAG = "WifiNetworkConfig";
49
50     private String mSecurity;
51     private String mSsid;
52     private String mPreSharedKey;
53     private boolean mHiddenSsid;
54     private int mNetworkId;
55
56     @VisibleForTesting
57     WifiNetworkConfig(String security, String ssid, String preSharedKey,
58             boolean hiddenSsid, int networkId) {
59         mSecurity = security;
60         mSsid = ssid;
61         mPreSharedKey = preSharedKey;
62         mHiddenSsid = hiddenSsid;
63         mNetworkId = networkId;
64     }
65
66     public WifiNetworkConfig(WifiNetworkConfig config) {
67         mSecurity = config.mSecurity;
68         mSsid = config.mSsid;
69         mPreSharedKey = config.mPreSharedKey;
70         mHiddenSsid = config.mHiddenSsid;
71         mNetworkId = config.mNetworkId;
72     }
73
74     /**
75      * Wi-Fi DPP activities should implement this interface for fragments to retrieve the
76      * WifiNetworkConfig for configuration
77      */
78     public interface Retriever {
79         public WifiNetworkConfig getWifiNetworkConfig();
80     }
81
82     /**
83      * Retrieve WifiNetworkConfig from below 2 intents
84      *
85      * android.settings.WIFI_DPP_CONFIGURATOR_QR_CODE_GENERATOR
86      * android.settings.WIFI_DPP_CONFIGURATOR_QR_CODE_SCANNER
87      */
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);
95
96         return getValidConfigOrNull(security, ssid, preSharedKey, hiddenSsid, networkId);
97     }
98
99     public static WifiNetworkConfig getValidConfigOrNull(String security, String ssid,
100             String preSharedKey, boolean hiddenSsid, int networkId) {
101         if (!isValidConfig(security, ssid, preSharedKey, hiddenSsid)) {
102             return null;
103         }
104
105         return new WifiNetworkConfig(security, ssid, preSharedKey, hiddenSsid, networkId);
106     }
107
108     public static boolean isValidConfig(WifiNetworkConfig config) {
109         if (config == null) {
110             return false;
111         } else {
112             return isValidConfig(config.mSecurity, config.mSsid, config.mPreSharedKey,
113                     config.mHiddenSsid);
114         }
115     }
116
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)) {
121                 return false;
122             }
123         }
124
125         if (!hiddenSsid && TextUtils.isEmpty(ssid)) {
126             return false;
127         }
128
129         return true;
130     }
131
132     /**
133      * Escaped special characters "\", ";", ":", "," with a backslash
134      * See https://github.com/zxing/zxing/wiki/Barcode-Contents
135      */
136     private String escapeSpecialCharacters(String str) {
137         if (TextUtils.isEmpty(str)) {
138             return str;
139         }
140
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 == ':') {
145                 buf.append('\\');
146             }
147             buf.append(ch);
148         }
149
150         return buf.toString();
151     }
152
153     /**
154      * Construct a barcode string for WiFi network login.
155      * See https://en.wikipedia.org/wiki/QR_code#WiFi_network_login
156      */
157     public String getQrCode() {
158         final String empty = "";
159         String barcode = new StringBuilder("WIFI:")
160                 .append("S:")
161                 .append(escapeSpecialCharacters(mSsid))
162                 .append(";")
163                 .append("T:")
164                 .append(TextUtils.isEmpty(mSecurity) ? empty : mSecurity)
165                 .append(";")
166                 .append("P:")
167                 .append(TextUtils.isEmpty(mPreSharedKey) ? empty
168                         : escapeSpecialCharacters(mPreSharedKey))
169                 .append(";")
170                 .append("H:")
171                 .append(mHiddenSsid)
172                 .append(";;")
173                 .toString();
174         return barcode;
175     }
176
177     @Keep
178     public String getSecurity() {
179         return mSecurity;
180     }
181
182     @Keep
183     public String getSsid() {
184         return mSsid;
185     }
186
187     @Keep
188     public String getPreSharedKey() {
189         return mPreSharedKey;
190     }
191
192     @Keep
193     public boolean getHiddenSsid() {
194         return mHiddenSsid;
195     }
196
197     @Keep
198     public int getNetworkId() {
199         return mNetworkId;
200     }
201
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);
207             }
208             return;
209         }
210
211         WifiManager wifiManager = (WifiManager)context.getSystemService(Context.WIFI_SERVICE);
212         wifiManager.connect(wifiConfiguration, listener);
213     }
214
215     public boolean isSupportWifiDpp(Context context) {
216         if (!WifiDppUtils.isWifiDppEnabled(context)) {
217             return false;
218         }
219
220         // DPP 1.0 only supports SAE and PSK.
221         if (SECURITY_SAE.equals(mSecurity) || SECURITY_WPA_PSK.equals(mSecurity)) {
222             return true;
223         }
224
225         return false;
226     }
227
228     /**
229      * This is a simplified method from {@code WifiConfigController.getConfig()}
230      */
231     private WifiConfiguration getWifiConfigurationOrNull() {
232         if (!isValidConfig(this)) {
233             return null;
234         }
235
236         final WifiConfiguration wifiConfiguration = new WifiConfiguration();
237         wifiConfiguration.SSID = addQuotationIfNeeded(mSsid);
238         wifiConfiguration.hiddenSSID = mHiddenSsid;
239         wifiConfiguration.networkId = mNetworkId;
240
241         if (TextUtils.isEmpty(mSecurity) || SECURITY_NO_PASSWORD.equals(mSecurity)) {
242             wifiConfiguration.allowedKeyManagement.set(KeyMgmt.NONE);
243             return wifiConfiguration;
244         }
245
246         if (mSecurity.startsWith(SECURITY_WEP)) {
247             wifiConfiguration.allowedKeyManagement.set(KeyMgmt.NONE);
248             wifiConfiguration.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN);
249             wifiConfiguration.allowedAuthAlgorithms.set(AuthAlgorithm.SHARED);
250
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;
256             } else {
257                 wifiConfiguration.wepKeys[0] = addQuotationIfNeeded(mPreSharedKey);
258             }
259         } else if (mSecurity.startsWith(SECURITY_WPA_PSK)) {
260             wifiConfiguration.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
261
262             if (mPreSharedKey.matches("[0-9A-Fa-f]{64}")) {
263                 wifiConfiguration.preSharedKey = mPreSharedKey;
264             } else {
265                 wifiConfiguration.preSharedKey = addQuotationIfNeeded(mPreSharedKey);
266             }
267         } else {
268             Log.w(TAG, "Unsupported security");
269             return null;
270         }
271
272         return wifiConfiguration;
273     }
274
275     private String addQuotationIfNeeded(String input) {
276         if (TextUtils.isEmpty(input)) {
277             return "";
278         }
279
280         if (input.length() >= 2 && input.startsWith("\"") && input.endsWith("\"")) {
281             return input;
282         }
283
284         StringBuilder sb = new StringBuilder();
285         sb.append("\"").append(input).append("\"");
286         return sb.toString();
287     }
288 }