2012年06月09日

本当にそれでいいの?AndroidプログラミングでのWifi接続先切り替え

Androidプログラミングの楽なところは、困ったらgoogle先生に尋ねると、懇切丁寧な解説サイトに連れて行ってくれて、ステキなスニペットまで土産に持たせてくれるってところ。しかし、スニペットをそのまま使ってたらトラブルに遭ったので、顛末をここに記す。

ほとんどのサイトでは、Wifiの切り替えはWifiManager.enableNetwork(id, true)を使うと解説している。第二引数のtrueが重要である。trueにすると、既に接続しているネットワークを切り離して指定したネットワークに繋ぐ。たとえば以下のようなコードを書く。

  WifiManager wiman = (WifiManager) getSystemService(Context.WIFI_SERVICE);
  WifiConfiguration conf=null;
  String ssid2 = "\"myAsciiSSID\"";
  for(WifiConfiguration c0 : wiman.getConfiguredNetworks()){
    if(c0.SSID.equals(ssid2)){
      conf = c0;
      break;
    }
  }
  if(conf!=null) wiman.enableNetwork(conf.networkId, true);

確かにこれでWifiの接続先切り替えに成功する。が、「SSID_Aに接続」→「SSID_Bに接続」→「SSID_Aに接続」…と交互に切り替えを繰り返すと、急にネットワークにつながらなくなる時がある。法則性としては、

  • Android 4.xでは発生しないが、2.xでは発生する確率が高い
  • 機種依存がある?WebではNexusシリーズやDroidでの被害報告を見た
  • なぜかディスプレイを切って、もう一度つけると直る
  • なぜか、「設定→無線とネットワーク」から明示的に接続させると、直る。この際、つながらないネットワークは「無効」と表示される

いろいろ試した結果、以下のようにすると連続で切り替えても上手くいくようである。

  WifiManager wiman = (WifiManager) getSystemService(Context.WIFI_SERVICE);
  WifiConfiguration conf=null;
  String ssid2 = "\"myAsciiSSID\"";
  for(WifiConfiguration c0 : wiman.getConfiguredNetworks()){
    if(c0.SSID.equals(ssid2)){
      conf = c0;
      break;
    }
  }
  if(conf!=null){
    wiman.enableNetwork(conf.networkId, true);
    for(WifiConfiguration c0 : m_wiman.getConfiguredNetworks()){
      m_wiman.enableNetwork(c0.networkId, false);
    }
    m_wiman.saveConfiguration();
  }

最後に足された4行が重要である。こうすることで、少なくともNexusOneでは症状が改善した。ただし、WifiManager.saveConfiguration()の後はしばらくWifiManager.getConfiguredNetworks()の動きがおかしくなるようで、上記ルーチンを連打すると、時々動きがおかしくなる。

どこまで正しいかわからないが考察。WifiManager.enableNetwork(id, true)はAPIマニュアルによると、他のネットワークを無効化して目的のネットワークに繋ぐ。よって、もともと繋いでいたアクセスポイントは「無効」にされてしまう。Androidの特定バージョンでは無効化されてしまったネットワークにはWifiManager.enableNetwork()で再びつなぐことが出来ない。「無効」のタグ付けを外すことさえできれば再接続できるので、WifiManager.enableNetwork(id, false)を使って無効化を解除する(falseをつけて無効化を外す手順は、addNetwork()の使い方を参照のこと)。trueをつけて一度呼び出すのは、アクセス先の優先順位リストを書き換えるためである。

ちなみに上記スニペットのヒントは、Android 2.3のソースコードからいただいた。 packages/apps/Settings/src/com/android/settings/wifi/WifiSettings.javaのonClick()、saveNetworks()、enableNetworks()あたりが参考になる。というか、設定画面の挙動そのまんまである。 ソースをちょっと眺めるだけならgitHubからいける。
https://github.com/OESF

ラベル:android
posted by yuji_at_radiance at 22:31| Comment(0) | TrackBack(0) | ソフトウェア | このブログの読者になる | 更新情報をチェックする
この記事へのコメント
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント:

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。

この記事へのトラックバック
×

この広告は1年以上新しい記事の投稿がないブログに表示されております。