diff options
Diffstat (limited to 'wifi/java/android')
19 files changed, 1692 insertions, 105 deletions
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl index 0535fe0..9ccd810 100644 --- a/wifi/java/android/net/wifi/IWifiManager.aidl +++ b/wifi/java/android/net/wifi/IWifiManager.aidl @@ -111,8 +111,6 @@ interface IWifiManager Messenger getWifiServiceMessenger(); - Messenger getWifiStateMachineMessenger(); - String getConfigFile(); void enableTdls(String remoteIPAddress, boolean enable); diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java index 1cb9546..3e3b6e3 100644 --- a/wifi/java/android/net/wifi/ScanResult.java +++ b/wifi/java/android/net/wifi/ScanResult.java @@ -16,6 +16,8 @@ package android.net.wifi; +import android.net.wifi.passpoint.PasspointInfo; +import android.net.wifi.passpoint.PasspointManager; import android.os.Parcelable; import android.os.Parcel; @@ -77,6 +79,13 @@ public class ScanResult implements Parcelable { public int distanceSdCm; /** + * Passpoint ANQP information. This is not fetched automatically. + * Use {@link PasspointManager#requestAnqpInfo} to request ANQP info. + * {@hide} + */ + public PasspointInfo passpoint; + + /** * {@hide} */ public final static int UNSPECIFIED = -1; @@ -122,6 +131,8 @@ public class ScanResult implements Parcelable { distanceCm = source.distanceCm; distanceSdCm = source.distanceSdCm; seen = source.seen; + if (source.passpoint != null) + passpoint = new PasspointInfo(source.passpoint); } } @@ -155,6 +166,9 @@ public class ScanResult implements Parcelable { sb.append(", distanceSd: ").append((distanceSdCm != UNSPECIFIED ? distanceSdCm : "?")). append("(cm)"); + if (passpoint != null) + sb.append(", passpoint: [").append(passpoint.toString()).append("]"); + return sb.toString(); } @@ -178,6 +192,12 @@ public class ScanResult implements Parcelable { dest.writeLong(timestamp); dest.writeInt(distanceCm); dest.writeInt(distanceSdCm); + if (passpoint != null) { + dest.writeInt(1); + passpoint.writeToParcel(dest, flags); + } else { + dest.writeInt(0); + } } /** Implement the Parcelable interface {@hide} */ @@ -188,7 +208,7 @@ public class ScanResult implements Parcelable { if (in.readInt() == 1) { wifiSsid = WifiSsid.CREATOR.createFromParcel(in); } - return new ScanResult( + ScanResult sr = new ScanResult( wifiSsid, in.readString(), in.readString(), @@ -198,6 +218,10 @@ public class ScanResult implements Parcelable { in.readInt(), in.readInt() ); + if (in.readInt() == 1) { + sr.passpoint = PasspointInfo.CREATOR.createFromParcel(in); + } + return sr; } public ScanResult[] newArray(int size) { diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java index 85b81d9..e73cce1 100644 --- a/wifi/java/android/net/wifi/WifiConfiguration.java +++ b/wifi/java/android/net/wifi/WifiConfiguration.java @@ -417,6 +417,12 @@ public class WifiConfiguration implements Parcelable { public int autoJoinStatus; /** + * Set if the configuration was self added by the framework + * @hide + */ + public boolean selfAdded; + + /** * @hide * Indicate that a WifiConfiguration is temporary and should not be saved * nor considered by AutoJoin. @@ -498,6 +504,8 @@ public class WifiConfiguration implements Parcelable { proxySettings = ProxySettings.UNASSIGNED; linkProperties = new LinkProperties(); autoJoinStatus = AUTO_JOIN_ENABLED; + selfAdded = false; + ephemeral = false; } /** @@ -794,8 +802,28 @@ public class WifiConfiguration implements Parcelable { return configKey(false); } + /** @hide + * return the config key string based on a scan result + */ + static public String configKey(ScanResult result) { + String key = "\"" + result.SSID + "\""; + + if (result.capabilities.contains("WEP")) { + key = key + "-WEP"; + } - /** Implement the Parcelable interface {@hide} */ + if (result.capabilities.contains("PSK")) { + key = key + "-" + KeyMgmt.strings[KeyMgmt.WPA_PSK]; + } + + if (result.capabilities.contains("EAP")) { + key = key + "-" + KeyMgmt.strings[KeyMgmt.WPA_EAP]; + } + + return key; + } + + /** Implement the Parcelable interface {@hide} */ public int describeContents() { return 0; } @@ -849,6 +877,7 @@ public class WifiConfiguration implements Parcelable { } mCachedConfigKey = null; //force null configKey autoJoinStatus = source.autoJoinStatus; + selfAdded = source.selfAdded; if (source.visibility != null) { visibility = new Visibility(source.visibility); @@ -886,6 +915,7 @@ public class WifiConfiguration implements Parcelable { dest.writeString(dhcpServer); dest.writeString(defaultGwMacAddress); dest.writeInt(autoJoinStatus); + dest.writeInt(selfAdded ? 1 : 0); } /** Implement the Parcelable interface {@hide} */ @@ -920,7 +950,7 @@ public class WifiConfiguration implements Parcelable { config.dhcpServer = in.readString(); config.defaultGwMacAddress = in.readString(); config.autoJoinStatus = in.readInt(); - + config.selfAdded = in.readInt() != 0; return config; } diff --git a/wifi/java/android/net/wifi/WifiLinkLayerStats.java b/wifi/java/android/net/wifi/WifiLinkLayerStats.java new file mode 100644 index 0000000..922eddd --- /dev/null +++ b/wifi/java/android/net/wifi/WifiLinkLayerStats.java @@ -0,0 +1,189 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.wifi; + +import android.os.Parcelable; +import android.os.Parcel; +import android.text.TextUtils; +import java.util.HashMap; +import java.util.Date; +import java.util.ArrayList; + +import java.util.BitSet; + +/** + * A class representing link layer statistics collected over a Wifi Interface. + */ +/** {@hide} */ +public class WifiLinkLayerStats implements Parcelable { + private static final String TAG = "WifiLinkLayerStats"; + + /** + * The current status of this network configuration entry. + * @see Status + */ + /** {@hide} */ + public int status; + + /** + * The network's SSID. Can either be an ASCII string, + * which must be enclosed in double quotation marks + * (e.g., {@code "MyNetwork"}, or a string of + * hex digits,which are not enclosed in quotes + * (e.g., {@code 01a243f405}). + */ + /** {@hide} */ + public String SSID; + /** + * When set. this is the BSSID the radio is currently associated with. + * The value is a string in the format of an Ethernet MAC address, e.g., + * <code>XX:XX:XX:XX:XX:XX</code> where each <code>X</code> is a hex digit. + */ + /** {@hide} */ + public String BSSID; + + /* number beacons received from our own AP */ + /** {@hide} */ + public int beacon_rx; + + /* RSSI taken on management frames */ + /** {@hide} */ + public int rssi_mgmt; + + /* packets counters */ + /** {@hide} */ + /* WME Best Effort Access Category (receive mpdu, transmit mpdu, lost mpdu, number of retries)*/ + public long rxmpdu_be; + /** {@hide} */ + public long txmpdu_be; + /** {@hide} */ + public long lostmpdu_be; + /** {@hide} */ + public long retries_be; + /** {@hide} */ + /* WME Background Access Category (receive mpdu, transmit mpdu, lost mpdu, number of retries) */ + public long rxmpdu_bk; + /** {@hide} */ + public long txmpdu_bk; + /** {@hide} */ + public long lostmpdu_bk; + /** {@hide} */ + public long retries_bk; + /** {@hide} */ + /* WME Video Access Category (receive mpdu, transmit mpdu, lost mpdu, number of retries) */ + public long rxmpdu_vi; + /** {@hide} */ + public long txmpdu_vi; + /** {@hide} */ + public long lostmpdu_vi; + /** {@hide} */ + public long retries_vi; + /** {@hide} */ + /* WME Voice Access Category (receive mpdu, transmit mpdu, lost mpdu, number of retries) */ + public long rxmpdu_vo; + /** {@hide} */ + public long txmpdu_vo; + /** {@hide} */ + public long lostmpdu_vo; + /** {@hide} */ + public long retries_vo; + + + /** {@hide} */ + public WifiLinkLayerStats() { + } + + @Override + /** {@hide} */ + public String toString() { + StringBuilder sbuf = new StringBuilder(); + if (this.SSID != null) { + sbuf.append(" SSID: ").append(this.SSID).append('\n'); + } + if (this.BSSID != null) { + sbuf.append(" BSSID: ").append(this.BSSID).append('\n'); + } + + sbuf.append(" my bss beacon rx: ").append(Integer.toString(this.beacon_rx)).append('\n'); + sbuf.append(" RSSI mgmt: ").append(Integer.toString(this.rssi_mgmt)).append('\n'); + sbuf.append(" BE : ").append(" rx=").append(Long.toString(this.rxmpdu_be)) + .append(" tx=").append(Long.toString(this.txmpdu_be)) + .append(" lost=").append(Long.toString(this.lostmpdu_be)) + .append(" retries=").append(Long.toString(this.retries_be)).append('\n'); + sbuf.append(" BK : ").append(" rx=").append(Long.toString(this.rxmpdu_bk)) + .append(" tx=").append(Long.toString(this.txmpdu_bk)) + .append(" lost=").append(Long.toString(this.lostmpdu_bk)) + .append(" retries=").append(Long.toString(this.retries_bk)).append('\n'); + sbuf.append(" VI : ").append(" rx=").append(Long.toString(this.rxmpdu_vi)) + .append(" tx=").append(Long.toString(this.txmpdu_vi)) + .append(" lost=").append(Long.toString(this.lostmpdu_vi)) + .append(" retries=").append(Long.toString(this.retries_vi)).append('\n'); + sbuf.append(" VO : ").append(" rx=").append(Long.toString(this.rxmpdu_vo)) + .append(" tx=").append(Long.toString(this.txmpdu_vo)) + .append(" lost=").append(Long.toString(this.lostmpdu_vo)) + .append(" retries=").append(Long.toString(this.retries_vo)).append('\n'); + + return sbuf.toString(); + } + + /** Implement the Parcelable interface {@hide} */ + public int describeContents() { + return 0; + } + + /** {@hide} */ + public String getPrintableSsid() { + if (SSID == null) return ""; + final int length = SSID.length(); + if (length > 2 && (SSID.charAt(0) == '"') && SSID.charAt(length - 1) == '"') { + return SSID.substring(1, length - 1); + } + + /** The ascii-encoded string format is P"<ascii-encoded-string>" + * The decoding is implemented in the supplicant for a newly configured + * network. + */ + if (length > 3 && (SSID.charAt(0) == 'P') && (SSID.charAt(1) == '"') && + (SSID.charAt(length-1) == '"')) { + WifiSsid wifiSsid = WifiSsid.createFromAsciiEncoded( + SSID.substring(2, length - 1)); + return wifiSsid.toString(); + } + return SSID; + } + + /** Implement the Parcelable interface {@hide} */ + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(SSID); + dest.writeString(BSSID); + } + + /** Implement the Parcelable interface {@hide} */ + public static final Creator<WifiLinkLayerStats> CREATOR = + new Creator<WifiLinkLayerStats>() { + public WifiLinkLayerStats createFromParcel(Parcel in) { + WifiLinkLayerStats stats = new WifiLinkLayerStats(); + stats.SSID = in.readString(); + stats.BSSID = in.readString(); + return stats; + }; + public WifiLinkLayerStats[] newArray(int size) { + return new WifiLinkLayerStats[size]; + } + + }; +} diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java index 15b65c1..9558d50 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -1783,18 +1783,6 @@ public class WifiManager { } } - /** - * Get a reference to WifiStateMachine handler. - * @return Messenger pointing to the WifiService handler - * @hide - */ - public Messenger getWifiStateMachineMessenger() { - try { - return mService.getWifiStateMachineMessenger(); - } catch (RemoteException e) { - return null; - } - } /** * Returns the file in which IP and proxy configuration data is stored diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java index e02e14c..9ea7027 100644 --- a/wifi/java/android/net/wifi/WifiScanner.java +++ b/wifi/java/android/net/wifi/WifiScanner.java @@ -31,7 +31,6 @@ import android.util.SparseArray; import com.android.internal.util.AsyncChannel; import com.android.internal.util.Protocol; -import java.util.ArrayList; import java.util.List; import java.util.concurrent.CountDownLatch; @@ -41,27 +40,45 @@ import java.util.concurrent.CountDownLatch; * Get an instance of this class by calling * {@link android.content.Context#getSystemService(String) Context.getSystemService(Context * .WIFI_SCANNING_SERVICE)}. - * @hide */ public class WifiScanner { + /** no band specified; use channel list instead */ public static final int WIFI_BAND_UNSPECIFIED = 0; /* not specified */ + + /** 2.4 GHz band */ public static final int WIFI_BAND_24_GHZ = 1; /* 2.4 GHz band */ + /** 5 GHz band excluding DFS channels */ public static final int WIFI_BAND_5_GHZ = 2; /* 5 GHz band without DFS channels */ + /** DFS channels from 5 GHz band only */ public static final int WIFI_BAND_5_GHZ_DFS_ONLY = 4; /* 5 GHz band with DFS channels */ + /** 5 GHz band including DFS channels */ public static final int WIFI_BAND_5_GHZ_WITH_DFS = 6; /* 5 GHz band with DFS channels */ + /** Both 2.4 GHz band and 5 GHz band; no DFS channels */ public static final int WIFI_BAND_BOTH = 3; /* both bands without DFS channels */ + /** Both 2.4 GHz band and 5 GHz band; with DFS channels */ public static final int WIFI_BAND_BOTH_WITH_DFS = 7; /* both bands with DFS channels */ - public static final int MIN_SCAN_PERIOD_MS = 300; /* minimum supported period */ + /** Minimum supported scanning period */ + public static final int MIN_SCAN_PERIOD_MS = 2000; /* minimum supported period */ + /** Maximum supported scanning period */ public static final int MAX_SCAN_PERIOD_MS = 1024000; /* maximum supported period */ + /** No Error */ public static final int REASON_SUCCEEDED = 0; + /** Unknown error */ public static final int REASON_UNSPECIFIED = -1; + /** Invalid listener */ public static final int REASON_INVALID_LISTENER = -2; + /** Invalid request */ public static final int REASON_INVALID_REQUEST = -3; + /** Request conflicts with other scans that may be going on */ public static final int REASON_CONFLICTING_REQUEST = -4; + /** + * Generic action callback invocation interface + * @hide + */ public static interface ActionListener { public void onSuccess(Object result); public void onFailure(int reason, Object exception); @@ -70,19 +87,35 @@ public class WifiScanner { /** * gives you all the possible channels; channel is specified as an * integer with frequency in MHz i.e. channel 1 is 2412 + * @hide */ public List<Integer> getAvailableChannels(int band) { return null; } /** - * provides channel specification to the APIs + * provides channel specification for scanning */ public static class ChannelSpec { + /** + * channel frequency in KHz; for example channel 1 is specified as 2412 + */ public int frequency; + /** + * if true, scan this channel in passive fashion. + * This flag is ignored on DFS channel specification. + * @hide + */ public boolean passive; /* ignored on DFS channels */ + /** + * how long to dwell on this channel + * @hide + */ public int dwellTimeMS; /* not supported for now */ + /** + * default constructor for channel spec + */ public ChannelSpec(int frequency) { this.frequency = frequency; passive = false; @@ -90,19 +123,26 @@ public class WifiScanner { } } + /** reports {@link ScanListener#onResults} when underlying buffers are full */ public static final int REPORT_EVENT_AFTER_BUFFER_FULL = 0; + /** reports {@link ScanListener#onResults} after each scan */ public static final int REPORT_EVENT_AFTER_EACH_SCAN = 1; + /** reports {@link ScanListener#onFullResult} whenever each beacon is discovered */ public static final int REPORT_EVENT_FULL_SCAN_RESULT = 2; /** - * scan configuration parameters + * scan configuration parameters to be sent to {@link #startBackgroundScan} */ public static class ScanSettings implements Parcelable { - public int band; /* ignore channels if specified */ - public ChannelSpec[] channels; /* list of channels to scan */ - public int periodInMs; /* period of scan */ - public int reportEvents; /* a valid REPORT_EVENT value */ + /** one of the WIFI_BAND values */ + public int band; + /** list of channels; used when band is set to WIFI_BAND_UNSPECIFIED */ + public ChannelSpec[] channels; + /** period of background scan; in millisecond */ + public int periodInMs; + /** must have a valid REPORT_EVENT value */ + public int reportEvents; /** Implement the Parcelable interface {@hide} */ public int describeContents() { @@ -113,6 +153,7 @@ public class WifiScanner { public void writeToParcel(Parcel dest, int flags) { dest.writeInt(band); dest.writeInt(periodInMs); + dest.writeInt(reportEvents); dest.writeInt(channels.length); for (int i = 0; i < channels.length; i++) { @@ -130,6 +171,7 @@ public class WifiScanner { ScanSettings settings = new ScanSettings(); settings.band = in.readInt(); settings.periodInMs = in.readInt(); + settings.reportEvents = in.readInt(); int num_channels = in.readInt(); settings.channels = new ChannelSpec[num_channels]; for (int i = 0; i < num_channels; i++) { @@ -151,14 +193,56 @@ public class WifiScanner { } + /** information element from beacon */ public static class InformationElement { public int id; public byte[] bytes; } - public static class FullScanResult { + /** scan result with information elements from beacons */ + public static class FullScanResult implements Parcelable { public ScanResult result; public InformationElement informationElements[]; + + /** Implement the Parcelable interface {@hide} */ + public int describeContents() { + return 0; + } + + /** Implement the Parcelable interface {@hide} */ + public void writeToParcel(Parcel dest, int flags) { + result.writeToParcel(dest, flags); + dest.writeInt(informationElements.length); + for (int i = 0; i < informationElements.length; i++) { + dest.writeInt(informationElements[i].id); + dest.writeInt(informationElements[i].bytes.length); + dest.writeByteArray(informationElements[i].bytes); + } + } + + /** Implement the Parcelable interface {@hide} */ + public static final Creator<FullScanResult> CREATOR = + new Creator<FullScanResult>() { + public FullScanResult createFromParcel(Parcel in) { + FullScanResult result = new FullScanResult(); + result.result = ScanResult.CREATOR.createFromParcel(in); + int n = in.readInt(); + result.informationElements = new InformationElement[n]; + for (int i = 0; i < n; i++) { + result.informationElements[i] = new InformationElement(); + result.informationElements[i].id = in.readInt(); + int len = in.readInt(); + result.informationElements[i].bytes = new byte[len]; + in.readByteArray(result.informationElements[i].bytes); + } + + return result; + } + + public FullScanResult[] newArray(int size) { + return new FullScanResult[size]; + } + }; } /** @hide */ @@ -206,88 +290,210 @@ public class WifiScanner { } /** - * Framework is co-ordinating scans across multiple apps; so it may not give exactly the - * same period requested. The period granted is stated on the onSuccess() event; and - * onPeriodChanged() will be called if/when it is changed because of multiple conflicting - * requests. This is similar to the way timers are handled. + * interface to get scan events on; specify this on {@link #startBackgroundScan} */ public interface ScanListener extends ActionListener { + /** + * Framework co-ordinates scans across multiple apps; so it may not give exactly the + * same period requested. If period of a scan is changed; it is reported by this event. + */ public void onPeriodChanged(int periodInMs); + /** + * reports results retrieved from background scan + */ public void onResults(ScanResult[] results); + /** + * reports full scan result for each access point found in scan + */ public void onFullResult(FullScanResult fullScanResult); } + /** @hide */ public void scan(ScanSettings settings, ScanListener listener) { validateChannel(); sAsyncChannel.sendMessage(CMD_SCAN, 0, putListener(listener), settings); } + + /** start wifi scan in background + * @param settings specifies various parameters for the scan; for more information look at + * {@link ScanSettings} + * @param listener specifies the object to report events to. This object is also treated as a + * key for this scan, and must also be specified to cancel the scan. Multiple + * scans should also not share this object. + */ public void startBackgroundScan(ScanSettings settings, ScanListener listener) { validateChannel(); sAsyncChannel.sendMessage(CMD_START_BACKGROUND_SCAN, 0, putListener(listener), settings); } - public void stopBackgroundScan(boolean flush, ScanListener listener) { + /** + * stop an ongoing wifi scan + * @param listener specifies which scan to cancel; must be same object as passed in {@link + * #startBackgroundScan} + */ + public void stopBackgroundScan(ScanListener listener) { validateChannel(); sAsyncChannel.sendMessage(CMD_STOP_BACKGROUND_SCAN, 0, removeListener(listener)); } + /** + * retrieves currently available scan results + * @param flush {@code true} means flush all results + * @param listener specifies which scan to cancel; must be same object as passed in {@link + * #startBackgroundScan} + */ public void retrieveScanResults(boolean flush, ScanListener listener) { validateChannel(); sAsyncChannel.sendMessage(CMD_GET_SCAN_RESULTS, 0, getListenerKey(listener)); } + /** specifies information about an access point of interest */ public static class HotspotInfo { + /** bssid of the access point; in XX:XX:XX:XX:XX:XX format */ public String bssid; + /** low signal strength threshold; more information at {@link ScanResult#level} */ public int low; /* minimum RSSI */ + /** high signal threshold; more information at {@link ScanResult#level} */ public int high; /* maximum RSSI */ + /** channel frequency (in KHz) where you may find this BSSID */ + public int frequencyHint; } - public static class WifiChangeSettings { - public int rssiSampleSize; /* sample size for RSSI averaging */ - public int lostApSampleSize; /* samples to confirm AP's loss */ - public int unchangedSampleSize; /* samples to confirm no change */ - public int minApsBreachingThreshold; /* change threshold to trigger event */ + /** @hide */ + public static class WifiChangeSettings implements Parcelable { + public int rssiSampleSize; /* sample size for RSSI averaging */ + public int lostApSampleSize; /* samples to confirm AP's loss */ + public int unchangedSampleSize; /* samples to confirm no change */ + public int minApsBreachingThreshold; /* change threshold to trigger event */ + public int periodInMs; /* scan period in millisecond */ public HotspotInfo[] hotspotInfos; + + /** Implement the Parcelable interface {@hide} */ + public int describeContents() { + return 0; + } + + /** Implement the Parcelable interface {@hide} */ + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(rssiSampleSize); + dest.writeInt(lostApSampleSize); + dest.writeInt(unchangedSampleSize); + dest.writeInt(minApsBreachingThreshold); + dest.writeInt(periodInMs); + dest.writeInt(hotspotInfos.length); + for (int i = 0; i < hotspotInfos.length; i++) { + HotspotInfo info = hotspotInfos[i]; + dest.writeString(info.bssid); + dest.writeInt(info.low); + dest.writeInt(info.high); + dest.writeInt(info.frequencyHint); + } + } + + /** Implement the Parcelable interface {@hide} */ + public static final Creator<WifiChangeSettings> CREATOR = + new Creator<WifiChangeSettings>() { + public WifiChangeSettings createFromParcel(Parcel in) { + WifiChangeSettings settings = new WifiChangeSettings(); + settings.rssiSampleSize = in.readInt(); + settings.lostApSampleSize = in.readInt(); + settings.unchangedSampleSize = in.readInt(); + settings.minApsBreachingThreshold = in.readInt(); + settings.periodInMs = in.readInt(); + int len = in.readInt(); + settings.hotspotInfos = new HotspotInfo[len]; + for (int i = 0; i < len; i++) { + HotspotInfo info = new HotspotInfo(); + info.bssid = in.readString(); + info.low = in.readInt(); + info.high = in.readInt(); + info.frequencyHint = in.readInt(); + settings.hotspotInfos[i] = info; + } + return settings; + } + + public WifiChangeSettings[] newArray(int size) { + return new WifiChangeSettings[size]; + } + }; + } - /* overrides the significant wifi change state machine configuration */ - public void configureSignificantWifiChange( + /** configure WifiChange detection + * @param rssiSampleSize number of samples used for RSSI averaging + * @param lostApSampleSize number of samples to confirm an access point's loss + * @param unchangedSampleSize number of samples to confirm there are no changes + * @param minApsBreachingThreshold minimum number of access points that need to be + * out of range to detect WifiChange + * @param periodInMs indicates period of scan to find changes + * @param hotspotInfos access points to watch + */ + public void configureWifiChange( int rssiSampleSize, /* sample size for RSSI averaging */ int lostApSampleSize, /* samples to confirm AP's loss */ int unchangedSampleSize, /* samples to confirm no change */ int minApsBreachingThreshold, /* change threshold to trigger event */ + int periodInMs, /* period of scan */ HotspotInfo[] hotspotInfos /* signal thresholds to crosss */ ) { validateChannel(); + WifiChangeSettings settings = new WifiChangeSettings(); settings.rssiSampleSize = rssiSampleSize; settings.lostApSampleSize = lostApSampleSize; settings.unchangedSampleSize = unchangedSampleSize; settings.minApsBreachingThreshold = minApsBreachingThreshold; + settings.periodInMs = periodInMs; settings.hotspotInfos = hotspotInfos; - sAsyncChannel.sendMessage(CMD_CONFIGURE_WIFI_CHANGE, 0, 0, settings); + configureWifiChange(settings); } - public interface SignificantWifiChangeListener extends ActionListener { + /** + * interface to get wifi change events on; use this on {@link #startTrackingWifiChange} + */ + public interface WifiChangeListener extends ActionListener { + /** indicates that changes were detected in wifi environment + * @param results indicate the access points that exhibited change + */ public void onChanging(ScanResult[] results); /* changes are found */ + /** indicates that no wifi changes are being detected for a while + * @param results indicate the access points that are bing monitored for change + */ public void onQuiescence(ScanResult[] results); /* changes settled down */ } - public void trackSignificantWifiChange(SignificantWifiChangeListener listener) { + /** + * track changes in wifi environment + * @param listener object to report events on; this object must be unique and must also be + * provided on {@link #stopTrackingWifiChange} + */ + public void startTrackingWifiChange(WifiChangeListener listener) { validateChannel(); sAsyncChannel.sendMessage(CMD_START_TRACKING_CHANGE, 0, putListener(listener)); } - public void untrackSignificantWifiChange(SignificantWifiChangeListener listener) { + + /** + * stop tracking changes in wifi environment + * @param listener object that was provided to report events on {@link + * #stopTrackingWifiChange} + */ + public void stopTrackingWifiChange(WifiChangeListener listener) { validateChannel(); sAsyncChannel.sendMessage(CMD_STOP_TRACKING_CHANGE, 0, removeListener(listener)); } - public void configureSignificantWifiChange(WifiChangeSettings settings) { + /** @hide */ + public void configureWifiChange(WifiChangeSettings settings) { validateChannel(); sAsyncChannel.sendMessage(CMD_CONFIGURE_WIFI_CHANGE, 0, 0, settings); } + /** interface to receive hotlist events on; use this on {@link #setHotlist} */ public static interface HotlistListener extends ActionListener { + /** indicates that access points were found by on going scans + * @param results list of scan results, one for each access point visible currently + */ public void onFound(ScanResult[] results); } @@ -310,6 +516,7 @@ public class WifiScanner { dest.writeString(info.bssid); dest.writeInt(info.low); dest.writeInt(info.high); + dest.writeInt(info.frequencyHint); } } @@ -326,6 +533,7 @@ public class WifiScanner { info.bssid = in.readString(); info.low = in.readInt(); info.high = in.readInt(); + info.frequencyHint = in.readInt(); settings.hotspotInfos[i] = info; } return settings; @@ -337,6 +545,13 @@ public class WifiScanner { }; } + /** + * set interesting access points to find + * @param hotspots access points of interest + * @param apLostThreshold number of scans needed to indicate that AP is lost + * @param listener object provided to report events on; this object must be unique and must + * also be provided on {@link #resetHotlist} + */ public void setHotlist(HotspotInfo[] hotspots, int apLostThreshold, HotlistListener listener) { validateChannel(); @@ -345,6 +560,10 @@ public class WifiScanner { sAsyncChannel.sendMessage(CMD_SET_HOTLIST, 0, putListener(listener), settings); } + /** + * remove tracking of interesting access points + * @param listener same object provided in {@link #setHotlist} + */ public void resetHotlist(HotlistListener listener) { validateChannel(); sAsyncChannel.sendMessage(CMD_RESET_HOTLIST, 0, removeListener(listener)); @@ -554,6 +773,7 @@ public class WifiScanner { break; case CMD_OP_FAILED : ((ActionListener) listener).onFailure(msg.arg1, msg.obj); + removeListener(msg.arg2); break; case CMD_SCAN_RESULT : ((ScanListener) listener).onResults( @@ -563,16 +783,19 @@ public class WifiScanner { FullScanResult result = (FullScanResult) msg.obj; ((ScanListener) listener).onFullResult(result); return; + case CMD_PERIOD_CHANGED: + ((ScanListener) listener).onPeriodChanged(msg.arg1); + return; case CMD_AP_FOUND: ((HotlistListener) listener).onFound( ((ParcelableScanResults) msg.obj).getResults()); return; case CMD_WIFI_CHANGE_DETECTED: - ((SignificantWifiChangeListener) listener).onChanging( + ((WifiChangeListener) listener).onChanging( ((ParcelableScanResults) msg.obj).getResults()); return; case CMD_WIFI_CHANGES_STABILIZED: - ((SignificantWifiChangeListener) listener).onQuiescence( + ((WifiChangeListener) listener).onQuiescence( ((ParcelableScanResults) msg.obj).getResults()); return; default: diff --git a/wifi/java/android/net/wifi/hotspot/WifiHotspotManager.java b/wifi/java/android/net/wifi/hotspot/WifiHotspotManager.java deleted file mode 100644 index ac15017..0000000 --- a/wifi/java/android/net/wifi/hotspot/WifiHotspotManager.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net.wifi.hotspot; - -import android.content.Context; -import android.os.RemoteException; -import android.util.Log; - -/** - * TODO: doc - */ -public class WifiHotspotManager { - - private static final String TAG = "WifiHotspotManager"; - - private Context mContext; - IWifiHotspotManager mService; - - public WifiHotspotManager(Context context, IWifiHotspotManager service) { - mContext = context; - mService = service; - } - - public void test() { - try{ - Log.d(TAG, "test()"); - mService.test(); - } - catch (RemoteException e) { - Log.e(TAG, "test() exception"); - e.printStackTrace(); - } - } -} diff --git a/wifi/java/android/net/wifi/passpoint/IPasspointManager.aidl b/wifi/java/android/net/wifi/passpoint/IPasspointManager.aidl new file mode 100644 index 0000000..e57db64 --- /dev/null +++ b/wifi/java/android/net/wifi/passpoint/IPasspointManager.aidl @@ -0,0 +1,31 @@ +/** + * Copyright (c) 2014, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.wifi.passpoint; + +import android.os.Messenger; + +/** + * Interface that allows controlling and querying Passpoint connectivity. + * + * {@hide} + */ +interface IPasspointManager +{ + Messenger getMessenger(); + int getPasspointState(); +} + diff --git a/wifi/java/android/net/wifi/hotspot/IWifiHotspotManager.aidl b/wifi/java/android/net/wifi/passpoint/PasspointCredential.aidl index 2b1601b..6f75cbe 100644 --- a/wifi/java/android/net/wifi/hotspot/IWifiHotspotManager.aidl +++ b/wifi/java/android/net/wifi/passpoint/PasspointCredential.aidl @@ -14,15 +14,6 @@ * limitations under the License. */ -package android.net.wifi.hotspot; - -/** - * Interface that allows controlling and querying Hotspot connectivity. - * - * {@hide} - */ -interface IWifiHotspotManager -{ - void test(); -} +package android.net.wifi.passpoint; +parcelable PasspointCredential; diff --git a/wifi/java/android/net/wifi/passpoint/PasspointCredential.java b/wifi/java/android/net/wifi/passpoint/PasspointCredential.java new file mode 100644 index 0000000..4218f23 --- /dev/null +++ b/wifi/java/android/net/wifi/passpoint/PasspointCredential.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.wifi.passpoint; + +import android.os.Parcelable; +import android.os.Parcel; + +public class PasspointCredential implements Parcelable { + + @Override + public String toString() { + // TODO + return null; + } + + /** Implement the Parcelable interface {@hide} */ + @Override + public int describeContents() { + return 0; + } + + /** Implement the Parcelable interface {@hide} */ + @Override + public void writeToParcel(Parcel dest, int flags) { + // TODO + } + + /** Implement the Parcelable interface {@hide} */ + public static final Creator<PasspointCredential> CREATOR = + new Creator<PasspointCredential>() { + @Override + public PasspointCredential createFromParcel(Parcel in) { + // TODO + return null; + } + + @Override + public PasspointCredential[] newArray(int size) { + return new PasspointCredential[size]; + } + }; +} diff --git a/wifi/java/android/net/wifi/passpoint/PasspointInfo.aidl b/wifi/java/android/net/wifi/passpoint/PasspointInfo.aidl new file mode 100644 index 0000000..cc11045 --- /dev/null +++ b/wifi/java/android/net/wifi/passpoint/PasspointInfo.aidl @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2014, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.wifi.passpoint; + +parcelable PasspointInfo; diff --git a/wifi/java/android/net/wifi/passpoint/PasspointInfo.java b/wifi/java/android/net/wifi/passpoint/PasspointInfo.java new file mode 100644 index 0000000..d57b0aa --- /dev/null +++ b/wifi/java/android/net/wifi/passpoint/PasspointInfo.java @@ -0,0 +1,274 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.wifi.passpoint; + +import android.os.Parcel; +import android.os.Parcelable; + +import java.util.ArrayList; +import java.util.List; + +/** + * TODO: doc + */ +public class PasspointInfo implements Parcelable { + + /** TODO doc */ + public static final int ANQP_CAPABILITY = 1 << 0; + + /** TODO doc */ + public static final int VENUE_NAME = 1 << 1; + + /** TODO doc */ + public static final int NETWORK_AUTH_TYPE = 1 << 2; + + /** TODO doc */ + public static final int ROAMING_CONSORTIUM = 1 << 3; + + /** TODO doc */ + public static final int IP_ADDR_TYPE_AVAILABILITY = 1 << 4; + + /** TODO doc */ + public static final int NAI_REALM = 1 << 5; + + /** TODO doc */ + public static final int CELLULAR_NETWORK = 1 << 6; + + /** TODO doc */ + public static final int DOMAIN_NAME = 1 << 7; + + /** TODO doc */ + public static final int HOTSPOT_CAPABILITY = 1 << 8; + + /** TODO doc */ + public static final int OPERATOR_FRIENDLY_NAME = 1 << 9; + + /** TODO doc */ + public static final int WAN_METRICS = 1 << 10; + + /** TODO doc */ + public static final int CONNECTION_CAPABILITY = 1 << 11; + + /** TODO doc */ + public static final int OSU_PROVIDER = 1 << 12; + + /** TODO doc */ + public static final int PRESET_CRED_MATCH = + ANQP_CAPABILITY | + HOTSPOT_CAPABILITY | + NAI_REALM | + CELLULAR_NETWORK | + DOMAIN_NAME; + + /** TODO doc */ + public static final int PRESET_ALL = + ANQP_CAPABILITY | + VENUE_NAME | + NETWORK_AUTH_TYPE | + ROAMING_CONSORTIUM | + IP_ADDR_TYPE_AVAILABILITY | + NAI_REALM | + CELLULAR_NETWORK | + DOMAIN_NAME | + HOTSPOT_CAPABILITY | + OPERATOR_FRIENDLY_NAME | + WAN_METRICS | + CONNECTION_CAPABILITY | + OSU_PROVIDER; + + + /** TODO doc */ + public String bssid; + + /** TODO doc */ + public String venueName; + + /** TODO doc */ + public String networkAuthType; + + /** TODO doc */ + public String roamingConsortium; + + /** TODO doc */ + public String ipAddrTypeAvaibility; + + /** TODO doc */ + public String naiRealm; + + /** TODO doc */ + public String cellularNetwork; + + /** TODO doc */ + public String domainName; + + /** TODO doc */ + public String operatorFriendlyName; + + /** TODO doc */ + public String wanMetrics; + + /** TODO doc */ + public String connectionCapability; + + /** TODO doc */ + public List<PasspointOsuProvider> osuProviderList; + + + /** default constructor @hide */ + public PasspointInfo() { +// osuProviderList = new ArrayList<OsuProvider>(); + } + + /** copy constructor @hide */ + public PasspointInfo(PasspointInfo source) { + // TODO + bssid = source.bssid; + venueName = source.venueName; + networkAuthType = source.networkAuthType; + roamingConsortium = source.roamingConsortium; + ipAddrTypeAvaibility = source.ipAddrTypeAvaibility; + naiRealm = source.naiRealm; + cellularNetwork = source.cellularNetwork; + domainName = source.domainName; + operatorFriendlyName = source.operatorFriendlyName; + wanMetrics = source.wanMetrics; + connectionCapability = source.connectionCapability; + if (source.osuProviderList != null) { + osuProviderList = new ArrayList<PasspointOsuProvider>(); + for (PasspointOsuProvider osu : source.osuProviderList) + osuProviderList.add(new PasspointOsuProvider(osu)); + } + } + + /** + * Convert mask to ANQP subtypes, for supplicant command use. + * + * @param mask The ANQP subtypes mask. + * @return String of ANQP subtypes, good for supplicant command use + * @hide + */ + public static String toAnqpSubtypes(int mask) { + StringBuilder sb = new StringBuilder(); + if ((mask & ANQP_CAPABILITY) != 0) sb.append("257,"); + if ((mask & VENUE_NAME) != 0) sb.append("258,"); + if ((mask & NETWORK_AUTH_TYPE) != 0) sb.append("260,"); + if ((mask & ROAMING_CONSORTIUM) != 0) sb.append("261,"); + if ((mask & IP_ADDR_TYPE_AVAILABILITY) != 0) sb.append("262,"); + if ((mask & NAI_REALM) != 0) sb.append("263,"); + if ((mask & CELLULAR_NETWORK) != 0) sb.append("264,"); + if ((mask & DOMAIN_NAME) != 0) sb.append("268,"); + if ((mask & HOTSPOT_CAPABILITY) != 0) sb.append("hs20:2,"); + if ((mask & OPERATOR_FRIENDLY_NAME) != 0) sb.append("hs20:3,"); + if ((mask & WAN_METRICS) != 0) sb.append("hs20:4,"); + if ((mask & CONNECTION_CAPABILITY) != 0) sb.append("hs20:5,"); + if ((mask & OSU_PROVIDER) != 0) sb.append("hs20:8,"); + if (sb.length() > 0) sb.deleteCharAt(sb.length() - 1); + return sb.toString(); + } + + @Override + public String toString() { + StringBuffer sb = new StringBuffer(); + sb.append("BSSID: ").append(bssid); + if (venueName != null) + sb.append(" venueName: ").append(venueName); + if (networkAuthType != null) + sb.append(" networkAuthType: ").append(networkAuthType); + if (roamingConsortium != null) + sb.append(" roamingConsortium: ").append(roamingConsortium); + if (ipAddrTypeAvaibility != null) + sb.append(" ipAddrTypeAvaibility: ").append(ipAddrTypeAvaibility); + if (naiRealm != null) + sb.append(" naiRealm: ").append(naiRealm); + if (cellularNetwork != null) + sb.append(" cellularNetwork: ").append(cellularNetwork); + if (domainName != null) + sb.append(" domainName: ").append(domainName); + if (operatorFriendlyName != null) + sb.append(" operatorFriendlyName: ").append(operatorFriendlyName); + if (wanMetrics != null) + sb.append(" wanMetrics: ").append(wanMetrics); + if (connectionCapability != null) + sb.append(" connectionCapability: ").append(connectionCapability); + if (osuProviderList != null) + sb.append(" osuProviderList: (size=" + osuProviderList.size() + ")"); + return sb.toString(); + } + + /** Implement the Parcelable interface {@hide} */ + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeValue(bssid); + out.writeValue(venueName); + out.writeValue(networkAuthType); + out.writeValue(roamingConsortium); + out.writeValue(ipAddrTypeAvaibility); + out.writeValue(naiRealm); + out.writeValue(cellularNetwork); + out.writeValue(domainName); + out.writeValue(operatorFriendlyName); + out.writeValue(wanMetrics); + out.writeValue(connectionCapability); + if (osuProviderList == null) { + out.writeInt(0); + } else { + out.writeInt(osuProviderList.size()); + for (PasspointOsuProvider osu : osuProviderList) + osu.writeToParcel(out, flags); + } + } + + /** Implement the Parcelable interface {@hide} */ + @Override + public int describeContents() { + return 0; + } + + /** Implement the Parcelable interface {@hide} */ + public static final Parcelable.Creator<PasspointInfo> CREATOR = + new Parcelable.Creator<PasspointInfo>() { + @Override + public PasspointInfo createFromParcel(Parcel in) { + PasspointInfo p = new PasspointInfo(); + p.bssid = (String) in.readValue(String.class.getClassLoader()); + p.venueName = (String) in.readValue(String.class.getClassLoader()); + p.networkAuthType = (String) in.readValue(String.class.getClassLoader()); + p.roamingConsortium = (String) in.readValue(String.class.getClassLoader()); + p.ipAddrTypeAvaibility = (String) in.readValue(String.class.getClassLoader()); + p.naiRealm = (String) in.readValue(String.class.getClassLoader()); + p.cellularNetwork = (String) in.readValue(String.class.getClassLoader()); + p.domainName = (String) in.readValue(String.class.getClassLoader()); + p.operatorFriendlyName = (String) in.readValue(String.class.getClassLoader()); + p.wanMetrics = (String) in.readValue(String.class.getClassLoader()); + p.connectionCapability = (String) in.readValue(String.class.getClassLoader()); + int n = in.readInt(); + if (n > 0) { + p.osuProviderList = new ArrayList<PasspointOsuProvider>(); + for (int i = 0; i < n; i++) { + PasspointOsuProvider osu = PasspointOsuProvider.CREATOR.createFromParcel(in); + p.osuProviderList.add(osu); + } + } + return p; + } + + @Override + public PasspointInfo[] newArray(int size) { + return new PasspointInfo[size]; + } + }; +} diff --git a/wifi/java/android/net/wifi/passpoint/PasspointManager.java b/wifi/java/android/net/wifi/passpoint/PasspointManager.java new file mode 100644 index 0000000..234a44c --- /dev/null +++ b/wifi/java/android/net/wifi/passpoint/PasspointManager.java @@ -0,0 +1,504 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.wifi.passpoint; + +import android.content.Context; +import android.net.wifi.ScanResult; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.os.Messenger; +import android.os.RemoteException; +import android.util.Log; + +import com.android.internal.util.AsyncChannel; +import com.android.internal.util.Protocol; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; + +/** + * TODO: doc + */ +public class PasspointManager { + + private static final String TAG = "PasspointManager"; + + private static final boolean DBG = true; + + /* Passpoint states values */ + + /** Passpoint is in an known state. This should only occur in boot time */ + public static final int PASSPOINT_STATE_UNKNOWN = 0; + + /** Passpoint is disabled. This occurs when wifi is disabled. */ + public static final int PASSPOINT_STATE_DISABLED = 1; + + /** Passpoint is enabled and in discovery state. */ + public static final int PASSPOINT_STATE_DISCOVERY = 2; + + /** Passpoint is enabled and in access state. */ + public static final int PASSPOINT_STATE_ACCESS = 3; + + /** Passpoint is enabled and in provisioning state. */ + public static final int PASSPOINT_STATE_PROVISION = 4; + + /* Passpoint callback error codes */ + + /** Indicates that the operation failed due to an internal error */ + public static final int ERROR = 0; + + /** Indicates that the operation failed because wifi is disabled */ + public static final int WIFI_DISABLED = 1; + + /** Indicates that the operation failed because the framework is busy */ + public static final int BUSY = 2; + + /* Passpoint broadcasts */ + + /** + * Broadcast intent action indicating that the state of Passpoint + * connectivity has changed + */ + public static final String PASSPOINT_STATE_CHANGED_ACTION = + "android.net.wifi.passpoint.STATE_CHANGE"; + + /** + * Broadcast intent action indicating that the saved Passpoint credential + * list has changed + */ + public static final String PASSPOINT_CRED_CHANGED_ACTION = + "android.net.wifi.passpoint.CRED_CHANGE"; + + /** + * Broadcast intent action indicating that Passpoint online sign up is + * avaiable. + * @hide + */ + public static final String PASSPOINT_OSU_AVAILABLE_ACTION = + "android.net.wifi.passpoint.OSU_AVAILABLE"; + + /** + * Broadcast intent action indicating that user remediation is required + * @hide + */ + public static final String PASSPOINT_USER_REM_REQ_ACTION = + "android.net.wifi.passpoint.USER_REM_REQ"; + + + /** + * Interface for callback invocation when framework channel is lost + */ + public interface ChannelListener { + /** + * The channel to the framework has been disconnected. Application could + * try re-initializing using {@link #initialize} + */ + public void onChannelDisconnected(); + } + + /** + * Interface for callback invocation on an application action + */ + public interface ActionListener { + /** The operation succeeded */ + public void onSuccess(); + + /** + * * The operation failed + * + * @param reason The reason for failure could be one of + * {@link #WIFI_DISABLED}, {@link #ERROR} or {@link #BUSY} + */ + public void onFailure(int reason); + } + + /** + * Interface for callback invocation when doing OSU or user remediation + * @hide + */ + public interface OsuRemListener { + /** The operation succeeded */ + public void onSuccess(); + + /** + * The operation failed + * + * @param reason The reason for failure could be one of + * {@link #WIFI_DISABLED}, {@link #ERROR} or {@link #BUSY} + */ + public void onFailure(int reason); + + /** + * Browser launch is requried for user interaction. When this callback + * is called, app should launch browser / webview to the given URL. + * + * @param url URL for browser launch + */ + public void onBrowserLaunch(String url); + + /** + * When this is called, app should dismiss the previously lanched browser. + */ + public void onBrowserDismiss(); + } + + /** + * A channel that connects the application to the wifi passpoint framework. + * Most passpoint operations require a Channel as an argument. + * An instance of Channel is obtained by doing a call on {@link #initialize} + */ + public static class Channel { + private final static int INVALID_LISTENER_KEY = 0; + + private ChannelListener mChannelListener; + + private HashMap<Integer, Object> mListenerMap = new HashMap<Integer, Object>(); + private HashMap<Integer, Integer> mListenerMapCount = new HashMap<Integer, Integer>(); + private Object mListenerMapLock = new Object(); + private int mListenerKey = 0; + + private List<ScanResult> mAnqpRequest = new LinkedList<ScanResult>(); + private Object mAnqpRequestLock = new Object(); + + private AsyncChannel mAsyncChannel; + private PasspointHandler mHandler; + Context mContext; + + Channel(Context context, Looper looper, ChannelListener l) { + mAsyncChannel = new AsyncChannel(); + mHandler = new PasspointHandler(looper); + mChannelListener = l; + mContext = context; + } + + private int putListener(Object listener) { + return putListener(listener, 1); + } + + private int putListener(Object listener, int count) { + if (listener == null || count <= 0) return INVALID_LISTENER_KEY; + int key; + synchronized (mListenerMapLock) { + do { + key = mListenerKey++; + } while (key == INVALID_LISTENER_KEY); + mListenerMap.put(key, listener); + mListenerMapCount.put(key, count); + } + return key; + } + + private Object getListener(int key, boolean force) { + Log.d(TAG, "getListener() key=" + key + " force=" + force); + if (key == INVALID_LISTENER_KEY) return null; + synchronized (mListenerMapLock) { + if (!force) { + int count = mListenerMapCount.get(key); + Log.d(TAG, "count=" + count); + mListenerMapCount.put(key, --count); + if (count > 0) return null; + } + Log.d(TAG, "remove key"); + mListenerMapCount.remove(key); + return mListenerMap.remove(key); + } + } + + private void anqpRequestStart(ScanResult sr) { + Log.d(TAG, "anqpRequestStart sr.bssid=" + sr.BSSID); + synchronized(mAnqpRequestLock) { mAnqpRequest.add(sr); } + } + + private void anqpRequestFinish(PasspointInfo result) { + Log.d(TAG, "anqpRequestFinish pi.bssid=" + result.bssid); + synchronized(mAnqpRequestLock) { + for (ScanResult sr : mAnqpRequest) + if (sr.BSSID.equals(result.bssid)) { + Log.d(TAG, "find hit " + result.bssid); + sr.passpoint = result; + mAnqpRequest.remove(sr); + Log.d(TAG, "mAnqpRequest.len=" + mAnqpRequest.size()); + break; + } + } + } + + private void anqpRequestFinish(ScanResult sr) { + Log.d(TAG, "anqpRequestFinish sr.bssid=" + sr.BSSID); + synchronized(mAnqpRequestLock) { + for (ScanResult sr1 : mAnqpRequest) + if (sr1.BSSID.equals(sr.BSSID)) { + mAnqpRequest.remove(sr1); + break; + } + } + } + + class PasspointHandler extends Handler { + PasspointHandler(Looper looper) { + super(looper); + } + + @Override + public void handleMessage(Message message) { + Object listener = getListener(message.arg2, false); + switch (message.what) { + case AsyncChannel.CMD_CHANNEL_DISCONNECTED: + if (mChannelListener != null) { + mChannelListener.onChannelDisconnected(); + mChannelListener = null; + } + break; + + case REQUEST_ANQP_INFO_SUCCEEDED: + PasspointInfo result = (PasspointInfo) message.obj; + anqpRequestFinish(result); + if (listener != null) { + ((ActionListener) listener).onSuccess(); + } + break; + + case REQUEST_ANQP_INFO_FAILED: + anqpRequestFinish((ScanResult) message.obj); + if (listener == null) getListener(message.arg2, true); + if (listener != null) { + ((ActionListener) listener).onFailure(message.arg1); + } + break; + + default: + Log.d(TAG, "Ignored " + message); + break; + } + } + } + + } + + + private static final int BASE = Protocol.BASE_WIFI_PASSPOINT_MANAGER; + + /** @hide */ + public static final int REQUEST_ANQP_INFO = BASE + 1; + + /** @hide */ + public static final int REQUEST_ANQP_INFO_FAILED = BASE + 2; + + /** @hide */ + public static final int REQUEST_ANQP_INFO_SUCCEEDED = BASE + 3; + + /** @hide */ + public static final int REQUEST_OSU_INFO = BASE + 4; + + /** @hide */ + public static final int REQUEST_OSU_INFO_FAILED = BASE + 5; + + /** @hide */ + public static final int REQUEST_OSU_INFO_SUCCEEDED = BASE + 6; + + + private Context mContext; + IPasspointManager mService; + + + /** + * TODO: doc + * @param context + * @param service + */ + public PasspointManager(Context context, IPasspointManager service) { + mContext = context; + mService = service; + } + + /** + * Registers the application with the framework. This function must be the + * first to be called before any async passpoint operations are performed. + * + * @param srcContext is the context of the source + * @param srcLooper is the Looper on which the callbacks are receivied + * @param listener for callback at loss of framework communication. Can be + * null. + * @return Channel instance that is necessary for performing any further + * passpoint operations + */ + public Channel initialize(Context srcContext, Looper srcLooper, ChannelListener listener) { + Messenger messenger = getMessenger(); + if (messenger == null) return null; + + Channel c = new Channel(srcContext, srcLooper, listener); + if (c.mAsyncChannel.connectSync(srcContext, c.mHandler, messenger) + == AsyncChannel.STATUS_SUCCESSFUL) { + return c; + } else { + return null; + } + } + + /** + * STOPSHIP: temp solution, should use supplicant manager instead, check + * with b/13931972 + * + * @hide + */ + public Messenger getMessenger() { + try { + return mService.getMessenger(); + } catch (RemoteException e) { + return null; + } + } + + /** + * Get Passpoint state. + * + * @return One of {@link #PASSPOINT_STATE_DISABLED}, + * {@link #PASSPOINT_STATE_DISCOVERY}, + * {@link #PASSPOINT_STATE_ACCESS}, + * {@link #PASSPOINT_STATE_PROVISION}, + * {@link #PASSPOINT_STATE_UNKNOWN} + */ + public int getPasspointState() { + try{ + return mService.getPasspointState(); + } + catch (RemoteException e) { + return PASSPOINT_STATE_UNKNOWN; + } + } + + /** + * TODO: doc + * + * @param c + * @param requested + * @param mask + * @param listener + * + * @hide + */ + public void requestAnqpInfo(Channel c, List<ScanResult> requested, int mask, + ActionListener listener) { + Log.d(TAG, "requestAnqpInfo start"); + Log.d(TAG, "requested.size=" + requested.size()); + checkChannel(c); + List<ScanResult> list = new ArrayList<ScanResult>(); + for (ScanResult sr : requested) if (sr.capabilities.contains("[HS20]")) { + list.add(sr); + c.anqpRequestStart(sr); + Log.d(TAG, "adding " + sr.BSSID); + } + int count = list.size(); + Log.d(TAG, "after filter, count=" + count); + if (count == 0) { + if (DBG) Log.d(TAG, "ANQP info request contains no HS20 APs, skipped"); + listener.onSuccess(); + return; + } + int key = c.putListener(listener, count); + for (ScanResult sr : list) + c.mAsyncChannel.sendMessage(REQUEST_ANQP_INFO, mask, key, sr); + Log.d(TAG, "requestAnqpInfo end"); + } + + /** + * TODO: doc + * + * @param c + * @param requested + * @param resolution + * @param listener + */ + public void requestOsuIcons(Channel c, List<PasspointOsuProvider> requested, + int resolution, ActionListener listener) { + } + + /** + * TODO: doc + * + * @param requested + * @return + */ + public List<PasspointPolicy> requestCredentialMatch(List<ScanResult> requested) { + return null; + } + + /* TODO: add credential APIs */ + + /** + * Give a list of all saved Passpoint credentials. + * + * @return The list of credentials + */ + public List<PasspointCredential> getSavedCredentials() { + return null; + } + + /** + * Add a new Passpoint credential. + * + * @param cred The credential to be added + * @return {@code true} if the operation succeeds, {@code false} otherwise + */ + public boolean addCredential(PasspointCredential cred) { + return true; + } + + /** + * Update an existing Passpoint credential. + * + * @param cred The credential to be updated + * @return {@code true} if the operation succeeds, {@code false} otherwise + */ + public boolean updateCredential(PasspointCredential cred) { + return true; + } + + /** + * Remove an existing Passpoint credential. + * + * @param cred The credential to be removed + * @return {@code true} if the operation succeeds, {@code false} otherwise + */ + public boolean removeCredential(PasspointCredential cred) { + return true; + } + + /** @hide */ + public void startOsu(Channel c, PasspointOsuProvider selected, OsuRemListener listener) { + + } + + /** @hide */ + public void startUserRemediation(Channel c, OsuRemListener listener) { + } + + /** + * Select and connect to a Passpoint network. + * + * @param selected Selected Passpoint network, see {@link PasspointPolicy} + */ + public void connect(PasspointPolicy selected) { + } + + private static void checkChannel(Channel c) { + if (c == null) throw new IllegalArgumentException("Channel needs to be initialized"); + } +} diff --git a/wifi/java/android/net/wifi/passpoint/PasspointOsuProvider.aidl b/wifi/java/android/net/wifi/passpoint/PasspointOsuProvider.aidl new file mode 100644 index 0000000..f5ecb7c --- /dev/null +++ b/wifi/java/android/net/wifi/passpoint/PasspointOsuProvider.aidl @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2014, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.wifi.passpoint; + +parcelable PasspointOsuProvider; diff --git a/wifi/java/android/net/wifi/passpoint/PasspointOsuProvider.java b/wifi/java/android/net/wifi/passpoint/PasspointOsuProvider.java new file mode 100644 index 0000000..80d5315 --- /dev/null +++ b/wifi/java/android/net/wifi/passpoint/PasspointOsuProvider.java @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.wifi.passpoint; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * TODO: doc + */ +public class PasspointOsuProvider implements Parcelable { + + /** TODO: doc */ + public static final int OSU_METHOD_UNKNOWN = -1; + + /** TODO: doc */ + public static final int OSU_METHOD_OMADM = 0; + + /** TODO: doc */ + public static final int OSU_METHOD_SOAP = 1; + + /** TODO: doc */ + public String ssid; + + /** TODO: doc */ + public String friendlyName; + + /** TODO: doc */ + public String serverUri; + + /** TODO: doc */ + public int osuMethod = OSU_METHOD_UNKNOWN; + + /** TODO: doc */ + public int iconWidth; + + /** TODO: doc */ + public int iconHeight; + + /** TODO: doc */ + public String iconType; + + /** TODO: doc */ + public String iconFileName; + + /** TODO: doc */ + public Object icon; // TODO: should change to image format + + /** TODO: doc */ + public String osuNai; + + /** TODO: doc */ + public String osuService; + + + /** default constructor @hide */ + public PasspointOsuProvider() { + // TODO + } + + /** copy constructor @hide */ + public PasspointOsuProvider(PasspointOsuProvider source) { + // TODO + } + + @Override + public String toString() { + StringBuffer sb = new StringBuffer(); + sb.append("SSID: ").append(ssid); + if (friendlyName != null) + sb.append(" friendlyName: ").append(friendlyName); + if (serverUri != null) + sb.append(" serverUri: ").append(serverUri); + sb.append(" osuMethod: ").append(osuMethod); + if (iconFileName != null) { + sb.append(" icon: [").append(iconWidth).append("x") + .append(iconHeight).append(" ") + .append(iconType).append(" ") + .append(iconFileName); + } + if (osuNai != null) + sb.append(" osuNai: ").append(osuNai); + if (osuService != null) + sb.append(" osuService: ").append(osuService); + return sb.toString(); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeValue(ssid); + out.writeValue(friendlyName); + out.writeValue(serverUri); + out.writeInt(osuMethod); + out.writeInt(iconWidth); + out.writeInt(iconHeight); + out.writeValue(iconType); + out.writeValue(iconFileName); + out.writeValue(osuNai); + out.writeValue(osuService); + // TODO: icon image? + } + + public static final Parcelable.Creator<PasspointOsuProvider> CREATOR = + new Parcelable.Creator<PasspointOsuProvider>() { + @Override + public PasspointOsuProvider createFromParcel(Parcel in) { + PasspointOsuProvider osu = new PasspointOsuProvider(); + osu.ssid = (String) in.readValue(String.class.getClassLoader()); + osu.friendlyName = (String) in.readValue(String.class.getClassLoader()); + osu.serverUri = (String) in.readValue(String.class.getClassLoader()); + osu.osuMethod = in.readInt(); + osu.iconWidth = in.readInt(); + osu.iconHeight = in.readInt(); + osu.iconType = (String) in.readValue(String.class.getClassLoader()); + osu.iconFileName = (String) in.readValue(String.class.getClassLoader()); + osu.osuNai = (String) in.readValue(String.class.getClassLoader()); + osu.osuService = (String) in.readValue(String.class.getClassLoader()); + return osu; + } + + @Override + public PasspointOsuProvider[] newArray(int size) { + return new PasspointOsuProvider[size]; + } + }; +} diff --git a/wifi/java/android/net/wifi/passpoint/PasspointPolicy.aidl b/wifi/java/android/net/wifi/passpoint/PasspointPolicy.aidl new file mode 100644 index 0000000..c2cc731 --- /dev/null +++ b/wifi/java/android/net/wifi/passpoint/PasspointPolicy.aidl @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2014, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.wifi.passpoint; + +parcelable PasspointPolicy; diff --git a/wifi/java/android/net/wifi/passpoint/PasspointPolicy.java b/wifi/java/android/net/wifi/passpoint/PasspointPolicy.java new file mode 100644 index 0000000..3a8806b --- /dev/null +++ b/wifi/java/android/net/wifi/passpoint/PasspointPolicy.java @@ -0,0 +1,55 @@ +/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.passpoint;
+
+import android.os.Parcelable;
+import android.os.Parcel;
+
+public class PasspointPolicy implements Parcelable {
+
+ @Override
+ public String toString() {
+ // TODO
+ return null;
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ // TODO
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ public static final Creator<PasspointPolicy> CREATOR =
+ new Creator<PasspointPolicy>() {
+ @Override
+ public PasspointPolicy createFromParcel(Parcel in) {
+ return null;
+ }
+
+ @Override
+ public PasspointPolicy[] newArray(int size) {
+ return new PasspointPolicy[size];
+ }
+ };
+}
diff --git a/wifi/java/android/net/wifi/passpoint/WifiTree.aidl b/wifi/java/android/net/wifi/passpoint/WifiTree.aidl new file mode 100644 index 0000000..8e2fab7 --- /dev/null +++ b/wifi/java/android/net/wifi/passpoint/WifiTree.aidl @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2014, The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.net.wifi.passpoint; + +parcelable WifiTree; diff --git a/wifi/java/android/net/wifi/passpoint/WifiTree.java b/wifi/java/android/net/wifi/passpoint/WifiTree.java new file mode 100644 index 0000000..8fdb6e1 --- /dev/null +++ b/wifi/java/android/net/wifi/passpoint/WifiTree.java @@ -0,0 +1,51 @@ +/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.wifi.passpoint;
+
+import android.os.Parcelable;
+import android.os.Parcel;
+
+/** @hide */
+public class WifiTree implements Parcelable {
+
+ /** Implement the Parcelable interface {@hide} */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ // TODO
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ public static final Parcelable.Creator<WifiTree> CREATOR =
+ new Parcelable.Creator<WifiTree>() {
+ @Override
+ public WifiTree createFromParcel(Parcel in) {
+ // TODO
+ return null;
+ }
+
+ @Override
+ public WifiTree[] newArray(int size) {
+ return new WifiTree[size];
+ }
+ };
+}
|
