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 android.net.wifi; 18 19import android.os.Parcelable; 20import android.os.Parcel; 21 22import java.util.ArrayList; 23import java.util.Collection; 24 25/** 26 * Describes the settings for batched wifi scans where the firmware performs many 27 * scans and stores the timestamped results without waking the main processor each time. 28 * This can give information over time with minimal battery impact. 29 * @hide pending review 30 */ 31public class BatchedScanSettings implements Parcelable { 32 private static final String TAG = "BatchedScanSettings"; 33 34 /** Used to indicate no preference for an int value */ 35 public final static int UNSPECIFIED = Integer.MAX_VALUE; 36 37 // TODO - make MIN/mAX dynamic and gservices adjustable. 38 public final static int MIN_SCANS_PER_BATCH = 2; 39 public final static int MAX_SCANS_PER_BATCH = 255; 40 public final static int DEFAULT_SCANS_PER_BATCH = MAX_SCANS_PER_BATCH; 41 42 public final static int MIN_AP_PER_SCAN = 2; 43 public final static int MAX_AP_PER_SCAN = 255; 44 public final static int DEFAULT_AP_PER_SCAN = 16; 45 46 public final static int MIN_INTERVAL_SEC = 0; 47 public final static int MAX_INTERVAL_SEC = 3600; 48 public final static int DEFAULT_INTERVAL_SEC = 30; 49 50 public final static int MIN_AP_FOR_DISTANCE = 0; 51 public final static int MAX_AP_FOR_DISTANCE = MAX_AP_PER_SCAN; 52 public final static int DEFAULT_AP_FOR_DISTANCE = 0; 53 54 public final static int MAX_WIFI_CHANNEL = 196; 55 56 /** The expected number of scans per batch. Note that the firmware may drop scans 57 * leading to fewer scans during the normal batch scan duration. This value need not 58 * be specified (may be set to {@link UNSPECIFIED}) by the application and we will try 59 * to scan as many times as the firmware can support. If another app requests fewer 60 * scans per batch we will attempt to honor that. 61 */ 62 public int maxScansPerBatch; 63 64 /** The maximum desired AP listed per scan. Fewer AP may be returned if that's all 65 * that the driver detected. If another application requests more AP per scan that 66 * will take precedence. The if more channels are detected than we request, the APs 67 * with the lowest signal strength will be dropped. 68 */ 69 public int maxApPerScan; 70 71 /** The channels used in the scan. If all channels should be used, {@code null} may be 72 * specified. If another application requests more channels or all channels, that 73 * will take precedence. 74 */ 75 public Collection<String> channelSet; 76 77 /** The time between the start of two sequential scans, in seconds. If another 78 * application requests more frequent scans, that will take precedence. If this 79 * value is less than the duration of a scan, the next scan should start immediately. 80 */ 81 public int scanIntervalSec; 82 83 /** The number of the best (strongest signal) APs for which the firmware will 84 * attempt to get distance information (RTT). Not all firmware supports this 85 * feature, so it may be ignored. If another application requests a greater 86 * number, that will take precedence. 87 */ 88 public int maxApForDistance; 89 90 public BatchedScanSettings() { 91 clear(); 92 } 93 94 public void clear() { 95 maxScansPerBatch = UNSPECIFIED; 96 maxApPerScan = UNSPECIFIED; 97 channelSet = null; 98 scanIntervalSec = UNSPECIFIED; 99 maxApForDistance = UNSPECIFIED; 100 } 101 102 public BatchedScanSettings(BatchedScanSettings source) { 103 maxScansPerBatch = source.maxScansPerBatch; 104 maxApPerScan = source.maxApPerScan; 105 if (source.channelSet != null) { 106 channelSet = new ArrayList(source.channelSet); 107 } 108 scanIntervalSec = source.scanIntervalSec; 109 maxApForDistance = source.maxApForDistance; 110 } 111 112 private boolean channelSetIsValid() { 113 if (channelSet == null || channelSet.isEmpty()) return true; 114 for (String channel : channelSet) { 115 try { 116 int i = Integer.parseInt(channel); 117 if (i > 0 && i <= MAX_WIFI_CHANNEL) continue; 118 } catch (NumberFormatException e) {} 119 if (channel.equals("A") || channel.equals("B")) continue; 120 return false; 121 } 122 return true; 123 } 124 /** @hide */ 125 public boolean isInvalid() { 126 if (maxScansPerBatch != UNSPECIFIED && (maxScansPerBatch < MIN_SCANS_PER_BATCH || 127 maxScansPerBatch > MAX_SCANS_PER_BATCH)) return true; 128 if (maxApPerScan != UNSPECIFIED && (maxApPerScan < MIN_AP_PER_SCAN || 129 maxApPerScan > MAX_AP_PER_SCAN)) return true; 130 if (channelSetIsValid() == false) return true; 131 if (scanIntervalSec != UNSPECIFIED && (scanIntervalSec < MIN_INTERVAL_SEC || 132 scanIntervalSec > MAX_INTERVAL_SEC)) return true; 133 if (maxApForDistance != UNSPECIFIED && (maxApForDistance < MIN_AP_FOR_DISTANCE || 134 maxApForDistance > MAX_AP_FOR_DISTANCE)) return true; 135 return false; 136 } 137 138 /** @hide */ 139 public void constrain() { 140 if (scanIntervalSec == UNSPECIFIED) { 141 scanIntervalSec = DEFAULT_INTERVAL_SEC; 142 } else if (scanIntervalSec < MIN_INTERVAL_SEC) { 143 scanIntervalSec = MIN_INTERVAL_SEC; 144 } else if (scanIntervalSec > MAX_INTERVAL_SEC) { 145 scanIntervalSec = MAX_INTERVAL_SEC; 146 } 147 148 if (maxScansPerBatch == UNSPECIFIED) { 149 maxScansPerBatch = DEFAULT_SCANS_PER_BATCH; 150 } else if (maxScansPerBatch < MIN_SCANS_PER_BATCH) { 151 maxScansPerBatch = MIN_SCANS_PER_BATCH; 152 } else if (maxScansPerBatch > MAX_SCANS_PER_BATCH) { 153 maxScansPerBatch = MAX_SCANS_PER_BATCH; 154 } 155 156 if (maxApPerScan == UNSPECIFIED) { 157 maxApPerScan = DEFAULT_AP_PER_SCAN; 158 } else if (maxApPerScan < MIN_AP_PER_SCAN) { 159 maxApPerScan = MIN_AP_PER_SCAN; 160 } else if (maxApPerScan > MAX_AP_PER_SCAN) { 161 maxApPerScan = MAX_AP_PER_SCAN; 162 } 163 164 if (maxApForDistance == UNSPECIFIED) { 165 maxApForDistance = DEFAULT_AP_FOR_DISTANCE; 166 } else if (maxApForDistance < MIN_AP_FOR_DISTANCE) { 167 maxApForDistance = MIN_AP_FOR_DISTANCE; 168 } else if (maxApForDistance > MAX_AP_FOR_DISTANCE) { 169 maxApForDistance = MAX_AP_FOR_DISTANCE; 170 } 171 } 172 173 174 @Override 175 public boolean equals(Object obj) { 176 if (obj instanceof BatchedScanSettings == false) return false; 177 BatchedScanSettings o = (BatchedScanSettings)obj; 178 if (maxScansPerBatch != o.maxScansPerBatch || 179 maxApPerScan != o.maxApPerScan || 180 scanIntervalSec != o.scanIntervalSec || 181 maxApForDistance != o.maxApForDistance) return false; 182 if (channelSet == null) { 183 return (o.channelSet == null); 184 } 185 return channelSet.equals(o.channelSet); 186 } 187 188 @Override 189 public int hashCode() { 190 return maxScansPerBatch + 191 (maxApPerScan * 3) + 192 (scanIntervalSec * 5) + 193 (maxApForDistance * 7) + 194 (channelSet.hashCode() * 11); 195 } 196 197 @Override 198 public String toString() { 199 StringBuffer sb = new StringBuffer(); 200 String none = "<none>"; 201 202 sb.append("BatchScanSettings [maxScansPerBatch: "). 203 append(maxScansPerBatch == UNSPECIFIED ? none : maxScansPerBatch). 204 append(", maxApPerScan: ").append(maxApPerScan == UNSPECIFIED? none : maxApPerScan). 205 append(", scanIntervalSec: "). 206 append(scanIntervalSec == UNSPECIFIED ? none : scanIntervalSec). 207 append(", maxApForDistance: "). 208 append(maxApForDistance == UNSPECIFIED ? none : maxApForDistance). 209 append(", channelSet: "); 210 if (channelSet == null) { 211 sb.append("ALL"); 212 } else { 213 sb.append("<"); 214 for (String channel : channelSet) { 215 sb.append(" " + channel); 216 } 217 sb.append(">"); 218 } 219 sb.append("]"); 220 return sb.toString(); 221 } 222 223 /** Implement the Parcelable interface {@hide} */ 224 public int describeContents() { 225 return 0; 226 } 227 228 /** Implement the Parcelable interface {@hide} */ 229 public void writeToParcel(Parcel dest, int flags) { 230 dest.writeInt(maxScansPerBatch); 231 dest.writeInt(maxApPerScan); 232 dest.writeInt(scanIntervalSec); 233 dest.writeInt(maxApForDistance); 234 dest.writeInt(channelSet == null ? 0 : channelSet.size()); 235 if (channelSet != null) { 236 for (String channel : channelSet) dest.writeString(channel); 237 } 238 } 239 240 /** Implement the Parcelable interface {@hide} */ 241 public static final Creator<BatchedScanSettings> CREATOR = 242 new Creator<BatchedScanSettings>() { 243 public BatchedScanSettings createFromParcel(Parcel in) { 244 BatchedScanSettings settings = new BatchedScanSettings(); 245 settings.maxScansPerBatch = in.readInt(); 246 settings.maxApPerScan = in.readInt(); 247 settings.scanIntervalSec = in.readInt(); 248 settings.maxApForDistance = in.readInt(); 249 int channelCount = in.readInt(); 250 if (channelCount > 0) { 251 settings.channelSet = new ArrayList(channelCount); 252 while (channelCount-- > 0) { 253 settings.channelSet.add(in.readString()); 254 } 255 } 256 return settings; 257 } 258 259 public BatchedScanSettings[] newArray(int size) { 260 return new BatchedScanSettings[size]; 261 } 262 }; 263} 264