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.KeyguardManager; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.hardware.biometrics.BiometricPrompt; 23 import android.net.wifi.SoftApConfiguration; 24 import android.net.wifi.WifiConfiguration; 25 import android.net.wifi.WifiConfiguration.KeyMgmt; 26 import android.net.wifi.WifiManager; 27 import android.os.CancellationSignal; 28 import android.os.Handler; 29 import android.os.Looper; 30 import android.os.UserHandle; 31 import android.os.VibrationEffect; 32 import android.os.Vibrator; 33 import android.security.keystore.KeyGenParameterSpec; 34 import android.security.keystore.KeyProperties; 35 import android.text.TextUtils; 36 37 import com.android.settings.R; 38 import com.android.settings.Utils; 39 import com.android.settingslib.wifi.AccessPoint; 40 import com.android.wifitrackerlib.WifiEntry; 41 42 import java.security.InvalidAlgorithmParameterException; 43 import java.security.InvalidKeyException; 44 import java.security.NoSuchAlgorithmException; 45 import java.time.Duration; 46 import java.util.List; 47 48 import javax.crypto.BadPaddingException; 49 import javax.crypto.Cipher; 50 import javax.crypto.IllegalBlockSizeException; 51 import javax.crypto.KeyGenerator; 52 import javax.crypto.NoSuchPaddingException; 53 import javax.crypto.SecretKey; 54 55 /** 56 * Here are the items shared by both WifiDppConfiguratorActivity & WifiDppEnrolleeActivity 57 * 58 * @see WifiQrCode 59 */ 60 public class WifiDppUtils { 61 /** 62 * The fragment tag specified to FragmentManager for container activities to manage fragments. 63 */ 64 static final String TAG_FRAGMENT_QR_CODE_SCANNER = "qr_code_scanner_fragment"; 65 66 /** 67 * @see #TAG_FRAGMENT_QR_CODE_SCANNER 68 */ 69 static final String TAG_FRAGMENT_QR_CODE_GENERATOR = "qr_code_generator_fragment"; 70 71 /** 72 * @see #TAG_FRAGMENT_QR_CODE_SCANNER 73 */ 74 static final String TAG_FRAGMENT_CHOOSE_SAVED_WIFI_NETWORK = 75 "choose_saved_wifi_network_fragment"; 76 77 /** 78 * @see #TAG_FRAGMENT_QR_CODE_SCANNER 79 */ 80 static final String TAG_FRAGMENT_ADD_DEVICE = "add_device_fragment"; 81 82 /** The data is one of the static String SECURITY_* in {@link WifiQrCode} */ 83 static final String EXTRA_WIFI_SECURITY = "security"; 84 85 /** The data corresponding to {@code WifiConfiguration} SSID */ 86 static final String EXTRA_WIFI_SSID = "ssid"; 87 88 /** The data corresponding to {@code WifiConfiguration} preSharedKey */ 89 static final String EXTRA_WIFI_PRE_SHARED_KEY = "preSharedKey"; 90 91 /** The data corresponding to {@code WifiConfiguration} hiddenSSID */ 92 static final String EXTRA_WIFI_HIDDEN_SSID = "hiddenSsid"; 93 94 /** The data corresponding to {@code WifiConfiguration} networkId */ 95 static final String EXTRA_WIFI_NETWORK_ID = "networkId"; 96 97 /** The data to recognize if it's a Wi-Fi hotspot for configuration */ 98 static final String EXTRA_IS_HOTSPOT = "isHotspot"; 99 100 /** 101 * Default status code for Easy Connect 102 */ 103 static final int EASY_CONNECT_EVENT_FAILURE_NONE = 0; 104 105 /** 106 * Success status code for Easy Connect. 107 */ 108 static final int EASY_CONNECT_EVENT_SUCCESS = 1; 109 110 private static final Duration VIBRATE_DURATION_QR_CODE_RECOGNITION = Duration.ofMillis(3); 111 112 private static final String AES_CBC_PKCS7_PADDING = "AES/CBC/PKCS7Padding"; 113 114 /** 115 * Returns whether the device support WiFi DPP. 116 */ isWifiDppEnabled(Context context)117 static boolean isWifiDppEnabled(Context context) { 118 final WifiManager manager = context.getSystemService(WifiManager.class); 119 return manager.isEasyConnectSupported(); 120 } 121 122 /** 123 * Returns an intent to launch QR code scanner for Wi-Fi DPP enrollee. 124 * 125 * After enrollee success, the callee activity will return connecting WifiConfiguration by 126 * putExtra {@code WifiDialogActivity.KEY_WIFI_CONFIGURATION} for 127 * {@code Activity#setResult(int resultCode, Intent data)}. The calling object should check 128 * if it's available before using it. 129 * 130 * @param ssid The data corresponding to {@code WifiConfiguration} SSID 131 * @return Intent for launching QR code scanner 132 */ getEnrolleeQrCodeScannerIntent(Context context, String ssid)133 public static Intent getEnrolleeQrCodeScannerIntent(Context context, String ssid) { 134 final Intent intent = new Intent(context, WifiDppEnrolleeActivity.class); 135 intent.setAction(WifiDppEnrolleeActivity.ACTION_ENROLLEE_QR_CODE_SCANNER); 136 if (!TextUtils.isEmpty(ssid)) { 137 intent.putExtra(EXTRA_WIFI_SSID, ssid); 138 } 139 return intent; 140 } 141 getPresharedKey(WifiManager wifiManager, WifiConfiguration wifiConfiguration)142 private static String getPresharedKey(WifiManager wifiManager, 143 WifiConfiguration wifiConfiguration) { 144 final List<WifiConfiguration> privilegedWifiConfigurations = 145 wifiManager.getPrivilegedConfiguredNetworks(); 146 147 for (WifiConfiguration privilegedWifiConfiguration : privilegedWifiConfigurations) { 148 if (privilegedWifiConfiguration.networkId == wifiConfiguration.networkId) { 149 // WEP uses a shared key hence the AuthAlgorithm.SHARED is used 150 // to identify it. 151 if (wifiConfiguration.allowedKeyManagement.get(KeyMgmt.NONE) 152 && wifiConfiguration.allowedAuthAlgorithms.get( 153 WifiConfiguration.AuthAlgorithm.SHARED)) { 154 return privilegedWifiConfiguration 155 .wepKeys[privilegedWifiConfiguration.wepTxKeyIndex]; 156 } else { 157 return privilegedWifiConfiguration.preSharedKey; 158 } 159 } 160 } 161 return wifiConfiguration.preSharedKey; 162 } 163 removeFirstAndLastDoubleQuotes(String str)164 static String removeFirstAndLastDoubleQuotes(String str) { 165 if (TextUtils.isEmpty(str)) { 166 return str; 167 } 168 169 int begin = 0; 170 int end = str.length() - 1; 171 if (str.charAt(begin) == '\"') { 172 begin++; 173 } 174 if (str.charAt(end) == '\"') { 175 end--; 176 } 177 return str.substring(begin, end+1); 178 } 179 getSecurityString(WifiConfiguration config)180 static String getSecurityString(WifiConfiguration config) { 181 if (config.allowedKeyManagement.get(KeyMgmt.SAE)) { 182 return WifiQrCode.SECURITY_SAE; 183 } 184 if (config.allowedKeyManagement.get(KeyMgmt.OWE)) { 185 return WifiQrCode.SECURITY_NO_PASSWORD; 186 } 187 if (config.allowedKeyManagement.get(KeyMgmt.WPA_PSK) || 188 config.allowedKeyManagement.get(KeyMgmt.WPA2_PSK)) { 189 return WifiQrCode.SECURITY_WPA_PSK; 190 } 191 return (config.wepKeys[0] == null) ? 192 WifiQrCode.SECURITY_NO_PASSWORD : WifiQrCode.SECURITY_WEP; 193 } 194 getSecurityString(WifiEntry wifiEntry)195 static String getSecurityString(WifiEntry wifiEntry) { 196 final int security = wifiEntry.getSecurity(); 197 switch (security) { 198 case WifiEntry.SECURITY_SAE: 199 return WifiQrCode.SECURITY_SAE; 200 case WifiEntry.SECURITY_PSK: 201 return WifiQrCode.SECURITY_WPA_PSK; 202 case WifiEntry.SECURITY_WEP: 203 return WifiQrCode.SECURITY_WEP; 204 case WifiEntry.SECURITY_OWE: 205 case WifiEntry.SECURITY_NONE: 206 default: 207 return WifiQrCode.SECURITY_NO_PASSWORD; 208 } 209 } 210 211 /** 212 * Returns an intent to launch QR code generator. It may return null if the security is not 213 * supported by QR code generator. 214 * 215 * Do not use this method for Wi-Fi hotspot network, use 216 * {@code getHotspotConfiguratorIntentOrNull} instead. 217 * 218 * @param context The context to use for the content resolver 219 * @param wifiManager An instance of {@link WifiManager} 220 * @param accessPoint An instance of {@link AccessPoint} 221 * @return Intent for launching QR code generator 222 */ getConfiguratorQrCodeGeneratorIntentOrNull(Context context, WifiManager wifiManager, AccessPoint accessPoint)223 public static Intent getConfiguratorQrCodeGeneratorIntentOrNull(Context context, 224 WifiManager wifiManager, AccessPoint accessPoint) { 225 final Intent intent = new Intent(context, WifiDppConfiguratorActivity.class); 226 if (isSupportConfiguratorQrCodeGenerator(context, accessPoint)) { 227 intent.setAction(WifiDppConfiguratorActivity.ACTION_CONFIGURATOR_QR_CODE_GENERATOR); 228 } else { 229 return null; 230 } 231 232 final WifiConfiguration wifiConfiguration = accessPoint.getConfig(); 233 setConfiguratorIntentExtra(intent, wifiManager, wifiConfiguration); 234 235 // For a transition mode Wi-Fi AP, creates a QR code that's compatible with more devices 236 if (accessPoint.isPskSaeTransitionMode()) { 237 intent.putExtra(EXTRA_WIFI_SECURITY, WifiQrCode.SECURITY_WPA_PSK); 238 } 239 240 return intent; 241 } 242 243 /** 244 * Returns an intent to launch QR code generator. It may return null if the security is not 245 * supported by QR code generator. 246 * 247 * Do not use this method for Wi-Fi hotspot network, use 248 * {@code getHotspotConfiguratorIntentOrNull} instead. 249 * 250 * @param context The context to use for the content resolver 251 * @param wifiManager An instance of {@link WifiManager} 252 * @param wifiEntry An instance of {@link WifiEntry} 253 * @return Intent for launching QR code generator 254 */ getConfiguratorQrCodeGeneratorIntentOrNull(Context context, WifiManager wifiManager, WifiEntry wifiEntry)255 public static Intent getConfiguratorQrCodeGeneratorIntentOrNull(Context context, 256 WifiManager wifiManager, WifiEntry wifiEntry) { 257 final Intent intent = new Intent(context, WifiDppConfiguratorActivity.class); 258 if (wifiEntry.canShare()) { 259 intent.setAction(WifiDppConfiguratorActivity.ACTION_CONFIGURATOR_QR_CODE_GENERATOR); 260 } else { 261 return null; 262 } 263 264 final WifiConfiguration wifiConfiguration = wifiEntry.getWifiConfiguration(); 265 setConfiguratorIntentExtra(intent, wifiManager, wifiConfiguration); 266 267 return intent; 268 } 269 270 /** 271 * Returns an intent to launch QR code scanner. It may return null if the security is not 272 * supported by QR code scanner. 273 * 274 * @param context The context to use for the content resolver 275 * @param wifiManager An instance of {@link WifiManager} 276 * @param wifiEntry An instance of {@link WifiEntry} 277 * @return Intent for launching QR code scanner 278 */ getConfiguratorQrCodeScannerIntentOrNull(Context context, WifiManager wifiManager, WifiEntry wifiEntry)279 public static Intent getConfiguratorQrCodeScannerIntentOrNull(Context context, 280 WifiManager wifiManager, WifiEntry wifiEntry) { 281 final Intent intent = new Intent(context, WifiDppConfiguratorActivity.class); 282 if (wifiEntry.canEasyConnect()) { 283 intent.setAction(WifiDppConfiguratorActivity.ACTION_CONFIGURATOR_QR_CODE_SCANNER); 284 } else { 285 return null; 286 } 287 288 final WifiConfiguration wifiConfiguration = wifiEntry.getWifiConfiguration(); 289 setConfiguratorIntentExtra(intent, wifiManager, wifiConfiguration); 290 291 if (wifiConfiguration.networkId == WifiConfiguration.INVALID_NETWORK_ID) { 292 throw new IllegalArgumentException("Invalid network ID"); 293 } else { 294 intent.putExtra(EXTRA_WIFI_NETWORK_ID, wifiConfiguration.networkId); 295 } 296 297 return intent; 298 } 299 300 /** 301 * Returns an intent to launch QR code generator for the Wi-Fi hotspot. It may return null if 302 * the security is not supported by QR code generator. 303 * 304 * @param context The context to use for the content resolver 305 * @param wifiManager An instance of {@link WifiManager} 306 * @param softApConfiguration {@link SoftApConfiguration} of the Wi-Fi hotspot 307 * @return Intent for launching QR code generator 308 */ getHotspotConfiguratorIntentOrNull(Context context, WifiManager wifiManager, SoftApConfiguration softApConfiguration)309 public static Intent getHotspotConfiguratorIntentOrNull(Context context, 310 WifiManager wifiManager, SoftApConfiguration softApConfiguration) { 311 final Intent intent = new Intent(context, WifiDppConfiguratorActivity.class); 312 if (isSupportHotspotConfiguratorQrCodeGenerator(softApConfiguration)) { 313 intent.setAction(WifiDppConfiguratorActivity.ACTION_CONFIGURATOR_QR_CODE_GENERATOR); 314 } else { 315 return null; 316 } 317 318 final String ssid = removeFirstAndLastDoubleQuotes(softApConfiguration.getSsid()); 319 String security; 320 final int securityType = softApConfiguration.getSecurityType(); 321 if (securityType == SoftApConfiguration.SECURITY_TYPE_WPA3_SAE) { 322 security = WifiQrCode.SECURITY_SAE; 323 } else if (securityType == SoftApConfiguration.SECURITY_TYPE_WPA2_PSK 324 || securityType == SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION) { 325 security = WifiQrCode.SECURITY_WPA_PSK; 326 } else { 327 security = WifiQrCode.SECURITY_NO_PASSWORD; 328 } 329 330 // When the value of this key is read, the actual key is not returned, just a "*". 331 // Call privileged system API to obtain actual key. 332 final String preSharedKey = removeFirstAndLastDoubleQuotes( 333 softApConfiguration.getPassphrase()); 334 335 if (!TextUtils.isEmpty(ssid)) { 336 intent.putExtra(EXTRA_WIFI_SSID, ssid); 337 } 338 if (!TextUtils.isEmpty(security)) { 339 intent.putExtra(EXTRA_WIFI_SECURITY, security); 340 } 341 if (!TextUtils.isEmpty(preSharedKey)) { 342 intent.putExtra(EXTRA_WIFI_PRE_SHARED_KEY, preSharedKey); 343 } 344 intent.putExtra(EXTRA_WIFI_HIDDEN_SSID, softApConfiguration.isHiddenSsid()); 345 346 347 intent.putExtra(EXTRA_WIFI_NETWORK_ID, WifiConfiguration.INVALID_NETWORK_ID); 348 intent.putExtra(EXTRA_IS_HOTSPOT, true); 349 350 return intent; 351 } 352 353 /** 354 * Set all extra except {@code EXTRA_WIFI_NETWORK_ID} for the intent to 355 * launch configurator activity later. 356 * 357 * @param intent the target to set extra 358 * @param wifiManager an instance of {@code WifiManager} 359 * @param wifiConfiguration the Wi-Fi network for launching configurator activity 360 */ setConfiguratorIntentExtra(Intent intent, WifiManager wifiManager, WifiConfiguration wifiConfiguration)361 private static void setConfiguratorIntentExtra(Intent intent, WifiManager wifiManager, 362 WifiConfiguration wifiConfiguration) { 363 final String ssid = removeFirstAndLastDoubleQuotes(wifiConfiguration.SSID); 364 final String security = getSecurityString(wifiConfiguration); 365 366 // When the value of this key is read, the actual key is not returned, just a "*". 367 // Call privileged system API to obtain actual key. 368 final String preSharedKey = removeFirstAndLastDoubleQuotes(getPresharedKey(wifiManager, 369 wifiConfiguration)); 370 371 if (!TextUtils.isEmpty(ssid)) { 372 intent.putExtra(EXTRA_WIFI_SSID, ssid); 373 } 374 if (!TextUtils.isEmpty(security)) { 375 intent.putExtra(EXTRA_WIFI_SECURITY, security); 376 } 377 if (!TextUtils.isEmpty(preSharedKey)) { 378 intent.putExtra(EXTRA_WIFI_PRE_SHARED_KEY, preSharedKey); 379 } 380 intent.putExtra(EXTRA_WIFI_HIDDEN_SSID, wifiConfiguration.hiddenSSID); 381 } 382 383 /** 384 * Checks whether the device is unlocked recently. 385 * 386 * @param keyStoreAlias key 387 * @param seconds how many seconds since the device is unlocked 388 * @return whether the device is unlocked within the time 389 */ isUnlockedWithinSeconds(String keyStoreAlias, int seconds)390 public static boolean isUnlockedWithinSeconds(String keyStoreAlias, int seconds) { 391 try { 392 Cipher cipher = Cipher.getInstance(AES_CBC_PKCS7_PADDING); 393 cipher.init(Cipher.ENCRYPT_MODE, generateSecretKey(keyStoreAlias, seconds)); 394 cipher.doFinal(); 395 return true; 396 } catch (NoSuchPaddingException 397 | IllegalBlockSizeException 398 | NoSuchAlgorithmException 399 | BadPaddingException 400 | InvalidKeyException e) { 401 return false; 402 } 403 } 404 generateSecretKey(String keyStoreAlias, int seconds)405 private static SecretKey generateSecretKey(String keyStoreAlias, int seconds) { 406 KeyGenParameterSpec spec = new KeyGenParameterSpec 407 .Builder(keyStoreAlias, KeyProperties.PURPOSE_ENCRYPT) 408 .setBlockModes(KeyProperties.BLOCK_MODE_CBC) 409 .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7) 410 .setUserAuthenticationRequired(true) 411 .setUserAuthenticationParameters( 412 seconds, 413 KeyProperties.AUTH_DEVICE_CREDENTIAL | KeyProperties.AUTH_BIOMETRIC_STRONG) 414 .build(); 415 try { 416 KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES); 417 keyGenerator.init(spec); 418 return keyGenerator.generateKey(); 419 } catch (NoSuchAlgorithmException 420 | InvalidAlgorithmParameterException e) { 421 return null; 422 } 423 } 424 425 /** 426 * Shows authentication screen to confirm credentials (pin, pattern or password) for the current 427 * user of the device. 428 * 429 * @param context The {@code Context} used to get {@code KeyguardManager} service 430 * @param successRunnable The {@code Runnable} which will be executed if the user does not setup 431 * device security or if lock screen is unlocked 432 */ showLockScreen(Context context, Runnable successRunnable)433 public static void showLockScreen(Context context, Runnable successRunnable) { 434 final KeyguardManager keyguardManager = (KeyguardManager) context.getSystemService( 435 Context.KEYGUARD_SERVICE); 436 437 if (keyguardManager.isKeyguardSecure()) { 438 final BiometricPrompt.AuthenticationCallback authenticationCallback = 439 new BiometricPrompt.AuthenticationCallback() { 440 @Override 441 public void onAuthenticationSucceeded( 442 BiometricPrompt.AuthenticationResult result) { 443 successRunnable.run(); 444 } 445 446 @Override 447 public void onAuthenticationError(int errorCode, CharSequence errString) { 448 //Do nothing 449 } 450 }; 451 452 final int userId = UserHandle.myUserId(); 453 454 final BiometricPrompt.Builder builder = new BiometricPrompt.Builder(context) 455 .setTitle(context.getText(R.string.wifi_dpp_lockscreen_title)); 456 457 if (keyguardManager.isDeviceSecure()) { 458 builder.setDeviceCredentialAllowed(true); 459 builder.setTextForDeviceCredential( 460 null /* title */, 461 Utils.getConfirmCredentialStringForUser( 462 context, userId, Utils.getCredentialType(context, userId)), 463 null /* description */); 464 } 465 466 final BiometricPrompt bp = builder.build(); 467 final Handler handler = new Handler(Looper.getMainLooper()); 468 bp.authenticate(new CancellationSignal(), 469 runnable -> handler.post(runnable), 470 authenticationCallback); 471 } else { 472 successRunnable.run(); 473 } 474 } 475 476 /** 477 * Checks if QR code generator supports to config other devices with the Wi-Fi network 478 * 479 * @param context The context to use for {@code WifiManager} 480 * @param accessPoint The {@link AccessPoint} of the Wi-Fi network 481 */ isSupportConfiguratorQrCodeGenerator(Context context, AccessPoint accessPoint)482 public static boolean isSupportConfiguratorQrCodeGenerator(Context context, 483 AccessPoint accessPoint) { 484 if (accessPoint.isPasspoint()) { 485 return false; 486 } 487 return isSupportZxing(context, accessPoint.getSecurity()); 488 } 489 490 /** 491 * Checks if this device supports to be configured by the Wi-Fi network of the security 492 * 493 * @param context The context to use for {@code WifiManager} 494 * @param wifiEntrySecurity The security constants defined in {@link WifiEntry} 495 */ isSupportEnrolleeQrCodeScanner(Context context, int wifiEntrySecurity)496 public static boolean isSupportEnrolleeQrCodeScanner(Context context, int wifiEntrySecurity) { 497 return isSupportWifiDpp(context, wifiEntrySecurity) 498 || isSupportZxing(context, wifiEntrySecurity); 499 } 500 isSupportHotspotConfiguratorQrCodeGenerator( SoftApConfiguration softApConfiguration)501 private static boolean isSupportHotspotConfiguratorQrCodeGenerator( 502 SoftApConfiguration softApConfiguration) { 503 final int securityType = softApConfiguration.getSecurityType(); 504 return securityType == SoftApConfiguration.SECURITY_TYPE_WPA3_SAE 505 || securityType == SoftApConfiguration.SECURITY_TYPE_WPA3_SAE_TRANSITION 506 || securityType == SoftApConfiguration.SECURITY_TYPE_WPA2_PSK 507 || securityType == SoftApConfiguration.SECURITY_TYPE_OPEN; 508 } 509 isSupportWifiDpp(Context context, int wifiEntrySecurity)510 private static boolean isSupportWifiDpp(Context context, int wifiEntrySecurity) { 511 if (!isWifiDppEnabled(context)) { 512 return false; 513 } 514 515 // DPP 1.0 only supports SAE and PSK. 516 final WifiManager wifiManager = context.getSystemService(WifiManager.class); 517 switch (wifiEntrySecurity) { 518 case WifiEntry.SECURITY_SAE: 519 if (wifiManager.isWpa3SaeSupported()) { 520 return true; 521 } 522 break; 523 case WifiEntry.SECURITY_PSK: 524 return true; 525 default: 526 } 527 return false; 528 } 529 isSupportZxing(Context context, int wifiEntrySecurity)530 private static boolean isSupportZxing(Context context, int wifiEntrySecurity) { 531 final WifiManager wifiManager = context.getSystemService(WifiManager.class); 532 switch (wifiEntrySecurity) { 533 case WifiEntry.SECURITY_PSK: 534 case WifiEntry.SECURITY_WEP: 535 case WifiEntry.SECURITY_NONE: 536 return true; 537 case WifiEntry.SECURITY_SAE: 538 if (wifiManager.isWpa3SaeSupported()) { 539 return true; 540 } 541 break; 542 case WifiEntry.SECURITY_OWE: 543 if (wifiManager.isEnhancedOpenSupported()) { 544 return true; 545 } 546 break; 547 default: 548 } 549 return false; 550 } 551 triggerVibrationForQrCodeRecognition(Context context)552 static void triggerVibrationForQrCodeRecognition(Context context) { 553 Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); 554 if (vibrator == null) { 555 return; 556 } 557 vibrator.vibrate(VibrationEffect.createOneShot( 558 VIBRATE_DURATION_QR_CODE_RECOGNITION.toMillis(), 559 VibrationEffect.DEFAULT_AMPLITUDE)); 560 } 561 562 @WifiEntry.Security getSecurityTypeFromWifiConfiguration(WifiConfiguration config)563 static int getSecurityTypeFromWifiConfiguration(WifiConfiguration config) { 564 if (config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.SAE)) { 565 return WifiEntry.SECURITY_SAE; 566 } 567 if (config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_PSK)) { 568 return WifiEntry.SECURITY_PSK; 569 } 570 if (config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.SUITE_B_192)) { 571 return WifiEntry.SECURITY_EAP_SUITE_B; 572 } 573 if (config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.WPA_EAP) 574 || config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.IEEE8021X)) { 575 return WifiEntry.SECURITY_EAP; 576 } 577 if (config.allowedKeyManagement.get(WifiConfiguration.KeyMgmt.OWE)) { 578 return WifiEntry.SECURITY_OWE; 579 } 580 return (config.wepKeys[0] != null) ? WifiEntry.SECURITY_WEP : WifiEntry.SECURITY_NONE; 581 } 582 } 583