WifiScanningServiceImpl.java revision 476bee2fef10d060c25c35858b1f7f60803d9f49
1/* 2 * Copyright (C) 2008 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 17package com.android.server.wifi; 18 19import android.app.AlarmManager; 20import android.app.PendingIntent; 21import android.content.BroadcastReceiver; 22import android.content.Context; 23import android.content.Intent; 24import android.content.IntentFilter; 25import android.net.wifi.IWifiScanner; 26import android.net.wifi.ScanResult; 27import android.net.wifi.WifiManager; 28import android.net.wifi.WifiScanner; 29import android.net.wifi.WifiScanner.ScanSettings; 30import android.net.wifi.WifiSsid; 31import android.os.Handler; 32import android.os.HandlerThread; 33import android.os.Looper; 34import android.os.Message; 35import android.os.Messenger; 36import android.os.RemoteException; 37import android.util.Log; 38import android.util.Slog; 39 40import com.android.internal.util.AsyncChannel; 41import com.android.internal.util.Protocol; 42import com.android.internal.util.StateMachine; 43import com.android.internal.util.State; 44 45import java.io.FileDescriptor; 46import java.io.PrintWriter; 47import java.util.ArrayList; 48import java.util.Collection; 49import java.util.HashMap; 50import java.util.HashSet; 51import java.util.Iterator; 52import java.util.List; 53import java.util.Map; 54 55public class WifiScanningServiceImpl extends IWifiScanner.Stub { 56 57 private static final String TAG = "WifiScanningService"; 58 private static final boolean DBG = true; 59 private static final int INVALID_KEY = 0; // same as WifiScanner 60 61 @Override 62 public Messenger getMessenger() { 63 return new Messenger(mClientHandler); 64 } 65 66 private class ClientHandler extends Handler { 67 68 ClientHandler(android.os.Looper looper) { 69 super(looper); 70 } 71 72 @Override 73 public void handleMessage(Message msg) { 74 75 if (DBG) Log.d(TAG, "ClientHandler got" + msg); 76 77 switch (msg.what) { 78 79 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: 80 if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { 81 AsyncChannel c = (AsyncChannel) msg.obj; 82 if (DBG) Slog.d(TAG, "New client listening to asynchronous messages: " + 83 msg.replyTo); 84 ClientInfo cInfo = new ClientInfo(c, msg.replyTo); 85 mClients.put(msg.replyTo, cInfo); 86 } else { 87 Slog.e(TAG, "Client connection failure, error=" + msg.arg1); 88 } 89 return; 90 case AsyncChannel.CMD_CHANNEL_DISCONNECTED: 91 if (msg.arg1 == AsyncChannel.STATUS_SEND_UNSUCCESSFUL) { 92 Slog.e(TAG, "Send failed, client connection lost"); 93 } else { 94 if (DBG) Slog.d(TAG, "Client connection lost with reason: " + msg.arg1); 95 } 96 if (DBG) Slog.d(TAG, "closing client " + msg.replyTo); 97 mClients.remove(msg.replyTo); 98 return; 99 case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: 100 AsyncChannel ac = new AsyncChannel(); 101 ac.connect(mContext, this, msg.replyTo); 102 return; 103 } 104 105 ClientInfo ci = mClients.get(msg.replyTo); 106 if (ci == null) { 107 Slog.e(TAG, "Could not find client info for message " + msg.replyTo); 108 replyFailed(msg, WifiScanner.REASON_INVALID_LISTENER, null); 109 return; 110 } 111 112 int validCommands[] = { 113 WifiScanner.CMD_SCAN, 114 WifiScanner.CMD_START_BACKGROUND_SCAN, 115 WifiScanner.CMD_STOP_BACKGROUND_SCAN, 116 WifiScanner.CMD_SET_HOTLIST, 117 WifiScanner.CMD_RESET_HOTLIST, 118 WifiScanner.CMD_CONFIGURE_WIFI_CHANGE, 119 WifiScanner.CMD_START_TRACKING_CHANGE, 120 WifiScanner.CMD_STOP_TRACKING_CHANGE }; 121 122 for(int cmd : validCommands) { 123 if (cmd == msg.what) { 124 mStateMachine.sendMessage(Message.obtain(msg)); 125 return; 126 } 127 } 128 129 replyFailed(msg, WifiScanner.REASON_INVALID_REQUEST, null); 130 } 131 } 132 133 private static final int BASE = Protocol.BASE_WIFI_SCANNER_SERVICE; 134 135 private static final int CMD_SCAN_RESULTS_AVAILABLE = BASE + 0; 136 private static final int CMD_FULL_SCAN_RESULTS = BASE + 1; 137 private static final int CMD_HOTLIST_AP_FOUND = BASE + 2; 138 private static final int CMD_HOTLIST_AP_LOST = BASE + 3; 139 private static final int CMD_WIFI_CHANGE_DETECTED = BASE + 4; 140 private static final int CMD_WIFI_CHANGES_STABILIZED = BASE + 5; 141 private static final int CMD_DRIVER_LOADED = BASE + 6; 142 private static final int CMD_DRIVER_UNLOADED = BASE + 7; 143 private static final int CMD_SCAN_PAUSED = BASE + 8; 144 private static final int CMD_SCAN_RESTARTED = BASE + 9; 145 146 private Context mContext; 147 private WifiScanningStateMachine mStateMachine; 148 private ClientHandler mClientHandler; 149 150 WifiScanningServiceImpl() { } 151 152 WifiScanningServiceImpl(Context context) { 153 mContext = context; 154 } 155 156 public void startService(Context context) { 157 mContext = context; 158 159 HandlerThread thread = new HandlerThread("WifiScanningService"); 160 thread.start(); 161 162 mClientHandler = new ClientHandler(thread.getLooper()); 163 mStateMachine = new WifiScanningStateMachine(thread.getLooper()); 164 mWifiChangeStateMachine = new WifiChangeStateMachine(thread.getLooper()); 165 166 mContext.registerReceiver( 167 new BroadcastReceiver() { 168 @Override 169 public void onReceive(Context context, Intent intent) { 170 int state = intent.getIntExtra( 171 WifiManager.EXTRA_SCAN_AVAILABLE, WifiManager.WIFI_STATE_DISABLED); 172 if (DBG) Log.d(TAG, "SCAN_AVAILABLE : " + state); 173 if (state == WifiManager.WIFI_STATE_ENABLED) { 174 mStateMachine.sendMessage(CMD_DRIVER_LOADED); 175 } else if (state == WifiManager.WIFI_STATE_DISABLED) { 176 mStateMachine.sendMessage(CMD_DRIVER_UNLOADED); 177 } 178 } 179 }, new IntentFilter(WifiManager.WIFI_SCAN_AVAILABLE)); 180 181 mStateMachine.start(); 182 mWifiChangeStateMachine.start(); 183 } 184 185 class WifiScanningStateMachine extends StateMachine implements WifiNative.ScanEventHandler, 186 WifiNative.HotlistEventHandler, WifiNative.SignificantWifiChangeEventHandler { 187 188 private final DefaultState mDefaultState = new DefaultState(); 189 private final StartedState mStartedState = new StartedState(); 190 private final PausedState mPausedState = new PausedState(); 191 192 public WifiScanningStateMachine(Looper looper) { 193 super(TAG, looper); 194 195 setLogRecSize(512); 196 setLogOnlyTransitions(false); 197 // setDbg(DBG); 198 199 addState(mDefaultState); 200 addState(mStartedState, mDefaultState); 201 addState(mPausedState, mDefaultState); 202 203 setInitialState(mDefaultState); 204 } 205 206 @Override 207 public void onScanResultsAvailable() { 208 if (DBG) Log.d(TAG, "onScanResultAvailable event received"); 209 sendMessage(CMD_SCAN_RESULTS_AVAILABLE); 210 } 211 212 @Override 213 public void onFullScanResult(ScanResult fullScanResult) { 214 if (DBG) Log.d(TAG, "Full scanresult received"); 215 sendMessage(CMD_FULL_SCAN_RESULTS, 0, 0, fullScanResult); 216 } 217 218 @Override 219 public void onScanPaused() { 220 sendMessage(CMD_SCAN_PAUSED); 221 } 222 223 @Override 224 public void onScanRestarted() { 225 sendMessage(CMD_SCAN_RESTARTED); 226 } 227 228 @Override 229 public void onHotlistApFound(ScanResult[] results) { 230 if (DBG) Log.d(TAG, "HotlistApFound event received"); 231 sendMessage(CMD_HOTLIST_AP_FOUND, 0, 0, results); 232 } 233 234 @Override 235 public void onChangesFound(ScanResult[] results) { 236 if (DBG) Log.d(TAG, "onWifiChangesFound event received"); 237 sendMessage(CMD_WIFI_CHANGE_DETECTED, 0, 0, results); 238 } 239 240 class DefaultState extends State { 241 @Override 242 public void enter() { 243 if (DBG) Log.d(TAG, "DefaultState"); 244 } 245 @Override 246 public boolean processMessage(Message msg) { 247 248 if (DBG) Log.d(TAG, "DefaultState got" + msg); 249 250 ClientInfo ci = mClients.get(msg.replyTo); 251 252 switch (msg.what) { 253 case CMD_DRIVER_LOADED: 254 if (WifiNative.startHal() && WifiNative.getInterfaces() != 0) { 255 WifiNative.ScanCapabilities capabilities = 256 new WifiNative.ScanCapabilities(); 257 if (WifiNative.getScanCapabilities(capabilities)) { 258 transitionTo(mStartedState); 259 } else { 260 loge("could not get scan capabilities"); 261 } 262 } else { 263 loge("could not start HAL"); 264 } 265 break; 266 case WifiScanner.CMD_SCAN: 267 case WifiScanner.CMD_START_BACKGROUND_SCAN: 268 case WifiScanner.CMD_STOP_BACKGROUND_SCAN: 269 case WifiScanner.CMD_SET_HOTLIST: 270 case WifiScanner.CMD_RESET_HOTLIST: 271 case WifiScanner.CMD_CONFIGURE_WIFI_CHANGE: 272 case WifiScanner.CMD_START_TRACKING_CHANGE: 273 case WifiScanner.CMD_STOP_TRACKING_CHANGE: 274 replyFailed(msg, WifiScanner.REASON_UNSPECIFIED, null); 275 break; 276 277 case CMD_SCAN_RESULTS_AVAILABLE: 278 if (DBG) log("ignored scan results available event"); 279 break; 280 281 case CMD_FULL_SCAN_RESULTS: 282 if (DBG) log("ignored full scan result event"); 283 break; 284 285 default: 286 break; 287 } 288 289 return HANDLED; 290 } 291 } 292 293 class StartedState extends State { 294 295 @Override 296 public void enter() { 297 if (DBG) Log.d(TAG, "StartedState"); 298 } 299 300 @Override 301 public boolean processMessage(Message msg) { 302 303 if (DBG) Log.d(TAG, "StartedState got" + msg); 304 305 ClientInfo ci = mClients.get(msg.replyTo); 306 307 switch (msg.what) { 308 case CMD_DRIVER_UNLOADED: 309 transitionTo(mDefaultState); 310 break; 311 case WifiScanner.CMD_SCAN: 312 replyFailed(msg, WifiScanner.REASON_UNSPECIFIED, null); 313 break; 314 case WifiScanner.CMD_START_BACKGROUND_SCAN: 315 addScanRequest(ci, msg.arg2, (ScanSettings) msg.obj); 316 replySucceeded(msg, null); 317 break; 318 case WifiScanner.CMD_STOP_BACKGROUND_SCAN: 319 removeScanRequest(ci, msg.arg2); 320 break; 321 case WifiScanner.CMD_GET_SCAN_RESULTS: { 322 ScanResult[] results = getScanResults(ci); 323 replySucceeded(msg, results); 324 } 325 break; 326 case WifiScanner.CMD_SET_HOTLIST: 327 setHotlist(ci, msg.arg2, (WifiScanner.HotlistSettings) msg.obj); 328 replySucceeded(msg, null); 329 break; 330 case WifiScanner.CMD_RESET_HOTLIST: 331 resetHotlist(ci, msg.arg2); 332 break; 333 case WifiScanner.CMD_START_TRACKING_CHANGE: 334 trackWifiChanges(ci, msg.arg2); 335 replySucceeded(msg, null); 336 break; 337 case WifiScanner.CMD_STOP_TRACKING_CHANGE: 338 untrackWifiChanges(ci, msg.arg2); 339 break; 340 case WifiScanner.CMD_CONFIGURE_WIFI_CHANGE: 341 configureWifiChange((WifiScanner.WifiChangeSettings) msg.obj); 342 break; 343 case CMD_SCAN_RESULTS_AVAILABLE: { 344 ScanResult[] results = WifiNative.getScanResults(); 345 Collection<ClientInfo> clients = mClients.values(); 346 for (ClientInfo ci2 : clients) { 347 ci2.reportScanResults(results); 348 } 349 } 350 break; 351 case CMD_FULL_SCAN_RESULTS: { 352 ScanResult result = (ScanResult) msg.obj; 353 Collection<ClientInfo> clients = mClients.values(); 354 for (ClientInfo ci2 : clients) { 355 ci2.reportFullScanResult(result); 356 } 357 } 358 break; 359 360 case CMD_HOTLIST_AP_FOUND: { 361 ScanResult[] results = (ScanResult[])msg.obj; 362 if (DBG) Log.d(TAG, "Found " + results.length + " results"); 363 Collection<ClientInfo> clients = mClients.values(); 364 for (ClientInfo ci2 : clients) { 365 ci2.reportHotlistResults(results); 366 } 367 } 368 break; 369 case CMD_WIFI_CHANGE_DETECTED: { 370 ScanResult[] results = (ScanResult[])msg.obj; 371 reportWifiChanged(results); 372 } 373 break; 374 case CMD_WIFI_CHANGES_STABILIZED: { 375 ScanResult[] results = (ScanResult[])msg.obj; 376 reportWifiStabilized(results); 377 } 378 break; 379 380 default: 381 return NOT_HANDLED; 382 } 383 384 return HANDLED; 385 } 386 } 387 388 class PausedState extends State { 389 @Override 390 public boolean processMessage(Message msg) { 391 switch (msg.what) { 392 case CMD_SCAN_RESTARTED: 393 transitionTo(mStartedState); 394 break; 395 default: 396 deferMessage(msg); 397 break; 398 } 399 return HANDLED; 400 } 401 402 } 403 404 @Override 405 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 406 super.dump(fd, pw, args); 407 pw.println("number of clients : " + mClients.size()); 408 pw.println(); 409 } 410 411 } 412 413 /* client management */ 414 HashMap<Messenger, ClientInfo> mClients = new HashMap<Messenger, ClientInfo>(); 415 416 private class ClientInfo { 417 private static final int MAX_LIMIT = 16; 418 private final AsyncChannel mChannel; 419 private final Messenger mMessenger; 420 421 ClientInfo(AsyncChannel c, Messenger m) { 422 mChannel = c; 423 mMessenger = m; 424 if (DBG) Slog.d(TAG, "New client, channel: " + c + " messenger: " + m); 425 } 426 427 @Override 428 public String toString() { 429 StringBuffer sb = new StringBuffer(); 430 sb.append("mChannel ").append(mChannel).append("\n"); 431 sb.append("mMessenger ").append(mMessenger).append("\n"); 432 433 Iterator<Map.Entry<Integer, ScanSettings>> it = mScanSettings.entrySet().iterator(); 434 for (; it.hasNext(); ) { 435 Map.Entry<Integer, ScanSettings> entry = it.next(); 436 sb.append("[ScanId ").append(entry.getKey()).append("\n"); 437 sb.append("ScanSettings ").append(entry.getValue()).append("\n"); 438 sb.append("]"); 439 } 440 441 return sb.toString(); 442 } 443 444 HashMap<Integer, ScanSettings> mScanSettings = new HashMap<Integer, ScanSettings>(4); 445 HashMap<Integer, Integer> mScanPeriods = new HashMap<Integer, Integer>(4); 446 447 void addScanRequest(ScanSettings settings, int id) { 448 mScanSettings.put(id, settings); 449 } 450 451 void removeScanRequest(int id) { 452 mScanSettings.remove(id); 453 } 454 455 Iterator<Map.Entry<Integer, WifiScanner.ScanSettings>> getScans() { 456 return mScanSettings.entrySet().iterator(); 457 } 458 459 Collection<ScanSettings> getScanSettings() { 460 return mScanSettings.values(); 461 } 462 463 void reportScanResults(ScanResult[] results) { 464 Iterator<Integer> it = mScanSettings.keySet().iterator(); 465 while (it.hasNext()) { 466 int handler = it.next(); 467 reportScanResults(results, handler); 468 } 469 } 470 471 void reportScanResults(ScanResult[] results, int handler) { 472 ScanSettings settings = mScanSettings.get(handler); 473 474 // check the channels this client asked for .. 475 int num_results = 0; 476 for (ScanResult result : results) { 477 for (WifiScanner.ChannelSpec channelSpec : settings.channels) { 478 if (channelSpec.frequency == result.frequency) { 479 num_results++; 480 break; 481 } 482 } 483 } 484 485 if (num_results == 0) { 486 // nothing to report 487 return; 488 } 489 490 ScanResult results2[] = new ScanResult[num_results]; 491 int index = 0; 492 for (ScanResult result : results) { 493 for (WifiScanner.ChannelSpec channelSpec : settings.channels) { 494 if (channelSpec.frequency == result.frequency) { 495 WifiSsid wifiSsid = WifiSsid.createFromAsciiEncoded(result.SSID); 496 ScanResult newResult = new ScanResult(wifiSsid, result.BSSID, "", 497 result.level, result.frequency, result.timestamp); 498 results2[index] = newResult; 499 index++; 500 break; 501 } 502 } 503 } 504 505 deliverScanResults(handler, results2); 506 } 507 508 void deliverScanResults(int handler, ScanResult results[]) { 509 WifiScanner.ParcelableScanResults parcelableScanResults = 510 new WifiScanner.ParcelableScanResults(results); 511 mChannel.sendMessage(WifiScanner.CMD_SCAN_RESULT, 0, handler, parcelableScanResults); 512 } 513 514 void reportFullScanResult(ScanResult result) { 515 Iterator<Integer> it = mScanSettings.keySet().iterator(); 516 while (it.hasNext()) { 517 int handler = it.next(); 518 ScanSettings settings = mScanSettings.get(handler); 519 for (WifiScanner.ChannelSpec channelSpec : settings.channels) { 520 if (channelSpec.frequency == result.frequency) { 521 mChannel.sendMessage(WifiScanner.CMD_FULL_SCAN_RESULT, 0, handler, result); 522 } 523 } 524 } 525 } 526 527 void reportPeriodChanged(int handler, ScanSettings settings, int newPeriodInMs) { 528 Integer prevPeriodObject = mScanPeriods.get(handler); 529 int prevPeriodInMs = settings.periodInMs; 530 if (prevPeriodObject != null) { 531 prevPeriodInMs = prevPeriodObject; 532 } 533 534 if (prevPeriodInMs != newPeriodInMs) { 535 mChannel.sendMessage(WifiScanner.CMD_PERIOD_CHANGED, newPeriodInMs, handler); 536 } 537 } 538 539 HashMap<Integer, WifiScanner.HotlistSettings> mHotlistSettings = 540 new HashMap<Integer, WifiScanner.HotlistSettings>(); 541 542 void addHostlistSettings(WifiScanner.HotlistSettings settings, int handler) { 543 mHotlistSettings.put(handler, settings); 544 } 545 546 void removeHostlistSettings(int handler) { 547 mHotlistSettings.remove(handler); 548 } 549 550 Collection<WifiScanner.HotlistSettings> getHotlistSettings() { 551 return mHotlistSettings.values(); 552 } 553 554 void reportHotlistResults(ScanResult[] results) { 555 Iterator<Map.Entry<Integer, WifiScanner.HotlistSettings>> it = 556 mHotlistSettings.entrySet().iterator(); 557 while (it.hasNext()) { 558 Map.Entry<Integer, WifiScanner.HotlistSettings> entry = it.next(); 559 int handler = entry.getKey(); 560 WifiScanner.HotlistSettings settings = entry.getValue(); 561 int num_results = 0; 562 for (ScanResult result : results) { 563 for (WifiScanner.HotspotInfo hotspotInfo : settings.hotspotInfos) { 564 if (result.BSSID.equalsIgnoreCase(hotspotInfo.bssid)) { 565 num_results++; 566 break; 567 } 568 } 569 } 570 571 if (num_results == 0) { 572 // nothing to report 573 return; 574 } 575 576 ScanResult results2[] = new ScanResult[num_results]; 577 int index = 0; 578 for (ScanResult result : results) { 579 for (WifiScanner.HotspotInfo hotspotInfo : settings.hotspotInfos) { 580 if (result.BSSID.equalsIgnoreCase(hotspotInfo.bssid)) { 581 results2[index] = result; 582 index++; 583 } 584 } 585 } 586 587 WifiScanner.ParcelableScanResults parcelableScanResults = 588 new WifiScanner.ParcelableScanResults(results2); 589 590 mChannel.sendMessage(WifiScanner.CMD_AP_FOUND, 0, handler, parcelableScanResults); 591 } 592 } 593 594 HashSet<Integer> mSignificantWifiHandlers = new HashSet<Integer>(); 595 void addSignificantWifiChange(int handler) { 596 mSignificantWifiHandlers.add(handler); 597 } 598 599 void removeSignificantWifiChange(int handler) { 600 mSignificantWifiHandlers.remove(handler); 601 } 602 603 Collection<Integer> getWifiChangeHandlers() { 604 return mSignificantWifiHandlers; 605 } 606 607 void reportWifiChanged(ScanResult[] results) { 608 WifiScanner.ParcelableScanResults parcelableScanResults = 609 new WifiScanner.ParcelableScanResults(results); 610 Iterator<Integer> it = mSignificantWifiHandlers.iterator(); 611 while (it.hasNext()) { 612 int handler = it.next(); 613 mChannel.sendMessage(WifiScanner.CMD_WIFI_CHANGE_DETECTED, 614 0, handler, parcelableScanResults); 615 } 616 } 617 618 void reportWifiStabilized(ScanResult[] results) { 619 WifiScanner.ParcelableScanResults parcelableScanResults = 620 new WifiScanner.ParcelableScanResults(results); 621 Iterator<Integer> it = mSignificantWifiHandlers.iterator(); 622 while (it.hasNext()) { 623 int handler = it.next(); 624 mChannel.sendMessage(WifiScanner.CMD_WIFI_CHANGES_STABILIZED, 625 0, handler, parcelableScanResults); 626 } 627 } 628 } 629 630 void replySucceeded(Message msg, Object obj) { 631 if (msg.replyTo != null) { 632 Message reply = Message.obtain(); 633 reply.what = WifiScanner.CMD_OP_SUCCEEDED; 634 reply.arg2 = msg.arg2; 635 reply.obj = obj; 636 try { 637 msg.replyTo.send(reply); 638 } catch (RemoteException e) { 639 // There's not much we can do if reply can't be sent! 640 } 641 } else { 642 // locally generated message; doesn't need a reply! 643 } 644 } 645 646 void replyFailed(Message msg, int reason, Object obj) { 647 Message reply = Message.obtain(); 648 reply.what = WifiScanner.CMD_OP_FAILED; 649 reply.arg1 = reason; 650 reply.arg2 = msg.arg2; 651 reply.obj = obj; 652 try { 653 msg.replyTo.send(reply); 654 } catch (RemoteException e) { 655 // There's not much we can do if reply can't be sent! 656 } 657 } 658 659 private static class SettingsComputer { 660 661 private static class TimeBucket { 662 int periodInSecond; 663 int periodMinInSecond; 664 int periodMaxInSecond; 665 666 TimeBucket(int p, int min, int max) { 667 periodInSecond = p; 668 periodMinInSecond = min; 669 periodMaxInSecond = max; 670 } 671 } 672 673 private static final TimeBucket[] mTimeBuckets = new TimeBucket[] { 674 new TimeBucket( 5, 0, 10 ), 675 new TimeBucket( 10, 10, 25 ), 676 new TimeBucket( 30, 25, 55 ), 677 new TimeBucket( 60, 55, 100), 678 new TimeBucket( 120, 100, 240), 679 new TimeBucket( 300, 240, 500), 680 new TimeBucket( 600, 500, 1500), 681 new TimeBucket( 1800, 1500, WifiScanner.MAX_SCAN_PERIOD_MS) }; 682 683 private static final int MAX_BUCKETS = 8; 684 private static final int MAX_CHANNELS = 8; 685 686 private WifiNative.ScanSettings mSettings; 687 { 688 mSettings = new WifiNative.ScanSettings(); 689 mSettings.max_ap_per_scan = 10; 690 mSettings.base_period_ms = 5000; 691 mSettings.report_threshold = 80; 692 693 mSettings.buckets = new WifiNative.BucketSettings[MAX_BUCKETS]; 694 for (int i = 0; i < mSettings.buckets.length; i++) { 695 WifiNative.BucketSettings bucketSettings = new WifiNative.BucketSettings(); 696 bucketSettings.bucket = i; 697 bucketSettings.report_events = 0; 698 bucketSettings.channels = new WifiNative.ChannelSettings[MAX_CHANNELS]; 699 bucketSettings.num_channels = 0; 700 for (int j = 0; j < bucketSettings.channels.length; j++) { 701 WifiNative.ChannelSettings channelSettings = new WifiNative.ChannelSettings(); 702 bucketSettings.channels[j] = channelSettings; 703 } 704 mSettings.buckets[i] = bucketSettings; 705 } 706 } 707 708 HashMap<Integer, Integer> mChannelToBucketMap = new HashMap<Integer, Integer>(); 709 710 private int getBestBucket(WifiScanner.ScanSettings settings) { 711 712 // check to see if any of the channels are being scanned already 713 // and find the smallest bucket index (it represents the quickest 714 // period of scan) 715 716 WifiScanner.ChannelSpec channels[] = settings.channels; 717 if (channels == null) { 718 // set channels based on band 719 channels = getChannelsForBand(settings.band); 720 } 721 722 if (channels == null) { 723 // still no channels; then there's nothing to scan 724 Log.e(TAG, "No channels to scan!!"); 725 return -1; 726 } 727 728 int mostFrequentBucketIndex = mTimeBuckets.length; 729 730 for (WifiScanner.ChannelSpec desiredChannelSpec : channels) { 731 if (mChannelToBucketMap.containsKey(desiredChannelSpec.frequency)) { 732 int bucket = mChannelToBucketMap.get(desiredChannelSpec.frequency); 733 if (bucket < mostFrequentBucketIndex) { 734 mostFrequentBucketIndex = bucket; 735 } 736 } 737 } 738 739 int bestBucketIndex = -1; // best by period 740 for (int i = 0; i < mTimeBuckets.length; i++) { 741 TimeBucket bucket = mTimeBuckets[i]; 742 if (bucket.periodMinInSecond * 1000 <= settings.periodInMs 743 && settings.periodInMs < bucket.periodMaxInSecond * 1000) { 744 // we set the time period to this 745 bestBucketIndex = i; 746 break; 747 } 748 } 749 750 if (mostFrequentBucketIndex < bestBucketIndex) { 751 for (WifiScanner.ChannelSpec desiredChannelSpec : channels) { 752 mChannelToBucketMap.put(desiredChannelSpec.frequency, mostFrequentBucketIndex); 753 } 754 Log.d(TAG, "returning mf bucket number " + mostFrequentBucketIndex); 755 return mostFrequentBucketIndex; 756 } else if (bestBucketIndex != -1) { 757 for (WifiScanner.ChannelSpec desiredChannelSpec : channels) { 758 mChannelToBucketMap.put(desiredChannelSpec.frequency, bestBucketIndex); 759 } 760 Log.d(TAG, "returning best bucket number " + bestBucketIndex); 761 return bestBucketIndex; 762 } 763 764 Log.e(TAG, "Could not find suitable bucket for period " + settings.periodInMs); 765 return -1; 766 } 767 768 void prepChannelMap(WifiScanner.ScanSettings settings) { 769 getBestBucket(settings); 770 } 771 772 int addScanRequestToBucket(WifiScanner.ScanSettings settings) { 773 774 int bucketIndex = getBestBucket(settings); 775 if (bucketIndex == -1) { 776 Log.e(TAG, "Ignoring invalid settings"); 777 return -1; 778 } 779 780 WifiScanner.ChannelSpec desiredChannels[] = settings.channels; 781 if (desiredChannels == null) { 782 // set channels based on band 783 desiredChannels = getChannelsForBand(settings.band); 784 if (desiredChannels == null) { 785 // still no channels; then there's nothing to scan 786 Log.e(TAG, "No channels to scan!!"); 787 return -1; 788 } 789 } 790 791 // merge the channel lists for these buckets 792 Log.d(TAG, "merging " + desiredChannels.length + " channels " 793 + " for period " + settings.periodInMs); 794 795 WifiNative.BucketSettings bucket = mSettings.buckets[bucketIndex]; 796 boolean added = (bucket.num_channels == 0) 797 && (bucket.band == WifiScanner.WIFI_BAND_UNSPECIFIED); 798 Log.d(TAG, "existing " + bucket.num_channels + " channels "); 799 800 if (settings.band != WifiScanner.WIFI_BAND_UNSPECIFIED 801 || (bucket.num_channels + desiredChannels.length) > bucket.channels.length) { 802 // can't accommodate all channels; switch to specifying band 803 bucket.num_channels = 0; 804 bucket.band = getBandFromChannels(bucket.channels) 805 | getBandFromChannels(desiredChannels); 806 bucket.channels = new WifiNative.ChannelSettings[0]; 807 } else { 808 for (WifiScanner.ChannelSpec desiredChannelSpec : desiredChannels) { 809 810 Log.d(TAG, "desired channel " + desiredChannelSpec.frequency); 811 812 boolean found = false; 813 for (WifiNative.ChannelSettings existingChannelSpec : bucket.channels) { 814 if (desiredChannelSpec.frequency == existingChannelSpec.frequency) { 815 found = true; 816 break; 817 } 818 } 819 820 if (!found) { 821 WifiNative.ChannelSettings channelSettings = bucket.channels[bucket.num_channels]; 822 channelSettings.frequency = desiredChannelSpec.frequency; 823 bucket.num_channels++; 824 mChannelToBucketMap.put(bucketIndex, channelSettings.frequency); 825 } else { 826 if (DBG) Log.d(TAG, "Already scanning channel " + desiredChannelSpec.frequency); 827 } 828 } 829 } 830 831 if (bucket.report_events < settings.reportEvents) { 832 if (DBG) Log.d(TAG, "setting report_events to " + settings.reportEvents); 833 bucket.report_events = settings.reportEvents; 834 } else { 835 if (DBG) Log.d(TAG, "report_events is " + settings.reportEvents); 836 } 837 838 if (added) { 839 bucket.period_ms = mTimeBuckets[bucketIndex].periodInSecond * 1000; 840 mSettings.num_buckets++; 841 } 842 843 return bucket.period_ms; 844 } 845 846 public WifiNative.ScanSettings getComputedSettings() { 847 return mSettings; 848 } 849 850 public void compressBuckets() { 851 int num_buckets = 0; 852 for (int i = 0; i < mSettings.buckets.length; i++) { 853 if (mSettings.buckets[i].num_channels != 0 854 || mSettings.buckets[i].band != WifiScanner.WIFI_BAND_UNSPECIFIED) { 855 mSettings.buckets[num_buckets] = mSettings.buckets[i]; 856 num_buckets++; 857 } 858 } 859 // remove unused buckets 860 for (int i = num_buckets; i < mSettings.buckets.length; i++) { 861 mSettings.buckets[i] = null; 862 } 863 864 mSettings.num_buckets = num_buckets; 865 if (num_buckets != 0) { 866 mSettings.base_period_ms = mSettings.buckets[0].period_ms; 867 } 868 } 869 } 870 871 void resetBuckets() { 872 SettingsComputer c = new SettingsComputer(); 873 Collection<ClientInfo> clients = mClients.values(); 874 for (ClientInfo ci : clients) { 875 Collection<ScanSettings> settings = ci.getScanSettings(); 876 for (ScanSettings s : settings) { 877 c.prepChannelMap(s); 878 } 879 } 880 881 for (ClientInfo ci : clients) { 882 Iterator it = ci.getScans(); 883 while (it.hasNext()) { 884 Map.Entry<Integer, WifiScanner.ScanSettings> entry = 885 (Map.Entry<Integer,WifiScanner.ScanSettings>)it.next(); 886 int id = entry.getKey(); 887 ScanSettings s = entry.getValue(); 888 int newPeriodInMs = c.addScanRequestToBucket(s); 889 if (newPeriodInMs != -1 && newPeriodInMs != s.periodInMs) { 890 ci.reportPeriodChanged(id, s, newPeriodInMs); 891 } 892 } 893 } 894 895 c.compressBuckets(); 896 897 WifiNative.ScanSettings s = c.getComputedSettings(); 898 if (s.num_buckets == 0) { 899 if (DBG) Log.d(TAG, "Stopping scan because there are no buckets"); 900 WifiNative.stopScan(); 901 } else { 902 if (WifiNative.startScan(s, mStateMachine)) { 903 if (DBG) Log.d(TAG, "Successfully started scan of " + s.num_buckets + " buckets"); 904 } else { 905 if (DBG) Log.d(TAG, "Failed to start scan of " + s.num_buckets + " buckets"); 906 } 907 } 908 } 909 910 void addScanRequest(ClientInfo ci, int handler, ScanSettings settings) { 911 ci.addScanRequest(settings, handler); 912 resetBuckets(); 913 } 914 915 void removeScanRequest(ClientInfo ci, int handler) { 916 ci.removeScanRequest(handler); 917 resetBuckets(); 918 } 919 920 ScanResult[] getScanResults(ClientInfo ci) { 921 ScanResult results[] = WifiNative.getScanResults(); 922 ci.reportScanResults(results); 923 return results; 924 } 925 926 void resetHotlist() { 927 Collection<ClientInfo> clients = mClients.values(); 928 int num_hotlist_ap = 0; 929 930 for (ClientInfo ci : clients) { 931 Collection<WifiScanner.HotlistSettings> c = ci.getHotlistSettings(); 932 for (WifiScanner.HotlistSettings s : c) { 933 num_hotlist_ap += s.hotspotInfos.length; 934 } 935 } 936 937 if (num_hotlist_ap == 0) { 938 WifiNative.resetHotlist(); 939 } else { 940 WifiScanner.HotspotInfo hotspotInfos[] = new WifiScanner.HotspotInfo[num_hotlist_ap]; 941 int index = 0; 942 for (ClientInfo ci : clients) { 943 Collection<WifiScanner.HotlistSettings> settings = ci.getHotlistSettings(); 944 for (WifiScanner.HotlistSettings s : settings) { 945 for (int i = 0; i < s.hotspotInfos.length; i++, index++) { 946 hotspotInfos[index] = s.hotspotInfos[i]; 947 } 948 } 949 } 950 951 WifiScanner.HotlistSettings settings = new WifiScanner.HotlistSettings(); 952 settings.hotspotInfos = hotspotInfos; 953 settings.apLostThreshold = 3; 954 WifiNative.setHotlist(settings, mStateMachine); 955 } 956 } 957 958 void setHotlist(ClientInfo ci, int handler, WifiScanner.HotlistSettings settings) { 959 ci.addHostlistSettings(settings, handler); 960 resetHotlist(); 961 } 962 963 void resetHotlist(ClientInfo ci, int handler) { 964 ci.removeHostlistSettings(handler); 965 resetHotlist(); 966 } 967 968 WifiChangeStateMachine mWifiChangeStateMachine; 969 970 void trackWifiChanges(ClientInfo ci, int handler) { 971 mWifiChangeStateMachine.enable(); 972 ci.addSignificantWifiChange(handler); 973 } 974 975 void untrackWifiChanges(ClientInfo ci, int handler) { 976 ci.removeSignificantWifiChange(handler); 977 Collection<ClientInfo> clients = mClients.values(); 978 for (ClientInfo ci2 : clients) { 979 if (ci2.getWifiChangeHandlers().size() != 0) { 980 // there is at least one client watching for 981 // significant changes; so nothing more to do 982 return; 983 } 984 } 985 986 // no more clients looking for significant wifi changes 987 // no need to keep the state machine running; disable it 988 mWifiChangeStateMachine.disable(); 989 } 990 991 void configureWifiChange(WifiScanner.WifiChangeSettings settings) { 992 mWifiChangeStateMachine.configure(settings); 993 } 994 995 996 void reportWifiChanged(ScanResult results[]) { 997 Collection<ClientInfo> clients = mClients.values(); 998 for (ClientInfo ci : clients) { 999 ci.reportWifiChanged(results); 1000 } 1001 } 1002 1003 void reportWifiStabilized(ScanResult results[]) { 1004 Collection<ClientInfo> clients = mClients.values(); 1005 for (ClientInfo ci : clients) { 1006 ci.reportWifiStabilized(results); 1007 } 1008 } 1009 1010 class WifiChangeStateMachine extends StateMachine 1011 implements WifiNative.SignificantWifiChangeEventHandler { 1012 1013 private static final String TAG = "WifiChangeStateMachine"; 1014 1015 private static final int WIFI_CHANGE_CMD_NEW_SCAN_RESULTS = 0; 1016 private static final int WIFI_CHANGE_CMD_CHANGE_DETECTED = 1; 1017 private static final int WIFI_CHANGE_CMD_CHANGE_TIMEOUT = 2; 1018 private static final int WIFI_CHANGE_CMD_ENABLE = 3; 1019 private static final int WIFI_CHANGE_CMD_DISABLE = 4; 1020 private static final int WIFI_CHANGE_CMD_CONFIGURE = 5; 1021 1022 private static final int MAX_APS_TO_TRACK = 3; 1023 private static final int MOVING_SCAN_PERIOD_MS = 10000; 1024 private static final int STATIONARY_SCAN_PERIOD_MS = 5000; 1025 private static final int MOVING_STATE_TIMEOUT_MS = 30000; 1026 1027 State mDefaultState = new DefaultState(); 1028 State mStationaryState = new StationaryState(); 1029 State mMovingState = new MovingState(); 1030 1031 private static final String ACTION_TIMEOUT = 1032 "com.android.server.WifiScanningServiceImpl.action.TIMEOUT"; 1033 AlarmManager mAlarmManager; 1034 PendingIntent mTimeoutIntent; 1035 ScanResult mCurrentHotspots[]; 1036 1037 WifiChangeStateMachine(Looper looper) { 1038 super("SignificantChangeStateMachine", looper); 1039 1040 mClients.put(null, mClientInfo); 1041 1042 addState(mDefaultState); 1043 addState(mStationaryState, mDefaultState); 1044 addState(mMovingState, mDefaultState); 1045 1046 setInitialState(mDefaultState); 1047 } 1048 1049 public void enable() { 1050 if (mAlarmManager == null) { 1051 mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); 1052 } 1053 1054 if (mTimeoutIntent == null) { 1055 Intent intent = new Intent(ACTION_TIMEOUT, null); 1056 mTimeoutIntent = PendingIntent.getBroadcast(mContext, 0, intent, 0); 1057 1058 mContext.registerReceiver( 1059 new BroadcastReceiver() { 1060 @Override 1061 public void onReceive(Context context, Intent intent) { 1062 sendMessage(WIFI_CHANGE_CMD_CHANGE_TIMEOUT); 1063 } 1064 }, new IntentFilter(ACTION_TIMEOUT)); 1065 } 1066 1067 sendMessage(WIFI_CHANGE_CMD_ENABLE); 1068 } 1069 1070 public void disable() { 1071 sendMessage(WIFI_CHANGE_CMD_DISABLE); 1072 } 1073 1074 public void configure(WifiScanner.WifiChangeSettings settings) { 1075 sendMessage(WIFI_CHANGE_CMD_CONFIGURE, settings); 1076 } 1077 1078 class DefaultState extends State { 1079 @Override 1080 public void enter() { 1081 if (DBG) Log.d(TAG, "Entering IdleState"); 1082 } 1083 1084 @Override 1085 public boolean processMessage(Message msg) { 1086 if (DBG) Log.d(TAG, "DefaultState state got " + msg); 1087 switch (msg.what) { 1088 case WIFI_CHANGE_CMD_ENABLE : 1089 transitionTo(mMovingState); 1090 break; 1091 case WIFI_CHANGE_CMD_DISABLE: 1092 // nothing to do 1093 break; 1094 case WIFI_CHANGE_CMD_NEW_SCAN_RESULTS: 1095 // nothing to do 1096 break; 1097 case WIFI_CHANGE_CMD_CONFIGURE: 1098 /* save configuration till we transition to moving state */ 1099 deferMessage(msg); 1100 break; 1101 default: 1102 return NOT_HANDLED; 1103 } 1104 return HANDLED; 1105 } 1106 1107 } 1108 1109 class StationaryState extends State { 1110 @Override 1111 public void enter() { 1112 if (DBG) Log.d(TAG, "Entering StationaryState"); 1113 reportWifiStabilized(mCurrentHotspots); 1114 } 1115 1116 @Override 1117 public boolean processMessage(Message msg) { 1118 if (DBG) Log.d(TAG, "Stationary state got " + msg); 1119 switch (msg.what) { 1120 case WIFI_CHANGE_CMD_ENABLE : 1121 // do nothing 1122 break; 1123 case WIFI_CHANGE_CMD_CHANGE_DETECTED: 1124 if (DBG) Log.d(TAG, "Got wifi change detected"); 1125 reportWifiChanged((ScanResult[])msg.obj); 1126 transitionTo(mMovingState); 1127 break; 1128 case WIFI_CHANGE_CMD_DISABLE: 1129 mCurrentHotspots = null; 1130 removeScanRequest(); 1131 untrackSignificantWifiChange(); 1132 transitionTo(mDefaultState); 1133 break; 1134 case WIFI_CHANGE_CMD_CONFIGURE: 1135 /* save configuration till we transition to moving state */ 1136 deferMessage(msg); 1137 break; 1138 default: 1139 return NOT_HANDLED; 1140 } 1141 return HANDLED; 1142 } 1143 } 1144 1145 class MovingState extends State { 1146 boolean mWifiChangeDetected = false; 1147 1148 @Override 1149 public void enter() { 1150 if (DBG) Log.d(TAG, "Entering MovingState"); 1151 WifiScanner.ScanSettings settings = new WifiScanner.ScanSettings(); 1152 settings.band = WifiScanner.WIFI_BAND_UNSPECIFIED; 1153 /* TODO: Currently no driver allows scanning with band; hence this workaround */ 1154 settings.channels = getChannelsForBand(WifiScanner.WIFI_BAND_24_GHZ); 1155 settings.periodInMs = MOVING_SCAN_PERIOD_MS; 1156 settings.reportEvents = WifiScanner.REPORT_EVENT_AFTER_EACH_SCAN; 1157 addScanRequest(settings); 1158 } 1159 1160 @Override 1161 public boolean processMessage(Message msg) { 1162 if (DBG) Log.d(TAG, "MovingState state got " + msg); 1163 switch (msg.what) { 1164 case WIFI_CHANGE_CMD_ENABLE : 1165 // do nothing 1166 break; 1167 case WIFI_CHANGE_CMD_DISABLE: 1168 mCurrentHotspots = null; 1169 removeScanRequest(); 1170 untrackSignificantWifiChange(); 1171 transitionTo(mDefaultState); 1172 break; 1173 case WIFI_CHANGE_CMD_NEW_SCAN_RESULTS: 1174 if (DBG) Log.d(TAG, "Got scan results"); 1175 reconfigureScan((ScanResult[])msg.obj, STATIONARY_SCAN_PERIOD_MS); 1176 mWifiChangeDetected = false; 1177 mAlarmManager.setExact(AlarmManager.RTC_WAKEUP, 1178 System.currentTimeMillis() + MOVING_STATE_TIMEOUT_MS, 1179 mTimeoutIntent); 1180 break; 1181 case WIFI_CHANGE_CMD_CONFIGURE: 1182 if (DBG) Log.d(TAG, "Got configuration from app"); 1183 reconfigureScan((WifiScanner.WifiChangeSettings) msg.obj); 1184 mWifiChangeDetected = false; 1185 mAlarmManager.setExact(AlarmManager.RTC_WAKEUP, 1186 System.currentTimeMillis() + MOVING_STATE_TIMEOUT_MS, 1187 mTimeoutIntent); 1188 break; 1189 case WIFI_CHANGE_CMD_CHANGE_DETECTED: 1190 mAlarmManager.cancel(mTimeoutIntent); 1191 reportWifiChanged((ScanResult[])msg.obj); 1192 mWifiChangeDetected = true; 1193 break; 1194 case WIFI_CHANGE_CMD_CHANGE_TIMEOUT: 1195 if (DBG) Log.d(TAG, "Got timeout event"); 1196 if (mWifiChangeDetected == false) { 1197 transitionTo(mStationaryState); 1198 } 1199 break; 1200 default: 1201 return NOT_HANDLED; 1202 } 1203 return HANDLED; 1204 } 1205 1206 @Override 1207 public void exit() { 1208 mAlarmManager.cancel(mTimeoutIntent); 1209 } 1210 } 1211 1212 void reconfigureScan(ScanResult[] results, int period) { 1213 // find brightest APs and set them as sentinels 1214 if (results.length < MAX_APS_TO_TRACK) { 1215 Log.d(TAG, "too few APs (" + results.length + ") available to track wifi change"); 1216 return; 1217 } 1218 1219 removeScanRequest(); 1220 1221 // remove duplicate BSSIDs 1222 HashMap<String, ScanResult> bssidToScanResult = new HashMap<String, ScanResult>(); 1223 for (ScanResult result : results) { 1224 ScanResult saved = bssidToScanResult.get(result.BSSID); 1225 if (saved == null) { 1226 bssidToScanResult.put(result.BSSID, result); 1227 } else if (saved.level > result.level) { 1228 bssidToScanResult.put(result.BSSID, result); 1229 } 1230 } 1231 1232 // find brightest BSSIDs 1233 ScanResult brightest[] = new ScanResult[MAX_APS_TO_TRACK]; 1234 Collection<ScanResult> results2 = bssidToScanResult.values(); 1235 for (ScanResult result : results2) { 1236 for (int j = 0; j < brightest.length; j++) { 1237 if (brightest[j] == null 1238 || (brightest[j].level < result.level)) { 1239 for (int k = brightest.length; k > (j + 1); k--) { 1240 brightest[k - 1] = brightest[k - 2]; 1241 } 1242 brightest[j] = result; 1243 break; 1244 } 1245 } 1246 } 1247 1248 // Get channels to scan for 1249 ArrayList<Integer> channels = new ArrayList<Integer>(); 1250 for (int i = 0; i < brightest.length; i++) { 1251 boolean found = false; 1252 for (int j = i + 1; j < brightest.length; j++) { 1253 if (brightest[j].frequency == brightest[i].frequency) { 1254 found = true; 1255 } 1256 } 1257 if (!found) { 1258 channels.add(brightest[i].frequency); 1259 } 1260 } 1261 1262 if (DBG) Log.d(TAG, "Found " + channels.size() + " channels"); 1263 1264 // set scanning schedule 1265 WifiScanner.ScanSettings settings = new WifiScanner.ScanSettings(); 1266 settings.band = WifiScanner.WIFI_BAND_UNSPECIFIED; 1267 settings.channels = new WifiScanner.ChannelSpec[channels.size()]; 1268 for (int i = 0; i < channels.size(); i++) { 1269 settings.channels[i] = new WifiScanner.ChannelSpec(channels.get(i)); 1270 } 1271 1272 settings.periodInMs = period; 1273 addScanRequest(settings); 1274 1275 WifiScanner.WifiChangeSettings settings2 = new WifiScanner.WifiChangeSettings(); 1276 settings2.rssiSampleSize = 3; 1277 settings2.lostApSampleSize = 3; 1278 settings2.unchangedSampleSize = 3; 1279 settings2.minApsBreachingThreshold = 3; 1280 settings2.hotspotInfos = new WifiScanner.HotspotInfo[brightest.length]; 1281 1282 for (int i = 0; i < brightest.length; i++) { 1283 WifiScanner.HotspotInfo hotspotInfo = new WifiScanner.HotspotInfo(); 1284 hotspotInfo.bssid = brightest[i].BSSID; 1285 int threshold = (100 + brightest[i].level) / 32 + 2; 1286 hotspotInfo.low = brightest[i].level - threshold; 1287 hotspotInfo.high = brightest[i].level + threshold; 1288 settings2.hotspotInfos[i] = hotspotInfo; 1289 1290 if (DBG) Log.d(TAG, "Setting bssid=" + hotspotInfo.bssid + ", " + 1291 "low=" + hotspotInfo.low + ", high=" + hotspotInfo.high); 1292 } 1293 1294 trackSignificantWifiChange(settings2); 1295 mCurrentHotspots = brightest; 1296 } 1297 1298 void reconfigureScan(WifiScanner.WifiChangeSettings settings) { 1299 1300 if (settings.hotspotInfos.length < MAX_APS_TO_TRACK) { 1301 Log.d(TAG, "too few APs (" + settings.hotspotInfos.length 1302 + ") available to track wifi change"); 1303 return; 1304 } 1305 1306 if (DBG) Log.d(TAG, "Setting configuration specified by app"); 1307 1308 mCurrentHotspots = new ScanResult[settings.hotspotInfos.length]; 1309 HashSet<Integer> channels = new HashSet<Integer>(); 1310 1311 for (int i = 0; i < settings.hotspotInfos.length; i++) { 1312 ScanResult result = new ScanResult(); 1313 result.BSSID = settings.hotspotInfos[i].bssid; 1314 mCurrentHotspots[i] = result; 1315 channels.add(settings.hotspotInfos[i].frequencyHint); 1316 } 1317 1318 // cancel previous scan 1319 removeScanRequest(); 1320 1321 // set new scanning schedule 1322 WifiScanner.ScanSettings settings2 = new WifiScanner.ScanSettings(); 1323 settings2.band = WifiScanner.WIFI_BAND_UNSPECIFIED; 1324 settings2.channels = new WifiScanner.ChannelSpec[channels.size()]; 1325 int i = 0; 1326 for (Integer channel : channels) { 1327 settings2.channels[i++] = new WifiScanner.ChannelSpec(channel); 1328 } 1329 1330 settings2.periodInMs = settings.periodInMs; 1331 addScanRequest(settings2); 1332 1333 // start tracking new APs 1334 trackSignificantWifiChange(settings); 1335 } 1336 1337 class ClientInfoLocal extends ClientInfo { 1338 ClientInfoLocal() { 1339 super(null, null); 1340 } 1341 @Override 1342 void deliverScanResults(int handler, ScanResult results[]) { 1343 if (DBG) Log.d(TAG, "Delivering messages directly"); 1344 sendMessage(WIFI_CHANGE_CMD_NEW_SCAN_RESULTS, 0, 0, results); 1345 } 1346 @Override 1347 void reportPeriodChanged(int handler, ScanSettings settings, int newPeriodInMs) { 1348 // nothing to do; no one is listening for this 1349 } 1350 } 1351 1352 @Override 1353 public void onChangesFound(ScanResult results[]) { 1354 sendMessage(WIFI_CHANGE_CMD_CHANGE_DETECTED, 0, 0, results); 1355 } 1356 1357 ClientInfo mClientInfo = new ClientInfoLocal(); 1358 private static final int SCAN_COMMAND_ID = 1; 1359 1360 void addScanRequest(WifiScanner.ScanSettings settings) { 1361 if (DBG) Log.d(TAG, "Starting scans"); 1362 Message msg = Message.obtain(); 1363 msg.what = WifiScanner.CMD_START_BACKGROUND_SCAN; 1364 msg.arg2 = SCAN_COMMAND_ID; 1365 msg.obj = settings; 1366 mClientHandler.sendMessage(msg); 1367 } 1368 1369 void removeScanRequest() { 1370 if (DBG) Log.d(TAG, "Stopping scans"); 1371 Message msg = Message.obtain(); 1372 msg.what = WifiScanner.CMD_STOP_BACKGROUND_SCAN; 1373 msg.arg2 = SCAN_COMMAND_ID; 1374 mClientHandler.sendMessage(msg); 1375 } 1376 1377 void trackSignificantWifiChange(WifiScanner.WifiChangeSettings settings) { 1378 WifiNative.trackSignificantWifiChange(settings, this); 1379 } 1380 1381 void untrackSignificantWifiChange() { 1382 WifiNative.untrackSignificantWifiChange(); 1383 } 1384 1385 } 1386 1387 private static WifiScanner.ChannelSpec[] getChannelsForBand(int band) { 1388 1389 /* TODO: We need to query this from the chip */ 1390 1391 if (band == WifiScanner.WIFI_BAND_24_GHZ) { 1392 return new WifiScanner.ChannelSpec[] { 1393 new WifiScanner.ChannelSpec(2412), 1394 new WifiScanner.ChannelSpec(2437), 1395 new WifiScanner.ChannelSpec(2462) 1396 }; 1397 } else if (band == WifiScanner.WIFI_BAND_5_GHZ 1398 || band == WifiScanner.WIFI_BAND_5_GHZ_WITH_DFS) { 1399 return new WifiScanner.ChannelSpec[] { 1400 new WifiScanner.ChannelSpec(5180), 1401 new WifiScanner.ChannelSpec(5200), 1402 new WifiScanner.ChannelSpec(5220), 1403 new WifiScanner.ChannelSpec(5745), 1404 new WifiScanner.ChannelSpec(5765), 1405 new WifiScanner.ChannelSpec(5785), 1406 new WifiScanner.ChannelSpec(5805), 1407 new WifiScanner.ChannelSpec(5825) 1408 }; 1409 } else if (band == WifiScanner.WIFI_BAND_BOTH 1410 || band == WifiScanner.WIFI_BAND_BOTH_WITH_DFS) { 1411 return new WifiScanner.ChannelSpec[] { 1412 new WifiScanner.ChannelSpec(2412), 1413 new WifiScanner.ChannelSpec(2437), 1414 new WifiScanner.ChannelSpec(2462), 1415 new WifiScanner.ChannelSpec(5180), 1416 new WifiScanner.ChannelSpec(5200), 1417 new WifiScanner.ChannelSpec(5220), 1418 new WifiScanner.ChannelSpec(5745), 1419 new WifiScanner.ChannelSpec(5765), 1420 new WifiScanner.ChannelSpec(5785), 1421 new WifiScanner.ChannelSpec(5805), 1422 new WifiScanner.ChannelSpec(5825) 1423 }; 1424 } else { 1425 return null; 1426 } 1427 } 1428 1429 private static int getBandFromChannels(WifiScanner.ChannelSpec[] channels) { 1430 int band = WifiScanner.WIFI_BAND_UNSPECIFIED; 1431 for (WifiScanner.ChannelSpec channel : channels) { 1432 if (2400 <= channel.frequency && channel.frequency < 2500) { 1433 band |= WifiScanner.WIFI_BAND_24_GHZ; 1434 } else if (5100 <= channel.frequency && channel.frequency < 6000) { 1435 band |= WifiScanner.WIFI_BAND_5_GHZ; 1436 } else { 1437 /* TODO: Add DFS Range */ 1438 } 1439 } 1440 return band; 1441 } 1442 private static int getBandFromChannels(WifiNative.ChannelSettings[] channels) { 1443 int band = WifiScanner.WIFI_BAND_UNSPECIFIED; 1444 for (WifiNative.ChannelSettings channel : channels) { 1445 if (2400 <= channel.frequency && channel.frequency < 2500) { 1446 band |= WifiScanner.WIFI_BAND_24_GHZ; 1447 } else if (5100 <= channel.frequency && channel.frequency < 6000) { 1448 band |= WifiScanner.WIFI_BAND_5_GHZ; 1449 } else { 1450 /* TODO: Add DFS Range */ 1451 } 1452 } 1453 return band; 1454 } 1455 1456} 1457