blob: 66dc992d6dc7aa4d6aaca160fde9373f57e123d5 [file] [log] [blame]
Vinit Deshapnde011e1b32014-05-07 21:09:11 -07001/*
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 android.net.wifi;
18
Roshan Pius5ac66162018-04-25 14:29:51 -070019import android.Manifest;
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -060020import android.annotation.RequiresPermission;
21import android.annotation.SuppressLint;
Wei Wang35d552f2014-07-08 21:37:01 -070022import android.annotation.SystemApi;
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -060023import android.annotation.SystemService;
Vinit Deshapnde011e1b32014-05-07 21:09:11 -070024import android.content.Context;
Vinit Deshpande15f89072014-09-05 20:43:57 -070025import android.os.Bundle;
Vinit Deshapnde011e1b32014-05-07 21:09:11 -070026import android.os.Handler;
Vinit Deshapnde011e1b32014-05-07 21:09:11 -070027import android.os.Looper;
28import android.os.Message;
29import android.os.Messenger;
30import android.os.Parcel;
31import android.os.Parcelable;
32import android.os.RemoteException;
Mitchell Willsd24427f2016-03-29 13:34:45 -070033import android.os.WorkSource;
Vinit Deshapnde011e1b32014-05-07 21:09:11 -070034import android.util.Log;
35import android.util.SparseArray;
36
37import com.android.internal.util.AsyncChannel;
Wei Wang3cf4da92016-02-16 23:38:41 -080038import com.android.internal.util.Preconditions;
Vinit Deshapnde011e1b32014-05-07 21:09:11 -070039import com.android.internal.util.Protocol;
40
Rebecca Silbersteinbfc76e02016-09-14 22:07:04 -070041import java.util.ArrayList;
42import java.util.Arrays;
Vinit Deshapnde011e1b32014-05-07 21:09:11 -070043import java.util.List;
Vinit Deshapnde011e1b32014-05-07 21:09:11 -070044
Vinit Deshapnde011e1b32014-05-07 21:09:11 -070045/**
46 * This class provides a way to scan the Wifi universe around the device
Vinit Deshpande55027bb2014-05-29 15:58:48 -070047 * @hide
Vinit Deshapnde011e1b32014-05-07 21:09:11 -070048 */
Wei Wang35d552f2014-07-08 21:37:01 -070049@SystemApi
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -060050@SystemService(Context.WIFI_SCANNING_SERVICE)
Vinit Deshapnde011e1b32014-05-07 21:09:11 -070051public class WifiScanner {
52
Vinit Deshapnde1ab9cc82014-05-09 19:13:56 -070053 /** no band specified; use channel list instead */
Vinit Deshapnde011e1b32014-05-07 21:09:11 -070054 public static final int WIFI_BAND_UNSPECIFIED = 0; /* not specified */
Vinit Deshapnde1ab9cc82014-05-09 19:13:56 -070055
56 /** 2.4 GHz band */
Vinit Deshapnde011e1b32014-05-07 21:09:11 -070057 public static final int WIFI_BAND_24_GHZ = 1; /* 2.4 GHz band */
Vinit Deshapnde1ab9cc82014-05-09 19:13:56 -070058 /** 5 GHz band excluding DFS channels */
Vinit Deshapnde011e1b32014-05-07 21:09:11 -070059 public static final int WIFI_BAND_5_GHZ = 2; /* 5 GHz band without DFS channels */
Vinit Deshapnde1ab9cc82014-05-09 19:13:56 -070060 /** DFS channels from 5 GHz band only */
Vinit Deshapnde011e1b32014-05-07 21:09:11 -070061 public static final int WIFI_BAND_5_GHZ_DFS_ONLY = 4; /* 5 GHz band with DFS channels */
Vinit Deshapnde1ab9cc82014-05-09 19:13:56 -070062 /** 5 GHz band including DFS channels */
Vinit Deshapnde011e1b32014-05-07 21:09:11 -070063 public static final int WIFI_BAND_5_GHZ_WITH_DFS = 6; /* 5 GHz band with DFS channels */
Vinit Deshapnde1ab9cc82014-05-09 19:13:56 -070064 /** Both 2.4 GHz band and 5 GHz band; no DFS channels */
Vinit Deshapnde011e1b32014-05-07 21:09:11 -070065 public static final int WIFI_BAND_BOTH = 3; /* both bands without DFS channels */
Vinit Deshapnde1ab9cc82014-05-09 19:13:56 -070066 /** Both 2.4 GHz band and 5 GHz band; with DFS channels */
Vinit Deshapnde011e1b32014-05-07 21:09:11 -070067 public static final int WIFI_BAND_BOTH_WITH_DFS = 7; /* both bands with DFS channels */
68
Vinit Deshapnde1ab9cc82014-05-09 19:13:56 -070069 /** Minimum supported scanning period */
Vinit Deshpande19024b62014-06-26 18:29:37 -070070 public static final int MIN_SCAN_PERIOD_MS = 1000; /* minimum supported period */
Vinit Deshapnde1ab9cc82014-05-09 19:13:56 -070071 /** Maximum supported scanning period */
Vinit Deshapnde011e1b32014-05-07 21:09:11 -070072 public static final int MAX_SCAN_PERIOD_MS = 1024000; /* maximum supported period */
73
Vinit Deshapnde1ab9cc82014-05-09 19:13:56 -070074 /** No Error */
Vinit Deshapnde011e1b32014-05-07 21:09:11 -070075 public static final int REASON_SUCCEEDED = 0;
Vinit Deshapnde1ab9cc82014-05-09 19:13:56 -070076 /** Unknown error */
Vinit Deshapnde011e1b32014-05-07 21:09:11 -070077 public static final int REASON_UNSPECIFIED = -1;
Vinit Deshapnde1ab9cc82014-05-09 19:13:56 -070078 /** Invalid listener */
Vinit Deshapnde011e1b32014-05-07 21:09:11 -070079 public static final int REASON_INVALID_LISTENER = -2;
Vinit Deshapnde1ab9cc82014-05-09 19:13:56 -070080 /** Invalid request */
Vinit Deshapnde011e1b32014-05-07 21:09:11 -070081 public static final int REASON_INVALID_REQUEST = -3;
Vinit Deshpande4b997562014-09-08 18:03:12 -070082 /** Invalid request */
83 public static final int REASON_NOT_AUTHORIZED = -4;
Wei Wang3cf4da92016-02-16 23:38:41 -080084 /** An outstanding request with the same listener hasn't finished yet. */
85 public static final int REASON_DUPLICATE_REQEUST = -5;
Vinit Deshapnde011e1b32014-05-07 21:09:11 -070086
Vinit Deshpande15f89072014-09-05 20:43:57 -070087 /** @hide */
88 public static final String GET_AVAILABLE_CHANNELS_EXTRA = "Channels";
89
Vinit Deshapnde1ab9cc82014-05-09 19:13:56 -070090 /**
91 * Generic action callback invocation interface
92 * @hide
93 */
Wei Wang35d552f2014-07-08 21:37:01 -070094 @SystemApi
Vinit Deshapnde011e1b32014-05-07 21:09:11 -070095 public static interface ActionListener {
Vinit Deshpande55027bb2014-05-29 15:58:48 -070096 public void onSuccess();
97 public void onFailure(int reason, String description);
Vinit Deshapnde011e1b32014-05-07 21:09:11 -070098 }
99
100 /**
101 * gives you all the possible channels; channel is specified as an
102 * integer with frequency in MHz i.e. channel 1 is 2412
Vinit Deshapnde1ab9cc82014-05-09 19:13:56 -0700103 * @hide
Vinit Deshapnde011e1b32014-05-07 21:09:11 -0700104 */
105 public List<Integer> getAvailableChannels(int band) {
Vinit Deshpande15f89072014-09-05 20:43:57 -0700106 try {
107 Bundle bundle = mService.getAvailableChannels(band);
108 return bundle.getIntegerArrayList(GET_AVAILABLE_CHANNELS_EXTRA);
109 } catch (RemoteException e) {
110 return null;
111 }
Vinit Deshapnde011e1b32014-05-07 21:09:11 -0700112 }
113
114 /**
Vinit Deshapnde1ab9cc82014-05-09 19:13:56 -0700115 * provides channel specification for scanning
Vinit Deshapnde011e1b32014-05-07 21:09:11 -0700116 */
117 public static class ChannelSpec {
Vinit Deshapnde1ab9cc82014-05-09 19:13:56 -0700118 /**
Vinit Deshpandedb0c15d2014-08-07 16:17:36 -0700119 * channel frequency in MHz; for example channel 1 is specified as 2412
Vinit Deshapnde1ab9cc82014-05-09 19:13:56 -0700120 */
Vinit Deshapnde011e1b32014-05-07 21:09:11 -0700121 public int frequency;
Vinit Deshapnde1ab9cc82014-05-09 19:13:56 -0700122 /**
123 * if true, scan this channel in passive fashion.
124 * This flag is ignored on DFS channel specification.
125 * @hide
126 */
Vinit Deshapnde011e1b32014-05-07 21:09:11 -0700127 public boolean passive; /* ignored on DFS channels */
Vinit Deshapnde1ab9cc82014-05-09 19:13:56 -0700128 /**
129 * how long to dwell on this channel
130 * @hide
131 */
Vinit Deshapnde011e1b32014-05-07 21:09:11 -0700132 public int dwellTimeMS; /* not supported for now */
133
Vinit Deshapnde1ab9cc82014-05-09 19:13:56 -0700134 /**
135 * default constructor for channel spec
136 */
Vinit Deshapnde011e1b32014-05-07 21:09:11 -0700137 public ChannelSpec(int frequency) {
138 this.frequency = frequency;
139 passive = false;
140 dwellTimeMS = 0;
141 }
142 }
143
Mitchell Willsc90855d2015-12-18 15:36:48 -0800144 /**
145 * reports {@link ScanListener#onResults} when underlying buffers are full
146 * this is simply the lack of the {@link #REPORT_EVENT_AFTER_EACH_SCAN} flag
Gina Dimino98ad8882016-05-31 17:25:48 -0700147 * @deprecated It is not supported anymore.
Soonil Nagarkar597492c2015-05-27 11:23:37 -0700148 */
149 @Deprecated
Vinit Deshapnde011e1b32014-05-07 21:09:11 -0700150 public static final int REPORT_EVENT_AFTER_BUFFER_FULL = 0;
Mitchell Willsc90855d2015-12-18 15:36:48 -0800151 /**
152 * reports {@link ScanListener#onResults} after each scan
153 */
154 public static final int REPORT_EVENT_AFTER_EACH_SCAN = (1 << 0);
155 /**
156 * reports {@link ScanListener#onFullResult} whenever each beacon is discovered
157 */
158 public static final int REPORT_EVENT_FULL_SCAN_RESULT = (1 << 1);
159 /**
160 * Do not place scans in the chip's scan history buffer
161 */
162 public static final int REPORT_EVENT_NO_BATCH = (1 << 2);
Vinit Deshapnde011e1b32014-05-07 21:09:11 -0700163
Roshan Pius00bbf342017-10-27 13:00:08 -0700164 /**
165 * This is used to indicate the purpose of the scan to the wifi chip in
166 * {@link ScanSettings#type}.
167 * On devices with multiple hardware radio chains (and hence different modes of scan),
168 * this type serves as an indication to the hardware on what mode of scan to perform.
169 * Only apps holding android.Manifest.permission.NETWORK_STACK permission can set this value.
170 *
171 * Note: This serves as an intent and not as a stipulation, the wifi chip
172 * might honor or ignore the indication based on the current radio conditions. Always
173 * use the {@link ScanResult#radioChainInfos} to figure out the radio chain configuration used
174 * to receive the corresponding scan result.
175 */
176 /** {@hide} */
177 public static final int TYPE_LOW_LATENCY = 0;
178 /** {@hide} */
179 public static final int TYPE_LOW_POWER = 1;
180 /** {@hide} */
181 public static final int TYPE_HIGH_ACCURACY = 2;
Mitchell Willsad95b6a2016-03-29 14:56:38 -0700182
183 /** {@hide} */
184 public static final String SCAN_PARAMS_SCAN_SETTINGS_KEY = "ScanSettings";
185 /** {@hide} */
186 public static final String SCAN_PARAMS_WORK_SOURCE_KEY = "WorkSource";
Roshan Pius7e757ea2018-11-21 11:37:44 -0800187 /** {@hide} */
188 public static final String REQUEST_PACKAGE_NAME_KEY = "PackageName";
189
Vinit Deshapnde011e1b32014-05-07 21:09:11 -0700190 /**
Vinit Deshapnde1ab9cc82014-05-09 19:13:56 -0700191 * scan configuration parameters to be sent to {@link #startBackgroundScan}
Vinit Deshapnde011e1b32014-05-07 21:09:11 -0700192 */
193 public static class ScanSettings implements Parcelable {
Roshan Pius8da6bdc2016-09-12 13:46:32 -0700194 /**
195 * Hidden network to be scanned for.
196 * {@hide}
197 */
198 public static class HiddenNetwork {
199 /** SSID of the network */
200 public String ssid;
201
202 /**
203 * Default constructor for HiddenNetwork.
204 */
205 public HiddenNetwork(String ssid) {
206 this.ssid = ssid;
207 }
208 }
Vinit Deshapnde011e1b32014-05-07 21:09:11 -0700209
Vinit Deshapnde1ab9cc82014-05-09 19:13:56 -0700210 /** one of the WIFI_BAND values */
211 public int band;
212 /** list of channels; used when band is set to WIFI_BAND_UNSPECIFIED */
213 public ChannelSpec[] channels;
Roshan Pius49b6f192016-03-04 17:33:17 -0800214 /**
Roshan Pius8da6bdc2016-09-12 13:46:32 -0700215 * list of hidden networks to scan for. Explicit probe requests are sent out for such
216 * networks during scan. Only valid for single scan requests.
Roshan Pius49b6f192016-03-04 17:33:17 -0800217 * {@hide}
Roshan Pius00bbf342017-10-27 13:00:08 -0700218 */
219 @RequiresPermission(android.Manifest.permission.NETWORK_STACK)
Roshan Pius8da6bdc2016-09-12 13:46:32 -0700220 public HiddenNetwork[] hiddenNetworks;
Vinit Deshpande19024b62014-06-26 18:29:37 -0700221 /** period of background scan; in millisecond, 0 => single shot scan */
Vinit Deshapnde1ab9cc82014-05-09 19:13:56 -0700222 public int periodInMs;
223 /** must have a valid REPORT_EVENT value */
224 public int reportEvents;
Vinit Deshpandeea676a02014-07-29 15:52:20 -0700225 /** defines number of bssids to cache from each scan */
226 public int numBssidsPerScan;
Vinit Deshpandef45acfe2014-10-30 11:01:25 -0700227 /**
228 * defines number of scans to cache; use it with REPORT_EVENT_AFTER_BUFFER_FULL
229 * to wake up at fixed interval
230 */
231 public int maxScansToCache;
Mitchell Wills075698c2015-11-16 14:23:59 -0800232 /**
233 * if maxPeriodInMs is non zero or different than period, then this bucket is
Randy Pan8c79fe52015-12-17 13:07:07 -0800234 * a truncated binary exponential backoff bucket and the scan period will grow
235 * exponentially as per formula: actual_period(N) = period * (2 ^ (N/stepCount))
236 * to maxPeriodInMs
Mitchell Wills075698c2015-11-16 14:23:59 -0800237 */
238 public int maxPeriodInMs;
239 /**
Randy Pan8c79fe52015-12-17 13:07:07 -0800240 * for truncated binary exponential back off bucket, number of scans to perform
241 * for a given period
Mitchell Wills075698c2015-11-16 14:23:59 -0800242 */
243 public int stepCount;
Roshan Piuse4fd1502016-03-01 13:18:41 -0800244 /**
245 * Flag to indicate if the scan settings are targeted for PNO scan.
246 * {@hide}
247 */
248 public boolean isPnoScan;
Roshan Pius00bbf342017-10-27 13:00:08 -0700249 /**
250 * Indicate the type of scan to be performed by the wifi chip.
251 * Default value: {@link #TYPE_LOW_LATENCY}.
252 * {@hide}
253 */
254 @RequiresPermission(android.Manifest.permission.NETWORK_STACK)
255 public int type = TYPE_LOW_LATENCY;
Soonil Nagarkar1e59a5f2018-11-16 09:26:48 -0800256 /**
257 * This scan request may ignore location settings while receiving scans. This should only
258 * be used in emergency situations.
259 * {@hide}
260 */
261 @SystemApi
Soonil Nagarkar1e59a5f2018-11-16 09:26:48 -0800262 public boolean ignoreLocationSettings;
Roshan Piusfc900aa2019-02-19 13:37:35 -0800263 /**
264 * This scan request will be hidden from app-ops noting for location information. This
265 * should only be used by FLP/NLP module on the device which is using the scan results to
266 * compute results for behalf on their clients. FLP/NLP module using this flag should ensure
267 * that they note in app-ops the eventual delivery of location information computed using
268 * these results to their client .
269 * {@hide}
270 */
271 @SystemApi
272 public boolean hideFromAppOps;
Vinit Deshapnde011e1b32014-05-07 21:09:11 -0700273
274 /** Implement the Parcelable interface {@hide} */
275 public int describeContents() {
276 return 0;
277 }
278
279 /** Implement the Parcelable interface {@hide} */
280 public void writeToParcel(Parcel dest, int flags) {
281 dest.writeInt(band);
282 dest.writeInt(periodInMs);
Vinit Deshapnde8ca03392014-05-13 15:36:48 -0700283 dest.writeInt(reportEvents);
Vinit Deshpandedb0c15d2014-08-07 16:17:36 -0700284 dest.writeInt(numBssidsPerScan);
Vinit Deshpandef45acfe2014-10-30 11:01:25 -0700285 dest.writeInt(maxScansToCache);
Mitchell Wills075698c2015-11-16 14:23:59 -0800286 dest.writeInt(maxPeriodInMs);
Mitchell Wills075698c2015-11-16 14:23:59 -0800287 dest.writeInt(stepCount);
Roshan Piuse4fd1502016-03-01 13:18:41 -0800288 dest.writeInt(isPnoScan ? 1 : 0);
Roshan Pius00bbf342017-10-27 13:00:08 -0700289 dest.writeInt(type);
Soonil Nagarkar1e59a5f2018-11-16 09:26:48 -0800290 dest.writeInt(ignoreLocationSettings ? 1 : 0);
Roshan Piusfc900aa2019-02-19 13:37:35 -0800291 dest.writeInt(hideFromAppOps ? 1 : 0);
Vinit Deshpandedaf215c2014-06-09 15:39:22 -0700292 if (channels != null) {
293 dest.writeInt(channels.length);
Vinit Deshpandedaf215c2014-06-09 15:39:22 -0700294 for (int i = 0; i < channels.length; i++) {
295 dest.writeInt(channels[i].frequency);
296 dest.writeInt(channels[i].dwellTimeMS);
297 dest.writeInt(channels[i].passive ? 1 : 0);
298 }
299 } else {
300 dest.writeInt(0);
Vinit Deshapnde011e1b32014-05-07 21:09:11 -0700301 }
Roshan Pius8da6bdc2016-09-12 13:46:32 -0700302 if (hiddenNetworks != null) {
303 dest.writeInt(hiddenNetworks.length);
304 for (int i = 0; i < hiddenNetworks.length; i++) {
305 dest.writeString(hiddenNetworks[i].ssid);
306 }
307 } else {
308 dest.writeInt(0);
309 }
Vinit Deshapnde011e1b32014-05-07 21:09:11 -0700310 }
311
312 /** Implement the Parcelable interface {@hide} */
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -0700313 public static final @android.annotation.NonNull Creator<ScanSettings> CREATOR =
Vinit Deshapnde011e1b32014-05-07 21:09:11 -0700314 new Creator<ScanSettings>() {
315 public ScanSettings createFromParcel(Parcel in) {
Vinit Deshapnde011e1b32014-05-07 21:09:11 -0700316 ScanSettings settings = new ScanSettings();
317 settings.band = in.readInt();
318 settings.periodInMs = in.readInt();
Vinit Deshapnde8ca03392014-05-13 15:36:48 -0700319 settings.reportEvents = in.readInt();
Vinit Deshpandedb0c15d2014-08-07 16:17:36 -0700320 settings.numBssidsPerScan = in.readInt();
Vinit Deshpandef45acfe2014-10-30 11:01:25 -0700321 settings.maxScansToCache = in.readInt();
Mitchell Wills075698c2015-11-16 14:23:59 -0800322 settings.maxPeriodInMs = in.readInt();
Mitchell Wills075698c2015-11-16 14:23:59 -0800323 settings.stepCount = in.readInt();
Roshan Piuse4fd1502016-03-01 13:18:41 -0800324 settings.isPnoScan = in.readInt() == 1;
Roshan Pius00bbf342017-10-27 13:00:08 -0700325 settings.type = in.readInt();
Soonil Nagarkar1e59a5f2018-11-16 09:26:48 -0800326 settings.ignoreLocationSettings = in.readInt() == 1;
Roshan Piusfc900aa2019-02-19 13:37:35 -0800327 settings.hideFromAppOps = in.readInt() == 1;
Vinit Deshapnde011e1b32014-05-07 21:09:11 -0700328 int num_channels = in.readInt();
329 settings.channels = new ChannelSpec[num_channels];
330 for (int i = 0; i < num_channels; i++) {
331 int frequency = in.readInt();
Vinit Deshapnde011e1b32014-05-07 21:09:11 -0700332 ChannelSpec spec = new ChannelSpec(frequency);
333 spec.dwellTimeMS = in.readInt();
334 spec.passive = in.readInt() == 1;
335 settings.channels[i] = spec;
336 }
Roshan Pius8da6bdc2016-09-12 13:46:32 -0700337 int numNetworks = in.readInt();
338 settings.hiddenNetworks = new HiddenNetwork[numNetworks];
339 for (int i = 0; i < numNetworks; i++) {
340 String ssid = in.readString();
341 settings.hiddenNetworks[i] = new HiddenNetwork(ssid);;
342 }
Vinit Deshapnde011e1b32014-05-07 21:09:11 -0700343 return settings;
344 }
345
346 public ScanSettings[] newArray(int size) {
347 return new ScanSettings[size];
348 }
349 };
350
351 }
352
Vinit Deshpandef45acfe2014-10-30 11:01:25 -0700353 /**
354 * all the information garnered from a single scan
355 */
356 public static class ScanData implements Parcelable {
357 /** scan identifier */
358 private int mId;
359 /** additional information about scan
360 * 0 => no special issues encountered in the scan
361 * non-zero => scan was truncated, so results may not be complete
362 */
363 private int mFlags;
Mitchell Wills0d193b42016-03-22 15:56:17 -0700364 /**
365 * Indicates the buckets that were scanned to generate these results.
366 * This is not relevant to WifiScanner API users and is used internally.
367 * {@hide}
368 */
369 private int mBucketsScanned;
Mitchell Wills9bc78e82016-09-06 15:08:36 -0700370 /**
Roshan Pius5a600f52018-11-14 10:43:15 -0800371 * Bands scanned. One of the WIFI_BAND values.
372 * Will be {@link #WIFI_BAND_UNSPECIFIED} if the list of channels do not fully cover
373 * any of the bands.
Mitchell Wills9bc78e82016-09-06 15:08:36 -0700374 * {@hide}
375 */
Roshan Pius5a600f52018-11-14 10:43:15 -0800376 private int mBandScanned;
Vinit Deshpandef45acfe2014-10-30 11:01:25 -0700377 /** all scan results discovered in this scan, sorted by timestamp in ascending order */
378 private ScanResult mResults[];
379
380 ScanData() {}
381
382 public ScanData(int id, int flags, ScanResult[] results) {
383 mId = id;
384 mFlags = flags;
385 mResults = results;
386 }
387
Mitchell Wills0d193b42016-03-22 15:56:17 -0700388 /** {@hide} */
Roshan Pius5a600f52018-11-14 10:43:15 -0800389 public ScanData(int id, int flags, int bucketsScanned, int bandScanned,
390 ScanResult[] results) {
Mitchell Wills0d193b42016-03-22 15:56:17 -0700391 mId = id;
392 mFlags = flags;
393 mBucketsScanned = bucketsScanned;
Roshan Pius5a600f52018-11-14 10:43:15 -0800394 mBandScanned = bandScanned;
Mitchell Wills0d193b42016-03-22 15:56:17 -0700395 mResults = results;
396 }
397
Vinit Deshpandef45acfe2014-10-30 11:01:25 -0700398 public ScanData(ScanData s) {
399 mId = s.mId;
400 mFlags = s.mFlags;
Mitchell Wills0d193b42016-03-22 15:56:17 -0700401 mBucketsScanned = s.mBucketsScanned;
Roshan Pius5a600f52018-11-14 10:43:15 -0800402 mBandScanned = s.mBandScanned;
Vinit Deshpandef45acfe2014-10-30 11:01:25 -0700403 mResults = new ScanResult[s.mResults.length];
404 for (int i = 0; i < s.mResults.length; i++) {
405 ScanResult result = s.mResults[i];
xinhe6e584242015-03-02 14:04:35 -0800406 ScanResult newResult = new ScanResult(result);
Vinit Deshpandef45acfe2014-10-30 11:01:25 -0700407 mResults[i] = newResult;
408 }
409 }
410
411 public int getId() {
412 return mId;
413 }
414
415 public int getFlags() {
416 return mFlags;
417 }
418
Mitchell Willsd1f33cc2016-03-25 17:56:26 -0700419 /** {@hide} */
420 public int getBucketsScanned() {
421 return mBucketsScanned;
422 }
423
Mitchell Wills9bc78e82016-09-06 15:08:36 -0700424 /** {@hide} */
Roshan Pius5a600f52018-11-14 10:43:15 -0800425 public int getBandScanned() {
426 return mBandScanned;
Mitchell Wills9bc78e82016-09-06 15:08:36 -0700427 }
428
Vinit Deshpandef45acfe2014-10-30 11:01:25 -0700429 public ScanResult[] getResults() {
430 return mResults;
431 }
432
433 /** Implement the Parcelable interface {@hide} */
434 public int describeContents() {
435 return 0;
436 }
437
438 /** Implement the Parcelable interface {@hide} */
439 public void writeToParcel(Parcel dest, int flags) {
440 if (mResults != null) {
441 dest.writeInt(mId);
442 dest.writeInt(mFlags);
Mitchell Wills0d193b42016-03-22 15:56:17 -0700443 dest.writeInt(mBucketsScanned);
Roshan Pius5a600f52018-11-14 10:43:15 -0800444 dest.writeInt(mBandScanned);
Vinit Deshpandef45acfe2014-10-30 11:01:25 -0700445 dest.writeInt(mResults.length);
446 for (int i = 0; i < mResults.length; i++) {
447 ScanResult result = mResults[i];
448 result.writeToParcel(dest, flags);
449 }
450 } else {
451 dest.writeInt(0);
452 }
453 }
454
455 /** Implement the Parcelable interface {@hide} */
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -0700456 public static final @android.annotation.NonNull Creator<ScanData> CREATOR =
Vinit Deshpandef45acfe2014-10-30 11:01:25 -0700457 new Creator<ScanData>() {
458 public ScanData createFromParcel(Parcel in) {
459 int id = in.readInt();
460 int flags = in.readInt();
Mitchell Wills0d193b42016-03-22 15:56:17 -0700461 int bucketsScanned = in.readInt();
Roshan Pius5a600f52018-11-14 10:43:15 -0800462 int bandScanned = in.readInt();
Vinit Deshpandef45acfe2014-10-30 11:01:25 -0700463 int n = in.readInt();
464 ScanResult results[] = new ScanResult[n];
465 for (int i = 0; i < n; i++) {
466 results[i] = ScanResult.CREATOR.createFromParcel(in);
467 }
Roshan Pius5a600f52018-11-14 10:43:15 -0800468 return new ScanData(id, flags, bucketsScanned, bandScanned, results);
Vinit Deshpandef45acfe2014-10-30 11:01:25 -0700469 }
470
471 public ScanData[] newArray(int size) {
472 return new ScanData[size];
473 }
474 };
475 }
476
477 public static class ParcelableScanData implements Parcelable {
478
479 public ScanData mResults[];
480
481 public ParcelableScanData(ScanData[] results) {
482 mResults = results;
483 }
484
485 public ScanData[] getResults() {
486 return mResults;
487 }
488
489 /** Implement the Parcelable interface {@hide} */
490 public int describeContents() {
491 return 0;
492 }
493
494 /** Implement the Parcelable interface {@hide} */
495 public void writeToParcel(Parcel dest, int flags) {
496 if (mResults != null) {
497 dest.writeInt(mResults.length);
498 for (int i = 0; i < mResults.length; i++) {
499 ScanData result = mResults[i];
500 result.writeToParcel(dest, flags);
501 }
502 } else {
503 dest.writeInt(0);
504 }
505 }
506
507 /** Implement the Parcelable interface {@hide} */
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -0700508 public static final @android.annotation.NonNull Creator<ParcelableScanData> CREATOR =
Vinit Deshpandef45acfe2014-10-30 11:01:25 -0700509 new Creator<ParcelableScanData>() {
510 public ParcelableScanData createFromParcel(Parcel in) {
511 int n = in.readInt();
512 ScanData results[] = new ScanData[n];
513 for (int i = 0; i < n; i++) {
514 results[i] = ScanData.CREATOR.createFromParcel(in);
515 }
516 return new ParcelableScanData(results);
517 }
518
519 public ParcelableScanData[] newArray(int size) {
520 return new ParcelableScanData[size];
521 }
522 };
523 }
524
Vinit Deshapnde011e1b32014-05-07 21:09:11 -0700525 public static class ParcelableScanResults implements Parcelable {
Vinit Deshpandef45acfe2014-10-30 11:01:25 -0700526
Vinit Deshapnde011e1b32014-05-07 21:09:11 -0700527 public ScanResult mResults[];
528
529 public ParcelableScanResults(ScanResult[] results) {
530 mResults = results;
531 }
532
533 public ScanResult[] getResults() {
534 return mResults;
535 }
536
537 /** Implement the Parcelable interface {@hide} */
538 public int describeContents() {
539 return 0;
540 }
541
542 /** Implement the Parcelable interface {@hide} */
543 public void writeToParcel(Parcel dest, int flags) {
Vinit Deshpandedaf215c2014-06-09 15:39:22 -0700544 if (mResults != null) {
545 dest.writeInt(mResults.length);
546 for (int i = 0; i < mResults.length; i++) {
547 ScanResult result = mResults[i];
548 result.writeToParcel(dest, flags);
549 }
550 } else {
551 dest.writeInt(0);
Vinit Deshapnde011e1b32014-05-07 21:09:11 -0700552 }
553 }
554
555 /** Implement the Parcelable interface {@hide} */
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -0700556 public static final @android.annotation.NonNull Creator<ParcelableScanResults> CREATOR =
Vinit Deshapnde011e1b32014-05-07 21:09:11 -0700557 new Creator<ParcelableScanResults>() {
558 public ParcelableScanResults createFromParcel(Parcel in) {
559 int n = in.readInt();
560 ScanResult results[] = new ScanResult[n];
561 for (int i = 0; i < n; i++) {
562 results[i] = ScanResult.CREATOR.createFromParcel(in);
563 }
564 return new ParcelableScanResults(results);
565 }
566
567 public ParcelableScanResults[] newArray(int size) {
568 return new ParcelableScanResults[size];
569 }
570 };
571 }
572
Roshan Piuse4fd1502016-03-01 13:18:41 -0800573 /** {@hide} */
574 public static final String PNO_PARAMS_PNO_SETTINGS_KEY = "PnoSettings";
575 /** {@hide} */
576 public static final String PNO_PARAMS_SCAN_SETTINGS_KEY = "ScanSettings";
577 /**
578 * PNO scan configuration parameters to be sent to {@link #startPnoScan}.
579 * Note: This structure needs to be in sync with |wifi_epno_params| struct in gscan HAL API.
580 * {@hide}
581 */
582 public static class PnoSettings implements Parcelable {
583 /**
584 * Pno network to be added to the PNO scan filtering.
585 * {@hide}
586 */
587 public static class PnoNetwork {
588 /*
589 * Pno flags bitmask to be set in {@link #PnoNetwork.flags}
590 */
591 /** Whether directed scan needs to be performed (for hidden SSIDs) */
592 public static final byte FLAG_DIRECTED_SCAN = (1 << 0);
593 /** Whether PNO event shall be triggered if the network is found on A band */
594 public static final byte FLAG_A_BAND = (1 << 1);
595 /** Whether PNO event shall be triggered if the network is found on G band */
596 public static final byte FLAG_G_BAND = (1 << 2);
597 /**
598 * Whether strict matching is required
599 * If required then the firmware must store the network's SSID and not just a hash
600 */
601 public static final byte FLAG_STRICT_MATCH = (1 << 3);
602 /**
603 * If this SSID should be considered the same network as the currently connected
604 * one for scoring.
605 */
606 public static final byte FLAG_SAME_NETWORK = (1 << 4);
607
608 /*
609 * Code for matching the beacon AUTH IE - additional codes. Bitmask to be set in
610 * {@link #PnoNetwork.authBitField}
611 */
612 /** Open Network */
613 public static final byte AUTH_CODE_OPEN = (1 << 0);
614 /** WPA_PSK or WPA2PSK */
615 public static final byte AUTH_CODE_PSK = (1 << 1);
616 /** any EAPOL */
617 public static final byte AUTH_CODE_EAPOL = (1 << 2);
618
619 /** SSID of the network */
620 public String ssid;
Roshan Piuse4fd1502016-03-01 13:18:41 -0800621 /** Bitmask of the FLAG_XXX */
xshub0856c52018-05-25 13:44:40 -0700622 public byte flags = 0;
Roshan Piuse4fd1502016-03-01 13:18:41 -0800623 /** Bitmask of the ATUH_XXX */
xshub0856c52018-05-25 13:44:40 -0700624 public byte authBitField = 0;
625 /** frequencies on which the particular network needs to be scanned for */
626 public int[] frequencies = {};
Roshan Piuse4fd1502016-03-01 13:18:41 -0800627
628 /**
629 * default constructor for PnoNetwork
630 */
631 public PnoNetwork(String ssid) {
632 this.ssid = ssid;
Roshan Piuse4fd1502016-03-01 13:18:41 -0800633 }
634 }
635
636 /** Connected vs Disconnected PNO flag {@hide} */
637 public boolean isConnected;
638 /** Minimum 5GHz RSSI for a BSSID to be considered */
639 public int min5GHzRssi;
640 /** Minimum 2.4GHz RSSI for a BSSID to be considered */
641 public int min24GHzRssi;
642 /** Maximum score that a network can have before bonuses */
643 public int initialScoreMax;
644 /**
645 * Only report when there is a network's score this much higher
646 * than the current connection.
647 */
648 public int currentConnectionBonus;
649 /** score bonus for all networks with the same network flag */
650 public int sameNetworkBonus;
651 /** score bonus for networks that are not open */
652 public int secureBonus;
653 /** 5GHz RSSI score bonus (applied to all 5GHz networks) */
654 public int band5GHzBonus;
655 /** Pno Network filter list */
656 public PnoNetwork[] networkList;
657
658 /** Implement the Parcelable interface {@hide} */
659 public int describeContents() {
660 return 0;
661 }
662
663 /** Implement the Parcelable interface {@hide} */
664 public void writeToParcel(Parcel dest, int flags) {
665 dest.writeInt(isConnected ? 1 : 0);
666 dest.writeInt(min5GHzRssi);
667 dest.writeInt(min24GHzRssi);
668 dest.writeInt(initialScoreMax);
669 dest.writeInt(currentConnectionBonus);
670 dest.writeInt(sameNetworkBonus);
671 dest.writeInt(secureBonus);
672 dest.writeInt(band5GHzBonus);
673 if (networkList != null) {
674 dest.writeInt(networkList.length);
675 for (int i = 0; i < networkList.length; i++) {
676 dest.writeString(networkList[i].ssid);
Roshan Piuse4fd1502016-03-01 13:18:41 -0800677 dest.writeByte(networkList[i].flags);
678 dest.writeByte(networkList[i].authBitField);
xshub0856c52018-05-25 13:44:40 -0700679 dest.writeIntArray(networkList[i].frequencies);
Roshan Piuse4fd1502016-03-01 13:18:41 -0800680 }
681 } else {
682 dest.writeInt(0);
683 }
684 }
685
686 /** Implement the Parcelable interface {@hide} */
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -0700687 public static final @android.annotation.NonNull Creator<PnoSettings> CREATOR =
Roshan Piuse4fd1502016-03-01 13:18:41 -0800688 new Creator<PnoSettings>() {
689 public PnoSettings createFromParcel(Parcel in) {
690 PnoSettings settings = new PnoSettings();
691 settings.isConnected = in.readInt() == 1;
692 settings.min5GHzRssi = in.readInt();
693 settings.min24GHzRssi = in.readInt();
694 settings.initialScoreMax = in.readInt();
695 settings.currentConnectionBonus = in.readInt();
696 settings.sameNetworkBonus = in.readInt();
697 settings.secureBonus = in.readInt();
698 settings.band5GHzBonus = in.readInt();
699 int numNetworks = in.readInt();
700 settings.networkList = new PnoNetwork[numNetworks];
701 for (int i = 0; i < numNetworks; i++) {
702 String ssid = in.readString();
703 PnoNetwork network = new PnoNetwork(ssid);
Roshan Piuse4fd1502016-03-01 13:18:41 -0800704 network.flags = in.readByte();
705 network.authBitField = in.readByte();
xshub0856c52018-05-25 13:44:40 -0700706 network.frequencies = in.createIntArray();
Roshan Piuse4fd1502016-03-01 13:18:41 -0800707 settings.networkList[i] = network;
708 }
709 return settings;
710 }
711
712 public PnoSettings[] newArray(int size) {
713 return new PnoSettings[size];
714 }
715 };
716
717 }
718
Vinit Deshapnde011e1b32014-05-07 21:09:11 -0700719 /**
Vinit Deshpandef45acfe2014-10-30 11:01:25 -0700720 * interface to get scan events on; specify this on {@link #startBackgroundScan} or
721 * {@link #startScan}
Vinit Deshapnde011e1b32014-05-07 21:09:11 -0700722 */
723 public interface ScanListener extends ActionListener {
Vinit Deshapnde1ab9cc82014-05-09 19:13:56 -0700724 /**
725 * Framework co-ordinates scans across multiple apps; so it may not give exactly the
726 * same period requested. If period of a scan is changed; it is reported by this event.
727 */
Vinit Deshapnde011e1b32014-05-07 21:09:11 -0700728 public void onPeriodChanged(int periodInMs);
Vinit Deshapnde1ab9cc82014-05-09 19:13:56 -0700729 /**
Vinit Deshpandef45acfe2014-10-30 11:01:25 -0700730 * reports results retrieved from background scan and single shot scans
Vinit Deshapnde1ab9cc82014-05-09 19:13:56 -0700731 */
Vinit Deshpandef45acfe2014-10-30 11:01:25 -0700732 public void onResults(ScanData[] results);
Vinit Deshapnde1ab9cc82014-05-09 19:13:56 -0700733 /**
734 * reports full scan result for each access point found in scan
735 */
Vinit Deshpande55027bb2014-05-29 15:58:48 -0700736 public void onFullResult(ScanResult fullScanResult);
Vinit Deshapnde011e1b32014-05-07 21:09:11 -0700737 }
738
Roshan Piuse4fd1502016-03-01 13:18:41 -0800739 /**
740 * interface to get PNO scan events on; specify this on {@link #startDisconnectedPnoScan} and
741 * {@link #startConnectedPnoScan}.
742 * {@hide}
743 */
744 public interface PnoScanListener extends ScanListener {
745 /**
746 * Invoked when one of the PNO networks are found in scan results.
747 */
748 void onPnoNetworkFound(ScanResult[] results);
749 }
750
Mitchell Willsdb818622016-06-22 16:14:58 -0700751 /**
Roshan Pius5ac66162018-04-25 14:29:51 -0700752 * Enable/Disable wifi scanning.
753 *
754 * {@hide}
755 */
756 @RequiresPermission(Manifest.permission.NETWORK_STACK)
757 public void setScanningEnabled(boolean enable) {
758 validateChannel();
759 mAsyncChannel.sendMessage(enable ? CMD_ENABLE : CMD_DISABLE);
760 }
761
762 /**
Mitchell Willsdb818622016-06-22 16:14:58 -0700763 * Register a listener that will receive results from all single scans
764 * Either the onSuccess/onFailure will be called once when the listener is registered. After
765 * (assuming onSuccess was called) all subsequent single scan results will be delivered to the
766 * listener. It is possible that onFullResult will not be called for all results of the first
767 * scan if the listener was registered during the scan.
768 *
769 * @param listener specifies the object to report events to. This object is also treated as a
770 * key for this request, and must also be specified to cancel the request.
771 * Multiple requests should also not share this object.
772 * {@hide}
773 */
Roshan Pius5a600f52018-11-14 10:43:15 -0800774 @RequiresPermission(Manifest.permission.NETWORK_STACK)
Mitchell Willsdb818622016-06-22 16:14:58 -0700775 public void registerScanListener(ScanListener listener) {
776 Preconditions.checkNotNull(listener, "listener cannot be null");
777 int key = addListener(listener);
778 if (key == INVALID_KEY) return;
779 validateChannel();
780 mAsyncChannel.sendMessage(CMD_REGISTER_SCAN_LISTENER, 0, key);
781 }
782
783 /**
784 * Deregister a listener for ongoing single scans
785 * @param listener specifies which scan to cancel; must be same object as passed in {@link
786 * #registerScanListener}
787 * {@hide}
788 */
789 public void deregisterScanListener(ScanListener listener) {
790 Preconditions.checkNotNull(listener, "listener cannot be null");
791 int key = removeListener(listener);
792 if (key == INVALID_KEY) return;
793 validateChannel();
794 mAsyncChannel.sendMessage(CMD_DEREGISTER_SCAN_LISTENER, 0, key);
795 }
796
Vinit Deshapnde1ab9cc82014-05-09 19:13:56 -0700797 /** start wifi scan in background
798 * @param settings specifies various parameters for the scan; for more information look at
799 * {@link ScanSettings}
800 * @param listener specifies the object to report events to. This object is also treated as a
801 * key for this scan, and must also be specified to cancel the scan. Multiple
802 * scans should also not share this object.
803 */
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -0600804 @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
Vinit Deshapnde011e1b32014-05-07 21:09:11 -0700805 public void startBackgroundScan(ScanSettings settings, ScanListener listener) {
Mitchell Willsd24427f2016-03-29 13:34:45 -0700806 startBackgroundScan(settings, listener, null);
807 }
808
809 /** start wifi scan in background
810 * @param settings specifies various parameters for the scan; for more information look at
811 * {@link ScanSettings}
812 * @param workSource WorkSource to blame for power usage
813 * @param listener specifies the object to report events to. This object is also treated as a
814 * key for this scan, and must also be specified to cancel the scan. Multiple
815 * scans should also not share this object.
816 */
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -0600817 @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
Mitchell Willsd24427f2016-03-29 13:34:45 -0700818 public void startBackgroundScan(ScanSettings settings, ScanListener listener,
819 WorkSource workSource) {
Wei Wang3cf4da92016-02-16 23:38:41 -0800820 Preconditions.checkNotNull(listener, "listener cannot be null");
821 int key = addListener(listener);
822 if (key == INVALID_KEY) return;
Vinit Deshapnde011e1b32014-05-07 21:09:11 -0700823 validateChannel();
Mitchell Willsad95b6a2016-03-29 14:56:38 -0700824 Bundle scanParams = new Bundle();
825 scanParams.putParcelable(SCAN_PARAMS_SCAN_SETTINGS_KEY, settings);
826 scanParams.putParcelable(SCAN_PARAMS_WORK_SOURCE_KEY, workSource);
Roshan Pius7e757ea2018-11-21 11:37:44 -0800827 scanParams.putString(REQUEST_PACKAGE_NAME_KEY, mContext.getOpPackageName());
Mitchell Wills91312c72016-04-06 17:03:35 -0700828 mAsyncChannel.sendMessage(CMD_START_BACKGROUND_SCAN, 0, key, scanParams);
Vinit Deshapnde011e1b32014-05-07 21:09:11 -0700829 }
Mitchell Willsd24427f2016-03-29 13:34:45 -0700830
Vinit Deshapnde1ab9cc82014-05-09 19:13:56 -0700831 /**
832 * stop an ongoing wifi scan
833 * @param listener specifies which scan to cancel; must be same object as passed in {@link
834 * #startBackgroundScan}
835 */
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -0600836 @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
Vinit Deshapnde1ab9cc82014-05-09 19:13:56 -0700837 public void stopBackgroundScan(ScanListener listener) {
Wei Wang3cf4da92016-02-16 23:38:41 -0800838 Preconditions.checkNotNull(listener, "listener cannot be null");
839 int key = removeListener(listener);
840 if (key == INVALID_KEY) return;
Vinit Deshapnde011e1b32014-05-07 21:09:11 -0700841 validateChannel();
Roshan Pius7e757ea2018-11-21 11:37:44 -0800842 Bundle scanParams = new Bundle();
843 scanParams.putString(REQUEST_PACKAGE_NAME_KEY, mContext.getOpPackageName());
844 mAsyncChannel.sendMessage(CMD_STOP_BACKGROUND_SCAN, 0, key, scanParams);
Vinit Deshapnde011e1b32014-05-07 21:09:11 -0700845 }
Roshan Pius7e757ea2018-11-21 11:37:44 -0800846
Vinit Deshapnde1ab9cc82014-05-09 19:13:56 -0700847 /**
Vinit Deshpandef45acfe2014-10-30 11:01:25 -0700848 * reports currently available scan results on appropriate listeners
849 * @return true if all scan results were reported correctly
Vinit Deshapnde1ab9cc82014-05-09 19:13:56 -0700850 */
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -0600851 @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
Vinit Deshpandef45acfe2014-10-30 11:01:25 -0700852 public boolean getScanResults() {
Vinit Deshapnde011e1b32014-05-07 21:09:11 -0700853 validateChannel();
Roshan Pius7e757ea2018-11-21 11:37:44 -0800854 Bundle scanParams = new Bundle();
855 scanParams.putString(REQUEST_PACKAGE_NAME_KEY, mContext.getOpPackageName());
856 Message reply =
857 mAsyncChannel.sendMessageSynchronously(CMD_GET_SCAN_RESULTS, 0, 0, scanParams);
Vinit Deshpandef45acfe2014-10-30 11:01:25 -0700858 return reply.what == CMD_OP_SUCCEEDED;
859 }
860
861 /**
862 * starts a single scan and reports results asynchronously
863 * @param settings specifies various parameters for the scan; for more information look at
864 * {@link ScanSettings}
865 * @param listener specifies the object to report events to. This object is also treated as a
866 * key for this scan, and must also be specified to cancel the scan. Multiple
867 * scans should also not share this object.
868 */
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -0600869 @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
Vinit Deshpandef45acfe2014-10-30 11:01:25 -0700870 public void startScan(ScanSettings settings, ScanListener listener) {
Mitchell Willsd24427f2016-03-29 13:34:45 -0700871 startScan(settings, listener, null);
872 }
873
874 /**
875 * starts a single scan and reports results asynchronously
876 * @param settings specifies various parameters for the scan; for more information look at
877 * {@link ScanSettings}
878 * @param workSource WorkSource to blame for power usage
879 * @param listener specifies the object to report events to. This object is also treated as a
880 * key for this scan, and must also be specified to cancel the scan. Multiple
881 * scans should also not share this object.
882 */
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -0600883 @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
Mitchell Willsd24427f2016-03-29 13:34:45 -0700884 public void startScan(ScanSettings settings, ScanListener listener, WorkSource workSource) {
Wei Wang3cf4da92016-02-16 23:38:41 -0800885 Preconditions.checkNotNull(listener, "listener cannot be null");
886 int key = addListener(listener);
887 if (key == INVALID_KEY) return;
Vinit Deshpandef45acfe2014-10-30 11:01:25 -0700888 validateChannel();
Mitchell Willsad95b6a2016-03-29 14:56:38 -0700889 Bundle scanParams = new Bundle();
890 scanParams.putParcelable(SCAN_PARAMS_SCAN_SETTINGS_KEY, settings);
891 scanParams.putParcelable(SCAN_PARAMS_WORK_SOURCE_KEY, workSource);
Roshan Pius7e757ea2018-11-21 11:37:44 -0800892 scanParams.putString(REQUEST_PACKAGE_NAME_KEY, mContext.getOpPackageName());
Mitchell Wills91312c72016-04-06 17:03:35 -0700893 mAsyncChannel.sendMessage(CMD_START_SINGLE_SCAN, 0, key, scanParams);
Vinit Deshpandef45acfe2014-10-30 11:01:25 -0700894 }
895
896 /**
897 * stops an ongoing single shot scan; only useful after {@link #startScan} if onResults()
898 * hasn't been called on the listener, ignored otherwise
899 * @param listener
900 */
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -0600901 @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE)
Vinit Deshpandef45acfe2014-10-30 11:01:25 -0700902 public void stopScan(ScanListener listener) {
Wei Wang3cf4da92016-02-16 23:38:41 -0800903 Preconditions.checkNotNull(listener, "listener cannot be null");
904 int key = removeListener(listener);
905 if (key == INVALID_KEY) return;
Vinit Deshpandef45acfe2014-10-30 11:01:25 -0700906 validateChannel();
Roshan Pius7e757ea2018-11-21 11:37:44 -0800907 Bundle scanParams = new Bundle();
908 scanParams.putString(REQUEST_PACKAGE_NAME_KEY, mContext.getOpPackageName());
909 mAsyncChannel.sendMessage(CMD_STOP_SINGLE_SCAN, 0, key, scanParams);
Vinit Deshapnde011e1b32014-05-07 21:09:11 -0700910 }
911
Rebecca Silbersteinbfc76e02016-09-14 22:07:04 -0700912 /**
913 * Retrieve the most recent scan results from a single scan request.
914 * {@hide}
915 */
916 public List<ScanResult> getSingleScanResults() {
917 validateChannel();
Roshan Pius7e757ea2018-11-21 11:37:44 -0800918 Bundle scanParams = new Bundle();
919 scanParams.putString(REQUEST_PACKAGE_NAME_KEY, mContext.getOpPackageName());
920 Message reply = mAsyncChannel.sendMessageSynchronously(CMD_GET_SINGLE_SCAN_RESULTS, 0, 0,
921 scanParams);
Rebecca Silbersteinbfc76e02016-09-14 22:07:04 -0700922 if (reply.what == WifiScanner.CMD_OP_SUCCEEDED) {
923 return Arrays.asList(((ParcelableScanResults) reply.obj).getResults());
924 }
925 OperationResult result = (OperationResult) reply.obj;
926 Log.e(TAG, "Error retrieving SingleScan results reason: " + result.reason
927 + " description: " + result.description);
928 return new ArrayList<ScanResult>();
929 }
930
Roshan Piuse4fd1502016-03-01 13:18:41 -0800931 private void startPnoScan(ScanSettings scanSettings, PnoSettings pnoSettings, int key) {
932 // Bundle up both the settings and send it across.
933 Bundle pnoParams = new Bundle();
Roshan Piuse4fd1502016-03-01 13:18:41 -0800934 // Set the PNO scan flag.
935 scanSettings.isPnoScan = true;
936 pnoParams.putParcelable(PNO_PARAMS_SCAN_SETTINGS_KEY, scanSettings);
937 pnoParams.putParcelable(PNO_PARAMS_PNO_SETTINGS_KEY, pnoSettings);
Mitchell Wills91312c72016-04-06 17:03:35 -0700938 mAsyncChannel.sendMessage(CMD_START_PNO_SCAN, 0, key, pnoParams);
Roshan Piuse4fd1502016-03-01 13:18:41 -0800939 }
940 /**
941 * Start wifi connected PNO scan
942 * @param scanSettings specifies various parameters for the scan; for more information look at
943 * {@link ScanSettings}
944 * @param pnoSettings specifies various parameters for PNO; for more information look at
945 * {@link PnoSettings}
946 * @param listener specifies the object to report events to. This object is also treated as a
947 * key for this scan, and must also be specified to cancel the scan. Multiple
948 * scans should also not share this object.
949 * {@hide}
950 */
951 public void startConnectedPnoScan(ScanSettings scanSettings, PnoSettings pnoSettings,
952 PnoScanListener listener) {
953 Preconditions.checkNotNull(listener, "listener cannot be null");
954 Preconditions.checkNotNull(pnoSettings, "pnoSettings cannot be null");
955 int key = addListener(listener);
956 if (key == INVALID_KEY) return;
957 validateChannel();
958 pnoSettings.isConnected = true;
959 startPnoScan(scanSettings, pnoSettings, key);
960 }
961 /**
962 * Start wifi disconnected PNO scan
963 * @param scanSettings specifies various parameters for the scan; for more information look at
964 * {@link ScanSettings}
965 * @param pnoSettings specifies various parameters for PNO; for more information look at
966 * {@link PnoSettings}
967 * @param listener specifies the object to report events to. This object is also treated as a
968 * key for this scan, and must also be specified to cancel the scan. Multiple
969 * scans should also not share this object.
970 * {@hide}
971 */
Roshan Pius8a73ce42018-07-18 14:16:07 -0700972 @RequiresPermission(android.Manifest.permission.NETWORK_STACK)
Roshan Piuse4fd1502016-03-01 13:18:41 -0800973 public void startDisconnectedPnoScan(ScanSettings scanSettings, PnoSettings pnoSettings,
974 PnoScanListener listener) {
975 Preconditions.checkNotNull(listener, "listener cannot be null");
976 Preconditions.checkNotNull(pnoSettings, "pnoSettings cannot be null");
977 int key = addListener(listener);
978 if (key == INVALID_KEY) return;
979 validateChannel();
980 pnoSettings.isConnected = false;
981 startPnoScan(scanSettings, pnoSettings, key);
982 }
983 /**
984 * Stop an ongoing wifi PNO scan
Roshan Piuse4fd1502016-03-01 13:18:41 -0800985 * @param listener specifies which scan to cancel; must be same object as passed in {@link
986 * #startPnoScan}
Roshan Piuse4fd1502016-03-01 13:18:41 -0800987 * {@hide}
988 */
Roshan Pius8a73ce42018-07-18 14:16:07 -0700989 @RequiresPermission(android.Manifest.permission.NETWORK_STACK)
Roshan Pius37aeb472016-04-07 10:31:23 -0700990 public void stopPnoScan(ScanListener listener) {
Roshan Piuse4fd1502016-03-01 13:18:41 -0800991 Preconditions.checkNotNull(listener, "listener cannot be null");
992 int key = removeListener(listener);
993 if (key == INVALID_KEY) return;
994 validateChannel();
Mitchell Wills91312c72016-04-06 17:03:35 -0700995 mAsyncChannel.sendMessage(CMD_STOP_PNO_SCAN, 0, key);
Roshan Piuse4fd1502016-03-01 13:18:41 -0800996 }
997
Vinit Deshapnde1ab9cc82014-05-09 19:13:56 -0700998 /** specifies information about an access point of interest */
Michael Plass5b1979f2017-03-31 11:36:36 -0700999 @Deprecated
Vinit Deshpandeea676a02014-07-29 15:52:20 -07001000 public static class BssidInfo {
Vinit Deshapnde1ab9cc82014-05-09 19:13:56 -07001001 /** bssid of the access point; in XX:XX:XX:XX:XX:XX format */
Vinit Deshapnde011e1b32014-05-07 21:09:11 -07001002 public String bssid;
Vinit Deshapnde1ab9cc82014-05-09 19:13:56 -07001003 /** low signal strength threshold; more information at {@link ScanResult#level} */
Vinit Deshapnde011e1b32014-05-07 21:09:11 -07001004 public int low; /* minimum RSSI */
Vinit Deshapnde1ab9cc82014-05-09 19:13:56 -07001005 /** high signal threshold; more information at {@link ScanResult#level} */
Vinit Deshapnde011e1b32014-05-07 21:09:11 -07001006 public int high; /* maximum RSSI */
Vinit Deshapnde8ca03392014-05-13 15:36:48 -07001007 /** channel frequency (in KHz) where you may find this BSSID */
1008 public int frequencyHint;
Vinit Deshapnde011e1b32014-05-07 21:09:11 -07001009 }
1010
Vinit Deshapnde1ab9cc82014-05-09 19:13:56 -07001011 /** @hide */
Wei Wang35d552f2014-07-08 21:37:01 -07001012 @SystemApi
Michael Plass5b1979f2017-03-31 11:36:36 -07001013 @Deprecated
Vinit Deshapnde8ca03392014-05-13 15:36:48 -07001014 public static class WifiChangeSettings implements Parcelable {
Vinit Deshapnde1ab9cc82014-05-09 19:13:56 -07001015 public int rssiSampleSize; /* sample size for RSSI averaging */
1016 public int lostApSampleSize; /* samples to confirm AP's loss */
1017 public int unchangedSampleSize; /* samples to confirm no change */
1018 public int minApsBreachingThreshold; /* change threshold to trigger event */
Vinit Deshapnde8ca03392014-05-13 15:36:48 -07001019 public int periodInMs; /* scan period in millisecond */
Vinit Deshpandeea676a02014-07-29 15:52:20 -07001020 public BssidInfo[] bssidInfos;
Vinit Deshapnde8ca03392014-05-13 15:36:48 -07001021
1022 /** Implement the Parcelable interface {@hide} */
1023 public int describeContents() {
1024 return 0;
1025 }
1026
1027 /** Implement the Parcelable interface {@hide} */
1028 public void writeToParcel(Parcel dest, int flags) {
Vinit Deshapnde8ca03392014-05-13 15:36:48 -07001029 }
1030
1031 /** Implement the Parcelable interface {@hide} */
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -07001032 public static final @android.annotation.NonNull Creator<WifiChangeSettings> CREATOR =
Vinit Deshapnde8ca03392014-05-13 15:36:48 -07001033 new Creator<WifiChangeSettings>() {
1034 public WifiChangeSettings createFromParcel(Parcel in) {
Michael Plass82b4fd92017-03-27 11:11:47 -07001035 return new WifiChangeSettings();
Vinit Deshapnde8ca03392014-05-13 15:36:48 -07001036 }
1037
1038 public WifiChangeSettings[] newArray(int size) {
1039 return new WifiChangeSettings[size];
1040 }
1041 };
1042
Vinit Deshapnde011e1b32014-05-07 21:09:11 -07001043 }
1044
Vinit Deshapnde1ab9cc82014-05-09 19:13:56 -07001045 /** configure WifiChange detection
1046 * @param rssiSampleSize number of samples used for RSSI averaging
1047 * @param lostApSampleSize number of samples to confirm an access point's loss
1048 * @param unchangedSampleSize number of samples to confirm there are no changes
1049 * @param minApsBreachingThreshold minimum number of access points that need to be
1050 * out of range to detect WifiChange
Vinit Deshapnde8ca03392014-05-13 15:36:48 -07001051 * @param periodInMs indicates period of scan to find changes
Vinit Deshpandeea676a02014-07-29 15:52:20 -07001052 * @param bssidInfos access points to watch
Vinit Deshapnde1ab9cc82014-05-09 19:13:56 -07001053 */
Michael Plass5b1979f2017-03-31 11:36:36 -07001054 @Deprecated
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -06001055 @SuppressLint("Doclava125")
Vinit Deshapnde1ab9cc82014-05-09 19:13:56 -07001056 public void configureWifiChange(
Vinit Deshapnde011e1b32014-05-07 21:09:11 -07001057 int rssiSampleSize, /* sample size for RSSI averaging */
1058 int lostApSampleSize, /* samples to confirm AP's loss */
1059 int unchangedSampleSize, /* samples to confirm no change */
1060 int minApsBreachingThreshold, /* change threshold to trigger event */
Vinit Deshapnde8ca03392014-05-13 15:36:48 -07001061 int periodInMs, /* period of scan */
Michael Plass82b4fd92017-03-27 11:11:47 -07001062 BssidInfo[] bssidInfos /* signal thresholds to cross */
Vinit Deshapnde011e1b32014-05-07 21:09:11 -07001063 )
1064 {
Michael Plass82b4fd92017-03-27 11:11:47 -07001065 throw new UnsupportedOperationException();
Vinit Deshapnde011e1b32014-05-07 21:09:11 -07001066 }
1067
Vinit Deshapnde1ab9cc82014-05-09 19:13:56 -07001068 /**
1069 * interface to get wifi change events on; use this on {@link #startTrackingWifiChange}
1070 */
Michael Plass5b1979f2017-03-31 11:36:36 -07001071 @Deprecated
Vinit Deshapnde1ab9cc82014-05-09 19:13:56 -07001072 public interface WifiChangeListener extends ActionListener {
1073 /** indicates that changes were detected in wifi environment
1074 * @param results indicate the access points that exhibited change
1075 */
Vinit Deshapnde011e1b32014-05-07 21:09:11 -07001076 public void onChanging(ScanResult[] results); /* changes are found */
Vinit Deshapnde1ab9cc82014-05-09 19:13:56 -07001077 /** indicates that no wifi changes are being detected for a while
1078 * @param results indicate the access points that are bing monitored for change
1079 */
Vinit Deshapnde011e1b32014-05-07 21:09:11 -07001080 public void onQuiescence(ScanResult[] results); /* changes settled down */
1081 }
1082
Vinit Deshapnde1ab9cc82014-05-09 19:13:56 -07001083 /**
1084 * track changes in wifi environment
1085 * @param listener object to report events on; this object must be unique and must also be
1086 * provided on {@link #stopTrackingWifiChange}
1087 */
Michael Plass5b1979f2017-03-31 11:36:36 -07001088 @Deprecated
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -06001089 @SuppressLint("Doclava125")
Vinit Deshapnde1ab9cc82014-05-09 19:13:56 -07001090 public void startTrackingWifiChange(WifiChangeListener listener) {
Michael Plass82b4fd92017-03-27 11:11:47 -07001091 throw new UnsupportedOperationException();
Vinit Deshapnde011e1b32014-05-07 21:09:11 -07001092 }
Vinit Deshapnde1ab9cc82014-05-09 19:13:56 -07001093
1094 /**
1095 * stop tracking changes in wifi environment
1096 * @param listener object that was provided to report events on {@link
1097 * #stopTrackingWifiChange}
1098 */
Michael Plass5b1979f2017-03-31 11:36:36 -07001099 @Deprecated
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -06001100 @SuppressLint("Doclava125")
Vinit Deshapnde1ab9cc82014-05-09 19:13:56 -07001101 public void stopTrackingWifiChange(WifiChangeListener listener) {
Michael Plass82b4fd92017-03-27 11:11:47 -07001102 throw new UnsupportedOperationException();
Vinit Deshapnde011e1b32014-05-07 21:09:11 -07001103 }
1104
Vinit Deshapnde1ab9cc82014-05-09 19:13:56 -07001105 /** @hide */
Wei Wang35d552f2014-07-08 21:37:01 -07001106 @SystemApi
Michael Plass5b1979f2017-03-31 11:36:36 -07001107 @Deprecated
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -06001108 @SuppressLint("Doclava125")
Vinit Deshapnde1ab9cc82014-05-09 19:13:56 -07001109 public void configureWifiChange(WifiChangeSettings settings) {
Michael Plass82b4fd92017-03-27 11:11:47 -07001110 throw new UnsupportedOperationException();
Vinit Deshapnde011e1b32014-05-07 21:09:11 -07001111 }
1112
Vinit Deshapnde1ab9cc82014-05-09 19:13:56 -07001113 /** interface to receive hotlist events on; use this on {@link #setHotlist} */
Michael Plass5b1979f2017-03-31 11:36:36 -07001114 @Deprecated
Vinit Deshpandeea676a02014-07-29 15:52:20 -07001115 public static interface BssidListener extends ActionListener {
Vinit Deshapnde1ab9cc82014-05-09 19:13:56 -07001116 /** indicates that access points were found by on going scans
1117 * @param results list of scan results, one for each access point visible currently
1118 */
Vinit Deshapnde011e1b32014-05-07 21:09:11 -07001119 public void onFound(ScanResult[] results);
Vinit Deshpandeab325cb2014-08-11 21:52:05 -07001120 /** indicates that access points were missed by on going scans
1121 * @param results list of scan results, for each access point that is not visible anymore
1122 */
1123 public void onLost(ScanResult[] results);
Vinit Deshapnde011e1b32014-05-07 21:09:11 -07001124 }
1125
1126 /** @hide */
Wei Wang35d552f2014-07-08 21:37:01 -07001127 @SystemApi
Michael Plass5b1979f2017-03-31 11:36:36 -07001128 @Deprecated
Vinit Deshapnde011e1b32014-05-07 21:09:11 -07001129 public static class HotlistSettings implements Parcelable {
Vinit Deshpandeea676a02014-07-29 15:52:20 -07001130 public BssidInfo[] bssidInfos;
Vinit Deshapnde011e1b32014-05-07 21:09:11 -07001131 public int apLostThreshold;
1132
1133 /** Implement the Parcelable interface {@hide} */
1134 public int describeContents() {
1135 return 0;
1136 }
1137
1138 /** Implement the Parcelable interface {@hide} */
1139 public void writeToParcel(Parcel dest, int flags) {
Vinit Deshapnde011e1b32014-05-07 21:09:11 -07001140 }
1141
1142 /** Implement the Parcelable interface {@hide} */
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -07001143 public static final @android.annotation.NonNull Creator<HotlistSettings> CREATOR =
Vinit Deshapnde011e1b32014-05-07 21:09:11 -07001144 new Creator<HotlistSettings>() {
1145 public HotlistSettings createFromParcel(Parcel in) {
1146 HotlistSettings settings = new HotlistSettings();
Vinit Deshapnde011e1b32014-05-07 21:09:11 -07001147 return settings;
1148 }
1149
1150 public HotlistSettings[] newArray(int size) {
1151 return new HotlistSettings[size];
1152 }
1153 };
1154 }
1155
Vinit Deshapnde1ab9cc82014-05-09 19:13:56 -07001156 /**
1157 * set interesting access points to find
Vinit Deshpandeea676a02014-07-29 15:52:20 -07001158 * @param bssidInfos access points of interest
Vinit Deshapnde1ab9cc82014-05-09 19:13:56 -07001159 * @param apLostThreshold number of scans needed to indicate that AP is lost
1160 * @param listener object provided to report events on; this object must be unique and must
Vinit Deshpandeea676a02014-07-29 15:52:20 -07001161 * also be provided on {@link #stopTrackingBssids}
Vinit Deshapnde1ab9cc82014-05-09 19:13:56 -07001162 */
Michael Plass5b1979f2017-03-31 11:36:36 -07001163 @Deprecated
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -06001164 @SuppressLint("Doclava125")
Vinit Deshpandeea676a02014-07-29 15:52:20 -07001165 public void startTrackingBssids(BssidInfo[] bssidInfos,
1166 int apLostThreshold, BssidListener listener) {
Michael Plass82b4fd92017-03-27 11:11:47 -07001167 throw new UnsupportedOperationException();
Vinit Deshapnde011e1b32014-05-07 21:09:11 -07001168 }
1169
Vinit Deshapnde1ab9cc82014-05-09 19:13:56 -07001170 /**
1171 * remove tracking of interesting access points
Vinit Deshpandeea676a02014-07-29 15:52:20 -07001172 * @param listener same object provided in {@link #startTrackingBssids}
Vinit Deshapnde1ab9cc82014-05-09 19:13:56 -07001173 */
Michael Plass5b1979f2017-03-31 11:36:36 -07001174 @Deprecated
Jeff Sharkeyd86b8fe2017-06-02 17:36:26 -06001175 @SuppressLint("Doclava125")
Vinit Deshpandeea676a02014-07-29 15:52:20 -07001176 public void stopTrackingBssids(BssidListener listener) {
Michael Plass82b4fd92017-03-27 11:11:47 -07001177 throw new UnsupportedOperationException();
Vinit Deshapnde011e1b32014-05-07 21:09:11 -07001178 }
1179
1180
1181 /* private members and methods */
1182
1183 private static final String TAG = "WifiScanner";
Vinit Deshpande85607192015-04-21 15:59:53 -07001184 private static final boolean DBG = false;
Vinit Deshapnde011e1b32014-05-07 21:09:11 -07001185
1186 /* commands for Wifi Service */
1187 private static final int BASE = Protocol.BASE_WIFI_SCANNER;
1188
1189 /** @hide */
Vinit Deshapnde011e1b32014-05-07 21:09:11 -07001190 public static final int CMD_START_BACKGROUND_SCAN = BASE + 2;
1191 /** @hide */
1192 public static final int CMD_STOP_BACKGROUND_SCAN = BASE + 3;
1193 /** @hide */
1194 public static final int CMD_GET_SCAN_RESULTS = BASE + 4;
1195 /** @hide */
1196 public static final int CMD_SCAN_RESULT = BASE + 5;
1197 /** @hide */
Vinit Deshapnde011e1b32014-05-07 21:09:11 -07001198 public static final int CMD_OP_SUCCEEDED = BASE + 17;
1199 /** @hide */
1200 public static final int CMD_OP_FAILED = BASE + 18;
1201 /** @hide */
Vinit Deshapnde011e1b32014-05-07 21:09:11 -07001202 public static final int CMD_FULL_SCAN_RESULT = BASE + 20;
Vinit Deshpandef45acfe2014-10-30 11:01:25 -07001203 /** @hide */
1204 public static final int CMD_START_SINGLE_SCAN = BASE + 21;
1205 /** @hide */
1206 public static final int CMD_STOP_SINGLE_SCAN = BASE + 22;
1207 /** @hide */
1208 public static final int CMD_SINGLE_SCAN_COMPLETED = BASE + 23;
Roshan Piuse4fd1502016-03-01 13:18:41 -08001209 /** @hide */
1210 public static final int CMD_START_PNO_SCAN = BASE + 24;
1211 /** @hide */
1212 public static final int CMD_STOP_PNO_SCAN = BASE + 25;
1213 /** @hide */
1214 public static final int CMD_PNO_NETWORK_FOUND = BASE + 26;
Mitchell Willsdb818622016-06-22 16:14:58 -07001215 /** @hide */
1216 public static final int CMD_REGISTER_SCAN_LISTENER = BASE + 27;
1217 /** @hide */
1218 public static final int CMD_DEREGISTER_SCAN_LISTENER = BASE + 28;
Rebecca Silbersteinbfc76e02016-09-14 22:07:04 -07001219 /** @hide */
1220 public static final int CMD_GET_SINGLE_SCAN_RESULTS = BASE + 29;
Roshan Pius5ac66162018-04-25 14:29:51 -07001221 /** @hide */
1222 public static final int CMD_ENABLE = BASE + 30;
1223 /** @hide */
1224 public static final int CMD_DISABLE = BASE + 31;
Vinit Deshapnde011e1b32014-05-07 21:09:11 -07001225
1226 private Context mContext;
1227 private IWifiScanner mService;
1228
1229 private static final int INVALID_KEY = 0;
Mitchell Wills91312c72016-04-06 17:03:35 -07001230 private int mListenerKey = 1;
Vinit Deshapnde011e1b32014-05-07 21:09:11 -07001231
Mitchell Wills91312c72016-04-06 17:03:35 -07001232 private final SparseArray mListenerMap = new SparseArray();
1233 private final Object mListenerMapLock = new Object();
Vinit Deshapnde011e1b32014-05-07 21:09:11 -07001234
Mitchell Wills91312c72016-04-06 17:03:35 -07001235 private AsyncChannel mAsyncChannel;
Mitchell Wills91312c72016-04-06 17:03:35 -07001236 private final Handler mInternalHandler;
Vinit Deshapnde011e1b32014-05-07 21:09:11 -07001237
1238 /**
1239 * Create a new WifiScanner instance.
1240 * Applications will almost always want to use
1241 * {@link android.content.Context#getSystemService Context.getSystemService()} to retrieve
1242 * the standard {@link android.content.Context#WIFI_SERVICE Context.WIFI_SERVICE}.
1243 * @param context the application context
1244 * @param service the Binder interface
Mitchell Wills91312c72016-04-06 17:03:35 -07001245 * @param looper the Looper used to deliver callbacks
Vinit Deshapnde011e1b32014-05-07 21:09:11 -07001246 * @hide
1247 */
Mitchell Wills91312c72016-04-06 17:03:35 -07001248 public WifiScanner(Context context, IWifiScanner service, Looper looper) {
Wei Wang3cf4da92016-02-16 23:38:41 -08001249 mContext = context;
1250 mService = service;
Wei Wang3cf4da92016-02-16 23:38:41 -08001251
Mitchell Wills91312c72016-04-06 17:03:35 -07001252 Messenger messenger = null;
1253 try {
1254 messenger = mService.getMessenger();
1255 } catch (RemoteException e) {
1256 throw e.rethrowFromSystemServer();
1257 }
Vinit Deshapnde011e1b32014-05-07 21:09:11 -07001258
Mitchell Wills91312c72016-04-06 17:03:35 -07001259 if (messenger == null) {
1260 throw new IllegalStateException("getMessenger() returned null! This is invalid.");
1261 }
Vinit Deshapnde011e1b32014-05-07 21:09:11 -07001262
Mitchell Wills91312c72016-04-06 17:03:35 -07001263 mAsyncChannel = new AsyncChannel();
Vinit Deshapnde011e1b32014-05-07 21:09:11 -07001264
Mitchell Wills91312c72016-04-06 17:03:35 -07001265 mInternalHandler = new ServiceHandler(looper);
Mitchell Wills0ed524de2016-04-14 13:39:44 -07001266 mAsyncChannel.connectSync(mContext, mInternalHandler, messenger);
1267 // We cannot use fullyConnectSync because it sends the FULL_CONNECTION message
1268 // synchronously, which causes WifiScanningService to receive the wrong replyTo value.
1269 mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
Vinit Deshapnde011e1b32014-05-07 21:09:11 -07001270 }
1271
1272 private void validateChannel() {
Mitchell Wills91312c72016-04-06 17:03:35 -07001273 if (mAsyncChannel == null) throw new IllegalStateException(
Vinit Deshapnde011e1b32014-05-07 21:09:11 -07001274 "No permission to access and change wifi or a bad initialization");
1275 }
1276
Wei Wang3cf4da92016-02-16 23:38:41 -08001277 // Add a listener into listener map. If the listener already exists, return INVALID_KEY and
1278 // send an error message to internal handler; Otherwise add the listener to the listener map and
1279 // return the key of the listener.
1280 private int addListener(ActionListener listener) {
Mitchell Wills91312c72016-04-06 17:03:35 -07001281 synchronized (mListenerMapLock) {
Wei Wang3cf4da92016-02-16 23:38:41 -08001282 boolean keyExists = (getListenerKey(listener) != INVALID_KEY);
1283 // Note we need to put the listener into listener map even if it's a duplicate as the
1284 // internal handler will need the key to find the listener. In case of duplicates,
1285 // removing duplicate key logic will be handled in internal handler.
1286 int key = putListener(listener);
1287 if (keyExists) {
1288 if (DBG) Log.d(TAG, "listener key already exists");
1289 OperationResult operationResult = new OperationResult(REASON_DUPLICATE_REQEUST,
1290 "Outstanding request with same key not stopped yet");
Mitchell Wills91312c72016-04-06 17:03:35 -07001291 Message message = Message.obtain(mInternalHandler, CMD_OP_FAILED, 0, key,
Wei Wang3cf4da92016-02-16 23:38:41 -08001292 operationResult);
1293 message.sendToTarget();
1294 return INVALID_KEY;
1295 } else {
1296 return key;
1297 }
1298 }
1299 }
1300
Mitchell Wills91312c72016-04-06 17:03:35 -07001301 private int putListener(Object listener) {
Vinit Deshapnde011e1b32014-05-07 21:09:11 -07001302 if (listener == null) return INVALID_KEY;
1303 int key;
Mitchell Wills91312c72016-04-06 17:03:35 -07001304 synchronized (mListenerMapLock) {
Vinit Deshapnde011e1b32014-05-07 21:09:11 -07001305 do {
Mitchell Wills91312c72016-04-06 17:03:35 -07001306 key = mListenerKey++;
Vinit Deshapnde011e1b32014-05-07 21:09:11 -07001307 } while (key == INVALID_KEY);
Mitchell Wills91312c72016-04-06 17:03:35 -07001308 mListenerMap.put(key, listener);
Vinit Deshapnde011e1b32014-05-07 21:09:11 -07001309 }
1310 return key;
1311 }
1312
Mitchell Wills91312c72016-04-06 17:03:35 -07001313 private Object getListener(int key) {
Vinit Deshapnde011e1b32014-05-07 21:09:11 -07001314 if (key == INVALID_KEY) return null;
Mitchell Wills91312c72016-04-06 17:03:35 -07001315 synchronized (mListenerMapLock) {
1316 Object listener = mListenerMap.get(key);
Vinit Deshapnde011e1b32014-05-07 21:09:11 -07001317 return listener;
1318 }
1319 }
1320
Mitchell Wills91312c72016-04-06 17:03:35 -07001321 private int getListenerKey(Object listener) {
Vinit Deshapnde011e1b32014-05-07 21:09:11 -07001322 if (listener == null) return INVALID_KEY;
Mitchell Wills91312c72016-04-06 17:03:35 -07001323 synchronized (mListenerMapLock) {
1324 int index = mListenerMap.indexOfValue(listener);
Vinit Deshapnde011e1b32014-05-07 21:09:11 -07001325 if (index == -1) {
1326 return INVALID_KEY;
1327 } else {
Mitchell Wills91312c72016-04-06 17:03:35 -07001328 return mListenerMap.keyAt(index);
Vinit Deshapnde011e1b32014-05-07 21:09:11 -07001329 }
1330 }
1331 }
1332
Mitchell Wills91312c72016-04-06 17:03:35 -07001333 private Object removeListener(int key) {
Vinit Deshapnde011e1b32014-05-07 21:09:11 -07001334 if (key == INVALID_KEY) return null;
Mitchell Wills91312c72016-04-06 17:03:35 -07001335 synchronized (mListenerMapLock) {
1336 Object listener = mListenerMap.get(key);
1337 mListenerMap.remove(key);
Vinit Deshapnde011e1b32014-05-07 21:09:11 -07001338 return listener;
1339 }
1340 }
1341
Mitchell Wills91312c72016-04-06 17:03:35 -07001342 private int removeListener(Object listener) {
Vinit Deshapnde011e1b32014-05-07 21:09:11 -07001343 int key = getListenerKey(listener);
Wei Wang3cf4da92016-02-16 23:38:41 -08001344 if (key == INVALID_KEY) {
1345 Log.e(TAG, "listener cannot be found");
1346 return key;
1347 }
Mitchell Wills91312c72016-04-06 17:03:35 -07001348 synchronized (mListenerMapLock) {
1349 mListenerMap.remove(key);
Vinit Deshapnde011e1b32014-05-07 21:09:11 -07001350 return key;
1351 }
1352 }
1353
Vinit Deshpandee344cb22014-06-03 15:55:36 -07001354 /** @hide */
1355 public static class OperationResult implements Parcelable {
1356 public int reason;
1357 public String description;
1358
1359 public OperationResult(int reason, String description) {
1360 this.reason = reason;
1361 this.description = description;
1362 }
1363
1364 /** Implement the Parcelable interface {@hide} */
1365 public int describeContents() {
1366 return 0;
1367 }
1368
1369 /** Implement the Parcelable interface {@hide} */
1370 public void writeToParcel(Parcel dest, int flags) {
1371 dest.writeInt(reason);
1372 dest.writeString(description);
1373 }
1374
1375 /** Implement the Parcelable interface {@hide} */
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -07001376 public static final @android.annotation.NonNull Creator<OperationResult> CREATOR =
Vinit Deshpandee344cb22014-06-03 15:55:36 -07001377 new Creator<OperationResult>() {
1378 public OperationResult createFromParcel(Parcel in) {
1379 int reason = in.readInt();
1380 String description = in.readString();
1381 return new OperationResult(reason, description);
1382 }
1383
1384 public OperationResult[] newArray(int size) {
1385 return new OperationResult[size];
1386 }
1387 };
1388 }
1389
Mitchell Wills91312c72016-04-06 17:03:35 -07001390 private class ServiceHandler extends Handler {
Vinit Deshapnde011e1b32014-05-07 21:09:11 -07001391 ServiceHandler(Looper looper) {
1392 super(looper);
1393 }
1394 @Override
1395 public void handleMessage(Message msg) {
1396 switch (msg.what) {
Vinit Deshapnde011e1b32014-05-07 21:09:11 -07001397 case AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED:
1398 return;
1399 case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
1400 Log.e(TAG, "Channel connection lost");
1401 // This will cause all further async API calls on the WifiManager
1402 // to fail and throw an exception
Mitchell Wills91312c72016-04-06 17:03:35 -07001403 mAsyncChannel = null;
Vinit Deshapnde011e1b32014-05-07 21:09:11 -07001404 getLooper().quit();
1405 return;
1406 }
1407
1408 Object listener = getListener(msg.arg2);
Vinit Deshpande7686c062014-06-30 15:25:01 -07001409
1410 if (listener == null) {
1411 if (DBG) Log.d(TAG, "invalid listener key = " + msg.arg2);
1412 return;
1413 } else {
1414 if (DBG) Log.d(TAG, "listener key = " + msg.arg2);
1415 }
Vinit Deshapnde011e1b32014-05-07 21:09:11 -07001416
1417 switch (msg.what) {
1418 /* ActionListeners grouped together */
1419 case CMD_OP_SUCCEEDED :
Vinit Deshpande55027bb2014-05-29 15:58:48 -07001420 ((ActionListener) listener).onSuccess();
Vinit Deshapnde011e1b32014-05-07 21:09:11 -07001421 break;
Vinit Deshpandee344cb22014-06-03 15:55:36 -07001422 case CMD_OP_FAILED : {
1423 OperationResult result = (OperationResult)msg.obj;
1424 ((ActionListener) listener).onFailure(result.reason, result.description);
1425 removeListener(msg.arg2);
1426 }
Vinit Deshapnde011e1b32014-05-07 21:09:11 -07001427 break;
1428 case CMD_SCAN_RESULT :
1429 ((ScanListener) listener).onResults(
Vinit Deshpandef45acfe2014-10-30 11:01:25 -07001430 ((ParcelableScanData) msg.obj).getResults());
Vinit Deshapnde011e1b32014-05-07 21:09:11 -07001431 return;
1432 case CMD_FULL_SCAN_RESULT :
Vinit Deshpande55027bb2014-05-29 15:58:48 -07001433 ScanResult result = (ScanResult) msg.obj;
Vinit Deshapnde011e1b32014-05-07 21:09:11 -07001434 ((ScanListener) listener).onFullResult(result);
1435 return;
Vinit Deshpandef45acfe2014-10-30 11:01:25 -07001436 case CMD_SINGLE_SCAN_COMPLETED:
Vinit Deshpandeed10e292015-06-03 18:00:38 -07001437 if (DBG) Log.d(TAG, "removing listener for single scan");
Vinit Deshpandef45acfe2014-10-30 11:01:25 -07001438 removeListener(msg.arg2);
1439 break;
Roshan Piuse4fd1502016-03-01 13:18:41 -08001440 case CMD_PNO_NETWORK_FOUND:
1441 ((PnoScanListener) listener).onPnoNetworkFound(
1442 ((ParcelableScanResults) msg.obj).getResults());
1443 return;
Vinit Deshapnde011e1b32014-05-07 21:09:11 -07001444 default:
1445 if (DBG) Log.d(TAG, "Ignoring message " + msg.what);
1446 return;
1447 }
1448 }
1449 }
1450}