OSDN Git Service

65be11cef4b8b18452ad7eb74cbd9a6c423bf453
[android-x86/packages-apps-Settings.git] / src / com / android / settings / wifi / dpp / WifiDppConfiguratorActivity.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 android.app.ActionBar;
20 import android.app.settings.SettingsEnums;
21 import android.content.Intent;
22 import android.net.wifi.WifiConfiguration;
23 import android.net.wifi.WifiInfo;
24 import android.net.wifi.WifiManager;
25 import android.os.Bundle;
26 import android.provider.Settings;
27 import android.util.Log;
28
29 import androidx.annotation.VisibleForTesting;
30 import androidx.fragment.app.Fragment;
31 import androidx.fragment.app.FragmentManager;
32 import androidx.fragment.app.FragmentTransaction;
33
34 import com.android.settings.R;
35 import com.android.settings.core.InstrumentedActivity;
36
37 import java.util.List;
38
39 /**
40  * To provision "other" device with specified Wi-Fi network.
41  *
42  * Uses different intents to specify different provisioning ways.
43  *
44  * For intent action {@code ACTION_CONFIGURATOR_QR_CODE_SCANNER} and
45  * {@code android.settings.WIFI_DPP_CONFIGURATOR_QR_CODE_GENERATOR}, specify the Wi-Fi network to be
46  * provisioned in:
47  *
48  * {@code WifiDppUtils.EXTRA_WIFI_SECURITY}
49  * {@code WifiDppUtils.EXTRA_WIFI_SSID}
50  * {@code WifiDppUtils.EXTRA_WIFI_PRE_SHARED_KEY}
51  * {@code WifiDppUtils.EXTRA_WIFI_HIDDEN_SSID}
52  *
53  * For intent action {@link Settings#ACTION_PROCESS_WIFI_EASY_CONNECT_QR_CODE}, specify Wi-Fi (DPP)
54  * QR code in {@code WifiDppUtils.EXTRA_QR_CODE}
55  */
56 public class WifiDppConfiguratorActivity extends InstrumentedActivity implements
57         WifiNetworkConfig.Retriever,
58         WifiDppQrCodeGeneratorFragment.OnQrCodeGeneratorFragmentAddButtonClickedListener,
59         WifiDppQrCodeScannerFragment.OnScanWifiDppSuccessListener,
60         WifiDppQrCodeScannerFragment.OnScanZxingWifiFormatSuccessListener,
61         WifiDppAddDeviceFragment.OnClickChooseDifferentNetworkListener,
62         WifiNetworkListFragment.OnChooseNetworkListener {
63
64     private static final String TAG = "WifiDppConfiguratorActivity";
65
66     public static final String ACTION_CONFIGURATOR_QR_CODE_SCANNER =
67             "android.settings.WIFI_DPP_CONFIGURATOR_QR_CODE_SCANNER";
68     public static final String ACTION_CONFIGURATOR_QR_CODE_GENERATOR =
69             "android.settings.WIFI_DPP_CONFIGURATOR_QR_CODE_GENERATOR";
70
71     // Key for Bundle usage
72     private static final String KEY_QR_CODE = "key_qr_code";
73     private static final String KEY_WIFI_SECURITY = "key_wifi_security";
74     private static final String KEY_WIFI_SSID = "key_wifi_ssid";
75     private static final String KEY_WIFI_PRESHARED_KEY = "key_wifi_preshared_key";
76     private static final String KEY_WIFI_HIDDEN_SSID = "key_wifi_hidden_ssid";
77     private static final String KEY_WIFI_NETWORK_ID = "key_wifi_network_id";
78
79     private FragmentManager mFragmentManager;
80
81     /** The Wi-Fi network which will be configured */
82     private WifiNetworkConfig mWifiNetworkConfig;
83
84     /** The Wi-Fi DPP QR code from intent ACTION_PROCESS_WIFI_EASY_CONNECT_QR_CODE */
85     private WifiQrCode mWifiDppQrCode;
86
87     /** Secret extra that allows fake networks to show in UI for testing purposes */
88     private boolean mIsTest;
89
90     @Override
91     public int getMetricsCategory() {
92         return SettingsEnums.SETTINGS_WIFI_DPP_CONFIGURATOR;
93     }
94
95     @Override
96     protected void onCreate(Bundle savedInstanceState) {
97         super.onCreate(savedInstanceState);
98
99         setContentView(R.layout.wifi_dpp_activity);
100         mFragmentManager = getSupportFragmentManager();
101
102         if (savedInstanceState != null) {
103             String qrCode = savedInstanceState.getString(KEY_QR_CODE);
104
105             mWifiDppQrCode = getValidWifiDppQrCodeOrNull(qrCode);
106
107             String security = savedInstanceState.getString(KEY_WIFI_SECURITY);
108             String ssid = savedInstanceState.getString(KEY_WIFI_SSID);
109             String preSharedKey = savedInstanceState.getString(KEY_WIFI_PRESHARED_KEY);
110             boolean hiddenSsid = savedInstanceState.getBoolean(KEY_WIFI_HIDDEN_SSID);
111             int networkId = savedInstanceState.getInt(KEY_WIFI_NETWORK_ID);
112
113             mWifiNetworkConfig = WifiNetworkConfig.getValidConfigOrNull(security, ssid,
114                     preSharedKey, hiddenSsid, networkId);
115         } else {
116             handleIntent(getIntent());
117         }
118
119         ActionBar actionBar = getActionBar();
120         if (actionBar != null) {
121             actionBar.setElevation(0);
122             actionBar.setDisplayShowTitleEnabled(false);
123         }
124     }
125
126     private void handleIntent(Intent intent) {
127         boolean cancelActivity = false;
128         WifiNetworkConfig config;
129         switch (intent.getAction()) {
130             case ACTION_CONFIGURATOR_QR_CODE_SCANNER:
131                 config = WifiNetworkConfig.getValidConfigOrNull(intent);
132                 if (config == null) {
133                     cancelActivity = true;
134                 } else {
135                     mWifiNetworkConfig = config;
136                     showQrCodeScannerFragment(/* addToBackStack= */ false);
137                 }
138                 break;
139             case ACTION_CONFIGURATOR_QR_CODE_GENERATOR:
140                 config = WifiNetworkConfig.getValidConfigOrNull(intent);
141                 if (config == null) {
142                     cancelActivity = true;
143                 } else {
144                     mWifiNetworkConfig = config;
145                     showQrCodeGeneratorFragment();
146                 }
147                 break;
148             case Settings.ACTION_PROCESS_WIFI_EASY_CONNECT_QR_CODE:
149                 String qrCode = intent.getStringExtra(Settings.EXTRA_QR_CODE);
150                 mIsTest = intent.getBooleanExtra(WifiDppUtils.EXTRA_TEST, false);
151                 mWifiDppQrCode = getValidWifiDppQrCodeOrNull(qrCode);
152                 final boolean isDppSupported = WifiDppUtils.isWifiDppEnabled(this);
153                 if (!isDppSupported) {
154                     Log.d(TAG, "Device doesn't support Wifi DPP");
155                 }
156                 if (mWifiDppQrCode == null || !isDppSupported) {
157                     cancelActivity = true;
158                 } else {
159                     final WifiNetworkConfig connectedConfig = getConnectedWifiNetworkConfigOrNull();
160                     if (connectedConfig == null) {
161                         showChooseSavedWifiNetworkFragment(/* addToBackStack */ false);
162                     } else {
163                         mWifiNetworkConfig = connectedConfig;
164                         showAddDeviceFragment(/* addToBackStack */ false);
165                     }
166                 }
167                 break;
168             default:
169                 cancelActivity = true;
170                 Log.e(TAG, "Launch with an invalid action");
171         }
172
173         if (cancelActivity) {
174             finish();
175         }
176     }
177
178     private void showQrCodeScannerFragment(boolean addToBackStack) {
179         WifiDppQrCodeScannerFragment fragment =
180                 (WifiDppQrCodeScannerFragment) mFragmentManager.findFragmentByTag(
181                         WifiDppUtils.TAG_FRAGMENT_QR_CODE_SCANNER);
182
183         if (fragment == null) {
184             fragment = new WifiDppQrCodeScannerFragment();
185         } else {
186             if (fragment.isVisible()) {
187                 return;
188             }
189
190             // When the fragment in back stack but not on top of the stack, we can simply pop
191             // stack because current fragment transactions are arranged in an order
192             mFragmentManager.popBackStackImmediate();
193             return;
194         }
195         final FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
196
197         fragmentTransaction.replace(R.id.fragment_container, fragment,
198                 WifiDppUtils.TAG_FRAGMENT_QR_CODE_SCANNER);
199         if (addToBackStack) {
200             fragmentTransaction.addToBackStack(/* name */ null);
201         }
202         fragmentTransaction.commit();
203     }
204
205     private void showQrCodeGeneratorFragment() {
206         WifiDppQrCodeGeneratorFragment fragment =
207                 (WifiDppQrCodeGeneratorFragment) mFragmentManager.findFragmentByTag(
208                         WifiDppUtils.TAG_FRAGMENT_QR_CODE_GENERATOR);
209
210         if (fragment == null) {
211             fragment = new WifiDppQrCodeGeneratorFragment();
212         } else {
213             if (fragment.isVisible()) {
214                 return;
215             }
216
217             // When the fragment in back stack but not on top of the stack, we can simply pop
218             // stack because current fragment transactions are arranged in an order
219             mFragmentManager.popBackStackImmediate();
220             return;
221         }
222         final FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
223
224         fragmentTransaction.replace(R.id.fragment_container, fragment,
225                 WifiDppUtils.TAG_FRAGMENT_QR_CODE_GENERATOR);
226         fragmentTransaction.commit();
227     }
228
229     private void showChooseSavedWifiNetworkFragment(boolean addToBackStack) {
230         WifiDppChooseSavedWifiNetworkFragment fragment =
231                 (WifiDppChooseSavedWifiNetworkFragment) mFragmentManager.findFragmentByTag(
232                         WifiDppUtils.TAG_FRAGMENT_CHOOSE_SAVED_WIFI_NETWORK);
233
234         if (fragment == null) {
235             fragment = new WifiDppChooseSavedWifiNetworkFragment();
236             if (mIsTest) {
237                 Bundle bundle = new Bundle();
238                 bundle.putBoolean(WifiDppUtils.EXTRA_TEST, true);
239                 fragment.setArguments(bundle);
240             }
241         } else {
242             if (fragment.isVisible()) {
243                 return;
244             }
245
246             // When the fragment in back stack but not on top of the stack, we can simply pop
247             // stack because current fragment transactions are arranged in an order
248             mFragmentManager.popBackStackImmediate();
249             return;
250         }
251         final FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
252
253         fragmentTransaction.replace(R.id.fragment_container, fragment,
254                 WifiDppUtils.TAG_FRAGMENT_CHOOSE_SAVED_WIFI_NETWORK);
255         if (addToBackStack) {
256             fragmentTransaction.addToBackStack(/* name */ null);
257         }
258         fragmentTransaction.commit();
259     }
260
261     private void showAddDeviceFragment(boolean addToBackStack) {
262         WifiDppAddDeviceFragment fragment =
263                 (WifiDppAddDeviceFragment) mFragmentManager.findFragmentByTag(
264                         WifiDppUtils.TAG_FRAGMENT_ADD_DEVICE);
265
266         if (fragment == null) {
267             fragment = new WifiDppAddDeviceFragment();
268         } else {
269             if (fragment.isVisible()) {
270                 return;
271             }
272
273             // When the fragment in back stack but not on top of the stack, we can simply pop
274             // stack because current fragment transactions are arranged in an order
275             mFragmentManager.popBackStackImmediate();
276             return;
277         }
278         final FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
279
280         fragmentTransaction.replace(R.id.fragment_container, fragment,
281                 WifiDppUtils.TAG_FRAGMENT_ADD_DEVICE);
282         if (addToBackStack) {
283             fragmentTransaction.addToBackStack(/* name */ null);
284         }
285         fragmentTransaction.commit();
286     }
287
288     private WifiQrCode getValidWifiDppQrCodeOrNull(String qrCode) {
289         WifiQrCode wifiQrCode;
290         try {
291             wifiQrCode = new WifiQrCode(qrCode);
292         } catch(IllegalArgumentException e) {
293             return null;
294         }
295
296         if (WifiQrCode.SCHEME_DPP.equals(wifiQrCode.getScheme())) {
297             return wifiQrCode;
298         }
299
300         return null;
301     }
302
303     @Override
304     public WifiNetworkConfig getWifiNetworkConfig() {
305         return mWifiNetworkConfig;
306     }
307
308     public WifiQrCode getWifiDppQrCode() {
309         return mWifiDppQrCode;
310     }
311
312     @VisibleForTesting
313     boolean setWifiNetworkConfig(WifiNetworkConfig config) {
314         if(!WifiNetworkConfig.isValidConfig(config)) {
315             return false;
316         } else {
317             mWifiNetworkConfig = new WifiNetworkConfig(config);
318             return true;
319         }
320     }
321
322     @VisibleForTesting
323     boolean setWifiDppQrCode(WifiQrCode wifiQrCode) {
324         if (wifiQrCode == null) {
325             return false;
326         }
327
328         if (!WifiQrCode.SCHEME_DPP.equals(wifiQrCode.getScheme())) {
329             return false;
330         }
331
332         mWifiDppQrCode = new WifiQrCode(wifiQrCode.getQrCode());
333         return true;
334     }
335
336     @Override
337     public boolean onNavigateUp() {
338         Fragment fragment = mFragmentManager.findFragmentById(R.id.fragment_container);
339         if (fragment instanceof WifiDppQrCodeGeneratorFragment) {
340             finish();
341             return true;
342         } else if (fragment instanceof WifiDppQrCodeScannerFragment) {
343             mFragmentManager.popBackStackImmediate();
344         }
345
346         return false;
347     }
348
349     @Override
350     public void onQrCodeGeneratorFragmentAddButtonClicked() {
351         showQrCodeScannerFragment(/* addToBackStack */ true);
352     }
353
354     @Override
355     public void onScanWifiDppSuccess(WifiQrCode wifiQrCode) {
356         mWifiDppQrCode = wifiQrCode;
357
358         showAddDeviceFragment(/* addToBackStack */ true);
359     }
360
361     @Override
362     public void onScanZxingWifiFormatSuccess(WifiNetworkConfig wifiNetworkConfig) {
363         // Do nothing, it's impossible to be a configurator without a Wi-Fi DPP QR code
364     }
365
366     @Override
367     public void onClickChooseDifferentNetwork() {
368         showChooseSavedWifiNetworkFragment(/* addToBackStack */ true);
369     }
370
371     @Override
372     public void onSaveInstanceState(Bundle outState) {
373         if (mWifiDppQrCode != null) {
374             outState.putString(KEY_QR_CODE, mWifiDppQrCode.getQrCode());
375         }
376
377         if (mWifiNetworkConfig != null) {
378             outState.putString(KEY_WIFI_SECURITY, mWifiNetworkConfig.getSecurity());
379             outState.putString(KEY_WIFI_SSID, mWifiNetworkConfig.getSsid());
380             outState.putString(KEY_WIFI_PRESHARED_KEY, mWifiNetworkConfig.getPreSharedKey());
381             outState.putBoolean(KEY_WIFI_HIDDEN_SSID, mWifiNetworkConfig.getHiddenSsid());
382             outState.putInt(KEY_WIFI_NETWORK_ID, mWifiNetworkConfig.getNetworkId());
383         }
384
385         super.onSaveInstanceState(outState);
386     }
387
388     @Override
389     public void onChooseNetwork(WifiNetworkConfig wifiNetworkConfig) {
390         mWifiNetworkConfig = new WifiNetworkConfig(wifiNetworkConfig);
391
392         showAddDeviceFragment(/* addToBackStack */ true);
393     }
394
395     private WifiNetworkConfig getConnectedWifiNetworkConfigOrNull() {
396         final WifiManager wifiManager = getSystemService(WifiManager.class);
397         if (!wifiManager.isWifiEnabled()) {
398             return null;
399         }
400
401         final WifiInfo connectionInfo = wifiManager.getConnectionInfo();
402         if (connectionInfo == null) {
403             return null;
404         }
405
406         final int connectionNetworkId = connectionInfo.getNetworkId();
407         final List<WifiConfiguration> configs = wifiManager.getConfiguredNetworks();
408         for (WifiConfiguration wifiConfiguration : configs) {
409             if (wifiConfiguration.networkId == connectionNetworkId) {
410                 return WifiNetworkConfig.getValidConfigOrNull(
411                     WifiDppUtils.getSecurityString(wifiConfiguration),
412                     wifiConfiguration.getPrintableSsid(),
413                     wifiConfiguration.preSharedKey,
414                     /* hiddenSsid */ false,
415                     wifiConfiguration.networkId);
416             }
417         }
418
419         return null;
420     }
421 }