Merge "export API to disable autojoin scan initial implementation" into lmp-mr1-wfc-dev
automerge: 7c39808
* commit '7c398083319bbd1ad51d23cb307cfc3ac9091c3a':
export API to disable autojoin scan initial implementation
diff --git a/Android.mk b/Android.mk
index 3b1991c..81113f7 100644
--- a/Android.mk
+++ b/Android.mk
@@ -386,6 +386,7 @@
wifi/java/android/net/wifi/p2p/IWifiP2pManager.aidl \
wifi/java/android/net/wifi/IWifiScanner.aidl \
wifi/java/android/net/wifi/IRttManager.aidl \
+ wifi/java/android/net/wifi/passpoint/IWifiPasspointManager.aidl \
packages/services/PacProcessor/com/android/net/IProxyService.aidl \
packages/services/Proxy/com/android/net/IProxyCallback.aidl \
packages/services/Proxy/com/android/net/IProxyPortListener.aidl \
diff --git a/api/current.txt b/api/current.txt
index 35423fd..87ed7a9 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -17867,11 +17867,23 @@
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
field public java.lang.String BSSID;
+ field public static final int CHANNEL_WIDTH_160MHZ = 3; // 0x3
+ field public static final int CHANNEL_WIDTH_20MHZ = 0; // 0x0
+ field public static final int CHANNEL_WIDTH_40MHZ = 1; // 0x1
+ field public static final int CHANNEL_WIDTH_80MHZ = 2; // 0x2
+ field public static final int CHANNEL_WIDTH_80MHZ_PLUS_MHZ = 4; // 0x4
field public java.lang.String SSID;
field public java.lang.String capabilities;
+ field public int centerFreq0;
+ field public int centerFreq1;
+ field public int channelWidth;
field public int frequency;
+ field public boolean is80211McRTTResponder;
field public int level;
+ field public java.lang.String operatorFriendlyName;
+ field public boolean passpointNetwork;
field public long timestamp;
+ field public java.lang.String venueName;
}
public final class SupplicantState extends java.lang.Enum implements android.os.Parcelable {
@@ -17898,6 +17910,7 @@
public class WifiConfiguration implements android.os.Parcelable {
ctor public WifiConfiguration();
method public int describeContents();
+ method public boolean isPasspoint();
method public void writeToParcel(android.os.Parcel, int);
field public java.lang.String BSSID;
field public java.lang.String FQDN;
@@ -17907,11 +17920,15 @@
field public java.util.BitSet allowedKeyManagement;
field public java.util.BitSet allowedPairwiseCiphers;
field public java.util.BitSet allowedProtocols;
+ field public int apBand;
+ field public int apChannel;
field public android.net.wifi.WifiEnterpriseConfig enterpriseConfig;
field public boolean hiddenSSID;
field public int networkId;
field public java.lang.String preSharedKey;
field public int priority;
+ field public java.lang.String providerFriendlyName;
+ field public java.util.HashSet<java.lang.Long> roamingConsortiumIds;
field public int status;
field public java.lang.String[] wepKeys;
field public int wepTxKeyIndex;
@@ -17969,6 +17986,7 @@
ctor public WifiEnterpriseConfig();
ctor public WifiEnterpriseConfig(android.net.wifi.WifiEnterpriseConfig);
method public int describeContents();
+ method public java.lang.String getAltSubjectMatch();
method public java.lang.String getAnonymousIdentity();
method public java.security.cert.X509Certificate getCaCertificate();
method public java.security.cert.X509Certificate getClientCertificate();
@@ -17976,7 +17994,10 @@
method public java.lang.String getIdentity();
method public java.lang.String getPassword();
method public int getPhase2Method();
- method public java.lang.String getSubjectMatch();
+ method public java.lang.String getPlmn();
+ method public java.lang.String getRealm();
+ method public deprecated java.lang.String getSubjectMatch();
+ method public void setAltSubjectMatch(java.lang.String);
method public void setAnonymousIdentity(java.lang.String);
method public void setCaCertificate(java.security.cert.X509Certificate);
method public void setClientKeyEntry(java.security.PrivateKey, java.security.cert.X509Certificate);
@@ -17984,7 +18005,9 @@
method public void setIdentity(java.lang.String);
method public void setPassword(java.lang.String);
method public void setPhase2Method(int);
- method public void setSubjectMatch(java.lang.String);
+ method public void setPlmn(java.lang.String);
+ method public void setRealm(java.lang.String);
+ method public deprecated void setSubjectMatch(java.lang.String);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.net.wifi.WifiEnterpriseConfig> CREATOR;
}
@@ -25862,6 +25885,7 @@
public static final class VoicemailContract.Status implements android.provider.BaseColumns {
method public static android.net.Uri buildSourceUri(java.lang.String);
+ method public static void setStatus(android.content.Context, android.telecom.PhoneAccountHandle, int, int, int);
field public static final java.lang.String CONFIGURATION_STATE = "configuration_state";
field public static final int CONFIGURATION_STATE_CAN_BE_CONFIGURED = 2; // 0x2
field public static final int CONFIGURATION_STATE_NOT_CONFIGURED = 1; // 0x1
@@ -25876,6 +25900,8 @@
field public static final int NOTIFICATION_CHANNEL_STATE_MESSAGE_WAITING = 2; // 0x2
field public static final int NOTIFICATION_CHANNEL_STATE_NO_CONNECTION = 1; // 0x1
field public static final int NOTIFICATION_CHANNEL_STATE_OK = 0; // 0x0
+ field public static final java.lang.String PHONE_ACCOUNT_COMPONENT_NAME = "phone_account_component_name";
+ field public static final java.lang.String PHONE_ACCOUNT_ID = "phone_account_id";
field public static final java.lang.String SETTINGS_URI = "settings_uri";
field public static final java.lang.String SOURCE_PACKAGE = "source_package";
field public static final java.lang.String VOICEMAIL_ACCESS_URI = "voicemail_access_uri";
@@ -25883,8 +25909,13 @@
public static final class VoicemailContract.Voicemails implements android.provider.BaseColumns android.provider.OpenableColumns {
method public static android.net.Uri buildSourceUri(java.lang.String);
+ method public static int deleteAll(android.content.Context);
+ method public static android.net.Uri insert(android.content.Context, android.telecom.Voicemail);
+ method public static int insert(android.content.Context, java.util.List<android.telecom.Voicemail>);
field public static final android.net.Uri CONTENT_URI;
field public static final java.lang.String DATE = "date";
+ field public static final java.lang.String DELETED = "deleted";
+ field public static final java.lang.String DIRTY = "dirty";
field public static final java.lang.String DIR_TYPE = "vnd.android.cursor.dir/voicemails";
field public static final java.lang.String DURATION = "duration";
field public static final java.lang.String HAS_CONTENT = "has_content";
@@ -25892,6 +25923,8 @@
field public static final java.lang.String ITEM_TYPE = "vnd.android.cursor.item/voicemail";
field public static final java.lang.String MIME_TYPE = "mime_type";
field public static final java.lang.String NUMBER = "number";
+ field public static final java.lang.String PHONE_ACCOUNT_COMPONENT_NAME = "subscription_component_name";
+ field public static final java.lang.String PHONE_ACCOUNT_ID = "subscription_id";
field public static final java.lang.String SOURCE_DATA = "source_data";
field public static final java.lang.String SOURCE_PACKAGE = "source_package";
field public static final java.lang.String TRANSCRIPTION = "transcription";
@@ -28166,8 +28199,81 @@
package android.telecom {
+ public class AuthenticatorService extends android.app.Service {
+ ctor public AuthenticatorService();
+ method public android.os.IBinder onBind(android.content.Intent);
+ }
+
+ public class AuthenticatorService.Authenticator extends android.accounts.AbstractAccountAuthenticator {
+ ctor public AuthenticatorService.Authenticator(android.content.Context);
+ method public android.os.Bundle addAccount(android.accounts.AccountAuthenticatorResponse, java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle) throws android.accounts.NetworkErrorException;
+ method public android.os.Bundle confirmCredentials(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, android.os.Bundle) throws android.accounts.NetworkErrorException;
+ method public android.os.Bundle editProperties(android.accounts.AccountAuthenticatorResponse, java.lang.String);
+ method public android.os.Bundle getAuthToken(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String, android.os.Bundle) throws android.accounts.NetworkErrorException;
+ method public java.lang.String getAuthTokenLabel(java.lang.String);
+ method public android.os.Bundle hasFeatures(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String[]) throws android.accounts.NetworkErrorException;
+ method public android.os.Bundle updateCredentials(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String, android.os.Bundle) throws android.accounts.NetworkErrorException;
+ }
+
+ public class PhoneAccount implements android.os.Parcelable {
+ method public static android.telecom.PhoneAccount.Builder builder(android.telecom.PhoneAccountHandle, java.lang.CharSequence);
+ method public android.graphics.drawable.Drawable createIconDrawable(android.content.Context);
+ method public int describeContents();
+ method public android.telecom.PhoneAccountHandle getAccountHandle();
+ method public android.net.Uri getAddress();
+ method public int getCapabilities();
+ method public int getHighlightColor();
+ method public android.graphics.Bitmap getIconBitmap();
+ method public java.lang.String getIconPackageName();
+ method public int getIconResId();
+ method public int getIconTint();
+ method public java.lang.CharSequence getLabel();
+ method public java.lang.CharSequence getShortDescription();
+ method public android.net.Uri getSubscriptionAddress();
+ method public java.util.List<java.lang.String> getSupportedUriSchemes();
+ method public boolean hasCapabilities(int);
+ method public boolean supportsUriScheme(java.lang.String);
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final int CAPABILITY_PLACE_EMERGENCY_CALLS = 16; // 0x10
+ field public static final int CAPABILITY_SIM_SUBSCRIPTION = 4; // 0x4
+ field public static final android.os.Parcelable.Creator<android.telecom.PhoneAccount> CREATOR;
+ field public static final int NO_HIGHLIGHT_COLOR = 0; // 0x0
+ field public static final int NO_ICON_TINT = 0; // 0x0
+ field public static final int NO_RESOURCE_ID = -1; // 0xffffffff
+ field public static final java.lang.String SCHEME_SIP = "sip";
+ field public static final java.lang.String SCHEME_TEL = "tel";
+ field public static final java.lang.String SCHEME_VOICEMAIL = "voicemail";
+ }
+
+ public static class PhoneAccount.Builder {
+ ctor public PhoneAccount.Builder(android.telecom.PhoneAccountHandle, java.lang.CharSequence);
+ ctor public PhoneAccount.Builder(android.telecom.PhoneAccount);
+ method public android.telecom.PhoneAccount build();
+ method public android.telecom.PhoneAccount.Builder setAddress(android.net.Uri);
+ method public android.telecom.PhoneAccount.Builder setCapabilities(int);
+ method public android.telecom.PhoneAccount.Builder setHighlightColor(int);
+ method public android.telecom.PhoneAccount.Builder setIcon(android.content.Context, int);
+ method public android.telecom.PhoneAccount.Builder setIcon(java.lang.String, int);
+ method public android.telecom.PhoneAccount.Builder setIcon(android.content.Context, int, int);
+ method public android.telecom.PhoneAccount.Builder setIcon(java.lang.String, int, int);
+ method public android.telecom.PhoneAccount.Builder setIcon(android.graphics.Bitmap);
+ method public android.telecom.PhoneAccount.Builder setShortDescription(java.lang.CharSequence);
+ method public android.telecom.PhoneAccount.Builder setSubscriptionAddress(android.net.Uri);
+ method public android.telecom.PhoneAccount.Builder setSupportedUriSchemes(java.util.List<java.lang.String>);
+ }
+
+ public class PhoneAccountHandle implements android.os.Parcelable {
+ ctor public PhoneAccountHandle(android.content.ComponentName, java.lang.String);
+ method public int describeContents();
+ method public android.content.ComponentName getComponentName();
+ method public java.lang.String getId();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.telecom.PhoneAccountHandle> CREATOR;
+ }
+
public class TelecomManager {
method public void cancelMissedCallsNotification();
+ method public android.telecom.PhoneAccount getPhoneAccount(android.telecom.PhoneAccountHandle);
method public boolean handleMmi(java.lang.String);
method public boolean isInCall();
method public void showInCallScreen(boolean);
@@ -28176,7 +28282,10 @@
field public static final char DTMF_CHARACTER_WAIT = 59; // 0x003b ';'
field public static final java.lang.String EXTRA_CALL_DISCONNECT_CAUSE = "android.telecom.extra.CALL_DISCONNECT_CAUSE";
field public static final java.lang.String EXTRA_CALL_DISCONNECT_MESSAGE = "android.telecom.extra.CALL_DISCONNECT_MESSAGE";
+ field public static final java.lang.String EXTRA_OUTGOING_CALL_EXTRAS = "android.telecom.extra.OUTGOING_CALL_EXTRAS";
+ field public static final java.lang.String EXTRA_PHONE_ACCOUNT_HANDLE = "android.telecom.extra.PHONE_ACCOUNT_HANDLE";
field public static final java.lang.String EXTRA_START_CALL_WITH_SPEAKERPHONE = "android.telecom.extra.START_CALL_WITH_SPEAKERPHONE";
+ field public static final java.lang.String EXTRA_START_CALL_WITH_VIDEO_STATE = "android.telecom.extra.START_CALL_WITH_VIDEO_STATE";
field public static final java.lang.String GATEWAY_ORIGINAL_ADDRESS = "android.telecom.extra.GATEWAY_ORIGINAL_ADDRESS";
field public static final java.lang.String GATEWAY_PROVIDER_PACKAGE = "android.telecom.extra.GATEWAY_PROVIDER_PACKAGE";
field public static final int PRESENTATION_ALLOWED = 1; // 0x1
@@ -28185,6 +28294,63 @@
field public static final int PRESENTATION_UNKNOWN = 3; // 0x3
}
+ public class VideoProfile implements android.os.Parcelable {
+ ctor public VideoProfile(int);
+ ctor public VideoProfile(int, int);
+ method public int describeContents();
+ method public int getQuality();
+ method public int getVideoState();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.telecom.VideoProfile> CREATOR;
+ field public static final int QUALITY_DEFAULT = 4; // 0x4
+ field public static final int QUALITY_HIGH = 1; // 0x1
+ field public static final int QUALITY_LOW = 3; // 0x3
+ field public static final int QUALITY_MEDIUM = 2; // 0x2
+ }
+
+ public static class VideoProfile.VideoState {
+ ctor public VideoProfile.VideoState();
+ method public static boolean isAudioOnly(int);
+ method public static boolean isBidirectional(int);
+ method public static boolean isPaused(int);
+ method public static boolean isReceptionEnabled(int);
+ method public static boolean isTransmissionEnabled(int);
+ field public static final int AUDIO_ONLY = 0; // 0x0
+ field public static final int BIDIRECTIONAL = 3; // 0x3
+ field public static final int PAUSED = 4; // 0x4
+ field public static final int RX_ENABLED = 2; // 0x2
+ field public static final int TX_ENABLED = 1; // 0x1
+ }
+
+ public class Voicemail implements android.os.Parcelable {
+ method public static android.telecom.Voicemail.Builder createForInsertion(long, java.lang.String);
+ method public int describeContents();
+ method public long getDuration();
+ method public long getId();
+ method public java.lang.String getNumber();
+ method public java.lang.String getSourceData();
+ method public java.lang.String getSourcePackage();
+ method public long getTimestampMillis();
+ method public android.net.Uri getUri();
+ method public boolean hasContent();
+ method public boolean isRead();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.telecom.Voicemail> CREATOR;
+ }
+
+ public static class Voicemail.Builder {
+ method public android.telecom.Voicemail build();
+ method public android.telecom.Voicemail.Builder setDuration(long);
+ method public android.telecom.Voicemail.Builder setHasContent(boolean);
+ method public android.telecom.Voicemail.Builder setId(long);
+ method public android.telecom.Voicemail.Builder setIsRead(boolean);
+ method public android.telecom.Voicemail.Builder setNumber(java.lang.String);
+ method public android.telecom.Voicemail.Builder setSourceData(java.lang.String);
+ method public android.telecom.Voicemail.Builder setSourcePackage(java.lang.String);
+ method public android.telecom.Voicemail.Builder setTimestamp(long);
+ method public android.telecom.Voicemail.Builder setUri(android.net.Uri);
+ }
+
}
package android.telephony {
@@ -28378,6 +28544,7 @@
public class PhoneNumberUtils {
ctor public PhoneNumberUtils();
+ method public static void addPhoneTtsSpan(android.text.Spannable, int, int);
method public static java.lang.String calledPartyBCDFragmentToString(byte[], int, int);
method public static java.lang.String calledPartyBCDToString(byte[], int, int);
method public static boolean compare(java.lang.String, java.lang.String);
@@ -28394,6 +28561,8 @@
method public static java.lang.String formatNumberToE164(java.lang.String, java.lang.String);
method public static deprecated int getFormatTypeForLocale(java.util.Locale);
method public static java.lang.String getNumberFromIntent(android.content.Intent, android.content.Context);
+ method public static android.text.style.TtsSpan getPhoneTtsSpan(java.lang.String);
+ method public static java.lang.CharSequence getPhoneTtsSpannable(java.lang.CharSequence);
method public static java.lang.String getStrippedReversed(java.lang.String);
method public static final boolean is12Key(char);
method public static final boolean isDialable(char);
diff --git a/api/system-current.txt b/api/system-current.txt
index 729f656..34fb8ca 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -19197,7 +19197,8 @@
}
public class RttManager {
- method public android.net.wifi.RttManager.Capabilities getCapabilities();
+ method public deprecated android.net.wifi.RttManager.Capabilities getCapabilities();
+ method public android.net.wifi.RttManager.RttCapabilities getRttCapabilities();
method public void startRanging(android.net.wifi.RttManager.RttParams[], android.net.wifi.RttManager.RttListener);
method public void stopRanging(android.net.wifi.RttManager.RttListener);
field public static final int BASE = 160256; // 0x27200
@@ -19207,10 +19208,19 @@
field public static final int CMD_OP_STOP_RANGING = 160257; // 0x27201
field public static final int CMD_OP_SUCCEEDED = 160259; // 0x27203
field public static final java.lang.String DESCRIPTION_KEY = "android.net.wifi.RttManager.Description";
+ field public static final int PREAMBLE_HT = 2; // 0x2
+ field public static final int PREAMBLE_LEGACY = 1; // 0x1
+ field public static final int PREAMBLE_VHT = 4; // 0x4
field public static final int REASON_INVALID_LISTENER = -3; // 0xfffffffd
field public static final int REASON_INVALID_REQUEST = -4; // 0xfffffffc
field public static final int REASON_NOT_AVAILABLE = -2; // 0xfffffffe
field public static final int REASON_UNSPECIFIED = -1; // 0xffffffff
+ field public static final int RTT_BW_10_SUPPORT = 2; // 0x2
+ field public static final int RTT_BW_160_SUPPORT = 32; // 0x20
+ field public static final int RTT_BW_20_SUPPORT = 4; // 0x4
+ field public static final int RTT_BW_40_SUPPORT = 8; // 0x8
+ field public static final int RTT_BW_5_SUPPORT = 1; // 0x1
+ field public static final int RTT_BW_80_SUPPORT = 16; // 0x10
field public static final int RTT_CHANNEL_WIDTH_10 = 6; // 0x6
field public static final int RTT_CHANNEL_WIDTH_160 = 3; // 0x3
field public static final int RTT_CHANNEL_WIDTH_20 = 0; // 0x0
@@ -19218,26 +19228,31 @@
field public static final int RTT_CHANNEL_WIDTH_5 = 5; // 0x5
field public static final int RTT_CHANNEL_WIDTH_80 = 2; // 0x2
field public static final int RTT_CHANNEL_WIDTH_80P80 = 4; // 0x4
- field public static final int RTT_CHANNEL_WIDTH_UNSPECIFIED = -1; // 0xffffffff
+ field public static final deprecated int RTT_CHANNEL_WIDTH_UNSPECIFIED = -1; // 0xffffffff
field public static final int RTT_PEER_TYPE_AP = 1; // 0x1
field public static final int RTT_PEER_TYPE_STA = 2; // 0x2
field public static final int RTT_PEER_TYPE_UNSPECIFIED = 0; // 0x0
field public static final int RTT_STATUS_ABORTED = 8; // 0x8
field public static final int RTT_STATUS_FAILURE = 1; // 0x1
field public static final int RTT_STATUS_FAIL_AP_ON_DIFF_CHANNEL = 6; // 0x6
+ field public static final int RTT_STATUS_FAIL_BUSY_TRY_LATER = 12; // 0xc
+ field public static final int RTT_STATUS_FAIL_INVALID_TS = 9; // 0x9
field public static final int RTT_STATUS_FAIL_NOT_SCHEDULED_YET = 4; // 0x4
field public static final int RTT_STATUS_FAIL_NO_CAPABILITY = 7; // 0x7
field public static final int RTT_STATUS_FAIL_NO_RSP = 2; // 0x2
+ field public static final int RTT_STATUS_FAIL_PROTOCOL = 10; // 0xa
field public static final int RTT_STATUS_FAIL_REJECTED = 3; // 0x3
+ field public static final int RTT_STATUS_FAIL_SCHEDULE = 11; // 0xb
field public static final int RTT_STATUS_FAIL_TM_TIMEOUT = 5; // 0x5
field public static final int RTT_STATUS_SUCCESS = 0; // 0x0
- field public static final int RTT_TYPE_11_MC = 4; // 0x4
- field public static final int RTT_TYPE_11_V = 2; // 0x2
+ field public static final deprecated int RTT_TYPE_11_MC = 4; // 0x4
+ field public static final deprecated int RTT_TYPE_11_V = 2; // 0x2
field public static final int RTT_TYPE_ONE_SIDED = 1; // 0x1
- field public static final int RTT_TYPE_UNSPECIFIED = 0; // 0x0
+ field public static final int RTT_TYPE_TWO_SIDED = 4; // 0x4
+ field public static final deprecated int RTT_TYPE_UNSPECIFIED = 0; // 0x0
}
- public class RttManager.Capabilities {
+ public deprecated class RttManager.Capabilities {
ctor public RttManager.Capabilities();
field public int supportedPeerType;
field public int supportedType;
@@ -19256,6 +19271,20 @@
field public android.net.wifi.RttManager.RttResult[] mResults;
}
+ public static class RttManager.RttCapabilities implements android.os.Parcelable {
+ ctor public RttManager.RttCapabilities();
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public int bwSupported;
+ field public boolean lciSupported;
+ field public boolean lcrSupported;
+ field public boolean oneSidedRttSupported;
+ field public int preambleSupported;
+ field public deprecated boolean supportedPeerType;
+ field public deprecated boolean supportedType;
+ field public boolean twoSided11McRttSupported;
+ }
+
public static abstract interface RttManager.RttListener {
method public abstract void onAborted();
method public abstract void onFailure(int, java.lang.String);
@@ -19264,41 +19293,87 @@
public static class RttManager.RttParams {
ctor public RttManager.RttParams();
+ field public boolean LCIRequest;
+ field public boolean LCRRequest;
+ field public int bandwidth;
field public java.lang.String bssid;
+ field public int burstTimeout;
+ field public int centerFreq0;
+ field public int centerFreq1;
field public int channelWidth;
field public int deviceType;
field public int frequency;
- field public int num_retries;
- field public int num_samples;
+ field public int interval;
+ field public int numRetriesPerFTMR;
+ field public int numRetriesPerMeasurementFrame;
+ field public int numSamplesPerBurst;
+ field public deprecated int num_retries;
+ field public deprecated int num_samples;
+ field public int numberBurst;
+ field public int preamble;
field public int requestType;
}
public static class RttManager.RttResult {
ctor public RttManager.RttResult();
field public java.lang.String bssid;
- field public int distance_cm;
- field public int distance_sd_cm;
- field public int distance_spread_cm;
- field public int requestType;
+ field public int burstDuration;
+ field public int burstNumber;
+ field public int distance;
+ field public int distanceSpread;
+ field public int distanceStandardDeviation;
+ field public deprecated int distance_cm;
+ field public deprecated int distance_sd_cm;
+ field public deprecated int distance_spread_cm;
+ field public int frameNumberPerBurstPeer;
+ field public int measurementFrameNumber;
+ field public int measurementType;
+ field public deprecated int requestType;
+ field public int retryAfterDuration;
field public int rssi;
- field public int rssi_spread;
- field public long rtt_ns;
- field public long rtt_sd_ns;
- field public long rtt_spread_ns;
+ field public int rssiSpread;
+ field public deprecated int rssi_spread;
+ field public long rtt;
+ field public long rttSpread;
+ field public long rttStandardDeviation;
+ field public deprecated long rtt_ns;
+ field public deprecated long rtt_sd_ns;
+ field public deprecated long rtt_spread_ns;
+ field public int rxRate;
field public int status;
+ field public int successMeasurementFrameNumber;
field public long ts;
- field public int tx_rate;
+ field public int txRate;
+ field public deprecated int tx_rate;
+ }
+
+ public class RttManager.wifiInformationElement {
+ ctor public RttManager.wifiInformationElement();
+ field public java.lang.String data;
+ field public int id;
}
public class ScanResult implements android.os.Parcelable {
method public int describeContents();
method public void writeToParcel(android.os.Parcel, int);
field public java.lang.String BSSID;
+ field public static final int CHANNEL_WIDTH_160MHZ = 3; // 0x3
+ field public static final int CHANNEL_WIDTH_20MHZ = 0; // 0x0
+ field public static final int CHANNEL_WIDTH_40MHZ = 1; // 0x1
+ field public static final int CHANNEL_WIDTH_80MHZ = 2; // 0x2
+ field public static final int CHANNEL_WIDTH_80MHZ_PLUS_MHZ = 4; // 0x4
field public java.lang.String SSID;
field public java.lang.String capabilities;
+ field public int centerFreq0;
+ field public int centerFreq1;
+ field public int channelWidth;
field public int frequency;
+ field public boolean is80211McRTTResponder;
field public int level;
+ field public java.lang.String operatorFriendlyName;
+ field public boolean passpointNetwork;
field public long timestamp;
+ field public java.lang.String venueName;
}
public final class SupplicantState extends java.lang.Enum implements android.os.Parcelable {
@@ -19325,6 +19400,7 @@
public class WifiConfiguration implements android.os.Parcelable {
ctor public WifiConfiguration();
method public int describeContents();
+ method public boolean isPasspoint();
method public void writeToParcel(android.os.Parcel, int);
field public java.lang.String BSSID;
field public java.lang.String FQDN;
@@ -19334,6 +19410,8 @@
field public java.util.BitSet allowedKeyManagement;
field public java.util.BitSet allowedPairwiseCiphers;
field public java.util.BitSet allowedProtocols;
+ field public int apBand;
+ field public int apChannel;
field public int creatorUid;
field public android.net.wifi.WifiEnterpriseConfig enterpriseConfig;
field public boolean hiddenSSID;
@@ -19344,6 +19422,8 @@
field public int numScorerOverrideAndSwitchedNetwork;
field public java.lang.String preSharedKey;
field public int priority;
+ field public java.lang.String providerFriendlyName;
+ field public java.util.HashSet<java.lang.Long> roamingConsortiumIds;
field public int status;
field public java.lang.String[] wepKeys;
field public int wepTxKeyIndex;
@@ -19416,6 +19496,7 @@
ctor public WifiEnterpriseConfig();
ctor public WifiEnterpriseConfig(android.net.wifi.WifiEnterpriseConfig);
method public int describeContents();
+ method public java.lang.String getAltSubjectMatch();
method public java.lang.String getAnonymousIdentity();
method public java.security.cert.X509Certificate getCaCertificate();
method public java.security.cert.X509Certificate getClientCertificate();
@@ -19423,7 +19504,10 @@
method public java.lang.String getIdentity();
method public java.lang.String getPassword();
method public int getPhase2Method();
- method public java.lang.String getSubjectMatch();
+ method public java.lang.String getPlmn();
+ method public java.lang.String getRealm();
+ method public deprecated java.lang.String getSubjectMatch();
+ method public void setAltSubjectMatch(java.lang.String);
method public void setAnonymousIdentity(java.lang.String);
method public void setCaCertificate(java.security.cert.X509Certificate);
method public void setClientKeyEntry(java.security.PrivateKey, java.security.cert.X509Certificate);
@@ -19431,7 +19515,9 @@
method public void setIdentity(java.lang.String);
method public void setPassword(java.lang.String);
method public void setPhase2Method(int);
- method public void setSubjectMatch(java.lang.String);
+ method public void setPlmn(java.lang.String);
+ method public void setRealm(java.lang.String);
+ method public deprecated void setSubjectMatch(java.lang.String);
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.net.wifi.WifiEnterpriseConfig> CREATOR;
}
@@ -19595,9 +19681,11 @@
method public void configureWifiChange(android.net.wifi.WifiScanner.WifiChangeSettings);
method public android.net.wifi.ScanResult[] getScanResults();
method public void startBackgroundScan(android.net.wifi.WifiScanner.ScanSettings, android.net.wifi.WifiScanner.ScanListener);
+ method public void startScan(android.net.wifi.WifiScanner.ScanSettings, android.net.wifi.WifiScanner.ScanListener);
method public void startTrackingBssids(android.net.wifi.WifiScanner.BssidInfo[], int, android.net.wifi.WifiScanner.BssidListener);
method public void startTrackingWifiChange(android.net.wifi.WifiScanner.WifiChangeListener);
method public void stopBackgroundScan(android.net.wifi.WifiScanner.ScanListener);
+ method public void stopScan(android.net.wifi.WifiScanner.ScanListener);
method public void stopTrackingBssids(android.net.wifi.WifiScanner.BssidListener);
method public void stopTrackingWifiChange(android.net.wifi.WifiScanner.WifiChangeListener);
field public static final int MAX_SCAN_PERIOD_MS = 1024000; // 0xfa000
@@ -19634,6 +19722,7 @@
public static abstract interface WifiScanner.BssidListener implements android.net.wifi.WifiScanner.ActionListener {
method public abstract void onFound(android.net.wifi.ScanResult[]);
+ method public abstract void onLost(android.net.wifi.ScanResult[]);
}
public static class WifiScanner.ChannelSpec {
@@ -19649,10 +19738,37 @@
field public android.net.wifi.WifiScanner.BssidInfo[] bssidInfos;
}
+ public static class WifiScanner.ParcelableScanData implements android.os.Parcelable {
+ ctor public WifiScanner.ParcelableScanData(android.net.wifi.WifiScanner.ScanData[]);
+ method public int describeContents();
+ method public android.net.wifi.WifiScanner.ScanData[] getResults();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public android.net.wifi.WifiScanner.ScanData[] mResults;
+ }
+
+ public static class WifiScanner.ParcelableScanResults implements android.os.Parcelable {
+ ctor public WifiScanner.ParcelableScanResults(android.net.wifi.ScanResult[]);
+ method public int describeContents();
+ method public android.net.wifi.ScanResult[] getResults();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public android.net.wifi.ScanResult[] mResults;
+ }
+
+ public static class WifiScanner.ScanData implements android.os.Parcelable {
+ ctor public WifiScanner.ScanData(int, int, android.net.wifi.ScanResult[]);
+ ctor public WifiScanner.ScanData(android.net.wifi.WifiScanner.ScanData);
+ method public int describeContents();
+ method public int getFlags();
+ method public int getId();
+ method public android.net.wifi.ScanResult[] getResults();
+ method public void writeToParcel(android.os.Parcel, int);
+ }
+
public static abstract interface WifiScanner.ScanListener implements android.net.wifi.WifiScanner.ActionListener {
method public abstract void onFullResult(android.net.wifi.ScanResult);
method public abstract void onPeriodChanged(int);
- method public abstract void onResults(android.net.wifi.ScanResult[]);
+ method public abstract deprecated void onResults(android.net.wifi.ScanResult[]);
+ method public abstract void onResults(android.net.wifi.WifiScanner.ScanData[]);
}
public static class WifiScanner.ScanSettings implements android.os.Parcelable {
@@ -19661,6 +19777,7 @@
method public void writeToParcel(android.os.Parcel, int);
field public int band;
field public android.net.wifi.WifiScanner.ChannelSpec[] channels;
+ field public int maxScansToCache;
field public int numBssidsPerScan;
field public int periodInMs;
field public int reportEvents;
@@ -27454,6 +27571,7 @@
public static final class VoicemailContract.Status implements android.provider.BaseColumns {
method public static android.net.Uri buildSourceUri(java.lang.String);
+ method public static void setStatus(android.content.Context, android.telecom.PhoneAccountHandle, int, int, int);
field public static final java.lang.String CONFIGURATION_STATE = "configuration_state";
field public static final int CONFIGURATION_STATE_CAN_BE_CONFIGURED = 2; // 0x2
field public static final int CONFIGURATION_STATE_NOT_CONFIGURED = 1; // 0x1
@@ -27468,6 +27586,8 @@
field public static final int NOTIFICATION_CHANNEL_STATE_MESSAGE_WAITING = 2; // 0x2
field public static final int NOTIFICATION_CHANNEL_STATE_NO_CONNECTION = 1; // 0x1
field public static final int NOTIFICATION_CHANNEL_STATE_OK = 0; // 0x0
+ field public static final java.lang.String PHONE_ACCOUNT_COMPONENT_NAME = "phone_account_component_name";
+ field public static final java.lang.String PHONE_ACCOUNT_ID = "phone_account_id";
field public static final java.lang.String SETTINGS_URI = "settings_uri";
field public static final java.lang.String SOURCE_PACKAGE = "source_package";
field public static final java.lang.String VOICEMAIL_ACCESS_URI = "voicemail_access_uri";
@@ -27475,8 +27595,13 @@
public static final class VoicemailContract.Voicemails implements android.provider.BaseColumns android.provider.OpenableColumns {
method public static android.net.Uri buildSourceUri(java.lang.String);
+ method public static int deleteAll(android.content.Context);
+ method public static android.net.Uri insert(android.content.Context, android.telecom.Voicemail);
+ method public static int insert(android.content.Context, java.util.List<android.telecom.Voicemail>);
field public static final android.net.Uri CONTENT_URI;
field public static final java.lang.String DATE = "date";
+ field public static final java.lang.String DELETED = "deleted";
+ field public static final java.lang.String DIRTY = "dirty";
field public static final java.lang.String DIR_TYPE = "vnd.android.cursor.dir/voicemails";
field public static final java.lang.String DURATION = "duration";
field public static final java.lang.String HAS_CONTENT = "has_content";
@@ -27484,6 +27609,8 @@
field public static final java.lang.String ITEM_TYPE = "vnd.android.cursor.item/voicemail";
field public static final java.lang.String MIME_TYPE = "mime_type";
field public static final java.lang.String NUMBER = "number";
+ field public static final java.lang.String PHONE_ACCOUNT_COMPONENT_NAME = "subscription_component_name";
+ field public static final java.lang.String PHONE_ACCOUNT_ID = "subscription_id";
field public static final java.lang.String SOURCE_DATA = "source_data";
field public static final java.lang.String SOURCE_PACKAGE = "source_package";
field public static final java.lang.String TRANSCRIPTION = "transcription";
@@ -29896,6 +30023,22 @@
field public final int supportedRouteMask;
}
+ public class AuthenticatorService extends android.app.Service {
+ ctor public AuthenticatorService();
+ method public android.os.IBinder onBind(android.content.Intent);
+ }
+
+ public class AuthenticatorService.Authenticator extends android.accounts.AbstractAccountAuthenticator {
+ ctor public AuthenticatorService.Authenticator(android.content.Context);
+ method public android.os.Bundle addAccount(android.accounts.AccountAuthenticatorResponse, java.lang.String, java.lang.String, java.lang.String[], android.os.Bundle) throws android.accounts.NetworkErrorException;
+ method public android.os.Bundle confirmCredentials(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, android.os.Bundle) throws android.accounts.NetworkErrorException;
+ method public android.os.Bundle editProperties(android.accounts.AccountAuthenticatorResponse, java.lang.String);
+ method public android.os.Bundle getAuthToken(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String, android.os.Bundle) throws android.accounts.NetworkErrorException;
+ method public java.lang.String getAuthTokenLabel(java.lang.String);
+ method public android.os.Bundle hasFeatures(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String[]) throws android.accounts.NetworkErrorException;
+ method public android.os.Bundle updateCredentials(android.accounts.AccountAuthenticatorResponse, android.accounts.Account, java.lang.String, android.os.Bundle) throws android.accounts.NetworkErrorException;
+ }
+
public final class Call {
method public void addListener(android.telecom.Call.Listener);
method public void answer(int);
@@ -30202,10 +30345,14 @@
method public java.util.List<java.lang.String> getSupportedUriSchemes();
method public boolean hasCapabilities(int);
method public boolean supportsUriScheme(java.lang.String);
+ method public android.telecom.PhoneAccount.Builder toBuilder();
method public void writeToParcel(android.os.Parcel, int);
+ field public static final int CAPABILITY_CALL_PROVIDER = 2; // 0x2
field public static final int CAPABILITY_CONNECTION_MANAGER = 1; // 0x1
+ field public static final int CAPABILITY_MULTI_USER = 32; // 0x20
field public static final int CAPABILITY_PLACE_EMERGENCY_CALLS = 16; // 0x10
field public static final int CAPABILITY_SIM_SUBSCRIPTION = 4; // 0x4
+ field public static final int CAPABILITY_VIDEO_CALLING = 8; // 0x8
field public static final android.os.Parcelable.Creator<android.telecom.PhoneAccount> CREATOR;
field public static final int NO_HIGHLIGHT_COLOR = 0; // 0x0
field public static final int NO_ICON_TINT = 0; // 0x0
@@ -30218,7 +30365,9 @@
public static class PhoneAccount.Builder {
ctor public PhoneAccount.Builder(android.telecom.PhoneAccountHandle, java.lang.CharSequence);
ctor public PhoneAccount.Builder(android.telecom.PhoneAccount);
+ method public android.telecom.PhoneAccount.Builder addSupportedUriScheme(java.lang.String);
method public android.telecom.PhoneAccount build();
+ method public android.telecom.PhoneAccount.Builder setAccountHandle(android.telecom.PhoneAccountHandle);
method public android.telecom.PhoneAccount.Builder setAddress(android.net.Uri);
method public android.telecom.PhoneAccount.Builder setCapabilities(int);
method public android.telecom.PhoneAccount.Builder setHighlightColor(int);
@@ -30234,9 +30383,11 @@
public class PhoneAccountHandle implements android.os.Parcelable {
ctor public PhoneAccountHandle(android.content.ComponentName, java.lang.String);
+ ctor public PhoneAccountHandle(android.content.ComponentName, java.lang.String, android.os.UserHandle);
method public int describeContents();
method public android.content.ComponentName getComponentName();
method public java.lang.String getId();
+ method public android.os.UserHandle getUserHandle();
method public void writeToParcel(android.os.Parcel, int);
field public static final android.os.Parcelable.Creator<android.telecom.PhoneAccountHandle> CREATOR;
}
@@ -30361,6 +30512,7 @@
method public void unregisterPhoneAccount(android.telecom.PhoneAccountHandle);
field public static final java.lang.String ACTION_CHANGE_PHONE_ACCOUNTS = "android.telecom.action.CHANGE_PHONE_ACCOUNTS";
field public static final java.lang.String ACTION_CONNECTION_SERVICE_CONFIGURE = "android.telecom.action.CONNECTION_SERVICE_CONFIGURE";
+ field public static final java.lang.String ACTION_PHONE_ACCOUNT_REGISTERED = "android.telecom.action.PHONE_ACCOUNT_REGISTERED";
field public static final java.lang.String ACTION_SHOW_CALL_SETTINGS = "android.telecom.action.SHOW_CALL_SETTINGS";
field public static final char DTMF_CHARACTER_PAUSE = 44; // 0x002c ','
field public static final char DTMF_CHARACTER_WAIT = 59; // 0x003b ';'
@@ -30372,6 +30524,7 @@
field public static final java.lang.String EXTRA_OUTGOING_CALL_EXTRAS = "android.telecom.extra.OUTGOING_CALL_EXTRAS";
field public static final java.lang.String EXTRA_PHONE_ACCOUNT_HANDLE = "android.telecom.extra.PHONE_ACCOUNT_HANDLE";
field public static final java.lang.String EXTRA_START_CALL_WITH_SPEAKERPHONE = "android.telecom.extra.START_CALL_WITH_SPEAKERPHONE";
+ field public static final java.lang.String EXTRA_START_CALL_WITH_VIDEO_STATE = "android.telecom.extra.START_CALL_WITH_VIDEO_STATE";
field public static final java.lang.String GATEWAY_ORIGINAL_ADDRESS = "android.telecom.extra.GATEWAY_ORIGINAL_ADDRESS";
field public static final java.lang.String GATEWAY_PROVIDER_PACKAGE = "android.telecom.extra.GATEWAY_PROVIDER_PACKAGE";
field public static final int PRESENTATION_ALLOWED = 1; // 0x1
@@ -30380,6 +30533,63 @@
field public static final int PRESENTATION_UNKNOWN = 3; // 0x3
}
+ public class VideoProfile implements android.os.Parcelable {
+ ctor public VideoProfile(int);
+ ctor public VideoProfile(int, int);
+ method public int describeContents();
+ method public int getQuality();
+ method public int getVideoState();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.telecom.VideoProfile> CREATOR;
+ field public static final int QUALITY_DEFAULT = 4; // 0x4
+ field public static final int QUALITY_HIGH = 1; // 0x1
+ field public static final int QUALITY_LOW = 3; // 0x3
+ field public static final int QUALITY_MEDIUM = 2; // 0x2
+ }
+
+ public static class VideoProfile.VideoState {
+ ctor public VideoProfile.VideoState();
+ method public static boolean isAudioOnly(int);
+ method public static boolean isBidirectional(int);
+ method public static boolean isPaused(int);
+ method public static boolean isReceptionEnabled(int);
+ method public static boolean isTransmissionEnabled(int);
+ field public static final int AUDIO_ONLY = 0; // 0x0
+ field public static final int BIDIRECTIONAL = 3; // 0x3
+ field public static final int PAUSED = 4; // 0x4
+ field public static final int RX_ENABLED = 2; // 0x2
+ field public static final int TX_ENABLED = 1; // 0x1
+ }
+
+ public class Voicemail implements android.os.Parcelable {
+ method public static android.telecom.Voicemail.Builder createForInsertion(long, java.lang.String);
+ method public int describeContents();
+ method public long getDuration();
+ method public long getId();
+ method public java.lang.String getNumber();
+ method public java.lang.String getSourceData();
+ method public java.lang.String getSourcePackage();
+ method public long getTimestampMillis();
+ method public android.net.Uri getUri();
+ method public boolean hasContent();
+ method public boolean isRead();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.telecom.Voicemail> CREATOR;
+ }
+
+ public static class Voicemail.Builder {
+ method public android.telecom.Voicemail build();
+ method public android.telecom.Voicemail.Builder setDuration(long);
+ method public android.telecom.Voicemail.Builder setHasContent(boolean);
+ method public android.telecom.Voicemail.Builder setId(long);
+ method public android.telecom.Voicemail.Builder setIsRead(boolean);
+ method public android.telecom.Voicemail.Builder setNumber(java.lang.String);
+ method public android.telecom.Voicemail.Builder setSourceData(java.lang.String);
+ method public android.telecom.Voicemail.Builder setSourcePackage(java.lang.String);
+ method public android.telecom.Voicemail.Builder setTimestamp(long);
+ method public android.telecom.Voicemail.Builder setUri(android.net.Uri);
+ }
+
}
package android.telephony {
@@ -30573,6 +30783,7 @@
public class PhoneNumberUtils {
ctor public PhoneNumberUtils();
+ method public static void addPhoneTtsSpan(android.text.Spannable, int, int);
method public static java.lang.String calledPartyBCDFragmentToString(byte[], int, int);
method public static java.lang.String calledPartyBCDToString(byte[], int, int);
method public static boolean compare(java.lang.String, java.lang.String);
@@ -30589,6 +30800,8 @@
method public static java.lang.String formatNumberToE164(java.lang.String, java.lang.String);
method public static deprecated int getFormatTypeForLocale(java.util.Locale);
method public static java.lang.String getNumberFromIntent(android.content.Intent, android.content.Context);
+ method public static android.text.style.TtsSpan getPhoneTtsSpan(java.lang.String);
+ method public static java.lang.CharSequence getPhoneTtsSpannable(java.lang.CharSequence);
method public static java.lang.String getStrippedReversed(java.lang.String);
method public static final boolean is12Key(char);
method public static final boolean isDialable(char);
diff --git a/core/java/android/bluetooth/le/ScanSettings.java b/core/java/android/bluetooth/le/ScanSettings.java
index 7eae439..5bdfdb5 100644
--- a/core/java/android/bluetooth/le/ScanSettings.java
+++ b/core/java/android/bluetooth/le/ScanSettings.java
@@ -25,6 +25,15 @@
* parameters for the scan.
*/
public final class ScanSettings implements Parcelable {
+
+ /**
+ * A special Bluetooth LE scan mode. Applications using this scan mode will passively listen for
+ * other scan results without starting BLE scans themselves.
+ *
+ * @hide
+ */
+ public static final int SCAN_MODE_OPPORTUNISTIC = -1;
+
/**
* Perform Bluetooth LE scan in low power mode. This is the default scan mode as it consumes the
* least power.
@@ -177,7 +186,7 @@
* @throws IllegalArgumentException If the {@code scanMode} is invalid.
*/
public Builder setScanMode(int scanMode) {
- if (scanMode < SCAN_MODE_LOW_POWER || scanMode > SCAN_MODE_LOW_LATENCY) {
+ if (scanMode < SCAN_MODE_OPPORTUNISTIC || scanMode > SCAN_MODE_LOW_LATENCY) {
throw new IllegalArgumentException("invalid scan mode " + scanMode);
}
mScanMode = scanMode;
diff --git a/core/java/android/net/BaseDhcpStateMachine.java b/core/java/android/net/BaseDhcpStateMachine.java
new file mode 100644
index 0000000..a25847d
--- /dev/null
+++ b/core/java/android/net/BaseDhcpStateMachine.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2015 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;
+
+import com.android.internal.util.StateMachine;
+
+/**
+ * Interface that must be implemented by DHCP state machines.
+ *
+ * This is an abstract class instead of a Java interface so that callers can just declare an object
+ * of this type and be able to call all the methods defined by either StateMachine or this class.
+ *
+ * @hide
+ */
+public abstract class BaseDhcpStateMachine extends StateMachine {
+ protected BaseDhcpStateMachine(String tag) {
+ super(tag);
+ }
+ public abstract void registerForPreDhcpNotification();
+ public abstract void doQuit();
+}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index eb2df0b..3b0d567 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -2370,7 +2370,7 @@
* successfully finding a network for the applications request. Retrieve it with
* {@link android.content.Intent#getParcelableExtra(String)}.
* <p>
- * Note that if you intend to invoke (@link #setProcessDefaultNetwork(Network)) or
+ * Note that if you intend to invoke {@link #setProcessDefaultNetwork} or
* {@link Network#openConnection(java.net.URL)} then you must get a
* ConnectivityManager instance before doing so.
*/
diff --git a/core/java/android/net/DhcpStateMachine.java b/core/java/android/net/DhcpStateMachine.java
index 5151a04..1b8adc8 100644
--- a/core/java/android/net/DhcpStateMachine.java
+++ b/core/java/android/net/DhcpStateMachine.java
@@ -47,7 +47,7 @@
*
* @hide
*/
-public class DhcpStateMachine extends StateMachine {
+public class DhcpStateMachine extends BaseDhcpStateMachine {
private static final String TAG = "DhcpStateMachine";
private static final boolean DBG = false;
@@ -161,6 +161,7 @@
* This is used by Wifi at this time for the purpose of doing BT-Wifi coex
* handling during Dhcp
*/
+ @Override
public void registerForPreDhcpNotification() {
mRegisteredForPreDhcpNotification = true;
}
@@ -170,6 +171,7 @@
*
* @hide
*/
+ @Override
public void doQuit() {
quit();
}
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index d2a2997..02fbe73 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -16,9 +16,11 @@
package android.net;
+import java.io.FileDescriptor;
import java.net.InetAddress;
import java.net.Inet4Address;
import java.net.Inet6Address;
+import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Collection;
import java.util.Locale;
@@ -56,6 +58,30 @@
/**
* Start the DHCP client daemon, in order to have it request addresses
+ * for the named interface. This returns {@code true} if the DHCPv4 daemon
+ * starts, {@code false} otherwise. This call blocks until such time as a
+ * result is available or the default discovery timeout has been reached.
+ * Callers should check {@link #getDhcpResults} to determine whether DHCP
+ * succeeded or failed, and if it succeeded, to fetch the {@link DhcpResults}.
+ * @param interfaceName the name of the interface to configure
+ * @return {@code true} for success, {@code false} for failure
+ */
+ public native static boolean startDhcp(String interfaceName);
+
+ /**
+ * Initiate renewal on the DHCP client daemon for the named interface. This
+ * returns {@code true} if the DHCPv4 daemon has been notified, {@code false}
+ * otherwise. This call blocks until such time as a result is available or
+ * the default renew timeout has been reached. Callers should check
+ * {@link #getDhcpResults} to determine whether DHCP succeeded or failed,
+ * and if it succeeded, to fetch the {@link DhcpResults}.
+ * @param interfaceName the name of the interface to configure
+ * @return {@code true} for success, {@code false} for failure
+ */
+ public native static boolean startDhcpRenew(String interfaceName);
+
+ /**
+ * Start the DHCP client daemon, in order to have it request addresses
* for the named interface, and then configure the interface with those
* addresses. This call blocks until it obtains a result (either success
* or failure) from the daemon.
@@ -64,17 +90,31 @@
* the IP address information.
* @return {@code true} for success, {@code false} for failure
*/
- public native static boolean runDhcp(String interfaceName, DhcpResults dhcpResults);
+ public static boolean runDhcp(String interfaceName, DhcpResults dhcpResults) {
+ return startDhcp(interfaceName) && getDhcpResults(interfaceName, dhcpResults);
+ }
/**
- * Initiate renewal on the Dhcp client daemon. This call blocks until it obtains
+ * Initiate renewal on the DHCP client daemon. This call blocks until it obtains
* a result (either success or failure) from the daemon.
* @param interfaceName the name of the interface to configure
* @param dhcpResults if the request succeeds, this object is filled in with
* the IP address information.
* @return {@code true} for success, {@code false} for failure
*/
- public native static boolean runDhcpRenew(String interfaceName, DhcpResults dhcpResults);
+ public static boolean runDhcpRenew(String interfaceName, DhcpResults dhcpResults) {
+ return startDhcpRenew(interfaceName) && getDhcpResults(interfaceName, dhcpResults);
+ }
+
+ /**
+ * Fetch results from the DHCP client daemon. This call returns {@code true} if
+ * if there are results available to be read, {@code false} otherwise.
+ * @param interfaceName the name of the interface to configure
+ * @param dhcpResults if the request succeeds, this object is filled in with
+ * the IP address information.
+ * @return {@code true} for success, {@code false} for failure
+ */
+ public native static boolean getDhcpResults(String interfaceName, DhcpResults dhcpResults);
/**
* Shut down the DHCP client daemon.
@@ -101,6 +141,11 @@
public native static String getDhcpError();
/**
+ * Attaches a socket filter that accepts DHCP packets to the given socket.
+ */
+ public native static void attachDhcpFilter(FileDescriptor fd) throws SocketException;
+
+ /**
* Binds the current process to the network designated by {@code netId}. All sockets created
* in the future (and not explicitly bound via a bound {@link SocketFactory} (see
* {@link Network#getSocketFactory}) will be bound to this network. Note that if this
@@ -133,6 +178,15 @@
public native static int bindSocketToNetwork(int socketfd, int netId);
/**
+ * Protect {@code fd} from VPN connections. After protecting, data sent through
+ * this socket will go directly to the underlying network, so its traffic will not be
+ * forwarded through the VPN.
+ */
+ public static boolean protectFromVpn(FileDescriptor fd) {
+ return protectFromVpn(fd.getInt$());
+ }
+
+ /**
* Protect {@code socketfd} from VPN connections. After protecting, data sent through
* this socket will go directly to the underlying network, so its traffic will not be
* forwarded through the VPN.
@@ -192,6 +246,25 @@
}
/**
+ * Convert an IPv4 netmask to a prefix length, checking that the netmask is contiguous.
+ * @param netmask as a {@code Inet4Address}.
+ * @return the network prefix length
+ * @throws IllegalArgumentException the specified netmask was not contiguous.
+ * @hide
+ */
+ public static int netmaskToPrefixLength(Inet4Address netmask) {
+ // inetAddressToInt returns an int in *network* byte order.
+ int i = Integer.reverseBytes(inetAddressToInt(netmask));
+ int prefixLength = Integer.bitCount(i);
+ int trailingZeros = Integer.numberOfTrailingZeros(i);
+ if (trailingZeros != 32 - prefixLength) {
+ throw new IllegalArgumentException("Non-contiguous netmask: " + Integer.toHexString(i));
+ }
+ return prefixLength;
+ }
+
+
+ /**
* Create an InetAddress from a string where the string must be a standard
* representation of a V4 or V6 address. Avoids doing a DNS lookup on failure
* but it will throw an IllegalArgumentException in that case.
@@ -271,6 +344,22 @@
}
/**
+ * Returns the implicit netmask of an IPv4 address, as was the custom before 1993.
+ */
+ public static int getImplicitNetmask(Inet4Address address) {
+ int firstByte = address.getAddress()[0] & 0xff; // Convert to an unsigned value.
+ if (firstByte < 128) {
+ return 8;
+ } else if (firstByte < 192) {
+ return 16;
+ } else if (firstByte < 224) {
+ return 24;
+ } else {
+ return 32; // Will likely not end well for other reasons.
+ }
+ }
+
+ /**
* Utility method to parse strings such as "192.0.2.5/24" or "2001:db8::cafe:d00d/64".
* @hide
*/
diff --git a/core/java/android/net/dhcp/DhcpStateMachine.java b/core/java/android/net/dhcp/DhcpStateMachine.java
deleted file mode 100644
index bc9a798..0000000
--- a/core/java/android/net/dhcp/DhcpStateMachine.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2010 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.dhcp;
-
-import java.net.InetAddress;
-import java.util.List;
-
-/**
- * This class defines the "next steps" which occur after a given DHCP
- * packet has been received.
- */
-interface DhcpStateMachine {
- /**
- * Signals that an offer packet has been received with the specified
- * parameters.
- */
- public void onOfferReceived(boolean broadcast, int transactionId,
- byte[] myMac, InetAddress offeredIpAddress,
- InetAddress serverIpAddress);
-
- /**
- * Signals that a NAK packet has been received.
- */
- public void onNakReceived();
-
- /**
- * Signals that the final ACK has been received from the server.
- */
- public void onAckReceived(InetAddress myIpAddress, InetAddress myNetMask,
- InetAddress myGateway, List<InetAddress> myDnsServers,
- InetAddress myDhcpServer, int leaseTime);
-
- /**
- * Signals that a client's DISCOVER packet has been received with the
- * specified parameters.
- */
- public void onDiscoverReceived(boolean broadcast, int transactionId,
- byte[] clientMac, byte[] requestedParameterList);
-
- /**
- * Signals that a client's REQUEST packet has been received with the
- * specified parameters.
- */
- public void onRequestReceived(boolean broadcast, int transactionId,
- byte[] clientMac, InetAddress requestedIp, byte[] requestedParams,
- String clientHostName);
-
- /**
- * Signals that a client's INFORM packet has been received with the
- * specified parameters.
- */
- public void onInformReceived(int transactionId, byte[] clientMac,
- InetAddress preassignedIp, byte[] requestedParams);
-
- /**
- * Signals that a client's DECLINE packet has been received with the
- * specified parameters.
- */
- public void onDeclineReceived(byte[] clientMac, InetAddress declinedIp);
-}
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index f023df7..2df9dbf 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -33,9 +33,12 @@
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.Data;
import android.provider.ContactsContract.DataUsageFeedback;
+import android.telecom.PhoneAccount;
import android.telecom.PhoneAccountHandle;
+import android.telecom.TelecomManager;
import android.telephony.PhoneNumberUtils;
import android.text.TextUtils;
+import android.util.Log;
import com.android.internal.telephony.CallerInfo;
import com.android.internal.telephony.PhoneConstants;
@@ -46,6 +49,8 @@
* The CallLog provider contains information about placed and received calls.
*/
public class CallLog {
+ private static final String LOG_TAG = "CallLog";
+
public static final String AUTHORITY = "call_log";
/**
@@ -336,24 +341,44 @@
// that was encoded into call log databases.
/**
- * The component name of the account in string form.
+ * The component name of the account used to place or receive the call; in string form.
* <P>Type: TEXT</P>
*/
public static final String PHONE_ACCOUNT_COMPONENT_NAME = "subscription_component_name";
/**
- * The identifier of a account that is unique to a specified component.
+ * The identifier for the account used to place or receive the call.
* <P>Type: TEXT</P>
*/
public static final String PHONE_ACCOUNT_ID = "subscription_id";
/**
- * The identifier of a account that is unique to a specified component. Equivalent value
- * to {@link #PHONE_ACCOUNT_ID}. For ContactsProvider internal use only.
+ * The address associated with the account used to place or receive the call; in string
+ * form. For SIM-based calls, this is the user's own phone number.
+ * <P>Type: TEXT</P>
+ *
+ * @hide
+ */
+ public static final String PHONE_ACCOUNT_ADDRESS = "phone_account_address";
+
+ /**
+ * Indicates that the entry will be hidden from all queries until the associated
+ * {@link android.telecom.PhoneAccount} is registered with the system.
* <P>Type: INTEGER</P>
*
* @hide
*/
+ public static final String PHONE_ACCOUNT_HIDDEN = "phone_account_hidden";
+
+ /**
+ * The subscription ID used to place this call. This is no longer used and has been
+ * replaced with PHONE_ACCOUNT_COMPONENT_NAME/PHONE_ACCOUNT_ID.
+ * For ContactsProvider internal use only.
+ * <P>Type: INTEGER</P>
+ *
+ * @Deprecated
+ * @hide
+ */
public static final String SUB_ID = "sub_id";
/**
@@ -421,6 +446,29 @@
long start, int duration, Long dataUsage, boolean addForAllUsers) {
final ContentResolver resolver = context.getContentResolver();
int numberPresentation = PRESENTATION_ALLOWED;
+ boolean isHidden = false;
+
+ TelecomManager tm = null;
+ try {
+ tm = TelecomManager.from(context);
+ } catch (UnsupportedOperationException e) {}
+
+ String accountAddress = null;
+ if (tm != null && accountHandle != null) {
+ PhoneAccount account = tm.getPhoneAccount(accountHandle);
+ if (account != null) {
+ Uri address = account.getSubscriptionAddress();
+ if (address != null) {
+ accountAddress = address.getSchemeSpecificPart();
+ }
+ } else {
+ // We could not find the account through telecom. For call log entries that
+ // are added with a phone account which is not registered, we automatically
+ // mark them as hidden. They are unhidden once the account is registered.
+ Log.i(LOG_TAG, "Marking call log entry as hidden.");
+ isHidden = true;
+ }
+ }
// Remap network specified number presentation types
// PhoneConstants.PRESENTATION_xxx to calllog number presentation types
@@ -463,6 +511,8 @@
}
values.put(PHONE_ACCOUNT_COMPONENT_NAME, accountComponentString);
values.put(PHONE_ACCOUNT_ID, accountId);
+ values.put(PHONE_ACCOUNT_ADDRESS, accountAddress);
+ values.put(PHONE_ACCOUNT_HIDDEN, Integer.valueOf(isHidden ? 1 : 0));
values.put(NEW, Integer.valueOf(1));
if (callType == MISSED_TYPE) {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index d773d4a..2647247 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -5436,6 +5436,14 @@
"hdmi_control_auto_device_off_enabled";
/**
+ * Whether to use the DHCP client from Lollipop and earlier instead of the newer Android DHCP
+ * client.
+ * (0 = false, 1 = true)
+ * @hide
+ */
+ public static final String LEGACY_DHCP_CLIENT = "legacy_dhcp_client";
+
+ /**
* Whether TV will switch to MHL port when a mobile device is plugged in.
* (0 = false, 1 = true)
* @hide
diff --git a/core/java/android/provider/VoicemailContract.java b/core/java/android/provider/VoicemailContract.java
index d71ad03..0da4fd5 100644
--- a/core/java/android/provider/VoicemailContract.java
+++ b/core/java/android/provider/VoicemailContract.java
@@ -19,10 +19,18 @@
import android.Manifest;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Context;
import android.content.Intent;
import android.database.ContentObserver;
+import android.database.Cursor;
import android.net.Uri;
import android.provider.CallLog.Calls;
+import android.telecom.PhoneAccountHandle;
+import android.telecom.Voicemail;
+
+import java.util.List;
/**
* The contract between the voicemail provider and applications. Contains
@@ -199,13 +207,100 @@
*/
public static final String _DATA = "_data";
+ // Note: PHONE_ACCOUNT_* constant values are "subscription_*" due to a historic naming
+ // that was encoded into call log databases.
+
+ /**
+ * The component name of the account in string form.
+ * <P>Type: TEXT</P>
+ */
+ public static final String PHONE_ACCOUNT_COMPONENT_NAME = "subscription_component_name";
+
+ /**
+ * The identifier of a account that is unique to a specified component.
+ * <P>Type: TEXT</P>
+ */
+ public static final String PHONE_ACCOUNT_ID = "subscription_id";
+
+ /**
+ * Flag used to indicate that local, unsynced changes are present.
+ * Currently, this is used to indicate that the voicemail was read or deleted.
+ * The value will be 1 if dirty is true, 0 if false.
+ * <P>Type: INTEGER (boolean)</P>
+ */
+ public static final String DIRTY = "dirty";
+
+ /**
+ * Flag used to indicate that the voicemail was deleted but not synced to the server.
+ * A deleted row should be ignored.
+ * The value will be 1 if deleted is true, 0 if false.
+ * <P>Type: INTEGER (boolean)</P>
+ */
+ public static final String DELETED = "deleted";
+
/**
* A convenience method to build voicemail URI specific to a source package by appending
* {@link VoicemailContract#PARAM_KEY_SOURCE_PACKAGE} param to the base URI.
*/
public static Uri buildSourceUri(String packageName) {
return Voicemails.CONTENT_URI.buildUpon()
- .appendQueryParameter(PARAM_KEY_SOURCE_PACKAGE, packageName).build();
+ .appendQueryParameter(PARAM_KEY_SOURCE_PACKAGE, packageName)
+ .build();
+ }
+
+ /**
+ * Inserts a new voicemail into the voicemail content provider.
+ *
+ * @param context The context of the app doing the inserting
+ * @param voicemail Data to be inserted
+ * @return {@link Uri} of the newly inserted {@link Voicemail}
+ */
+ public static Uri insert(Context context, Voicemail voicemail) {
+ ContentResolver contentResolver = context.getContentResolver();
+ ContentValues contentValues = getContentValues(voicemail);
+ return contentResolver.insert(Voicemails.CONTENT_URI, contentValues);
+ }
+
+ /**
+ * Inserts a list of voicemails into the voicemail content provider.
+ *
+ * @param context The context of the app doing the inserting
+ * @param voicemails Data to be inserted
+ * @return the number of voicemails inserted
+ */
+ public static int insert(Context context, List<Voicemail> voicemails) {
+ ContentResolver contentResolver = context.getContentResolver();
+ int count = voicemails.size();
+ for (int i = 0; i < count; i++) {
+ ContentValues contentValues = getContentValues(voicemails.get(i));
+ contentResolver.insert(Voicemails.CONTENT_URI, contentValues);
+ }
+ return count;
+ }
+
+ /**
+ * Clears all voicemails accessible to this voicemail content provider for the calling
+ * package. By default, a package only has permission to delete voicemails it inserted.
+ *
+ * @return the number of voicemails deleted
+ */
+ public static int deleteAll(Context context) {
+ return context.getContentResolver().delete(
+ buildSourceUri(context.getPackageName()), "", new String[0]);
+ }
+
+ /**
+ * Maps structured {@link Voicemail} to {@link ContentValues} in content provider.
+ */
+ private static ContentValues getContentValues(Voicemail voicemail) {
+ ContentValues contentValues = new ContentValues();
+ contentValues.put(Voicemails.DATE, String.valueOf(voicemail.getTimestampMillis()));
+ contentValues.put(Voicemails.NUMBER, voicemail.getNumber());
+ contentValues.put(Voicemails.DURATION, String.valueOf(voicemail.getDuration()));
+ contentValues.put(Voicemails.SOURCE_PACKAGE, voicemail.getSourcePackage());
+ contentValues.put(Voicemails.SOURCE_DATA, voicemail.getSourceData());
+ contentValues.put(Voicemails.IS_READ, voicemail.isRead() ? 1 : 0);
+ return contentValues;
}
}
@@ -222,10 +317,27 @@
private Status() {
}
/**
- * The package name of the voicemail source. There can only be a one entry per source.
+ * The package name of the voicemail source. There can only be a one entry per account
+ * per source.
* <P>Type: TEXT</P>
*/
public static final String SOURCE_PACKAGE = SOURCE_PACKAGE_FIELD;
+
+ // Note: Multiple entries may exist for a single source if they are differentiated by the
+ // PHONE_ACCOUNT_* fields.
+
+ /**
+ * The component name of the account in string form.
+ * <P>Type: TEXT</P>
+ */
+ public static final String PHONE_ACCOUNT_COMPONENT_NAME = "phone_account_component_name";
+
+ /**
+ * The identifier of a account that is unique to a specified component.
+ * <P>Type: TEXT</P>
+ */
+ public static final String PHONE_ACCOUNT_ID = "phone_account_id";
+
/**
* The URI to call to invoke source specific voicemail settings screen. On a user request
* to setup voicemail an intent with action VIEW with this URI will be fired by the system.
@@ -318,5 +430,50 @@
return Status.CONTENT_URI.buildUpon()
.appendQueryParameter(PARAM_KEY_SOURCE_PACKAGE, packageName).build();
}
+
+ /**
+ * A helper method to set the status of a voicemail source.
+ *
+ * @param context The context from the package calling the method. This will be the source.
+ * @param accountHandle The handle for the account the source is associated with.
+ * @param configurationState See {@link Status#CONFIGURATION_STATE}
+ * @param dataChannelState See {@link Status#DATA_CHANNEL_STATE}
+ * @param notificationChannelState See {@link Status#NOTIFICATION_CHANNEL_STATE}
+ */
+ public static void setStatus(Context context, PhoneAccountHandle accountHandle,
+ int configurationState, int dataChannelState, int notificationChannelState) {
+ ContentResolver contentResolver = context.getContentResolver();
+ Uri statusUri = buildSourceUri(context.getPackageName());
+ ContentValues values = new ContentValues();
+ values.put(Status.PHONE_ACCOUNT_COMPONENT_NAME,
+ accountHandle.getComponentName().toString());
+ values.put(Status.PHONE_ACCOUNT_ID, accountHandle.getId());
+ values.put(Status.CONFIGURATION_STATE, configurationState);
+ values.put(Status.DATA_CHANNEL_STATE, dataChannelState);
+ values.put(Status.NOTIFICATION_CHANNEL_STATE, notificationChannelState);
+
+ if (isStatusPresent(contentResolver, statusUri)) {
+ contentResolver.update(statusUri, values, null, null);
+ } else {
+ contentResolver.insert(statusUri, values);
+ }
+ }
+
+ /**
+ * Determines if a voicemail source exists in the status table.
+ *
+ * @param contentResolver A content resolver constructed from the appropriate context.
+ * @param statusUri The content uri for the source.
+ * @return {@code true} if a status entry for this source exists
+ */
+ private static boolean isStatusPresent(ContentResolver contentResolver, Uri statusUri) {
+ Cursor cursor = null;
+ try {
+ cursor = contentResolver.query(statusUri, null, null, null, null);
+ return cursor != null && cursor.getCount() != 0;
+ } finally {
+ if (cursor != null) cursor.close();
+ }
+ }
}
}
diff --git a/core/java/com/android/internal/util/Protocol.java b/core/java/com/android/internal/util/Protocol.java
index d9ebc25..a106f48 100644
--- a/core/java/com/android/internal/util/Protocol.java
+++ b/core/java/com/android/internal/util/Protocol.java
@@ -52,6 +52,7 @@
public static final int BASE_WIFI_RTT_SERVICE = 0x00027300;
public static final int BASE_WIFI_PASSPOINT_MANAGER = 0x00028000;
public static final int BASE_WIFI_PASSPOINT_SERVICE = 0x00028100;
+ public static final int BASE_WIFI_LOGGER = 0x00028300;
public static final int BASE_DHCP = 0x00030000;
public static final int BASE_DATA_CONNECTION = 0x00040000;
public static final int BASE_DATA_CONNECTION_AC = 0x00041000;
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index 8b9f574..e97d61e 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -24,6 +24,14 @@
#include <android_runtime/AndroidRuntime.h>
#include <utils/Log.h>
#include <arpa/inet.h>
+#include <net/if.h>
+#include <linux/filter.h>
+#include <linux/if.h>
+#include <linux/if_ether.h>
+#include <linux/if_packet.h>
+#include <net/if_ether.h>
+#include <netinet/ip.h>
+#include <netinet/udp.h>
#include <cutils/properties.h>
extern "C" {
@@ -31,27 +39,18 @@
int ifc_disable(const char *ifname);
int ifc_reset_connections(const char *ifname, int reset_mask);
-int dhcp_do_request(const char * const ifname,
- const char *ipaddr,
- const char *gateway,
- uint32_t *prefixLength,
- const char *dns[],
- const char *server,
- uint32_t *lease,
- const char *vendorInfo,
- const char *domains,
- const char *mtu);
-
-int dhcp_do_request_renew(const char * const ifname,
- const char *ipaddr,
- const char *gateway,
- uint32_t *prefixLength,
- const char *dns[],
- const char *server,
- uint32_t *lease,
- const char *vendorInfo,
- const char *domains,
- const char *mtu);
+int dhcp_start(const char * const ifname);
+int dhcp_start_renew(const char * const ifname);
+int dhcp_get_results(const char * const ifname,
+ const char *ipaddr,
+ const char *gateway,
+ uint32_t *prefixLength,
+ const char *dns[],
+ const char *server,
+ uint32_t *lease,
+ const char *vendorInfo,
+ const char *domains,
+ const char *mtu);
int dhcp_stop(const char *ifname);
int dhcp_release_lease(const char *ifname);
@@ -62,6 +61,8 @@
namespace android {
+static const uint16_t kDhcpClientPort = 68;
+
/*
* The following remembers the jfieldID's of the fields
* of the DhcpInfo Java object, so that we don't have
@@ -93,8 +94,8 @@
return (jint)result;
}
-static jboolean android_net_utils_runDhcpCommon(JNIEnv* env, jobject clazz, jstring ifname,
- jobject dhcpResults, bool renew)
+static jboolean android_net_utils_getDhcpResults(JNIEnv* env, jobject clazz, jstring ifname,
+ jobject dhcpResults)
{
int result;
char ipaddr[PROPERTY_VALUE_MAX];
@@ -114,15 +115,10 @@
const char *nameStr = env->GetStringUTFChars(ifname, NULL);
if (nameStr == NULL) return (jboolean)false;
- if (renew) {
- result = ::dhcp_do_request_renew(nameStr, ipaddr, gateway, &prefixLength,
- dns, server, &lease, vendorInfo, domains, mtu);
- } else {
- result = ::dhcp_do_request(nameStr, ipaddr, gateway, &prefixLength,
- dns, server, &lease, vendorInfo, domains, mtu);
- }
+ result = ::dhcp_get_results(nameStr, ipaddr, gateway, &prefixLength,
+ dns, server, &lease, vendorInfo, domains, mtu);
if (result != 0) {
- ALOGD("dhcp_do_request failed : %s (%s)", nameStr, renew ? "renew" : "new");
+ ALOGD("dhcp_get_results failed : %s (%s)", nameStr, ::dhcp_get_errmsg());
}
env->ReleaseStringUTFChars(ifname, nameStr);
@@ -182,19 +178,28 @@
return (jboolean)(result == 0);
}
-
-static jboolean android_net_utils_runDhcp(JNIEnv* env, jobject clazz, jstring ifname, jobject info)
+static jboolean android_net_utils_startDhcp(JNIEnv* env, jobject clazz, jstring ifname)
{
- return android_net_utils_runDhcpCommon(env, clazz, ifname, info, false);
+ const char *nameStr = env->GetStringUTFChars(ifname, NULL);
+ if (nameStr == NULL) return (jboolean)false;
+ if (::dhcp_start(nameStr) != 0) {
+ ALOGD("dhcp_start failed : %s", nameStr);
+ return (jboolean)false;
+ }
+ return (jboolean)true;
}
-static jboolean android_net_utils_runDhcpRenew(JNIEnv* env, jobject clazz, jstring ifname,
- jobject info)
+static jboolean android_net_utils_startDhcpRenew(JNIEnv* env, jobject clazz, jstring ifname)
{
- return android_net_utils_runDhcpCommon(env, clazz, ifname, info, true);
+ const char *nameStr = env->GetStringUTFChars(ifname, NULL);
+ if (nameStr == NULL) return (jboolean)false;
+ if (::dhcp_start_renew(nameStr) != 0) {
+ ALOGD("dhcp_start_renew failed : %s", nameStr);
+ return (jboolean)false;
+ }
+ return (jboolean)true;
}
-
static jboolean android_net_utils_stopDhcp(JNIEnv* env, jobject clazz, jstring ifname)
{
int result;
@@ -220,6 +225,44 @@
return env->NewStringUTF(::dhcp_get_errmsg());
}
+static void android_net_utils_attachDhcpFilter(JNIEnv *env, jobject clazz, jobject javaFd)
+{
+ int fd = jniGetFDFromFileDescriptor(env, javaFd);
+ uint32_t ip_offset = sizeof(ether_header);
+ uint32_t proto_offset = ip_offset + offsetof(iphdr, protocol);
+ uint32_t flags_offset = ip_offset + offsetof(iphdr, frag_off);
+ uint32_t dport_indirect_offset = ip_offset + offsetof(udphdr, dest);
+ struct sock_filter filter_code[] = {
+ // Check the protocol is UDP.
+ BPF_STMT(BPF_LD | BPF_B | BPF_ABS, proto_offset),
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, IPPROTO_UDP, 0, 6),
+
+ // Check this is not a fragment.
+ BPF_STMT(BPF_LD | BPF_H | BPF_ABS, flags_offset),
+ BPF_JUMP(BPF_JMP | BPF_JSET | BPF_K, 0x1fff, 4, 0),
+
+ // Get the IP header length.
+ BPF_STMT(BPF_LDX | BPF_B | BPF_MSH, ip_offset),
+
+ // Check the destination port.
+ BPF_STMT(BPF_LD | BPF_H | BPF_IND, dport_indirect_offset),
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, kDhcpClientPort, 0, 1),
+
+ // Accept or reject.
+ BPF_STMT(BPF_RET | BPF_K, 0xffff),
+ BPF_STMT(BPF_RET | BPF_K, 0)
+ };
+ struct sock_fprog filter = {
+ sizeof(filter_code) / sizeof(filter_code[0]),
+ filter_code,
+ };
+
+ if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) != 0) {
+ jniThrowExceptionFmt(env, "java/net/SocketException",
+ "setsockopt(SO_ATTACH_FILTER): %s", strerror(errno));
+ }
+}
+
static jboolean android_net_utils_bindProcessToNetwork(JNIEnv *env, jobject thiz, jint netId)
{
return (jboolean) !setNetworkForProcess(netId);
@@ -247,6 +290,7 @@
return (jboolean) !protectFromVpn(socket);
}
+
// ----------------------------------------------------------------------------
/*
@@ -255,8 +299,9 @@
static JNINativeMethod gNetworkUtilMethods[] = {
/* name, signature, funcPtr */
{ "resetConnections", "(Ljava/lang/String;I)I", (void *)android_net_utils_resetConnections },
- { "runDhcp", "(Ljava/lang/String;Landroid/net/DhcpResults;)Z", (void *)android_net_utils_runDhcp },
- { "runDhcpRenew", "(Ljava/lang/String;Landroid/net/DhcpResults;)Z", (void *)android_net_utils_runDhcpRenew },
+ { "startDhcp", "(Ljava/lang/String;)Z", (void *)android_net_utils_startDhcp },
+ { "startDhcpRenew", "(Ljava/lang/String;)Z", (void *)android_net_utils_startDhcpRenew },
+ { "getDhcpResults", "(Ljava/lang/String;Landroid/net/DhcpResults;)Z", (void *)android_net_utils_getDhcpResults },
{ "stopDhcp", "(Ljava/lang/String;)Z", (void *)android_net_utils_stopDhcp },
{ "releaseDhcpLease", "(Ljava/lang/String;)Z", (void *)android_net_utils_releaseDhcpLease },
{ "getDhcpError", "()Ljava/lang/String;", (void*) android_net_utils_getDhcpError },
@@ -265,6 +310,7 @@
{ "bindProcessToNetworkForHostResolution", "(I)Z", (void*) android_net_utils_bindProcessToNetworkForHostResolution },
{ "bindSocketToNetwork", "(II)I", (void*) android_net_utils_bindSocketToNetwork },
{ "protectFromVpn", "(I)Z", (void*)android_net_utils_protectFromVpn },
+ { "attachDhcpFilter", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_attachDhcpFilter },
};
int register_android_net_NetworkUtils(JNIEnv* env)
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 3de2268..ad328a6 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1087,6 +1087,18 @@
device does not support multiple advertisement-->
<integer translatable="false" name="config_bluetooth_max_advertisers">0</integer>
+ <!-- Idle current for bluetooth controller. 0 by default-->
+ <integer translatable="false" name="config_bluetooth_idle_cur_ma">1</integer>
+
+ <!-- Rx current for bluetooth controller. 0 by default-->
+ <integer translatable="false" name="config_bluetooth_rx_cur_ma">2</integer>
+
+ <!-- Tx current for bluetooth controller. 0 by default-->
+ <integer translatable="false" name="config_bluetooth_tx_cur_ma">3</integer>
+
+ <!-- Operating volatage for bluetooth controller. 0 by default-->
+ <integer translatable="false" name="config_bluetooth_operating_voltage_mv">4</integer>
+
<!-- The default data-use polling period. -->
<integer name="config_datause_polling_period_sec">600</integer>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 9f71093..fc0b753 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3830,10 +3830,10 @@
</plurals>
<!-- A notification is shown when a wifi captive portal network is detected. This is the notification's title. -->
- <string name="wifi_available_sign_in">Sign into Wi-Fi network</string>
+ <string name="wifi_available_sign_in">Sign in to Wi-Fi network</string>
<!-- A notification is shown when a captive portal network is detected. This is the notification's title. -->
- <string name="network_available_sign_in">Sign into network</string>
+ <string name="network_available_sign_in">Sign in to network</string>
<!-- A notification is shown when a captive portal network is detected. This is the notification's message. -->
<string name="network_available_sign_in_detailed"><xliff:g id="network_ssid">%1$s</xliff:g></string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index e10ea63..997225c 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -344,6 +344,10 @@
<java-symbol type="integer" name="config_wifi_framework_current_network_boost" />
<java-symbol type="integer" name="config_bluetooth_max_advertisers" />
<java-symbol type="integer" name="config_bluetooth_max_scan_filters" />
+ <java-symbol type="integer" name="config_bluetooth_idle_cur_ma" />
+ <java-symbol type="integer" name="config_bluetooth_rx_cur_ma" />
+ <java-symbol type="integer" name="config_bluetooth_tx_cur_ma" />
+ <java-symbol type="integer" name="config_bluetooth_operating_voltage_mv" />
<java-symbol type="integer" name="config_cursorWindowSize" />
<java-symbol type="integer" name="config_doublePressOnPowerBehavior" />
<java-symbol type="integer" name="config_extraFreeKbytesAdjust" />
diff --git a/core/tests/coretests/src/android/net/NetworkUtilsTest.java b/core/tests/coretests/src/android/net/NetworkUtilsTest.java
new file mode 100644
index 0000000..8d51c3b
--- /dev/null
+++ b/core/tests/coretests/src/android/net/NetworkUtilsTest.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2015 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;
+
+import android.net.NetworkUtils;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import java.net.Inet4Address;
+import java.net.InetAddress;
+
+import junit.framework.TestCase;
+
+public class NetworkUtilsTest extends TestCase {
+
+ private InetAddress Address(String addr) {
+ return InetAddress.parseNumericAddress(addr);
+ }
+
+ private Inet4Address IPv4Address(String addr) {
+ return (Inet4Address) Address(addr);
+ }
+
+ @SmallTest
+ public void testGetImplicitNetmask() {
+ assertEquals(8, NetworkUtils.getImplicitNetmask(IPv4Address("4.2.2.2")));
+ assertEquals(8, NetworkUtils.getImplicitNetmask(IPv4Address("10.5.6.7")));
+ assertEquals(16, NetworkUtils.getImplicitNetmask(IPv4Address("173.194.72.105")));
+ assertEquals(16, NetworkUtils.getImplicitNetmask(IPv4Address("172.23.68.145")));
+ assertEquals(24, NetworkUtils.getImplicitNetmask(IPv4Address("192.0.2.1")));
+ assertEquals(24, NetworkUtils.getImplicitNetmask(IPv4Address("192.168.5.1")));
+ assertEquals(32, NetworkUtils.getImplicitNetmask(IPv4Address("224.0.0.1")));
+ assertEquals(32, NetworkUtils.getImplicitNetmask(IPv4Address("255.6.7.8")));
+ }
+
+ private void assertInvalidNetworkMask(Inet4Address addr) {
+ try {
+ NetworkUtils.netmaskToPrefixLength(addr);
+ fail("Invalid netmask " + addr.getHostAddress() + " did not cause exception");
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ @SmallTest
+ public void testNetmaskToPrefixLength() {
+ assertEquals(0, NetworkUtils.netmaskToPrefixLength(IPv4Address("0.0.0.0")));
+ assertEquals(9, NetworkUtils.netmaskToPrefixLength(IPv4Address("255.128.0.0")));
+ assertEquals(17, NetworkUtils.netmaskToPrefixLength(IPv4Address("255.255.128.0")));
+ assertEquals(23, NetworkUtils.netmaskToPrefixLength(IPv4Address("255.255.254.0")));
+ assertEquals(31, NetworkUtils.netmaskToPrefixLength(IPv4Address("255.255.255.254")));
+ assertEquals(32, NetworkUtils.netmaskToPrefixLength(IPv4Address("255.255.255.255")));
+
+ assertInvalidNetworkMask(IPv4Address("0.0.0.1"));
+ assertInvalidNetworkMask(IPv4Address("255.255.255.253"));
+ assertInvalidNetworkMask(IPv4Address("255.255.0.255"));
+ }
+}
diff --git a/packages/CaptivePortalLogin/res/values-en-rGB/strings.xml b/packages/CaptivePortalLogin/res/values-en-rGB/strings.xml
index 687a14e..bfda753 100644
--- a/packages/CaptivePortalLogin/res/values-en-rGB/strings.xml
+++ b/packages/CaptivePortalLogin/res/values-en-rGB/strings.xml
@@ -4,5 +4,5 @@
<string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
<string name="action_use_network" msgid="6076184727448466030">"Use this network as is"</string>
<string name="action_do_not_use_network" msgid="4577366536956516683">"Do not use this network"</string>
- <string name="action_bar_label" msgid="2573986763322074279">"Sign-in to network"</string>
+ <string name="action_bar_label" msgid="2573986763322074279">"Sign in to network"</string>
</resources>
diff --git a/packages/CaptivePortalLogin/res/values-en-rIN/strings.xml b/packages/CaptivePortalLogin/res/values-en-rIN/strings.xml
index 687a14e..bfda753 100644
--- a/packages/CaptivePortalLogin/res/values-en-rIN/strings.xml
+++ b/packages/CaptivePortalLogin/res/values-en-rIN/strings.xml
@@ -4,5 +4,5 @@
<string name="app_name" msgid="5934709770924185752">"CaptivePortalLogin"</string>
<string name="action_use_network" msgid="6076184727448466030">"Use this network as is"</string>
<string name="action_do_not_use_network" msgid="4577366536956516683">"Do not use this network"</string>
- <string name="action_bar_label" msgid="2573986763322074279">"Sign-in to network"</string>
+ <string name="action_bar_label" msgid="2573986763322074279">"Sign in to network"</string>
</resources>
diff --git a/packages/CaptivePortalLogin/res/values/strings.xml b/packages/CaptivePortalLogin/res/values/strings.xml
index 1b0f0a4..8348be9 100644
--- a/packages/CaptivePortalLogin/res/values/strings.xml
+++ b/packages/CaptivePortalLogin/res/values/strings.xml
@@ -4,6 +4,6 @@
<string name="app_name">CaptivePortalLogin</string>
<string name="action_use_network">Use this network as is</string>
<string name="action_do_not_use_network">Do not use this network</string>
- <string name="action_bar_label">Sign-in to network</string>
+ <string name="action_bar_label">Sign in to network</string>
</resources>
diff --git a/services/Android.mk b/services/Android.mk
index 3c94f43..e4b0cbb 100644
--- a/services/Android.mk
+++ b/services/Android.mk
@@ -24,6 +24,7 @@
appwidget \
backup \
devicepolicy \
+ net \
print \
restrictions \
usage \
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 8c56c8c..0437a2a 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -1374,7 +1374,8 @@
mConnector.execute("softap", "set", wlanIface);
} else {
mConnector.execute("softap", "set", wlanIface, wifiConfig.SSID,
- "broadcast", "6", getSecurityType(wifiConfig),
+ "broadcast", Integer.toString(wifiConfig.apChannel),
+ getSecurityType(wifiConfig),
new SensitiveArg(wifiConfig.preSharedKey));
}
mConnector.execute("softap", "startap");
diff --git a/services/core/java/com/android/server/telecom/TelecomLoaderService.java b/services/core/java/com/android/server/telecom/TelecomLoaderService.java
index 64a67fc..22fee22 100644
--- a/services/core/java/com/android/server/telecom/TelecomLoaderService.java
+++ b/services/core/java/com/android/server/telecom/TelecomLoaderService.java
@@ -63,7 +63,7 @@
private static final ComponentName SERVICE_COMPONENT = new ComponentName(
"com.android.server.telecom",
- "com.android.server.telecom.TelecomService");
+ "com.android.server.telecom.components.TelecomService");
private static final String SERVICE_ACTION = "com.android.ITelecomService";
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 334cdf6..0705fbd 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -677,7 +677,8 @@
mSystemServiceManager.startService("com.android.server.wifi.RttService");
- if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_ETHERNET)) {
+ if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_ETHERNET) ||
+ mPackageManager.hasSystemFeature(PackageManager.FEATURE_USB_HOST)) {
mSystemServiceManager.startService(ETHERNET_SERVICE_CLASS);
}
diff --git a/services/net/Android.mk b/services/net/Android.mk
new file mode 100644
index 0000000..336bc45
--- /dev/null
+++ b/services/net/Android.mk
@@ -0,0 +1,10 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := services.net
+
+LOCAL_SRC_FILES += \
+ $(call all-java-files-under,java)
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/core/java/android/net/dhcp/DhcpAckPacket.java b/services/net/java/android/net/dhcp/DhcpAckPacket.java
similarity index 77%
rename from core/java/android/net/dhcp/DhcpAckPacket.java
rename to services/net/java/android/net/dhcp/DhcpAckPacket.java
index 7b8be9c..25b8093 100644
--- a/core/java/android/net/dhcp/DhcpAckPacket.java
+++ b/services/net/java/android/net/dhcp/DhcpAckPacket.java
@@ -16,7 +16,6 @@
package android.net.dhcp;
-import java.net.InetAddress;
import java.net.Inet4Address;
import java.nio.ByteBuffer;
@@ -28,12 +27,11 @@
/**
* The address of the server which sent this packet.
*/
- private final InetAddress mSrcIp;
+ private final Inet4Address mSrcIp;
- DhcpAckPacket(int transId, boolean broadcast, InetAddress serverAddress,
- InetAddress clientIp, byte[] clientMac) {
- super(transId, Inet4Address.ANY, clientIp, serverAddress,
- Inet4Address.ANY, clientMac, broadcast);
+ DhcpAckPacket(int transId, boolean broadcast, Inet4Address serverAddress,
+ Inet4Address clientIp, byte[] clientMac) {
+ super(transId, INADDR_ANY, clientIp, serverAddress, INADDR_ANY, clientMac, broadcast);
mBroadcast = broadcast;
mSrcIp = serverAddress;
}
@@ -42,7 +40,7 @@
String s = super.toString();
String dnsServers = " DNS servers: ";
- for (InetAddress dnsServer: mDnsServers) {
+ for (Inet4Address dnsServer: mDnsServers) {
dnsServers += dnsServer.toString() + " ";
}
@@ -57,8 +55,8 @@
*/
public ByteBuffer buildPacket(int encap, short destUdp, short srcUdp) {
ByteBuffer result = ByteBuffer.allocate(MAX_LENGTH);
- InetAddress destIp = mBroadcast ? Inet4Address.ALL : mYourIp;
- InetAddress srcIp = mBroadcast ? Inet4Address.ANY : mSrcIp;
+ Inet4Address destIp = mBroadcast ? INADDR_BROADCAST : mYourIp;
+ Inet4Address srcIp = mBroadcast ? INADDR_ANY : mSrcIp;
fillInPacket(encap, destIp, srcIp, destUdp, srcUdp, result,
DHCP_BOOTREPLY, mBroadcast);
@@ -98,12 +96,4 @@
return v.intValue();
}
}
-
- /**
- * Notifies the specified state machine of the ACK packet parameters.
- */
- public void doNextOp(DhcpStateMachine machine) {
- machine.onAckReceived(mYourIp, mSubnetMask, mGateway, mDnsServers,
- mServerIdentifier, getInt(mLeaseTime));
- }
}
diff --git a/services/net/java/android/net/dhcp/DhcpClient.java b/services/net/java/android/net/dhcp/DhcpClient.java
new file mode 100644
index 0000000..57cc251
--- /dev/null
+++ b/services/net/java/android/net/dhcp/DhcpClient.java
@@ -0,0 +1,807 @@
+/*
+ * Copyright (C) 2015 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.dhcp;
+
+import com.android.internal.util.HexDump;
+import com.android.internal.util.Protocol;
+import com.android.internal.util.State;
+import com.android.internal.util.StateMachine;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.DhcpResults;
+import android.net.BaseDhcpStateMachine;
+import android.net.DhcpStateMachine;
+import android.net.InterfaceConfiguration;
+import android.net.LinkAddress;
+import android.net.NetworkUtils;
+import android.os.IBinder;
+import android.os.INetworkManagementService;
+import android.os.Message;
+import android.os.PowerManager;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.os.SystemClock;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.PacketSocketAddress;
+import android.util.Log;
+import android.util.TimeUtils;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.lang.Thread;
+import java.net.Inet4Address;
+import java.net.InetSocketAddress;
+import java.net.NetworkInterface;
+import java.net.SocketException;
+import java.nio.BufferUnderflowException;
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.Random;
+
+import libcore.io.IoUtils;
+
+import static android.system.OsConstants.*;
+import static android.net.dhcp.DhcpPacket.*;
+
+/**
+ * A DHCPv4 client.
+ *
+ * Written to behave similarly to the DhcpStateMachine + dhcpcd 5.5.6 combination used in Android
+ * 5.1 and below, as configured on Nexus 6. The interface is the same as DhcpStateMachine.
+ *
+ * TODO:
+ *
+ * - Exponential backoff when receiving NAKs (not specified by the RFC, but current behaviour).
+ * - Support persisting lease state and support INIT-REBOOT. Android 5.1 does this, but it does not
+ * do so correctly: instead of requesting the lease last obtained on a particular network (e.g., a
+ * given SSID), it requests the last-leased IP address on the same interface, causing a delay if
+ * the server NAKs or a timeout if it doesn't.
+ *
+ * Known differences from current behaviour:
+ *
+ * - Does not request the "static routes" option.
+ * - Does not support BOOTP servers. DHCP has been around since 1993, should be everywhere now.
+ * - Requests the "broadcast" option, but does nothing with it.
+ * - Rejects invalid subnet masks such as 255.255.255.1 (current code treats that as 255.255.255.0).
+ *
+ * @hide
+ */
+public class DhcpClient extends BaseDhcpStateMachine {
+
+ private static final String TAG = "DhcpClient";
+ private static final boolean DBG = true;
+ private static final boolean STATE_DBG = false;
+ private static final boolean MSG_DBG = false;
+
+ // Timers and timeouts.
+ private static final int SECONDS = 1000;
+ private static final int FIRST_TIMEOUT_MS = 2 * SECONDS;
+ private static final int MAX_TIMEOUT_MS = 128 * SECONDS;
+
+ // This is not strictly needed, since the client is asynchronous and implements exponential
+ // backoff. It's maintained for backwards compatibility with the previous DHCP code, which was
+ // a blocking operation with a 30-second timeout. We pick 36 seconds so we can send packets at
+ // t=0, t=2, t=6, t=14, t=30, allowing for 10% jitter.
+ private static final int DHCP_TIMEOUT_MS = 36 * SECONDS;
+
+ // Messages.
+ private static final int BASE = Protocol.BASE_DHCP + 100;
+ private static final int CMD_KICK = BASE + 1;
+ private static final int CMD_RECEIVED_PACKET = BASE + 2;
+ private static final int CMD_TIMEOUT = BASE + 3;
+
+ // DHCP parameters that we request.
+ private static final byte[] REQUESTED_PARAMS = new byte[] {
+ DHCP_SUBNET_MASK,
+ DHCP_ROUTER,
+ DHCP_DNS_SERVER,
+ DHCP_DOMAIN_NAME,
+ DHCP_MTU,
+ DHCP_BROADCAST_ADDRESS, // TODO: currently ignored.
+ DHCP_LEASE_TIME,
+ DHCP_RENEWAL_TIME,
+ DHCP_REBINDING_TIME,
+ };
+
+ // DHCP flag that means "yes, we support unicast."
+ private static final boolean DO_UNICAST = false;
+
+ // System services / libraries we use.
+ private final Context mContext;
+ private final AlarmManager mAlarmManager;
+ private final Random mRandom;
+ private final INetworkManagementService mNMService;
+
+ // Sockets.
+ // - We use a packet socket to receive, because servers send us packets bound for IP addresses
+ // which we have not yet configured, and the kernel protocol stack drops these.
+ // - We use a UDP socket to send, so the kernel handles ARP and routing for us (DHCP servers can
+ // be off-link as well as on-link).
+ private FileDescriptor mPacketSock;
+ private FileDescriptor mUdpSock;
+ private ReceiveThread mReceiveThread;
+
+ // State variables.
+ private final StateMachine mController;
+ private final PendingIntent mKickIntent;
+ private final PendingIntent mTimeoutIntent;
+ private final PendingIntent mRenewIntent;
+ private final String mIfaceName;
+
+ private boolean mRegisteredForPreDhcpNotification;
+ private NetworkInterface mIface;
+ private byte[] mHwAddr;
+ private PacketSocketAddress mInterfaceBroadcastAddr;
+ private int mTransactionId;
+ private DhcpResults mDhcpLease;
+ private long mDhcpLeaseExpiry;
+ private DhcpResults mOffer;
+
+ // States.
+ private State mStoppedState = new StoppedState();
+ private State mDhcpState = new DhcpState();
+ private State mDhcpInitState = new DhcpInitState();
+ private State mDhcpSelectingState = new DhcpSelectingState();
+ private State mDhcpRequestingState = new DhcpRequestingState();
+ private State mDhcpBoundState = new DhcpBoundState();
+ private State mDhcpRenewingState = new DhcpRenewingState();
+ private State mDhcpRebindingState = new DhcpRebindingState();
+ private State mDhcpInitRebootState = new DhcpInitRebootState();
+ private State mDhcpRebootingState = new DhcpRebootingState();
+ private State mWaitBeforeStartState = new WaitBeforeStartState(mDhcpInitState);
+ private State mWaitBeforeRenewalState = new WaitBeforeRenewalState(mDhcpRenewingState);
+
+ private DhcpClient(Context context, StateMachine controller, String iface) {
+ super(TAG);
+
+ mContext = context;
+ mController = controller;
+ mIfaceName = iface;
+
+ addState(mStoppedState);
+ addState(mDhcpState);
+ addState(mDhcpInitState, mDhcpState);
+ addState(mWaitBeforeStartState, mDhcpState);
+ addState(mDhcpSelectingState, mDhcpState);
+ addState(mDhcpRequestingState, mDhcpState);
+ addState(mDhcpBoundState, mDhcpState);
+ addState(mWaitBeforeRenewalState, mDhcpState);
+ addState(mDhcpRenewingState, mDhcpState);
+ addState(mDhcpRebindingState, mDhcpState);
+ addState(mDhcpInitRebootState, mDhcpState);
+ addState(mDhcpRebootingState, mDhcpState);
+
+ setInitialState(mStoppedState);
+
+ mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
+ IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
+ mNMService = INetworkManagementService.Stub.asInterface(b);
+
+ mRandom = new Random();
+
+ mKickIntent = createStateMachineCommandIntent("KICK", CMD_KICK);
+ mTimeoutIntent = createStateMachineCommandIntent("TIMEOUT", CMD_TIMEOUT);
+ mRenewIntent = createStateMachineCommandIntent("RENEW", DhcpStateMachine.CMD_RENEW_DHCP);
+ }
+
+ @Override
+ public void registerForPreDhcpNotification() {
+ mRegisteredForPreDhcpNotification = true;
+ }
+
+ public static BaseDhcpStateMachine makeDhcpStateMachine(
+ Context context, StateMachine controller, String intf) {
+ DhcpClient client = new DhcpClient(context, controller, intf);
+ client.start();
+ return client;
+ }
+
+ /**
+ * Constructs a PendingIntent that sends the specified command to the state machine. This is
+ * implemented by creating an Intent with the specified parameters, and creating and registering
+ * a BroadcastReceiver for it. The broadcast must be sent by a process that holds the
+ * {@code CONNECTIVITY_INTERNAL} permission.
+ *
+ * @param cmdName the name of the command. The intent's action will be
+ * {@code android.net.dhcp.DhcpClient.<cmdName>}
+ * @param cmd the command to send to the state machine when the PendingIntent is triggered.
+ * @return the PendingIntent
+ */
+ private PendingIntent createStateMachineCommandIntent(final String cmdName, final int cmd) {
+ String action = DhcpClient.class.getName() + "." + cmdName;
+
+ // TODO: figure out what values to pass to intent.setPackage() and intent.setClass() that
+ // result in the Intent being received by this class and nowhere else, and use them.
+ Intent intent = new Intent(action, null)
+ .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+ PendingIntent pendingIntent = PendingIntent.getBroadcast(mContext, cmd, intent, 0);
+
+ mContext.registerReceiver(
+ new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ sendMessage(cmd);
+ }
+ },
+ new IntentFilter(action),
+ android.Manifest.permission.CONNECTIVITY_INTERNAL,
+ null);
+
+ return pendingIntent;
+ }
+
+ private boolean initInterface() {
+ try {
+ mIface = NetworkInterface.getByName(mIfaceName);
+ mHwAddr = mIface.getHardwareAddress();
+ mInterfaceBroadcastAddr = new PacketSocketAddress(mIface.getIndex(),
+ DhcpPacket.ETHER_BROADCAST);
+ return true;
+ } catch(SocketException e) {
+ Log.wtf(TAG, "Can't determine ifindex or MAC address for " + mIfaceName);
+ return false;
+ }
+ }
+
+ private void initTransactionId() {
+ mTransactionId = mRandom.nextInt();
+ }
+
+ private boolean initSockets() {
+ try {
+ mPacketSock = Os.socket(AF_PACKET, SOCK_RAW, ETH_P_IP);
+ PacketSocketAddress addr = new PacketSocketAddress((short) ETH_P_IP, mIface.getIndex());
+ Os.bind(mPacketSock, addr);
+ NetworkUtils.attachDhcpFilter(mPacketSock);
+ } catch(SocketException|ErrnoException e) {
+ Log.e(TAG, "Error creating packet socket", e);
+ return false;
+ }
+ try {
+ mUdpSock = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+ Os.setsockoptInt(mUdpSock, SOL_SOCKET, SO_REUSEADDR, 1);
+ Os.setsockoptIfreq(mUdpSock, SOL_SOCKET, SO_BINDTODEVICE, mIfaceName);
+ Os.setsockoptInt(mUdpSock, SOL_SOCKET, SO_BROADCAST, 1);
+ Os.bind(mUdpSock, Inet4Address.ANY, DhcpPacket.DHCP_CLIENT);
+ NetworkUtils.protectFromVpn(mUdpSock);
+ } catch(SocketException|ErrnoException e) {
+ Log.e(TAG, "Error creating UDP socket", e);
+ return false;
+ }
+ return true;
+ }
+
+ private void closeSockets() {
+ IoUtils.closeQuietly(mUdpSock);
+ IoUtils.closeQuietly(mPacketSock);
+ }
+
+ private boolean setIpAddress(LinkAddress address) {
+ InterfaceConfiguration ifcg = new InterfaceConfiguration();
+ ifcg.setLinkAddress(address);
+ try {
+ mNMService.setInterfaceConfig(mIfaceName, ifcg);
+ } catch (RemoteException|IllegalStateException e) {
+ Log.e(TAG, "Error configuring IP address : " + e);
+ return false;
+ }
+ return true;
+ }
+
+ class ReceiveThread extends Thread {
+
+ private final byte[] mPacket = new byte[DhcpPacket.MAX_LENGTH];
+ private boolean stopped = false;
+
+ public void halt() {
+ stopped = true;
+ closeSockets(); // Interrupts the read() call the thread is blocked in.
+ }
+
+ @Override
+ public void run() {
+ maybeLog("Starting receive thread");
+ while (!stopped) {
+ try {
+ int length = Os.read(mPacketSock, mPacket, 0, mPacket.length);
+ DhcpPacket packet = null;
+ packet = DhcpPacket.decodeFullPacket(mPacket, length, DhcpPacket.ENCAP_L2);
+ if (packet != null) {
+ maybeLog("Received packet: " + packet);
+ sendMessage(CMD_RECEIVED_PACKET, packet);
+ }
+ } catch(IOException|ErrnoException e) {
+ Log.e(TAG, "Read error", e);
+ }
+ }
+ maybeLog("Stopping receive thread");
+ }
+ }
+
+ private boolean transmitPacket(ByteBuffer buf, String description, Inet4Address to) {
+ try {
+ if (to.equals(INADDR_BROADCAST)) {
+ maybeLog("Broadcasting " + description);
+ Os.sendto(mPacketSock, buf.array(), 0, buf.limit(), 0, mInterfaceBroadcastAddr);
+ } else {
+ maybeLog("Unicasting " + description + " to " + to.getHostAddress());
+ Os.sendto(mUdpSock, buf, 0, to, DhcpPacket.DHCP_SERVER);
+ }
+ } catch(ErrnoException|IOException e) {
+ Log.e(TAG, "Can't send packet: ", e);
+ return false;
+ }
+ return true;
+ }
+
+ private boolean sendDiscoverPacket() {
+ ByteBuffer packet = DhcpPacket.buildDiscoverPacket(
+ DhcpPacket.ENCAP_L2, mTransactionId, mHwAddr, DO_UNICAST, REQUESTED_PARAMS);
+ return transmitPacket(packet, "DHCPDISCOVER", INADDR_BROADCAST);
+ }
+
+ private boolean sendRequestPacket(
+ Inet4Address clientAddress, Inet4Address requestedAddress,
+ Inet4Address serverAddress, Inet4Address to) {
+ // TODO: should we use the transaction ID from the server?
+ int encap = to.equals(INADDR_BROADCAST) ? DhcpPacket.ENCAP_L2 : DhcpPacket.ENCAP_BOOTP;
+
+ ByteBuffer packet = DhcpPacket.buildRequestPacket(
+ encap, mTransactionId, clientAddress,
+ DO_UNICAST, mHwAddr, requestedAddress,
+ serverAddress, REQUESTED_PARAMS, null);
+ String description = "DHCPREQUEST ciaddr=" + clientAddress.getHostAddress() +
+ " request=" + requestedAddress.getHostAddress() +
+ " to=" + serverAddress.getHostAddress();
+ return transmitPacket(packet, description, to);
+ }
+
+ private void scheduleRenew() {
+ long now = SystemClock.elapsedRealtime();
+ long alarmTime = (now + mDhcpLeaseExpiry) / 2;
+ mAlarmManager.cancel(mRenewIntent);
+ mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, alarmTime, mRenewIntent);
+ Log.d(TAG, "Scheduling renewal in " + ((alarmTime - now) / 1000) + "s");
+ }
+
+ private void notifyLease() {
+ mController.sendMessage(DhcpStateMachine.CMD_POST_DHCP_ACTION,
+ DhcpStateMachine.DHCP_SUCCESS, 0, mDhcpLease);
+ }
+
+ private void notifyFailure() {
+ mController.sendMessage(DhcpStateMachine.CMD_POST_DHCP_ACTION,
+ DhcpStateMachine.DHCP_FAILURE, 0, null);
+ }
+
+ private void clearDhcpState() {
+ mDhcpLease = null;
+ mDhcpLeaseExpiry = 0;
+ mOffer = null;
+ }
+
+ /**
+ * Quit the DhcpStateMachine.
+ *
+ * @hide
+ */
+ @Override
+ public void doQuit() {
+ Log.d(TAG, "doQuit");
+ quit();
+ }
+
+ protected void onQuitting() {
+ Log.d(TAG, "onQuitting");
+ mController.sendMessage(DhcpStateMachine.CMD_ON_QUIT);
+ }
+
+ private void maybeLog(String msg) {
+ if (DBG) Log.d(TAG, msg);
+ }
+
+ abstract class LoggingState extends State {
+ public void enter() {
+ if (STATE_DBG) Log.d(TAG, "Entering state " + getName());
+ }
+
+ private String messageName(int what) {
+ switch (what) {
+ case DhcpStateMachine.CMD_START_DHCP:
+ return "CMD_START_DHCP";
+ case DhcpStateMachine.CMD_STOP_DHCP:
+ return "CMD_STOP_DHCP";
+ case DhcpStateMachine.CMD_RENEW_DHCP:
+ return "CMD_RENEW_DHCP";
+ case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
+ return "CMD_PRE_DHCP_ACTION";
+ case DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE:
+ return "CMD_PRE_DHCP_ACTION_COMPLETE";
+ case DhcpStateMachine.CMD_POST_DHCP_ACTION:
+ return "CMD_POST_DHCP_ACTION";
+ case CMD_KICK:
+ return "CMD_KICK";
+ case CMD_RECEIVED_PACKET:
+ return "CMD_RECEIVED_PACKET";
+ default:
+ return Integer.toString(what);
+ }
+ }
+
+ private String messageToString(Message message) {
+ long now = SystemClock.uptimeMillis();
+ StringBuilder b = new StringBuilder(" ");
+ TimeUtils.formatDuration(message.getWhen() - now, b);
+ b.append(" ").append(messageName(message.what))
+ .append(" ").append(message.arg1)
+ .append(" ").append(message.arg2)
+ .append(" ").append(message.obj);
+ return b.toString();
+ }
+
+ @Override
+ public boolean processMessage(Message message) {
+ if (MSG_DBG) {
+ Log.d(TAG, getName() + messageToString(message));
+ }
+ return NOT_HANDLED;
+ }
+ }
+
+ // Sends CMD_PRE_DHCP_ACTION to the controller, waits for the controller to respond with
+ // CMD_PRE_DHCP_ACTION_COMPLETE, and then transitions to mOtherState.
+ abstract class WaitBeforeOtherState extends LoggingState {
+ protected State mOtherState;
+
+ @Override
+ public void enter() {
+ super.enter();
+ mController.sendMessage(DhcpStateMachine.CMD_PRE_DHCP_ACTION);
+ }
+
+ @Override
+ public boolean processMessage(Message message) {
+ super.processMessage(message);
+ switch (message.what) {
+ case DhcpStateMachine.CMD_PRE_DHCP_ACTION_COMPLETE:
+ transitionTo(mOtherState);
+ return HANDLED;
+ default:
+ return NOT_HANDLED;
+ }
+ }
+ }
+
+ class StoppedState extends LoggingState {
+ @Override
+ public boolean processMessage(Message message) {
+ super.processMessage(message);
+ switch (message.what) {
+ case DhcpStateMachine.CMD_START_DHCP:
+ if (mRegisteredForPreDhcpNotification) {
+ transitionTo(mWaitBeforeStartState);
+ } else {
+ transitionTo(mDhcpInitState);
+ }
+ return HANDLED;
+ default:
+ return NOT_HANDLED;
+ }
+ }
+ }
+
+ class WaitBeforeStartState extends WaitBeforeOtherState {
+ public WaitBeforeStartState(State otherState) {
+ super();
+ mOtherState = otherState;
+ }
+ }
+
+ class WaitBeforeRenewalState extends WaitBeforeOtherState {
+ public WaitBeforeRenewalState(State otherState) {
+ super();
+ mOtherState = otherState;
+ }
+ }
+
+ class DhcpState extends LoggingState {
+ @Override
+ public void enter() {
+ super.enter();
+ clearDhcpState();
+ if (initInterface() && initSockets()) {
+ mReceiveThread = new ReceiveThread();
+ mReceiveThread.start();
+ } else {
+ notifyFailure();
+ transitionTo(mStoppedState);
+ }
+ }
+
+ @Override
+ public void exit() {
+ mReceiveThread.halt(); // Also closes sockets.
+ clearDhcpState();
+ }
+
+ @Override
+ public boolean processMessage(Message message) {
+ super.processMessage(message);
+ switch (message.what) {
+ case DhcpStateMachine.CMD_STOP_DHCP:
+ transitionTo(mStoppedState);
+ return HANDLED;
+ default:
+ return NOT_HANDLED;
+ }
+ }
+ }
+
+ public boolean isValidPacket(DhcpPacket packet) {
+ // TODO: check checksum.
+ int xid = packet.getTransactionId();
+ if (xid != mTransactionId) {
+ Log.d(TAG, "Unexpected transaction ID " + xid + ", expected " + mTransactionId);
+ return false;
+ }
+ if (!Arrays.equals(packet.getClientMac(), mHwAddr)) {
+ Log.d(TAG, "MAC addr mismatch: got " +
+ HexDump.toHexString(packet.getClientMac()) + ", expected " +
+ HexDump.toHexString(packet.getClientMac()));
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Retransmits packets using jittered exponential backoff with an optional timeout. Packet
+ * transmission is triggered by CMD_KICK, which is sent by an AlarmManager alarm.
+ *
+ * Concrete subclasses must implement sendPacket, which is called when the alarm fires and a
+ * packet needs to be transmitted, and receivePacket, which is triggered by CMD_RECEIVED_PACKET
+ * sent by the receive thread. They may implement timeout, which is called when the timeout
+ * fires.
+ */
+ abstract class PacketRetransmittingState extends LoggingState {
+
+ private int mTimer;
+ protected int mTimeout = 0;
+
+ @Override
+ public void enter() {
+ super.enter();
+ initTimer();
+ maybeInitTimeout();
+ sendMessage(CMD_KICK);
+ }
+
+ @Override
+ public boolean processMessage(Message message) {
+ super.processMessage(message);
+ switch (message.what) {
+ case CMD_KICK:
+ sendPacket();
+ scheduleKick();
+ return HANDLED;
+ case CMD_RECEIVED_PACKET:
+ receivePacket((DhcpPacket) message.obj);
+ return HANDLED;
+ case CMD_TIMEOUT:
+ timeout();
+ return HANDLED;
+ default:
+ return NOT_HANDLED;
+ }
+ }
+
+ public void exit() {
+ mAlarmManager.cancel(mKickIntent);
+ mAlarmManager.cancel(mTimeoutIntent);
+ }
+
+ abstract protected boolean sendPacket();
+ abstract protected void receivePacket(DhcpPacket packet);
+ protected void timeout() {}
+
+ protected void initTimer() {
+ mTimer = FIRST_TIMEOUT_MS;
+ }
+
+ protected int jitterTimer(int baseTimer) {
+ int maxJitter = baseTimer / 10;
+ int jitter = mRandom.nextInt(2 * maxJitter) - maxJitter;
+ return baseTimer + jitter;
+ }
+
+ protected void scheduleKick() {
+ long now = SystemClock.elapsedRealtime();
+ long timeout = jitterTimer(mTimer);
+ long alarmTime = now + timeout;
+ mAlarmManager.cancel(mKickIntent);
+ mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP, alarmTime, mKickIntent);
+ mTimer *= 2;
+ if (mTimer > MAX_TIMEOUT_MS) {
+ mTimer = MAX_TIMEOUT_MS;
+ }
+ }
+
+ protected void maybeInitTimeout() {
+ if (mTimeout > 0) {
+ long alarmTime = SystemClock.elapsedRealtime() + mTimeout;
+ mAlarmManager.setExact(
+ AlarmManager.ELAPSED_REALTIME_WAKEUP, alarmTime, mTimeoutIntent);
+ }
+ }
+ }
+
+ class DhcpInitState extends PacketRetransmittingState {
+ public DhcpInitState() {
+ super();
+ mTimeout = DHCP_TIMEOUT_MS;
+ }
+
+ @Override
+ public void enter() {
+ super.enter();
+ initTransactionId();
+ }
+
+ protected boolean sendPacket() {
+ return sendDiscoverPacket();
+ }
+
+ protected void timeout() {
+ maybeLog("Timeout");
+ notifyFailure();
+ }
+
+ protected void receivePacket(DhcpPacket packet) {
+ if (!isValidPacket(packet)) return;
+ if (!(packet instanceof DhcpOfferPacket)) return;
+ mOffer = packet.toDhcpResults();
+ if (mOffer != null) {
+ Log.d(TAG, "Got pending lease: " + mOffer);
+ transitionTo(mDhcpRequestingState);
+ }
+ }
+ }
+
+ // Not implemented. We request the first offer we receive.
+ class DhcpSelectingState extends LoggingState {
+ }
+
+ class DhcpRequestingState extends PacketRetransmittingState {
+ public DhcpRequestingState() {
+ super();
+ mTimeout = DHCP_TIMEOUT_MS / 2;
+ }
+
+ protected boolean sendPacket() {
+ return sendRequestPacket(
+ INADDR_ANY, // ciaddr
+ (Inet4Address) mOffer.ipAddress.getAddress(), // DHCP_REQUESTED_IP
+ (Inet4Address) mOffer.serverAddress, // DHCP_SERVER_IDENTIFIER
+ INADDR_BROADCAST); // packet destination address
+ }
+
+ protected void receivePacket(DhcpPacket packet) {
+ if (!isValidPacket(packet)) return;
+ if ((packet instanceof DhcpAckPacket)) {
+ DhcpResults results = packet.toDhcpResults();
+ if (results != null) {
+ mDhcpLease = results;
+ Log.d(TAG, "Confirmed lease: " + mDhcpLease);
+ mDhcpLeaseExpiry = SystemClock.elapsedRealtime() +
+ mDhcpLease.leaseDuration * 1000;
+ mOffer = null;
+ transitionTo(mDhcpBoundState);
+ }
+ } else if (packet instanceof DhcpNakPacket) {
+ Log.d(TAG, "Received NAK, returning to INIT");
+ mOffer = null;
+ transitionTo(mDhcpInitState);
+ }
+ }
+
+ protected void timeout() {
+ notifyFailure();
+ transitionTo(mDhcpInitState);
+ }
+ }
+
+ class DhcpBoundState extends LoggingState {
+ @Override
+ public void enter() {
+ super.enter();
+ if (!setIpAddress(mDhcpLease.ipAddress)) {
+ notifyFailure();
+ transitionTo(mStoppedState);
+ }
+ notifyLease();
+ // TODO: DhcpStateMachine only supports renewing at 50% of the lease time, and does not
+ // support rebinding. Fix this.
+ scheduleRenew();
+ }
+
+ @Override
+ public boolean processMessage(Message message) {
+ super.processMessage(message);
+ switch (message.what) {
+ case DhcpStateMachine.CMD_RENEW_DHCP:
+ if (mRegisteredForPreDhcpNotification) {
+ transitionTo(mWaitBeforeRenewalState);
+ } else {
+ transitionTo(mDhcpRenewingState);
+ }
+ return HANDLED;
+ default:
+ return NOT_HANDLED;
+ }
+ }
+ }
+
+ // TODO: timeout.
+ class DhcpRenewingState extends PacketRetransmittingState {
+ public DhcpRenewingState() {
+ super();
+ mTimeout = DHCP_TIMEOUT_MS;
+ }
+
+ @Override
+ public void enter() {
+ super.enter();
+ initTransactionId();
+ }
+
+ protected boolean sendPacket() {
+ return sendRequestPacket(
+ (Inet4Address) mDhcpLease.ipAddress.getAddress(), // ciaddr
+ INADDR_ANY, // DHCP_REQUESTED_IP
+ INADDR_ANY, // DHCP_SERVER_IDENTIFIER
+ (Inet4Address) mDhcpLease.serverAddress); // packet destination address
+ }
+
+ protected void receivePacket(DhcpPacket packet) {
+ if (!isValidPacket(packet)) return;
+ if ((packet instanceof DhcpAckPacket)) {
+ DhcpResults results = packet.toDhcpResults();
+ mDhcpLease.leaseDuration = results.leaseDuration;
+ mDhcpLeaseExpiry = SystemClock.elapsedRealtime() +
+ mDhcpLease.leaseDuration * 1000;
+ transitionTo(mDhcpBoundState);
+ } else if (packet instanceof DhcpNakPacket) {
+ transitionTo(mDhcpInitState);
+ }
+ }
+ }
+
+ // Not implemented. DhcpStateMachine does not implement it either.
+ class DhcpRebindingState extends LoggingState {
+ }
+
+ class DhcpInitRebootState extends LoggingState {
+ }
+
+ class DhcpRebootingState extends LoggingState {
+ }
+}
diff --git a/core/java/android/net/dhcp/DhcpDeclinePacket.java b/services/net/java/android/net/dhcp/DhcpDeclinePacket.java
similarity index 81%
rename from core/java/android/net/dhcp/DhcpDeclinePacket.java
rename to services/net/java/android/net/dhcp/DhcpDeclinePacket.java
index 7646eb4..9d985ac 100644
--- a/core/java/android/net/dhcp/DhcpDeclinePacket.java
+++ b/services/net/java/android/net/dhcp/DhcpDeclinePacket.java
@@ -16,7 +16,7 @@
package android.net.dhcp;
-import java.net.InetAddress;
+import java.net.Inet4Address;
import java.nio.ByteBuffer;
/**
@@ -26,8 +26,8 @@
/**
* Generates a DECLINE packet with the specified parameters.
*/
- DhcpDeclinePacket(int transId, InetAddress clientIp, InetAddress yourIp,
- InetAddress nextIp, InetAddress relayIp,
+ DhcpDeclinePacket(int transId, Inet4Address clientIp, Inet4Address yourIp,
+ Inet4Address nextIp, Inet4Address relayIp,
byte[] clientMac) {
super(transId, clientIp, yourIp, nextIp, relayIp, clientMac, false);
}
@@ -55,11 +55,4 @@
void finishPacket(ByteBuffer buffer) {
// None needed
}
-
- /**
- * Informs the state machine of the arrival of a DECLINE packet.
- */
- public void doNextOp(DhcpStateMachine machine) {
- machine.onDeclineReceived(mClientMac, mRequestedIp);
- }
}
diff --git a/core/java/android/net/dhcp/DhcpDiscoverPacket.java b/services/net/java/android/net/dhcp/DhcpDiscoverPacket.java
similarity index 73%
rename from core/java/android/net/dhcp/DhcpDiscoverPacket.java
rename to services/net/java/android/net/dhcp/DhcpDiscoverPacket.java
index 0e2d39b..a031080 100644
--- a/core/java/android/net/dhcp/DhcpDiscoverPacket.java
+++ b/services/net/java/android/net/dhcp/DhcpDiscoverPacket.java
@@ -16,7 +16,6 @@
package android.net.dhcp;
-import java.net.InetAddress;
import java.net.Inet4Address;
import java.nio.ByteBuffer;
@@ -28,8 +27,7 @@
* Generates a DISCOVER packet with the specified parameters.
*/
DhcpDiscoverPacket(int transId, byte[] clientMac, boolean broadcast) {
- super(transId, Inet4Address.ANY, Inet4Address.ANY, Inet4Address.ANY,
- Inet4Address.ANY, clientMac, broadcast);
+ super(transId, INADDR_ANY, INADDR_ANY, INADDR_ANY, INADDR_ANY, clientMac, broadcast);
}
public String toString() {
@@ -43,10 +41,8 @@
*/
public ByteBuffer buildPacket(int encap, short destUdp, short srcUdp) {
ByteBuffer result = ByteBuffer.allocate(MAX_LENGTH);
- InetAddress destIp = Inet4Address.ALL;
-
- fillInPacket(encap, Inet4Address.ALL, Inet4Address.ANY, destUdp, srcUdp,
- result, DHCP_BOOTREQUEST, true);
+ fillInPacket(encap, INADDR_BROADCAST, INADDR_ANY, destUdp,
+ srcUdp, result, DHCP_BOOTREQUEST, mBroadcast);
result.flip();
return result;
}
@@ -56,16 +52,8 @@
*/
void finishPacket(ByteBuffer buffer) {
addTlv(buffer, DHCP_MESSAGE_TYPE, DHCP_MESSAGE_TYPE_DISCOVER);
+ addCommonClientTlvs(buffer);
addTlv(buffer, DHCP_PARAMETER_LIST, mRequestedParams);
addTlvEnd(buffer);
}
-
- /**
- * Informs the state machine of the arrival of a DISCOVER packet.
- */
- public void doNextOp(DhcpStateMachine machine) {
- // currently omitted: host name
- machine.onDiscoverReceived(mBroadcast, mTransId, mClientMac,
- mRequestedParams);
- }
}
diff --git a/core/java/android/net/dhcp/DhcpInformPacket.java b/services/net/java/android/net/dhcp/DhcpInformPacket.java
similarity index 77%
rename from core/java/android/net/dhcp/DhcpInformPacket.java
rename to services/net/java/android/net/dhcp/DhcpInformPacket.java
index da73216..8bc7cdd 100644
--- a/core/java/android/net/dhcp/DhcpInformPacket.java
+++ b/services/net/java/android/net/dhcp/DhcpInformPacket.java
@@ -16,7 +16,7 @@
package android.net.dhcp;
-import java.net.InetAddress;
+import java.net.Inet4Address;
import java.nio.ByteBuffer;
/**
@@ -26,8 +26,8 @@
/**
* Generates an INFORM packet with the specified parameters.
*/
- DhcpInformPacket(int transId, InetAddress clientIp, InetAddress yourIp,
- InetAddress nextIp, InetAddress relayIp,
+ DhcpInformPacket(int transId, Inet4Address clientIp, Inet4Address yourIp,
+ Inet4Address nextIp, Inet4Address relayIp,
byte[] clientMac) {
super(transId, clientIp, yourIp, nextIp, relayIp, clientMac, false);
}
@@ -62,15 +62,4 @@
addTlv(buffer, DHCP_PARAMETER_LIST, mRequestedParams);
addTlvEnd(buffer);
}
-
- /**
- * Informs the state machine of the arrival of an INFORM packet. Not
- * used currently.
- */
- public void doNextOp(DhcpStateMachine machine) {
- InetAddress clientRequest =
- mRequestedIp == null ? mClientIp : mRequestedIp;
- machine.onInformReceived(mTransId, mClientMac, clientRequest,
- mRequestedParams);
- }
}
diff --git a/core/java/android/net/dhcp/DhcpNakPacket.java b/services/net/java/android/net/dhcp/DhcpNakPacket.java
similarity index 78%
rename from core/java/android/net/dhcp/DhcpNakPacket.java
rename to services/net/java/android/net/dhcp/DhcpNakPacket.java
index 1f340ad..1390ea7 100644
--- a/core/java/android/net/dhcp/DhcpNakPacket.java
+++ b/services/net/java/android/net/dhcp/DhcpNakPacket.java
@@ -16,7 +16,6 @@
package android.net.dhcp;
-import java.net.InetAddress;
import java.net.Inet4Address;
import java.nio.ByteBuffer;
@@ -27,10 +26,10 @@
/**
* Generates a NAK packet with the specified parameters.
*/
- DhcpNakPacket(int transId, InetAddress clientIp, InetAddress yourIp,
- InetAddress nextIp, InetAddress relayIp,
+ DhcpNakPacket(int transId, Inet4Address clientIp, Inet4Address yourIp,
+ Inet4Address nextIp, Inet4Address relayIp,
byte[] clientMac) {
- super(transId, Inet4Address.ANY, Inet4Address.ANY, nextIp, relayIp,
+ super(transId, INADDR_ANY, INADDR_ANY, nextIp, relayIp,
clientMac, false);
}
@@ -44,8 +43,8 @@
*/
public ByteBuffer buildPacket(int encap, short destUdp, short srcUdp) {
ByteBuffer result = ByteBuffer.allocate(MAX_LENGTH);
- InetAddress destIp = mClientIp;
- InetAddress srcIp = mYourIp;
+ Inet4Address destIp = mClientIp;
+ Inet4Address srcIp = mYourIp;
fillInPacket(encap, destIp, srcIp, destUdp, srcUdp, result,
DHCP_BOOTREPLY, mBroadcast);
@@ -62,11 +61,4 @@
addTlv(buffer, DHCP_MESSAGE, mMessage);
addTlvEnd(buffer);
}
-
- /**
- * Notifies the specified state machine of the newly-arrived NAK packet.
- */
- public void doNextOp(DhcpStateMachine machine) {
- machine.onNakReceived();
- }
}
diff --git a/core/java/android/net/dhcp/DhcpOfferPacket.java b/services/net/java/android/net/dhcp/DhcpOfferPacket.java
similarity index 77%
rename from core/java/android/net/dhcp/DhcpOfferPacket.java
rename to services/net/java/android/net/dhcp/DhcpOfferPacket.java
index f1c30e1..b1f3bbd 100644
--- a/core/java/android/net/dhcp/DhcpOfferPacket.java
+++ b/services/net/java/android/net/dhcp/DhcpOfferPacket.java
@@ -16,7 +16,6 @@
package android.net.dhcp;
-import java.net.InetAddress;
import java.net.Inet4Address;
import java.nio.ByteBuffer;
@@ -27,15 +26,14 @@
/**
* The IP address of the server which sent this packet.
*/
- private final InetAddress mSrcIp;
+ private final Inet4Address mSrcIp;
/**
* Generates a OFFER packet with the specified parameters.
*/
- DhcpOfferPacket(int transId, boolean broadcast, InetAddress serverAddress,
- InetAddress clientIp, byte[] clientMac) {
- super(transId, Inet4Address.ANY, clientIp, Inet4Address.ANY,
- Inet4Address.ANY, clientMac, broadcast);
+ DhcpOfferPacket(int transId, boolean broadcast, Inet4Address serverAddress,
+ Inet4Address clientIp, byte[] clientMac) {
+ super(transId, INADDR_ANY, clientIp, INADDR_ANY, INADDR_ANY, clientMac, broadcast);
mSrcIp = serverAddress;
}
@@ -44,7 +42,7 @@
String dnsServers = ", DNS servers: ";
if (mDnsServers != null) {
- for (InetAddress dnsServer: mDnsServers) {
+ for (Inet4Address dnsServer: mDnsServers) {
dnsServers += dnsServer + " ";
}
}
@@ -59,8 +57,8 @@
*/
public ByteBuffer buildPacket(int encap, short destUdp, short srcUdp) {
ByteBuffer result = ByteBuffer.allocate(MAX_LENGTH);
- InetAddress destIp = mBroadcast ? Inet4Address.ALL : mYourIp;
- InetAddress srcIp = mBroadcast ? Inet4Address.ANY : mSrcIp;
+ Inet4Address destIp = mBroadcast ? INADDR_BROADCAST : mYourIp;
+ Inet4Address srcIp = mBroadcast ? INADDR_ANY : mSrcIp;
fillInPacket(encap, destIp, srcIp, destUdp, srcUdp, result,
DHCP_BOOTREPLY, mBroadcast);
@@ -89,12 +87,4 @@
addTlv(buffer, DHCP_DNS_SERVER, mDnsServers);
addTlvEnd(buffer);
}
-
- /**
- * Notifies the state machine of the OFFER packet parameters.
- */
- public void doNextOp(DhcpStateMachine machine) {
- machine.onOfferReceived(mBroadcast, mTransId, mClientMac, mYourIp,
- mServerIdentifier);
- }
}
diff --git a/core/java/android/net/dhcp/DhcpPacket.java b/services/net/java/android/net/dhcp/DhcpPacket.java
similarity index 60%
rename from core/java/android/net/dhcp/DhcpPacket.java
rename to services/net/java/android/net/dhcp/DhcpPacket.java
index c7c25f0..a232a6e 100644
--- a/core/java/android/net/dhcp/DhcpPacket.java
+++ b/services/net/java/android/net/dhcp/DhcpPacket.java
@@ -1,13 +1,23 @@
package android.net.dhcp;
-import java.net.InetAddress;
+import android.net.DhcpResults;
+import android.net.LinkAddress;
+import android.net.NetworkUtils;
+import android.os.Build;
+import android.os.SystemProperties;
+import android.system.OsConstants;
+
+import java.io.UnsupportedEncodingException;
+import java.net.Inet4Address;
import java.net.UnknownHostException;
+import java.nio.BufferUnderflowException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.StandardCharsets;
import java.nio.ShortBuffer;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
/**
@@ -18,6 +28,13 @@
abstract class DhcpPacket {
protected static final String TAG = "DhcpPacket";
+ public static final Inet4Address INADDR_ANY = (Inet4Address) Inet4Address.ANY;
+ public static final Inet4Address INADDR_BROADCAST = (Inet4Address) Inet4Address.ALL;
+ public static final byte[] ETHER_BROADCAST = new byte[] {
+ (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ (byte) 0xff, (byte) 0xff, (byte) 0xff,
+ };
+
/**
* Packet encapsulations.
*/
@@ -26,6 +43,14 @@
public static final int ENCAP_BOOTP = 2; // BOOTP contents only
/**
+ * Minimum length of a DHCP packet, excluding options, in the above encapsulations.
+ */
+ public static final int MIN_PACKET_LENGTH_BOOTP = 236; // See diagram in RFC 2131, section 2.
+ public static final int MIN_PACKET_LENGTH_L3 = MIN_PACKET_LENGTH_BOOTP + 20 + 8;
+ public static final int MIN_PACKET_LENGTH_L2 = MIN_PACKET_LENGTH_L3 + 14;
+
+ public static final int MAX_OPTION_LEN = 255;
+ /**
* IP layer definitions.
*/
private static final byte IP_TYPE_UDP = (byte) 0x11;
@@ -85,19 +110,19 @@
* DHCP Optional Type: DHCP Subnet Mask
*/
protected static final byte DHCP_SUBNET_MASK = 1;
- protected InetAddress mSubnetMask;
+ protected Inet4Address mSubnetMask;
/**
* DHCP Optional Type: DHCP Router
*/
protected static final byte DHCP_ROUTER = 3;
- protected InetAddress mGateway;
+ protected Inet4Address mGateway;
/**
* DHCP Optional Type: DHCP DNS Server
*/
protected static final byte DHCP_DNS_SERVER = 6;
- protected List<InetAddress> mDnsServers;
+ protected List<Inet4Address> mDnsServers;
/**
* DHCP Optional Type: DHCP Host Name
@@ -112,16 +137,22 @@
protected String mDomainName;
/**
+ * DHCP Optional Type: DHCP Interface MTU
+ */
+ protected static final byte DHCP_MTU = 26;
+ protected Short mMtu;
+
+ /**
* DHCP Optional Type: DHCP BROADCAST ADDRESS
*/
protected static final byte DHCP_BROADCAST_ADDRESS = 28;
- protected InetAddress mBroadcastAddress;
+ protected Inet4Address mBroadcastAddress;
/**
* DHCP Optional Type: DHCP Requested IP Address
*/
protected static final byte DHCP_REQUESTED_IP = 50;
- protected InetAddress mRequestedIp;
+ protected Inet4Address mRequestedIp;
/**
* DHCP Optional Type: DHCP Lease Time
@@ -146,7 +177,7 @@
* DHCP Optional Type: DHCP Server Identifier
*/
protected static final byte DHCP_SERVER_IDENTIFIER = 54;
- protected InetAddress mServerIdentifier;
+ protected Inet4Address mServerIdentifier;
/**
* DHCP Optional Type: DHCP Parameter List
@@ -161,14 +192,28 @@
protected String mMessage;
/**
+ * DHCP Optional Type: Maximum DHCP Message Size
+ */
+ protected static final byte DHCP_MAX_MESSAGE_SIZE = 57;
+ protected Short mMaxMessageSize;
+
+ /**
* DHCP Optional Type: DHCP Renewal Time Value
*/
protected static final byte DHCP_RENEWAL_TIME = 58;
+ protected Integer mT1;
+
+ /**
+ * DHCP Optional Type: Rebinding Time Value
+ */
+ protected static final byte DHCP_REBINDING_TIME = 59;
+ protected Integer mT2;
/**
* DHCP Optional Type: Vendor Class Identifier
*/
protected static final byte DHCP_VENDOR_CLASS_ID = 60;
+ protected String mVendorId;
/**
* DHCP Optional Type: DHCP Client Identifier
@@ -185,10 +230,10 @@
* proposed by the client (from an earlier DHCP negotiation) or
* supplied by the server.
*/
- protected final InetAddress mClientIp;
- protected final InetAddress mYourIp;
- private final InetAddress mNextIp;
- private final InetAddress mRelayIp;
+ protected final Inet4Address mClientIp;
+ protected final Inet4Address mYourIp;
+ private final Inet4Address mNextIp;
+ private final Inet4Address mRelayIp;
/**
* Does the client request a broadcast response?
@@ -201,13 +246,6 @@
protected final byte[] mClientMac;
/**
- * Asks the packet object to signal the next operation in the DHCP
- * protocol. The available actions are methods defined in the
- * DhcpStateMachine interface.
- */
- public abstract void doNextOp(DhcpStateMachine stateMachine);
-
- /**
* Asks the packet object to create a ByteBuffer serialization of
* the packet for transmission.
*/
@@ -220,8 +258,8 @@
*/
abstract void finishPacket(ByteBuffer buffer);
- protected DhcpPacket(int transId, InetAddress clientIp, InetAddress yourIp,
- InetAddress nextIp, InetAddress relayIp,
+ protected DhcpPacket(int transId, Inet4Address clientIp, Inet4Address yourIp,
+ Inet4Address nextIp, Inet4Address relayIp,
byte[] clientMac, boolean broadcast) {
mTransId = transId;
mClientIp = clientIp;
@@ -240,15 +278,23 @@
}
/**
+ * Returns the client MAC.
+ */
+ public byte[] getClientMac() {
+ return mClientMac;
+ }
+
+ /**
* Creates a new L3 packet (including IP header) containing the
* DHCP udp packet. This method relies upon the delegated method
* finishPacket() to insert the per-packet contents.
*/
- protected void fillInPacket(int encap, InetAddress destIp,
- InetAddress srcIp, short destUdp, short srcUdp, ByteBuffer buf,
+ protected void fillInPacket(int encap, Inet4Address destIp,
+ Inet4Address srcIp, short destUdp, short srcUdp, ByteBuffer buf,
byte requestCode, boolean broadcast) {
byte[] destIpArray = destIp.getAddress();
byte[] srcIpArray = srcIp.getAddress();
+ int ipHeaderOffset = 0;
int ipLengthOffset = 0;
int ipChecksumOffset = 0;
int endIpHeader = 0;
@@ -259,11 +305,17 @@
buf.clear();
buf.order(ByteOrder.BIG_ENDIAN);
+ if (encap == ENCAP_L2) {
+ buf.put(ETHER_BROADCAST);
+ buf.put(mClientMac);
+ buf.putShort((short) OsConstants.ETH_P_IP);
+ }
+
// if a full IP packet needs to be generated, put the IP & UDP
// headers in place, and pre-populate with artificial values
// needed to seed the IP checksum.
- if (encap == ENCAP_L3) {
- // fake IP header, used in the IP-header checksum
+ if (encap <= ENCAP_L3) {
+ ipHeaderOffset = buf.position();
buf.put(IP_VERSION_HEADER_LEN);
buf.put(IP_TOS_LOWDELAY); // tos: IPTOS_LOWDELAY
ipLengthOffset = buf.position();
@@ -322,7 +374,7 @@
// If an IP packet is being built, the IP & UDP checksums must be
// computed.
- if (encap == ENCAP_L3) {
+ if (encap <= ENCAP_L3) {
// fix UDP header: insert length
short udpLen = (short)(buf.position() - udpHeaderOffset);
buf.putShort(udpLengthOffset, udpLen);
@@ -345,10 +397,10 @@
udpHeaderOffset,
buf.position()));
// fix IP header: insert length
- buf.putShort(ipLengthOffset, (short)buf.position());
+ buf.putShort(ipLengthOffset, (short)(buf.position() - ipHeaderOffset));
// fixup IP-header checksum
buf.putShort(ipChecksumOffset,
- (short) checksum(buf, 0, 0, endIpHeader));
+ (short) checksum(buf, 0, ipHeaderOffset, endIpHeader));
}
}
@@ -356,13 +408,8 @@
* Converts a signed short value to an unsigned int value. Needed
* because Java does not have unsigned types.
*/
- private int intAbs(short v) {
- if (v < 0) {
- int r = v + 65536;
- return r;
- } else {
- return(v);
- }
+ private static int intAbs(short v) {
+ return v & 0xFFFF;
}
/**
@@ -412,7 +459,7 @@
/**
* Adds an optional parameter containing a single byte value.
*/
- protected void addTlv(ByteBuffer buf, byte type, byte value) {
+ protected static void addTlv(ByteBuffer buf, byte type, byte value) {
buf.put(type);
buf.put((byte) 1);
buf.put(value);
@@ -421,8 +468,12 @@
/**
* Adds an optional parameter containing an array of bytes.
*/
- protected void addTlv(ByteBuffer buf, byte type, byte[] payload) {
+ protected static void addTlv(ByteBuffer buf, byte type, byte[] payload) {
if (payload != null) {
+ if (payload.length > MAX_OPTION_LEN) {
+ throw new IllegalArgumentException("DHCP option too long: "
+ + payload.length + " vs. " + MAX_OPTION_LEN);
+ }
buf.put(type);
buf.put((byte) payload.length);
buf.put(payload);
@@ -432,7 +483,7 @@
/**
* Adds an optional parameter containing an IP address.
*/
- protected void addTlv(ByteBuffer buf, byte type, InetAddress addr) {
+ protected static void addTlv(ByteBuffer buf, byte type, Inet4Address addr) {
if (addr != null) {
addTlv(buf, type, addr.getAddress());
}
@@ -441,21 +492,38 @@
/**
* Adds an optional parameter containing a list of IP addresses.
*/
- protected void addTlv(ByteBuffer buf, byte type, List<InetAddress> addrs) {
- if (addrs != null && addrs.size() > 0) {
- buf.put(type);
- buf.put((byte)(4 * addrs.size()));
+ protected static void addTlv(ByteBuffer buf, byte type, List<Inet4Address> addrs) {
+ if (addrs == null || addrs.size() == 0) return;
- for (InetAddress addr : addrs) {
- buf.put(addr.getAddress());
- }
+ int optionLen = 4 * addrs.size();
+ if (optionLen > MAX_OPTION_LEN) {
+ throw new IllegalArgumentException("DHCP option too long: "
+ + optionLen + " vs. " + MAX_OPTION_LEN);
+ }
+
+ buf.put(type);
+ buf.put((byte)(optionLen));
+
+ for (Inet4Address addr : addrs) {
+ buf.put(addr.getAddress());
+ }
+ }
+
+ /**
+ * Adds an optional parameter containing a short integer
+ */
+ protected static void addTlv(ByteBuffer buf, byte type, Short value) {
+ if (value != null) {
+ buf.put(type);
+ buf.put((byte) 2);
+ buf.putShort(value.shortValue());
}
}
/**
* Adds an optional parameter containing a simple integer
*/
- protected void addTlv(ByteBuffer buf, byte type, Integer value) {
+ protected static void addTlv(ByteBuffer buf, byte type, Integer value) {
if (value != null) {
buf.put(type);
buf.put((byte) 4);
@@ -464,27 +532,36 @@
}
/**
- * Adds an optional parameter containing and ASCII string.
+ * Adds an optional parameter containing an ASCII string.
*/
- protected void addTlv(ByteBuffer buf, byte type, String str) {
- if (str != null) {
- buf.put(type);
- buf.put((byte) str.length());
-
- for (int i = 0; i < str.length(); i++) {
- buf.put((byte) str.charAt(i));
- }
+ protected static void addTlv(ByteBuffer buf, byte type, String str) {
+ try {
+ addTlv(buf, type, str.getBytes("US-ASCII"));
+ } catch (UnsupportedEncodingException e) {
+ throw new IllegalArgumentException("String is not US-ASCII: " + str);
}
}
/**
* Adds the special end-of-optional-parameters indicator.
*/
- protected void addTlvEnd(ByteBuffer buf) {
+ protected static void addTlvEnd(ByteBuffer buf) {
buf.put((byte) 0xFF);
}
/**
+ * Adds common client TLVs.
+ *
+ * TODO: Does this belong here? The alternative would be to modify all the buildXyzPacket
+ * methods to take them.
+ */
+ protected void addCommonClientTlvs(ByteBuffer buf) {
+ addTlv(buf, DHCP_MAX_MESSAGE_SIZE, (short) MAX_LENGTH);
+ addTlv(buf, DHCP_VENDOR_CLASS_ID, "android-dhcp-" + Build.VERSION.RELEASE);
+ addTlv(buf, DHCP_HOST_NAME, SystemProperties.get("net.hostname"));
+ }
+
+ /**
* Converts a MAC from an array of octets to an ASCII string.
*/
public static String macToString(byte[] mac) {
@@ -515,13 +592,13 @@
* Reads a four-octet value from a ByteBuffer and construct
* an IPv4 address from that value.
*/
- private static InetAddress readIpAddress(ByteBuffer packet) {
- InetAddress result = null;
+ private static Inet4Address readIpAddress(ByteBuffer packet) {
+ Inet4Address result = null;
byte[] ipAddr = new byte[4];
packet.get(ipAddr);
try {
- result = InetAddress.getByAddress(ipAddr);
+ result = (Inet4Address) Inet4Address.getByAddress(ipAddr);
} catch (UnknownHostException ex) {
// ipAddr is numeric, so this should not be
// triggered. However, if it is, just nullify
@@ -553,25 +630,34 @@
{
// bootp parameters
int transactionId;
- InetAddress clientIp;
- InetAddress yourIp;
- InetAddress nextIp;
- InetAddress relayIp;
+ Inet4Address clientIp;
+ Inet4Address yourIp;
+ Inet4Address nextIp;
+ Inet4Address relayIp;
byte[] clientMac;
- List<InetAddress> dnsServers = new ArrayList<InetAddress>();
- InetAddress gateway = null; // aka router
- Integer leaseTime = null;
- InetAddress serverIdentifier = null;
- InetAddress netMask = null;
+ List<Inet4Address> dnsServers = new ArrayList<Inet4Address>();
+ Inet4Address gateway = null; // aka router
+ Inet4Address serverIdentifier = null;
+ Inet4Address netMask = null;
String message = null;
String vendorId = null;
byte[] expectedParams = null;
String hostName = null;
String domainName = null;
- InetAddress ipSrc = null;
- InetAddress ipDst = null;
- InetAddress bcAddr = null;
- InetAddress requestedIp = null;
+ Inet4Address ipSrc = null;
+ Inet4Address ipDst = null;
+ Inet4Address bcAddr = null;
+ Inet4Address requestedIp = null;
+
+ // The following are all unsigned integers. Internally we store them as signed integers of
+ // the same length because that way we're guaranteed that they can't be out of the range of
+ // the unsigned field in the packet. Callers wanting to pass in an unsigned value will need
+ // to cast it.
+ Short mtu = null;
+ Short maxMessageSize = null;
+ Integer leaseTime = null;
+ Integer T1 = null;
+ Integer T2 = null;
// dhcp options
byte dhcpType = (byte) 0xFF;
@@ -580,7 +666,10 @@
// check to see if we need to parse L2, IP, and UDP encaps
if (pktType == ENCAP_L2) {
- // System.out.println("buffer len " + packet.limit());
+ if (packet.remaining() < MIN_PACKET_LENGTH_L2) {
+ return null;
+ }
+
byte[] l2dst = new byte[6];
byte[] l2src = new byte[6];
@@ -589,13 +678,21 @@
short l2type = packet.getShort();
- if (l2type != 0x0800)
+ if (l2type != OsConstants.ETH_P_IP)
return null;
}
- if ((pktType == ENCAP_L2) || (pktType == ENCAP_L3)) {
- // assume l2type is 0x0800, i.e. IP
- byte ipType = packet.get();
+ if (pktType <= ENCAP_L3) {
+ if (packet.remaining() < MIN_PACKET_LENGTH_L3) {
+ return null;
+ }
+
+ byte ipTypeAndLength = packet.get();
+ int ipVersion = (ipTypeAndLength & 0xf0) >> 4;
+ if (ipVersion != 4) {
+ return null;
+ }
+
// System.out.println("ipType is " + ipType);
byte ipDiffServicesField = packet.get();
short ipTotalLength = packet.getShort();
@@ -612,6 +709,14 @@
if (ipProto != IP_TYPE_UDP) // UDP
return null;
+ // Skip options. This cannot cause us to read beyond the end of the buffer because the
+ // IPv4 header cannot be more than (0x0f * 4) = 60 bytes long, and that is less than
+ // MIN_PACKET_LENGTH_L3.
+ int optionWords = ((ipTypeAndLength & 0x0f) - 5);
+ for (int i = 0; i < optionWords; i++) {
+ packet.getInt();
+ }
+
// assume UDP
short udpSrcPort = packet.getShort();
short udpDstPort = packet.getShort();
@@ -622,7 +727,11 @@
return null;
}
- // assume bootp
+ // We need to check the length even for ENCAP_L3 because the IPv4 header is variable-length.
+ if (pktType > ENCAP_BOOTP || packet.remaining() < MIN_PACKET_LENGTH_BOOTP) {
+ return null;
+ }
+
byte type = packet.get();
byte hwType = packet.get();
byte addrLen = packet.get();
@@ -635,13 +744,13 @@
try {
packet.get(ipv4addr);
- clientIp = InetAddress.getByAddress(ipv4addr);
+ clientIp = (Inet4Address) Inet4Address.getByAddress(ipv4addr);
packet.get(ipv4addr);
- yourIp = InetAddress.getByAddress(ipv4addr);
+ yourIp = (Inet4Address) Inet4Address.getByAddress(ipv4addr);
packet.get(ipv4addr);
- nextIp = InetAddress.getByAddress(ipv4addr);
+ nextIp = (Inet4Address) Inet4Address.getByAddress(ipv4addr);
packet.get(ipv4addr);
- relayIp = InetAddress.getByAddress(ipv4addr);
+ relayIp = (Inet4Address) Inet4Address.getByAddress(ipv4addr);
} catch (UnknownHostException ex) {
return null;
}
@@ -663,88 +772,105 @@
boolean notFinishedOptions = true;
while ((packet.position() < packet.limit()) && notFinishedOptions) {
- byte optionType = packet.get();
+ try {
+ byte optionType = packet.get();
- if (optionType == (byte) 0xFF) {
- notFinishedOptions = false;
- } else {
- byte optionLen = packet.get();
- int expectedLen = 0;
+ if (optionType == (byte) 0xFF) {
+ notFinishedOptions = false;
+ } else {
+ int optionLen = packet.get() & 0xFF;
+ int expectedLen = 0;
- switch(optionType) {
- case DHCP_SUBNET_MASK:
- netMask = readIpAddress(packet);
- expectedLen = 4;
- break;
- case DHCP_ROUTER:
- gateway = readIpAddress(packet);
- expectedLen = 4;
- break;
- case DHCP_DNS_SERVER:
- expectedLen = 0;
+ switch(optionType) {
+ case DHCP_SUBNET_MASK:
+ netMask = readIpAddress(packet);
+ expectedLen = 4;
+ break;
+ case DHCP_ROUTER:
+ gateway = readIpAddress(packet);
+ expectedLen = 4;
+ break;
+ case DHCP_DNS_SERVER:
+ for (expectedLen = 0; expectedLen < optionLen; expectedLen += 4) {
+ dnsServers.add(readIpAddress(packet));
+ }
+ break;
+ case DHCP_HOST_NAME:
+ expectedLen = optionLen;
+ hostName = readAsciiString(packet, optionLen);
+ break;
+ case DHCP_MTU:
+ expectedLen = 2;
+ mtu = Short.valueOf(packet.getShort());
+ break;
+ case DHCP_DOMAIN_NAME:
+ expectedLen = optionLen;
+ domainName = readAsciiString(packet, optionLen);
+ break;
+ case DHCP_BROADCAST_ADDRESS:
+ bcAddr = readIpAddress(packet);
+ expectedLen = 4;
+ break;
+ case DHCP_REQUESTED_IP:
+ requestedIp = readIpAddress(packet);
+ expectedLen = 4;
+ break;
+ case DHCP_LEASE_TIME:
+ leaseTime = Integer.valueOf(packet.getInt());
+ expectedLen = 4;
+ break;
+ case DHCP_MESSAGE_TYPE:
+ dhcpType = packet.get();
+ expectedLen = 1;
+ break;
+ case DHCP_SERVER_IDENTIFIER:
+ serverIdentifier = readIpAddress(packet);
+ expectedLen = 4;
+ break;
+ case DHCP_PARAMETER_LIST:
+ expectedParams = new byte[optionLen];
+ packet.get(expectedParams);
+ expectedLen = optionLen;
+ break;
+ case DHCP_MESSAGE:
+ expectedLen = optionLen;
+ message = readAsciiString(packet, optionLen);
+ break;
+ case DHCP_MAX_MESSAGE_SIZE:
+ expectedLen = 2;
+ maxMessageSize = Short.valueOf(packet.getShort());
+ break;
+ case DHCP_RENEWAL_TIME:
+ expectedLen = 4;
+ T1 = Integer.valueOf(packet.getInt());
+ break;
+ case DHCP_REBINDING_TIME:
+ expectedLen = 4;
+ T2 = Integer.valueOf(packet.getInt());
+ break;
+ case DHCP_VENDOR_CLASS_ID:
+ expectedLen = optionLen;
+ vendorId = readAsciiString(packet, optionLen);
+ break;
+ case DHCP_CLIENT_IDENTIFIER: { // Client identifier
+ byte[] id = new byte[optionLen];
+ packet.get(id);
+ expectedLen = optionLen;
+ } break;
+ default:
+ // ignore any other parameters
+ for (int i = 0; i < optionLen; i++) {
+ expectedLen++;
+ byte throwaway = packet.get();
+ }
+ }
- for (expectedLen = 0; expectedLen < optionLen;
- expectedLen += 4) {
- dnsServers.add(readIpAddress(packet));
- }
- break;
- case DHCP_HOST_NAME:
- expectedLen = optionLen;
- hostName = readAsciiString(packet, optionLen);
- break;
- case DHCP_DOMAIN_NAME:
- expectedLen = optionLen;
- domainName = readAsciiString(packet, optionLen);
- break;
- case DHCP_BROADCAST_ADDRESS:
- bcAddr = readIpAddress(packet);
- expectedLen = 4;
- break;
- case DHCP_REQUESTED_IP:
- requestedIp = readIpAddress(packet);
- expectedLen = 4;
- break;
- case DHCP_LEASE_TIME:
- leaseTime = Integer.valueOf(packet.getInt());
- expectedLen = 4;
- break;
- case DHCP_MESSAGE_TYPE:
- dhcpType = packet.get();
- expectedLen = 1;
- break;
- case DHCP_SERVER_IDENTIFIER:
- serverIdentifier = readIpAddress(packet);
- expectedLen = 4;
- break;
- case DHCP_PARAMETER_LIST:
- expectedParams = new byte[optionLen];
- packet.get(expectedParams);
- expectedLen = optionLen;
- break;
- case DHCP_MESSAGE:
- expectedLen = optionLen;
- message = readAsciiString(packet, optionLen);
- break;
- case DHCP_VENDOR_CLASS_ID:
- expectedLen = optionLen;
- vendorId = readAsciiString(packet, optionLen);
- break;
- case DHCP_CLIENT_IDENTIFIER: { // Client identifier
- byte[] id = new byte[optionLen];
- packet.get(id);
- expectedLen = optionLen;
- } break;
- default:
- // ignore any other parameters
- for (int i = 0; i < optionLen; i++) {
- expectedLen++;
- byte throwaway = packet.get();
- }
+ if (expectedLen != optionLen) {
+ return null;
+ }
}
-
- if (expectedLen != optionLen) {
- return null;
- }
+ } catch (BufferUnderflowException e) {
+ return null;
}
}
@@ -795,23 +921,67 @@
newPacket.mHostName = hostName;
newPacket.mLeaseTime = leaseTime;
newPacket.mMessage = message;
+ newPacket.mMtu = mtu;
newPacket.mRequestedIp = requestedIp;
newPacket.mRequestedParams = expectedParams;
newPacket.mServerIdentifier = serverIdentifier;
newPacket.mSubnetMask = netMask;
+ newPacket.mMaxMessageSize = maxMessageSize;
+ newPacket.mT1 = T1;
+ newPacket.mT2 = T2;
+ newPacket.mVendorId = vendorId;
return newPacket;
}
/**
- * Parse a packet from an array of bytes.
+ * Parse a packet from an array of bytes, stopping at the given length.
*/
- public static DhcpPacket decodeFullPacket(byte[] packet, int pktType)
+ public static DhcpPacket decodeFullPacket(byte[] packet, int length, int pktType)
{
- ByteBuffer buffer = ByteBuffer.wrap(packet).order(ByteOrder.BIG_ENDIAN);
+ ByteBuffer buffer = ByteBuffer.wrap(packet, 0, length).order(ByteOrder.BIG_ENDIAN);
return decodeFullPacket(buffer, pktType);
}
/**
+ * Construct a DhcpResults object from a DHCP reply packet.
+ */
+ public DhcpResults toDhcpResults() {
+ Inet4Address ipAddress = mYourIp;
+ if (ipAddress == Inet4Address.ANY) {
+ ipAddress = mClientIp;
+ if (ipAddress == Inet4Address.ANY) {
+ return null;
+ }
+ }
+
+ int prefixLength;
+ if (mSubnetMask != null) {
+ try {
+ prefixLength = NetworkUtils.netmaskToPrefixLength(mSubnetMask);
+ } catch (IllegalArgumentException e) {
+ // Non-contiguous netmask.
+ return null;
+ }
+ } else {
+ prefixLength = NetworkUtils.getImplicitNetmask(ipAddress);
+ }
+
+ DhcpResults results = new DhcpResults();
+ try {
+ results.ipAddress = new LinkAddress(ipAddress, prefixLength);
+ } catch (IllegalArgumentException e) {
+ return null;
+ }
+ results.gateway = mGateway;
+ results.dnsServers.addAll(mDnsServers);
+ results.domains = mDomainName;
+ results.serverAddress = mServerIdentifier;
+ results.vendorInfo = mVendorId;
+ results.leaseDuration = mLeaseTime;
+ return results;
+ }
+
+ /**
* Builds a DHCP-DISCOVER packet from the required specified
* parameters.
*/
@@ -828,10 +998,10 @@
* parameters.
*/
public static ByteBuffer buildOfferPacket(int encap, int transactionId,
- boolean broadcast, InetAddress serverIpAddr, InetAddress clientIpAddr,
- byte[] mac, Integer timeout, InetAddress netMask, InetAddress bcAddr,
- InetAddress gateway, List<InetAddress> dnsServers,
- InetAddress dhcpServerIdentifier, String domainName) {
+ boolean broadcast, Inet4Address serverIpAddr, Inet4Address clientIpAddr,
+ byte[] mac, Integer timeout, Inet4Address netMask, Inet4Address bcAddr,
+ Inet4Address gateway, List<Inet4Address> dnsServers,
+ Inet4Address dhcpServerIdentifier, String domainName) {
DhcpPacket pkt = new DhcpOfferPacket(
transactionId, broadcast, serverIpAddr, clientIpAddr, mac);
pkt.mGateway = gateway;
@@ -848,10 +1018,10 @@
* Builds a DHCP-ACK packet from the required specified parameters.
*/
public static ByteBuffer buildAckPacket(int encap, int transactionId,
- boolean broadcast, InetAddress serverIpAddr, InetAddress clientIpAddr,
- byte[] mac, Integer timeout, InetAddress netMask, InetAddress bcAddr,
- InetAddress gateway, List<InetAddress> dnsServers,
- InetAddress dhcpServerIdentifier, String domainName) {
+ boolean broadcast, Inet4Address serverIpAddr, Inet4Address clientIpAddr,
+ byte[] mac, Integer timeout, Inet4Address netMask, Inet4Address bcAddr,
+ Inet4Address gateway, List<Inet4Address> dnsServers,
+ Inet4Address dhcpServerIdentifier, String domainName) {
DhcpPacket pkt = new DhcpAckPacket(
transactionId, broadcast, serverIpAddr, clientIpAddr, mac);
pkt.mGateway = gateway;
@@ -868,7 +1038,7 @@
* Builds a DHCP-NAK packet from the required specified parameters.
*/
public static ByteBuffer buildNakPacket(int encap, int transactionId,
- InetAddress serverIpAddr, InetAddress clientIpAddr, byte[] mac) {
+ Inet4Address serverIpAddr, Inet4Address clientIpAddr, byte[] mac) {
DhcpPacket pkt = new DhcpNakPacket(transactionId, clientIpAddr,
serverIpAddr, serverIpAddr, serverIpAddr, mac);
pkt.mMessage = "requested address not available";
@@ -880,9 +1050,9 @@
* Builds a DHCP-REQUEST packet from the required specified parameters.
*/
public static ByteBuffer buildRequestPacket(int encap,
- int transactionId, InetAddress clientIp, boolean broadcast,
- byte[] clientMac, InetAddress requestedIpAddress,
- InetAddress serverIdentifier, byte[] requestedParams, String hostName) {
+ int transactionId, Inet4Address clientIp, boolean broadcast,
+ byte[] clientMac, Inet4Address requestedIpAddress,
+ Inet4Address serverIdentifier, byte[] requestedParams, String hostName) {
DhcpPacket pkt = new DhcpRequestPacket(transactionId, clientIp,
clientMac, broadcast);
pkt.mRequestedIp = requestedIpAddress;
diff --git a/core/java/android/net/dhcp/DhcpRequestPacket.java b/services/net/java/android/net/dhcp/DhcpRequestPacket.java
similarity index 69%
rename from core/java/android/net/dhcp/DhcpRequestPacket.java
rename to services/net/java/android/net/dhcp/DhcpRequestPacket.java
index cf32957..42b7b0c 100644
--- a/core/java/android/net/dhcp/DhcpRequestPacket.java
+++ b/services/net/java/android/net/dhcp/DhcpRequestPacket.java
@@ -18,7 +18,6 @@
import android.util.Log;
-import java.net.InetAddress;
import java.net.Inet4Address;
import java.nio.ByteBuffer;
@@ -29,10 +28,9 @@
/**
* Generates a REQUEST packet with the specified parameters.
*/
- DhcpRequestPacket(int transId, InetAddress clientIp, byte[] clientMac,
+ DhcpRequestPacket(int transId, Inet4Address clientIp, byte[] clientMac,
boolean broadcast) {
- super(transId, clientIp, Inet4Address.ANY, Inet4Address.ANY,
- Inet4Address.ANY, clientMac, broadcast);
+ super(transId, clientIp, INADDR_ANY, INADDR_ANY, INADDR_ANY, clientMac, broadcast);
}
public String toString() {
@@ -48,7 +46,7 @@
public ByteBuffer buildPacket(int encap, short destUdp, short srcUdp) {
ByteBuffer result = ByteBuffer.allocate(MAX_LENGTH);
- fillInPacket(encap, Inet4Address.ALL, Inet4Address.ANY, destUdp, srcUdp,
+ fillInPacket(encap, INADDR_BROADCAST, INADDR_ANY, destUdp, srcUdp,
result, DHCP_BOOTREQUEST, mBroadcast);
result.flip();
return result;
@@ -65,22 +63,15 @@
System.arraycopy(mClientMac, 0, clientId, 1, 6);
addTlv(buffer, DHCP_MESSAGE_TYPE, DHCP_MESSAGE_TYPE_REQUEST);
- addTlv(buffer, DHCP_PARAMETER_LIST, mRequestedParams);
- addTlv(buffer, DHCP_REQUESTED_IP, mRequestedIp);
- addTlv(buffer, DHCP_SERVER_IDENTIFIER, mServerIdentifier);
+ if (!INADDR_ANY.equals(mRequestedIp)) {
+ addTlv(buffer, DHCP_REQUESTED_IP, mRequestedIp);
+ }
+ if (!INADDR_ANY.equals(mServerIdentifier)) {
+ addTlv(buffer, DHCP_SERVER_IDENTIFIER, mServerIdentifier);
+ }
addTlv(buffer, DHCP_CLIENT_IDENTIFIER, clientId);
+ addCommonClientTlvs(buffer);
+ addTlv(buffer, DHCP_PARAMETER_LIST, mRequestedParams);
addTlvEnd(buffer);
}
-
- /**
- * Notifies the specified state machine of the REQUEST packet parameters.
- */
- public void doNextOp(DhcpStateMachine machine) {
- InetAddress clientRequest =
- mRequestedIp == null ? mClientIp : mRequestedIp;
- Log.v(TAG, "requested IP is " + mRequestedIp + " and client IP is " +
- mClientIp);
- machine.onRequestReceived(mBroadcast, mTransId, mClientMac,
- clientRequest, mRequestedParams, mHostName);
- }
}
diff --git a/telecomm/java/android/telecom/AuthenticatorService.java b/telecomm/java/android/telecom/AuthenticatorService.java
new file mode 100644
index 0000000..39717c3
--- /dev/null
+++ b/telecomm/java/android/telecom/AuthenticatorService.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2015 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.telecom;
+import android.accounts.AbstractAccountAuthenticator;
+import android.accounts.Account;
+import android.accounts.AccountAuthenticatorResponse;
+import android.accounts.NetworkErrorException;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.IBinder;
+
+/**
+ * A generic stub account authenticator service often used for sync adapters that do not directly
+ * involve accounts.
+ */
+public class AuthenticatorService extends Service {
+ private static Authenticator mAuthenticator;
+
+ @Override
+ public void onCreate() {
+ mAuthenticator = new Authenticator(this);
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return mAuthenticator.getIBinder();
+ }
+
+ /**
+ * Stub account authenticator. All methods either return null or throw an exception.
+ */
+ public class Authenticator extends AbstractAccountAuthenticator {
+ public Authenticator(Context context) {
+ super(context);
+ }
+
+ @Override
+ public Bundle editProperties(AccountAuthenticatorResponse accountAuthenticatorResponse,
+ String s) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Bundle addAccount(AccountAuthenticatorResponse accountAuthenticatorResponse,
+ String s, String s2, String[] strings, Bundle bundle)
+ throws NetworkErrorException {
+ return null;
+ }
+
+ @Override
+ public Bundle confirmCredentials(AccountAuthenticatorResponse accountAuthenticatorResponse,
+ Account account, Bundle bundle)
+ throws NetworkErrorException {
+ return null;
+ }
+
+ @Override
+ public Bundle getAuthToken(AccountAuthenticatorResponse accountAuthenticatorResponse,
+ Account account, String s, Bundle bundle)
+ throws NetworkErrorException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String getAuthTokenLabel(String s) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Bundle updateCredentials(AccountAuthenticatorResponse accountAuthenticatorResponse,
+ Account account, String s, Bundle bundle)
+ throws NetworkErrorException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Bundle hasFeatures(AccountAuthenticatorResponse accountAuthenticatorResponse,
+ Account account, String[] strings)
+ throws NetworkErrorException {
+ throw new UnsupportedOperationException();
+ }
+ }
+}
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index c1d2f9b..436f20a 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -141,28 +141,42 @@
public static final int CAPABILITY_MANAGE_CONFERENCE = 0x00000080;
/**
- * Local device supports video telephony.
+ * Local device supports receiving video.
* @hide
*/
- public static final int CAPABILITY_SUPPORTS_VT_LOCAL = 0x00000100;
+ public static final int CAPABILITY_SUPPORTS_VT_LOCAL_RX = 0x00000100;
/**
- * Remote device supports video telephony.
+ * Local device supports transmitting video.
* @hide
*/
- public static final int CAPABILITY_SUPPORTS_VT_REMOTE = 0x00000200;
+ public static final int CAPABILITY_SUPPORTS_VT_LOCAL_TX = 0x00000200;
/**
- * Call is using high definition audio.
+ * Local device supports bidirectional video calling.
* @hide
*/
- public static final int CAPABILITY_HIGH_DEF_AUDIO = 0x00000400;
+ public static final int CAPABILITY_SUPPORTS_VT_LOCAL =
+ CAPABILITY_SUPPORTS_VT_LOCAL_RX | CAPABILITY_SUPPORTS_VT_LOCAL_TX;
/**
- * Call is using WIFI.
+ * Remote device supports receiving video.
* @hide
*/
- public static final int CAPABILITY_WIFI = 0x00000800;
+ public static final int CAPABILITY_SUPPORTS_VT_REMOTE_RX = 0x00000400;
+
+ /**
+ * Remote device supports transmitting video.
+ * @hide
+ */
+ public static final int CAPABILITY_SUPPORTS_VT_REMOTE_TX = 0x00000800;
+
+ /**
+ * Remote device supports bidirectional video calling.
+ * @hide
+ */
+ public static final int CAPABILITY_SUPPORTS_VT_REMOTE =
+ CAPABILITY_SUPPORTS_VT_REMOTE_RX | CAPABILITY_SUPPORTS_VT_REMOTE_TX;
/**
* Call is able to be separated from its parent {@code Conference}, if any.
@@ -183,10 +197,37 @@
public static final int CAPABILITY_GENERIC_CONFERENCE = 0x00004000;
/**
+ * Call is using high definition audio.
+ * @hide
+ */
+ public static final int CAPABILITY_HIGH_DEF_AUDIO = 0x00008000;
+
+ /**
+ * Call is using WIFI.
+ * @hide
+ */
+ public static final int CAPABILITY_WIFI = 0x00010000;
+
+ //******************************************************************************************
+ // Next CAPABILITY value: 0x00020000
+ //******************************************************************************************
+
+ /**
+ * Indicates that the current device callback number should be shown.
+ *
+ * @hide
+ */
+ public static final int CAPABILITY_SHOW_CALLBACK_NUMBER = 0x00020000;
+
+ /**
* Speed up audio setup for MT call.
* @hide
*/
- public static final int CAPABILITY_SPEED_UP_MT_AUDIO = 0x00008000;
+ public static final int CAPABILITY_SPEED_UP_MT_AUDIO = 0x00040000;
+
+ //******************************************************************************************
+ // Next CAPABILITY value: 0x00080000
+ //******************************************************************************************
private final Uri mHandle;
private final int mHandlePresentation;
@@ -255,9 +296,21 @@
if (can(capabilities, CAPABILITY_MANAGE_CONFERENCE)) {
builder.append(" CAPABILITY_MANAGE_CONFERENCE");
}
+ if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_RX)) {
+ builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL_RX");
+ }
+ if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_TX)) {
+ builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL_TX");
+ }
if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL)) {
builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL");
}
+ if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_RX)) {
+ builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_RX");
+ }
+ if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_TX)) {
+ builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_TX");
+ }
if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE)) {
builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE");
}
@@ -270,8 +323,11 @@
if (can(capabilities, CAPABILITY_GENERIC_CONFERENCE)) {
builder.append(" CAPABILITY_GENERIC_CONFERENCE");
}
+ if (can(capabilities, CAPABILITY_SHOW_CALLBACK_NUMBER)) {
+ builder.append(" CAPABILITY_SHOW_CALLBACK_NUMBER");
+ }
if (can(capabilities, CAPABILITY_SPEED_UP_MT_AUDIO)) {
- builder.append(" CAPABILITY_SPEED_UP_IMS_MT_AUDIO");
+ builder.append(" CAPABILITY_SPEED_UP_MT_AUDIO");
}
builder.append("]");
return builder.toString();
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 569163a..bab064e 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -106,28 +106,42 @@
public static final int CAPABILITY_MANAGE_CONFERENCE = 0x00000080;
/**
- * Local device supports video telephony.
+ * Local device supports receiving video.
* @hide
*/
- public static final int CAPABILITY_SUPPORTS_VT_LOCAL = 0x00000100;
+ public static final int CAPABILITY_SUPPORTS_VT_LOCAL_RX = 0x00000100;
/**
- * Remote device supports video telephony.
+ * Local device supports transmitting video.
* @hide
*/
- public static final int CAPABILITY_SUPPORTS_VT_REMOTE = 0x00000200;
+ public static final int CAPABILITY_SUPPORTS_VT_LOCAL_TX = 0x00000200;
/**
- * Connection is using high definition audio.
+ * Local device supports bidirectional video calling.
* @hide
*/
- public static final int CAPABILITY_HIGH_DEF_AUDIO = 0x00000400;
+ public static final int CAPABILITY_SUPPORTS_VT_LOCAL =
+ CAPABILITY_SUPPORTS_VT_LOCAL_RX | CAPABILITY_SUPPORTS_VT_LOCAL_TX;
/**
- * Connection is using WIFI.
+ * Remote device supports receiving video.
* @hide
*/
- public static final int CAPABILITY_WIFI = 0x00000800;
+ public static final int CAPABILITY_SUPPORTS_VT_REMOTE_RX = 0x00000400;
+
+ /**
+ * Remote device supports transmitting video.
+ * @hide
+ */
+ public static final int CAPABILITY_SUPPORTS_VT_REMOTE_TX = 0x00000800;
+
+ /**
+ * Remote device supports bidirectional video calling.
+ * @hide
+ */
+ public static final int CAPABILITY_SUPPORTS_VT_REMOTE =
+ CAPABILITY_SUPPORTS_VT_REMOTE_RX | CAPABILITY_SUPPORTS_VT_REMOTE_TX;
/**
* Connection is able to be separated from its parent {@code Conference}, if any.
@@ -148,10 +162,33 @@
public static final int CAPABILITY_GENERIC_CONFERENCE = 0x00004000;
/**
+ * Connection is using high definition audio.
+ * @hide
+ */
+ public static final int CAPABILITY_HIGH_DEF_AUDIO = 0x00008000;
+
+ /**
+ * Connection is using WIFI.
+ * @hide
+ */
+ public static final int CAPABILITY_WIFI = 0x00010000;
+
+ /**
+ * Indicates that the current device callback number should be shown.
+ *
+ * @hide
+ */
+ public static final int CAPABILITY_SHOW_CALLBACK_NUMBER = 0x00020000;
+
+ /**
* Speed up audio setup for MT call.
* @hide
*/
- public static final int CAPABILITY_SPEED_UP_MT_AUDIO = 0x00008000;
+ public static final int CAPABILITY_SPEED_UP_MT_AUDIO = 0x00040000;
+
+ //**********************************************************************************************
+ // Next CAPABILITY value: 0x00080000
+ //**********************************************************************************************
// Flag controlling whether PII is emitted into the logs
private static final boolean PII_DEBUG = Log.isLoggable(android.util.Log.DEBUG);
@@ -224,9 +261,21 @@
if (can(capabilities, CAPABILITY_MANAGE_CONFERENCE)) {
builder.append(" CAPABILITY_MANAGE_CONFERENCE");
}
+ if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_RX)) {
+ builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL_RX");
+ }
+ if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL_TX)) {
+ builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL_TX");
+ }
if (can(capabilities, CAPABILITY_SUPPORTS_VT_LOCAL)) {
builder.append(" CAPABILITY_SUPPORTS_VT_LOCAL");
}
+ if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_RX)) {
+ builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_RX");
+ }
+ if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE_TX)) {
+ builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE_TX");
+ }
if (can(capabilities, CAPABILITY_SUPPORTS_VT_REMOTE)) {
builder.append(" CAPABILITY_SUPPORTS_VT_REMOTE");
}
@@ -239,8 +288,11 @@
if (can(capabilities, CAPABILITY_GENERIC_CONFERENCE)) {
builder.append(" CAPABILITY_GENERIC_CONFERENCE");
}
+ if (can(capabilities, CAPABILITY_SHOW_CALLBACK_NUMBER)) {
+ builder.append(" CAPABILITY_SHOW_CALLBACK_NUMBER");
+ }
if (can(capabilities, CAPABILITY_SPEED_UP_MT_AUDIO)) {
- builder.append(" CAPABILITY_SPEED_UP_IMS_MT_AUDIO");
+ builder.append(" CAPABILITY_SPEED_UP_MT_AUDIO");
}
builder.append("]");
return builder.toString();
diff --git a/telecomm/java/android/telecom/PhoneAccount.java b/telecomm/java/android/telecom/PhoneAccount.java
index 052a481..a94c2f6 100644
--- a/telecomm/java/android/telecom/PhoneAccount.java
+++ b/telecomm/java/android/telecom/PhoneAccount.java
@@ -40,15 +40,13 @@
/**
* Represents a distinct method to place or receive a phone call. Apps which can place calls and
* want those calls to be integrated into the dialer and in-call UI should build an instance of
- * this class and register it with the system using {@link TelecomManager#registerPhoneAccount}.
+ * this class and register it with the system using {@link TelecomManager}.
* <p>
* {@link TelecomManager} uses registered {@link PhoneAccount}s to present the user with
* alternative options when placing a phone call. When building a {@link PhoneAccount}, the app
- * should supply a valid {@link PhoneAccountHandle} that references the {@link ConnectionService}
+ * should supply a valid {@link PhoneAccountHandle} that references the connection service
* implementation Telecom will use to interact with the app.
- * @hide
*/
-@SystemApi
public class PhoneAccount implements Parcelable {
/**
@@ -62,7 +60,9 @@
* if the user has explicitly selected it to be used as the default connection manager.
* <p>
* See {@link #getCapabilities}
+ * @hide
*/
+ @SystemApi
public static final int CAPABILITY_CONNECTION_MANAGER = 0x1;
/**
@@ -76,6 +76,7 @@
* <p>
* {@hide}
*/
+ @SystemApi
public static final int CAPABILITY_CALL_PROVIDER = 0x2;
/**
@@ -94,6 +95,7 @@
* See {@link #getCapabilities}
* @hide
*/
+ @SystemApi
public static final int CAPABILITY_VIDEO_CALLING = 0x8;
/**
@@ -111,6 +113,7 @@
* See {@link #getCapabilities}
* @hide
*/
+ @SystemApi
public static final int CAPABILITY_MULTI_USER = 0x20;
/**
@@ -203,6 +206,7 @@
}
/** @hide */
+ @SystemApi
public Builder setAccountHandle(PhoneAccountHandle accountHandle) {
mAccountHandle = accountHandle;
return this;
@@ -333,6 +337,7 @@
* @return The builder.
* @hide
*/
+ @SystemApi
public Builder addSupportedUriScheme(String uriScheme) {
if (!TextUtils.isEmpty(uriScheme) && !mSupportedUriSchemes.contains(uriScheme)) {
this.mSupportedUriSchemes.add(uriScheme);
@@ -423,6 +428,7 @@
* @return The builder.
* @hide
*/
+ @SystemApi
public Builder toBuilder() { return new Builder(this); }
/**
diff --git a/telecomm/java/android/telecom/PhoneAccountHandle.java b/telecomm/java/android/telecom/PhoneAccountHandle.java
index 97af41a..4600b72 100644
--- a/telecomm/java/android/telecom/PhoneAccountHandle.java
+++ b/telecomm/java/android/telecom/PhoneAccountHandle.java
@@ -29,16 +29,13 @@
* The unique identifier for a {@link PhoneAccount}. A {@code PhoneAccountHandle} is made of two
* parts:
* <ul>
- * <li>The component name of the associated {@link ConnectionService}.</li>
+ * <li>The component name of the associated connection service.</li>
* <li>A string identifier that is unique across {@code PhoneAccountHandle}s with the same
* component name.</li>
* </ul>
*
- * See {@link PhoneAccount},
- * {@link TelecomManager#registerPhoneAccount TelecomManager.registerPhoneAccount}.
- * @hide
+ * See {@link PhoneAccount}, {@link TelecomManager}.
*/
-@SystemApi
public class PhoneAccountHandle implements Parcelable {
private final ComponentName mComponentName;
private final String mId;
@@ -51,6 +48,7 @@
}
/** @hide */
+ @SystemApi
public PhoneAccountHandle(
ComponentName componentName,
String id,
@@ -61,8 +59,8 @@
}
/**
- * The {@code ComponentName} of the {@link android.telecom.ConnectionService} which is
- * responsible for making phone calls using this {@code PhoneAccountHandle}.
+ * The {@code ComponentName} of the connection service which is responsible for making phone
+ * calls using this {@code PhoneAccountHandle}.
*
* @return A suitable {@code ComponentName}.
*/
@@ -72,9 +70,9 @@
/**
* A string that uniquely distinguishes this particular {@code PhoneAccountHandle} from all the
- * others supported by the {@link ConnectionService} that created it.
+ * others supported by the connection service that created it.
* <p>
- * A {@code ConnectionService} must select identifiers that are stable for the lifetime of
+ * A connection service must select identifiers that are stable for the lifetime of
* their users' relationship with their service, across many Android devices. For example, a
* good set of identifiers might be the email addresses with which with users registered for
* their accounts with a particular service. Depending on how a service chooses to operate,
@@ -82,6 +80,9 @@
* ({@code 0}, {@code 1}, {@code 2}, ...) that are generated locally on each phone and could
* collide with values generated on other phones or after a data wipe of a given phone.
*
+ * Important: A non-unique identifier could cause non-deterministic call-log backup/restore
+ * behavior.
+ *
* @return A service-specific unique identifier for this {@code PhoneAccountHandle}.
*/
public String getId() {
@@ -92,6 +93,7 @@
* @return the {@link UserHandle} to use when connecting to this PhoneAccount.
* @hide
*/
+ @SystemApi
public UserHandle getUserHandle() {
return mUserHandle;
}
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 1a6b292..8be3e66 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -92,6 +92,15 @@
"android.telecom.action.CHANGE_PHONE_ACCOUNTS";
/**
+ * The {@link android.content.Intent} action used indicate that a new phone account was
+ * just registered.
+ * @hide
+ */
+ @SystemApi
+ public static final String ACTION_PHONE_ACCOUNT_REGISTERED =
+ "android.telecom.action.PHONE_ACCOUNT_REGISTERED";
+
+ /**
* Optional extra for {@link android.content.Intent#ACTION_CALL} containing a boolean that
* determines whether the speakerphone should be automatically turned on for an outgoing call.
*/
@@ -106,7 +115,6 @@
* {@link VideoProfile.VideoState#BIDIRECTIONAL},
* {@link VideoProfile.VideoState#RX_ENABLED},
* {@link VideoProfile.VideoState#TX_ENABLED}.
- * @hide
*/
public static final String EXTRA_START_CALL_WITH_VIDEO_STATE =
"android.telecom.extra.START_CALL_WITH_VIDEO_STATE";
@@ -117,9 +125,7 @@
* {@link PhoneAccountHandle} to use when making the call.
* <p class="note">
* Retrieve with {@link android.content.Intent#getParcelableExtra(String)}.
- * @hide
*/
- @SystemApi
public static final String EXTRA_PHONE_ACCOUNT_HANDLE =
"android.telecom.extra.PHONE_ACCOUNT_HANDLE";
@@ -139,10 +145,7 @@
* {@link android.content.Intent#ACTION_DIAL} {@code Intent} containing a {@link Bundle}
* which contains metadata about the call. This {@link Bundle} will be saved into
* {@code Call.Details}.
- *
- * @hide
*/
- @SystemApi
public static final String EXTRA_OUTGOING_CALL_EXTRAS =
"android.telecom.extra.OUTGOING_CALL_EXTRAS";
@@ -554,9 +557,7 @@
*
* @param account The {@link PhoneAccountHandle}.
* @return The {@link PhoneAccount} object.
- * @hide
*/
- @SystemApi
public PhoneAccount getPhoneAccount(PhoneAccountHandle account) {
try {
if (isServiceConnected()) {
diff --git a/telecomm/java/android/telecom/VideoProfile.java b/telecomm/java/android/telecom/VideoProfile.java
index f5cb054..e62e994 100644
--- a/telecomm/java/android/telecom/VideoProfile.java
+++ b/telecomm/java/android/telecom/VideoProfile.java
@@ -21,8 +21,6 @@
/**
* Represents attributes of video calls.
- *
- * {@hide}
*/
public class VideoProfile implements Parcelable {
/**
diff --git a/telecomm/java/android/telecom/Voicemail.java b/telecomm/java/android/telecom/Voicemail.java
new file mode 100644
index 0000000..864c6b1
--- /dev/null
+++ b/telecomm/java/android/telecom/Voicemail.java
@@ -0,0 +1,266 @@
+/*
+ * Copyright (C) 2015 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.telecom;
+
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Represents a single voicemail stored in the voicemail content provider.
+ */
+public class Voicemail implements Parcelable {
+ private final Long mTimestamp;
+ private final String mNumber;
+ private final Long mId;
+ private final Long mDuration;
+ private final String mSource;
+ private final String mProviderData;
+ private final Uri mUri;
+ private final Boolean mIsRead;
+ private final Boolean mHasContent;
+
+ private Voicemail(Long timestamp, String number, Long id, Long duration, String source,
+ String providerData, Uri uri, Boolean isRead, Boolean hasContent) {
+ mTimestamp = timestamp;
+ mNumber = number;
+ mId = id;
+ mDuration = duration;
+ mSource = source;
+ mProviderData = providerData;
+ mUri = uri;
+ mIsRead = isRead;
+ mHasContent = hasContent;
+ }
+
+ /**
+ * Create a {@link Builder} for a new {@link Voicemail} to be inserted.
+ * <p>
+ * The number and the timestamp are mandatory for insertion.
+ */
+ public static Builder createForInsertion(long timestamp, String number) {
+ return new Builder().setNumber(number).setTimestamp(timestamp);
+ }
+
+ /**
+ * Builder pattern for creating a {@link Voicemail}. The builder must be created with the
+ * {@link #createForInsertion(long, String)} method.
+ * <p>
+ * This class is <b>not thread safe</b>
+ */
+ public static class Builder {
+ private Long mBuilderTimestamp;
+ private String mBuilderNumber;
+ private Long mBuilderId;
+ private Long mBuilderDuration;
+ private String mBuilderSourcePackage;
+ private String mBuilderSourceData;
+ private Uri mBuilderUri;
+ private Boolean mBuilderIsRead;
+ private boolean mBuilderHasContent;
+
+ /** You should use the correct factory method to construct a builder. */
+ private Builder() {
+ }
+
+ public Builder setNumber(String number) {
+ mBuilderNumber = number;
+ return this;
+ }
+
+ public Builder setTimestamp(long timestamp) {
+ mBuilderTimestamp = timestamp;
+ return this;
+ }
+
+ public Builder setId(long id) {
+ mBuilderId = id;
+ return this;
+ }
+
+ public Builder setDuration(long duration) {
+ mBuilderDuration = duration;
+ return this;
+ }
+
+ public Builder setSourcePackage(String sourcePackage) {
+ mBuilderSourcePackage = sourcePackage;
+ return this;
+ }
+
+ public Builder setSourceData(String sourceData) {
+ mBuilderSourceData = sourceData;
+ return this;
+ }
+
+ public Builder setUri(Uri uri) {
+ mBuilderUri = uri;
+ return this;
+ }
+
+ public Builder setIsRead(boolean isRead) {
+ mBuilderIsRead = isRead;
+ return this;
+ }
+
+ public Builder setHasContent(boolean hasContent) {
+ mBuilderHasContent = hasContent;
+ return this;
+ }
+
+ public Voicemail build() {
+ mBuilderId = mBuilderId == null ? -1 : mBuilderId;
+ mBuilderTimestamp = mBuilderTimestamp == null ? 0 : mBuilderTimestamp;
+ mBuilderDuration = mBuilderDuration == null ? 0: mBuilderDuration;
+ mBuilderIsRead = mBuilderIsRead == null ? false : mBuilderIsRead;
+ return new Voicemail(mBuilderTimestamp, mBuilderNumber, mBuilderId, mBuilderDuration,
+ mBuilderSourcePackage, mBuilderSourceData, mBuilderUri, mBuilderIsRead,
+ mBuilderHasContent);
+ }
+ }
+
+ /**
+ * The identifier of the voicemail in the content provider.
+ * <p>
+ * This may be missing in the case of a new {@link Voicemail} that we plan to insert into the
+ * content provider, since until it has been inserted we don't know what id it should have. If
+ * none is specified, we return -1.
+ */
+ public long getId() {
+ return mId;
+ }
+
+ /** The number of the person leaving the voicemail, empty string if unknown, null if not set. */
+ public String getNumber() {
+ return mNumber;
+ }
+
+ /** The timestamp the voicemail was received, in millis since the epoch, zero if not set. */
+ public long getTimestampMillis() {
+ return mTimestamp;
+ }
+
+ /** Gets the duration of the voicemail in millis, or zero if the field is not set. */
+ public long getDuration() {
+ return mDuration;
+ }
+
+ /**
+ * Returns the package name of the source that added this voicemail, or null if this field is
+ * not set.
+ */
+ public String getSourcePackage() {
+ return mSource;
+ }
+
+ /**
+ * Returns the application-specific data type stored with the voicemail, or null if this field
+ * is not set.
+ * <p>
+ * Source data is typically used as an identifier to uniquely identify the voicemail against
+ * the voicemail server. This is likely to be something like the IMAP UID, or some other
+ * server-generated identifying string.
+ */
+ public String getSourceData() {
+ return mProviderData;
+ }
+
+ /**
+ * Gets the Uri that can be used to refer to this voicemail, and to make it play.
+ * <p>
+ * Returns null if we don't know the Uri.
+ */
+ public Uri getUri() {
+ return mUri;
+ }
+
+ /**
+ * Tells us if the voicemail message has been marked as read.
+ * <p>
+ * Always returns false if this field has not been set, i.e. if hasRead() returns false.
+ */
+ public boolean isRead() {
+ return mIsRead;
+ }
+
+ /**
+ * Tells us if there is content stored at the Uri.
+ */
+ public boolean hasContent() {
+ return mHasContent;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeLong(mTimestamp);
+ dest.writeCharSequence(mNumber);
+ dest.writeLong(mId);
+ dest.writeLong(mDuration);
+ dest.writeCharSequence(mSource);
+ dest.writeCharSequence(mProviderData);
+ if (mUri == null) {
+ dest.writeInt(0);
+ } else {
+ dest.writeInt(1);
+ mUri.writeToParcel(dest, flags);
+ }
+ if (mIsRead) {
+ dest.writeInt(1);
+ } else {
+ dest.writeInt(0);
+ }
+ if (mHasContent) {
+ dest.writeInt(1);
+ } else {
+ dest.writeInt(0);
+ }
+ }
+
+ public static final Creator<Voicemail> CREATOR
+ = new Creator<Voicemail>() {
+ @Override
+ public Voicemail createFromParcel(Parcel in) {
+ return new Voicemail(in);
+ }
+
+ @Override
+ public Voicemail[] newArray(int size) {
+ return new Voicemail[size];
+ }
+ };
+
+ private Voicemail(Parcel in) {
+ mTimestamp = in.readLong();
+ mNumber = (String) in.readCharSequence();
+ mId = in.readLong();
+ mDuration = in.readLong();
+ mSource = (String) in.readCharSequence();
+ mProviderData = (String) in.readCharSequence();
+ if (in.readInt() > 0) {
+ mUri = Uri.CREATOR.createFromParcel(in);
+ } else {
+ mUri = null;
+ }
+ mIsRead = in.readInt() > 0 ? true : false;
+ mHasContent = in.readInt() > 0 ? true : false;
+ }
+}
\ No newline at end of file
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index c043659..3572846 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -34,11 +34,11 @@
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
-import android.telephony.Rlog;
import android.text.style.TtsSpan;
import android.util.SparseIntArray;
-import static com.android.internal.telephony.PhoneConstants.SUBSCRIPTION_KEY;
+import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY;
+import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_ISO_COUNTRY;
import static com.android.internal.telephony.TelephonyProperties.PROPERTY_OPERATOR_IDP_STRING;
import java.util.Locale;
@@ -2311,15 +2311,13 @@
*
* @param phoneNumber A {@code CharSequence} the entirety of which represents a phone number.
* @return A {@code CharSequence} with appropriate annotations.
- *
- * @hide
*/
- public static CharSequence ttsSpanAsPhoneNumber(CharSequence phoneNumber) {
+ public static CharSequence getPhoneTtsSpannable(CharSequence phoneNumber) {
if (phoneNumber == null) {
return null;
}
Spannable spannable = Spannable.Factory.getInstance().newSpannable(phoneNumber);
- PhoneNumberUtils.ttsSpanAsPhoneNumber(spannable, 0, spannable.length());
+ PhoneNumberUtils.addPhoneTtsSpan(spannable, 0, spannable.length());
return spannable;
}
@@ -2330,19 +2328,83 @@
* @param s A {@code Spannable} to annotate.
* @param start The starting character position of the phone number in {@code s}.
* @param end The ending character position of the phone number in {@code s}.
- *
- * @hide
*/
- public static void ttsSpanAsPhoneNumber(Spannable s, int start, int end) {
- s.setSpan(
- new TtsSpan.TelephoneBuilder()
- .setNumberParts(splitAtNonNumerics(s.subSequence(start, end)))
- .build(),
+ public static void addPhoneTtsSpan(Spannable s, int start, int end) {
+ s.setSpan(getPhoneTtsSpan(s.subSequence(start, end).toString()),
start,
end,
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
+ /**
+ * Wrap the supplied {@code CharSequence} with a {@code TtsSpan}, annotating it as
+ * containing a phone number in its entirety.
+ *
+ * @param phoneNumber A {@code CharSequence} the entirety of which represents a phone number.
+ * @return A {@code CharSequence} with appropriate annotations.
+ * @deprecated Renamed {@link #getPhoneTtsSpannable}.
+ *
+ * @hide
+ */
+ @Deprecated
+ public static CharSequence ttsSpanAsPhoneNumber(CharSequence phoneNumber) {
+ return getPhoneTtsSpannable(phoneNumber);
+ }
+
+ /**
+ * Attach a {@link TtsSpan} to the supplied {@code Spannable} at the indicated location,
+ * annotating that location as containing a phone number.
+ *
+ * @param s A {@code Spannable} to annotate.
+ * @param start The starting character position of the phone number in {@code s}.
+ * @param end The ending character position of the phone number in {@code s}.
+ *
+ * @deprecated Renamed {@link #addPhoneTtsSpan}.
+ *
+ * @hide
+ */
+ @Deprecated
+ public static void ttsSpanAsPhoneNumber(Spannable s, int start, int end) {
+ addPhoneTtsSpan(s, start, end);
+ }
+
+ /**
+ * Create a {@code TtsSpan} for the supplied {@code String}.
+ *
+ * @param phoneNumberString A {@code String} the entirety of which represents a phone number.
+ * @return A {@code TtsSpan} for {@param phoneNumberString}.
+ */
+ public static TtsSpan getPhoneTtsSpan(String phoneNumberString) {
+ if (phoneNumberString == null) {
+ return null;
+ }
+
+ // Parse the phone number
+ final PhoneNumberUtil phoneNumberUtil = PhoneNumberUtil.getInstance();
+ PhoneNumber phoneNumber = null;
+ try {
+ // Don't supply a defaultRegion so this fails for non-international numbers because
+ // we don't want to TalkBalk to read a country code (e.g. +1) if it is not already
+ // present
+ phoneNumber = phoneNumberUtil.parse(phoneNumberString, /* defaultRegion */ null);
+ } catch (NumberParseException ignored) {
+ }
+
+ // Build a telephone tts span
+ final TtsSpan.TelephoneBuilder builder = new TtsSpan.TelephoneBuilder();
+ if (phoneNumber == null) {
+ // Strip separators otherwise TalkBack will be silent
+ // (this behavior was observed with TalkBalk 4.0.2 from their alpha channel)
+ builder.setNumberParts(splitAtNonNumerics(phoneNumberString));
+ } else {
+ if (phoneNumber.hasCountryCode()) {
+ builder.setCountryCode(Integer.toString(phoneNumber.getCountryCode()));
+ }
+ builder.setNumberParts(Long.toString(phoneNumber.getNationalNumber()));
+ }
+ return builder.build();
+ }
+
// Split a phone number like "+20(123)-456#" using spaces, ignoring anything that is not
// a digit, to produce a result like "20 123 456".
private static String splitAtNonNumerics(CharSequence number) {
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index b8de144..e1a3de7 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -29,6 +29,7 @@
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemProperties;
+import android.telecom.PhoneAccount;
import android.util.Log;
import com.android.internal.telecom.ITelecomService;
@@ -3779,7 +3780,7 @@
/**
* Returns the IMS Registration Status
- *@hide
+ * @hide
*/
public boolean isImsRegistered() {
try {
@@ -4158,4 +4159,21 @@
ServiceState.rilRadioTechnologyToString(type));
}
}
+
+ /**
+ * Returns the subscription ID for the given phone account.
+ * @hide
+ */
+ public int getSubIdForPhoneAccount(PhoneAccount phoneAccount) {
+ int retval = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+ try {
+ ITelephony service = getITelephony();
+ if (service != null) {
+ retval = service.getSubIdForPhoneAccount(phoneAccount);
+ }
+ } catch (RemoteException e) {
+ }
+
+ return retval;
+ }
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index bb0bd04..d03fa3a 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -18,6 +18,7 @@
import android.content.Intent;
import android.os.Bundle;
+import android.telecom.PhoneAccount;
import android.telephony.CellInfo;
import android.telephony.IccOpenLogicalChannelResponse;
import android.telephony.NeighboringCellInfo;
@@ -891,4 +892,9 @@
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
*/
String getDeviceId();
+
+ /**
+ * Returns the subscription ID associated with the specified PhoneAccount.
+ */
+ int getSubIdForPhoneAccount(in PhoneAccount phoneAccount);
}
diff --git a/wifi/java/android/net/wifi/IRttManager.aidl b/wifi/java/android/net/wifi/IRttManager.aidl
index d929f55..90f66c4 100644
--- a/wifi/java/android/net/wifi/IRttManager.aidl
+++ b/wifi/java/android/net/wifi/IRttManager.aidl
@@ -15,8 +15,8 @@
*/
package android.net.wifi;
-
import android.os.Messenger;
+import android.net.wifi.RttManager;
/**
* {@hide}
@@ -24,4 +24,5 @@
interface IRttManager
{
Messenger getMessenger();
+ RttManager.RttCapabilities getRttCapabilities();
}
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index ca95ec1..5342494 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -79,6 +79,8 @@
void setCountryCode(String country, boolean persist);
+ String getCountryCode();
+
void setFrequencyBand(int band, boolean persist);
int getFrequencyBand();
diff --git a/wifi/java/android/net/wifi/RttManager.aidl b/wifi/java/android/net/wifi/RttManager.aidl
new file mode 100644
index 0000000..5c6d447
--- /dev/null
+++ b/wifi/java/android/net/wifi/RttManager.aidl
@@ -0,0 +1,18 @@
+/**
+ * Copyright (c) 2015, 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;
+parcelable RttManager.RttCapabilities;
\ No newline at end of file
diff --git a/wifi/java/android/net/wifi/RttManager.java b/wifi/java/android/net/wifi/RttManager.java
index 57343c5..65ecf5d 100644
--- a/wifi/java/android/net/wifi/RttManager.java
+++ b/wifi/java/android/net/wifi/RttManager.java
@@ -26,10 +26,19 @@
private static final boolean DBG = true;
private static final String TAG = "RttManager";
- public static final int RTT_TYPE_UNSPECIFIED = 0;
- public static final int RTT_TYPE_ONE_SIDED = 1;
- public static final int RTT_TYPE_11_V = 2;
- public static final int RTT_TYPE_11_MC = 4;
+ /** @deprecated Type must be specified*/
+ @Deprecated
+ public static final int RTT_TYPE_UNSPECIFIED = 0;
+ public static final int RTT_TYPE_ONE_SIDED = 1;
+
+ /** @deprecated It is not supported*/
+ @Deprecated
+ public static final int RTT_TYPE_11_V = 2;
+ public static final int RTT_TYPE_TWO_SIDED = 4;
+
+ /** @deprecated It is not supported*/
+ @Deprecated
+ public static final int RTT_TYPE_11_MC = 4;
public static final int RTT_PEER_TYPE_UNSPECIFIED = 0;
public static final int RTT_PEER_TYPE_AP = 1;
@@ -42,6 +51,9 @@
public static final int RTT_CHANNEL_WIDTH_80P80 = 4;
public static final int RTT_CHANNEL_WIDTH_5 = 5;
public static final int RTT_CHANNEL_WIDTH_10 = 6;
+
+ /** @deprecated channel info must be specified*/
+ @Deprecated
public static final int RTT_CHANNEL_WIDTH_UNSPECIFIED = -1;
public static final int RTT_STATUS_SUCCESS = 0;
@@ -53,6 +65,12 @@
public static final int RTT_STATUS_FAIL_AP_ON_DIFF_CHANNEL = 6;
public static final int RTT_STATUS_FAIL_NO_CAPABILITY = 7;
public static final int RTT_STATUS_ABORTED = 8;
+ //if the T1-T4 or TOD/TOA Timestamp is illegal
+ public static final int RTT_STATUS_FAIL_INVALID_TS = 9;
+ //11mc protocol failed, eg, unrecognized FTMR/FTM
+ public static final int RTT_STATUS_FAIL_PROTOCOL = 10;
+ public static final int RTT_STATUS_FAIL_SCHEDULE = 11;
+ public static final int RTT_STATUS_FAIL_BUSY_TRY_LATER = 12;
public static final int REASON_UNSPECIFIED = -1;
public static final int REASON_NOT_AVAILABLE = -2;
@@ -61,41 +79,269 @@
public static final String DESCRIPTION_KEY = "android.net.wifi.RttManager.Description";
+ /**
+ * RTT BW supported bit mask
+ */
+ public static final int RTT_BW_5_SUPPORT = 0x1;
+ public static final int RTT_BW_10_SUPPORT = 0x2;
+ public static final int RTT_BW_20_SUPPORT = 0x4;
+ public static final int RTT_BW_40_SUPPORT = 0x8;
+ public static final int RTT_BW_80_SUPPORT = 0x10;
+ public static final int RTT_BW_160_SUPPORT = 0x20;
+
+ /**
+ * RTT Preamble Support bit mask
+ */
+ public static final int PREAMBLE_LEGACY = 0x1;
+ public static final int PREAMBLE_HT = 0x2;
+ public static final int PREAMBLE_VHT = 0x4;
+
+ /** @deprecated It has been replaced by RttCapabilities*/
+ @Deprecated
public class Capabilities {
public int supportedType;
public int supportedPeerType;
}
+ /** @deprecated It has been replaced by getRttCapabilities*/
+ @Deprecated
public Capabilities getCapabilities() {
return new Capabilities();
}
+ /**
+ * This class describe the RTT capability of the Hardware
+ */
+ public static class RttCapabilities implements Parcelable {
+ /** @deprecated It is not supported*/
+ @Deprecated
+ public boolean supportedType;
+ /** @deprecated It is not supported*/
+ @Deprecated
+ public boolean supportedPeerType;
+ //1-sided rtt measurement is supported
+ public boolean oneSidedRttSupported;
+ //11mc 2-sided rtt measurement is supported
+ public boolean twoSided11McRttSupported;
+ //location configuration information supported
+ public boolean lciSupported;
+ //location civic records supported
+ public boolean lcrSupported;
+ //preamble supported, see bit mask definition above
+ public int preambleSupported;
+ //RTT bandwidth supported
+ public int bwSupported;
+
+ @Override
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append("oneSidedRtt ").
+ append(oneSidedRttSupported ? "is Supported. " : "is not supported. ").
+ append("twoSided11McRtt ").
+ append(twoSided11McRttSupported ? "is Supported. " : "is not supported. ").
+ append("lci ").
+ append(lciSupported ? "is Supported. " : "is not supported. ").
+ append("lcr ").
+ append(lcrSupported ? "is Supported. " : "is not supported. ");
+
+ if ((preambleSupported & PREAMBLE_LEGACY) != 0) {
+ sb.append("Legacy ");
+ }
+
+ if ((preambleSupported & PREAMBLE_HT) != 0) {
+ sb.append("HT ");
+ }
+
+ if ((preambleSupported & PREAMBLE_VHT) != 0) {
+ sb.append("VHT ");
+ }
+
+ sb.append("is supported. \n");
+
+ if ((bwSupported & RTT_BW_5_SUPPORT) != 0) {
+ sb.append("5 MHz ");
+ }
+
+ if ((bwSupported & RTT_BW_10_SUPPORT) != 0) {
+ sb.append("10 MHz ");
+ }
+
+ if ((bwSupported & RTT_BW_20_SUPPORT) != 0) {
+ sb.append("20 MHz ");
+ }
+
+ if ((bwSupported & RTT_BW_40_SUPPORT) != 0) {
+ sb.append("40 MHz ");
+ }
+
+ if ((bwSupported & RTT_BW_80_SUPPORT) != 0) {
+ sb.append("80 MHz ");
+ }
+
+ if ((bwSupported & RTT_BW_160_SUPPORT) != 0) {
+ sb.append("160 MHz ");
+ }
+
+ sb.append("is supported.");
+
+ return sb.toString();
+ }
+ /** Implement the Parcelable interface {@hide} */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(oneSidedRttSupported ? 1 : 0);
+ dest.writeInt(twoSided11McRttSupported ? 1 : 0);
+ dest.writeInt(lciSupported ? 1 : 0);
+ dest.writeInt(lcrSupported ? 1 : 0);
+ dest.writeInt(preambleSupported);
+ dest.writeInt(bwSupported);
+
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ public static final Creator<RttCapabilities> CREATOR =
+ new Creator<RttCapabilities>() {
+ public RttCapabilities createFromParcel(Parcel in) {
+ RttCapabilities capabilities = new RttCapabilities();
+ capabilities.oneSidedRttSupported = in.readInt() == 1 ? true : false;
+ capabilities.twoSided11McRttSupported = in.readInt() == 1 ? true : false;
+ capabilities.lciSupported = in.readInt() == 1 ? true : false;
+ capabilities.lcrSupported = in.readInt() == 1 ? true : false;
+ capabilities.preambleSupported = in.readInt();
+ capabilities.bwSupported = in.readInt();
+ return capabilities;
+ }
+ /** Implement the Parcelable interface {@hide} */
+ @Override
+ public RttCapabilities[] newArray(int size) {
+ return new RttCapabilities[size];
+ }
+ };
+ }
+
+ public RttCapabilities getRttCapabilities() {
+ synchronized (sCapabilitiesLock) {
+ if (mRttCapabilities == null) {
+ try {
+ mRttCapabilities = mService.getRttCapabilities();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Can not get RTT Capabilities");
+ }
+ }
+ return mRttCapabilities;
+ }
+ }
+
/** specifies parameters for RTT request */
public static class RttParams {
-
- /** type of device being ranged; one of RTT_PEER_TYPE_AP or RTT_PEER_TYPE_STA */
+ /**
+ * type of destination device being ranged; one of RTT_PEER_TYPE_AP or RTT_PEER_TYPE_STA
+ */
public int deviceType;
- /** type of RTT being sought; one of RTT_TYPE_ONE_SIDED
- * RTT_TYPE_11_V or RTT_TYPE_11_MC or RTT_TYPE_UNSPECIFIED */
+ /**
+ * type of RTT measurement method; one of RTT_TYPE_ONE_SIDED or RTT_TYPE_TWO_SIDED.
+ */
public int requestType;
/** mac address of the device being ranged */
public String bssid;
- /** channel frequency that the device is on; optional */
+ /**
+ * The primary 20 MHz frequency (in MHz) of the channel over which the client is
+ * communicating with the access point.Similar as ScanResult.frequency
+ */
public int frequency;
- /** optional channel width. wider channels result in better accuracy,
- * but they take longer time, and even get aborted may times; use
- * RTT_CHANNEL_WIDTH_UNSPECIFIED if not specifying */
+ /**
+ * channel width used for RTT measurement. User need verify the highest BW the destination
+ * support (from scan result etc) before set this value. Wider channels result usually give
+ * better accuracy. However, the frame loss can increase. Similar as ScanResult.channelWidth
+ */
public int channelWidth;
- /** number of samples to be taken */
+ /**
+ * Not used if the AP bandwidth is 20 MHz
+ * If the AP use 40, 80 or 160 MHz, this is the center frequency
+ * if the AP use 80 + 80 MHz, this is the center frequency of the first segment
+ * similar as ScanResult.centerFreq0
+ */
+ public int centerFreq0;
+
+ /**
+ * Only used if the AP bandwidth is 80 + 80 MHz
+ * if the AP use 80 + 80 MHz, this is the center frequency of the second segment
+ * similar as ScanResult.centerFreq1
+ */
+ public int centerFreq1;
+ /**
+ * number of samples to be taken
+ * @deprecated It has been replaced by numSamplesPerBurst
+ */
+ @Deprecated
public int num_samples;
- /** number of retries if a sample fails */
+ /**
+ * number of retries if a sample fails
+ * @deprecated It has been replaced by numRetriesPerMeasurementFrame
+ */
+ @Deprecated
public int num_retries;
+
+ /** Number of burst. fixed to 1 for single side RTT*/
+ public int numberBurst;
+
+ /** valid only if numberBurst > 1, interval between burst(ms). Not used by singe side RTT */
+ public int interval;
+
+ /** number of samples to be taken in one burst*/
+ public int numSamplesPerBurst;
+
+ /** number of retries for each measurement frame if a sample fails
+ * Only used by single side RTT
+ */
+ public int numRetriesPerMeasurementFrame;
+
+ /** number of retries for FTMR frame if fails Only used by 80211MC double side RTT */
+ public int numRetriesPerFTMR;
+
+ /** Request LCI information */
+ public boolean LCIRequest;
+
+ /** Request LCR information */
+ public boolean LCRRequest;
+
+ /** Timeout for each burst, unit of 250 us*/
+ public int burstTimeout;
+
+ /** preamble used for RTT measurement
+ * should be one of PREAMBLE_LEGACY, PREAMBLE_HT, PREAMBLE_VHT
+ */
+ public int preamble;
+
+ /** bandWidth used for RTT measurement.User need verify the highest BW the destination
+ * support (from scan result etc) before set this value. Wider channels result usually give
+ * better accuracy. However, the frame loss can increase too.
+ * should be one of RTT_CHANNEL_WIDTH_20 to RTT_CHANNEL_WIDTH_80
+ */
+ public int bandwidth;
+
+ public RttParams() {
+ //provide initial value for RttParams
+ deviceType = RTT_PEER_TYPE_AP;
+ numberBurst = 1;
+ numSamplesPerBurst = 8;
+ numRetriesPerMeasurementFrame = 0;
+ burstTimeout = 40 + numSamplesPerBurst *4;
+ preamble = PREAMBLE_LEGACY;
+ bandwidth = RTT_CHANNEL_WIDTH_20;
+ }
}
/** pseudo-private class used to parcel arguments */
@@ -121,10 +367,20 @@
dest.writeInt(params.deviceType);
dest.writeInt(params.requestType);
dest.writeString(params.bssid);
- dest.writeInt(params.frequency);
dest.writeInt(params.channelWidth);
- dest.writeInt(params.num_samples);
- dest.writeInt(params.num_retries);
+ dest.writeInt(params.frequency);
+ dest.writeInt(params.centerFreq0);
+ dest.writeInt(params.centerFreq1);
+ dest.writeInt(params.numberBurst);
+ dest.writeInt(params.interval);
+ dest.writeInt(params.numSamplesPerBurst);
+ dest.writeInt(params.numRetriesPerMeasurementFrame);
+ dest.writeInt(params.numRetriesPerFTMR);
+ dest.writeInt(params.LCIRequest ? 1 : 0);
+ dest.writeInt(params.LCRRequest ? 1 : 0);
+ dest.writeInt(params.burstTimeout);
+ dest.writeInt(params.preamble);
+ dest.writeInt(params.bandwidth);
}
} else {
dest.writeInt(0);
@@ -148,11 +404,20 @@
params[i].deviceType = in.readInt();
params[i].requestType = in.readInt();
params[i].bssid = in.readString();
- params[i].frequency = in.readInt();
params[i].channelWidth = in.readInt();
- params[i].num_samples = in.readInt();
- params[i].num_retries = in.readInt();
-
+ params[i].frequency = in.readInt();
+ params[i].centerFreq0 = in.readInt();
+ params[i].centerFreq1 = in.readInt();
+ params[i].numberBurst = in.readInt();
+ params[i].interval = in.readInt();
+ params[i].numSamplesPerBurst = in.readInt();
+ params[i].numRetriesPerMeasurementFrame = in.readInt();
+ params[i].numRetriesPerFTMR = in.readInt();
+ params[i].LCIRequest = in.readInt() == 1 ? true : false;
+ params[i].LCRRequest = in.readInt() == 1 ? true : false;
+ params[i].burstTimeout = in.readInt();
+ params[i].preamble = in.readInt();
+ params[i].bandwidth = in.readInt();
}
ParcelableRttParams parcelableParams = new ParcelableRttParams(params);
@@ -165,46 +430,143 @@
};
}
+ public class wifiInformationElement {
+ /** Information Element ID*/
+ public int id;
+ public String data;
+ }
/** specifies RTT results */
public static class RttResult {
/** mac address of the device being ranged */
public String bssid;
+ /** # of burst for this measurement*/
+ public int burstNumber;
+
+ /** total number of measurement frames in this measurement*/
+ public int measurementFrameNumber;
+
+ /** total successful number of measurement frames in this measurement*/
+ public int successMeasurementFrameNumber;
+
+ /** Maximum number of frames per burst supported by peer */
+ public int frameNumberPerBurstPeer;
+
/** status of the request */
public int status;
- /** type of the request used */
+ /**
+ * type of the request used
+ * @deprecated It has been replaced by measurementType
+ */
+ @Deprecated
public int requestType;
+ /** RTT measurement method type used, shoudl be one of RTT_TYPE_ONE_SIDED or
+ * RTT_TYPE_TWO_SIDED.
+ */
+ public int measurementType;
+
+ /** please retry RTT measurement after this S since peer indicate busy at ths moment*/
+ public int retryAfterDuration;
+
/** timestamp of completion, in microsecond since boot */
public long ts;
- /** average RSSI observed */
+ /** average RSSI observed, unit of 0.5 dB */
public int rssi;
- /** RSSI spread (i.e. max - min) */
+ /**
+ * RSSI spread (i.e. max - min)
+ * @deprecated It has been replaced by rssi_spread
+ */
+ @Deprecated
public int rssi_spread;
- /** average transmit rate */
+ /**RSSI spread (i.e. max - min), unit of 0.5 dB */
+ public int rssiSpread;
+
+ /**
+ * average transmit rate
+ * @deprecated It has been replaced by txRate
+ */
+ @Deprecated
public int tx_rate;
- /** average round trip time in nano second */
+ /** average transmit rate */
+ public int txRate;
+
+ /** average receiving rate */
+ public int rxRate;
+
+ /**
+ * average round trip time in nano second
+ * @deprecated It has been replaced by rtt
+ */
+ @Deprecated
public long rtt_ns;
- /** standard deviation observed in round trip time */
+ /** average round trip time in 0.1 nano second */
+ public long rtt;
+
+ /**
+ * standard deviation observed in round trip time
+ * @deprecated It has been replaced by rttStandardDeviation
+ */
+ @Deprecated
public long rtt_sd_ns;
- /** spread (i.e. max - min) round trip time */
+ /** standard deviation of RTT in 0.1 ns */
+ public long rttStandardDeviation;
+
+ /**
+ * spread (i.e. max - min) round trip time
+ * @deprecated It has been replaced by rttSpread
+ */
+ @Deprecated
public long rtt_spread_ns;
- /** average distance in centimeter, computed based on rtt_ns */
+ /** spread (i.e. max - min) RTT in 0.1 ns */
+ public long rttSpread;
+
+ /**
+ * average distance in centimeter, computed based on rtt_ns
+ * @deprecated It has been replaced by distance
+ */
+ @Deprecated
public int distance_cm;
- /** standard deviation observed in distance */
+ /** average distance in cm, computed based on rtt */
+ public int distance;
+
+ /**
+ * standard deviation observed in distance
+ * @deprecated It has been replaced with distanceStandardDeviation
+ */
+ @Deprecated
public int distance_sd_cm;
- /** spread (i.e. max - min) distance */
+ /** standard deviation observed in distance in cm*/
+ public int distanceStandardDeviation;
+
+ /**
+ * spread (i.e. max - min) distance
+ * @deprecated It has been replaced by distanceSpread
+ */
+ @Deprecated
public int distance_spread_cm;
+
+ /** spread (i.e. max - min) distance in cm */
+ public int distanceSpread;
+
+ /** the duration of this measurement burst*/
+ public int burstDuration;
+
+ /** LCI information Element*/
+ wifiInformationElement LCI;
+
+ /** LCR information Element*/
+ wifiInformationElement LCR;
}
@@ -228,18 +590,28 @@
dest.writeInt(mResults.length);
for (RttResult result : mResults) {
dest.writeString(result.bssid);
+ dest.writeInt(result.burstNumber);
+ dest.writeInt(result.measurementFrameNumber);
+ dest.writeInt(result.successMeasurementFrameNumber);
+ dest.writeInt(result.frameNumberPerBurstPeer);
dest.writeInt(result.status);
- dest.writeInt(result.requestType);
+ dest.writeInt(result.measurementType);
+ dest.writeInt(result.retryAfterDuration);
dest.writeLong(result.ts);
dest.writeInt(result.rssi);
- dest.writeInt(result.rssi_spread);
- dest.writeInt(result.tx_rate);
- dest.writeLong(result.rtt_ns);
- dest.writeLong(result.rtt_sd_ns);
- dest.writeLong(result.rtt_spread_ns);
- dest.writeInt(result.distance_cm);
- dest.writeInt(result.distance_sd_cm);
- dest.writeInt(result.distance_spread_cm);
+ dest.writeInt(result.rssiSpread);
+ dest.writeInt(result.txRate);
+ dest.writeLong(result.rtt);
+ dest.writeLong(result.rttStandardDeviation);
+ dest.writeLong(result.rttSpread);
+ dest.writeInt(result.distance);
+ dest.writeInt(result.distanceStandardDeviation);
+ dest.writeInt(result.distanceSpread);
+ dest.writeInt(result.burstDuration);
+ //dest.writeInt(result.LCI.id);
+ //dest.writeString(result.LCI.data);
+ //dest.writeInt(result.LCR.id);
+ //dest.writeString(result.LCR.data);
}
} else {
dest.writeInt(0);
@@ -261,18 +633,28 @@
for (int i = 0; i < num; i++) {
results[i] = new RttResult();
results[i].bssid = in.readString();
+ results[i].burstNumber = in.readInt();
+ results[i].measurementFrameNumber = in.readInt();
+ results[i].successMeasurementFrameNumber = in.readInt();
+ results[i].frameNumberPerBurstPeer = in.readInt();
results[i].status = in.readInt();
- results[i].requestType = in.readInt();
+ results[i].measurementType = in.readInt();
+ results[i].retryAfterDuration = in.readInt();
results[i].ts = in.readLong();
results[i].rssi = in.readInt();
- results[i].rssi_spread = in.readInt();
- results[i].tx_rate = in.readInt();
- results[i].rtt_ns = in.readLong();
- results[i].rtt_sd_ns = in.readLong();
- results[i].rtt_spread_ns = in.readLong();
- results[i].distance_cm = in.readInt();
- results[i].distance_sd_cm = in.readInt();
- results[i].distance_spread_cm = in.readInt();
+ results[i].rssiSpread = in.readInt();
+ results[i].txRate = in.readInt();
+ results[i].rtt = in.readLong();
+ results[i].rttStandardDeviation = in.readLong();
+ results[i].rttSpread = in.readLong();
+ results[i].distance = in.readInt();
+ results[i].distanceStandardDeviation = in.readInt();
+ results[i].distanceSpread = in.readInt();
+ results[i].burstDuration = in.readInt();
+ //results[i].LCI.id = in.readInt();
+ //results[i].LCI.data = in.readString();
+ //results[i].LCR.id = in.readInt();
+ //results[i].LCR.data = in.readString();
}
ParcelableRttResults parcelableResults = new ParcelableRttResults(results);
@@ -292,7 +674,70 @@
public void onAborted();
}
+ private boolean rttParamSanity(RttParams params, int index) {
+ if (mRttCapabilities == null) {
+ if(getRttCapabilities() == null) {
+ Log.e(TAG, "Can not get RTT capabilities");
+ //throw new IllegalStateException("RTT chip is not working");
+ }
+ }
+
+ if (params.deviceType != RTT_PEER_TYPE_AP) {
+ return false;
+ } else if (params.requestType != RTT_TYPE_ONE_SIDED && params.requestType !=
+ RTT_TYPE_TWO_SIDED) {
+ Log.e(TAG, "Request " + index + ": Illegal Request Type: " + params.requestType);
+ return false;
+ } else if (params.requestType == RTT_TYPE_ONE_SIDED &&
+ !mRttCapabilities.oneSidedRttSupported) {
+ Log.e(TAG, "Request " + index + ": One side RTT is not supported");
+ return false;
+ } else if (params.requestType == RTT_TYPE_TWO_SIDED &&
+ !mRttCapabilities.twoSided11McRttSupported) {
+ Log.e(TAG, "Request " + index + ": two side RTT is not supported");
+ return false;
+ } else if ( params.numberBurst <= 0 ) {
+ Log.e(TAG, "Request " + index + ": Illegal number of burst: " + params.numberBurst);
+ return false;
+ } else if (params.numberBurst > 1 && params.interval <= 0) {
+ Log.e(TAG, "Request " + index + ": Illegal interval value: " + params.interval);
+ return false;
+ } else if (params.numSamplesPerBurst <= 0) {
+ Log.e(TAG, "Request " + index + ": Illegal sample number per burst: " +
+ params.numSamplesPerBurst);
+ return false;
+ } else if (params.numRetriesPerMeasurementFrame < 0 || params.numRetriesPerFTMR < 0) {
+ Log.e(TAG, "Request " + index + ": Illegal retry number");
+ return false;
+ } else if (params.LCIRequest && !mRttCapabilities.lciSupported) {
+ Log.e(TAG, "Request " + index + ": LCI is not supported");
+ return false;
+ } else if (params.LCRRequest && !mRttCapabilities.lcrSupported) {
+ Log.e(TAG, "Request " + index + ": LCR is not supported");
+ return false;
+ } else if (params.burstTimeout <= 0){
+ Log.e(TAG, "Request " + index + ": Illegal burst timeout: " + params.burstTimeout);
+ return false;
+ } else if ((params.preamble & mRttCapabilities.preambleSupported) == 0) {
+ Log.e(TAG, "Request " + index + ": Do not support this preamble: " + params.preamble);
+ return false;
+ } else if ((params.bandwidth & mRttCapabilities.bwSupported) == 0) {
+ Log.e(TAG, "Request " + index + ": Do not support this bandwidth: " + params.bandwidth);
+ return false;
+ }
+
+ return true;
+ }
+
public void startRanging(RttParams[] params, RttListener listener) {
+ int index = 0;
+ for(RttParams rttParam : params) {
+ if (!rttParamSanity(rttParam, index)) {
+ throw new IllegalArgumentException("RTT Request Parameter Illegal");
+ }
+ index++;
+ }
+
validateChannel();
ParcelableRttParams parcelableParams = new ParcelableRttParams(params);
sAsyncChannel.sendMessage(CMD_OP_START_RANGING,
@@ -315,12 +760,14 @@
private Context mContext;
private IRttManager mService;
+ private RttCapabilities mRttCapabilities;
private static final int INVALID_KEY = 0;
private static int sListenerKey = 1;
private static final SparseArray sListenerMap = new SparseArray();
private static final Object sListenerMapLock = new Object();
+ private static final Object sCapabilitiesLock = new Object();
private static AsyncChannel sAsyncChannel;
private static CountDownLatch sConnected;
diff --git a/wifi/java/android/net/wifi/ScanResult.java b/wifi/java/android/net/wifi/ScanResult.java
index 9729c91..e8a51e3 100644
--- a/wifi/java/android/net/wifi/ScanResult.java
+++ b/wifi/java/android/net/wifi/ScanResult.java
@@ -53,11 +53,55 @@
*/
public int level;
/**
- * The frequency in MHz of the channel over which the client is communicating
+ * The primary 20 MHz frequency (in MHz) of the channel over which the client is communicating
* with the access point.
*/
public int frequency;
+ /**
+ * AP Channel bandwidth is 20 MHZ
+ */
+ public static final int CHANNEL_WIDTH_20MHZ = 0;
+ /**
+ * AP Channel bandwidth is 40 MHZ
+ */
+ public static final int CHANNEL_WIDTH_40MHZ = 1;
+ /**
+ * AP Channel bandwidth is 80 MHZ
+ */
+ public static final int CHANNEL_WIDTH_80MHZ = 2;
+ /**
+ * AP Channel bandwidth is 160 MHZ
+ */
+ public static final int CHANNEL_WIDTH_160MHZ = 3;
+ /**
+ * AP Channel bandwidth is 160 MHZ, but 80MHZ + 80MHZ
+ */
+ public static final int CHANNEL_WIDTH_80MHZ_PLUS_MHZ = 4;
+
+ /**
+ * AP Channel bandwidth
+ */
+ public int channelWidth;
+
+ /**
+ * Not used if the AP bandwidth is 20 MHz
+ * If the AP use 40, 80 or 160 MHz, this is the center frequency
+ * if the AP use 80 + 80 MHz, this is the center frequency of the first segment
+ */
+ public int centerFreq0;
+
+ /**
+ * Only used if the AP bandwidth is 80 + 80 MHz
+ * if the AP use 80 + 80 MHz, this is the center frequency of the second segment
+ */
+ public int centerFreq1;
+
+ /**
+ * Whether the AP support 802.11mc Responder
+ */
+ public boolean is80211McRTTResponder;
+
/**
* timestamp in microseconds (since boot) when
* this result was last seen.
@@ -169,6 +213,21 @@
public int distanceSdCm;
/**
+ * Indicates if the scan result represents a passpoint AP
+ */
+ public boolean passpointNetwork;
+
+ /**
+ * Indicates if venue name
+ */
+ public String venueName;
+
+ /**
+ * Indicates operator name
+ */
+ public String operatorFriendlyName;
+
+ /**
* {@hide}
*/
public final static int UNSPECIFIED = -1;
@@ -235,6 +294,11 @@
this.timestamp = tsf;
this.distanceCm = UNSPECIFIED;
this.distanceSdCm = UNSPECIFIED;
+ this.channelWidth = UNSPECIFIED;
+ this.centerFreq0 = UNSPECIFIED;
+ this.centerFreq1 = UNSPECIFIED;
+ this.is80211McRTTResponder = false;
+ this.passpointNetwork = false;
}
/** {@hide} */
@@ -249,6 +313,31 @@
this.timestamp = tsf;
this.distanceCm = distCm;
this.distanceSdCm = distSdCm;
+ this.channelWidth = UNSPECIFIED;
+ this.centerFreq0 = UNSPECIFIED;
+ this.centerFreq1 = UNSPECIFIED;
+ this.is80211McRTTResponder = false;
+ this.passpointNetwork = false;
+ }
+
+ /** {@hide} */
+ public ScanResult(WifiSsid wifiSsid, String BSSID, String caps, int level, int frequency,
+ long tsf, int distCm, int distSdCm, int channelWidth, int centerFreq0, int centerFreq1,
+ boolean is80211McRTTResponder) {
+ this.wifiSsid = wifiSsid;
+ this.SSID = (wifiSsid != null) ? wifiSsid.toString() : WifiSsid.NONE;
+ this.BSSID = BSSID;
+ this.capabilities = caps;
+ this.level = level;
+ this.frequency = frequency;
+ this.timestamp = tsf;
+ this.distanceCm = distCm;
+ this.distanceSdCm = distSdCm;
+ this.channelWidth = channelWidth;
+ this.centerFreq0 = centerFreq0;
+ this.centerFreq1 = centerFreq1;
+ this.is80211McRTTResponder = is80211McRTTResponder;
+ this.passpointNetwork = false;
}
/** copy constructor {@hide} */
@@ -260,6 +349,10 @@
capabilities = source.capabilities;
level = source.level;
frequency = source.frequency;
+ channelWidth = source.channelWidth;
+ centerFreq0 = source.centerFreq0;
+ centerFreq1 = source.centerFreq1;
+ is80211McRTTResponder = source.is80211McRTTResponder;
timestamp = source.timestamp;
distanceCm = source.distanceCm;
distanceSdCm = source.distanceSdCm;
@@ -270,6 +363,9 @@
numUsage = source.numUsage;
numIpConfigFailures = source.numIpConfigFailures;
isAutoJoinCandidate = source.isAutoJoinCandidate;
+ passpointNetwork = source.passpointNetwork;
+ venueName = source.venueName;
+ operatorFriendlyName = source.operatorFriendlyName;
}
}
@@ -303,9 +399,15 @@
sb.append(", distanceSd: ").append((distanceSdCm != UNSPECIFIED ? distanceSdCm : "?")).
append("(cm)");
+ sb.append(", passpoint: ").append(passpointNetwork ? "yes" : "no");
if (autoJoinStatus != 0) {
sb.append(", status: ").append(autoJoinStatus);
}
+ sb.append(", ChannelBandwidth: ").append(channelWidth);
+ sb.append(", centerFreq0: ").append(centerFreq0);
+ sb.append(", centerFreq1: ").append(centerFreq1);
+ sb.append(", 80211mcResponder: ").append(is80211McRTTResponder?
+ "is supported":"is not supported");
return sb.toString();
}
@@ -329,6 +431,10 @@
dest.writeLong(timestamp);
dest.writeInt(distanceCm);
dest.writeInt(distanceSdCm);
+ dest.writeInt(channelWidth);
+ dest.writeInt(centerFreq0);
+ dest.writeInt(centerFreq1);
+ dest.writeInt(is80211McRTTResponder ? 1 : 0);
dest.writeLong(seen);
dest.writeInt(autoJoinStatus);
dest.writeInt(untrusted ? 1 : 0);
@@ -336,6 +442,10 @@
dest.writeInt(numUsage);
dest.writeInt(numIpConfigFailures);
dest.writeInt(isAutoJoinCandidate);
+ dest.writeInt(passpointNetwork ? 1 : 0);
+ dest.writeString(venueName);
+ dest.writeString(operatorFriendlyName);
+
if (informationElements != null) {
dest.writeInt(informationElements.length);
for (int i = 0; i < informationElements.length; i++) {
@@ -364,7 +474,11 @@
in.readInt(),
in.readLong(),
in.readInt(),
- in.readInt()
+ in.readInt(),
+ in.readInt(),
+ in.readInt(),
+ in.readInt(),
+ in.readInt() == 1
);
sr.seen = in.readLong();
sr.autoJoinStatus = in.readInt();
@@ -373,6 +487,9 @@
sr.numUsage = in.readInt();
sr.numIpConfigFailures = in.readInt();
sr.isAutoJoinCandidate = in.readInt();
+ sr.passpointNetwork = in.readInt() == 1;
+ sr.venueName = in.readString();
+ sr.operatorFriendlyName = in.readString();
int n = in.readInt();
if (n != 0) {
sr.informationElements = new InformationElement[n];
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 87db951..50beda7 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -19,19 +19,18 @@
import android.annotation.SystemApi;
import android.net.IpConfiguration;
import android.net.IpConfiguration.ProxySettings;
-import android.net.IpConfiguration.IpAssignment;
import android.net.ProxyInfo;
import android.net.StaticIpConfiguration;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
-import android.annotation.SystemApi;
import java.util.HashMap;
import java.util.BitSet;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
+import java.util.HashSet;
/**
* A class representing a configured Wi-Fi network, including the
@@ -59,6 +58,7 @@
public static final String updateIdentiferVarName = "update_identifier";
/** {@hide} */
public static final int INVALID_NETWORK_ID = -1;
+
/**
* Recognized key management schemes.
*/
@@ -233,17 +233,21 @@
* <code>XX:XX:XX:XX:XX:XX</code> where each <code>X</code> is a hex digit.
*/
public String BSSID;
+
/**
- * Fully qualified domain name (FQDN) of AAA server or RADIUS server
- * e.g. {@code "mail.example.com"}.
+ * The band which AP resides on
+ * 0-2G 1-5G
+ * By default, 2G is chosen
*/
- public String FQDN;
+ public int apBand = 0;
+
/**
- * Network access identifier (NAI) realm, for Passpoint credential.
- * e.g. {@code "myhost.example.com"}.
- * @hide
+ * The channel which AP resides on,currently, US only
+ * 2G 1-11
+ * 5G 36,40,44,48,149,153,157,161,165
+ * 0 - find a random available channel according to the apBand
*/
- public String naiRealm;
+ public int apChannel = 0;
/**
* Pre-shared key for use with WPA-PSK.
@@ -328,6 +332,21 @@
public WifiEnterpriseConfig enterpriseConfig;
/**
+ * Fully qualified domain name of a passpoint configuration
+ */
+ public String FQDN;
+
+ /**
+ * Service provider name, for Passpoint credential.
+ */
+ public String providerFriendlyName;
+
+ /**
+ * Roaming Consortium Id, for Passpoint credential.
+ */
+ public HashSet<Long> roamingConsortiumIds;
+
+ /**
* @hide
*/
private IpConfiguration mIpConfiguration;
@@ -862,7 +881,7 @@
SSID = null;
BSSID = null;
FQDN = null;
- naiRealm = null;
+ roamingConsortiumIds = new HashSet<Long>();
priority = 0;
hiddenSSID = false;
disableReason = DISABLED_UNKNOWN_REASON;
@@ -907,11 +926,38 @@
}
}
+ if (TextUtils.isEmpty(FQDN) == false) {
+ /* this is passpoint configuration; it must not have an SSID */
+ if (TextUtils.isEmpty(SSID) == false) {
+ return false;
+ }
+ /* this is passpoint configuration; it must have a providerFriendlyName */
+ if (TextUtils.isEmpty(providerFriendlyName)) {
+ return false;
+ }
+ /* this is passpoint configuration; it must have enterprise config */
+ if (enterpriseConfig == null
+ || enterpriseConfig.getEapMethod() == WifiEnterpriseConfig.Eap.NONE ) {
+ return false;
+ }
+ }
+
// TODO: Add more checks
return true;
}
/**
+ * Identify if this configuration represents a passpoint network
+ */
+ public boolean isPasspoint() {
+ return TextUtils.isEmpty(SSID)
+ && !TextUtils.isEmpty(FQDN)
+ && !TextUtils.isEmpty(providerFriendlyName)
+ && enterpriseConfig != null
+ && enterpriseConfig.getEapMethod() != WifiEnterpriseConfig.Eap.NONE;
+ }
+
+ /**
* Helper function, identify if a configuration is linked
* @hide
*/
@@ -1042,8 +1088,9 @@
sbuf.append("- DSBLE ");
}
sbuf.append("ID: ").append(this.networkId).append(" SSID: ").append(this.SSID).
+ append(" PROVIDER-NAME: ").append(this.providerFriendlyName).
append(" BSSID: ").append(this.BSSID).append(" FQDN: ").append(this.FQDN).
- append(" REALM: ").append(this.naiRealm).append(" PRIO: ").append(this.priority).
+ append(" PRIO: ").append(this.priority).
append('\n');
if (this.numConnectionFailures > 0) {
sbuf.append(" numConnectFailures ").append(this.numConnectionFailures).append("\n");
@@ -1383,6 +1430,8 @@
String key;
if (allowCached && mCachedConfigKey != null) {
key = mCachedConfigKey;
+ } else if (providerFriendlyName != null) {
+ key = FQDN + KeyMgmt.strings[KeyMgmt.WPA_EAP];
} else {
if (allowedKeyManagement.get(KeyMgmt.WPA_PSK)) {
key = SSID + KeyMgmt.strings[KeyMgmt.WPA_PSK];
@@ -1498,9 +1547,17 @@
SSID = source.SSID;
BSSID = source.BSSID;
FQDN = source.FQDN;
- naiRealm = source.naiRealm;
+ roamingConsortiumIds = new HashSet<Long>();
+ for (Long roamingConsortiumId : source.roamingConsortiumIds) {
+ roamingConsortiumIds.add(roamingConsortiumId);
+ }
+
+ providerFriendlyName = source.providerFriendlyName;
preSharedKey = source.preSharedKey;
+ apBand = source.apBand;
+ apChannel = source.apChannel;
+
wepKeys = new String[4];
for (int i = 0; i < wepKeys.length; i++) {
wepKeys[i] = source.wepKeys[i];
@@ -1593,9 +1650,15 @@
dest.writeInt(disableReason);
dest.writeString(SSID);
dest.writeString(BSSID);
+ dest.writeInt(apBand);
+ dest.writeInt(apChannel);
dest.writeString(autoJoinBSSID);
dest.writeString(FQDN);
- dest.writeString(naiRealm);
+ dest.writeString(providerFriendlyName);
+ dest.writeInt(roamingConsortiumIds.size());
+ for (Long roamingConsortiumId : roamingConsortiumIds) {
+ dest.writeLong(roamingConsortiumId);
+ }
dest.writeString(preSharedKey);
for (String wepKey : wepKeys) {
dest.writeString(wepKey);
@@ -1658,9 +1721,15 @@
config.disableReason = in.readInt();
config.SSID = in.readString();
config.BSSID = in.readString();
+ config.apBand = in.readInt();
+ config.apChannel = in.readInt();
config.autoJoinBSSID = in.readString();
config.FQDN = in.readString();
- config.naiRealm = in.readString();
+ config.providerFriendlyName = in.readString();
+ int numRoamingConsortiumIds = in.readInt();
+ for (int i = 0; i < numRoamingConsortiumIds; i++) {
+ config.roamingConsortiumIds.add(in.readLong());
+ }
config.preSharedKey = in.readString();
for (int i = 0; i < config.wepKeys.length; i++) {
config.wepKeys[i] = in.readString();
diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
index cf3cba3..36fc96b 100644
--- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
+++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
@@ -54,6 +54,8 @@
/** @hide */
public static final String SUBJECT_MATCH_KEY = "subject_match";
/** @hide */
+ public static final String ALTSUBJECT_MATCH_KEY = "altsubject_match";
+ /** @hide */
public static final String OPP_KEY_CACHING = "proactive_key_caching";
/**
* String representing the keystore OpenSSL ENGINE's ID.
@@ -93,6 +95,11 @@
public static final String ENGINE_ID_KEY = "engine_id";
/** @hide */
public static final String PRIVATE_KEY_ID_KEY = "key_id";
+ /** @hide */
+ public static final String REALM_KEY = "realm";
+ /** @hide */
+ public static final String PLMN_KEY = "plmn";
+
private HashMap<String, String> mFields = new HashMap<String, String>();
private X509Certificate mCaCert;
@@ -530,22 +537,74 @@
}
/**
- * Set subject match. This is the substring to be matched against the subject of the
- * authentication server certificate.
+ * Set subject match (deprecated). This is the substring to be matched against the subject of
+ * the authentication server certificate.
* @param subjectMatch substring to be matched
+ * @deprecated in favor of altSubjectMatch
*/
public void setSubjectMatch(String subjectMatch) {
setFieldValue(SUBJECT_MATCH_KEY, subjectMatch, "");
}
/**
- * Get subject match
+ * Get subject match (deprecated)
* @return the subject match string
+ * @deprecated in favor of altSubjectMatch
*/
public String getSubjectMatch() {
return getFieldValue(SUBJECT_MATCH_KEY, "");
}
+ /**
+ * Set alternate subject match. This is the substring to be matched against the
+ * alternate subject of the authentication server certificate.
+ * @param altSubjectMatch substring to be matched, for example
+ * DNS:server.example.com;EMAIL:server@example.com
+ */
+ public void setAltSubjectMatch(String altSubjectMatch) {
+ setFieldValue(ALTSUBJECT_MATCH_KEY, altSubjectMatch, "");
+ }
+
+ /**
+ * Get alternate subject match
+ * @return the alternate subject match string
+ */
+ public String getAltSubjectMatch() {
+ return getFieldValue(ALTSUBJECT_MATCH_KEY, "");
+ }
+
+ /**
+ * Set realm for passpoint credential
+ * @param realm the realm
+ */
+ public void setRealm(String realm) {
+ setFieldValue(REALM_KEY, realm, "");
+ }
+
+ /**
+ * Get realm for passpoint credential
+ * @return the realm
+ */
+ public String getRealm() {
+ return getFieldValue(REALM_KEY, "");
+ }
+
+ /**
+ * Set plmn for passpoint credential
+ * @param plmn the plmn value derived from mcc & mnc
+ */
+ public void setPlmn(String plmn) {
+ setFieldValue(PLMN_KEY, plmn, "");
+ }
+
+ /**
+ * Set plmn for passpoint credential
+ * @return the plmn
+ */
+ public String getPlmn() {
+ return getFieldValue(PLMN_KEY, "");
+ }
+
/** See {@link WifiConfiguration#getKeyIdForCredentials} @hide */
String getKeyId(WifiEnterpriseConfig current) {
String eap = mFields.get(EAP_KEY);
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 97e10dc..407624c 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -1238,6 +1238,21 @@
}
/**
+ * get the country code.
+ * @return the country code in ISO 3166 format.
+ *
+ * @hide
+ */
+ public String getCountryCode() {
+ try {
+ String country = mService.getCountryCode();
+ return(country);
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
+ /**
* Set the operational frequency band.
* @param band One of
* {@link #WIFI_FREQUENCY_BAND_AUTO},
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
index aaa2f98..fea934f 100644
--- a/wifi/java/android/net/wifi/WifiScanner.java
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -158,6 +158,11 @@
public int reportEvents;
/** defines number of bssids to cache from each scan */
public int numBssidsPerScan;
+ /**
+ * defines number of scans to cache; use it with REPORT_EVENT_AFTER_BUFFER_FULL
+ * to wake up at fixed interval
+ */
+ public int maxScansToCache;
/** Implement the Parcelable interface {@hide} */
public int describeContents() {
@@ -170,6 +175,7 @@
dest.writeInt(periodInMs);
dest.writeInt(reportEvents);
dest.writeInt(numBssidsPerScan);
+ dest.writeInt(maxScansToCache);
if (channels != null) {
dest.writeInt(channels.length);
@@ -194,6 +200,7 @@
settings.periodInMs = in.readInt();
settings.reportEvents = in.readInt();
settings.numBssidsPerScan = in.readInt();
+ settings.maxScansToCache = in.readInt();
int num_channels = in.readInt();
settings.channels = new ChannelSpec[num_channels];
for (int i = 0; i < num_channels; i++) {
@@ -215,8 +222,143 @@
}
- /** @hide */
+ /**
+ * all the information garnered from a single scan
+ */
+ public static class ScanData implements Parcelable {
+ /** scan identifier */
+ private int mId;
+ /** additional information about scan
+ * 0 => no special issues encountered in the scan
+ * non-zero => scan was truncated, so results may not be complete
+ */
+ private int mFlags;
+ /** all scan results discovered in this scan, sorted by timestamp in ascending order */
+ private ScanResult mResults[];
+
+ ScanData() {}
+
+ public ScanData(int id, int flags, ScanResult[] results) {
+ mId = id;
+ mFlags = flags;
+ mResults = results;
+ }
+
+ public ScanData(ScanData s) {
+ mId = s.mId;
+ mFlags = s.mFlags;
+ mResults = new ScanResult[s.mResults.length];
+ for (int i = 0; i < s.mResults.length; i++) {
+ ScanResult result = s.mResults[i];
+ WifiSsid wifiSsid = WifiSsid.createFromAsciiEncoded(result.SSID);
+ ScanResult newResult = new ScanResult(result);
+ newResult.wifiSsid = wifiSsid;
+ mResults[i] = newResult;
+ }
+ }
+
+ public int getId() {
+ return mId;
+ }
+
+ public int getFlags() {
+ return mFlags;
+ }
+
+ public ScanResult[] getResults() {
+ return mResults;
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ public int describeContents() {
+ return 0;
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ public void writeToParcel(Parcel dest, int flags) {
+ if (mResults != null) {
+ dest.writeInt(mId);
+ dest.writeInt(mFlags);
+ dest.writeInt(mResults.length);
+ for (int i = 0; i < mResults.length; i++) {
+ ScanResult result = mResults[i];
+ result.writeToParcel(dest, flags);
+ }
+ } else {
+ dest.writeInt(0);
+ }
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ public static final Creator<ScanData> CREATOR =
+ new Creator<ScanData>() {
+ public ScanData createFromParcel(Parcel in) {
+ int id = in.readInt();
+ int flags = in.readInt();
+ int n = in.readInt();
+ ScanResult results[] = new ScanResult[n];
+ for (int i = 0; i < n; i++) {
+ results[i] = ScanResult.CREATOR.createFromParcel(in);
+ }
+ return new ScanData(id, flags, results);
+ }
+
+ public ScanData[] newArray(int size) {
+ return new ScanData[size];
+ }
+ };
+ }
+
+ public static class ParcelableScanData implements Parcelable {
+
+ public ScanData mResults[];
+
+ public ParcelableScanData(ScanData[] results) {
+ mResults = results;
+ }
+
+ public ScanData[] getResults() {
+ return mResults;
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ public int describeContents() {
+ return 0;
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ public void writeToParcel(Parcel dest, int flags) {
+ if (mResults != null) {
+ dest.writeInt(mResults.length);
+ for (int i = 0; i < mResults.length; i++) {
+ ScanData result = mResults[i];
+ result.writeToParcel(dest, flags);
+ }
+ } else {
+ dest.writeInt(0);
+ }
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ public static final Creator<ParcelableScanData> CREATOR =
+ new Creator<ParcelableScanData>() {
+ public ParcelableScanData createFromParcel(Parcel in) {
+ int n = in.readInt();
+ ScanData results[] = new ScanData[n];
+ for (int i = 0; i < n; i++) {
+ results[i] = ScanData.CREATOR.createFromParcel(in);
+ }
+ return new ParcelableScanData(results);
+ }
+
+ public ParcelableScanData[] newArray(int size) {
+ return new ParcelableScanData[size];
+ }
+ };
+ }
+
public static class ParcelableScanResults implements Parcelable {
+
public ScanResult mResults[];
public ParcelableScanResults(ScanResult[] results) {
@@ -264,7 +406,8 @@
}
/**
- * interface to get scan events on; specify this on {@link #startBackgroundScan}
+ * interface to get scan events on; specify this on {@link #startBackgroundScan} or
+ * {@link #startScan}
*/
public interface ScanListener extends ActionListener {
/**
@@ -273,10 +416,15 @@
*/
public void onPeriodChanged(int periodInMs);
/**
- * reports results retrieved from background scan
+ * reports results retrieved from background scan and single shot scans
+ * @deprecated in favor of {@link #onResults(ScanData[])}
*/
public void onResults(ScanResult[] results);
/**
+ * reports results retrieved from background scan and single shot scans
+ */
+ public void onResults(ScanData[] results);
+ /**
* reports full scan result for each access point found in scan
*/
public void onFullResult(ScanResult fullScanResult);
@@ -303,13 +451,36 @@
sAsyncChannel.sendMessage(CMD_STOP_BACKGROUND_SCAN, 0, removeListener(listener));
}
/**
- * retrieves currently available scan results
+ * reports currently available scan results on appropriate listeners
*/
public ScanResult[] getScanResults() {
validateChannel();
Message reply = sAsyncChannel.sendMessageSynchronously(CMD_GET_SCAN_RESULTS, 0);
- ScanResult[] results = (ScanResult[]) reply.obj;
- return results;
+ // return reply.what == CMD_OP_SUCCEEDED;
+ return null;
+ }
+
+ /**
+ * starts a single scan and reports results asynchronously
+ * @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 startScan(ScanSettings settings, ScanListener listener) {
+ validateChannel();
+ sAsyncChannel.sendMessage(CMD_START_SINGLE_SCAN, 0, putListener(listener), settings);
+ }
+
+ /**
+ * stops an ongoing single shot scan; only useful after {@link #startScan} if onResults()
+ * hasn't been called on the listener, ignored otherwise
+ * @param listener
+ */
+ public void stopScan(ScanListener listener) {
+ validateChannel();
+ sAsyncChannel.sendMessage(CMD_STOP_SINGLE_SCAN, 0, removeListener(listener));
}
/** specifies information about an access point of interest */
@@ -468,6 +639,10 @@
* @param results list of scan results, one for each access point visible currently
*/
public void onFound(ScanResult[] results);
+ /** indicates that access points were missed by on going scans
+ * @param results list of scan results, for each access point that is not visible anymore
+ */
+ public void onLost(ScanResult[] results);
}
/** @hide */
@@ -593,6 +768,12 @@
public static final int CMD_PERIOD_CHANGED = BASE + 19;
/** @hide */
public static final int CMD_FULL_SCAN_RESULT = BASE + 20;
+ /** @hide */
+ public static final int CMD_START_SINGLE_SCAN = BASE + 21;
+ /** @hide */
+ public static final int CMD_STOP_SINGLE_SCAN = BASE + 22;
+ /** @hide */
+ public static final int CMD_SINGLE_SCAN_COMPLETED = BASE + 23;
private Context mContext;
private IWifiScanner mService;
@@ -800,7 +981,7 @@
break;
case CMD_SCAN_RESULT :
((ScanListener) listener).onResults(
- ((ParcelableScanResults) msg.obj).getResults());
+ ((ParcelableScanData) msg.obj).getResults());
return;
case CMD_FULL_SCAN_RESULT :
ScanResult result = (ScanResult) msg.obj;
@@ -813,6 +994,10 @@
((BssidListener) listener).onFound(
((ParcelableScanResults) msg.obj).getResults());
return;
+ case CMD_AP_LOST:
+ ((BssidListener) listener).onLost(
+ ((ParcelableScanResults) msg.obj).getResults());
+ return;
case CMD_WIFI_CHANGE_DETECTED:
((WifiChangeListener) listener).onChanging(
((ParcelableScanResults) msg.obj).getResults());
@@ -821,6 +1006,10 @@
((WifiChangeListener) listener).onQuiescence(
((ParcelableScanResults) msg.obj).getResults());
return;
+ case CMD_SINGLE_SCAN_COMPLETED:
+ Log.d(TAG, "removing listener for single scan");
+ removeListener(msg.arg2);
+ break;
default:
if (DBG) Log.d(TAG, "Ignoring message " + msg.what);
return;
diff --git a/wifi/java/android/net/wifi/passpoint/IWifiPasspointManager.aidl b/wifi/java/android/net/wifi/passpoint/IWifiPasspointManager.aidl
new file mode 100644
index 0000000..50bec33
--- /dev/null
+++ b/wifi/java/android/net/wifi/passpoint/IWifiPasspointManager.aidl
@@ -0,0 +1,45 @@
+/**
+ * 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.net.wifi.ScanResult;
+import android.net.wifi.passpoint.WifiPasspointPolicy;
+import android.net.wifi.passpoint.WifiPasspointCredential;
+import android.os.Messenger;
+
+/**
+ * Interface that allows controlling and querying Wifi Passpoint connectivity.
+ *
+ * {@hide}
+ */
+interface IWifiPasspointManager
+{
+ Messenger getMessenger();
+
+ int getPasspointState();
+
+ List<WifiPasspointPolicy> requestCredentialMatch(in List<ScanResult> requested);
+
+ List<WifiPasspointCredential> getCredentials();
+
+ boolean addCredential(in WifiPasspointCredential cred);
+
+ boolean updateCredential(in WifiPasspointCredential cred);
+
+ boolean removeCredential(in WifiPasspointCredential cred);
+}
+
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointCredential.aidl b/wifi/java/android/net/wifi/passpoint/WifiPasspointCredential.aidl
new file mode 100644
index 0000000..cfd3605
--- /dev/null
+++ b/wifi/java/android/net/wifi/passpoint/WifiPasspointCredential.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 WifiPasspointCredential;
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointCredential.java b/wifi/java/android/net/wifi/passpoint/WifiPasspointCredential.java
new file mode 100644
index 0000000..0a7230f
--- /dev/null
+++ b/wifi/java/android/net/wifi/passpoint/WifiPasspointCredential.java
@@ -0,0 +1,667 @@
+/*
+ * 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.net.wifi.WifiEnterpriseConfig;
+import android.os.Parcelable;
+import android.os.Parcel;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+
+
+/**
+ * A class representing a Wi-Fi Passpoint credential.
+ * @hide
+ */
+public class WifiPasspointCredential implements Parcelable {
+
+ private final static String TAG = "PasspointCredential";
+ private final static boolean DBG = true;
+
+ /** Wi-Fi nodes**/
+ private String mWifiSpFqdn;
+
+ /** PerProviderSubscription nodes **/
+ private String mCredentialName;
+
+ /** SubscriptionUpdate nodes **/
+ private String mSubscriptionUpdateInterval;
+ private String mSubscriptionUpdateMethod;
+ private String mSubscriptionUpdateRestriction;
+ private String mSubscriptionUpdateURI;
+ private String mSubscriptionUpdateUsername;
+ private String mSubscriptionUpdatePassword;
+
+ /** HomeSP nodes **/
+ private String mHomeSpFqdn;
+ private String mFriendlyName;
+ private Collection<WifiPasspointDmTree.HomeOIList> mHomeOIList;
+ private Collection<WifiPasspointDmTree.OtherHomePartners> mOtherHomePartnerList;
+
+ /** SubscriptionParameters nodes**/
+ private String mCreationDate;
+ private String mExpirationDate;
+
+ /** Credential nodes **/
+ private String mType;
+ private String mInnerMethod;
+ private String mCertType;
+ private String mCertSha256Fingerprint;
+ private String mUpdateIdentifier;
+ private String mUsername;
+ private String mPasswd;
+ private String mRealm;
+ private String mImsi;
+ private String mMcc;
+ private String mMnc;
+ private String mCaRootCert;
+ private String mClientCert;
+ private boolean mCheckAaaServerCertStatus;
+
+ /** Policy nodes **/
+ private String mPolicyUpdateUri;
+ private String mPolicyUpdateInterval;
+ private String mPolicyUpdateUsername;
+ private String mPolicyUpdatePassword;
+ private String mPolicyUpdateRestriction;
+ private String mPolicyUpdateMethod;
+ private Collection<WifiPasspointDmTree.PreferredRoamingPartnerList> mPreferredRoamingPartnerList;
+ private Collection<WifiPasspointDmTree.MinBackhaulThresholdNetwork> mMinBackhaulThresholdNetwork;
+ private Collection<WifiPasspointDmTree.SPExclusionList> mSpExclusionList;
+ private Collection<WifiPasspointDmTree.RequiredProtoPortTuple> mRequiredProtoPortTuple;
+ private String mMaxBssLoad;
+
+ /** CrednetialPriority node **/
+ private int mCrednetialPriority;
+
+ /** AAAServerTrustRoot nodes **/
+ private String mAaaCertUrl;
+ private String mAaaSha256Fingerprint;
+
+ /** Others **/
+ private boolean mIsMachineRemediation;
+ private boolean mUserPreferred = false;
+ private String mWifiTreePath;
+ private WifiEnterpriseConfig mEnterpriseConfig;
+
+ /** @hide */
+ public WifiPasspointCredential() {}
+
+ /**
+ * Constructor
+ * @param realm Realm of the passpoint credential
+ * @param fqdn Fully qualified domain name (FQDN) of the credential
+ * @param config Enterprise config, must be either EAP-TLS or EAP-TTLS
+ * @see WifiEnterpriseConfig
+ */
+ public WifiPasspointCredential(String realm, String fqdn, WifiEnterpriseConfig config) {
+ mRealm = realm;
+ switch (config.getEapMethod()) {
+ case WifiEnterpriseConfig.Eap.TLS:
+ case WifiEnterpriseConfig.Eap.TTLS:
+ mEnterpriseConfig = new WifiEnterpriseConfig(config);
+ break;
+ default:
+ // ignore
+ }
+ }
+
+ /** @hide */
+ public WifiPasspointCredential(String type,
+ String caroot,
+ String clientcert,
+ String mcc,
+ String mnc,
+ WifiPasspointDmTree.SpFqdn sp,
+ WifiPasspointDmTree.CredentialInfo credinfo) {
+
+ if (credinfo == null) {
+ return;
+ }
+
+ mType = type;
+ mCaRootCert = caroot;
+ mClientCert = clientcert;
+
+ mWifiSpFqdn = sp.nodeName;
+ mUpdateIdentifier = sp.perProviderSubscription.UpdateIdentifier;
+
+ mCredentialName = credinfo.nodeName;
+ mOtherHomePartnerList = credinfo.homeSP.otherHomePartners.values();
+
+ Set set = credinfo.aAAServerTrustRoot.entrySet();
+ Iterator i = set.iterator();
+ if (i.hasNext()) {
+ Map.Entry entry3 = (Map.Entry) i.next();
+ WifiPasspointDmTree.AAAServerTrustRoot aaa = (WifiPasspointDmTree.AAAServerTrustRoot) entry3.getValue();
+ mAaaCertUrl = aaa.CertURL;
+ mAaaSha256Fingerprint = aaa.CertSHA256Fingerprint;
+ }
+
+ mCertType = credinfo.credential.digitalCertificate.CertificateType;
+ mCertSha256Fingerprint = credinfo.credential.digitalCertificate.CertSHA256Fingerprint;
+ mUsername = credinfo.credential.usernamePassword.Username;
+ mPasswd = credinfo.credential.usernamePassword.Password;
+ mIsMachineRemediation = credinfo.credential.usernamePassword.MachineManaged;
+ mInnerMethod = credinfo.credential.usernamePassword.eAPMethod.InnerMethod;
+ mImsi = credinfo.credential.sim.IMSI;
+ mMcc = mcc;
+ mMnc = mnc;
+ mCreationDate = credinfo.credential.CreationDate;
+ mExpirationDate = credinfo.credential.ExpirationDate;
+ mRealm = credinfo.credential.Realm;
+
+ if (credinfo.credentialPriority == null) {
+ mCrednetialPriority = 128;
+ } else {
+ mCrednetialPriority = Integer.parseInt(credinfo.credentialPriority);
+ }
+
+ mHomeSpFqdn = credinfo.homeSP.FQDN;
+
+ mSubscriptionUpdateInterval = credinfo.subscriptionUpdate.UpdateInterval;
+ mSubscriptionUpdateMethod = credinfo.subscriptionUpdate.UpdateMethod;
+ mSubscriptionUpdateRestriction = credinfo.subscriptionUpdate.Restriction;
+ mSubscriptionUpdateURI = credinfo.subscriptionUpdate.URI;
+ mSubscriptionUpdateUsername = credinfo.subscriptionUpdate.usernamePassword.Username;
+ mSubscriptionUpdatePassword = credinfo.subscriptionUpdate.usernamePassword.Password;
+
+ mPolicyUpdateUri = credinfo.policy.policyUpdate.URI;
+ mPolicyUpdateInterval = credinfo.policy.policyUpdate.UpdateInterval;
+ mPolicyUpdateUsername = credinfo.policy.policyUpdate.usernamePassword.Username;
+ mPolicyUpdatePassword = credinfo.policy.policyUpdate.usernamePassword.Password;
+ mPolicyUpdateRestriction = credinfo.policy.policyUpdate.Restriction;
+ mPolicyUpdateMethod = credinfo.policy.policyUpdate.UpdateMethod;
+ mPreferredRoamingPartnerList = credinfo.policy.preferredRoamingPartnerList.values();
+ mMinBackhaulThresholdNetwork = credinfo.policy.minBackhaulThreshold.values();
+ mRequiredProtoPortTuple = credinfo.policy.requiredProtoPortTuple.values();
+ mMaxBssLoad = credinfo.policy.maximumBSSLoadValue;
+ mSpExclusionList = credinfo.policy.sPExclusionList.values();
+
+ mHomeOIList = credinfo.homeSP.homeOIList.values();
+ mFriendlyName = credinfo.homeSP.FriendlyName;
+ mCheckAaaServerCertStatus = credinfo.credential.CheckAAAServerCertStatus;
+ }
+
+ /** @hide */
+ public String getUpdateIdentifier() {
+ return mUpdateIdentifier;
+ }
+
+ /** @hide */
+ public String getUpdateMethod() {
+ return mSubscriptionUpdateMethod;
+ }
+
+ /** @hide */
+ public void setUpdateMethod(String method) {
+ mSubscriptionUpdateMethod = method;
+ }
+
+ /** @hide */
+ public String getWifiSpFqdn() {
+ return mWifiSpFqdn;
+ }
+
+ /** @hide */
+ public String getCredName() {
+ return mCredentialName;
+ }
+
+ /** @hide */
+ public String getType() {
+ return mType;
+ }
+
+ /**
+ * Get enterprise config of this Passpoint credential.
+ * @return Enterprise config
+ * @see WifiEnterpriseConfig
+ */
+ public WifiEnterpriseConfig getEnterpriseConfig() {
+ return new WifiEnterpriseConfig(mEnterpriseConfig);
+ }
+
+ /**
+ * Set enterprise config of this Passpoint credential.
+ * @param config Enterprise config, must be either EAP-TLS or EAP-TTLS
+ * @see WifiEnterpriseConfig
+ */
+ public void setEnterpriseConfig(WifiEnterpriseConfig config) {
+ // TODO
+ }
+
+ /** @hide */
+ public String getCertType() {
+ return mCertType;
+ }
+
+ /** @hide */
+ public String getCertSha256Fingerprint() {
+ return mCertSha256Fingerprint;
+ }
+
+ /** @hide */
+ public String getUserName() {
+ return mUsername;
+ }
+
+ /** @hide */
+ public String getPassword() {
+ // TODO: guarded by connectivity internal
+ return mPasswd;
+ }
+
+ /** @hide */
+ public String getImsi() {
+ return mImsi;
+ }
+
+ /** @hide */
+ public String getMcc() {
+ return mMcc;
+ }
+
+ /** @hide */
+ public String getMnc() {
+ return mMnc;
+ }
+
+ /** @hide */
+ public String getCaRootCertPath() {
+ return mCaRootCert;
+ }
+
+ /** @hide */
+ public String getClientCertPath() {
+ return mClientCert;
+ }
+
+ /**
+ * Get the realm of this Passpoint credential.
+ * @return Realm
+ */
+ public String getRealm() {
+ return mRealm;
+ }
+
+ /**
+ * Set the ream of this Passpoint credential.
+ * @param realm Realm
+ */
+ public void setRealm(String realm) {
+ mRealm = realm;
+ }
+
+ /** @hide */
+ public int getPriority() {
+ if (mUserPreferred) {
+ return 0;
+ }
+
+ return mCrednetialPriority;
+ }
+
+ /**
+ * Get the fully qualified domain name (FQDN) of this Passpoint credential.
+ * @return FQDN
+ */
+ public String getHomeSpFqdn() {
+ return mHomeSpFqdn;
+ }
+
+ /**
+ * Set the fully qualified domain name (FQDN) of this Passpoint credential.
+ * @param fqdn FQDN
+ */
+ public void setHomeFqdn(String fqdn) {
+ mHomeSpFqdn = fqdn;
+ }
+
+
+ /** @hide */
+ public Collection<WifiPasspointDmTree.OtherHomePartners> getOtherHomePartnerList() {
+ return mOtherHomePartnerList;
+ }
+
+ /** @hide */
+ public String getSubscriptionUpdateUsername() {
+ return mSubscriptionUpdateUsername;
+ }
+
+ /** @hide */
+ public String getSubscriptionUpdatePassword() {
+ return mSubscriptionUpdatePassword;
+ }
+
+ /** @hide */
+ public String getPolicyUpdateUri() {
+ return mPolicyUpdateUri;
+ }
+
+ /** @hide */
+ public String getPolicyUpdateInterval() {
+ return mPolicyUpdateInterval;
+ }
+
+ /** @hide */
+ public String getPolicyUpdateUsername() {
+ return mPolicyUpdateUsername;
+ }
+
+ /** @hide */
+ public String getPolicyUpdatePassword() {
+ return mPolicyUpdatePassword;
+ }
+
+ /** @hide */
+ public String getPolicyUpdateRestriction() {
+ return mPolicyUpdateRestriction;
+ }
+
+ /** @hide */
+ public String getPolicyUpdateMethod() {
+ return mPolicyUpdateMethod;
+ }
+
+ /** @hide */
+ public String getCreationDate() {
+ return mCreationDate;
+ }
+
+ /** @hide */
+ public String getExpirationDate() {
+ return mExpirationDate;
+ }
+
+ /** @hide */
+ public void setExpirationDate(String expirationdate) {
+ mExpirationDate = expirationdate;
+ }
+
+ /** @hide */
+ public Collection<WifiPasspointDmTree.PreferredRoamingPartnerList> getPreferredRoamingPartnerList() {
+ return mPreferredRoamingPartnerList;
+ }
+
+ /** @hide */
+ public Collection<WifiPasspointDmTree.HomeOIList> getHomeOiList() {
+ return mHomeOIList;
+ }
+
+ /** @hide */
+ public Collection<WifiPasspointDmTree.MinBackhaulThresholdNetwork> getBackhaulThresholdList() {
+ return mMinBackhaulThresholdNetwork;
+ }
+
+ /** @hide */
+ public Collection<WifiPasspointDmTree.RequiredProtoPortTuple> getRequiredProtoPortList() {
+ return mRequiredProtoPortTuple;
+ }
+
+ /** @hide */
+ public Collection<WifiPasspointDmTree.SPExclusionList> getSPExclusionList() {
+ return mSpExclusionList;
+ }
+
+ /** @hide */
+ public boolean getIsMachineRemediation() {
+ return mIsMachineRemediation;
+ }
+
+ /** @hide */
+ public String getAaaCertUrl() {
+ return mAaaCertUrl;
+ }
+
+ /** @hide */
+ public String getAaaSha256Fingerprint() {
+ return mAaaSha256Fingerprint;
+ }
+
+ /** @hide */
+ public String getSubscriptionUpdateRestriction() {
+ return mSubscriptionUpdateRestriction;
+ }
+
+ /** @hide */
+ public String getSubscriptionUpdateURI() {
+ return mSubscriptionUpdateURI;
+ }
+
+ /** @hide */
+ public String getSubscriptionUpdateInterval() {
+ return mSubscriptionUpdateInterval;
+ }
+
+ /** @hide */
+ public String getFriendlyName() {
+ return mFriendlyName;
+ }
+
+ /** @hide */
+ public String getMaxBssLoad() {
+ return mMaxBssLoad;
+ }
+
+ /** @hide */
+ public boolean getUserPreference() {
+ return mUserPreferred;
+ }
+
+ /** @hide */
+ public boolean getCheckAaaServerCertStatus() {
+ return mCheckAaaServerCertStatus;
+ }
+
+ /** @hide */
+ public void setUserPreference(boolean value) {
+ mUserPreferred = value;
+ }
+
+ @Override
+ /** @hide */
+ public boolean equals(Object obj) {
+ boolean result = false;
+ if (obj instanceof WifiPasspointCredential) {
+ final WifiPasspointCredential other = (WifiPasspointCredential) obj;
+ if (this.mType.equals(other.mType)) {
+ if (this.mType.equals("TTLS")) {
+ result = this.mUsername.equals(other.mUsername) &&
+ this.mPasswd.equals(other.mPasswd) &&
+ this.mRealm.equals(other.mRealm) &&
+ this.mHomeSpFqdn.equals(other.mHomeSpFqdn);
+ }
+ if (this.mType.equals("TLS")) {
+ result = this.mRealm.equals(other.mRealm) &&
+ this.mHomeSpFqdn.equals(other.mHomeSpFqdn) &&
+ this.mClientCert.equals(other.mClientCert);
+ }
+ if (this.mType.equals("SIM")) {
+ result = this.mMcc.equals(other.mMcc) &&
+ this.mMnc.equals(other.mMnc) &&
+ this.mImsi.equals(other.mImsi) &&
+ this.mHomeSpFqdn.equals(other.mHomeSpFqdn);
+ }
+ }
+ }
+ return result;
+ }
+
+ @Override
+ /** @hide */
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ String none = "<none>";
+
+ if (!DBG) {
+ sb.append(none);
+ } else {
+ sb.append(", UpdateIdentifier: ")
+ .append(mUpdateIdentifier == null ? none : mUpdateIdentifier)
+ .append(", SubscriptionUpdateMethod: ")
+ .append(mSubscriptionUpdateMethod == null ? none : mSubscriptionUpdateMethod)
+ .append(", Type: ").append(mType == null ? none : mType)
+ .append(", Username: ").append(mUsername == null ? none : mUsername)
+ .append(", Passwd: ").append(mPasswd == null ? none : mPasswd)
+ .append(", SubDMAccUsername: ")
+ .append(mSubscriptionUpdateUsername == null ? none : mSubscriptionUpdateUsername)
+ .append(", SubDMAccPassword: ")
+ .append(mSubscriptionUpdatePassword == null ? none : mSubscriptionUpdatePassword)
+ .append(", PolDMAccUsername: ")
+ .append(mPolicyUpdateUsername == null ? none : mPolicyUpdateUsername)
+ .append(", PolDMAccPassword: ")
+ .append(mPolicyUpdatePassword == null ? none : mPolicyUpdatePassword)
+ .append(", Imsi: ").append(mImsi == null ? none : mImsi)
+ .append(", Mcc: ").append(mMcc == null ? none : mMcc)
+ .append(", Mnc: ").append(mMnc == null ? none : mMnc)
+ .append(", CaRootCert: ").append(mCaRootCert == null ? none : mCaRootCert)
+ .append(", Realm: ").append(mRealm == null ? none : mRealm)
+ .append(", Priority: ").append(mCrednetialPriority)
+ .append(", Fqdn: ").append(mHomeSpFqdn == null ? none : mHomeSpFqdn)
+ .append(", Otherhomepartners: ")
+ .append(mOtherHomePartnerList == null ? none : mOtherHomePartnerList)
+ .append(", ExpirationDate: ")
+ .append(mExpirationDate == null ? none : mExpirationDate)
+ .append(", MaxBssLoad: ").append(mMaxBssLoad == null ? none : mMaxBssLoad)
+ .append(", SPExclusionList: ").append(mSpExclusionList);
+
+ if (mPreferredRoamingPartnerList != null) {
+ sb.append("PreferredRoamingPartnerList:");
+ for (WifiPasspointDmTree.PreferredRoamingPartnerList prpListItem : mPreferredRoamingPartnerList) {
+ sb.append("[fqdnmatch:").append(prpListItem.FQDN_Match).
+ append(", priority:").append(prpListItem.Priority).
+ append(", country:").append(prpListItem.Country).append("]");
+ }
+ }
+
+ if (mHomeOIList != null) {
+ sb.append("HomeOIList:");
+ for (WifiPasspointDmTree.HomeOIList HomeOIListItem : mHomeOIList) {
+ sb.append("[HomeOI:").append(HomeOIListItem.HomeOI).
+ append(", HomeOIRequired:").append(HomeOIListItem.HomeOIRequired).
+ append("]");
+ }
+ }
+
+ if (mMinBackhaulThresholdNetwork != null) {
+ sb.append("BackHaulThreshold:");
+ for (WifiPasspointDmTree.MinBackhaulThresholdNetwork BhtListItem : mMinBackhaulThresholdNetwork) {
+ sb.append("[networkType:").append(BhtListItem.NetworkType).
+ append(", dlBandwidth:").append(BhtListItem.DLBandwidth).
+ append(", ulBandwidth:").append(BhtListItem.ULBandwidth).
+ append("]");
+ }
+ }
+
+ if (mRequiredProtoPortTuple != null) {
+ sb.append("WifiMORequiredProtoPortTupleList:");
+ for (WifiPasspointDmTree.RequiredProtoPortTuple RpptListItem : mRequiredProtoPortTuple) {
+ sb.append("[IPProtocol:").append(RpptListItem.IPProtocol).
+ append(", PortNumber:").append(RpptListItem.PortNumber).
+ append("]");
+ }
+ }
+ }
+ return sb.toString();
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ public int describeContents() {
+ return 0;
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mWifiSpFqdn);
+ dest.writeString(mCredentialName);
+ dest.writeString(mType);
+ dest.writeInt(mCrednetialPriority);
+ dest.writeString(mHomeSpFqdn);
+ dest.writeString(mRealm);
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ public void readFromParcel(Parcel in) {
+ mWifiSpFqdn = in.readString();
+ mCredentialName = in.readString();
+ mType = in.readString();
+ mCrednetialPriority = in.readInt();
+ mHomeSpFqdn = in.readString();
+ mRealm = in.readString();
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ public static final Creator<WifiPasspointCredential> CREATOR =
+ new Creator<WifiPasspointCredential>() {
+ public WifiPasspointCredential createFromParcel(Parcel in) {
+ WifiPasspointCredential pc = new WifiPasspointCredential();
+ pc.mWifiSpFqdn = in.readString();
+ pc.mCredentialName = in.readString();
+ pc.mType = in.readString();
+ pc.mCrednetialPriority = in.readInt();
+ pc.mHomeSpFqdn = in.readString();
+ pc.mRealm = in.readString();
+ return pc;
+ }
+
+ public WifiPasspointCredential[] newArray(int size) {
+ return new WifiPasspointCredential[size];
+ }
+ };
+
+ /** @hide */
+ public int compareTo(WifiPasspointCredential another) {
+
+ //The smaller the higher
+ if (mCrednetialPriority < another.mCrednetialPriority) {
+ return -1;
+ } else if (mCrednetialPriority == another.mCrednetialPriority) {
+ return this.mType.compareTo(another.mType);
+ } else {
+ return 1;
+ }
+ }
+
+ @Override
+ /** @hide */
+ public int hashCode() {
+ int hash = 208;
+ if (mType != null) {
+ hash += mType.hashCode();
+ }
+ if (mRealm != null) {
+ hash += mRealm.hashCode();
+ }
+ if (mHomeSpFqdn != null) {
+ hash += mHomeSpFqdn.hashCode();
+ }
+ if (mUsername != null) {
+ hash += mUsername.hashCode();
+ }
+ if (mPasswd != null) {
+ hash += mPasswd.hashCode();
+ }
+
+ return hash;
+ }
+}
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointDmTree.aidl b/wifi/java/android/net/wifi/passpoint/WifiPasspointDmTree.aidl
new file mode 100644
index 0000000..6a88b2e
--- /dev/null
+++ b/wifi/java/android/net/wifi/passpoint/WifiPasspointDmTree.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 WifiPasspointDmTree;
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointDmTree.java b/wifi/java/android/net/wifi/passpoint/WifiPasspointDmTree.java
new file mode 100644
index 0000000..bbf5fc6
--- /dev/null
+++ b/wifi/java/android/net/wifi/passpoint/WifiPasspointDmTree.java
@@ -0,0 +1,1377 @@
+/*
+ * 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;
+import android.util.Log;
+
+import java.util.HashMap;
+
+/**
+ * Required Mobile Device Management Tree Structure
+ *
+ * +----------+
+ * | ./(Root) |
+ * +----+-----+
+ * |
+ * +---------+ | +---------+ +---------+
+ * | DevInfo |-----------+---------| Wi-Fi |--|SP FQDN* |
+ * +---------+ | +---------+ +---------+
+ * +---------+ | |
+ * |DevDetail|-----------+ +-----------------------+
+ * +---------+ |PerproviderSubscription|--<X>+
+ * +-----------------------+
+ *
+ * This class contains all nodes start from Wi-Fi
+ * @hide
+ **/
+public class WifiPasspointDmTree implements Parcelable {
+ private final static String TAG = "WifiTree";
+ public int PpsMoId;//plugfest used only
+ public HashMap<String, SpFqdn> spFqdn = new HashMap<String, SpFqdn>();//Maps.newHashMap();
+
+ public SpFqdn createSpFqdn(String name) {
+ SpFqdn obj = new SpFqdn(name);
+ spFqdn.put(name, obj);
+ return obj;
+ }
+
+ public static class SpFqdn implements Parcelable {
+ public String nodeName;
+ public PerProviderSubscription perProviderSubscription = new PerProviderSubscription();
+
+ public SpFqdn(String name) {
+ nodeName = name;
+ }
+
+ public SpFqdn() {
+ }
+
+ public SpFqdn(Parcel in) {
+ readFromParcel(in);
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(nodeName);
+ out.writeParcelable(perProviderSubscription, flags);
+ }
+
+ public void readFromParcel(Parcel in) {
+ if (in == null) {
+ //log here
+ } else {
+ nodeName = in.readString();
+ perProviderSubscription = in.readParcelable(PerProviderSubscription.class
+ .getClassLoader());
+ }
+ }
+
+ public static final Parcelable.Creator<SpFqdn> CREATOR = new Parcelable.Creator<SpFqdn>() {
+ public SpFqdn createFromParcel(Parcel in) {
+ return new SpFqdn(in);
+ }
+
+ public SpFqdn[] newArray(int size) {
+ return new SpFqdn[size];
+ }
+ };
+ }
+
+ /**
+ * PerProviderSubscription
+ **/
+ public static class PerProviderSubscription implements Parcelable {
+ /**
+ * PerProviderSubscription/UpdateIdentifier
+ **/
+ public String UpdateIdentifier;
+ public HashMap<String, CredentialInfo> credentialInfo = new HashMap<String, CredentialInfo>();
+
+ public CredentialInfo createCredentialInfo(String name) {
+ CredentialInfo obj = new CredentialInfo(name);
+ credentialInfo.put(name, obj);
+ return obj;
+ }
+
+ public PerProviderSubscription() {
+ }
+
+ public PerProviderSubscription(Parcel in) {
+ readFromParcel(in);
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(UpdateIdentifier);
+ out.writeMap(credentialInfo);
+ }
+
+ public void readFromParcel(Parcel in) {
+ if (in == null) {
+ //log here
+ } else {
+ UpdateIdentifier = in.readString();
+ in.readMap(credentialInfo, CredentialInfo.class.getClassLoader());
+ }
+ }
+
+ public static final Parcelable.Creator<PerProviderSubscription> CREATOR = new Parcelable.Creator<PerProviderSubscription>() {
+ public PerProviderSubscription createFromParcel(Parcel in) {
+ return new PerProviderSubscription(in);
+ }
+
+ public PerProviderSubscription[] newArray(int size) {
+ return new PerProviderSubscription[size];
+ }
+ };
+
+ }
+
+ /**
+ * PerProviderSubscription/<X+>
+ * This interior node contains the Home SP information, subscription policy, management and credential information.
+ **/
+ public static class CredentialInfo implements Parcelable {
+ public String nodeName;
+ public Policy policy = new Policy();
+ public String credentialPriority;
+ public HashMap<String, AAAServerTrustRoot> aAAServerTrustRoot = new HashMap<String, AAAServerTrustRoot>();
+ public SubscriptionUpdate subscriptionUpdate = new SubscriptionUpdate();
+ public HomeSP homeSP = new HomeSP();
+ public SubscriptionParameters subscriptionParameters = new SubscriptionParameters();
+ public Credential credential = new Credential();
+ public Extension extension = new Extension();
+
+ public CredentialInfo(String nn) {
+ nodeName = nn;
+ }
+
+ public AAAServerTrustRoot createAAAServerTrustRoot(String name, String url, String fp) {
+ AAAServerTrustRoot obj = new AAAServerTrustRoot(name, url, fp);
+ aAAServerTrustRoot.put(name, obj);
+ return obj;
+ }
+
+ public CredentialInfo() {
+ }
+
+ public CredentialInfo(Parcel in) {
+ readFromParcel(in);
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(nodeName);
+ out.writeParcelable(policy, flags);
+ out.writeString(credentialPriority);
+ out.writeMap(aAAServerTrustRoot);
+ out.writeParcelable(subscriptionUpdate, flags);
+ out.writeParcelable(homeSP, flags);
+ out.writeParcelable(subscriptionParameters, flags);
+ out.writeParcelable(credential, flags);
+ //out.writeParcelable(extension, flags);
+ }
+
+ public void readFromParcel(Parcel in) {
+ if (in == null) {
+ //log here
+ } else {
+ nodeName = in.readString();
+ policy = in.readParcelable(Policy.class.getClassLoader());
+ credentialPriority = in.readString();
+ in.readMap(aAAServerTrustRoot, AAAServerTrustRoot.class.getClassLoader());
+ subscriptionUpdate = in.readParcelable(SubscriptionUpdate.class.getClassLoader());
+ homeSP = in.readParcelable(HomeSP.class.getClassLoader());
+ subscriptionParameters = in.readParcelable(SubscriptionParameters.class
+ .getClassLoader());
+ credential = in.readParcelable(Credential.class.getClassLoader());
+ //extension = in.readParcelable(Extension.class.getClassLoader());
+ }
+ }
+
+ public static final Parcelable.Creator<CredentialInfo> CREATOR = new Parcelable.Creator<CredentialInfo>() {
+ public CredentialInfo createFromParcel(Parcel in) {
+ return new CredentialInfo(in);
+ }
+
+ public CredentialInfo[] newArray(int size) {
+ return new CredentialInfo[size];
+ }
+ };
+
+ }
+
+ /**
+ * PerProviderSubscription/<X+>/Policy
+ **/
+ public static class Policy implements Parcelable {
+ public HashMap<String, PreferredRoamingPartnerList> preferredRoamingPartnerList = new HashMap<String, PreferredRoamingPartnerList>();
+ public HashMap<String, MinBackhaulThresholdNetwork> minBackhaulThreshold = new HashMap<String, MinBackhaulThresholdNetwork>();
+ public PolicyUpdate policyUpdate = new PolicyUpdate();
+ public HashMap<String, SPExclusionList> sPExclusionList = new HashMap<String, SPExclusionList>();
+ public HashMap<String, RequiredProtoPortTuple> requiredProtoPortTuple = new HashMap<String, RequiredProtoPortTuple>();
+ public String maximumBSSLoadValue;
+
+ public PreferredRoamingPartnerList createPreferredRoamingPartnerList(String name,
+ String fqdn, String priority, String country) {
+ PreferredRoamingPartnerList obj = new PreferredRoamingPartnerList(name, fqdn, priority,
+ country);
+ preferredRoamingPartnerList.put(name, obj);
+ return obj;
+ }
+
+ public MinBackhaulThresholdNetwork createMinBackhaulThreshold(String name, String type,
+ String dl, String ul) {
+ MinBackhaulThresholdNetwork obj = new MinBackhaulThresholdNetwork(name, type, dl, ul);
+ minBackhaulThreshold.put(name, obj);
+ return obj;
+ }
+
+ public SPExclusionList createSPExclusionList(String name, String ssid) {
+ SPExclusionList obj = new SPExclusionList(name, ssid);
+ sPExclusionList.put(name, obj);
+ return obj;
+ }
+
+ public RequiredProtoPortTuple createRequiredProtoPortTuple(String name, String proto,
+ String port) {
+ RequiredProtoPortTuple obj = new RequiredProtoPortTuple(name, proto, port);
+ requiredProtoPortTuple.put(name, obj);
+ return obj;
+ }
+
+ public Policy() {
+ }
+
+ public Policy(Parcel in) {
+ readFromParcel(in);
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeMap(preferredRoamingPartnerList);
+ out.writeMap(minBackhaulThreshold);
+ out.writeParcelable(policyUpdate, flags);
+ out.writeMap(sPExclusionList);
+ out.writeMap(requiredProtoPortTuple);
+ out.writeString(maximumBSSLoadValue);
+ }
+
+ public void readFromParcel(Parcel in) {
+ if (in == null) {
+ //log here
+ } else {
+ in.readMap(preferredRoamingPartnerList,
+ PreferredRoamingPartnerList.class.getClassLoader());
+ in.readMap(minBackhaulThreshold, MinBackhaulThresholdNetwork.class.getClassLoader());
+ policyUpdate = in.readParcelable(PolicyUpdate.class.getClassLoader());
+ in.readMap(sPExclusionList, SPExclusionList.class.getClassLoader());
+ in.readMap(requiredProtoPortTuple, RequiredProtoPortTuple.class.getClassLoader());
+ maximumBSSLoadValue = in.readString();
+
+ }
+ }
+
+ public static final Parcelable.Creator<Policy> CREATOR = new Parcelable.Creator<Policy>() {
+ public Policy createFromParcel(Parcel in) {
+ return new Policy(in);
+ }
+
+ public Policy[] newArray(int size) {
+ return new Policy[size];
+ }
+ };
+
+ }
+
+ /**
+ * PerProviderSubscription/<X+>/Policy/PreferredRoamingPartnerList/<X+>
+ **/
+ public static class PreferredRoamingPartnerList implements Parcelable {
+ public String nodeName;
+ public String FQDN_Match; //maximum 255 + ",includeSubdomains", equals 273
+ public String Priority;
+ public String Country; // maximum 600 octets
+
+ public PreferredRoamingPartnerList(String nn, String f, String p, String c) {
+ nodeName = nn;
+ FQDN_Match = f;
+ Priority = p;
+ Country = c;
+ }
+
+ public PreferredRoamingPartnerList() {
+ }
+
+ public PreferredRoamingPartnerList(Parcel in) {
+ readFromParcel(in);
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(nodeName);
+ out.writeString(FQDN_Match);
+ out.writeString(Priority);
+ out.writeString(Country);
+ }
+
+ public void readFromParcel(Parcel in) {
+ if (in == null) {
+ //log here
+ } else {
+ nodeName = in.readString();
+ FQDN_Match = in.readString();
+ Priority = in.readString();
+ Country = in.readString();
+ }
+ }
+
+ public static final Parcelable.Creator<PreferredRoamingPartnerList> CREATOR = new Parcelable.Creator<PreferredRoamingPartnerList>() {
+ public PreferredRoamingPartnerList createFromParcel(Parcel in) {
+ return new PreferredRoamingPartnerList(in);
+ }
+
+ public PreferredRoamingPartnerList[] newArray(int size) {
+ return new PreferredRoamingPartnerList[size];
+ }
+ };
+ }
+
+ /**
+ * PerProviderSubscription/<X+>/Policy/MinBackhaulThreshold
+ **/
+ public static class MinBackhaulThresholdNetwork implements Parcelable {
+ public String nodeName;
+ public String NetworkType;
+ public String DLBandwidth;
+ public String ULBandwidth;
+
+ public MinBackhaulThresholdNetwork(String nn, String nt, String d, String u) {
+ nodeName = nn;
+ NetworkType = nt;
+ DLBandwidth = d;
+ ULBandwidth = u;
+ }
+
+ public MinBackhaulThresholdNetwork() {
+ }
+
+ public MinBackhaulThresholdNetwork(Parcel in) {
+ readFromParcel(in);
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(nodeName);
+ out.writeString(NetworkType);
+ out.writeString(DLBandwidth);
+ out.writeString(ULBandwidth);
+ }
+
+ public void readFromParcel(Parcel in) {
+ if (in == null) {
+ //log here
+ } else {
+ nodeName = in.readString();
+ NetworkType = in.readString();
+ DLBandwidth = in.readString();
+ ULBandwidth = in.readString();
+ }
+ }
+
+ public static final Parcelable.Creator<MinBackhaulThresholdNetwork> CREATOR = new Parcelable.Creator<MinBackhaulThresholdNetwork>() {
+ public MinBackhaulThresholdNetwork createFromParcel(Parcel in) {
+ return new MinBackhaulThresholdNetwork(in);
+ }
+
+ public MinBackhaulThresholdNetwork[] newArray(int size) {
+ return new MinBackhaulThresholdNetwork[size];
+ }
+ };
+
+ }
+
+ /**
+ * PerProviderSubscription/<X+>/Policy/PolicyUpdate
+ **/
+ public static class PolicyUpdate implements Parcelable {
+ public String UpdateInterval;
+ public String UpdateMethod;
+ public String Restriction;
+ public String URI;
+ public UsernamePassword usernamePassword = new UsernamePassword();
+ public String Other;
+ public TrustRoot trustRoot = new TrustRoot();
+
+ public PolicyUpdate() {
+ }
+
+ public PolicyUpdate(Parcel in) {
+ readFromParcel(in);
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(UpdateInterval);
+ out.writeString(UpdateMethod);
+ out.writeString(Restriction);
+ out.writeString(URI);
+ out.writeParcelable(usernamePassword, flags);
+ out.writeString(Other);
+ out.writeParcelable(trustRoot, flags);
+
+ }
+
+ public void readFromParcel(Parcel in) {
+ if (in == null) {
+ //log here
+ } else {
+ UpdateInterval = in.readString();
+ UpdateMethod = in.readString();
+ Restriction = in.readString();
+ URI = in.readString();
+ usernamePassword = in.readParcelable(UsernamePassword.class.getClassLoader());
+ Other = in.readString();
+ trustRoot = in.readParcelable(TrustRoot.class.getClassLoader());
+ }
+ }
+
+ public static final Parcelable.Creator<PolicyUpdate> CREATOR = new Parcelable.Creator<PolicyUpdate>() {
+ public PolicyUpdate createFromParcel(Parcel in) {
+ return new PolicyUpdate(in);
+ }
+
+ public PolicyUpdate[] newArray(int size) {
+ return new PolicyUpdate[size];
+ }
+ };
+ }
+
+ /**
+ * PerProviderSubscription/<X+>/Policy/SPExclusionList
+ **/
+ public static class SPExclusionList implements Parcelable {
+ public String nodeName;
+ public String SSID;
+
+ public SPExclusionList(String nn, String s) {
+ nodeName = nn;
+ SSID = s;
+ }
+
+ public SPExclusionList() {
+ }
+
+ public SPExclusionList(Parcel in) {
+ readFromParcel(in);
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(nodeName);
+ out.writeString(SSID);
+ }
+
+ public void readFromParcel(Parcel in) {
+ if (in == null) {
+ //log here
+ } else {
+ nodeName = in.readString();
+ SSID = in.readString();
+ }
+ }
+
+ public static final Parcelable.Creator<SPExclusionList> CREATOR = new Parcelable.Creator<SPExclusionList>() {
+ public SPExclusionList createFromParcel(Parcel in) {
+ return new SPExclusionList(in);
+ }
+
+ public SPExclusionList[] newArray(int size) {
+ return new SPExclusionList[size];
+ }
+ };
+ }
+
+ /**
+ * PerProviderSubscription/<X+>/Policy/RequiredProtoPortTuple
+ **/
+ public static class RequiredProtoPortTuple implements Parcelable {
+ public String nodeName;
+ public String IPProtocol;
+ public String PortNumber;
+
+ public RequiredProtoPortTuple() {
+ }
+
+ public RequiredProtoPortTuple(String nn, String protocol, String port) {
+ nodeName = nn;
+ IPProtocol = protocol;
+ PortNumber = port;
+ }
+
+ public RequiredProtoPortTuple(Parcel in) {
+ readFromParcel(in);
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(nodeName);
+ out.writeString(IPProtocol);
+ out.writeString(PortNumber);
+ }
+
+ public void readFromParcel(Parcel in) {
+ if (in == null) {
+ //log here
+ } else {
+ nodeName = in.readString();
+ IPProtocol = in.readString();
+ PortNumber = in.readString();
+ }
+ }
+
+ public static final Parcelable.Creator<RequiredProtoPortTuple> CREATOR = new Parcelable.Creator<RequiredProtoPortTuple>() {
+ public RequiredProtoPortTuple createFromParcel(Parcel in) {
+ return new RequiredProtoPortTuple(in);
+ }
+
+ public RequiredProtoPortTuple[] newArray(int size) {
+ return new RequiredProtoPortTuple[size];
+ }
+ };
+ }
+
+ /**
+ * PerProviderSubscription/<X+>/AAAServerTrustRoot
+ **/
+ public static class AAAServerTrustRoot implements Parcelable {
+ public String nodeName;
+ public String CertURL;
+ public String CertSHA256Fingerprint;
+
+ public AAAServerTrustRoot(String nn, String url, String fp) {
+ nodeName = nn;
+ CertURL = url;
+ CertSHA256Fingerprint = fp;
+ }
+
+ public AAAServerTrustRoot() {
+ }
+
+ public AAAServerTrustRoot(Parcel in) {
+ readFromParcel(in);
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(nodeName);
+ out.writeString(CertURL);
+ out.writeString(CertSHA256Fingerprint);
+ }
+
+ public void readFromParcel(Parcel in) {
+ if (in == null) {
+ //log here
+ } else {
+ nodeName = in.readString();
+ CertURL = in.readString();
+ CertSHA256Fingerprint = in.readString();
+ }
+ }
+
+ public static final Parcelable.Creator<AAAServerTrustRoot> CREATOR = new Parcelable.Creator<AAAServerTrustRoot>() {
+ public AAAServerTrustRoot createFromParcel(Parcel in) {
+ return new AAAServerTrustRoot(in);
+ }
+
+ public AAAServerTrustRoot[] newArray(int size) {
+ return new AAAServerTrustRoot[size];
+ }
+ };
+ }
+
+ /**
+ * PerProviderSubscription/<X+>/SubscriptionUpdate
+ **/
+ public static class SubscriptionUpdate implements Parcelable {
+ public String UpdateInterval;
+ public String UpdateMethod;
+ public String Restriction;
+ public String URI;
+ public UsernamePassword usernamePassword = new UsernamePassword();
+ public String Other;
+ public TrustRoot trustRoot = new TrustRoot();
+
+ public SubscriptionUpdate() {
+ }
+
+ public SubscriptionUpdate(Parcel in) {
+ readFromParcel(in);
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(UpdateInterval);
+ out.writeString(UpdateMethod);
+ out.writeString(Restriction);
+ out.writeString(URI);
+ out.writeParcelable(usernamePassword, flags);
+ out.writeString(Other);
+ out.writeParcelable(trustRoot, flags);
+ }
+
+ public void readFromParcel(Parcel in) {
+ if (in == null) {
+ //log here
+ } else {
+ UpdateInterval = in.readString();
+ UpdateMethod = in.readString();
+ Restriction = in.readString();
+ URI = in.readString();
+ usernamePassword = in.readParcelable(UsernamePassword.class.getClassLoader());
+ Other = in.readString();
+ trustRoot = in.readParcelable(TrustRoot.class.getClassLoader());
+ }
+ }
+
+ public static final Parcelable.Creator<SubscriptionUpdate> CREATOR = new Parcelable.Creator<SubscriptionUpdate>() {
+ public SubscriptionUpdate createFromParcel(Parcel in) {
+ return new SubscriptionUpdate(in);
+ }
+
+ public SubscriptionUpdate[] newArray(int size) {
+ return new SubscriptionUpdate[size];
+ }
+ };
+
+ }
+
+ /**
+ * PerProviderSubscription/<X+>/Policy/PolicyUpdate/TrustRoot
+ * PerProviderSubscription/<X+>/SubscriptionUpdate/TrustRoot
+ * PerProviderSubscription/<X+>/AAAServerTrustRoot/<X+>
+ **/
+ public static class TrustRoot implements Parcelable {
+ public String CertURL;
+ public String CertSHA256Fingerprint;
+
+ public TrustRoot() {
+ }
+
+ public TrustRoot(Parcel in) {
+ readFromParcel(in);
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(CertURL);
+ out.writeString(CertSHA256Fingerprint);
+ }
+
+ public void readFromParcel(Parcel in) {
+ if (in == null) {
+ //log here
+ } else {
+ CertURL = in.readString();
+ CertSHA256Fingerprint = in.readString();
+ }
+ }
+
+ public static final Parcelable.Creator<TrustRoot> CREATOR = new Parcelable.Creator<TrustRoot>() {
+ public TrustRoot createFromParcel(Parcel in) {
+ return new TrustRoot(in);
+ }
+
+ public TrustRoot[] newArray(int size) {
+ return new TrustRoot[size];
+ }
+ };
+ }
+
+ /**
+ * PerProviderSubscription/<X+>/Policy/PolicyUpdate/UsernamePassword
+ * PerProviderSubscription/<X+>/SubscriptionUpdate/UsernamePassword
+ * PerProviderSubscription/<X+>/Credential/UsernamePassword
+ **/
+ public static class UsernamePassword implements Parcelable {
+ public String Username;
+ public String Password;
+ //following are Credential node used only
+ public boolean MachineManaged;
+ public String SoftTokenApp;
+ public String AbleToShare;
+ public EAPMethod eAPMethod = new EAPMethod();
+
+ public UsernamePassword() {
+ }
+
+ public UsernamePassword(Parcel in) {
+ readFromParcel(in);
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(Username);
+ out.writeString(Password);
+ out.writeInt(MachineManaged ? 1 : 0);
+ out.writeString(SoftTokenApp);
+ out.writeString(AbleToShare);
+ out.writeParcelable(eAPMethod, flags);
+ }
+
+ public void readFromParcel(Parcel in) {
+ if (in == null) {
+ //log here
+ } else {
+ Username = in.readString();
+ Password = in.readString();
+ MachineManaged = (in.readInt() == 1) ? true : false;
+ SoftTokenApp = in.readString();
+ AbleToShare = in.readString();
+ eAPMethod = in.readParcelable(EAPMethod.class.getClassLoader());
+ }
+ }
+
+ public static final Parcelable.Creator<UsernamePassword> CREATOR = new Parcelable.Creator<UsernamePassword>() {
+ public UsernamePassword createFromParcel(Parcel in) {
+ return new UsernamePassword(in);
+ }
+
+ public UsernamePassword[] newArray(int size) {
+ return new UsernamePassword[size];
+ }
+ };
+
+ }
+
+ /**
+ * PerProviderSubscription/<X+>/Credential/UsernamePassword/EAPMethod
+ **/
+ public static class EAPMethod implements Parcelable {
+ public String EAPType;
+ public String VendorId;
+ public String VendorType;
+ public String InnerEAPType;
+ public String InnerVendorId;
+ public String InnerVendorType;
+ public String InnerMethod;
+
+ public EAPMethod() {
+ }
+
+ public EAPMethod(Parcel in) {
+ readFromParcel(in);
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(EAPType);
+ out.writeString(VendorId);
+ out.writeString(VendorType);
+ out.writeString(InnerEAPType);
+ out.writeString(InnerVendorId);
+ out.writeString(InnerVendorType);
+ out.writeString(InnerMethod);
+ }
+
+ public void readFromParcel(Parcel in) {
+ if (in == null) {
+ //log here
+ } else {
+ EAPType = in.readString();
+ VendorId = in.readString();
+ VendorType = in.readString();
+ InnerEAPType = in.readString();
+ InnerVendorId = in.readString();
+ InnerVendorType = in.readString();
+ InnerMethod = in.readString();
+ }
+ }
+
+ public static final Parcelable.Creator<EAPMethod> CREATOR = new Parcelable.Creator<EAPMethod>() {
+ public EAPMethod createFromParcel(Parcel in) {
+ return new EAPMethod(in);
+ }
+
+ public EAPMethod[] newArray(int size) {
+ return new EAPMethod[size];
+ }
+ };
+ }
+
+ /**
+ * PerProviderSubscription/<X+>/HomeSP
+ **/
+ public static class HomeSP implements Parcelable {
+ public HashMap<String, NetworkID> networkID = new HashMap<String, NetworkID>();
+ public String FriendlyName;
+ public String IconURL;
+ public String FQDN;
+ public HashMap<String, HomeOIList> homeOIList = new HashMap<String, HomeOIList>();
+ public HashMap<String, OtherHomePartners> otherHomePartners = new HashMap<String, OtherHomePartners>();
+ public String RoamingConsortiumOI;
+
+ public NetworkID createNetworkID(String name, String ssid, String hessid) {
+ NetworkID obj = new NetworkID(name, ssid, hessid);
+ networkID.put(name, obj);
+ return obj;
+ }
+
+ public HomeOIList createHomeOIList(String name, String homeoi, boolean required) {
+ HomeOIList obj = new HomeOIList(name, homeoi, required);
+ homeOIList.put(name, obj);
+ return obj;
+ }
+
+ public OtherHomePartners createOtherHomePartners(String name, String fqdn) {
+ OtherHomePartners obj = new OtherHomePartners(name, fqdn);
+ otherHomePartners.put(name, obj);
+ return obj;
+ }
+
+ public HomeSP() {
+ }
+
+ public HomeSP(Parcel in) {
+ readFromParcel(in);
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeMap(networkID);
+ out.writeString(FriendlyName);
+ out.writeString(IconURL);
+ out.writeString(FQDN);
+ out.writeMap(homeOIList);
+ out.writeMap(otherHomePartners);
+ out.writeString(RoamingConsortiumOI);
+ }
+
+ public void readFromParcel(Parcel in) {
+ if (in == null) {
+ //log here
+ } else {
+ in.readMap(networkID, NetworkID.class.getClassLoader());
+ FriendlyName = in.readString();
+ IconURL = in.readString();
+ FQDN = in.readString();
+ in.readMap(homeOIList, HomeOIList.class.getClassLoader());
+ in.readMap(otherHomePartners, OtherHomePartners.class.getClassLoader());
+ RoamingConsortiumOI = in.readString();
+ }
+ }
+
+ public static final Parcelable.Creator<HomeSP> CREATOR = new Parcelable.Creator<HomeSP>() {
+ public HomeSP createFromParcel(Parcel in) {
+ return new HomeSP(in);
+ }
+
+ public HomeSP[] newArray(int size) {
+ return new HomeSP[size];
+ }
+ };
+
+ }
+
+ /**
+ * PerProviderSubscription/<X+>/HomeSP/NetworkID
+ **/
+ public static class NetworkID implements Parcelable {
+ public String nodeName;
+ public String SSID;
+ public String HESSID;
+
+ public NetworkID(String nn, String s, String h) {
+ nodeName = nn;
+ SSID = s;
+ HESSID = h;
+ }
+
+ public NetworkID() {
+ }
+
+ public NetworkID(Parcel in) {
+ readFromParcel(in);
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(nodeName);
+ out.writeString(SSID);
+ out.writeString(HESSID);
+ }
+
+ public void readFromParcel(Parcel in) {
+ if (in == null) {
+ //log here
+ } else {
+ nodeName = in.readString();
+ SSID = in.readString();
+ HESSID = in.readString();
+ }
+ }
+
+ public static final Parcelable.Creator<NetworkID> CREATOR = new Parcelable.Creator<NetworkID>() {
+ public NetworkID createFromParcel(Parcel in) {
+ return new NetworkID(in);
+ }
+
+ public NetworkID[] newArray(int size) {
+ return new NetworkID[size];
+ }
+ };
+
+ }
+
+ /**
+ * PerProviderSubscription/<X+>/HomeSP/HomeOIList
+ **/
+ public static class HomeOIList implements Parcelable {
+ public String nodeName;
+ public String HomeOI;
+ public boolean HomeOIRequired;
+
+ public HomeOIList(String nn, String h, boolean r) {
+ nodeName = nn;
+ HomeOI = h;
+ HomeOIRequired = r;
+ }
+
+ public HomeOIList() {
+ }
+
+ public HomeOIList(Parcel in) {
+ readFromParcel(in);
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(nodeName);
+ out.writeString(HomeOI);
+ out.writeInt(HomeOIRequired ? 1 : 0);
+ }
+
+ public void readFromParcel(Parcel in) {
+ if (in == null) {
+ //log here
+ } else {
+ nodeName = in.readString();
+ HomeOI = in.readString();
+ HomeOIRequired = (in.readInt() == 1) ? true : false;
+ }
+ }
+
+ public static final Parcelable.Creator<HomeOIList> CREATOR = new Parcelable.Creator<HomeOIList>() {
+ public HomeOIList createFromParcel(Parcel in) {
+ return new HomeOIList(in);
+ }
+
+ public HomeOIList[] newArray(int size) {
+ return new HomeOIList[size];
+ }
+ };
+
+ }
+
+ /**
+ * PerProviderSubscription/<X+>/HomeSP/OtherHomePartners
+ **/
+ public static class OtherHomePartners implements Parcelable {
+ public String nodeName;
+ public String FQDN;
+
+ public OtherHomePartners(String nn, String f) {
+ nodeName = nn;
+ FQDN = f;
+ }
+
+ public OtherHomePartners() {
+ }
+
+ public OtherHomePartners(Parcel in) {
+ readFromParcel(in);
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(nodeName);
+ out.writeString(FQDN);
+ }
+
+ public void readFromParcel(Parcel in) {
+ if (in == null) {
+ //log here
+ } else {
+ nodeName = in.readString();
+ FQDN = in.readString();
+ }
+ }
+
+ public static final Parcelable.Creator<OtherHomePartners> CREATOR = new Parcelable.Creator<OtherHomePartners>() {
+ public OtherHomePartners createFromParcel(Parcel in) {
+ return new OtherHomePartners(in);
+ }
+
+ public OtherHomePartners[] newArray(int size) {
+ return new OtherHomePartners[size];
+ }
+ };
+
+ }
+
+ /**
+ * PerProviderSubscription/<X+>/SubscriptionParameters
+ **/
+ public static class SubscriptionParameters implements Parcelable {
+ public String CreationDate;
+ public String ExpirationDate;
+ public String TypeOfSubscription;
+ public UsageLimits usageLimits = new UsageLimits();
+
+ public SubscriptionParameters() {
+ }
+
+ public SubscriptionParameters(Parcel in) {
+ readFromParcel(in);
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(CreationDate);
+ out.writeString(ExpirationDate);
+ out.writeString(TypeOfSubscription);
+ out.writeParcelable(usageLimits, flags);
+ }
+
+ public void readFromParcel(Parcel in) {
+ if (in == null) {
+ //log here
+ } else {
+ CreationDate = in.readString();
+ ExpirationDate = in.readString();
+ TypeOfSubscription = in.readString();
+ usageLimits = in.readParcelable(UsageLimits.class.getClassLoader());
+ }
+ }
+
+ public static final Parcelable.Creator<SubscriptionParameters> CREATOR = new Parcelable.Creator<SubscriptionParameters>() {
+ public SubscriptionParameters createFromParcel(Parcel in) {
+ return new SubscriptionParameters(in);
+ }
+
+ public SubscriptionParameters[] newArray(int size) {
+ return new SubscriptionParameters[size];
+ }
+ };
+
+ }
+
+ /**
+ * PerProviderSubscription/<X+>/SubscriptionParameters/UsageLimits
+ **/
+ public static class UsageLimits implements Parcelable {
+ public String DataLimit;
+ public String StartDate;
+ public String TimeLimit;
+ public String UsageTimePeriod;
+
+ public UsageLimits() {
+ }
+
+ public UsageLimits(Parcel in) {
+ readFromParcel(in);
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(DataLimit);
+ out.writeString(StartDate);
+ out.writeString(TimeLimit);
+ out.writeString(UsageTimePeriod);
+ }
+
+ public void readFromParcel(Parcel in) {
+ if (in == null) {
+ //log here
+ } else {
+ DataLimit = in.readString();
+ StartDate = in.readString();
+ TimeLimit = in.readString();
+ UsageTimePeriod = in.readString();
+ }
+ }
+
+ public static final Parcelable.Creator<UsageLimits> CREATOR = new Parcelable.Creator<UsageLimits>() {
+ public UsageLimits createFromParcel(Parcel in) {
+ return new UsageLimits(in);
+ }
+
+ public UsageLimits[] newArray(int size) {
+ return new UsageLimits[size];
+ }
+ };
+ }
+
+ /**
+ * PerProviderSubscription/<X+>/Credential
+ **/
+ public static class Credential implements Parcelable {
+ public String CreationDate;
+ public String ExpirationDate;
+ public UsernamePassword usernamePassword = new UsernamePassword();
+ public DigitalCertificate digitalCertificate = new DigitalCertificate();
+ public String Realm;
+ public boolean CheckAAAServerCertStatus;
+ public SIM sim = new SIM();
+
+ public Credential() {
+ }
+
+ public Credential(Parcel in) {
+ readFromParcel(in);
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(CreationDate);
+ out.writeString(ExpirationDate);
+ out.writeParcelable(usernamePassword, flags);
+ out.writeParcelable(digitalCertificate, flags);
+ out.writeString(Realm);
+ out.writeInt(CheckAAAServerCertStatus ? 1 : 0);
+ out.writeParcelable(sim, flags);
+ }
+
+ public void readFromParcel(Parcel in) {
+ if (in == null) {
+ //log here
+ } else {
+ CreationDate = in.readString();
+ ExpirationDate = in.readString();
+ usernamePassword = in.readParcelable(UsernamePassword.class.getClassLoader());
+ digitalCertificate = in.readParcelable(DigitalCertificate.class.getClassLoader());
+ Realm = in.readString();
+ CheckAAAServerCertStatus = (in.readInt() == 1) ? true : false;
+ sim = in.readParcelable(SIM.class.getClassLoader());
+ }
+ }
+
+ public static final Parcelable.Creator<Credential> CREATOR = new Parcelable.Creator<Credential>() {
+ public Credential createFromParcel(Parcel in) {
+ return new Credential(in);
+ }
+
+ public Credential[] newArray(int size) {
+ return new Credential[size];
+ }
+ };
+ }
+
+ /**
+ * PerProviderSubscription/<X+>/Credential/DigitalCertificate
+ **/
+ public static class DigitalCertificate implements Parcelable {
+ public String CertificateType;
+ public String CertSHA256Fingerprint;
+
+ public DigitalCertificate() {
+ }
+
+ public DigitalCertificate(Parcel in) {
+ readFromParcel(in);
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(CertificateType);
+ out.writeString(CertSHA256Fingerprint);
+ }
+
+ public void readFromParcel(Parcel in) {
+ if (in == null) {
+ //log here
+ } else {
+ CertificateType = in.readString();
+ CertSHA256Fingerprint = in.readString();
+ }
+ }
+
+ public static final Parcelable.Creator<DigitalCertificate> CREATOR = new Parcelable.Creator<DigitalCertificate>() {
+ public DigitalCertificate createFromParcel(Parcel in) {
+ return new DigitalCertificate(in);
+ }
+
+ public DigitalCertificate[] newArray(int size) {
+ return new DigitalCertificate[size];
+ }
+ };
+
+ }
+
+ /**
+ * PerProviderSubscription/<X+>/Credential/SIM
+ **/
+ public static class SIM implements Parcelable {
+ public String IMSI;
+ public String EAPType;
+
+ public SIM() {
+ }
+
+ public SIM(Parcel in) {
+ readFromParcel(in);
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(IMSI);
+ out.writeString(EAPType);
+ }
+
+ public void readFromParcel(Parcel in) {
+ if (in == null) {
+ //log here
+ } else {
+ IMSI = in.readString();
+ EAPType = in.readString();
+ }
+ }
+
+ public static final Parcelable.Creator<SIM> CREATOR = new Parcelable.Creator<SIM>() {
+ public SIM createFromParcel(Parcel in) {
+ return new SIM(in);
+ }
+
+ public SIM[] newArray(int size) {
+ return new SIM[size];
+ }
+ };
+
+ }
+
+ /**
+ * PerProviderSubscription/<X+>/Extension
+ **/
+ public static class Extension {
+ public String empty;
+ }
+
+ public WifiPasspointDmTree() {
+ }
+
+ public WifiPasspointDmTree(Parcel in) {
+ readFromParcel(in);
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeMap(spFqdn);
+ }
+
+ public void readFromParcel(Parcel in) {
+ if (in == null) {
+ //log here
+ } else {
+ in.readMap(spFqdn, SpFqdn.class.getClassLoader());
+ }
+ }
+
+ public static final Parcelable.Creator<WifiPasspointDmTree> CREATOR = new Parcelable.Creator<WifiPasspointDmTree>() {
+ public WifiPasspointDmTree createFromParcel(Parcel in) {
+ return new WifiPasspointDmTree(in);
+ }
+
+ public WifiPasspointDmTree[] newArray(int size) {
+ return new WifiPasspointDmTree[size];
+ }
+ };
+
+}
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointInfo.aidl b/wifi/java/android/net/wifi/passpoint/WifiPasspointInfo.aidl
new file mode 100644
index 0000000..27f23bc
--- /dev/null
+++ b/wifi/java/android/net/wifi/passpoint/WifiPasspointInfo.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 WifiPasspointInfo;
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointInfo.java b/wifi/java/android/net/wifi/passpoint/WifiPasspointInfo.java
new file mode 100644
index 0000000..33db3f5
--- /dev/null
+++ b/wifi/java/android/net/wifi/passpoint/WifiPasspointInfo.java
@@ -0,0 +1,559 @@
+/*
+ * 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;
+
+/** @hide */
+public class WifiPasspointInfo 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;
+
+
+ public static class WanMetrics {
+ public static final int STATUS_RESERVED = 0;
+ public static final int STATUS_UP = 1;
+ public static final int STATUS_DOWN = 2;
+ public static final int STATUS_TEST = 3;
+
+ public int wanInfo;
+ public long downlinkSpeed;
+ public long uplinkSpeed;
+ public int downlinkLoad;
+ public int uplinkLoad;
+ public int lmd;
+
+ public int getLinkStatus() {
+ return wanInfo & 0x3;
+ }
+
+ public boolean getSymmetricLink() {
+ return (wanInfo & (1 << 2)) != 0;
+ }
+
+ public boolean getAtCapacity() {
+ return (wanInfo & (1 << 3)) != 0;
+ }
+
+ @Override
+ public String toString() {
+ return wanInfo + "," + downlinkSpeed + "," + uplinkSpeed + "," +
+ downlinkLoad + "," + uplinkLoad + "," + lmd;
+ }
+ }
+
+ public static class IpProtoPort {
+ public static final int STATUS_CLOSED = 0;
+ public static final int STATUS_OPEN = 1;
+ public static final int STATUS_UNKNOWN = 2;
+
+ public int proto;
+ public int port;
+ public int status;
+
+ @Override
+ public String toString() {
+ return proto + "," + port + "," + status;
+ }
+ }
+
+ public static class NetworkAuthType {
+ public static final int TYPE_TERMS_AND_CONDITION = 0;
+ public static final int TYPE_ONLINE_ENROLLMENT = 1;
+ public static final int TYPE_HTTP_REDIRECTION = 2;
+ public static final int TYPE_DNS_REDIRECTION = 3;
+
+ public int type;
+ public String redirectUrl;
+
+ @Override
+ public String toString() {
+ return type + "," + redirectUrl;
+ }
+ }
+
+ public static class IpAddressType {
+ public static final int IPV6_NOT_AVAILABLE = 0;
+ public static final int IPV6_AVAILABLE = 1;
+ public static final int IPV6_UNKNOWN = 2;
+
+ public static final int IPV4_NOT_AVAILABLE = 0;
+ public static final int IPV4_PUBLIC = 1;
+ public static final int IPV4_PORT_RESTRICTED = 2;
+ public static final int IPV4_SINGLE_NAT = 3;
+ public static final int IPV4_DOUBLE_NAT = 4;
+ public static final int IPV4_PORT_RESTRICTED_SINGLE_NAT = 5;
+ public static final int IPV4_PORT_RESTRICTED_DOUBLE_NAT = 6;
+ public static final int IPV4_PORT_UNKNOWN = 7;
+
+ private static final int NULL_VALUE = -1;
+
+ public int availability;
+
+ public int getIpv6Availability() {
+ return availability & 0x3;
+ }
+
+ public int getIpv4Availability() {
+ return (availability & 0xFF) >> 2;
+ }
+
+ @Override
+ public String toString() {
+ return getIpv6Availability() + "," + getIpv4Availability();
+ }
+ }
+
+ public static class NaiRealm {
+ public static final int ENCODING_RFC4282 = 0;
+ public static final int ENCODING_UTF8 = 1;
+
+ public int encoding;
+ public String realm;
+
+ @Override
+ public String toString() {
+ return encoding + "," + realm;
+ }
+ }
+
+ public static class CellularNetwork {
+ public String mcc;
+ public String mnc;
+
+ @Override
+ public String toString() {
+ return mcc + "," + mnc;
+ }
+ }
+
+ /** BSSID */
+ public String bssid;
+
+ /** venue name */
+ public String venueName;
+
+ /** list of network authentication types */
+ public List<NetworkAuthType> networkAuthTypeList;
+
+ /** list of roaming consortium OIs */
+ public List<String> roamingConsortiumList;
+
+ /** IP address availability */
+ public IpAddressType ipAddrTypeAvailability;
+
+ /** list of NAI realm */
+ public List<NaiRealm> naiRealmList;
+
+ /** list of 3GPP cellular network */
+ public List<CellularNetwork> cellularNetworkList;
+
+ /** list of fully qualified domain name (FQDN) */
+ public List<String> domainNameList;
+
+ /** HS 2.0 operator friendly name */
+ public String operatorFriendlyName;
+
+ /** HS 2.0 wan metrics */
+ public WanMetrics wanMetrics;
+
+ /** list of HS 2.0 IP proto port */
+ public List<IpProtoPort> connectionCapabilityList;
+
+ /** list of HS 2.0 OSU providers */
+ public List<WifiPasspointOsuProvider> osuProviderList;
+
+ /**
+ * 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("(").append(bssid).append(")");
+
+ if (venueName != null)
+ sb.append(" venueName: ").append("(")
+ .append(venueName.replace("\n", "\\n")).append(")");
+
+ if (networkAuthTypeList != null) {
+ sb.append(" networkAuthType: ");
+ for (NetworkAuthType auth : networkAuthTypeList)
+ sb.append("(").append(auth.toString()).append(")");
+ }
+
+ if (roamingConsortiumList != null) {
+ sb.append(" roamingConsortium: ");
+ for (String oi : roamingConsortiumList)
+ sb.append("(").append(oi).append(")");
+ }
+
+ if (ipAddrTypeAvailability != null) {
+ sb.append(" ipAddrTypeAvaibility: ").append("(")
+ .append(ipAddrTypeAvailability.toString()).append(")");
+ }
+
+ if (naiRealmList != null) {
+ sb.append(" naiRealm: ");
+ for (NaiRealm realm : naiRealmList)
+ sb.append("(").append(realm.toString()).append(")");
+ }
+
+ if (cellularNetworkList != null) {
+ sb.append(" cellularNetwork: ");
+ for (CellularNetwork plmn : cellularNetworkList)
+ sb.append("(").append(plmn.toString()).append(")");
+ }
+
+ if (domainNameList != null) {
+ sb.append(" domainName: ");
+ for (String fqdn : domainNameList)
+ sb.append("(").append(fqdn).append(")");
+ }
+
+ if (operatorFriendlyName != null)
+ sb.append(" operatorFriendlyName: ").append("(")
+ .append(operatorFriendlyName).append(")");
+
+ if (wanMetrics != null)
+ sb.append(" wanMetrics: ").append("(")
+ .append(wanMetrics.toString()).append(")");
+
+ if (connectionCapabilityList != null) {
+ sb.append(" connectionCapability: ");
+ for (IpProtoPort ip : connectionCapabilityList)
+ sb.append("(").append(ip.toString()).append(")");
+ }
+
+ if (osuProviderList != null) {
+ sb.append(" osuProviderList: ");
+ for (WifiPasspointOsuProvider osu : osuProviderList)
+ sb.append("(").append(osu.toString()).append(")");
+ }
+
+ return sb.toString();
+ }
+
+ /** Implement the Parcelable interface {@hide} */
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(bssid);
+ out.writeString(venueName);
+
+ if (networkAuthTypeList == null) {
+ out.writeInt(0);
+ } else {
+ out.writeInt(networkAuthTypeList.size());
+ for (NetworkAuthType auth : networkAuthTypeList) {
+ out.writeInt(auth.type);
+ out.writeString(auth.redirectUrl);
+ }
+ }
+
+ if (roamingConsortiumList == null) {
+ out.writeInt(0);
+ } else {
+ out.writeInt(roamingConsortiumList.size());
+ for (String oi : roamingConsortiumList)
+ out.writeString(oi);
+ }
+
+ if (ipAddrTypeAvailability == null) {
+ out.writeInt(IpAddressType.NULL_VALUE);
+ } else {
+ out.writeInt(ipAddrTypeAvailability.availability);
+ }
+
+ if (naiRealmList == null) {
+ out.writeInt(0);
+ } else {
+ out.writeInt(naiRealmList.size());
+ for (NaiRealm realm : naiRealmList) {
+ out.writeInt(realm.encoding);
+ out.writeString(realm.realm);
+ }
+ }
+
+ if (cellularNetworkList == null) {
+ out.writeInt(0);
+ } else {
+ out.writeInt(cellularNetworkList.size());
+ for (CellularNetwork plmn : cellularNetworkList) {
+ out.writeString(plmn.mcc);
+ out.writeString(plmn.mnc);
+ }
+ }
+
+
+ if (domainNameList == null) {
+ out.writeInt(0);
+ } else {
+ out.writeInt(domainNameList.size());
+ for (String fqdn : domainNameList)
+ out.writeString(fqdn);
+ }
+
+ out.writeString(operatorFriendlyName);
+
+ if (wanMetrics == null) {
+ out.writeInt(0);
+ } else {
+ out.writeInt(1);
+ out.writeInt(wanMetrics.wanInfo);
+ out.writeLong(wanMetrics.downlinkSpeed);
+ out.writeLong(wanMetrics.uplinkSpeed);
+ out.writeInt(wanMetrics.downlinkLoad);
+ out.writeInt(wanMetrics.uplinkLoad);
+ out.writeInt(wanMetrics.lmd);
+ }
+
+ if (connectionCapabilityList == null) {
+ out.writeInt(0);
+ } else {
+ out.writeInt(connectionCapabilityList.size());
+ for (IpProtoPort ip : connectionCapabilityList) {
+ out.writeInt(ip.proto);
+ out.writeInt(ip.port);
+ out.writeInt(ip.status);
+ }
+ }
+
+ if (osuProviderList == null) {
+ out.writeInt(0);
+ } else {
+ out.writeInt(osuProviderList.size());
+ for (WifiPasspointOsuProvider 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<WifiPasspointInfo> CREATOR =
+ new Parcelable.Creator<WifiPasspointInfo>() {
+ @Override
+ public WifiPasspointInfo createFromParcel(Parcel in) {
+ WifiPasspointInfo p = new WifiPasspointInfo();
+ int n;
+
+ p.bssid = in.readString();
+ p.venueName = in.readString();
+
+ n = in.readInt();
+ if (n > 0) {
+ p.networkAuthTypeList = new ArrayList<NetworkAuthType>();
+ for (int i = 0; i < n; i++) {
+ NetworkAuthType auth = new NetworkAuthType();
+ auth.type = in.readInt();
+ auth.redirectUrl = in.readString();
+ p.networkAuthTypeList.add(auth);
+ }
+ }
+
+ n = in.readInt();
+ if (n > 0) {
+ p.roamingConsortiumList = new ArrayList<String>();
+ for (int i = 0; i < n; i++)
+ p.roamingConsortiumList.add(in.readString());
+ }
+
+ n = in.readInt();
+ if (n != IpAddressType.NULL_VALUE) {
+ p.ipAddrTypeAvailability = new IpAddressType();
+ p.ipAddrTypeAvailability.availability = n;
+ }
+
+ n = in.readInt();
+ if (n > 0) {
+ p.naiRealmList = new ArrayList<NaiRealm>();
+ for (int i = 0; i < n; i++) {
+ NaiRealm realm = new NaiRealm();
+ realm.encoding = in.readInt();
+ realm.realm = in.readString();
+ p.naiRealmList.add(realm);
+ }
+ }
+
+ n = in.readInt();
+ if (n > 0) {
+ p.cellularNetworkList = new ArrayList<CellularNetwork>();
+ for (int i = 0; i < n; i++) {
+ CellularNetwork plmn = new CellularNetwork();
+ plmn.mcc = in.readString();
+ plmn.mnc = in.readString();
+ p.cellularNetworkList.add(plmn);
+ }
+ }
+
+ n = in.readInt();
+ if (n > 0) {
+ p.domainNameList = new ArrayList<String>();
+ for (int i = 0; i < n; i++)
+ p.domainNameList.add(in.readString());
+ }
+
+ p.operatorFriendlyName = in.readString();
+
+ n = in.readInt();
+ if (n > 0) {
+ p.wanMetrics = new WanMetrics();
+ p.wanMetrics.wanInfo = in.readInt();
+ p.wanMetrics.downlinkSpeed = in.readLong();
+ p.wanMetrics.uplinkSpeed = in.readLong();
+ p.wanMetrics.downlinkLoad = in.readInt();
+ p.wanMetrics.uplinkLoad = in.readInt();
+ p.wanMetrics.lmd = in.readInt();
+ }
+
+ n = in.readInt();
+ if (n > 0) {
+ p.connectionCapabilityList = new ArrayList<IpProtoPort>();
+ for (int i = 0; i < n; i++) {
+ IpProtoPort ip = new IpProtoPort();
+ ip.proto = in.readInt();
+ ip.port = in.readInt();
+ ip.status = in.readInt();
+ p.connectionCapabilityList.add(ip);
+ }
+ }
+
+ n = in.readInt();
+ if (n > 0) {
+ p.osuProviderList = new ArrayList<WifiPasspointOsuProvider>();
+ for (int i = 0; i < n; i++) {
+ WifiPasspointOsuProvider osu = WifiPasspointOsuProvider.CREATOR
+ .createFromParcel(in);
+ p.osuProviderList.add(osu);
+ }
+ }
+
+ return p;
+ }
+
+ @Override
+ public WifiPasspointInfo[] newArray(int size) {
+ return new WifiPasspointInfo[size];
+ }
+ };
+}
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java b/wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java
new file mode 100644
index 0000000..0245a3d
--- /dev/null
+++ b/wifi/java/android/net/wifi/passpoint/WifiPasspointManager.java
@@ -0,0 +1,567 @@
+/*
+ * 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.Parcel;
+import android.os.Parcelable;
+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;
+
+/**
+ * Provides APIs for managing Wifi Passpoint credentials.
+ * @hide
+ */
+public class WifiPasspointManager {
+
+ private static final String TAG = "PasspointManager";
+
+ private static final boolean DBG = true;
+
+ /* Passpoint states values */
+
+ /** Passpoint is in an unknown 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 REASON_ERROR = 0;
+
+ /** Indicates that the operation failed because wifi is disabled */
+ public static final int REASON_WIFI_DISABLED = 1;
+
+ /** Indicates that the operation failed because the framework is busy */
+ public static final int REASON_BUSY = 2;
+
+ /** Indicates that the operation failed because parameter is invalid */
+ public static final int REASON_INVALID_PARAMETER = 3;
+
+ /** Indicates that the operation failed because the server is not trusted */
+ public static final int REASON_NOT_TRUSTED = 4;
+
+ /**
+ * protocol supported for Passpoint
+ */
+ public static final String PROTOCOL_DM = "OMA-DM-ClientInitiated";
+
+ /**
+ * protocol supported for Passpoint
+ */
+ public static final String PROTOCOL_SOAP = "SPP-ClientInitiated";
+
+ /* 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.
+ */
+ public static final String PASSPOINT_OSU_AVAILABLE_ACTION =
+ "android.net.wifi.passpoint.OSU_AVAILABLE";
+
+ /**
+ * Broadcast intent action indicating that user remediation is required
+ */
+ 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
+ */
+ 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 URI.
+ *
+ * @param uri URI for browser launch
+ */
+ public void onBrowserLaunch(String uri);
+
+ /**
+ * 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 peekListener(int key) {
+ Log.d(TAG, "peekListener() key=" + key);
+ if (key == INVALID_LISTENER_KEY)
+ return null;
+ synchronized (mListenerMapLock) {
+ return mListenerMap.get(key);
+ }
+ }
+
+
+ private Object getListener(int key, boolean forceRemove) {
+ Log.d(TAG, "getListener() key=" + key + " force=" + forceRemove);
+ if (key == INVALID_LISTENER_KEY)
+ return null;
+ synchronized (mListenerMapLock) {
+ if (!forceRemove) {
+ 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(WifiPasspointInfo 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 = null;
+
+ switch (message.what) {
+ case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
+ if (mChannelListener != null) {
+ mChannelListener.onChannelDisconnected();
+ mChannelListener = null;
+ }
+ break;
+
+ case REQUEST_ANQP_INFO_SUCCEEDED:
+ WifiPasspointInfo result = (WifiPasspointInfo) message.obj;
+ anqpRequestFinish(result);
+ listener = getListener(message.arg2, false);
+ if (listener != null) {
+ ((ActionListener) listener).onSuccess();
+ }
+ break;
+
+ case REQUEST_ANQP_INFO_FAILED:
+ anqpRequestFinish((ScanResult) message.obj);
+ listener = getListener(message.arg2, false);
+ if (listener == null)
+ getListener(message.arg2, true);
+ if (listener != null) {
+ ((ActionListener) listener).onFailure(message.arg1);
+ }
+ break;
+
+ case START_OSU_SUCCEEDED:
+ listener = getListener(message.arg2, true);
+ if (listener != null) {
+ ((OsuRemListener) listener).onSuccess();
+ }
+ break;
+
+ case START_OSU_FAILED:
+ listener = getListener(message.arg2, true);
+ if (listener != null) {
+ ((OsuRemListener) listener).onFailure(message.arg1);
+ }
+ break;
+
+ case START_OSU_BROWSER:
+ listener = peekListener(message.arg2);
+ if (listener != null) {
+ ParcelableString str = (ParcelableString) message.obj;
+ if (str == null || str.string == null)
+ ((OsuRemListener) listener).onBrowserDismiss();
+ else
+ ((OsuRemListener) listener).onBrowserLaunch(str.string);
+ }
+ break;
+
+ default:
+ Log.d(TAG, "Ignored " + message);
+ break;
+ }
+ }
+ }
+
+ }
+
+ public static class ParcelableString implements Parcelable {
+ public String string;
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(string);
+ }
+
+ public static final Parcelable.Creator<ParcelableString> CREATOR =
+ new Parcelable.Creator<ParcelableString>() {
+ @Override
+ public ParcelableString createFromParcel(Parcel in) {
+ ParcelableString ret = new ParcelableString();
+ ret.string = in.readString();
+ return ret;
+ }
+ @Override
+ public ParcelableString[] newArray(int size) {
+ return new ParcelableString[size];
+ }
+ };
+ }
+
+ private static final int BASE = Protocol.BASE_WIFI_PASSPOINT_MANAGER;
+
+ public static final int REQUEST_ANQP_INFO = BASE + 1;
+ public static final int REQUEST_ANQP_INFO_FAILED = BASE + 2;
+ public static final int REQUEST_ANQP_INFO_SUCCEEDED = BASE + 3;
+ public static final int REQUEST_OSU_ICON = BASE + 4;
+ public static final int REQUEST_OSU_ICON_FAILED = BASE + 5;
+ public static final int REQUEST_OSU_ICON_SUCCEEDED = BASE + 6;
+ public static final int START_OSU = BASE + 7;
+ public static final int START_OSU_BROWSER = BASE + 8;
+ public static final int START_OSU_FAILED = BASE + 9;
+ public static final int START_OSU_SUCCEEDED = BASE + 10;
+
+ private Context mContext;
+ IWifiPasspointManager mService;
+
+ /**
+ * TODO: doc
+ * @param context
+ * @param service
+ */
+ public WifiPasspointManager(Context context, IWifiPasspointManager 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
+ */
+ public Messenger getMessenger() {
+ try {
+ return mService.getMessenger();
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
+ public int getPasspointState() {
+ try {
+ return mService.getPasspointState();
+ } catch (RemoteException e) {
+ return PASSPOINT_STATE_UNKNOWN;
+ }
+ }
+
+ 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");
+ }
+
+ public void requestOsuIcons(Channel c, List<WifiPasspointOsuProvider> requested,
+ int resolution, ActionListener listener) {
+ }
+
+ public List<WifiPasspointPolicy> requestCredentialMatch(List<ScanResult> requested) {
+ try {
+ return mService.requestCredentialMatch(requested);
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Get a list of saved Passpoint credentials. Only those credentials owned
+ * by the caller will be returned.
+ *
+ * @return The list of credentials
+ */
+ public List<WifiPasspointCredential> getCredentials() {
+ try {
+ return mService.getCredentials();
+ } catch (RemoteException e) {
+ 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(WifiPasspointCredential cred) {
+ try {
+ return mService.addCredential(cred);
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Update an existing Passpoint credential. Only system or the owner of this
+ * credential has the permission to do this.
+ *
+ * @param cred The credential to be updated
+ * @return {@code true} if the operation succeeds, {@code false} otherwise
+ */
+ public boolean updateCredential(WifiPasspointCredential cred) {
+ try {
+ return mService.updateCredential(cred);
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Remove an existing Passpoint credential. Only system or the owner of this
+ * credential has the permission to do this.
+ *
+ * @param cred The credential to be removed
+ * @return {@code true} if the operation succeeds, {@code false} otherwise
+ */
+ public boolean removeCredential(WifiPasspointCredential cred) {
+ try {
+ return mService.removeCredential(cred);
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
+ public void startOsu(Channel c, WifiPasspointOsuProvider osu, OsuRemListener listener) {
+ Log.d(TAG, "startOsu start");
+ checkChannel(c);
+ int key = c.putListener(listener);
+ c.mAsyncChannel.sendMessage(START_OSU, 0, key, osu);
+ Log.d(TAG, "startOsu end");
+ }
+
+ public void startRemediation(Channel c, OsuRemListener listener) {
+ }
+
+ public void connect(WifiPasspointPolicy policy) {
+ }
+
+ 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/WifiPasspointOsuProvider.aidl b/wifi/java/android/net/wifi/passpoint/WifiPasspointOsuProvider.aidl
new file mode 100644
index 0000000..088136f
--- /dev/null
+++ b/wifi/java/android/net/wifi/passpoint/WifiPasspointOsuProvider.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 WifiPasspointOsuProvider;
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointOsuProvider.java b/wifi/java/android/net/wifi/passpoint/WifiPasspointOsuProvider.java
new file mode 100644
index 0000000..b54b70c
--- /dev/null
+++ b/wifi/java/android/net/wifi/passpoint/WifiPasspointOsuProvider.java
@@ -0,0 +1,152 @@
+/*
+ * 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;
+
+/** @hide */
+public class WifiPasspointOsuProvider implements Parcelable {
+
+ /** TODO: doc
+ * @hide
+ */
+ public static final int OSU_METHOD_UNKNOWN = -1;
+
+ /** TODO: doc
+ * @hide
+ */
+ public static final int OSU_METHOD_OMADM = 0;
+
+ /** TODO: doc
+ * @hide
+ */
+ public static final int OSU_METHOD_SOAP = 1;
+
+ /** TODO: doc */
+ public String ssid;
+
+ /** TODO: doc */
+ public String friendlyName;
+
+ /** TODO: doc
+ * @hide
+ */
+ public String serverUri;
+
+ /** TODO: doc
+ * @hide
+ */
+ 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 WifiPasspointOsuProvider() {
+ // TODO
+ }
+
+ /** copy constructor @hide */
+ public WifiPasspointOsuProvider(WifiPasspointOsuProvider source) {
+ // TODO
+ }
+
+ @Override
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append("SSID: ").append("<").append(ssid).append(">");
+ if (friendlyName != null)
+ sb.append(" friendlyName: ").append("<").append(friendlyName).append(">");
+ if (serverUri != null)
+ sb.append(" serverUri: ").append("<").append(serverUri).append(">");
+ sb.append(" osuMethod: ").append("<").append(osuMethod).append(">");
+ if (iconFileName != null) {
+ sb.append(" icon: <").append(iconWidth).append("x")
+ .append(iconHeight).append(" ")
+ .append(iconType).append(" ")
+ .append(iconFileName).append(">");
+ }
+ if (osuNai != null)
+ sb.append(" osuNai: ").append("<").append(osuNai).append(">");
+ if (osuService != null)
+ sb.append(" osuService: ").append("<").append(osuService).append(">");
+ return sb.toString();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(ssid);
+ out.writeString(friendlyName);
+ out.writeString(serverUri);
+ out.writeInt(osuMethod);
+ out.writeInt(iconWidth);
+ out.writeInt(iconHeight);
+ out.writeString(iconType);
+ out.writeString(iconFileName);
+ out.writeString(osuNai);
+ out.writeString(osuService);
+ // TODO: icon image?
+ }
+
+ public static final Parcelable.Creator<WifiPasspointOsuProvider> CREATOR =
+ new Parcelable.Creator<WifiPasspointOsuProvider>() {
+ @Override
+ public WifiPasspointOsuProvider createFromParcel(Parcel in) {
+ WifiPasspointOsuProvider osu = new WifiPasspointOsuProvider();
+ osu.ssid = in.readString();
+ osu.friendlyName = in.readString();
+ osu.serverUri = in.readString();
+ osu.osuMethod = in.readInt();
+ osu.iconWidth = in.readInt();
+ osu.iconHeight = in.readInt();
+ osu.iconType = in.readString();
+ osu.iconFileName = in.readString();
+ osu.osuNai = in.readString();
+ osu.osuService = in.readString();
+ return osu;
+ }
+
+ @Override
+ public WifiPasspointOsuProvider[] newArray(int size) {
+ return new WifiPasspointOsuProvider[size];
+ }
+ };
+}
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointPolicy.aidl b/wifi/java/android/net/wifi/passpoint/WifiPasspointPolicy.aidl
new file mode 100644
index 0000000..1d61da0
--- /dev/null
+++ b/wifi/java/android/net/wifi/passpoint/WifiPasspointPolicy.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 WifiPasspointPolicy;
diff --git a/wifi/java/android/net/wifi/passpoint/WifiPasspointPolicy.java b/wifi/java/android/net/wifi/passpoint/WifiPasspointPolicy.java
new file mode 100644
index 0000000..f84ac88
--- /dev/null
+++ b/wifi/java/android/net/wifi/passpoint/WifiPasspointPolicy.java
@@ -0,0 +1,386 @@
+/*
+ * 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.net.wifi.WifiConfiguration;
+import android.net.wifi.ScanResult;
+import android.os.Parcelable;
+import android.os.Parcel;
+import android.security.Credentials;
+import android.util.Log;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.List;
+
+
+/** @hide */
+public class WifiPasspointPolicy implements Parcelable {
+
+ private final static String TAG = "PasspointPolicy";
+
+ /** @hide */
+ public static final int HOME_SP = 0;
+
+ /** @hide */
+ public static final int ROAMING_PARTNER = 1;
+
+ /** @hide */
+ public static final int UNRESTRICTED = 2;
+
+ private String mName;
+ private int mCredentialPriority;
+ private int mRoamingPriority;
+ private String mBssid;
+ private String mSsid;
+ private WifiPasspointCredential mCredential;
+ private int mRestriction;// Permitted values are "HomeSP", "RoamingPartner", or "Unrestricted"
+ private boolean mIsHomeSp;
+
+ private final String INT_PRIVATE_KEY = "private_key";
+ private final String INT_PHASE2 = "phase2";
+ private final String INT_PASSWORD = "password";
+ private final String INT_IDENTITY = "identity";
+ private final String INT_EAP = "eap";
+ private final String INT_CLIENT_CERT = "client_cert";
+ private final String INT_CA_CERT = "ca_cert";
+ private final String INT_ANONYMOUS_IDENTITY = "anonymous_identity";
+ private final String INT_SIM_SLOT = "sim_slot";
+ private final String INT_ENTERPRISEFIELD_NAME ="android.net.wifi.WifiConfiguration$EnterpriseField";
+ private final String ISO8601DATEFORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'";
+ private final String ENTERPRISE_PHASE2_MSCHAPV2 = "auth=MSCHAPV2";
+ private final String ENTERPRISE_PHASE2_MSCHAP = "auth=MSCHAP";
+
+ /** @hide */
+ public WifiPasspointPolicy(String name, String ssid,
+ String bssid, WifiPasspointCredential pc,
+ int restriction, boolean ishomesp) {
+ mName = name;
+ if (pc != null) {
+ mCredentialPriority = pc.getPriority();
+ }
+ //PerProviderSubscription/<X+>/Policy/PreferredRoamingPartnerList/<X+>/Priority
+ mRoamingPriority = 128; //default priority value of 128
+ mSsid = ssid;
+ mCredential = pc;
+ mBssid = bssid;
+ mRestriction = restriction;
+ mIsHomeSp = ishomesp;
+ }
+
+ public String getSsid() {
+ return mSsid;
+ }
+
+ /** @hide */
+ public void setBssid(String bssid) {
+ mBssid = bssid;
+ }
+
+ public String getBssid() {
+ return mBssid;
+ }
+
+ /** @hide */
+ public void setRestriction(int r) {
+ mRestriction = r;
+ }
+
+ /** @hide */
+ public int getRestriction() {
+ return mRestriction;
+ }
+
+ /** @hide */
+ public void setHomeSp(boolean b) {
+ mIsHomeSp = b;
+ }
+
+ /** @hide */
+ public boolean isHomeSp() {
+ return mIsHomeSp;
+ }
+
+ /** @hide */
+ public void setCredential(WifiPasspointCredential newCredential) {
+ mCredential = newCredential;
+ }
+
+ public WifiPasspointCredential getCredential() {
+ // TODO: return a copy
+ return mCredential;
+ }
+
+ /** @hide */
+ public void setCredentialPriority(int priority) {
+ mCredentialPriority = priority;
+ }
+
+ /** @hide */
+ public void setRoamingPriority(int priority) {
+ mRoamingPriority = priority;
+ }
+
+ public int getCredentialPriority() {
+ return mCredentialPriority;
+ }
+
+ public int getRoamingPriority() {
+ return mRoamingPriority;
+ }
+
+ public WifiConfiguration createWifiConfiguration() {
+ WifiConfiguration wfg = new WifiConfiguration();
+ if (mBssid != null) {
+ Log.d(TAG, "create bssid:" + mBssid);
+ wfg.BSSID = mBssid;
+ }
+
+ if (mSsid != null) {
+ Log.d(TAG, "create ssid:" + mSsid);
+ wfg.SSID = mSsid;
+ }
+ //TODO: 1. add pmf configuration
+ // 2. add ocsp configuration
+ // 3. add eap-sim configuration
+ /*Key management*/
+ wfg.status = WifiConfiguration.Status.ENABLED;
+ wfg.allowedKeyManagement.clear();
+ wfg.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.WPA_EAP);
+ wfg.allowedKeyManagement.set(WifiConfiguration.KeyMgmt.IEEE8021X);
+
+ /*Group Ciphers*/
+ wfg.allowedGroupCiphers.clear();
+ wfg.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.CCMP);
+ wfg.allowedPairwiseCiphers.set(WifiConfiguration.PairwiseCipher.TKIP);
+
+ /*Protocols*/
+ wfg.allowedProtocols.clear();
+ wfg.allowedProtocols.set(WifiConfiguration.Protocol.RSN);
+ wfg.allowedProtocols.set(WifiConfiguration.Protocol.WPA);
+
+ Class[] enterpriseFieldArray = WifiConfiguration.class.getClasses();
+ Class<?> enterpriseFieldClass = null;
+
+
+ for(Class<?> myClass : enterpriseFieldArray) {
+ if(myClass.getName().equals(INT_ENTERPRISEFIELD_NAME)) {
+ enterpriseFieldClass = myClass;
+ break;
+ }
+ }
+ Log.d(TAG, "class chosen " + enterpriseFieldClass.getName() );
+
+
+ Field anonymousId = null, caCert = null, clientCert = null,
+ eap = null, identity = null, password = null,
+ phase2 = null, privateKey = null;
+
+ Field[] fields = WifiConfiguration.class.getFields();
+
+
+ for (Field tempField : fields) {
+ if (tempField.getName().trim().equals(INT_ANONYMOUS_IDENTITY)) {
+ anonymousId = tempField;
+ Log.d(TAG, "field " + anonymousId.getName() );
+ } else if (tempField.getName().trim().equals(INT_CA_CERT)) {
+ caCert = tempField;
+ } else if (tempField.getName().trim().equals(INT_CLIENT_CERT)) {
+ clientCert = tempField;
+ Log.d(TAG, "field " + clientCert.getName() );
+ } else if (tempField.getName().trim().equals(INT_EAP)) {
+ eap = tempField;
+ Log.d(TAG, "field " + eap.getName() );
+ } else if (tempField.getName().trim().equals(INT_IDENTITY)) {
+ identity = tempField;
+ Log.d(TAG, "field " + identity.getName() );
+ } else if (tempField.getName().trim().equals(INT_PASSWORD)) {
+ password = tempField;
+ Log.d(TAG, "field " + password.getName() );
+ } else if (tempField.getName().trim().equals(INT_PHASE2)) {
+ phase2 = tempField;
+ Log.d(TAG, "field " + phase2.getName() );
+
+ } else if (tempField.getName().trim().equals(INT_PRIVATE_KEY)) {
+ privateKey = tempField;
+ }
+ }
+
+
+ Method setValue = null;
+
+ for(Method m: enterpriseFieldClass.getMethods()) {
+ if(m.getName().trim().equals("setValue")) {
+ Log.d(TAG, "method " + m.getName() );
+ setValue = m;
+ break;
+ }
+ }
+
+ try {
+ // EAP
+ String eapmethod = mCredential.getType();
+ Log.d(TAG, "eapmethod:" + eapmethod);
+ setValue.invoke(eap.get(wfg), eapmethod);
+
+ // Username, password, EAP Phase 2
+ if ("TTLS".equals(eapmethod)) {
+ setValue.invoke(phase2.get(wfg), ENTERPRISE_PHASE2_MSCHAPV2);
+ setValue.invoke(identity.get(wfg), mCredential.getUserName());
+ setValue.invoke(password.get(wfg), mCredential.getPassword());
+ setValue.invoke(anonymousId.get(wfg), "anonymous@" + mCredential.getRealm());
+ }
+
+ // EAP CA Certificate
+ String cacertificate = null;
+ String rootCA = mCredential.getCaRootCertPath();
+ if (rootCA == null){
+ cacertificate = null;
+ } else {
+ cacertificate = "keystore://" + Credentials.WIFI + "HS20" + Credentials.CA_CERTIFICATE + rootCA;
+ }
+ Log.d(TAG, "cacertificate:" + cacertificate);
+ setValue.invoke(caCert.get(wfg), cacertificate);
+
+ //User certificate
+ if ("TLS".equals(eapmethod)) {
+ String usercertificate = null;
+ String privatekey = null;
+ String clientCertPath = mCredential.getClientCertPath();
+ if (clientCertPath != null){
+ privatekey = "keystore://" + Credentials.WIFI + "HS20" + Credentials.USER_PRIVATE_KEY + clientCertPath;
+ usercertificate = "keystore://" + Credentials.WIFI + "HS20" + Credentials.USER_CERTIFICATE + clientCertPath;
+ }
+ Log.d(TAG, "privatekey:" + privatekey);
+ Log.d(TAG, "usercertificate:" + usercertificate);
+ if (privatekey != null && usercertificate != null) {
+ setValue.invoke(privateKey.get(wfg), privatekey);
+ setValue.invoke(clientCert.get(wfg), usercertificate);
+ }
+ }
+ } catch (Exception e) {
+ Log.d(TAG, "createWifiConfiguration err:" + e);
+ }
+
+ return wfg;
+ }
+
+ /** {@inheritDoc} @hide */
+ public int compareTo(WifiPasspointPolicy another) {
+ Log.d(TAG, "this:" + this);
+ Log.d(TAG, "another:" + another);
+
+ if (another == null) {
+ return -1;
+ } else if (this.mIsHomeSp == true && another.isHomeSp() == false) {
+ //home sp priority is higher then roaming
+ Log.d(TAG, "compare HomeSP first, this is HomeSP, another isn't");
+ return -1;
+ } else if ((this.mIsHomeSp == true && another.isHomeSp() == true)) {
+ Log.d(TAG, "both HomeSP");
+ //if both home sp, compare credential priority
+ if (this.mCredentialPriority < another.getCredentialPriority()) {
+ Log.d(TAG, "this priority is higher");
+ return -1;
+ } else if (this.mCredentialPriority == another.getCredentialPriority()) {
+ Log.d(TAG, "both priorities equal");
+ //if priority still the same, compare name(ssid)
+ if (this.mName.compareTo(another.mName) != 0) {
+ Log.d(TAG, "compare mName return:" + this.mName.compareTo(another.mName));
+ return this.mName.compareTo(another.mName);
+ }
+ /**
+ *if name still the same, compare credential
+ *the device may has two more credentials(TLS,SIM..etc)
+ *it can associate to one AP(same ssid). so we should compare by credential
+ */
+ if (this.mCredential != null && another.mCredential != null) {
+ if (this.mCredential.compareTo(another.mCredential) != 0) {
+ Log.d(TAG,
+ "compare mCredential return:" + this.mName.compareTo(another.mName));
+ return this.mCredential.compareTo(another.mCredential);
+ }
+ }
+ } else {
+ return 1;
+ }
+ } else if ((this.mIsHomeSp == false && another.isHomeSp() == false)) {
+ Log.d(TAG, "both RoamingSp");
+ //if both roaming sp, compare roaming priority(preferredRoamingPartnerList/<X+>/priority)
+ if (this.mRoamingPriority < another.getRoamingPriority()) {
+ Log.d(TAG, "this priority is higher");
+ return -1;
+ } else if (this.mRoamingPriority == another.getRoamingPriority()) {//priority equals, compare name
+ Log.d(TAG, "both priorities equal");
+ //if priority still the same, compare name(ssid)
+ if (this.mName.compareTo(another.mName) != 0) {
+ Log.d(TAG, "compare mName return:" + this.mName.compareTo(another.mName));
+ return this.mName.compareTo(another.mName);
+ }
+ //if name still the same, compare credential
+ if (this.mCredential != null && another.mCredential != null) {
+ if (this.mCredential.compareTo(another.mCredential) != 0) {
+ Log.d(TAG,
+ "compare mCredential return:"
+ + this.mCredential.compareTo(another.mCredential));
+ return this.mCredential.compareTo(another.mCredential);
+ }
+ }
+ } else {
+ return 1;
+ }
+ }
+
+ Log.d(TAG, "both policies equal");
+ return 0;
+ }
+
+ @Override
+ /** @hide */
+ public String toString() {
+ return "PasspointPolicy: name=" + mName + " CredentialPriority=" + mCredentialPriority +
+ " mRoamingPriority" + mRoamingPriority +
+ " ssid=" + mSsid + " restriction=" + mRestriction +
+ " ishomesp=" + mIsHomeSp + " Credential=" + mCredential;
+ }
+
+ /** 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<WifiPasspointPolicy> CREATOR =
+ new Creator<WifiPasspointPolicy>() {
+ @Override
+ public WifiPasspointPolicy createFromParcel(Parcel in) {
+ return null;
+ }
+
+ @Override
+ public WifiPasspointPolicy[] newArray(int size) {
+ return new WifiPasspointPolicy[size];
+ }
+ };
+}