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 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;
29 import androidx.annotation.VisibleForTesting;
30 import androidx.fragment.app.Fragment;
31 import androidx.fragment.app.FragmentManager;
32 import androidx.fragment.app.FragmentTransaction;
34 import com.android.settings.R;
35 import com.android.settings.core.InstrumentedActivity;
37 import java.util.List;
40 * To provision "other" device with specified Wi-Fi network.
42 * Uses different intents to specify different provisioning ways.
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
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}
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}
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 {
64 private static final String TAG = "WifiDppConfiguratorActivity";
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";
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";
79 private FragmentManager mFragmentManager;
81 /** The Wi-Fi network which will be configured */
82 private WifiNetworkConfig mWifiNetworkConfig;
84 /** The Wi-Fi DPP QR code from intent ACTION_PROCESS_WIFI_EASY_CONNECT_QR_CODE */
85 private WifiQrCode mWifiDppQrCode;
87 /** Secret extra that allows fake networks to show in UI for testing purposes */
88 private boolean mIsTest;
91 public int getMetricsCategory() {
92 return SettingsEnums.SETTINGS_WIFI_DPP_CONFIGURATOR;
96 protected void onCreate(Bundle savedInstanceState) {
97 super.onCreate(savedInstanceState);
99 setContentView(R.layout.wifi_dpp_activity);
100 mFragmentManager = getSupportFragmentManager();
102 if (savedInstanceState != null) {
103 String qrCode = savedInstanceState.getString(KEY_QR_CODE);
105 mWifiDppQrCode = getValidWifiDppQrCodeOrNull(qrCode);
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);
113 mWifiNetworkConfig = WifiNetworkConfig.getValidConfigOrNull(security, ssid,
114 preSharedKey, hiddenSsid, networkId);
116 handleIntent(getIntent());
119 ActionBar actionBar = getActionBar();
120 if (actionBar != null) {
121 actionBar.setElevation(0);
122 actionBar.setDisplayShowTitleEnabled(false);
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;
135 mWifiNetworkConfig = config;
136 showQrCodeScannerFragment(/* addToBackStack= */ false);
139 case ACTION_CONFIGURATOR_QR_CODE_GENERATOR:
140 config = WifiNetworkConfig.getValidConfigOrNull(intent);
141 if (config == null) {
142 cancelActivity = true;
144 mWifiNetworkConfig = config;
145 showQrCodeGeneratorFragment();
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");
156 if (mWifiDppQrCode == null || !isDppSupported) {
157 cancelActivity = true;
159 final WifiNetworkConfig connectedConfig = getConnectedWifiNetworkConfigOrNull();
160 if (connectedConfig == null) {
161 showChooseSavedWifiNetworkFragment(/* addToBackStack */ false);
163 mWifiNetworkConfig = connectedConfig;
164 showAddDeviceFragment(/* addToBackStack */ false);
169 cancelActivity = true;
170 Log.e(TAG, "Launch with an invalid action");
173 if (cancelActivity) {
178 private void showQrCodeScannerFragment(boolean addToBackStack) {
179 WifiDppQrCodeScannerFragment fragment =
180 (WifiDppQrCodeScannerFragment) mFragmentManager.findFragmentByTag(
181 WifiDppUtils.TAG_FRAGMENT_QR_CODE_SCANNER);
183 if (fragment == null) {
184 fragment = new WifiDppQrCodeScannerFragment();
186 if (fragment.isVisible()) {
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();
195 final FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
197 fragmentTransaction.replace(R.id.fragment_container, fragment,
198 WifiDppUtils.TAG_FRAGMENT_QR_CODE_SCANNER);
199 if (addToBackStack) {
200 fragmentTransaction.addToBackStack(/* name */ null);
202 fragmentTransaction.commit();
205 private void showQrCodeGeneratorFragment() {
206 WifiDppQrCodeGeneratorFragment fragment =
207 (WifiDppQrCodeGeneratorFragment) mFragmentManager.findFragmentByTag(
208 WifiDppUtils.TAG_FRAGMENT_QR_CODE_GENERATOR);
210 if (fragment == null) {
211 fragment = new WifiDppQrCodeGeneratorFragment();
213 if (fragment.isVisible()) {
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();
222 final FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
224 fragmentTransaction.replace(R.id.fragment_container, fragment,
225 WifiDppUtils.TAG_FRAGMENT_QR_CODE_GENERATOR);
226 fragmentTransaction.commit();
229 private void showChooseSavedWifiNetworkFragment(boolean addToBackStack) {
230 WifiDppChooseSavedWifiNetworkFragment fragment =
231 (WifiDppChooseSavedWifiNetworkFragment) mFragmentManager.findFragmentByTag(
232 WifiDppUtils.TAG_FRAGMENT_CHOOSE_SAVED_WIFI_NETWORK);
234 if (fragment == null) {
235 fragment = new WifiDppChooseSavedWifiNetworkFragment();
237 Bundle bundle = new Bundle();
238 bundle.putBoolean(WifiDppUtils.EXTRA_TEST, true);
239 fragment.setArguments(bundle);
242 if (fragment.isVisible()) {
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();
251 final FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
253 fragmentTransaction.replace(R.id.fragment_container, fragment,
254 WifiDppUtils.TAG_FRAGMENT_CHOOSE_SAVED_WIFI_NETWORK);
255 if (addToBackStack) {
256 fragmentTransaction.addToBackStack(/* name */ null);
258 fragmentTransaction.commit();
261 private void showAddDeviceFragment(boolean addToBackStack) {
262 WifiDppAddDeviceFragment fragment =
263 (WifiDppAddDeviceFragment) mFragmentManager.findFragmentByTag(
264 WifiDppUtils.TAG_FRAGMENT_ADD_DEVICE);
266 if (fragment == null) {
267 fragment = new WifiDppAddDeviceFragment();
269 if (fragment.isVisible()) {
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();
278 final FragmentTransaction fragmentTransaction = mFragmentManager.beginTransaction();
280 fragmentTransaction.replace(R.id.fragment_container, fragment,
281 WifiDppUtils.TAG_FRAGMENT_ADD_DEVICE);
282 if (addToBackStack) {
283 fragmentTransaction.addToBackStack(/* name */ null);
285 fragmentTransaction.commit();
288 private WifiQrCode getValidWifiDppQrCodeOrNull(String qrCode) {
289 WifiQrCode wifiQrCode;
291 wifiQrCode = new WifiQrCode(qrCode);
292 } catch(IllegalArgumentException e) {
296 if (WifiQrCode.SCHEME_DPP.equals(wifiQrCode.getScheme())) {
304 public WifiNetworkConfig getWifiNetworkConfig() {
305 return mWifiNetworkConfig;
308 public WifiQrCode getWifiDppQrCode() {
309 return mWifiDppQrCode;
313 boolean setWifiNetworkConfig(WifiNetworkConfig config) {
314 if(!WifiNetworkConfig.isValidConfig(config)) {
317 mWifiNetworkConfig = new WifiNetworkConfig(config);
323 boolean setWifiDppQrCode(WifiQrCode wifiQrCode) {
324 if (wifiQrCode == null) {
328 if (!WifiQrCode.SCHEME_DPP.equals(wifiQrCode.getScheme())) {
332 mWifiDppQrCode = new WifiQrCode(wifiQrCode.getQrCode());
337 public boolean onNavigateUp() {
338 Fragment fragment = mFragmentManager.findFragmentById(R.id.fragment_container);
339 if (fragment instanceof WifiDppQrCodeGeneratorFragment) {
342 } else if (fragment instanceof WifiDppQrCodeScannerFragment) {
343 mFragmentManager.popBackStackImmediate();
350 public void onQrCodeGeneratorFragmentAddButtonClicked() {
351 showQrCodeScannerFragment(/* addToBackStack */ true);
355 public void onScanWifiDppSuccess(WifiQrCode wifiQrCode) {
356 mWifiDppQrCode = wifiQrCode;
358 showAddDeviceFragment(/* addToBackStack */ true);
362 public void onScanZxingWifiFormatSuccess(WifiNetworkConfig wifiNetworkConfig) {
363 // Do nothing, it's impossible to be a configurator without a Wi-Fi DPP QR code
367 public void onClickChooseDifferentNetwork() {
368 showChooseSavedWifiNetworkFragment(/* addToBackStack */ true);
372 public void onSaveInstanceState(Bundle outState) {
373 if (mWifiDppQrCode != null) {
374 outState.putString(KEY_QR_CODE, mWifiDppQrCode.getQrCode());
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());
385 super.onSaveInstanceState(outState);
389 public void onChooseNetwork(WifiNetworkConfig wifiNetworkConfig) {
390 mWifiNetworkConfig = new WifiNetworkConfig(wifiNetworkConfig);
392 showAddDeviceFragment(/* addToBackStack */ true);
395 private WifiNetworkConfig getConnectedWifiNetworkConfigOrNull() {
396 final WifiManager wifiManager = getSystemService(WifiManager.class);
397 if (!wifiManager.isWifiEnabled()) {
401 final WifiInfo connectionInfo = wifiManager.getConnectionInfo();
402 if (connectionInfo == null) {
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);