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