diff options
76 files changed, 7624 insertions, 2777 deletions
diff --git a/Android.mk b/Android.mk index 3b1991cce502..81113f791bee 100644 --- a/Android.mk +++ b/Android.mk @@ -386,6 +386,7 @@ LOCAL_SRC_FILES += \ 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 35423fdcbfe3..f9ea1a7ad1a5 100644 --- a/api/current.txt +++ b/api/current.txt @@ -6662,6 +6662,7 @@ package android.bluetooth.le { field public static final int SCAN_MODE_BALANCED = 1; // 0x1 field public static final int SCAN_MODE_LOW_LATENCY = 2; // 0x2 field public static final int SCAN_MODE_LOW_POWER = 0; // 0x0 + field public static final int SCAN_MODE_OPPORTUNISTIC = -1; // 0xffffffff } public static final class ScanSettings.Builder { @@ -17867,11 +17868,23 @@ package android.net.wifi { 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 +17911,7 @@ package android.net.wifi { 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 +17921,15 @@ package android.net.wifi { 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 +17987,7 @@ package android.net.wifi { 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 +17995,10 @@ package android.net.wifi { 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 +18006,9 @@ package android.net.wifi { 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 +25886,7 @@ package android.provider { 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 +25901,8 @@ package android.provider { 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 +25910,13 @@ package android.provider { 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 +25924,8 @@ package android.provider { 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 +28200,81 @@ package android.system { 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 +28283,10 @@ package android.telecom { 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 +28295,63 @@ package android.telecom { 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 +28545,7 @@ package android.telephony { 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 +28562,8 @@ package android.telephony { 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 729f65618046..a1b53c1441d0 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -6889,6 +6889,7 @@ package android.bluetooth.le { field public static final int SCAN_MODE_BALANCED = 1; // 0x1 field public static final int SCAN_MODE_LOW_LATENCY = 2; // 0x2 field public static final int SCAN_MODE_LOW_POWER = 0; // 0x0 + field public static final int SCAN_MODE_OPPORTUNISTIC = -1; // 0xffffffff field public static final int SCAN_RESULT_TYPE_ABBREVIATED = 1; // 0x1 field public static final int SCAN_RESULT_TYPE_FULL = 0; // 0x0 } @@ -19197,7 +19198,8 @@ package android.net.wifi { } 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 +19209,19 @@ package android.net.wifi { 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 +19229,31 @@ package android.net.wifi { 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 +19272,20 @@ package android.net.wifi { 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 +19294,87 @@ package android.net.wifi { 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 +19401,7 @@ package android.net.wifi { 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 +19411,8 @@ package android.net.wifi { 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 +19423,8 @@ package android.net.wifi { 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 +19497,7 @@ package android.net.wifi { 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 +19505,10 @@ package android.net.wifi { 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 +19516,9 @@ package android.net.wifi { 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 +19682,11 @@ package android.net.wifi { 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 +19723,7 @@ package android.net.wifi { 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 +19739,37 @@ package android.net.wifi { 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 +19778,7 @@ package android.net.wifi { 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 +27572,7 @@ package android.provider { 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 +27587,8 @@ package android.provider { 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 +27596,13 @@ package android.provider { 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 +27610,8 @@ package android.provider { 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 +30024,22 @@ package android.telecom { 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 +30346,14 @@ package android.telecom { 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 +30366,9 @@ package android.telecom { 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 +30384,11 @@ package android.telecom { 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 +30513,7 @@ package android.telecom { 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 +30525,7 @@ package android.telecom { 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 +30534,63 @@ package android.telecom { 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 +30784,7 @@ package android.telephony { 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 +30801,8 @@ package android.telephony { 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 7eae4398e59d..0106686f8f82 100644 --- a/core/java/android/bluetooth/le/ScanSettings.java +++ b/core/java/android/bluetooth/le/ScanSettings.java @@ -25,6 +25,13 @@ import android.os.Parcelable; * 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. + */ + 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 +184,7 @@ public final class ScanSettings implements Parcelable { * @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 000000000000..a25847daa8f2 --- /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/BaseNetworkStateTracker.java b/core/java/android/net/BaseNetworkStateTracker.java deleted file mode 100644 index e4e5b1e35d6c..000000000000 --- a/core/java/android/net/BaseNetworkStateTracker.java +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Copyright (C) 2012 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.content.Context; -import android.os.Handler; -import android.os.Messenger; - -import java.util.concurrent.atomic.AtomicBoolean; - -import com.android.internal.util.Preconditions; - -/** - * Interface to control and observe state of a specific network, hiding - * network-specific details from {@link ConnectivityManager}. Surfaces events - * through the registered {@link Handler} to enable {@link ConnectivityManager} - * to respond to state changes over time. - * - * @hide - */ -public abstract class BaseNetworkStateTracker implements NetworkStateTracker { - // TODO: better document threading expectations - // TODO: migrate to make NetworkStateTracker abstract class - - public static final String PROP_TCP_BUFFER_UNKNOWN = "net.tcp.buffersize.unknown"; - public static final String PROP_TCP_BUFFER_WIFI = "net.tcp.buffersize.wifi"; - - protected Context mContext; - private Handler mTarget; - - protected NetworkInfo mNetworkInfo; - protected LinkProperties mLinkProperties; - protected NetworkCapabilities mNetworkCapabilities; - protected Network mNetwork = new Network(ConnectivityManager.NETID_UNSET); - - private AtomicBoolean mTeardownRequested = new AtomicBoolean(false); - private AtomicBoolean mPrivateDnsRouteSet = new AtomicBoolean(false); - private AtomicBoolean mDefaultRouteSet = new AtomicBoolean(false); - - public BaseNetworkStateTracker(int networkType) { - mNetworkInfo = new NetworkInfo( - networkType, -1, ConnectivityManager.getNetworkTypeName(networkType), null); - mLinkProperties = new LinkProperties(); - mNetworkCapabilities = new NetworkCapabilities(); - } - - protected BaseNetworkStateTracker() { - // By default, let the sub classes construct everything - } - - @Deprecated - protected Handler getTargetHandler() { - return mTarget; - } - - protected final void dispatchStateChanged() { - // TODO: include snapshot of other fields when sending - mTarget.obtainMessage(EVENT_STATE_CHANGED, getNetworkInfo()).sendToTarget(); - } - - protected final void dispatchConfigurationChanged() { - // TODO: include snapshot of other fields when sending - mTarget.obtainMessage(EVENT_CONFIGURATION_CHANGED, getNetworkInfo()).sendToTarget(); - } - - @Override - public void startMonitoring(Context context, Handler target) { - mContext = Preconditions.checkNotNull(context); - mTarget = Preconditions.checkNotNull(target); - startMonitoringInternal(); - } - - protected void startMonitoringInternal() { - - } - - @Override - public NetworkInfo getNetworkInfo() { - return new NetworkInfo(mNetworkInfo); - } - - @Override - public LinkProperties getLinkProperties() { - return new LinkProperties(mLinkProperties); - } - - @Override - public NetworkCapabilities getNetworkCapabilities() { - return new NetworkCapabilities(mNetworkCapabilities); - } - - @Override - public LinkQualityInfo getLinkQualityInfo() { - return null; - } - - @Override - public void captivePortalCheckCompleted(boolean isCaptivePortal) { - // not implemented - } - - @Override - public boolean setRadio(boolean turnOn) { - // Base tracker doesn't handle radios - return true; - } - - @Override - public boolean isAvailable() { - return mNetworkInfo.isAvailable(); - } - - @Override - public void setUserDataEnable(boolean enabled) { - // Base tracker doesn't handle enabled flags - } - - @Override - public void setPolicyDataEnable(boolean enabled) { - // Base tracker doesn't handle enabled flags - } - - @Override - public boolean isPrivateDnsRouteSet() { - return mPrivateDnsRouteSet.get(); - } - - @Override - public void privateDnsRouteSet(boolean enabled) { - mPrivateDnsRouteSet.set(enabled); - } - - @Override - public boolean isDefaultRouteSet() { - return mDefaultRouteSet.get(); - } - - @Override - public void defaultRouteSet(boolean enabled) { - mDefaultRouteSet.set(enabled); - } - - @Override - public boolean isTeardownRequested() { - return mTeardownRequested.get(); - } - - @Override - public void setTeardownRequested(boolean isRequested) { - mTeardownRequested.set(isRequested); - } - - @Override - public void setDependencyMet(boolean met) { - // Base tracker doesn't handle dependencies - } - - @Override - public void supplyMessenger(Messenger messenger) { - // not supported on this network - } - - @Override - public String getNetworkInterfaceName() { - if (mLinkProperties != null) { - return mLinkProperties.getInterfaceName(); - } else { - return null; - } - } - - @Override - public void startSampling(SamplingDataTracker.SamplingSnapshot s) { - // nothing to do - } - - @Override - public void stopSampling(SamplingDataTracker.SamplingSnapshot s) { - // nothing to do - } - - @Override - public void setNetId(int netId) { - mNetwork = new Network(netId); - } - - @Override - public Network getNetwork() { - return mNetwork; - } -} diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java index eb2df0bf0dd6..a00246fd99b4 100644 --- a/core/java/android/net/ConnectivityManager.java +++ b/core/java/android/net/ConnectivityManager.java @@ -1793,25 +1793,6 @@ public class ConnectivityManager { } /** - * Sets a secondary requirement bit for the given networkType. - * This requirement bit is generally under the control of the carrier - * or its agents and is not directly controlled by the user. - * - * @param networkType The network who's dependence has changed - * @param met Boolean - true if network use is OK, false if not - * - * <p>This method requires the call to hold the permission - * {@link android.Manifest.permission#CONNECTIVITY_INTERNAL}. - * {@hide} - */ - public void setDataDependency(int networkType, boolean met) { - try { - mService.setDataDependency(networkType, met); - } catch (RemoteException e) { - } - } - - /** * Returns true if the hardware supports the given network type * else it returns false. This doesn't indicate we have coverage * or are authorized onto a network, just whether or not the @@ -1892,20 +1873,6 @@ public class ConnectivityManager { } /** - * Supply the backend messenger for a network tracker - * - * @param networkType NetworkType to set - * @param messenger {@link Messenger} - * {@hide} - */ - public void supplyMessenger(int networkType, Messenger messenger) { - try { - mService.supplyMessenger(networkType, messenger); - } catch (RemoteException e) { - } - } - - /** * Check mobile provisioning. * * @param suggestedTimeOutMs, timeout in milliseconds @@ -2370,7 +2337,7 @@ public class ConnectivityManager { * 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 5151a04b577b..1b8adc8e24bf 100644 --- a/core/java/android/net/DhcpStateMachine.java +++ b/core/java/android/net/DhcpStateMachine.java @@ -47,7 +47,7 @@ import android.util.Log; * * @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 @@ public class DhcpStateMachine extends StateMachine { * 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 @@ public class DhcpStateMachine extends StateMachine { * * @hide */ + @Override public void doQuit() { quit(); } diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl index 46af112d1d49..d8852f882cae 100644 --- a/core/java/android/net/IConnectivityManager.aidl +++ b/core/java/android/net/IConnectivityManager.aidl @@ -102,8 +102,6 @@ interface IConnectivityManager ProxyInfo getDefaultProxy(); - void setDataDependency(int networkType, boolean met); - boolean prepareVpn(String oldPackage, String newPackage); void setVpnPackageAuthorization(boolean authorized); @@ -120,8 +118,6 @@ interface IConnectivityManager void captivePortalCheckCompleted(in NetworkInfo info, boolean isCaptivePortal); - void supplyMessenger(int networkType, in Messenger messenger); - int findConnectionTypeForIface(in String iface); int checkMobileProvisioning(int suggestedTimeOutMs); diff --git a/core/java/android/net/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java deleted file mode 100644 index abbb7b8eeb4e..000000000000 --- a/core/java/android/net/MobileDataStateTracker.java +++ /dev/null @@ -1,910 +0,0 @@ -/* - * Copyright (C) 2008 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.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.net.NetworkInfo.DetailedState; -import android.os.Bundle; -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.os.Messenger; -import android.os.RemoteException; -import android.os.ServiceManager; -import android.telephony.PhoneStateListener; -import android.telephony.SignalStrength; -import android.telephony.TelephonyManager; -import android.text.TextUtils; -import android.util.Slog; - -import com.android.internal.telephony.DctConstants; -import com.android.internal.telephony.ITelephony; -import com.android.internal.telephony.PhoneConstants; -import com.android.internal.telephony.TelephonyIntents; -import com.android.internal.util.AsyncChannel; - -import java.io.CharArrayWriter; -import java.io.PrintWriter; -import java.util.concurrent.atomic.AtomicBoolean; - -/** - * Track the state of mobile data connectivity. This is done by - * receiving broadcast intents from the Phone process whenever - * the state of data connectivity changes. - * - * {@hide} - */ -public class MobileDataStateTracker extends BaseNetworkStateTracker { - - private static final String TAG = "MobileDataStateTracker"; - private static final boolean DBG = false; - private static final boolean VDBG = false; - - private PhoneConstants.DataState mMobileDataState; - private ITelephony mPhoneService; - - private String mApnType; - private NetworkInfo mNetworkInfo; - private boolean mTeardownRequested = false; - private Handler mTarget; - private Context mContext; - private LinkProperties mLinkProperties; - private boolean mPrivateDnsRouteSet = false; - private boolean mDefaultRouteSet = false; - - // NOTE: these are only kept for debugging output; actual values are - // maintained in DataConnectionTracker. - protected boolean mUserDataEnabled = true; - protected boolean mPolicyDataEnabled = true; - - private Handler mHandler; - private AsyncChannel mDataConnectionTrackerAc; - - private AtomicBoolean mIsCaptivePortal = new AtomicBoolean(false); - - private SignalStrength mSignalStrength; - - private SamplingDataTracker mSamplingDataTracker = new SamplingDataTracker(); - - private static final int UNKNOWN = LinkQualityInfo.UNKNOWN_INT; - - /** - * Create a new MobileDataStateTracker - * @param netType the ConnectivityManager network type - * @param tag the name of this network - */ - public MobileDataStateTracker(int netType, String tag) { - mNetworkInfo = new NetworkInfo(netType, - TelephonyManager.getDefault().getNetworkType(), tag, - TelephonyManager.getDefault().getNetworkTypeName()); - mApnType = networkTypeToApnType(netType); - } - - /** - * Begin monitoring data connectivity. - * - * @param context is the current Android context - * @param target is the Hander to which to return the events. - */ - public void startMonitoring(Context context, Handler target) { - mTarget = target; - mContext = context; - - mHandler = new MdstHandler(target.getLooper(), this); - - IntentFilter filter = new IntentFilter(); - filter.addAction(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED); - filter.addAction(TelephonyIntents.ACTION_DATA_CONNECTION_CONNECTED_TO_PROVISIONING_APN); - filter.addAction(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED); - - mContext.registerReceiver(new MobileDataStateReceiver(), filter); - mMobileDataState = PhoneConstants.DataState.DISCONNECTED; - - TelephonyManager tm = (TelephonyManager)mContext.getSystemService( - Context.TELEPHONY_SERVICE); - tm.listen(mPhoneStateListener, PhoneStateListener.LISTEN_SIGNAL_STRENGTHS); - } - - private final PhoneStateListener mPhoneStateListener = new PhoneStateListener() { - @Override - public void onSignalStrengthsChanged(SignalStrength signalStrength) { - mSignalStrength = signalStrength; - } - }; - - static class MdstHandler extends Handler { - private MobileDataStateTracker mMdst; - - MdstHandler(Looper looper, MobileDataStateTracker mdst) { - super(looper); - mMdst = mdst; - } - - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED: - if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) { - if (VDBG) { - mMdst.log("MdstHandler connected"); - } - mMdst.mDataConnectionTrackerAc = (AsyncChannel) msg.obj; - } else { - if (VDBG) { - mMdst.log("MdstHandler %s NOT connected error=" + msg.arg1); - } - } - break; - case AsyncChannel.CMD_CHANNEL_DISCONNECTED: - if (VDBG) mMdst.log("Disconnected from DataStateTracker"); - mMdst.mDataConnectionTrackerAc = null; - break; - default: { - if (VDBG) mMdst.log("Ignorning unknown message=" + msg); - break; - } - } - } - } - - public boolean isPrivateDnsRouteSet() { - return mPrivateDnsRouteSet; - } - - public void privateDnsRouteSet(boolean enabled) { - mPrivateDnsRouteSet = enabled; - } - - public NetworkInfo getNetworkInfo() { - return mNetworkInfo; - } - - public boolean isDefaultRouteSet() { - return mDefaultRouteSet; - } - - public void defaultRouteSet(boolean enabled) { - mDefaultRouteSet = enabled; - } - - /** - * This is not implemented. - */ - public void releaseWakeLock() { - } - - private void updateLinkProperitesAndCapatilities(Intent intent) { - mLinkProperties = intent.getParcelableExtra( - PhoneConstants.DATA_LINK_PROPERTIES_KEY); - if (mLinkProperties == null) { - loge("CONNECTED event did not supply link properties."); - mLinkProperties = new LinkProperties(); - } - mLinkProperties.setMtu(mContext.getResources().getInteger( - com.android.internal.R.integer.config_mobile_mtu)); - mNetworkCapabilities = intent.getParcelableExtra( - PhoneConstants.DATA_NETWORK_CAPABILITIES_KEY); - if (mNetworkCapabilities == null) { - loge("CONNECTED event did not supply network capabilities."); - mNetworkCapabilities = new NetworkCapabilities(); - } - } - - private class MobileDataStateReceiver extends BroadcastReceiver { - @Override - public void onReceive(Context context, Intent intent) { - if (intent.getAction().equals(TelephonyIntents. - ACTION_DATA_CONNECTION_CONNECTED_TO_PROVISIONING_APN)) { - String apnName = intent.getStringExtra(PhoneConstants.DATA_APN_KEY); - String apnType = intent.getStringExtra(PhoneConstants.DATA_APN_TYPE_KEY); - if (!TextUtils.equals(mApnType, apnType)) { - return; - } - if (DBG) { - log("Broadcast received: " + intent.getAction() + " apnType=" + apnType - + " apnName=" + apnName); - } - - // Make us in the connecting state until we make a new TYPE_MOBILE_PROVISIONING - mMobileDataState = PhoneConstants.DataState.CONNECTING; - updateLinkProperitesAndCapatilities(intent); - mNetworkInfo.setIsConnectedToProvisioningNetwork(true); - - // Change state to SUSPENDED so setDetailedState - // sends EVENT_STATE_CHANGED to connectivityService - setDetailedState(DetailedState.SUSPENDED, "", apnName); - } else if (intent.getAction().equals(TelephonyIntents. - ACTION_ANY_DATA_CONNECTION_STATE_CHANGED)) { - String apnType = intent.getStringExtra(PhoneConstants.DATA_APN_TYPE_KEY); - if (VDBG) { - log(String.format("Broadcast received: ACTION_ANY_DATA_CONNECTION_STATE_CHANGED" - + "mApnType=%s %s received apnType=%s", mApnType, - TextUtils.equals(apnType, mApnType) ? "==" : "!=", apnType)); - } - if (!TextUtils.equals(apnType, mApnType)) { - return; - } - // Assume this isn't a provisioning network. - mNetworkInfo.setIsConnectedToProvisioningNetwork(false); - if (DBG) { - log("Broadcast received: " + intent.getAction() + " apnType=" + apnType); - } - - int oldSubtype = mNetworkInfo.getSubtype(); - int newSubType = TelephonyManager.getDefault().getNetworkType(); - String subTypeName = TelephonyManager.getDefault().getNetworkTypeName(); - mNetworkInfo.setSubtype(newSubType, subTypeName); - if (newSubType != oldSubtype && mNetworkInfo.isConnected()) { - Message msg = mTarget.obtainMessage(EVENT_NETWORK_SUBTYPE_CHANGED, - oldSubtype, 0, mNetworkInfo); - msg.sendToTarget(); - } - - PhoneConstants.DataState state = Enum.valueOf(PhoneConstants.DataState.class, - intent.getStringExtra(PhoneConstants.STATE_KEY)); - String reason = intent.getStringExtra(PhoneConstants.STATE_CHANGE_REASON_KEY); - String apnName = intent.getStringExtra(PhoneConstants.DATA_APN_KEY); - mNetworkInfo.setRoaming(intent.getBooleanExtra( - PhoneConstants.DATA_NETWORK_ROAMING_KEY, false)); - if (VDBG) { - log(mApnType + " setting isAvailable to " + - intent.getBooleanExtra(PhoneConstants.NETWORK_UNAVAILABLE_KEY,false)); - } - mNetworkInfo.setIsAvailable(!intent.getBooleanExtra( - PhoneConstants.NETWORK_UNAVAILABLE_KEY, false)); - - if (DBG) { - log("Received state=" + state + ", old=" + mMobileDataState + - ", reason=" + (reason == null ? "(unspecified)" : reason)); - } - if (mMobileDataState != state) { - mMobileDataState = state; - switch (state) { - case DISCONNECTED: - if(isTeardownRequested()) { - setTeardownRequested(false); - } - - setDetailedState(DetailedState.DISCONNECTED, reason, apnName); - // can't do this here - ConnectivityService needs it to clear stuff - // it's ok though - just leave it to be refreshed next time - // we connect. - //if (DBG) log("clearing mInterfaceName for "+ mApnType + - // " as it DISCONNECTED"); - //mInterfaceName = null; - break; - case CONNECTING: - setDetailedState(DetailedState.CONNECTING, reason, apnName); - break; - case SUSPENDED: - setDetailedState(DetailedState.SUSPENDED, reason, apnName); - break; - case CONNECTED: - updateLinkProperitesAndCapatilities(intent); - setDetailedState(DetailedState.CONNECTED, reason, apnName); - break; - } - - if (VDBG) { - Slog.d(TAG, "TelephonyMgr.DataConnectionStateChanged"); - if (mNetworkInfo != null) { - Slog.d(TAG, "NetworkInfo = " + mNetworkInfo); - Slog.d(TAG, "subType = " + mNetworkInfo.getSubtype()); - Slog.d(TAG, "subType = " + mNetworkInfo.getSubtypeName()); - } - if (mLinkProperties != null) { - Slog.d(TAG, "LinkProperties = " + mLinkProperties); - } else { - Slog.d(TAG, "LinkProperties = " ); - } - - if (mNetworkCapabilities != null) { - Slog.d(TAG, mNetworkCapabilities.toString()); - } else { - Slog.d(TAG, "NetworkCapabilities = " ); - } - } - - - /* lets not sample traffic data across state changes */ - mSamplingDataTracker.resetSamplingData(); - } else { - // There was no state change. Check if LinkProperties has been updated. - if (TextUtils.equals(reason, PhoneConstants.REASON_LINK_PROPERTIES_CHANGED)) { - mLinkProperties = intent.getParcelableExtra( - PhoneConstants.DATA_LINK_PROPERTIES_KEY); - if (mLinkProperties == null) { - loge("No link property in LINK_PROPERTIES change event."); - mLinkProperties = new LinkProperties(); - } - // Just update reason field in this NetworkInfo - mNetworkInfo.setDetailedState(mNetworkInfo.getDetailedState(), reason, - mNetworkInfo.getExtraInfo()); - Message msg = mTarget.obtainMessage(EVENT_CONFIGURATION_CHANGED, - mNetworkInfo); - msg.sendToTarget(); - } - } - } else if (intent.getAction(). - equals(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED)) { - String apnType = intent.getStringExtra(PhoneConstants.DATA_APN_TYPE_KEY); - if (!TextUtils.equals(apnType, mApnType)) { - if (DBG) { - log(String.format( - "Broadcast received: ACTION_ANY_DATA_CONNECTION_FAILED ignore, " + - "mApnType=%s != received apnType=%s", mApnType, apnType)); - } - return; - } - // Assume this isn't a provisioning network. - mNetworkInfo.setIsConnectedToProvisioningNetwork(false); - String reason = intent.getStringExtra(PhoneConstants.FAILURE_REASON_KEY); - String apnName = intent.getStringExtra(PhoneConstants.DATA_APN_KEY); - if (DBG) { - log("Broadcast received: " + intent.getAction() + - " reason=" + reason == null ? "null" : reason); - } - setDetailedState(DetailedState.FAILED, reason, apnName); - } else { - if (DBG) log("Broadcast received: ignore " + intent.getAction()); - } - } - } - - private void getPhoneService(boolean forceRefresh) { - if ((mPhoneService == null) || forceRefresh) { - mPhoneService = ITelephony.Stub.asInterface(ServiceManager.getService("phone")); - } - } - - /** - * Report whether data connectivity is possible. - */ - public boolean isAvailable() { - return mNetworkInfo.isAvailable(); - } - - /** - * Return the system properties name associated with the tcp buffer sizes - * for this network. - */ - public String getTcpBufferSizesPropName() { - String networkTypeStr = "unknown"; - TelephonyManager tm = new TelephonyManager(mContext); - //TODO We have to edit the parameter for getNetworkType regarding CDMA - switch(tm.getNetworkType()) { - case TelephonyManager.NETWORK_TYPE_GPRS: - networkTypeStr = "gprs"; - break; - case TelephonyManager.NETWORK_TYPE_EDGE: - networkTypeStr = "edge"; - break; - case TelephonyManager.NETWORK_TYPE_UMTS: - networkTypeStr = "umts"; - break; - case TelephonyManager.NETWORK_TYPE_HSDPA: - networkTypeStr = "hsdpa"; - break; - case TelephonyManager.NETWORK_TYPE_HSUPA: - networkTypeStr = "hsupa"; - break; - case TelephonyManager.NETWORK_TYPE_HSPA: - networkTypeStr = "hspa"; - break; - case TelephonyManager.NETWORK_TYPE_HSPAP: - networkTypeStr = "hspap"; - break; - case TelephonyManager.NETWORK_TYPE_CDMA: - networkTypeStr = "cdma"; - break; - case TelephonyManager.NETWORK_TYPE_1xRTT: - networkTypeStr = "1xrtt"; - break; - case TelephonyManager.NETWORK_TYPE_EVDO_0: - networkTypeStr = "evdo"; - break; - case TelephonyManager.NETWORK_TYPE_EVDO_A: - networkTypeStr = "evdo"; - break; - case TelephonyManager.NETWORK_TYPE_EVDO_B: - networkTypeStr = "evdo"; - break; - case TelephonyManager.NETWORK_TYPE_IDEN: - networkTypeStr = "iden"; - break; - case TelephonyManager.NETWORK_TYPE_LTE: - case TelephonyManager.NETWORK_TYPE_IWLAN: - networkTypeStr = "lte"; - break; - case TelephonyManager.NETWORK_TYPE_EHRPD: - networkTypeStr = "ehrpd"; - break; - default: - loge("unknown network type: " + tm.getNetworkType()); - } - return "net.tcp.buffersize." + networkTypeStr; - } - - /** - * Tear down mobile data connectivity, i.e., disable the ability to create - * mobile data connections. - * TODO - make async and return nothing? - */ - public boolean teardown() { - setTeardownRequested(true); - return (setEnableApn(mApnType, false) != PhoneConstants.APN_REQUEST_FAILED); - } - - /** - * @return true if this is ready to operate - */ - public boolean isReady() { - return mDataConnectionTrackerAc != null; - } - - @Override - public void captivePortalCheckCompleted(boolean isCaptivePortal) { - if (mIsCaptivePortal.getAndSet(isCaptivePortal) != isCaptivePortal) { - // Captive portal change enable/disable failing fast - setEnableFailFastMobileData( - isCaptivePortal ? DctConstants.ENABLED : DctConstants.DISABLED); - } - } - - /** - * Record the detailed state of a network, and if it is a - * change from the previous state, send a notification to - * any listeners. - * @param state the new {@code DetailedState} - * @param reason a {@code String} indicating a reason for the state change, - * if one was supplied. May be {@code null}. - * @param extraInfo optional {@code String} providing extra information about the state change - */ - private void setDetailedState(NetworkInfo.DetailedState state, String reason, - String extraInfo) { - if (DBG) log("setDetailed state, old =" - + mNetworkInfo.getDetailedState() + " and new state=" + state); - if (state != mNetworkInfo.getDetailedState()) { - boolean wasConnecting = (mNetworkInfo.getState() == NetworkInfo.State.CONNECTING); - String lastReason = mNetworkInfo.getReason(); - /* - * If a reason was supplied when the CONNECTING state was entered, and no - * reason was supplied for entering the CONNECTED state, then retain the - * reason that was supplied when going to CONNECTING. - */ - if (wasConnecting && state == NetworkInfo.DetailedState.CONNECTED && reason == null - && lastReason != null) - reason = lastReason; - mNetworkInfo.setDetailedState(state, reason, extraInfo); - Message msg = mTarget.obtainMessage(EVENT_STATE_CHANGED, new NetworkInfo(mNetworkInfo)); - msg.sendToTarget(); - } - } - - public void setTeardownRequested(boolean isRequested) { - mTeardownRequested = isRequested; - } - - public boolean isTeardownRequested() { - return mTeardownRequested; - } - - /** - * Re-enable mobile data connectivity after a {@link #teardown()}. - * TODO - make async and always get a notification? - */ - public boolean reconnect() { - boolean retValue = false; //connected or expect to be? - setTeardownRequested(false); - switch (setEnableApn(mApnType, true)) { - case PhoneConstants.APN_ALREADY_ACTIVE: - // need to set self to CONNECTING so the below message is handled. - retValue = true; - break; - case PhoneConstants.APN_REQUEST_STARTED: - // set IDLE here , avoid the following second FAILED not sent out - mNetworkInfo.setDetailedState(DetailedState.IDLE, null, null); - retValue = true; - break; - case PhoneConstants.APN_REQUEST_FAILED: - case PhoneConstants.APN_TYPE_NOT_AVAILABLE: - break; - default: - loge("Error in reconnect - unexpected response."); - break; - } - return retValue; - } - - /** - * Turn on or off the mobile radio. No connectivity will be possible while the - * radio is off. The operation is a no-op if the radio is already in the desired state. - * @param turnOn {@code true} if the radio should be turned on, {@code false} if - */ - public boolean setRadio(boolean turnOn) { - getPhoneService(false); - /* - * If the phone process has crashed in the past, we'll get a - * RemoteException and need to re-reference the service. - */ - for (int retry = 0; retry < 2; retry++) { - if (mPhoneService == null) { - loge("Ignoring mobile radio request because could not acquire PhoneService"); - break; - } - - try { - return mPhoneService.setRadio(turnOn); - } catch (RemoteException e) { - if (retry == 0) getPhoneService(true); - } - } - - loge("Could not set radio power to " + (turnOn ? "on" : "off")); - return false; - } - - - public void setInternalDataEnable(boolean enabled) { - if (DBG) log("setInternalDataEnable: E enabled=" + enabled); - final AsyncChannel channel = mDataConnectionTrackerAc; - if (channel != null) { - channel.sendMessage(DctConstants.EVENT_SET_INTERNAL_DATA_ENABLE, - enabled ? DctConstants.ENABLED : DctConstants.DISABLED); - } - if (VDBG) log("setInternalDataEnable: X enabled=" + enabled); - } - - @Override - public void setUserDataEnable(boolean enabled) { - if (DBG) log("setUserDataEnable: E enabled=" + enabled); - final AsyncChannel channel = mDataConnectionTrackerAc; - if (channel != null) { - channel.sendMessage(DctConstants.CMD_SET_USER_DATA_ENABLE, - enabled ? DctConstants.ENABLED : DctConstants.DISABLED); - mUserDataEnabled = enabled; - } - if (VDBG) log("setUserDataEnable: X enabled=" + enabled); - } - - @Override - public void setPolicyDataEnable(boolean enabled) { - if (DBG) log("setPolicyDataEnable(enabled=" + enabled + ")"); - final AsyncChannel channel = mDataConnectionTrackerAc; - if (channel != null) { - channel.sendMessage(DctConstants.CMD_SET_POLICY_DATA_ENABLE, - enabled ? DctConstants.ENABLED : DctConstants.DISABLED); - mPolicyDataEnabled = enabled; - } - } - - /** - * Eanble/disable FailFast - * - * @param enabled is DctConstants.ENABLED/DISABLED - */ - public void setEnableFailFastMobileData(int enabled) { - if (DBG) log("setEnableFailFastMobileData(enabled=" + enabled + ")"); - final AsyncChannel channel = mDataConnectionTrackerAc; - if (channel != null) { - channel.sendMessage(DctConstants.CMD_SET_ENABLE_FAIL_FAST_MOBILE_DATA, enabled); - } - } - - /** - * carrier dependency is met/unmet - * @param met - */ - public void setDependencyMet(boolean met) { - Bundle bundle = Bundle.forPair(DctConstants.APN_TYPE_KEY, mApnType); - try { - if (DBG) log("setDependencyMet: E met=" + met); - Message msg = Message.obtain(); - msg.what = DctConstants.CMD_SET_DEPENDENCY_MET; - msg.arg1 = (met ? DctConstants.ENABLED : DctConstants.DISABLED); - msg.setData(bundle); - mDataConnectionTrackerAc.sendMessage(msg); - if (VDBG) log("setDependencyMet: X met=" + met); - } catch (NullPointerException e) { - loge("setDependencyMet: X mAc was null" + e); - } - } - - /** - * Inform DCT mobile provisioning has started, it ends when provisioning completes. - */ - public void enableMobileProvisioning(String url) { - if (DBG) log("enableMobileProvisioning(url=" + url + ")"); - final AsyncChannel channel = mDataConnectionTrackerAc; - if (channel != null) { - Message msg = Message.obtain(); - msg.what = DctConstants.CMD_ENABLE_MOBILE_PROVISIONING; - msg.setData(Bundle.forPair(DctConstants.PROVISIONING_URL_KEY, url)); - channel.sendMessage(msg); - } - } - - /** - * Return if this network is the provisioning network. Valid only if connected. - * @param met - */ - public boolean isProvisioningNetwork() { - boolean retVal; - try { - Message msg = Message.obtain(); - msg.what = DctConstants.CMD_IS_PROVISIONING_APN; - msg.setData(Bundle.forPair(DctConstants.APN_TYPE_KEY, mApnType)); - Message result = mDataConnectionTrackerAc.sendMessageSynchronously(msg); - retVal = result.arg1 == DctConstants.ENABLED; - } catch (NullPointerException e) { - loge("isProvisioningNetwork: X " + e); - retVal = false; - } - if (DBG) log("isProvisioningNetwork: retVal=" + retVal); - return retVal; - } - - @Override - public String toString() { - final CharArrayWriter writer = new CharArrayWriter(); - final PrintWriter pw = new PrintWriter(writer); - pw.print("Mobile data state: "); pw.println(mMobileDataState); - pw.print("Data enabled: user="); pw.print(mUserDataEnabled); - pw.print(", policy="); pw.println(mPolicyDataEnabled); - return writer.toString(); - } - - /** - * Internal method supporting the ENABLE_MMS feature. - * @param apnType the type of APN to be enabled or disabled (e.g., mms) - * @param enable {@code true} to enable the specified APN type, - * {@code false} to disable it. - * @return an integer value representing the outcome of the request. - */ - private int setEnableApn(String apnType, boolean enable) { - getPhoneService(false); - /* - * If the phone process has crashed in the past, we'll get a - * RemoteException and need to re-reference the service. - */ - for (int retry = 0; retry < 2; retry++) { - if (mPhoneService == null) { - loge("Ignoring feature request because could not acquire PhoneService"); - break; - } - -// try { -// if (enable) { -// return mPhoneService.enableApnType(apnType); -// } else { -// return mPhoneService.disableApnType(apnType); -// } -// } catch (RemoteException e) { -// if (retry == 0) getPhoneService(true); -// } - } - - loge("Could not " + (enable ? "enable" : "disable") + " APN type \"" + apnType + "\""); - return PhoneConstants.APN_REQUEST_FAILED; - } - - public static String networkTypeToApnType(int netType) { - switch(netType) { - case ConnectivityManager.TYPE_MOBILE: - return PhoneConstants.APN_TYPE_DEFAULT; // TODO - use just one of these - case ConnectivityManager.TYPE_MOBILE_MMS: - return PhoneConstants.APN_TYPE_MMS; - case ConnectivityManager.TYPE_MOBILE_SUPL: - return PhoneConstants.APN_TYPE_SUPL; - case ConnectivityManager.TYPE_MOBILE_DUN: - return PhoneConstants.APN_TYPE_DUN; - case ConnectivityManager.TYPE_MOBILE_HIPRI: - return PhoneConstants.APN_TYPE_HIPRI; - case ConnectivityManager.TYPE_MOBILE_FOTA: - return PhoneConstants.APN_TYPE_FOTA; - case ConnectivityManager.TYPE_MOBILE_IMS: - return PhoneConstants.APN_TYPE_IMS; - case ConnectivityManager.TYPE_MOBILE_CBS: - return PhoneConstants.APN_TYPE_CBS; - case ConnectivityManager.TYPE_MOBILE_IA: - return PhoneConstants.APN_TYPE_IA; - case ConnectivityManager.TYPE_MOBILE_EMERGENCY: - return PhoneConstants.APN_TYPE_EMERGENCY; - default: - sloge("Error mapping networkType " + netType + " to apnType."); - return null; - } - } - - - /** - * @see android.net.NetworkStateTracker#getLinkProperties() - */ - @Override - public LinkProperties getLinkProperties() { - return new LinkProperties(mLinkProperties); - } - - public void supplyMessenger(Messenger messenger) { - if (VDBG) log(mApnType + " got supplyMessenger"); - AsyncChannel ac = new AsyncChannel(); - ac.connect(mContext, MobileDataStateTracker.this.mHandler, messenger); - } - - private void log(String s) { - Slog.d(TAG, mApnType + ": " + s); - } - - private void loge(String s) { - Slog.e(TAG, mApnType + ": " + s); - } - - static private void sloge(String s) { - Slog.e(TAG, s); - } - - @Override - public LinkQualityInfo getLinkQualityInfo() { - if (mNetworkInfo == null || mNetworkInfo.getType() == ConnectivityManager.TYPE_NONE) { - // no data available yet; just return - return null; - } - - MobileLinkQualityInfo li = new MobileLinkQualityInfo(); - - li.setNetworkType(mNetworkInfo.getType()); - - mSamplingDataTracker.setCommonLinkQualityInfoFields(li); - - if (mNetworkInfo.getSubtype() != TelephonyManager.NETWORK_TYPE_UNKNOWN) { - li.setMobileNetworkType(mNetworkInfo.getSubtype()); - - NetworkDataEntry entry = getNetworkDataEntry(mNetworkInfo.getSubtype()); - if (entry != null) { - li.setTheoreticalRxBandwidth(entry.downloadBandwidth); - li.setTheoreticalRxBandwidth(entry.uploadBandwidth); - li.setTheoreticalLatency(entry.latency); - } - - if (mSignalStrength != null) { - li.setNormalizedSignalStrength(getNormalizedSignalStrength( - li.getMobileNetworkType(), mSignalStrength)); - } - } - - SignalStrength ss = mSignalStrength; - if (ss != null) { - - li.setRssi(ss.getGsmSignalStrength()); - li.setGsmErrorRate(ss.getGsmBitErrorRate()); - li.setCdmaDbm(ss.getCdmaDbm()); - li.setCdmaEcio(ss.getCdmaEcio()); - li.setEvdoDbm(ss.getEvdoDbm()); - li.setEvdoEcio(ss.getEvdoEcio()); - li.setEvdoSnr(ss.getEvdoSnr()); - li.setLteSignalStrength(ss.getLteSignalStrength()); - li.setLteRsrp(ss.getLteRsrp()); - li.setLteRsrq(ss.getLteRsrq()); - li.setLteRssnr(ss.getLteRssnr()); - li.setLteCqi(ss.getLteCqi()); - } - - if (VDBG) { - Slog.d(TAG, "Returning LinkQualityInfo with" - + " MobileNetworkType = " + String.valueOf(li.getMobileNetworkType()) - + " Theoretical Rx BW = " + String.valueOf(li.getTheoreticalRxBandwidth()) - + " gsm Signal Strength = " + String.valueOf(li.getRssi()) - + " cdma Signal Strength = " + String.valueOf(li.getCdmaDbm()) - + " evdo Signal Strength = " + String.valueOf(li.getEvdoDbm()) - + " Lte Signal Strength = " + String.valueOf(li.getLteSignalStrength())); - } - - return li; - } - - static class NetworkDataEntry { - public int networkType; - public int downloadBandwidth; // in kbps - public int uploadBandwidth; // in kbps - public int latency; // in millisecond - - NetworkDataEntry(int i1, int i2, int i3, int i4) { - networkType = i1; - downloadBandwidth = i2; - uploadBandwidth = i3; - latency = i4; - } - } - - private static NetworkDataEntry [] mTheoreticalBWTable = new NetworkDataEntry[] { - new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_EDGE, 237, 118, UNKNOWN), - new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_GPRS, 48, 40, UNKNOWN), - new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_UMTS, 384, 64, UNKNOWN), - new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_HSDPA, 14400, UNKNOWN, UNKNOWN), - new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_HSUPA, 14400, 5760, UNKNOWN), - new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_HSPA, 14400, 5760, UNKNOWN), - new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_HSPAP, 21000, 5760, UNKNOWN), - new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_CDMA, UNKNOWN, UNKNOWN, UNKNOWN), - new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_1xRTT, UNKNOWN, UNKNOWN, UNKNOWN), - new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_EVDO_0, 2468, 153, UNKNOWN), - new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_EVDO_A, 3072, 1800, UNKNOWN), - new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_EVDO_B, 14700, 1800, UNKNOWN), - new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_IDEN, UNKNOWN, UNKNOWN, UNKNOWN), - new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_LTE, 100000, 50000, UNKNOWN), - new NetworkDataEntry(TelephonyManager.NETWORK_TYPE_EHRPD, UNKNOWN, UNKNOWN, UNKNOWN), - }; - - private static NetworkDataEntry getNetworkDataEntry(int networkType) { - for (NetworkDataEntry entry : mTheoreticalBWTable) { - if (entry.networkType == networkType) { - return entry; - } - } - - Slog.e(TAG, "Could not find Theoretical BW entry for " + String.valueOf(networkType)); - return null; - } - - private static int getNormalizedSignalStrength(int networkType, SignalStrength ss) { - - int level; - - switch(networkType) { - case TelephonyManager.NETWORK_TYPE_EDGE: - case TelephonyManager.NETWORK_TYPE_GPRS: - case TelephonyManager.NETWORK_TYPE_UMTS: - case TelephonyManager.NETWORK_TYPE_HSDPA: - case TelephonyManager.NETWORK_TYPE_HSUPA: - case TelephonyManager.NETWORK_TYPE_HSPA: - case TelephonyManager.NETWORK_TYPE_HSPAP: - level = ss.getGsmLevel(); - break; - case TelephonyManager.NETWORK_TYPE_CDMA: - case TelephonyManager.NETWORK_TYPE_1xRTT: - level = ss.getCdmaLevel(); - break; - case TelephonyManager.NETWORK_TYPE_EVDO_0: - case TelephonyManager.NETWORK_TYPE_EVDO_A: - case TelephonyManager.NETWORK_TYPE_EVDO_B: - level = ss.getEvdoLevel(); - break; - case TelephonyManager.NETWORK_TYPE_LTE: - level = ss.getLteLevel(); - break; - case TelephonyManager.NETWORK_TYPE_IDEN: - case TelephonyManager.NETWORK_TYPE_EHRPD: - default: - return UNKNOWN; - } - - return (level * LinkQualityInfo.NORMALIZED_SIGNAL_STRENGTH_RANGE) / - SignalStrength.NUM_SIGNAL_STRENGTH_BINS; - } - - @Override - public void startSampling(SamplingDataTracker.SamplingSnapshot s) { - mSamplingDataTracker.startSampling(s); - } - - @Override - public void stopSampling(SamplingDataTracker.SamplingSnapshot s) { - mSamplingDataTracker.stopSampling(s); - } -} diff --git a/core/java/android/net/NetworkStateTracker.java b/core/java/android/net/NetworkStateTracker.java deleted file mode 100644 index c80782c4fd60..000000000000 --- a/core/java/android/net/NetworkStateTracker.java +++ /dev/null @@ -1,250 +0,0 @@ -/* - * Copyright (C) 2008 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.content.Context; -import android.os.Handler; -import android.os.Messenger; - -import static com.android.internal.util.Protocol.BASE_NETWORK_STATE_TRACKER; - -/** - * Interface provides the {@link com.android.server.ConnectivityService} - * with three services. Events to the ConnectivityService when - * changes occur, an API for controlling the network and storage - * for network specific information. - * - * The Connectivity will call startMonitoring before any other - * method is called. - * - * {@hide} - */ -public interface NetworkStateTracker { - - /** - * ------------------------------------------------------------- - * Event Interface back to ConnectivityService. - * - * The events that are to be sent back to the Handler passed - * to startMonitoring when the particular event occurs. - * ------------------------------------------------------------- - */ - - /** - * The network state has changed and the NetworkInfo object - * contains the new state. - * - * msg.what = EVENT_STATE_CHANGED - * msg.obj = NetworkInfo object - */ - public static final int EVENT_STATE_CHANGED = BASE_NETWORK_STATE_TRACKER; - - /** - * msg.what = EVENT_CONFIGURATION_CHANGED - * msg.obj = NetworkInfo object - */ - public static final int EVENT_CONFIGURATION_CHANGED = BASE_NETWORK_STATE_TRACKER + 1; - - /** - * msg.what = EVENT_RESTORE_DEFAULT_NETWORK - * msg.obj = FeatureUser object - */ - public static final int EVENT_RESTORE_DEFAULT_NETWORK = BASE_NETWORK_STATE_TRACKER + 2; - - /** - * msg.what = EVENT_NETWORK_SUBTYPE_CHANGED - * msg.obj = NetworkInfo object - */ - public static final int EVENT_NETWORK_SUBTYPE_CHANGED = BASE_NETWORK_STATE_TRACKER + 3; - - /** - * msg.what = EVENT_NETWORK_CONNECTED - * msg.obj = LinkProperties object - */ - public static final int EVENT_NETWORK_CONNECTED = BASE_NETWORK_STATE_TRACKER + 4; - - /** - * msg.what = EVENT_NETWORK_CONNECTION_DISCONNECTED - * msg.obj = LinkProperties object, same iface name - */ - public static final int EVENT_NETWORK_DISCONNECTED = BASE_NETWORK_STATE_TRACKER + 5; - - /** - * ------------------------------------------------------------- - * Control Interface - * ------------------------------------------------------------- - */ - /** - * Begin monitoring data connectivity. - * - * This is the first method called when this interface is used. - * - * @param context is the current Android context - * @param target is the Hander to which to return the events. - */ - public void startMonitoring(Context context, Handler target); - - /** - * Fetch NetworkInfo for the network - */ - public NetworkInfo getNetworkInfo(); - - /** - * Return the LinkProperties for the connection. - * - * @return a copy of the LinkProperties, is never null. - */ - public LinkProperties getLinkProperties(); - - /** - * @return a copy of this connections capabilities, may be empty but never null. - */ - public NetworkCapabilities getNetworkCapabilities(); - - /** - * Get interesting information about this network link - * @return a copy of link information, null if not available - */ - public LinkQualityInfo getLinkQualityInfo(); - - /** - * Return the system properties name associated with the tcp buffer sizes - * for this network. - */ - public String getTcpBufferSizesPropName(); - - /** - * Disable connectivity to a network - * @return {@code true} if a teardown occurred, {@code false} if the - * teardown did not occur. - */ - public boolean teardown(); - - /** - * Reenable connectivity to a network after a {@link #teardown()}. - * @return {@code true} if we're connected or expect to be connected - */ - public boolean reconnect(); - - /** - * Captive portal check has completed - */ - public void captivePortalCheckCompleted(boolean isCaptive); - - /** - * Turn the wireless radio off for a network. - * @param turnOn {@code true} to turn the radio on, {@code false} - */ - public boolean setRadio(boolean turnOn); - - /** - * Returns an indication of whether this network is available for - * connections. A value of {@code false} means that some quasi-permanent - * condition prevents connectivity to this network. - * - * NOTE that this is broken on multi-connection devices. Should be fixed in J release - * TODO - fix on multi-pdp devices - */ - public boolean isAvailable(); - - /** - * User control of data connection through this network, typically persisted - * internally. - */ - public void setUserDataEnable(boolean enabled); - - /** - * Policy control of data connection through this network, typically not - * persisted internally. Usually used when {@link NetworkPolicy#limitBytes} - * is passed. - */ - public void setPolicyDataEnable(boolean enabled); - - /** - * ------------------------------------------------------------- - * Storage API used by ConnectivityService for saving - * Network specific information. - * ------------------------------------------------------------- - */ - - /** - * Check if private DNS route is set for the network - */ - public boolean isPrivateDnsRouteSet(); - - /** - * Set a flag indicating private DNS route is set - */ - public void privateDnsRouteSet(boolean enabled); - - /** - * Check if default route is set - */ - public boolean isDefaultRouteSet(); - - /** - * Set a flag indicating default route is set for the network - */ - public void defaultRouteSet(boolean enabled); - - /** - * Check if tear down was requested - */ - public boolean isTeardownRequested(); - - /** - * Indicate tear down requested from connectivity - */ - public void setTeardownRequested(boolean isRequested); - - /** - * An external dependency has been met/unmet - */ - public void setDependencyMet(boolean met); - - /* - * Called once to setup async channel between this and - * the underlying network specific code. - */ - public void supplyMessenger(Messenger messenger); - - /* - * Network interface name that we'll lookup for sampling data - */ - public String getNetworkInterfaceName(); - - /* - * Save the starting sample - */ - public void startSampling(SamplingDataTracker.SamplingSnapshot s); - - /* - * Save the ending sample - */ - public void stopSampling(SamplingDataTracker.SamplingSnapshot s); - - /* - * Record the current netId - */ - public void setNetId(int netId); - - /* - * ? - */ - public Network getNetwork(); - -} diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java index d2a29975c3e7..02fbe7350b67 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 @@ public class NetworkUtils { /** * 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 @@ public class NetworkUtils { * 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 class NetworkUtils { 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 class NetworkUtils { 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 @@ public class NetworkUtils { } /** + * 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 @@ public class NetworkUtils { } /** + * 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/ProxyDataTracker.java b/core/java/android/net/ProxyDataTracker.java deleted file mode 100644 index 7d231256525b..000000000000 --- a/core/java/android/net/ProxyDataTracker.java +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Copyright (C) 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net; - -import android.content.BroadcastReceiver; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.ServiceConnection; -import android.os.Bundle; -import android.os.Handler; -import android.os.IBinder; -import android.os.Message; -import android.os.Messenger; -import android.os.RemoteException; -import android.os.UserHandle; -import android.util.Log; - -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; - -/** - * A data tracker responsible for bringing up and tearing down the system proxy server. - * - * {@hide} - */ -public class ProxyDataTracker extends BaseNetworkStateTracker { - private static final String TAG = "ProxyDataTracker"; - private static final String NETWORK_TYPE = "PROXY"; - - // TODO: investigate how to get these DNS addresses from the system. - private static final String DNS1 = "8.8.8.8"; - private static final String DNS2 = "8.8.4.4"; - private static final String INTERFACE_NAME = "ifb0"; - private static final String REASON_ENABLED = "enabled"; - private static final String REASON_DISABLED = "disabled"; - private static final String REASON_PROXY_DOWN = "proxy_down"; - - private static final int MSG_TEAR_DOWN_REQUEST = 1; - private static final int MSG_SETUP_REQUEST = 2; - - private static final String PERMISSION_PROXY_STATUS_SENDER = - "android.permission.ACCESS_NETWORK_CONDITIONS"; - private static final String ACTION_PROXY_STATUS_CHANGE = - "com.android.net.PROXY_STATUS_CHANGE"; - private static final String KEY_IS_PROXY_AVAILABLE = "is_proxy_available"; - private static final String KEY_REPLY_TO_MESSENGER_BINDER = "reply_to_messenger_binder"; - private static final String KEY_REPLY_TO_MESSENGER_BINDER_BUNDLE = - "reply_to_messenger_binder_bundle"; - - private Handler mTarget; - private Messenger mProxyStatusService; - private AtomicBoolean mReconnectRequested = new AtomicBoolean(false); - private AtomicBoolean mIsProxyAvailable = new AtomicBoolean(false); - private final AtomicInteger mDefaultGatewayAddr = new AtomicInteger(0); - - private final BroadcastReceiver mProxyStatusServiceListener = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (intent.getAction().equals(ACTION_PROXY_STATUS_CHANGE)) { - mIsProxyAvailable.set(intent.getBooleanExtra(KEY_IS_PROXY_AVAILABLE, false)); - if (mIsProxyAvailable.get()) { - Bundle bundle = intent.getBundleExtra(KEY_REPLY_TO_MESSENGER_BINDER_BUNDLE); - if (bundle == null || bundle.getBinder(KEY_REPLY_TO_MESSENGER_BINDER) == null) { - Log.e(TAG, "no messenger binder in the intent to send future requests"); - mIsProxyAvailable.set(false); - return; - } - mProxyStatusService = - new Messenger(bundle.getBinder(KEY_REPLY_TO_MESSENGER_BINDER)); - // If there is a pending reconnect request, do it now. - if (mReconnectRequested.get()) { - reconnect(); - } - } else { - setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, - REASON_PROXY_DOWN, null); - } - } else { - Log.d(TAG, "Unrecognized broadcast intent"); - } - } - }; - - /** - * Create a new ProxyDataTracker - */ - public ProxyDataTracker() { - mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_PROXY, 0, NETWORK_TYPE, ""); - mLinkProperties = new LinkProperties(); - mNetworkCapabilities = new NetworkCapabilities(); - mNetworkInfo.setIsAvailable(true); - try { - mLinkProperties.addDnsServer(InetAddress.getByName(DNS1)); - mLinkProperties.addDnsServer(InetAddress.getByName(DNS2)); - mLinkProperties.setInterfaceName(INTERFACE_NAME); - } catch (UnknownHostException e) { - Log.e(TAG, "Could not add DNS address", e); - } - } - - @Override - public Object clone() throws CloneNotSupportedException { - throw new CloneNotSupportedException(); - } - - @Override - public void startMonitoring(Context context, Handler target) { - mContext = context; - mTarget = target; - mContext.registerReceiver(mProxyStatusServiceListener, - new IntentFilter(ACTION_PROXY_STATUS_CHANGE), - PERMISSION_PROXY_STATUS_SENDER, - null); - } - - /** - * Disable connectivity to the network. - */ - public boolean teardown() { - setTeardownRequested(true); - mReconnectRequested.set(false); - try { - if (mIsProxyAvailable.get() && mProxyStatusService != null) { - mProxyStatusService.send(Message.obtain(null, MSG_TEAR_DOWN_REQUEST)); - } - } catch (RemoteException e) { - Log.e(TAG, "Unable to connect to proxy status service", e); - return false; - } - setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, REASON_DISABLED, null); - return true; - } - - /** - * Re-enable proxy data connectivity after a {@link #teardown()}. - */ - public boolean reconnect() { - mReconnectRequested.set(true); - setTeardownRequested(false); - if (!mIsProxyAvailable.get()) { - Log.w(TAG, "Reconnect requested even though proxy service is not up. Bailing."); - return false; - } - setDetailedState(NetworkInfo.DetailedState.CONNECTING, REASON_ENABLED, null); - - try { - mProxyStatusService.send(Message.obtain(null, MSG_SETUP_REQUEST)); - } catch (RemoteException e) { - Log.e(TAG, "Unable to connect to proxy status service", e); - setDetailedState(NetworkInfo.DetailedState.DISCONNECTED, REASON_PROXY_DOWN, null); - return false; - } - // We'll assume proxy is set up successfully. If not, a status change broadcast will be - // received afterwards to indicate any failure. - setDetailedState(NetworkInfo.DetailedState.CONNECTED, REASON_ENABLED, null); - return true; - } - - /** - * Fetch default gateway address for the network - */ - public int getDefaultGatewayAddr() { - return mDefaultGatewayAddr.get(); - } - - /** - * Return the system properties name associated with the tcp buffer sizes - * for this network. - */ - public String getTcpBufferSizesPropName() { - return "net.tcp.buffersize.wifi"; - } - - /** - * Record the detailed state of a network, and if it is a - * change from the previous state, send a notification to - * any listeners. - * @param state the new @{code DetailedState} - * @param reason a {@code String} indicating a reason for the state change, - * if one was supplied. May be {@code null}. - * @param extraInfo optional {@code String} providing extra information about the state change - */ - private void setDetailedState(NetworkInfo.DetailedState state, String reason, - String extraInfo) { - mNetworkInfo.setDetailedState(state, reason, extraInfo); - Message msg = mTarget.obtainMessage(EVENT_STATE_CHANGED, mNetworkInfo); - msg.sendToTarget(); - } -} diff --git a/core/java/android/net/SamplingDataTracker.java b/core/java/android/net/SamplingDataTracker.java deleted file mode 100644 index acd56f2dfdad..000000000000 --- a/core/java/android/net/SamplingDataTracker.java +++ /dev/null @@ -1,300 +0,0 @@ -/* - * Copyright (C) 2013 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.os.SystemClock; -import android.util.Slog; - -import java.io.BufferedReader; -import java.io.FileNotFoundException; -import java.io.FileReader; -import java.io.IOException; -import java.util.Iterator; -import java.util.Map; - -/** - * @hide - */ -public class SamplingDataTracker -{ - private static final boolean DBG = false; - private static final String TAG = "SamplingDataTracker"; - - public static class SamplingSnapshot - { - public long mTxByteCount; - public long mRxByteCount; - public long mTxPacketCount; - public long mRxPacketCount; - public long mTxPacketErrorCount; - public long mRxPacketErrorCount; - public long mTimestamp; - } - - public static void getSamplingSnapshots(Map<String, SamplingSnapshot> mapIfaceToSample) { - - BufferedReader reader = null; - try { - reader = new BufferedReader(new FileReader("/proc/net/dev")); - - // Skip over the line bearing column titles (there are 2 lines) - String line; - reader.readLine(); - reader.readLine(); - - while ((line = reader.readLine()) != null) { - - // remove leading whitespace - line = line.trim(); - - String[] tokens = line.split("[ ]+"); - if (tokens.length < 17) { - continue; - } - - /* column format is - * Interface (Recv)bytes packets errs drop fifo frame compressed multicast \ - * (Transmit)bytes packets errs drop fifo colls carrier compress - */ - - String currentIface = tokens[0].split(":")[0]; - if (DBG) Slog.d(TAG, "Found data for interface " + currentIface); - if (mapIfaceToSample.containsKey(currentIface)) { - - try { - SamplingSnapshot ss = new SamplingSnapshot(); - - ss.mTxByteCount = Long.parseLong(tokens[1]); - ss.mTxPacketCount = Long.parseLong(tokens[2]); - ss.mTxPacketErrorCount = Long.parseLong(tokens[3]); - ss.mRxByteCount = Long.parseLong(tokens[9]); - ss.mRxPacketCount = Long.parseLong(tokens[10]); - ss.mRxPacketErrorCount = Long.parseLong(tokens[11]); - - ss.mTimestamp = SystemClock.elapsedRealtime(); - - if (DBG) { - Slog.d(TAG, "Interface = " + currentIface); - Slog.d(TAG, "ByteCount = " + String.valueOf(ss.mTxByteCount)); - Slog.d(TAG, "TxPacketCount = " + String.valueOf(ss.mTxPacketCount)); - Slog.d(TAG, "TxPacketErrorCount = " - + String.valueOf(ss.mTxPacketErrorCount)); - Slog.d(TAG, "RxByteCount = " + String.valueOf(ss.mRxByteCount)); - Slog.d(TAG, "RxPacketCount = " + String.valueOf(ss.mRxPacketCount)); - Slog.d(TAG, "RxPacketErrorCount = " - + String.valueOf(ss.mRxPacketErrorCount)); - Slog.d(TAG, "Timestamp = " + String.valueOf(ss.mTimestamp)); - Slog.d(TAG, "---------------------------"); - } - - mapIfaceToSample.put(currentIface, ss); - - } catch (NumberFormatException e) { - // just ignore this data point - } - } - } - - if (DBG) { - Iterator it = mapIfaceToSample.entrySet().iterator(); - while (it.hasNext()) { - Map.Entry kvpair = (Map.Entry)it.next(); - if (kvpair.getValue() == null) { - Slog.d(TAG, "could not find snapshot for interface " + kvpair.getKey()); - } - } - } - } catch(FileNotFoundException e) { - Slog.e(TAG, "could not find /proc/net/dev"); - } catch (IOException e) { - Slog.e(TAG, "could not read /proc/net/dev"); - } finally { - try { - if (reader != null) { - reader.close(); - } - } catch (IOException e) { - Slog.e(TAG, "could not close /proc/net/dev"); - } - } - } - - // Snapshots from previous sampling interval - private SamplingSnapshot mBeginningSample; - private SamplingSnapshot mEndingSample; - - // Starting snapshot of current interval - private SamplingSnapshot mLastSample; - - // Protects sampling data from concurrent access - public final Object mSamplingDataLock = new Object(); - - // We need long enough time for a good sample - private final int MINIMUM_SAMPLING_INTERVAL = 15 * 1000; - - // statistics is useless unless we have enough data - private final int MINIMUM_SAMPLED_PACKETS = 30; - - public void startSampling(SamplingSnapshot s) { - synchronized(mSamplingDataLock) { - mLastSample = s; - } - } - - public void stopSampling(SamplingSnapshot s) { - synchronized(mSamplingDataLock) { - if (mLastSample != null) { - if (s.mTimestamp - mLastSample.mTimestamp > MINIMUM_SAMPLING_INTERVAL - && getSampledPacketCount(mLastSample, s) > MINIMUM_SAMPLED_PACKETS) { - mBeginningSample = mLastSample; - mEndingSample = s; - mLastSample = null; - } else { - if (DBG) Slog.d(TAG, "Throwing current sample away because it is too small"); - } - } - } - } - - public void resetSamplingData() { - if (DBG) Slog.d(TAG, "Resetting sampled network data"); - synchronized(mSamplingDataLock) { - - // We could just take another sample here and treat it as an - // 'ending sample' effectively shortening sampling interval, but that - // requires extra work (specifically, reading the sample needs to be - // done asynchronously) - - mLastSample = null; - } - } - - public long getSampledTxByteCount() { - synchronized(mSamplingDataLock) { - if (mBeginningSample != null && mEndingSample != null) { - return mEndingSample.mTxByteCount - mBeginningSample.mTxByteCount; - } else { - return LinkQualityInfo.UNKNOWN_LONG; - } - } - } - - public long getSampledTxPacketCount() { - synchronized(mSamplingDataLock) { - if (mBeginningSample != null && mEndingSample != null) { - return mEndingSample.mTxPacketCount - mBeginningSample.mTxPacketCount; - } else { - return LinkQualityInfo.UNKNOWN_LONG; - } - } - } - - public long getSampledTxPacketErrorCount() { - synchronized(mSamplingDataLock) { - if (mBeginningSample != null && mEndingSample != null) { - return mEndingSample.mTxPacketErrorCount - mBeginningSample.mTxPacketErrorCount; - } else { - return LinkQualityInfo.UNKNOWN_LONG; - } - } - } - - public long getSampledRxByteCount() { - synchronized(mSamplingDataLock) { - if (mBeginningSample != null && mEndingSample != null) { - return mEndingSample.mRxByteCount - mBeginningSample.mRxByteCount; - } else { - return LinkQualityInfo.UNKNOWN_LONG; - } - } - } - - public long getSampledRxPacketCount() { - synchronized(mSamplingDataLock) { - if (mBeginningSample != null && mEndingSample != null) { - return mEndingSample.mRxPacketCount - mBeginningSample.mRxPacketCount; - } else { - return LinkQualityInfo.UNKNOWN_LONG; - } - } - } - - public long getSampledPacketCount() { - return getSampledPacketCount(mBeginningSample, mEndingSample); - } - - public long getSampledPacketCount(SamplingSnapshot begin, SamplingSnapshot end) { - if (begin != null && end != null) { - long rxPacketCount = end.mRxPacketCount - begin.mRxPacketCount; - long txPacketCount = end.mTxPacketCount - begin.mTxPacketCount; - return rxPacketCount + txPacketCount; - } else { - return LinkQualityInfo.UNKNOWN_LONG; - } - } - - public long getSampledPacketErrorCount() { - if (mBeginningSample != null && mEndingSample != null) { - long rxPacketErrorCount = getSampledRxPacketErrorCount(); - long txPacketErrorCount = getSampledTxPacketErrorCount(); - return rxPacketErrorCount + txPacketErrorCount; - } else { - return LinkQualityInfo.UNKNOWN_LONG; - } - } - - public long getSampledRxPacketErrorCount() { - synchronized(mSamplingDataLock) { - if (mBeginningSample != null && mEndingSample != null) { - return mEndingSample.mRxPacketErrorCount - mBeginningSample.mRxPacketErrorCount; - } else { - return LinkQualityInfo.UNKNOWN_LONG; - } - } - } - - public long getSampleTimestamp() { - synchronized(mSamplingDataLock) { - if (mEndingSample != null) { - return mEndingSample.mTimestamp; - } else { - return LinkQualityInfo.UNKNOWN_LONG; - } - } - } - - public int getSampleDuration() { - synchronized(mSamplingDataLock) { - if (mBeginningSample != null && mEndingSample != null) { - return (int) (mEndingSample.mTimestamp - mBeginningSample.mTimestamp); - } else { - return LinkQualityInfo.UNKNOWN_INT; - } - } - } - - public void setCommonLinkQualityInfoFields(LinkQualityInfo li) { - synchronized(mSamplingDataLock) { - li.setLastDataSampleTime(getSampleTimestamp()); - li.setDataSampleDuration(getSampleDuration()); - li.setPacketCount(getSampledPacketCount()); - li.setPacketErrorCount(getSampledPacketErrorCount()); - } - } -} - diff --git a/core/java/android/net/dhcp/DhcpStateMachine.java b/core/java/android/net/dhcp/DhcpStateMachine.java deleted file mode 100644 index bc9a7988c894..000000000000 --- 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 f023df7de0b4..2df9dbfb467b 100644 --- a/core/java/android/provider/CallLog.java +++ b/core/java/android/provider/CallLog.java @@ -33,9 +33,12 @@ import android.provider.ContactsContract.CommonDataKinds.Callable; 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 @@ import java.util.List; * 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 @@ public class CallLog { // 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 @@ public class CallLog { 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 @@ public class CallLog { } 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 d773d4aef5c2..2647247102d2 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -5436,6 +5436,14 @@ public final class Settings { "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 d71ad03b6456..0da4fd5ec276 100644 --- a/core/java/android/provider/VoicemailContract.java +++ b/core/java/android/provider/VoicemailContract.java @@ -19,10 +19,18 @@ package android.provider; 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 class VoicemailContract { */ 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 @@ public class VoicemailContract { 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 @@ public class VoicemailContract { 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/android/view/TextureView.java b/core/java/android/view/TextureView.java index 59ec058b35dd..ad34f020fa9d 100644 --- a/core/java/android/view/TextureView.java +++ b/core/java/android/view/TextureView.java @@ -723,6 +723,12 @@ public class TextureView extends View { mSurface.release(); } mSurface = surfaceTexture; + + // If the view is visible, update the listener in the new surface to use + // the existing listener in the view. + if (((mViewFlags & VISIBILITY_MASK) == VISIBLE)) { + mSurface.setOnFrameAvailableListener(mUpdateListener, mAttachInfo.mHandler); + } mUpdateSurface = true; invalidateParentIfNeeded(); } diff --git a/core/java/com/android/internal/util/Protocol.java b/core/java/com/android/internal/util/Protocol.java index d9ebc258a8b1..a106f48745cf 100644 --- a/core/java/com/android/internal/util/Protocol.java +++ b/core/java/com/android/internal/util/Protocol.java @@ -52,6 +52,7 @@ public class Protocol { 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 8b9f5744d244..e97d61e54c6d 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_enable(const char *ifname); 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 @@ char *dhcp_get_errmsg(); 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 @@ static jint android_net_utils_resetConnections(JNIEnv* env, jobject clazz, 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 @@ static jboolean android_net_utils_runDhcpCommon(JNIEnv* env, jobject clazz, jstr 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 @@ static jboolean android_net_utils_runDhcpCommon(JNIEnv* env, jobject clazz, jstr 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 @@ static jstring android_net_utils_getDhcpError(JNIEnv* env, jobject clazz) 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 @@ static jboolean android_net_utils_protectFromVpn(JNIEnv *env, jobject thiz, jint return (jboolean) !protectFromVpn(socket); } + // ---------------------------------------------------------------------------- /* @@ -255,8 +299,9 @@ static jboolean android_net_utils_protectFromVpn(JNIEnv *env, jobject thiz, jint 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 @@ static JNINativeMethod gNetworkUtilMethods[] = { { "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 3de2268f2302..ad328a685dd8 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 9f710932f89b..fc0b753a98ff 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 e10ea6399908..997225c9dbda 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 000000000000..8d51c3b01258 --- /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 687a14ee3152..bfda753eb5d1 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 687a14ee3152..bfda753eb5d1 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 1b0f0a481edd..8348be9f1c5b 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 3c94f437778d..e4b0cbb7d183 100644 --- a/services/Android.mk +++ b/services/Android.mk @@ -24,6 +24,7 @@ services := \ appwidget \ backup \ devicepolicy \ + net \ print \ restrictions \ usage \ diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index b72b29dbb1d2..d9ef766f2b71 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -48,7 +48,6 @@ import android.net.INetworkPolicyManager; import android.net.INetworkStatsService; import android.net.LinkProperties; import android.net.LinkProperties.CompareResult; -import android.net.MobileDataStateTracker; import android.net.Network; import android.net.NetworkAgent; import android.net.NetworkCapabilities; @@ -59,12 +58,10 @@ import android.net.NetworkMisc; import android.net.NetworkQuotaInfo; import android.net.NetworkRequest; import android.net.NetworkState; -import android.net.NetworkStateTracker; import android.net.NetworkUtils; import android.net.Proxy; import android.net.ProxyInfo; import android.net.RouteInfo; -import android.net.SamplingDataTracker; import android.net.UidRange; import android.net.Uri; import android.os.Binder; @@ -153,9 +150,6 @@ public class ConnectivityService extends IConnectivityManager.Stub private static final boolean DBG = true; private static final boolean VDBG = false; - // network sampling debugging - private static final boolean SAMPLE_DBG = false; - private static final boolean LOGD_RULES = false; // TODO: create better separation between radio types and network types @@ -166,33 +160,10 @@ public class ConnectivityService extends IConnectivityManager.Stub private static final String NETWORK_RESTORE_DELAY_PROP_NAME = "android.telephony.apn-restore"; - // Default value if FAIL_FAST_TIME_MS is not set - private static final int DEFAULT_FAIL_FAST_TIME_MS = 1 * 60 * 1000; - // system property that can override DEFAULT_FAIL_FAST_TIME_MS - private static final String FAIL_FAST_TIME_MS = - "persist.radio.fail_fast_time_ms"; - - private static final String ACTION_PKT_CNT_SAMPLE_INTERVAL_ELAPSED = - "android.net.ConnectivityService.action.PKT_CNT_SAMPLE_INTERVAL_ELAPSED"; - - private static final int SAMPLE_INTERVAL_ELAPSED_REQUEST_CODE = 0; - // How long to delay to removal of a pending intent based request. // See Settings.Secure.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS private final int mReleasePendingIntentDelayMs; - private PendingIntent mSampleIntervalElapsedIntent; - - // Set network sampling interval at 12 minutes, this way, even if the timers get - // aggregated, it will fire at around 15 minutes, which should allow us to - // aggregate this timer with other timers (specially the socket keep alive timers) - private static final int DEFAULT_SAMPLING_INTERVAL_IN_SECONDS = (SAMPLE_DBG ? 30 : 12 * 60); - - // start network sampling a minute after booting ... - private static final int DEFAULT_START_SAMPLING_INTERVAL_IN_SECONDS = (SAMPLE_DBG ? 30 : 60); - - AlarmManager mAlarmManager; - private Tethering mTethering; private final PermissionMonitor mPermissionMonitor; @@ -212,13 +183,6 @@ public class ConnectivityService extends IConnectivityManager.Stub /** Set of ifaces that are costly. */ private HashSet<String> mMeteredIfaces = Sets.newHashSet(); - /** - * Sometimes we want to refer to the individual network state - * trackers separately, and sometimes we just want to treat them - * abstractly. - */ - private NetworkStateTracker mNetTrackers[]; - private Context mContext; private int mNetworkPreference; // 0 is full bad, 100 is full good @@ -278,28 +242,11 @@ public class ConnectivityService extends IConnectivityManager.Stub private static final int EVENT_APPLY_GLOBAL_HTTP_PROXY = 9; /** - * used internally to set external dependency met/unmet - * arg1 = ENABLED (met) or DISABLED (unmet) - * arg2 = NetworkType - */ - private static final int EVENT_SET_DEPENDENCY_MET = 10; - - /** * used internally to send a sticky broadcast delayed. */ private static final int EVENT_SEND_STICKY_BROADCAST_INTENT = 11; /** - * Used internally to disable fail fast of mobile data - */ - private static final int EVENT_ENABLE_FAIL_FAST_MOBILE_DATA = 14; - - /** - * used internally to indicate that data sampling interval is up - */ - private static final int EVENT_SAMPLE_INTERVAL_ELAPSED = 15; - - /** * PAC manager has received new port. */ private static final int EVENT_PROXY_HAS_CHANGED = 16; @@ -419,8 +366,6 @@ public class ConnectivityService extends IConnectivityManager.Stub private DataConnectionStats mDataConnectionStats; - private AtomicInteger mEnableFailFastMobileDataTag = new AtomicInteger(0); - TelephonyManager mTelephonyManager; // sequence number for Networks; keep in sync with system/netd/NetworkController.cpp @@ -650,9 +595,6 @@ public class ConnectivityService extends IConnectivityManager.Stub com.android.internal.R.integer.config_networkTransitionTimeout); mPendingIntentWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG); - mNetTrackers = new NetworkStateTracker[ - ConnectivityManager.MAX_NETWORK_TYPE+1]; - mNetConfigs = new NetworkConfig[ConnectivityManager.MAX_NETWORK_TYPE+1]; // TODO: What is the "correct" way to do determine if this is a wifi only device? @@ -740,23 +682,6 @@ public class ConnectivityService extends IConnectivityManager.Stub mDataConnectionStats = new DataConnectionStats(mContext); mDataConnectionStats.startMonitoring(); - mAlarmManager = (AlarmManager)mContext.getSystemService(Context.ALARM_SERVICE); - - IntentFilter filter = new IntentFilter(); - filter.addAction(ACTION_PKT_CNT_SAMPLE_INTERVAL_ELAPSED); - mContext.registerReceiver( - new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); - if (action.equals(ACTION_PKT_CNT_SAMPLE_INTERVAL_ELAPSED)) { - mHandler.sendMessage(mHandler.obtainMessage - (EVENT_SAMPLE_INTERVAL_ELAPSED)); - } - } - }, - new IntentFilter(filter)); - mPacManager = new PacManager(mContext, mHandler, EVENT_PROXY_HAS_CHANGED); mUserManager = (UserManager) context.getSystemService(Context.USER_SERVICE); @@ -782,15 +707,6 @@ public class ConnectivityService extends IConnectivityManager.Stub throw new IllegalStateException("No free netIds"); } - private boolean teardown(NetworkStateTracker netTracker) { - if (netTracker.teardown()) { - netTracker.setTeardownRequested(true); - return true; - } else { - return false; - } - } - private NetworkState getFilteredNetworkState(int networkType, int uid) { NetworkInfo info = null; LinkProperties lp = null; @@ -1350,22 +1266,6 @@ public class ConnectivityService extends IConnectivityManager.Stub return true; } - public void setDataDependency(int networkType, boolean met) { - enforceConnectivityInternalPermission(); - - mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_DEPENDENCY_MET, - (met ? ENABLED : DISABLED), networkType)); - } - - private void handleSetDependencyMet(int networkType, boolean met) { - if (mNetTrackers[networkType] != null) { - if (DBG) { - log("handleSetDependencyMet(" + networkType + ", " + met + ")"); - } - mNetTrackers[networkType].setDependencyMet(met); - } - } - private INetworkPolicyListener mPolicyListener = new INetworkPolicyListener.Stub() { @Override public void onUidRulesChanged(int uid, int uidRules) { @@ -1406,21 +1306,6 @@ public class ConnectivityService extends IConnectivityManager.Stub if (LOGD_RULES) { log("onRestrictBackgroundChanged(restrictBackground=" + restrictBackground + ")"); } - - // kick off connectivity change broadcast for active network, since - // global background policy change is radical. - // TODO: Dead code; remove. - // - // final int networkType = mActiveDefaultNetwork; - // if (isNetworkTypeValid(networkType)) { - // final NetworkStateTracker tracker = mNetTrackers[networkType]; - // if (tracker != null) { - // final NetworkInfo info = tracker.getNetworkInfo(); - // if (info != null && info.isConnected()) { - // sendConnectedBroadcast(info); - // } - // } - // } } }; @@ -1536,14 +1421,6 @@ public class ConnectivityService extends IConnectivityManager.Stub } void systemReady() { - // start network sampling .. - Intent intent = new Intent(ACTION_PKT_CNT_SAMPLE_INTERVAL_ELAPSED); - intent.setPackage(mContext.getPackageName()); - - mSampleIntervalElapsedIntent = PendingIntent.getBroadcast(mContext, - SAMPLE_INTERVAL_ELAPSED_REQUEST_CODE, intent, 0); - setAlarm(DEFAULT_START_SAMPLING_INTERVAL_IN_SECONDS * 1000, mSampleIntervalElapsedIntent); - loadGlobalProxy(); synchronized(this) { @@ -2015,66 +1892,6 @@ public class ConnectivityService extends IConnectivityManager.Stub } break; } - case NetworkStateTracker.EVENT_STATE_CHANGED: { - info = (NetworkInfo) msg.obj; - NetworkInfo.State state = info.getState(); - - if (VDBG || (state == NetworkInfo.State.CONNECTED) || - (state == NetworkInfo.State.DISCONNECTED) || - (state == NetworkInfo.State.SUSPENDED)) { - log("ConnectivityChange for " + - info.getTypeName() + ": " + - state + "/" + info.getDetailedState()); - } - - EventLogTags.writeConnectivityStateChanged( - info.getType(), info.getSubtype(), info.getDetailedState().ordinal()); - - if (info.isConnectedToProvisioningNetwork()) { - /** - * TODO: Create ConnectivityManager.TYPE_MOBILE_PROVISIONING - * for now its an in between network, its a network that - * is actually a default network but we don't want it to be - * announced as such to keep background applications from - * trying to use it. It turns out that some still try so we - * take the additional step of clearing any default routes - * to the link that may have incorrectly setup by the lower - * levels. - */ - LinkProperties lp = getLinkPropertiesForType(info.getType()); - if (DBG) { - log("EVENT_STATE_CHANGED: connected to provisioning network, lp=" + lp); - } - - // Clear any default routes setup by the radio so - // any activity by applications trying to use this - // connection will fail until the provisioning network - // is enabled. - /* - for (RouteInfo r : lp.getRoutes()) { - removeRoute(lp, r, TO_DEFAULT_TABLE, - mNetTrackers[info.getType()].getNetwork().netId); - } - */ - } else if (state == NetworkInfo.State.DISCONNECTED) { - } else if (state == NetworkInfo.State.SUSPENDED) { - } else if (state == NetworkInfo.State.CONNECTED) { - // handleConnect(info); - } - notifyLockdownVpn(null); - break; - } - case NetworkStateTracker.EVENT_CONFIGURATION_CHANGED: { - info = (NetworkInfo) msg.obj; - // TODO: Temporary allowing network configuration - // change not resetting sockets. - // @see bug/4455071 - /* - handleConnectivityChange(info.getType(), mCurrentLinkProperties[info.getType()], - false); - */ - break; - } } } } @@ -2439,34 +2256,11 @@ public class ConnectivityService extends IConnectivityManager.Stub handleDeprecatedGlobalHttpProxy(); break; } - case EVENT_SET_DEPENDENCY_MET: { - boolean met = (msg.arg1 == ENABLED); - handleSetDependencyMet(msg.arg2, met); - break; - } case EVENT_SEND_STICKY_BROADCAST_INTENT: { Intent intent = (Intent)msg.obj; sendStickyBroadcast(intent); break; } - case EVENT_ENABLE_FAIL_FAST_MOBILE_DATA: { - int tag = mEnableFailFastMobileDataTag.get(); - if (msg.arg1 == tag) { - MobileDataStateTracker mobileDst = - (MobileDataStateTracker) mNetTrackers[ConnectivityManager.TYPE_MOBILE]; - if (mobileDst != null) { - mobileDst.setEnableFailFastMobileData(msg.arg2); - } - } else { - log("EVENT_ENABLE_FAIL_FAST_MOBILE_DATA: stale arg1:" + msg.arg1 - + " != tag:" + tag); - } - break; - } - case EVENT_SAMPLE_INTERVAL_ELAPSED: { - handleNetworkSamplingTimeout(); - break; - } case EVENT_PROXY_HAS_CHANGED: { handleApplyDefaultProxy((ProxyInfo)msg.obj); break; @@ -3066,14 +2860,6 @@ public class ConnectivityService extends IConnectivityManager.Stub } } - public void supplyMessenger(int networkType, Messenger messenger) { - enforceConnectivityInternalPermission(); - - if (isNetworkTypeValid(networkType) && mNetTrackers[networkType] != null) { - mNetTrackers[networkType].supplyMessenger(messenger); - } - } - public int findConnectionTypeForIface(String iface) { enforceConnectivityInternalPermission(); @@ -3091,23 +2877,6 @@ public class ConnectivityService extends IConnectivityManager.Stub return ConnectivityManager.TYPE_NONE; } - /** - * Have mobile data fail fast if enabled. - * - * @param enabled DctConstants.ENABLED/DISABLED - */ - private void setEnableFailFastMobileData(int enabled) { - int tag; - - if (enabled == DctConstants.ENABLED) { - tag = mEnableFailFastMobileDataTag.incrementAndGet(); - } else { - tag = mEnableFailFastMobileDataTag.get(); - } - mHandler.sendMessage(mHandler.obtainMessage(EVENT_ENABLE_FAIL_FAST_MOBILE_DATA, tag, - enabled)); - } - @Override public int checkMobileProvisioning(int suggestedTimeOutMs) { // TODO: Remove? Any reason to trigger a provisioning check? @@ -3392,69 +3161,6 @@ public class ConnectivityService extends IConnectivityManager.Stub } }; - /* Infrastructure for network sampling */ - - private void handleNetworkSamplingTimeout() { - - if (SAMPLE_DBG) log("Sampling interval elapsed, updating statistics .."); - - // initialize list of interfaces .. - Map<String, SamplingDataTracker.SamplingSnapshot> mapIfaceToSample = - new HashMap<String, SamplingDataTracker.SamplingSnapshot>(); - for (NetworkStateTracker tracker : mNetTrackers) { - if (tracker != null) { - String ifaceName = tracker.getNetworkInterfaceName(); - if (ifaceName != null) { - mapIfaceToSample.put(ifaceName, null); - } - } - } - - // Read samples for all interfaces - SamplingDataTracker.getSamplingSnapshots(mapIfaceToSample); - - // process samples for all networks - for (NetworkStateTracker tracker : mNetTrackers) { - if (tracker != null) { - String ifaceName = tracker.getNetworkInterfaceName(); - SamplingDataTracker.SamplingSnapshot ss = mapIfaceToSample.get(ifaceName); - if (ss != null) { - // end the previous sampling cycle - tracker.stopSampling(ss); - // start a new sampling cycle .. - tracker.startSampling(ss); - } - } - } - - if (SAMPLE_DBG) log("Done."); - - int samplingIntervalInSeconds = Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.CONNECTIVITY_SAMPLING_INTERVAL_IN_SECONDS, - DEFAULT_SAMPLING_INTERVAL_IN_SECONDS); - - if (SAMPLE_DBG) { - log("Setting timer for " + String.valueOf(samplingIntervalInSeconds) + "seconds"); - } - - setAlarm(samplingIntervalInSeconds * 1000, mSampleIntervalElapsedIntent); - } - - /** - * Sets a network sampling alarm. - */ - void setAlarm(int timeoutInMilliseconds, PendingIntent intent) { - long wakeupTime = SystemClock.elapsedRealtime() + timeoutInMilliseconds; - int alarmType; - if (Resources.getSystem().getBoolean( - R.bool.config_networkSamplingWakesDevice)) { - alarmType = AlarmManager.ELAPSED_REALTIME_WAKEUP; - } else { - alarmType = AlarmManager.ELAPSED_REALTIME; - } - mAlarmManager.set(alarmType, wakeupTime, intent); - } - private final HashMap<Messenger, NetworkFactoryInfo> mNetworkFactoryInfos = new HashMap<Messenger, NetworkFactoryInfo>(); private final HashMap<NetworkRequest, NetworkRequestInfo> mNetworkRequests = diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java index 8c56c8c5f057..0437a2acc85f 100644 --- a/services/core/java/com/android/server/NetworkManagementService.java +++ b/services/core/java/com/android/server/NetworkManagementService.java @@ -1374,7 +1374,8 @@ public class NetworkManagementService extends INetworkManagementService.Stub 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 64a67fc239f5..22fee22141f1 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 @@ public class TelecomLoaderService extends SystemService { 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 334cdf6246aa..0705fbdeaaeb 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -677,7 +677,8 @@ public final class SystemServer { 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 000000000000..336bc45c6ab7 --- /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 index 7b8be9c80d77..25b80936f944 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 @@ class DhcpAckPacket extends DhcpPacket { /** * 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 @@ class DhcpAckPacket extends DhcpPacket { String s = super.toString(); String dnsServers = " DNS servers: "; - for (InetAddress dnsServer: mDnsServers) { + for (Inet4Address dnsServer: mDnsServers) { dnsServers += dnsServer.toString() + " "; } @@ -57,8 +55,8 @@ class DhcpAckPacket extends DhcpPacket { */ 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 @@ class DhcpAckPacket extends DhcpPacket { 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 000000000000..57cc251649a3 --- /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 index 7646eb46999f..9d985ac90213 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 @@ class DhcpDeclinePacket extends DhcpPacket { /** * 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 @@ class DhcpDeclinePacket extends DhcpPacket { 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 index 0e2d39be7183..a031080d9a98 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 @@ class DhcpDiscoverPacket extends DhcpPacket { * 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 @@ class DhcpDiscoverPacket extends DhcpPacket { */ 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 @@ class DhcpDiscoverPacket extends DhcpPacket { */ 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 index da73216caaa9..8bc7cdd59c24 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 @@ class DhcpInformPacket extends DhcpPacket { /** * 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 @@ class DhcpInformPacket extends DhcpPacket { 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 index 1f340ad4f098..1390ea7d1031 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 @@ class DhcpNakPacket extends DhcpPacket { /** * 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 @@ class DhcpNakPacket extends DhcpPacket { */ 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 @@ class DhcpNakPacket extends DhcpPacket { 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 index f1c30e11675b..b1f3bbd4a3df 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 @@ class DhcpOfferPacket extends DhcpPacket { /** * 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 @@ class DhcpOfferPacket extends DhcpPacket { String dnsServers = ", DNS servers: "; if (mDnsServers != null) { - for (InetAddress dnsServer: mDnsServers) { + for (Inet4Address dnsServer: mDnsServers) { dnsServers += dnsServer + " "; } } @@ -59,8 +57,8 @@ class DhcpOfferPacket extends DhcpPacket { */ 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 @@ class DhcpOfferPacket extends DhcpPacket { 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 index c7c25f0e9ffb..a232a6eb273f 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 @@ import java.util.List; 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 @@ abstract class DhcpPacket { 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 @@ abstract class DhcpPacket { * 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 @@ abstract class DhcpPacket { 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 @@ abstract class DhcpPacket { * 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 @@ abstract class DhcpPacket { 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 @@ abstract class DhcpPacket { * 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 @@ abstract class DhcpPacket { 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 class DhcpPacket { */ 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 @@ abstract class DhcpPacket { } /** + * 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 @@ abstract class DhcpPacket { 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 @@ abstract class DhcpPacket { // 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 @@ abstract class DhcpPacket { 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 @@ abstract class DhcpPacket { * 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 @@ abstract class DhcpPacket { /** * 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 @@ abstract class DhcpPacket { /** * 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 @@ abstract class DhcpPacket { /** * 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 @@ abstract class DhcpPacket { /** * 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 @@ abstract class DhcpPacket { } /** - * 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 @@ abstract class DhcpPacket { * 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 @@ abstract class DhcpPacket { { // 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 @@ abstract class DhcpPacket { // 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 @@ abstract class DhcpPacket { 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 @@ abstract class DhcpPacket { 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 @@ abstract class DhcpPacket { 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 @@ abstract class DhcpPacket { 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 @@ abstract class DhcpPacket { boolean notFinishedOptions = true; while ((packet.position() < packet.limit()) && notFinishedOptions) { - byte optionType = packet.get(); - - if (optionType == (byte) 0xFF) { - notFinishedOptions = false; - } else { - byte optionLen = packet.get(); - 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; - - 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; + try { + byte optionType = packet.get(); + + 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: + 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(); + } + } + + if (expectedLen != optionLen) { + return null; + } } + } catch (BufferUnderflowException e) { + return null; } } @@ -795,23 +921,67 @@ abstract class DhcpPacket { 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 @@ abstract class DhcpPacket { * 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 @@ abstract class DhcpPacket { * 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 @@ abstract class DhcpPacket { * 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 @@ abstract class DhcpPacket { * 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 index cf32957fd3bd..42b7b0c945c3 100644 --- a/core/java/android/net/dhcp/DhcpRequestPacket.java +++ b/services/net/java/android/net/dhcp/DhcpRequestPacket.java @@ -18,7 +18,6 @@ package android.net.dhcp; import android.util.Log; -import java.net.InetAddress; import java.net.Inet4Address; import java.nio.ByteBuffer; @@ -29,10 +28,9 @@ class DhcpRequestPacket extends DhcpPacket { /** * 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 @@ class DhcpRequestPacket extends DhcpPacket { 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 @@ class DhcpRequestPacket extends DhcpPacket { 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/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java index beb353a6cf29..c19890075a25 100644 --- a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java @@ -20,7 +20,6 @@ import static android.net.ConnectivityManager.CONNECTIVITY_ACTION_IMMEDIATE; import static android.net.ConnectivityManager.TYPE_MOBILE; import static android.net.ConnectivityManager.TYPE_WIFI; import static android.net.ConnectivityManager.getNetworkTypeName; -import static android.net.NetworkStateTracker.EVENT_STATE_CHANGED; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.eq; import static org.mockito.Matchers.isA; diff --git a/telecomm/java/android/telecom/AuthenticatorService.java b/telecomm/java/android/telecom/AuthenticatorService.java new file mode 100644 index 000000000000..39717c3e0fc2 --- /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 c1d2f9b3d618..436f20a43822 100644 --- a/telecomm/java/android/telecom/Call.java +++ b/telecomm/java/android/telecom/Call.java @@ -141,28 +141,42 @@ public final class Call { 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_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_WIFI = 0x00000800; + 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 final class Call { 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 @@ public final class Call { 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 @@ public final class Call { 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 569163a8f9ee..bab064ed5de7 100644 --- a/telecomm/java/android/telecom/Connection.java +++ b/telecomm/java/android/telecom/Connection.java @@ -106,28 +106,42 @@ public abstract class Connection implements IConferenceable { 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_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_WIFI = 0x00000800; + 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 abstract class Connection implements IConferenceable { 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 @@ public abstract class Connection implements IConferenceable { 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 @@ public abstract class Connection implements IConferenceable { 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 052a481f1ab2..a94c2f6487a4 100644 --- a/telecomm/java/android/telecom/PhoneAccount.java +++ b/telecomm/java/android/telecom/PhoneAccount.java @@ -40,15 +40,13 @@ import java.util.MissingResourceException; /** * 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 @@ public class PhoneAccount implements Parcelable { * 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 @@ public class PhoneAccount implements Parcelable { * <p> * {@hide} */ + @SystemApi public static final int CAPABILITY_CALL_PROVIDER = 0x2; /** @@ -94,6 +95,7 @@ public class PhoneAccount implements Parcelable { * See {@link #getCapabilities} * @hide */ + @SystemApi public static final int CAPABILITY_VIDEO_CALLING = 0x8; /** @@ -111,6 +113,7 @@ public class PhoneAccount implements Parcelable { * See {@link #getCapabilities} * @hide */ + @SystemApi public static final int CAPABILITY_MULTI_USER = 0x20; /** @@ -203,6 +206,7 @@ public class PhoneAccount implements Parcelable { } /** @hide */ + @SystemApi public Builder setAccountHandle(PhoneAccountHandle accountHandle) { mAccountHandle = accountHandle; return this; @@ -333,6 +337,7 @@ public class PhoneAccount implements Parcelable { * @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 @@ public class PhoneAccount implements Parcelable { * @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 97af41afd31a..4600b724e3ef 100644 --- a/telecomm/java/android/telecom/PhoneAccountHandle.java +++ b/telecomm/java/android/telecom/PhoneAccountHandle.java @@ -29,16 +29,13 @@ import java.util.Objects; * 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 @@ public class PhoneAccountHandle implements Parcelable { } /** @hide */ + @SystemApi public PhoneAccountHandle( ComponentName componentName, String id, @@ -61,8 +59,8 @@ public class PhoneAccountHandle implements Parcelable { } /** - * 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 @@ public class PhoneAccountHandle implements Parcelable { /** * 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 @@ public class PhoneAccountHandle implements Parcelable { * ({@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 @@ public class PhoneAccountHandle implements Parcelable { * @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 1a6b2928af8e..8be3e66ca331 100644 --- a/telecomm/java/android/telecom/TelecomManager.java +++ b/telecomm/java/android/telecom/TelecomManager.java @@ -92,6 +92,15 @@ public class TelecomManager { "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 @@ public class TelecomManager { * {@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 @@ public class TelecomManager { * {@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 @@ public class TelecomManager { * {@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 @@ public class TelecomManager { * * @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 f5cb054b0f50..e62e9949bff2 100644 --- a/telecomm/java/android/telecom/VideoProfile.java +++ b/telecomm/java/android/telecom/VideoProfile.java @@ -21,8 +21,6 @@ import android.os.Parcelable; /** * 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 000000000000..864c6b1765e5 --- /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 c043659f15a9..3572846da665 100644 --- a/telephony/java/android/telephony/PhoneNumberUtils.java +++ b/telephony/java/android/telephony/PhoneNumberUtils.java @@ -34,11 +34,11 @@ import android.text.Editable; 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 @@ public class PhoneNumberUtils * * @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 @@ public class PhoneNumberUtils * @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 b8de1447053a..e1a3de7b7f6e 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -29,6 +29,7 @@ import android.os.Bundle; 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 @@ public class TelephonyManager { /** * Returns the IMS Registration Status - *@hide + * @hide */ public boolean isImsRegistered() { try { @@ -4158,4 +4159,21 @@ public class TelephonyManager { 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 bb0bd04d7775..d03fa3aa51f2 100644 --- a/telephony/java/com/android/internal/telephony/ITelephony.aidl +++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl @@ -18,6 +18,7 @@ package com.android.internal.telephony; 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 @@ interface ITelephony { * {@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 d929f55987ee..90f66c4adc1a 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 @@ import android.os.Messenger; 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 ca95ec1f7358..53424948d359 100644 --- a/wifi/java/android/net/wifi/IWifiManager.aidl +++ b/wifi/java/android/net/wifi/IWifiManager.aidl @@ -79,6 +79,8 @@ interface IWifiManager 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 000000000000..5c6d44710ea5 --- /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 57343c52262d..65ecf5d728a6 100644 --- a/wifi/java/android/net/wifi/RttManager.java +++ b/wifi/java/android/net/wifi/RttManager.java @@ -26,10 +26,19 @@ public class RttManager { 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 class RttManager { 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 class RttManager { 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 class RttManager { 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 @@ public class RttManager { 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 @@ public class RttManager { 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 RttManager { }; } + 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 @@ public class RttManager { 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 @@ public class RttManager { 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 class RttManager { 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 @@ public class RttManager { 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 9729c9191640..e8a51e336f7d 100644 --- a/wifi/java/android/net/wifi/ScanResult.java +++ b/wifi/java/android/net/wifi/ScanResult.java @@ -53,11 +53,55 @@ public class ScanResult implements Parcelable { */ 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 class ScanResult implements Parcelable { 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 @@ public class ScanResult implements Parcelable { 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 @@ public class ScanResult implements Parcelable { 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 @@ public class ScanResult implements Parcelable { 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 @@ public class ScanResult implements Parcelable { numUsage = source.numUsage; numIpConfigFailures = source.numIpConfigFailures; isAutoJoinCandidate = source.isAutoJoinCandidate; + passpointNetwork = source.passpointNetwork; + venueName = source.venueName; + operatorFriendlyName = source.operatorFriendlyName; } } @@ -303,9 +399,15 @@ public class ScanResult implements Parcelable { 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 @@ public class ScanResult implements Parcelable { 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 @@ public class ScanResult implements Parcelable { 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 @@ public class ScanResult implements Parcelable { 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 @@ public class ScanResult implements Parcelable { 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 87db951e0bd3..34ae386fa45e 100644 --- a/wifi/java/android/net/wifi/WifiConfiguration.java +++ b/wifi/java/android/net/wifi/WifiConfiguration.java @@ -19,19 +19,18 @@ package android.net.wifi; 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 class WifiConfiguration implements Parcelable { public static final String updateIdentiferVarName = "update_identifier"; /** {@hide} */ public static final int INVALID_NETWORK_ID = -1; + /** * Recognized key management schemes. */ @@ -233,17 +233,21 @@ public class WifiConfiguration implements Parcelable { * <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 class WifiConfiguration implements Parcelable { 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 @@ public class WifiConfiguration implements Parcelable { SSID = null; BSSID = null; FQDN = null; - naiRealm = null; + roamingConsortiumIds = new HashSet<Long>(); priority = 0; hiddenSSID = false; disableReason = DISABLED_UNKNOWN_REASON; @@ -907,11 +926,37 @@ public class WifiConfiguration implements Parcelable { } } + 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(FQDN) + && !TextUtils.isEmpty(providerFriendlyName) + && enterpriseConfig != null + && enterpriseConfig.getEapMethod() != WifiEnterpriseConfig.Eap.NONE; + } + + /** * Helper function, identify if a configuration is linked * @hide */ @@ -1042,8 +1087,9 @@ public class WifiConfiguration implements Parcelable { 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 +1429,8 @@ public class WifiConfiguration implements Parcelable { 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 +1546,17 @@ public class WifiConfiguration implements Parcelable { 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 +1649,15 @@ public class WifiConfiguration implements Parcelable { 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 +1720,15 @@ public class WifiConfiguration implements Parcelable { 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 cf3cba3ec0da..36fc96b81feb 100644 --- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java +++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java @@ -54,6 +54,8 @@ public class WifiEnterpriseConfig implements Parcelable { /** @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 class WifiEnterpriseConfig implements Parcelable { 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 @@ public class WifiEnterpriseConfig implements Parcelable { } /** - * 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 97e10dcc1f82..407624cb36f7 100644 --- a/wifi/java/android/net/wifi/WifiManager.java +++ b/wifi/java/android/net/wifi/WifiManager.java @@ -1238,6 +1238,21 @@ public class WifiManager { } /** + * 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 aaa2f9893645..fea934f860c6 100644 --- a/wifi/java/android/net/wifi/WifiScanner.java +++ b/wifi/java/android/net/wifi/WifiScanner.java @@ -158,6 +158,11 @@ public class WifiScanner { 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 @@ public class WifiScanner { dest.writeInt(periodInMs); dest.writeInt(reportEvents); dest.writeInt(numBssidsPerScan); + dest.writeInt(maxScansToCache); if (channels != null) { dest.writeInt(channels.length); @@ -194,6 +200,7 @@ public class WifiScanner { 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 @@ public class WifiScanner { } - /** @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 @@ public class WifiScanner { } /** - * 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 class WifiScanner { */ 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 @@ public class WifiScanner { 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 @@ public class WifiScanner { * @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 class WifiScanner { 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 @@ public class WifiScanner { 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 @@ public class WifiScanner { ((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 @@ public class WifiScanner { ((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 000000000000..50bec33ea6d2 --- /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 000000000000..cfd36059063f --- /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 000000000000..0a7230f42383 --- /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 000000000000..6a88b2e2c1ee --- /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 000000000000..bbf5fc608ed2 --- /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 000000000000..27f23bc3dc45 --- /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 000000000000..33db3f5491f8 --- /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 000000000000..0245a3d0617a --- /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 000000000000..088136f5e98c --- /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 000000000000..b54b70ceb087 --- /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 000000000000..1d61da00ed15 --- /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 000000000000..f84ac88c0caf --- /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]; + } + }; +} |