Android で Wi-Fi ScanResult を WifiConfiguration に変換する方法
この記事は Android の Wi-Fi 実装に関する情報のまとめ の一部として書かれました
「Android の Wi-Fi Access Point を表す ScanResult, WifiConfiguration, WifiInfo の違い」 で書いたように、接続先を追加する際には WifiConfiguration を新規作成する必要があります。 しかし、そのような変換ユーティリティメソッドなどは用意されていません。
AOSP ではどうしているのか
では、AOSP の設定アプリではどのようにしているのかを調べてみると1、 com.android.settings.wifi.WifiConfigController.getConfig()
というメソッドで WifiConfiguration
を作成していました。
以下2つのクラスを読むと大体の概要がわかるでしょう。
同等なメソッドを実装
com.android.settings.wifi.WifiConfigController
や com.android.settingslib.wifi.AccessPoint
は基本的には外部から利用することが出来ません。
ただ、実際の getConfig()
はかなりシンプルです2。
そこで、同等のメソッドを実装してみました。
以下が ScanResult
から WifiConfiguration
に変換するためのメソッドです3。
最も需要がありそうな ScanResult
からの変換を実装しましたが、
SSID
4, SecurityType
, password
がわかっていれば WifiConfiguration
は新規作成可能なので ScanResult
以外から作成することも難しくないはずです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | public static WifiConfiguration convertScanResultToWifiConfiguration( ScanResult scanResult, @Nullable String password) { WifiConfiguration config = new WifiConfiguration(); // Quote を忘れないように config.SSID = '"' + scanResult.SSID + '"' ; // ScanResult を取得出来ているということは hiddenSSID ではない config.hiddenSSID = false ; SecurityType securityType = getSecurity(scanResult); switch (securityType) { case SECURITY_NONE: config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); break ; case SECURITY_WEP: config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.NONE); config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.OPEN); config.allowedAuthAlgorithms.set(WifiConfiguration.AuthAlgorithm.SHARED); if (password != null ) { int length = password.length(); // WEP-40, WEP-104, and 256-bit WEP (WEP-232?) if ((length == 10 || length == 26 || length == 58 ) && password.matches( "[0-9A-Fa-f]*" )) { config.wepKeys[ 0 ] = password; } else { config.wepKeys[ 0 ] = '"' + password + '"' ; } } break ; case SECURITY_PSK: config.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_PSK); if (password != null ) { if (password.matches( "[0-9A-Fa-f]{64}" )) { config.preSharedKey = password; } else { config.preSharedKey = '"' + password + '"' ; } } break ; case SECURITY_EAP: // EAP は省略 // WifiConfigController.getConfig() 内の実装を参考にすれば // 同じように作れるはず Log.e(TAG, "EAP: Does not support" ); break ; default : return null ; } /************************************************************** 以下は hide 属性のついたメソッド DHCP でつなぐ場合は問題ないが、それ以外の場合は設定しないと動かないかも その場合は Refrection しかないか? **************************************************************/ //config.setIpConfiguration( // new IpConfiguration(mIpAssignment, mProxySettings, // mStaticIpConfiguration, mHttpProxy)); return config; } private enum SecurityType { SECURITY_NONE, SECURITY_WEP, SECURITY_PSK, SECURITY_EAP } private static SecurityType getSecurity(ScanResult result) { if (result.capabilities.contains( "WEP" )) { return SecurityType.SECURITY_WEP; } else if (result.capabilities.contains( "PSK" )) { return SecurityType.SECURITY_PSK; } else if (result.capabilities.contains( "EAP" )) { return SecurityType.SECURITY_EAP; } return SecurityType.SECURITY_NONE; } |
気をつけなければならないのは、 WifiConfiguration.setIpConfiguration()
が外部からのアクセス不可能なメソッドになっている点です。
調度良い環境がないので確かめていないのですが、DHCP を使っていなかったり、Proxy を使っていたりするとうまく IP がとれないかもしれません。
WifiConfigController 内の getConfig() の実装
Android 7.0.0_r19 のコードをあげておきます。 EAP が長いので読みづらく感じますが、先にあげたものとほとんど同じであることがわかると思います。
451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 | /* package */ WifiConfiguration getConfig() { if (mMode == WifiConfigUiBase.MODE_VIEW) { return null ; } WifiConfiguration config = new WifiConfiguration(); if (mAccessPoint == null ) { config.SSID = AccessPoint.convertToQuotedString( mSsidView.getText().toString()); // If the user adds a network manually, assume that it is hidden. config.hiddenSSID = true ; } else if (!mAccessPoint.isSaved()) { config.SSID = AccessPoint.convertToQuotedString( mAccessPoint.getSsidStr()); } else { config.networkId = mAccessPoint.getConfig().networkId; } config.shared = mSharedCheckBox.isChecked(); switch (mAccessPointSecurity) { case AccessPoint.SECURITY_NONE: config.allowedKeyManagement.set(KeyMgmt.NONE); break ; case AccessPoint.SECURITY_WEP: config.allowedKeyManagement.set(KeyMgmt.NONE); config.allowedAuthAlgorithms.set(AuthAlgorithm.OPEN); config.allowedAuthAlgorithms.set(AuthAlgorithm.SHARED); if (mPasswordView.length() != 0 ) { int length = mPasswordView.length(); String password = mPasswordView.getText().toString(); // WEP-40, WEP-104, and 256-bit WEP (WEP-232?) if ((length == 10 || length == 26 || length == 58 ) && password.matches( "[0-9A-Fa-f]*" )) { config.wepKeys[ 0 ] = password; } else { config.wepKeys[ 0 ] = '"' + password + '"' ; } } break ; case AccessPoint.SECURITY_PSK: config.allowedKeyManagement.set(KeyMgmt.WPA_PSK); if (mPasswordView.length() != 0 ) { String password = mPasswordView.getText().toString(); if (password.matches( "[0-9A-Fa-f]{64}" )) { config.preSharedKey = password; } else { config.preSharedKey = '"' + password + '"' ; } } break ; case AccessPoint.SECURITY_EAP: config.allowedKeyManagement.set(KeyMgmt.WPA_EAP); config.allowedKeyManagement.set(KeyMgmt.IEEE8021X); config.enterpriseConfig = new WifiEnterpriseConfig(); int eapMethod = mEapMethodSpinner.getSelectedItemPosition(); int phase2Method = mPhase2Spinner.getSelectedItemPosition(); config.enterpriseConfig.setEapMethod(eapMethod); switch (eapMethod) { case Eap.PEAP: // PEAP supports limited phase2 values // Map the index from the mPhase2PeapAdapter to the one used // by the API which has the full list of PEAP methods. switch (phase2Method) { case WIFI_PEAP_PHASE2_NONE: config.enterpriseConfig.setPhase2Method(Phase2.NONE); break ; case WIFI_PEAP_PHASE2_MSCHAPV2: config.enterpriseConfig.setPhase2Method(Phase2.MSCHAPV2); break ; case WIFI_PEAP_PHASE2_GTC: config.enterpriseConfig.setPhase2Method(Phase2.GTC); break ; default : Log.e(TAG, "Unknown phase2 method" + phase2Method); break ; } break ; default : // The default index from mPhase2FullAdapter maps to the API config.enterpriseConfig.setPhase2Method(phase2Method); break ; } String caCert = (String) mEapCaCertSpinner.getSelectedItem(); config.enterpriseConfig.setCaCertificateAliases( null ); config.enterpriseConfig.setCaPath( null ); config.enterpriseConfig.setDomainSuffixMatch(mEapDomainView.getText().toString()); if (caCert.equals(mUnspecifiedCertString) || caCert.equals(mDoNotValidateEapServerString)) { // ca_cert already set to null, so do nothing. } else if (caCert.equals(mUseSystemCertsString)) { config.enterpriseConfig.setCaPath(SYSTEM_CA_STORE_PATH); } else if (caCert.equals(mMultipleCertSetString)) { if (mAccessPoint != null ) { if (!mAccessPoint.isSaved()) { Log.e(TAG, "Multiple certs can only be set " + "when editing saved network" ); } config.enterpriseConfig.setCaCertificateAliases( mAccessPoint .getConfig() .enterpriseConfig .getCaCertificateAliases()); } } else { config.enterpriseConfig.setCaCertificateAliases( new String[] {caCert}); } // ca_cert or ca_path should not both be non-null, since we only intend to let // the use either their own certificate, or the system certificates, not both. // The variable that is not used must explicitly be set to null, so that a // previously-set value on a saved configuration will be erased on an update. if (config.enterpriseConfig.getCaCertificateAliases() != null && config.enterpriseConfig.getCaPath() != null ) { Log.e(TAG, "ca_cert (" + config.enterpriseConfig.getCaCertificateAliases() + ") and ca_path (" + config.enterpriseConfig.getCaPath() + ") should not both be non-null" ); } String clientCert = (String) mEapUserCertSpinner.getSelectedItem(); if (clientCert.equals(mUnspecifiedCertString) || clientCert.equals(mDoNotProvideEapUserCertString)) { // Note: |clientCert| should not be able to take the value |unspecifiedCert|, // since we prevent such configurations from being saved. clientCert = "" ; } config.enterpriseConfig.setClientCertificateAlias(clientCert); if (eapMethod == Eap.SIM || eapMethod == Eap.AKA || eapMethod == Eap.AKA_PRIME) { config.enterpriseConfig.setIdentity( "" ); config.enterpriseConfig.setAnonymousIdentity( "" ); } else if (eapMethod == Eap.PWD) { config.enterpriseConfig.setIdentity(mEapIdentityView.getText().toString()); config.enterpriseConfig.setAnonymousIdentity( "" ); } else { config.enterpriseConfig.setIdentity(mEapIdentityView.getText().toString()); config.enterpriseConfig.setAnonymousIdentity( mEapAnonymousView.getText().toString()); } if (mPasswordView.isShown()) { // For security reasons, a previous password is not displayed to user. // Update only if it has been changed. if (mPasswordView.length() > 0 ) { config.enterpriseConfig.setPassword(mPasswordView.getText().toString()); } } else { // clear password config.enterpriseConfig.setPassword(mPasswordView.getText().toString()); } break ; default : return null ; } config.setIpConfiguration( new IpConfiguration(mIpAssignment, mProxySettings, mStaticIpConfiguration, mHttpProxy)); return config; } |
0 件のコメント:
コメントを投稿