Merge "More time zone update API classes"
diff --git a/Android.mk b/Android.mk
index 283e9dc..02caa0a 100644
--- a/Android.mk
+++ b/Android.mk
@@ -132,7 +132,6 @@
core/java/android/bluetooth/IBluetoothGatt.aidl \
core/java/android/bluetooth/IBluetoothGattCallback.aidl \
core/java/android/bluetooth/IBluetoothGattServerCallback.aidl \
- core/java/android/bluetooth/le/IAdvertiserCallback.aidl \
core/java/android/bluetooth/le/IAdvertisingSetCallback.aidl \
core/java/android/bluetooth/le/IPeriodicAdvertisingCallback.aidl \
core/java/android/bluetooth/le/IScannerCallback.aidl \
@@ -406,6 +405,7 @@
media/java/android/media/projection/IMediaProjectionManager.aidl \
media/java/android/media/projection/IMediaProjectionWatcherCallback.aidl \
media/java/android/media/session/IActiveSessionsListener.aidl \
+ media/java/android/media/session/ICallback.aidl \
media/java/android/media/session/ISessionController.aidl \
media/java/android/media/session/ISessionControllerCallback.aidl \
media/java/android/media/session/ISession.aidl \
@@ -434,6 +434,12 @@
telecomm/java/com/android/internal/telecom/IInCallService.aidl \
telecomm/java/com/android/internal/telecom/ITelecomService.aidl \
telecomm/java/com/android/internal/telecom/RemoteServiceCallback.aidl \
+ telephony/java/android/telephony/mbms/IMbmsDownloadManagerCallback.aidl \
+ telephony/java/android/telephony/mbms/IMbmsStreamingManagerCallback.aidl \
+ telephony/java/android/telephony/mbms/IDownloadCallback.aidl \
+ telephony/java/android/telephony/mbms/IStreamingServiceCallback.aidl \
+ telephony/java/android/telephony/mbms/vendor/IMbmsDownloadService.aidl \
+ telephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.aidl \
telephony/java/com/android/ims/internal/IImsCallSession.aidl \
telephony/java/com/android/ims/internal/IImsCallSessionListener.aidl \
telephony/java/com/android/ims/internal/IImsConfig.aidl \
@@ -542,6 +548,13 @@
include $(CLEAR_VARS)
aidl_files := \
+ frameworks/base/telephony/java/android/telephony/mbms/DownloadRequest.aidl \
+ frameworks/base/telephony/java/android/telephony/mbms/DownloadStatus.aidl \
+ frameworks/base/telephony/java/android/telephony/mbms/FileInfo.aidl \
+ frameworks/base/telephony/java/android/telephony/mbms/FileServiceInfo.aidl \
+ frameworks/base/telephony/java/android/telephony/mbms/ServiceInfo.aidl \
+ frameworks/base/telephony/java/android/telephony/mbms/StreamingService.aidl \
+ frameworks/base/telephony/java/android/telephony/mbms/StreamingServiceInfo.aidl \
frameworks/base/telephony/java/android/telephony/ServiceState.aidl \
frameworks/base/telephony/java/android/telephony/SubscriptionInfo.aidl \
frameworks/base/telephony/java/android/telephony/CellInfo.aidl \
diff --git a/api/current.txt b/api/current.txt
index 00b6986..3ba7f8f 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -36,6 +36,7 @@
field public static final java.lang.String BIND_TELECOM_CONNECTION_SERVICE = "android.permission.BIND_TELECOM_CONNECTION_SERVICE";
field public static final java.lang.String BIND_TEXT_SERVICE = "android.permission.BIND_TEXT_SERVICE";
field public static final java.lang.String BIND_TV_INPUT = "android.permission.BIND_TV_INPUT";
+ field public static final java.lang.String BIND_VISUAL_VOICEMAIL_SERVICE = "android.permission.BIND_VISUAL_VOICEMAIL_SERVICE";
field public static final java.lang.String BIND_VOICE_INTERACTION = "android.permission.BIND_VOICE_INTERACTION";
field public static final java.lang.String BIND_VPN_SERVICE = "android.permission.BIND_VPN_SERVICE";
field public static final java.lang.String BIND_VR_LISTENER_SERVICE = "android.permission.BIND_VR_LISTENER_SERVICE";
@@ -7077,6 +7078,7 @@
method public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback);
method public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback, int);
method public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback, int, int);
+ method public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback, int, int, android.os.Handler);
method public boolean createBond();
method public android.bluetooth.BluetoothSocket createInsecureRfcommSocketToServiceRecord(java.util.UUID) throws java.io.IOException;
method public android.bluetooth.BluetoothSocket createRfcommSocketToServiceRecord(java.util.UUID) throws java.io.IOException;
@@ -7501,7 +7503,7 @@
method public void setAdvertisingData(android.bluetooth.le.AdvertiseData);
method public void setAdvertisingParameters(android.bluetooth.le.AdvertisingSetParameters);
method public void setPeriodicAdvertisingData(android.bluetooth.le.AdvertiseData);
- method public void setPeriodicAdvertisingEnable(boolean);
+ method public void setPeriodicAdvertisingEnabled(boolean);
method public void setPeriodicAdvertisingParameters(android.bluetooth.le.PeriodicAdvertisingParameters);
method public void setScanResponseData(android.bluetooth.le.AdvertiseData);
}
@@ -7671,8 +7673,10 @@
field public static final android.os.Parcelable.Creator<android.bluetooth.le.ScanResult> CREATOR;
field public static final int DATA_COMPLETE = 0; // 0x0
field public static final int DATA_TRUNCATED = 2; // 0x2
+ field public static final int PERIODIC_INTERVAL_NOT_PRESENT = 0; // 0x0
field public static final int PHY_UNUSED = 0; // 0x0
field public static final int SID_NOT_PRESENT = 255; // 0xff
+ field public static final int TX_POWER_NOT_PRESENT = 127; // 0x7f
}
public final class ScanSettings implements android.os.Parcelable {
@@ -8318,7 +8322,6 @@
field public static final java.lang.String HARDWARE_PROPERTIES_SERVICE = "hardware_properties";
field public static final java.lang.String INPUT_METHOD_SERVICE = "input_method";
field public static final java.lang.String INPUT_SERVICE = "input";
- field public static final java.lang.String IPSEC_SERVICE = "ipsec";
field public static final java.lang.String JOB_SCHEDULER_SERVICE = "jobscheduler";
field public static final java.lang.String KEYGUARD_SERVICE = "keyguard";
field public static final java.lang.String LAUNCHER_APPS_SERVICE = "launcherapps";
@@ -18179,9 +18182,9 @@
method protected final void computeGregorianFields(int);
method protected int computeGregorianMonthStart(int, int);
method protected int computeJulianDay();
- method protected int computeMillisInDay();
+ method protected deprecated int computeMillisInDay();
method protected void computeTime();
- method protected int computeZoneOffset(long, int);
+ method protected deprecated int computeZoneOffset(long, int);
method public int fieldDifference(java.util.Date, int);
method protected java.lang.String fieldName(int);
method protected static final long floorDivide(long, long);
@@ -23870,70 +23873,6 @@
field public static final android.os.Parcelable.Creator<android.net.IpPrefix> CREATOR;
}
- public final class IpSecAlgorithm implements android.os.Parcelable {
- ctor public IpSecAlgorithm(java.lang.String, byte[]);
- ctor public IpSecAlgorithm(java.lang.String, byte[], int);
- method public int describeContents();
- method public byte[] getKey();
- method public java.lang.String getName();
- method public int getTruncationLengthBits();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final java.lang.String AUTH_HMAC_MD5 = "hmac(md5)";
- field public static final java.lang.String AUTH_HMAC_SHA1 = "hmac(sha1)";
- field public static final java.lang.String AUTH_HMAC_SHA256 = "hmac(sha256)";
- field public static final java.lang.String AUTH_HMAC_SHA384 = "hmac(sha384)";
- field public static final java.lang.String AUTH_HMAC_SHA512 = "hmac(sha512)";
- field public static final android.os.Parcelable.Creator<android.net.IpSecAlgorithm> CREATOR;
- field public static final java.lang.String CRYPT_AES_CBC = "cbc(aes)";
- }
-
- public final class IpSecManager {
- method public void applyTransportModeTransform(java.net.Socket, android.net.IpSecTransform) throws java.io.IOException;
- method public void applyTransportModeTransform(java.net.DatagramSocket, android.net.IpSecTransform) throws java.io.IOException;
- method public void applyTransportModeTransform(java.io.FileDescriptor, android.net.IpSecTransform) throws java.io.IOException;
- method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket(int) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
- method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket() throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
- method public void removeTransportModeTransform(java.net.Socket, android.net.IpSecTransform);
- method public void removeTransportModeTransform(java.net.DatagramSocket, android.net.IpSecTransform);
- method public void removeTransportModeTransform(java.io.FileDescriptor, android.net.IpSecTransform);
- method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(int, java.net.InetAddress) throws android.net.IpSecManager.ResourceUnavailableException;
- method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(int, java.net.InetAddress, int) throws android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
- field public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; // 0x0
- }
-
- public static final class IpSecManager.ResourceUnavailableException extends android.util.AndroidException {
- }
-
- public static final class IpSecManager.SecurityParameterIndex implements java.lang.AutoCloseable {
- method public void close();
- method public int getSpi();
- }
-
- public static final class IpSecManager.SpiUnavailableException extends android.util.AndroidException {
- method public int getSpi();
- }
-
- public static final class IpSecManager.UdpEncapsulationSocket implements java.lang.AutoCloseable {
- method public void close();
- method public int getPort();
- method public java.io.FileDescriptor getSocket();
- }
-
- public final class IpSecTransform implements java.lang.AutoCloseable {
- method public void close();
- field public static final int DIRECTION_IN = 0; // 0x0
- field public static final int DIRECTION_OUT = 1; // 0x1
- }
-
- public static class IpSecTransform.Builder {
- ctor public IpSecTransform.Builder(android.content.Context);
- method public android.net.IpSecTransform buildTransportModeTransform(java.net.InetAddress) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
- method public android.net.IpSecTransform.Builder setAuthentication(int, android.net.IpSecAlgorithm);
- method public android.net.IpSecTransform.Builder setEncryption(int, android.net.IpSecAlgorithm);
- method public android.net.IpSecTransform.Builder setIpv4Encapsulation(android.net.IpSecManager.UdpEncapsulationSocket, int);
- method public android.net.IpSecTransform.Builder setSpi(int, android.net.IpSecManager.SecurityParameterIndex);
- }
-
public class LinkAddress implements android.os.Parcelable {
method public int describeContents();
method public java.net.InetAddress getAddress();
@@ -33654,8 +33593,8 @@
}
public static final class Telephony.ServiceStateTable {
- method public static android.net.Uri getUriForSubId(int);
- method public static android.net.Uri getUriForSubIdAndField(int, java.lang.String);
+ method public static android.net.Uri getUriForSubscriptionId(int);
+ method public static android.net.Uri getUriForSubscriptionIdAndField(int, java.lang.String);
field public static final java.lang.String AUTHORITY = "service-state";
field public static final android.net.Uri CONTENT_URI;
field public static final java.lang.String IS_MANUAL_NETWORK_SELECTION = "is_manual_network_selection";
@@ -33844,6 +33783,8 @@
public static final class VoicemailContract.Voicemails implements android.provider.BaseColumns android.provider.OpenableColumns {
method public static android.net.Uri buildSourceUri(java.lang.String);
+ field public static final java.lang.String ARCHIVED = "archived";
+ field public static final java.lang.String BACKED_UP = "backed_up";
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";
@@ -33851,6 +33792,7 @@
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";
+ field public static final java.lang.String IS_OMTP_VOICEMAIL = "is_omtp_voicemail";
field public static final java.lang.String IS_READ = "is_read";
field public static final java.lang.String ITEM_TYPE = "vnd.android.cursor.item/voicemail";
field public static final java.lang.String LAST_MODIFIED = "last_modified";
@@ -33858,6 +33800,7 @@
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 RESTORED = "restored";
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";
@@ -37110,7 +37053,6 @@
}
public static final class Connection.RttModifyStatus {
- ctor public Connection.RttModifyStatus();
field public static final int SESSION_MODIFY_REQUEST_FAIL = 2; // 0x2
field public static final int SESSION_MODIFY_REQUEST_INVALID = 3; // 0x3
field public static final int SESSION_MODIFY_REQUEST_REJECTED_BY_REMOTE = 5; // 0x5
@@ -37592,7 +37534,8 @@
field public static final java.lang.String KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL = "carrier_volte_provisioning_required_bool";
field public static final java.lang.String KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL = "carrier_volte_tty_supported_bool";
field public static final java.lang.String KEY_CARRIER_VT_AVAILABLE_BOOL = "carrier_vt_available_bool";
- field public static final java.lang.String KEY_CARRIER_VVM_PACKAGE_NAME_STRING = "carrier_vvm_package_name_string";
+ field public static final deprecated java.lang.String KEY_CARRIER_VVM_PACKAGE_NAME_STRING = "carrier_vvm_package_name_string";
+ field public static final java.lang.String KEY_CARRIER_VVM_PACKAGE_NAME_STRING_ARRAY = "carrier_vvm_package_name_string_array";
field public static final java.lang.String KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL = "carrier_wfc_ims_available_bool";
field public static final java.lang.String KEY_CARRIER_WFC_SUPPORTS_WIFI_ONLY_BOOL = "carrier_wfc_supports_wifi_only_bool";
field public static final java.lang.String KEY_CDMA_DTMF_TONE_DELAY_INT = "cdma_dtmf_tone_delay_int";
@@ -37676,9 +37619,13 @@
field public static final java.lang.String KEY_VOICE_PRIVACY_DISABLE_UI_BOOL = "voice_privacy_disable_ui_bool";
field public static final java.lang.String KEY_VOLTE_REPLACEMENT_RAT_INT = "volte_replacement_rat_int";
field public static final java.lang.String KEY_VVM_CELLULAR_DATA_REQUIRED_BOOL = "vvm_cellular_data_required_bool";
+ field public static final java.lang.String KEY_VVM_CLIENT_PREFIX_STRING = "vvm_client_prefix_string";
field public static final java.lang.String KEY_VVM_DESTINATION_NUMBER_STRING = "vvm_destination_number_string";
+ field public static final java.lang.String KEY_VVM_DISABLED_CAPABILITIES_STRING_ARRAY = "vvm_disabled_capabilities_string_array";
+ field public static final java.lang.String KEY_VVM_LEGACY_MODE_ENABLED_BOOL = "vvm_legacy_mode_enabled_bool";
field public static final java.lang.String KEY_VVM_PORT_NUMBER_INT = "vvm_port_number_int";
field public static final java.lang.String KEY_VVM_PREFETCH_BOOL = "vvm_prefetch_bool";
+ field public static final java.lang.String KEY_VVM_SSL_ENABLED_BOOL = "vvm_ssl_enabled_bool";
field public static final java.lang.String KEY_VVM_TYPE_STRING = "vvm_type_string";
field public static final java.lang.String KEY_WORLD_PHONE_BOOL = "world_phone_bool";
}
@@ -38178,7 +38125,6 @@
method public android.os.PersistableBundle getCarrierConfig();
method public deprecated android.telephony.CellLocation getCellLocation();
method public int getDataActivity();
- method public boolean getDataEnabled();
method public int getDataNetworkType();
method public int getDataState();
method public deprecated java.lang.String getDeviceId();
@@ -38210,6 +38156,7 @@
method public int getSimState();
method public int getSimState(int);
method public java.lang.String getSubscriberId();
+ method public java.lang.String getVisualVoicemailPackageName();
method public java.lang.String getVoiceMailAlphaTag();
method public java.lang.String getVoiceMailNumber();
method public int getVoiceNetworkType();
@@ -38222,6 +38169,8 @@
method public android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannel(java.lang.String, int);
method public java.lang.String iccTransmitApduBasicChannel(int, int, int, int, int, java.lang.String);
method public java.lang.String iccTransmitApduLogicalChannel(int, int, int, int, int, int, java.lang.String);
+ method public boolean isConcurrentVoiceAndDataAllowed();
+ method public boolean isDataEnabled();
method public boolean isHearingAidCompatibilitySupported();
method public boolean isNetworkRoaming();
method public boolean isSmsCapable();
@@ -38231,6 +38180,7 @@
method public boolean isWorldPhone();
method public void listen(android.telephony.PhoneStateListener, int);
method public java.lang.String sendEnvelopeWithStatus(java.lang.String);
+ method public void sendUssdRequest(java.lang.String, android.telephony.TelephonyManager.OnReceiveUssdResponseCallback, android.os.Handler);
method public void setDataEnabled(boolean);
method public boolean setLine1NumberForDisplay(java.lang.String, java.lang.String);
method public boolean setOperatorBrandOverride(java.lang.String);
@@ -38305,6 +38255,57 @@
field public static final java.lang.String VVM_TYPE_OMTP = "vvm_type_omtp";
}
+ public static abstract class TelephonyManager.OnReceiveUssdResponseCallback {
+ ctor public TelephonyManager.OnReceiveUssdResponseCallback();
+ method public void onReceiveUssdResponse(java.lang.String, java.lang.CharSequence);
+ method public void onReceiveUssdResponseFailed(java.lang.String, int);
+ }
+
+ public abstract class VisualVoicemailService extends android.app.Service {
+ ctor public VisualVoicemailService();
+ method public android.os.IBinder onBind(android.content.Intent);
+ method public abstract void onCellServiceConnected(android.telephony.VisualVoicemailService.VisualVoicemailTask, android.telecom.PhoneAccountHandle);
+ method public abstract void onSimRemoved(android.telephony.VisualVoicemailService.VisualVoicemailTask, android.telecom.PhoneAccountHandle);
+ method public abstract void onSmsReceived(android.telephony.VisualVoicemailService.VisualVoicemailTask, android.telephony.VisualVoicemailSms);
+ method public abstract void onStopped(android.telephony.VisualVoicemailService.VisualVoicemailTask);
+ method public static final void sendVisualVoicemailSms(android.content.Context, android.telecom.PhoneAccountHandle, java.lang.String, short, java.lang.String, android.app.PendingIntent);
+ method public static final void setSmsFilterSettings(android.content.Context, android.telecom.PhoneAccountHandle, android.telephony.VisualVoicemailSmsFilterSettings);
+ field public static final java.lang.String SERVICE_INTERFACE = "android.telephony.VisualVoicemailService";
+ }
+
+ public static class VisualVoicemailService.VisualVoicemailTask {
+ method public final void finish();
+ }
+
+ public final class VisualVoicemailSms implements android.os.Parcelable {
+ method public int describeContents();
+ method public android.os.Bundle getFields();
+ method public java.lang.String getMessageBody();
+ method public android.telecom.PhoneAccountHandle getPhoneAccountHandle();
+ method public java.lang.String getPrefix();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.telephony.VisualVoicemailSms> CREATOR;
+ }
+
+ public final class VisualVoicemailSmsFilterSettings implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.telephony.VisualVoicemailSmsFilterSettings> CREATOR;
+ field public static final int DESTINATION_PORT_ANY = -1; // 0xffffffff
+ field public static final int DESTINATION_PORT_DATA_SMS = -2; // 0xfffffffe
+ field public final java.lang.String clientPrefix;
+ field public final int destinationPort;
+ field public final java.util.List<java.lang.String> originatingNumbers;
+ }
+
+ public static class VisualVoicemailSmsFilterSettings.Builder {
+ ctor public VisualVoicemailSmsFilterSettings.Builder();
+ method public android.telephony.VisualVoicemailSmsFilterSettings build();
+ method public android.telephony.VisualVoicemailSmsFilterSettings.Builder setClientPrefix(java.lang.String);
+ method public android.telephony.VisualVoicemailSmsFilterSettings.Builder setDestinationPort(int);
+ method public android.telephony.VisualVoicemailSmsFilterSettings.Builder setOriginatingNumbers(java.util.List<java.lang.String>);
+ }
+
}
package android.telephony.cdma {
@@ -49708,15 +49709,15 @@
ctor public DexClassLoader(java.lang.String, java.lang.String, java.lang.String, java.lang.ClassLoader);
}
- public final class DexFile {
- ctor public DexFile(java.io.File) throws java.io.IOException;
- ctor public DexFile(java.lang.String) throws java.io.IOException;
+ public final deprecated class DexFile {
+ ctor public deprecated DexFile(java.io.File) throws java.io.IOException;
+ ctor public deprecated DexFile(java.lang.String) throws java.io.IOException;
method public void close() throws java.io.IOException;
method public java.util.Enumeration<java.lang.String> entries();
method public java.lang.String getName();
method public static boolean isDexOptNeeded(java.lang.String) throws java.io.FileNotFoundException, java.io.IOException;
method public java.lang.Class loadClass(java.lang.String, java.lang.ClassLoader);
- method public static dalvik.system.DexFile loadDex(java.lang.String, java.lang.String, int) throws java.io.IOException;
+ method public static deprecated dalvik.system.DexFile loadDex(java.lang.String, java.lang.String, int) throws java.io.IOException;
}
public final class InMemoryDexClassLoader extends dalvik.system.BaseDexClassLoader {
diff --git a/api/system-current.txt b/api/system-current.txt
index 9eb4599..8623df7 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -55,6 +55,7 @@
field public static final java.lang.String BIND_TRUST_AGENT = "android.permission.BIND_TRUST_AGENT";
field public static final java.lang.String BIND_TV_INPUT = "android.permission.BIND_TV_INPUT";
field public static final java.lang.String BIND_TV_REMOTE_SERVICE = "android.permission.BIND_TV_REMOTE_SERVICE";
+ field public static final java.lang.String BIND_VISUAL_VOICEMAIL_SERVICE = "android.permission.BIND_VISUAL_VOICEMAIL_SERVICE";
field public static final java.lang.String BIND_VOICE_INTERACTION = "android.permission.BIND_VOICE_INTERACTION";
field public static final java.lang.String BIND_VPN_SERVICE = "android.permission.BIND_VPN_SERVICE";
field public static final java.lang.String BIND_VR_LISTENER_SERVICE = "android.permission.BIND_VR_LISTENER_SERVICE";
@@ -7380,6 +7381,7 @@
method public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback);
method public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback, int);
method public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback, int, int);
+ method public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback, int, int, android.os.Handler);
method public boolean createBond();
method public android.bluetooth.BluetoothSocket createInsecureRfcommSocketToServiceRecord(java.util.UUID) throws java.io.IOException;
method public android.bluetooth.BluetoothSocket createRfcommSocketToServiceRecord(java.util.UUID) throws java.io.IOException;
@@ -7806,7 +7808,7 @@
method public void setAdvertisingData(android.bluetooth.le.AdvertiseData);
method public void setAdvertisingParameters(android.bluetooth.le.AdvertisingSetParameters);
method public void setPeriodicAdvertisingData(android.bluetooth.le.AdvertiseData);
- method public void setPeriodicAdvertisingEnable(boolean);
+ method public void setPeriodicAdvertisingEnabled(boolean);
method public void setPeriodicAdvertisingParameters(android.bluetooth.le.PeriodicAdvertisingParameters);
method public void setScanResponseData(android.bluetooth.le.AdvertiseData);
}
@@ -7989,8 +7991,10 @@
field public static final android.os.Parcelable.Creator<android.bluetooth.le.ScanResult> CREATOR;
field public static final int DATA_COMPLETE = 0; // 0x0
field public static final int DATA_TRUNCATED = 2; // 0x2
+ field public static final int PERIODIC_INTERVAL_NOT_PRESENT = 0; // 0x0
field public static final int PHY_UNUSED = 0; // 0x0
field public static final int SID_NOT_PRESENT = 255; // 0xff
+ field public static final int TX_POWER_NOT_PRESENT = 127; // 0x7f
}
public final class ScanSettings implements android.os.Parcelable {
@@ -8653,7 +8657,6 @@
field public static final java.lang.String HDMI_CONTROL_SERVICE = "hdmi_control";
field public static final java.lang.String INPUT_METHOD_SERVICE = "input_method";
field public static final java.lang.String INPUT_SERVICE = "input";
- field public static final java.lang.String IPSEC_SERVICE = "ipsec";
field public static final java.lang.String JOB_SCHEDULER_SERVICE = "jobscheduler";
field public static final java.lang.String KEYGUARD_SERVICE = "keyguard";
field public static final java.lang.String LAUNCHER_APPS_SERVICE = "launcherapps";
@@ -19394,9 +19397,9 @@
method protected final void computeGregorianFields(int);
method protected int computeGregorianMonthStart(int, int);
method protected int computeJulianDay();
- method protected int computeMillisInDay();
+ method protected deprecated int computeMillisInDay();
method protected void computeTime();
- method protected int computeZoneOffset(long, int);
+ method protected deprecated int computeZoneOffset(long, int);
method public int fieldDifference(java.util.Date, int);
method protected java.lang.String fieldName(int);
method protected static final long floorDivide(long, long);
@@ -25708,72 +25711,6 @@
field public static final android.os.Parcelable.Creator<android.net.IpPrefix> CREATOR;
}
- public final class IpSecAlgorithm implements android.os.Parcelable {
- ctor public IpSecAlgorithm(java.lang.String, byte[]);
- ctor public IpSecAlgorithm(java.lang.String, byte[], int);
- method public int describeContents();
- method public byte[] getKey();
- method public java.lang.String getName();
- method public int getTruncationLengthBits();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final java.lang.String AUTH_HMAC_MD5 = "hmac(md5)";
- field public static final java.lang.String AUTH_HMAC_SHA1 = "hmac(sha1)";
- field public static final java.lang.String AUTH_HMAC_SHA256 = "hmac(sha256)";
- field public static final java.lang.String AUTH_HMAC_SHA384 = "hmac(sha384)";
- field public static final java.lang.String AUTH_HMAC_SHA512 = "hmac(sha512)";
- field public static final android.os.Parcelable.Creator<android.net.IpSecAlgorithm> CREATOR;
- field public static final java.lang.String CRYPT_AES_CBC = "cbc(aes)";
- }
-
- public final class IpSecManager {
- method public void applyTransportModeTransform(java.net.Socket, android.net.IpSecTransform) throws java.io.IOException;
- method public void applyTransportModeTransform(java.net.DatagramSocket, android.net.IpSecTransform) throws java.io.IOException;
- method public void applyTransportModeTransform(java.io.FileDescriptor, android.net.IpSecTransform) throws java.io.IOException;
- method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket(int) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
- method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket() throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
- method public void removeTransportModeTransform(java.net.Socket, android.net.IpSecTransform);
- method public void removeTransportModeTransform(java.net.DatagramSocket, android.net.IpSecTransform);
- method public void removeTransportModeTransform(java.io.FileDescriptor, android.net.IpSecTransform);
- method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(int, java.net.InetAddress) throws android.net.IpSecManager.ResourceUnavailableException;
- method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(int, java.net.InetAddress, int) throws android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
- field public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; // 0x0
- }
-
- public static final class IpSecManager.ResourceUnavailableException extends android.util.AndroidException {
- }
-
- public static final class IpSecManager.SecurityParameterIndex implements java.lang.AutoCloseable {
- method public void close();
- method public int getSpi();
- }
-
- public static final class IpSecManager.SpiUnavailableException extends android.util.AndroidException {
- method public int getSpi();
- }
-
- public static final class IpSecManager.UdpEncapsulationSocket implements java.lang.AutoCloseable {
- method public void close();
- method public int getPort();
- method public java.io.FileDescriptor getSocket();
- }
-
- public final class IpSecTransform implements java.lang.AutoCloseable {
- method public void close();
- field public static final int DIRECTION_IN = 0; // 0x0
- field public static final int DIRECTION_OUT = 1; // 0x1
- }
-
- public static class IpSecTransform.Builder {
- ctor public IpSecTransform.Builder(android.content.Context);
- method public android.net.IpSecTransform buildTransportModeTransform(java.net.InetAddress) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
- method public android.net.IpSecTransform.Builder setAuthentication(int, android.net.IpSecAlgorithm);
- method public android.net.IpSecTransform.Builder setEncryption(int, android.net.IpSecAlgorithm);
- method public android.net.IpSecTransform.Builder setIpv4Encapsulation(android.net.IpSecManager.UdpEncapsulationSocket, int);
- method public android.net.IpSecTransform.Builder setNattKeepalive(int);
- method public android.net.IpSecTransform.Builder setSpi(int, android.net.IpSecManager.SecurityParameterIndex);
- method public android.net.IpSecTransform.Builder setUnderlyingNetwork(android.net.Network);
- }
-
public class LinkAddress implements android.os.Parcelable {
method public int describeContents();
method public java.net.InetAddress getAddress();
@@ -36498,8 +36435,8 @@
}
public static final class Telephony.ServiceStateTable {
- method public static android.net.Uri getUriForSubId(int);
- method public static android.net.Uri getUriForSubIdAndField(int, java.lang.String);
+ method public static android.net.Uri getUriForSubscriptionId(int);
+ method public static android.net.Uri getUriForSubscriptionIdAndField(int, java.lang.String);
field public static final java.lang.String AUTHORITY = "service-state";
field public static final android.net.Uri CONTENT_URI;
field public static final java.lang.String IS_MANUAL_NETWORK_SELECTION = "is_manual_network_selection";
@@ -36688,6 +36625,8 @@
public static final class VoicemailContract.Voicemails implements android.provider.BaseColumns android.provider.OpenableColumns {
method public static android.net.Uri buildSourceUri(java.lang.String);
+ field public static final java.lang.String ARCHIVED = "archived";
+ field public static final java.lang.String BACKED_UP = "backed_up";
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";
@@ -36695,6 +36634,7 @@
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";
+ field public static final java.lang.String IS_OMTP_VOICEMAIL = "is_omtp_voicemail";
field public static final java.lang.String IS_READ = "is_read";
field public static final java.lang.String ITEM_TYPE = "vnd.android.cursor.item/voicemail";
field public static final java.lang.String LAST_MODIFIED = "last_modified";
@@ -36702,6 +36642,7 @@
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 RESTORED = "restored";
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";
@@ -40095,7 +40036,6 @@
}
public static final class Connection.RttModifyStatus {
- ctor public Connection.RttModifyStatus();
field public static final int SESSION_MODIFY_REQUEST_FAIL = 2; // 0x2
field public static final int SESSION_MODIFY_REQUEST_INVALID = 3; // 0x3
field public static final int SESSION_MODIFY_REQUEST_REJECTED_BY_REMOTE = 5; // 0x5
@@ -40765,7 +40705,8 @@
field public static final java.lang.String KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL = "carrier_volte_provisioning_required_bool";
field public static final java.lang.String KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL = "carrier_volte_tty_supported_bool";
field public static final java.lang.String KEY_CARRIER_VT_AVAILABLE_BOOL = "carrier_vt_available_bool";
- field public static final java.lang.String KEY_CARRIER_VVM_PACKAGE_NAME_STRING = "carrier_vvm_package_name_string";
+ field public static final deprecated java.lang.String KEY_CARRIER_VVM_PACKAGE_NAME_STRING = "carrier_vvm_package_name_string";
+ field public static final java.lang.String KEY_CARRIER_VVM_PACKAGE_NAME_STRING_ARRAY = "carrier_vvm_package_name_string_array";
field public static final java.lang.String KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL = "carrier_wfc_ims_available_bool";
field public static final java.lang.String KEY_CARRIER_WFC_SUPPORTS_WIFI_ONLY_BOOL = "carrier_wfc_supports_wifi_only_bool";
field public static final java.lang.String KEY_CDMA_DTMF_TONE_DELAY_INT = "cdma_dtmf_tone_delay_int";
@@ -40849,9 +40790,13 @@
field public static final java.lang.String KEY_VOICE_PRIVACY_DISABLE_UI_BOOL = "voice_privacy_disable_ui_bool";
field public static final java.lang.String KEY_VOLTE_REPLACEMENT_RAT_INT = "volte_replacement_rat_int";
field public static final java.lang.String KEY_VVM_CELLULAR_DATA_REQUIRED_BOOL = "vvm_cellular_data_required_bool";
+ field public static final java.lang.String KEY_VVM_CLIENT_PREFIX_STRING = "vvm_client_prefix_string";
field public static final java.lang.String KEY_VVM_DESTINATION_NUMBER_STRING = "vvm_destination_number_string";
+ field public static final java.lang.String KEY_VVM_DISABLED_CAPABILITIES_STRING_ARRAY = "vvm_disabled_capabilities_string_array";
+ field public static final java.lang.String KEY_VVM_LEGACY_MODE_ENABLED_BOOL = "vvm_legacy_mode_enabled_bool";
field public static final java.lang.String KEY_VVM_PORT_NUMBER_INT = "vvm_port_number_int";
field public static final java.lang.String KEY_VVM_PREFETCH_BOOL = "vvm_prefetch_bool";
+ field public static final java.lang.String KEY_VVM_SSL_ENABLED_BOOL = "vvm_ssl_enabled_bool";
field public static final java.lang.String KEY_VVM_TYPE_STRING = "vvm_type_string";
field public static final java.lang.String KEY_WORLD_PHONE_BOOL = "world_phone_bool";
}
@@ -41391,8 +41336,8 @@
method public int getCurrentPhoneType();
method public int getCurrentPhoneType(int);
method public int getDataActivity();
- method public boolean getDataEnabled();
- method public boolean getDataEnabled(int);
+ method public deprecated boolean getDataEnabled();
+ method public deprecated boolean getDataEnabled(int);
method public int getDataNetworkType();
method public int getDataState();
method public deprecated java.lang.String getDeviceId();
@@ -41425,6 +41370,7 @@
method public int getSimState(int);
method public java.lang.String getSubscriberId();
method public java.util.List<android.telephony.TelephonyHistogram> getTelephonyHistograms();
+ method public java.lang.String getVisualVoicemailPackageName();
method public java.lang.String getVoiceMailAlphaTag();
method public java.lang.String getVoiceMailNumber();
method public int getVoiceNetworkType();
@@ -41439,7 +41385,9 @@
method public android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannel(java.lang.String, int);
method public java.lang.String iccTransmitApduBasicChannel(int, int, int, int, int, java.lang.String);
method public java.lang.String iccTransmitApduLogicalChannel(int, int, int, int, int, int, java.lang.String);
+ method public boolean isConcurrentVoiceAndDataAllowed();
method public boolean isDataConnectivityPossible();
+ method public boolean isDataEnabled();
method public boolean isHearingAidCompatibilitySupported();
method public boolean isIdle();
method public boolean isNetworkRoaming();
@@ -41456,6 +41404,7 @@
method public void listen(android.telephony.PhoneStateListener, int);
method public boolean needsOtaServiceProvisioning();
method public java.lang.String sendEnvelopeWithStatus(java.lang.String);
+ method public void sendUssdRequest(java.lang.String, android.telephony.TelephonyManager.OnReceiveUssdResponseCallback, android.os.Handler);
method public int setAllowedCarriers(int, java.util.List<android.service.carrier.CarrierIdentifier>);
method public void setDataEnabled(boolean);
method public void setDataEnabled(int, boolean);
@@ -41551,6 +41500,57 @@
field public static final java.lang.String VVM_TYPE_OMTP = "vvm_type_omtp";
}
+ public static abstract class TelephonyManager.OnReceiveUssdResponseCallback {
+ ctor public TelephonyManager.OnReceiveUssdResponseCallback();
+ method public void onReceiveUssdResponse(java.lang.String, java.lang.CharSequence);
+ method public void onReceiveUssdResponseFailed(java.lang.String, int);
+ }
+
+ public abstract class VisualVoicemailService extends android.app.Service {
+ ctor public VisualVoicemailService();
+ method public android.os.IBinder onBind(android.content.Intent);
+ method public abstract void onCellServiceConnected(android.telephony.VisualVoicemailService.VisualVoicemailTask, android.telecom.PhoneAccountHandle);
+ method public abstract void onSimRemoved(android.telephony.VisualVoicemailService.VisualVoicemailTask, android.telecom.PhoneAccountHandle);
+ method public abstract void onSmsReceived(android.telephony.VisualVoicemailService.VisualVoicemailTask, android.telephony.VisualVoicemailSms);
+ method public abstract void onStopped(android.telephony.VisualVoicemailService.VisualVoicemailTask);
+ method public static final void sendVisualVoicemailSms(android.content.Context, android.telecom.PhoneAccountHandle, java.lang.String, short, java.lang.String, android.app.PendingIntent);
+ method public static final void setSmsFilterSettings(android.content.Context, android.telecom.PhoneAccountHandle, android.telephony.VisualVoicemailSmsFilterSettings);
+ field public static final java.lang.String SERVICE_INTERFACE = "android.telephony.VisualVoicemailService";
+ }
+
+ public static class VisualVoicemailService.VisualVoicemailTask {
+ method public final void finish();
+ }
+
+ public final class VisualVoicemailSms implements android.os.Parcelable {
+ method public int describeContents();
+ method public android.os.Bundle getFields();
+ method public java.lang.String getMessageBody();
+ method public android.telecom.PhoneAccountHandle getPhoneAccountHandle();
+ method public java.lang.String getPrefix();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.telephony.VisualVoicemailSms> CREATOR;
+ }
+
+ public final class VisualVoicemailSmsFilterSettings implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.telephony.VisualVoicemailSmsFilterSettings> CREATOR;
+ field public static final int DESTINATION_PORT_ANY = -1; // 0xffffffff
+ field public static final int DESTINATION_PORT_DATA_SMS = -2; // 0xfffffffe
+ field public final java.lang.String clientPrefix;
+ field public final int destinationPort;
+ field public final java.util.List<java.lang.String> originatingNumbers;
+ }
+
+ public static class VisualVoicemailSmsFilterSettings.Builder {
+ ctor public VisualVoicemailSmsFilterSettings.Builder();
+ method public android.telephony.VisualVoicemailSmsFilterSettings build();
+ method public android.telephony.VisualVoicemailSmsFilterSettings.Builder setClientPrefix(java.lang.String);
+ method public android.telephony.VisualVoicemailSmsFilterSettings.Builder setDestinationPort(int);
+ method public android.telephony.VisualVoicemailSmsFilterSettings.Builder setOriginatingNumbers(java.util.List<java.lang.String>);
+ }
+
}
package android.telephony.cdma {
@@ -53332,15 +53332,15 @@
ctor public DexClassLoader(java.lang.String, java.lang.String, java.lang.String, java.lang.ClassLoader);
}
- public final class DexFile {
- ctor public DexFile(java.io.File) throws java.io.IOException;
- ctor public DexFile(java.lang.String) throws java.io.IOException;
+ public final deprecated class DexFile {
+ ctor public deprecated DexFile(java.io.File) throws java.io.IOException;
+ ctor public deprecated DexFile(java.lang.String) throws java.io.IOException;
method public void close() throws java.io.IOException;
method public java.util.Enumeration<java.lang.String> entries();
method public java.lang.String getName();
method public static boolean isDexOptNeeded(java.lang.String) throws java.io.FileNotFoundException, java.io.IOException;
method public java.lang.Class loadClass(java.lang.String, java.lang.ClassLoader);
- method public static dalvik.system.DexFile loadDex(java.lang.String, java.lang.String, int) throws java.io.IOException;
+ method public static deprecated dalvik.system.DexFile loadDex(java.lang.String, java.lang.String, int) throws java.io.IOException;
}
public final class InMemoryDexClassLoader extends dalvik.system.BaseDexClassLoader {
diff --git a/api/test-current.txt b/api/test-current.txt
index 57e2ed8..2fc87ada 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -36,6 +36,7 @@
field public static final java.lang.String BIND_TELECOM_CONNECTION_SERVICE = "android.permission.BIND_TELECOM_CONNECTION_SERVICE";
field public static final java.lang.String BIND_TEXT_SERVICE = "android.permission.BIND_TEXT_SERVICE";
field public static final java.lang.String BIND_TV_INPUT = "android.permission.BIND_TV_INPUT";
+ field public static final java.lang.String BIND_VISUAL_VOICEMAIL_SERVICE = "android.permission.BIND_VISUAL_VOICEMAIL_SERVICE";
field public static final java.lang.String BIND_VOICE_INTERACTION = "android.permission.BIND_VOICE_INTERACTION";
field public static final java.lang.String BIND_VPN_SERVICE = "android.permission.BIND_VPN_SERVICE";
field public static final java.lang.String BIND_VR_LISTENER_SERVICE = "android.permission.BIND_VR_LISTENER_SERVICE";
@@ -7086,6 +7087,7 @@
method public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback);
method public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback, int);
method public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback, int, int);
+ method public android.bluetooth.BluetoothGatt connectGatt(android.content.Context, boolean, android.bluetooth.BluetoothGattCallback, int, int, android.os.Handler);
method public boolean createBond();
method public android.bluetooth.BluetoothSocket createInsecureRfcommSocketToServiceRecord(java.util.UUID) throws java.io.IOException;
method public android.bluetooth.BluetoothSocket createRfcommSocketToServiceRecord(java.util.UUID) throws java.io.IOException;
@@ -7510,7 +7512,7 @@
method public void setAdvertisingData(android.bluetooth.le.AdvertiseData);
method public void setAdvertisingParameters(android.bluetooth.le.AdvertisingSetParameters);
method public void setPeriodicAdvertisingData(android.bluetooth.le.AdvertiseData);
- method public void setPeriodicAdvertisingEnable(boolean);
+ method public void setPeriodicAdvertisingEnabled(boolean);
method public void setPeriodicAdvertisingParameters(android.bluetooth.le.PeriodicAdvertisingParameters);
method public void setScanResponseData(android.bluetooth.le.AdvertiseData);
}
@@ -7680,8 +7682,10 @@
field public static final android.os.Parcelable.Creator<android.bluetooth.le.ScanResult> CREATOR;
field public static final int DATA_COMPLETE = 0; // 0x0
field public static final int DATA_TRUNCATED = 2; // 0x2
+ field public static final int PERIODIC_INTERVAL_NOT_PRESENT = 0; // 0x0
field public static final int PHY_UNUSED = 0; // 0x0
field public static final int SID_NOT_PRESENT = 255; // 0xff
+ field public static final int TX_POWER_NOT_PRESENT = 127; // 0x7f
}
public final class ScanSettings implements android.os.Parcelable {
@@ -8329,7 +8333,6 @@
field public static final java.lang.String HARDWARE_PROPERTIES_SERVICE = "hardware_properties";
field public static final java.lang.String INPUT_METHOD_SERVICE = "input_method";
field public static final java.lang.String INPUT_SERVICE = "input";
- field public static final java.lang.String IPSEC_SERVICE = "ipsec";
field public static final java.lang.String JOB_SCHEDULER_SERVICE = "jobscheduler";
field public static final java.lang.String KEYGUARD_SERVICE = "keyguard";
field public static final java.lang.String LAUNCHER_APPS_SERVICE = "launcherapps";
@@ -18197,9 +18200,9 @@
method protected final void computeGregorianFields(int);
method protected int computeGregorianMonthStart(int, int);
method protected int computeJulianDay();
- method protected int computeMillisInDay();
+ method protected deprecated int computeMillisInDay();
method protected void computeTime();
- method protected int computeZoneOffset(long, int);
+ method protected deprecated int computeZoneOffset(long, int);
method public int fieldDifference(java.util.Date, int);
method protected java.lang.String fieldName(int);
method protected static final long floorDivide(long, long);
@@ -23944,70 +23947,6 @@
field public static final android.os.Parcelable.Creator<android.net.IpPrefix> CREATOR;
}
- public final class IpSecAlgorithm implements android.os.Parcelable {
- ctor public IpSecAlgorithm(java.lang.String, byte[]);
- ctor public IpSecAlgorithm(java.lang.String, byte[], int);
- method public int describeContents();
- method public byte[] getKey();
- method public java.lang.String getName();
- method public int getTruncationLengthBits();
- method public void writeToParcel(android.os.Parcel, int);
- field public static final java.lang.String AUTH_HMAC_MD5 = "hmac(md5)";
- field public static final java.lang.String AUTH_HMAC_SHA1 = "hmac(sha1)";
- field public static final java.lang.String AUTH_HMAC_SHA256 = "hmac(sha256)";
- field public static final java.lang.String AUTH_HMAC_SHA384 = "hmac(sha384)";
- field public static final java.lang.String AUTH_HMAC_SHA512 = "hmac(sha512)";
- field public static final android.os.Parcelable.Creator<android.net.IpSecAlgorithm> CREATOR;
- field public static final java.lang.String CRYPT_AES_CBC = "cbc(aes)";
- }
-
- public final class IpSecManager {
- method public void applyTransportModeTransform(java.net.Socket, android.net.IpSecTransform) throws java.io.IOException;
- method public void applyTransportModeTransform(java.net.DatagramSocket, android.net.IpSecTransform) throws java.io.IOException;
- method public void applyTransportModeTransform(java.io.FileDescriptor, android.net.IpSecTransform) throws java.io.IOException;
- method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket(int) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
- method public android.net.IpSecManager.UdpEncapsulationSocket openUdpEncapsulationSocket() throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException;
- method public void removeTransportModeTransform(java.net.Socket, android.net.IpSecTransform);
- method public void removeTransportModeTransform(java.net.DatagramSocket, android.net.IpSecTransform);
- method public void removeTransportModeTransform(java.io.FileDescriptor, android.net.IpSecTransform);
- method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(int, java.net.InetAddress) throws android.net.IpSecManager.ResourceUnavailableException;
- method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(int, java.net.InetAddress, int) throws android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
- field public static final int INVALID_SECURITY_PARAMETER_INDEX = 0; // 0x0
- }
-
- public static final class IpSecManager.ResourceUnavailableException extends android.util.AndroidException {
- }
-
- public static final class IpSecManager.SecurityParameterIndex implements java.lang.AutoCloseable {
- method public void close();
- method public int getSpi();
- }
-
- public static final class IpSecManager.SpiUnavailableException extends android.util.AndroidException {
- method public int getSpi();
- }
-
- public static final class IpSecManager.UdpEncapsulationSocket implements java.lang.AutoCloseable {
- method public void close();
- method public int getPort();
- method public java.io.FileDescriptor getSocket();
- }
-
- public final class IpSecTransform implements java.lang.AutoCloseable {
- method public void close();
- field public static final int DIRECTION_IN = 0; // 0x0
- field public static final int DIRECTION_OUT = 1; // 0x1
- }
-
- public static class IpSecTransform.Builder {
- ctor public IpSecTransform.Builder(android.content.Context);
- method public android.net.IpSecTransform buildTransportModeTransform(java.net.InetAddress) throws java.io.IOException, android.net.IpSecManager.ResourceUnavailableException, android.net.IpSecManager.SpiUnavailableException;
- method public android.net.IpSecTransform.Builder setAuthentication(int, android.net.IpSecAlgorithm);
- method public android.net.IpSecTransform.Builder setEncryption(int, android.net.IpSecAlgorithm);
- method public android.net.IpSecTransform.Builder setIpv4Encapsulation(android.net.IpSecManager.UdpEncapsulationSocket, int);
- method public android.net.IpSecTransform.Builder setSpi(int, android.net.IpSecManager.SecurityParameterIndex);
- }
-
public class LinkAddress implements android.os.Parcelable {
method public int describeContents();
method public java.net.InetAddress getAddress();
@@ -33735,8 +33674,8 @@
}
public static final class Telephony.ServiceStateTable {
- method public static android.net.Uri getUriForSubId(int);
- method public static android.net.Uri getUriForSubIdAndField(int, java.lang.String);
+ method public static android.net.Uri getUriForSubscriptionId(int);
+ method public static android.net.Uri getUriForSubscriptionIdAndField(int, java.lang.String);
field public static final java.lang.String AUTHORITY = "service-state";
field public static final android.net.Uri CONTENT_URI;
field public static final java.lang.String IS_MANUAL_NETWORK_SELECTION = "is_manual_network_selection";
@@ -33926,6 +33865,8 @@
public static final class VoicemailContract.Voicemails implements android.provider.BaseColumns android.provider.OpenableColumns {
method public static android.net.Uri buildSourceUri(java.lang.String);
+ field public static final java.lang.String ARCHIVED = "archived";
+ field public static final java.lang.String BACKED_UP = "backed_up";
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";
@@ -33933,6 +33874,7 @@
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";
+ field public static final java.lang.String IS_OMTP_VOICEMAIL = "is_omtp_voicemail";
field public static final java.lang.String IS_READ = "is_read";
field public static final java.lang.String ITEM_TYPE = "vnd.android.cursor.item/voicemail";
field public static final java.lang.String LAST_MODIFIED = "last_modified";
@@ -33940,6 +33882,7 @@
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 RESTORED = "restored";
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";
@@ -37201,7 +37144,6 @@
}
public static final class Connection.RttModifyStatus {
- ctor public Connection.RttModifyStatus();
field public static final int SESSION_MODIFY_REQUEST_FAIL = 2; // 0x2
field public static final int SESSION_MODIFY_REQUEST_INVALID = 3; // 0x3
field public static final int SESSION_MODIFY_REQUEST_REJECTED_BY_REMOTE = 5; // 0x5
@@ -37691,7 +37633,8 @@
field public static final java.lang.String KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL = "carrier_volte_provisioning_required_bool";
field public static final java.lang.String KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL = "carrier_volte_tty_supported_bool";
field public static final java.lang.String KEY_CARRIER_VT_AVAILABLE_BOOL = "carrier_vt_available_bool";
- field public static final java.lang.String KEY_CARRIER_VVM_PACKAGE_NAME_STRING = "carrier_vvm_package_name_string";
+ field public static final deprecated java.lang.String KEY_CARRIER_VVM_PACKAGE_NAME_STRING = "carrier_vvm_package_name_string";
+ field public static final java.lang.String KEY_CARRIER_VVM_PACKAGE_NAME_STRING_ARRAY = "carrier_vvm_package_name_string_array";
field public static final java.lang.String KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL = "carrier_wfc_ims_available_bool";
field public static final java.lang.String KEY_CARRIER_WFC_SUPPORTS_WIFI_ONLY_BOOL = "carrier_wfc_supports_wifi_only_bool";
field public static final java.lang.String KEY_CDMA_DTMF_TONE_DELAY_INT = "cdma_dtmf_tone_delay_int";
@@ -37775,9 +37718,13 @@
field public static final java.lang.String KEY_VOICE_PRIVACY_DISABLE_UI_BOOL = "voice_privacy_disable_ui_bool";
field public static final java.lang.String KEY_VOLTE_REPLACEMENT_RAT_INT = "volte_replacement_rat_int";
field public static final java.lang.String KEY_VVM_CELLULAR_DATA_REQUIRED_BOOL = "vvm_cellular_data_required_bool";
+ field public static final java.lang.String KEY_VVM_CLIENT_PREFIX_STRING = "vvm_client_prefix_string";
field public static final java.lang.String KEY_VVM_DESTINATION_NUMBER_STRING = "vvm_destination_number_string";
+ field public static final java.lang.String KEY_VVM_DISABLED_CAPABILITIES_STRING_ARRAY = "vvm_disabled_capabilities_string_array";
+ field public static final java.lang.String KEY_VVM_LEGACY_MODE_ENABLED_BOOL = "vvm_legacy_mode_enabled_bool";
field public static final java.lang.String KEY_VVM_PORT_NUMBER_INT = "vvm_port_number_int";
field public static final java.lang.String KEY_VVM_PREFETCH_BOOL = "vvm_prefetch_bool";
+ field public static final java.lang.String KEY_VVM_SSL_ENABLED_BOOL = "vvm_ssl_enabled_bool";
field public static final java.lang.String KEY_VVM_TYPE_STRING = "vvm_type_string";
field public static final java.lang.String KEY_WORLD_PHONE_BOOL = "world_phone_bool";
}
@@ -38277,7 +38224,6 @@
method public android.os.PersistableBundle getCarrierConfig();
method public deprecated android.telephony.CellLocation getCellLocation();
method public int getDataActivity();
- method public boolean getDataEnabled();
method public int getDataNetworkType();
method public int getDataState();
method public deprecated java.lang.String getDeviceId();
@@ -38309,6 +38255,7 @@
method public int getSimState();
method public int getSimState(int);
method public java.lang.String getSubscriberId();
+ method public java.lang.String getVisualVoicemailPackageName();
method public java.lang.String getVoiceMailAlphaTag();
method public java.lang.String getVoiceMailNumber();
method public int getVoiceNetworkType();
@@ -38321,6 +38268,8 @@
method public android.telephony.IccOpenLogicalChannelResponse iccOpenLogicalChannel(java.lang.String, int);
method public java.lang.String iccTransmitApduBasicChannel(int, int, int, int, int, java.lang.String);
method public java.lang.String iccTransmitApduLogicalChannel(int, int, int, int, int, int, java.lang.String);
+ method public boolean isConcurrentVoiceAndDataAllowed();
+ method public boolean isDataEnabled();
method public boolean isHearingAidCompatibilitySupported();
method public boolean isNetworkRoaming();
method public boolean isSmsCapable();
@@ -38330,6 +38279,7 @@
method public boolean isWorldPhone();
method public void listen(android.telephony.PhoneStateListener, int);
method public java.lang.String sendEnvelopeWithStatus(java.lang.String);
+ method public void sendUssdRequest(java.lang.String, android.telephony.TelephonyManager.OnReceiveUssdResponseCallback, android.os.Handler);
method public void setDataEnabled(boolean);
method public boolean setLine1NumberForDisplay(java.lang.String, java.lang.String);
method public boolean setOperatorBrandOverride(java.lang.String);
@@ -38404,6 +38354,57 @@
field public static final java.lang.String VVM_TYPE_OMTP = "vvm_type_omtp";
}
+ public static abstract class TelephonyManager.OnReceiveUssdResponseCallback {
+ ctor public TelephonyManager.OnReceiveUssdResponseCallback();
+ method public void onReceiveUssdResponse(java.lang.String, java.lang.CharSequence);
+ method public void onReceiveUssdResponseFailed(java.lang.String, int);
+ }
+
+ public abstract class VisualVoicemailService extends android.app.Service {
+ ctor public VisualVoicemailService();
+ method public android.os.IBinder onBind(android.content.Intent);
+ method public abstract void onCellServiceConnected(android.telephony.VisualVoicemailService.VisualVoicemailTask, android.telecom.PhoneAccountHandle);
+ method public abstract void onSimRemoved(android.telephony.VisualVoicemailService.VisualVoicemailTask, android.telecom.PhoneAccountHandle);
+ method public abstract void onSmsReceived(android.telephony.VisualVoicemailService.VisualVoicemailTask, android.telephony.VisualVoicemailSms);
+ method public abstract void onStopped(android.telephony.VisualVoicemailService.VisualVoicemailTask);
+ method public static final void sendVisualVoicemailSms(android.content.Context, android.telecom.PhoneAccountHandle, java.lang.String, short, java.lang.String, android.app.PendingIntent);
+ method public static final void setSmsFilterSettings(android.content.Context, android.telecom.PhoneAccountHandle, android.telephony.VisualVoicemailSmsFilterSettings);
+ field public static final java.lang.String SERVICE_INTERFACE = "android.telephony.VisualVoicemailService";
+ }
+
+ public static class VisualVoicemailService.VisualVoicemailTask {
+ method public final void finish();
+ }
+
+ public final class VisualVoicemailSms implements android.os.Parcelable {
+ method public int describeContents();
+ method public android.os.Bundle getFields();
+ method public java.lang.String getMessageBody();
+ method public android.telecom.PhoneAccountHandle getPhoneAccountHandle();
+ method public java.lang.String getPrefix();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.telephony.VisualVoicemailSms> CREATOR;
+ }
+
+ public final class VisualVoicemailSmsFilterSettings implements android.os.Parcelable {
+ method public int describeContents();
+ method public void writeToParcel(android.os.Parcel, int);
+ field public static final android.os.Parcelable.Creator<android.telephony.VisualVoicemailSmsFilterSettings> CREATOR;
+ field public static final int DESTINATION_PORT_ANY = -1; // 0xffffffff
+ field public static final int DESTINATION_PORT_DATA_SMS = -2; // 0xfffffffe
+ field public final java.lang.String clientPrefix;
+ field public final int destinationPort;
+ field public final java.util.List<java.lang.String> originatingNumbers;
+ }
+
+ public static class VisualVoicemailSmsFilterSettings.Builder {
+ ctor public VisualVoicemailSmsFilterSettings.Builder();
+ method public android.telephony.VisualVoicemailSmsFilterSettings build();
+ method public android.telephony.VisualVoicemailSmsFilterSettings.Builder setClientPrefix(java.lang.String);
+ method public android.telephony.VisualVoicemailSmsFilterSettings.Builder setDestinationPort(int);
+ method public android.telephony.VisualVoicemailSmsFilterSettings.Builder setOriginatingNumbers(java.util.List<java.lang.String>);
+ }
+
}
package android.telephony.cdma {
@@ -49817,15 +49818,15 @@
ctor public DexClassLoader(java.lang.String, java.lang.String, java.lang.String, java.lang.ClassLoader);
}
- public final class DexFile {
- ctor public DexFile(java.io.File) throws java.io.IOException;
- ctor public DexFile(java.lang.String) throws java.io.IOException;
+ public final deprecated class DexFile {
+ ctor public deprecated DexFile(java.io.File) throws java.io.IOException;
+ ctor public deprecated DexFile(java.lang.String) throws java.io.IOException;
method public void close() throws java.io.IOException;
method public java.util.Enumeration<java.lang.String> entries();
method public java.lang.String getName();
method public static boolean isDexOptNeeded(java.lang.String) throws java.io.FileNotFoundException, java.io.IOException;
method public java.lang.Class loadClass(java.lang.String, java.lang.ClassLoader);
- method public static dalvik.system.DexFile loadDex(java.lang.String, java.lang.String, int) throws java.io.IOException;
+ method public static deprecated dalvik.system.DexFile loadDex(java.lang.String, java.lang.String, int) throws java.io.IOException;
}
public final class InMemoryDexClassLoader extends dalvik.system.BaseDexClassLoader {
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 845a47d..ff52f27 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -466,6 +466,30 @@
"android.bluetooth.adapter.action.BLE_STATE_CHANGED";
/**
+ * Intent used to broadcast the change in the Bluetooth address
+ * of the local Bluetooth adapter.
+ * <p>Always contains the extra field {@link
+ * #EXTRA_BLUETOOTH_ADDRESS} containing the Bluetooth address.
+ *
+ * Note: only system level processes are allowed to send this
+ * defined broadcast.
+ *
+ * @hide
+ */
+ public static final String ACTION_BLUETOOTH_ADDRESS_CHANGED =
+ "android.bluetooth.adapter.action.BLUETOOTH_ADDRESS_CHANGED";
+
+ /**
+ * Used as a String extra field in {@link
+ * #ACTION_BLUETOOTH_ADDRESS_CHANGED} intent to store the local
+ * Bluetooth address.
+ *
+ * @hide
+ */
+ public static final String EXTRA_BLUETOOTH_ADDRESS =
+ "android.bluetooth.adapter.extra.BLUETOOTH_ADDRESS";
+
+ /**
* Broadcast Action: The notifys Bluetooth ACL connected event. This will be
* by BLE Always on enabled application to know the ACL_CONNECTED event
* when Bluetooth state in STATE_BLE_ON. This denotes GATT connection
@@ -1008,28 +1032,6 @@
}
/**
- * enable or disable Bluetooth HCI snoop log.
- *
- * <p>Requires the {@link android.Manifest.permission#BLUETOOTH_ADMIN}
- * permission
- *
- * @return true to indicate configure HCI log successfully, or false on
- * immediate error
- * @hide
- */
- public boolean configHciSnoopLog(boolean enable) {
- try {
- mServiceLock.readLock().lock();
- if (mService != null) return mService.configHciSnoopLog(enable);
- } catch (RemoteException e) {
- Log.e(TAG, "", e);
- } finally {
- mServiceLock.readLock().unlock();
- }
- return false;
- }
-
- /**
* Factory reset bluetooth settings.
*
* <p>Requires the {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED}
@@ -1484,8 +1486,8 @@
}
/**
- * Return the maximum LE advertising data length,
- * if LE Extended Advertising feature is supported.
+ * Return the maximum LE advertising data length in bytes,
+ * if LE Extended Advertising feature is supported, 0 otherwise.
*
* @return the maximum LE advertising data length.
*/
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index e6cebc0..e0b03d2 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -22,6 +22,8 @@
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemApi;
import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.ParcelUuid;
@@ -593,32 +595,38 @@
public static final int TRANSPORT_LE = 2;
/**
- * Bluetooth LE 1M PHY.
+ * Bluetooth LE 1M PHY. Used to refer to LE 1M Physical Channel for advertising, scanning or
+ * connection.
*/
public static final int PHY_LE_1M = 1;
/**
- * Bluetooth LE 2M PHY.
+ * Bluetooth LE 2M PHY. Used to refer to LE 2M Physical Channel for advertising, scanning or
+ * connection.
*/
public static final int PHY_LE_2M = 2;
/**
- * Bluetooth LE Coded PHY.
+ * Bluetooth LE Coded PHY. Used to refer to LE Coded Physical Channel for advertising, scanning
+ * or connection.
*/
public static final int PHY_LE_CODED = 3;
/**
- * Bluetooth LE 1M PHY mask.
+ * Bluetooth LE 1M PHY mask. Used to specify LE 1M Physical Channel as one of many available
+ * options in a bitmask.
*/
public static final int PHY_LE_1M_MASK = 1;
/**
- * Bluetooth LE 2M PHY mask.
+ * Bluetooth LE 2M PHY mask. Used to specify LE 2M Physical Channel as one of many available
+ * options in a bitmask.
*/
public static final int PHY_LE_2M_MASK = 2;
/**
- * Bluetooth LE Coded PHY mask.
+ * Bluetooth LE Coded PHY mask. Used to specify LE Coded Physical Channel as one of many
+ * available options in a bitmask.
*/
public static final int PHY_LE_CODED_MASK = 4;
@@ -1679,12 +1687,45 @@
* {@link BluetoothDevice#TRANSPORT_BREDR} or {@link BluetoothDevice#TRANSPORT_LE}
* @param phy preferred PHY for connections to remote LE device. Bitwise OR of any of
* {@link BluetoothDevice#PHY_LE_1M_MASK}, {@link BluetoothDevice#PHY_LE_2M_MASK},
- * and {@link BluetoothDevice#PHY_LE_CODED_MASK}. This option does not take effect if
- * {@code autoConnect} is set to true.
- * @throws IllegalArgumentException if callback is null
+ * and {@link BluetoothDevice#PHY_LE_CODED_MASK}. This option does not take effect
+ * if {@code autoConnect} is set to true.
+ * @throws NullPointerException if callback is null
*/
public BluetoothGatt connectGatt(Context context, boolean autoConnect,
BluetoothGattCallback callback, int transport, int phy) {
+ return connectGatt(context, autoConnect,callback, TRANSPORT_AUTO, PHY_LE_1M_MASK, null);
+ }
+
+ /**
+ * Connect to GATT Server hosted by this device. Caller acts as GATT client.
+ * The callback is used to deliver results to Caller, such as connection status as well
+ * as any further GATT client operations.
+ * The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct
+ * GATT client operations.
+ * @param callback GATT callback handler that will receive asynchronous callbacks.
+ * @param autoConnect Whether to directly connect to the remote device (false)
+ * or to automatically connect as soon as the remote
+ * device becomes available (true).
+ * @param transport preferred transport for GATT connections to remote dual-mode devices
+ * {@link BluetoothDevice#TRANSPORT_AUTO} or
+ * {@link BluetoothDevice#TRANSPORT_BREDR} or {@link BluetoothDevice#TRANSPORT_LE}
+ * @param phy preferred PHY for connections to remote LE device. Bitwise OR of any of
+ * {@link BluetoothDevice#PHY_LE_1M_MASK}, {@link BluetoothDevice#PHY_LE_2M_MASK},
+ * an d{@link BluetoothDevice#PHY_LE_CODED_MASK}. This option does not take effect
+ * if {@code autoConnect} is set to true.
+ * @param handler The handler to use for the callback. If {@code null}, callbacks will happen
+ * on the service's main thread.
+ * @throws NullPointerException if callback is null
+ */
+ public BluetoothGatt connectGatt(Context context, boolean autoConnect,
+ BluetoothGattCallback callback, int transport, int phy,
+ Handler handler) {
+ if (callback == null)
+ throw new NullPointerException("callback is null");
+
+ if (handler == null)
+ handler = new Handler(Looper.getMainLooper());
+
// TODO(Bluetooth) check whether platform support BLE
// Do the check here or in GattServer?
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
@@ -1696,7 +1737,7 @@
return null;
}
BluetoothGatt gatt = new BluetoothGatt(iGatt, this, transport, phy);
- gatt.connect(autoConnect, callback);
+ gatt.connect(autoConnect, callback, handler);
return gatt;
} catch (RemoteException e) {Log.e(TAG, "", e);}
return null;
diff --git a/core/java/android/bluetooth/BluetoothGatt.java b/core/java/android/bluetooth/BluetoothGatt.java
index 1a969b9..40f10a8 100644
--- a/core/java/android/bluetooth/BluetoothGatt.java
+++ b/core/java/android/bluetooth/BluetoothGatt.java
@@ -17,6 +17,7 @@
package android.bluetooth;
import android.content.Context;
+import android.os.Handler;
import android.os.ParcelUuid;
import android.os.RemoteException;
import android.util.Log;
@@ -43,6 +44,7 @@
private IBluetoothGatt mService;
private BluetoothGattCallback mCallback;
+ private Handler mHandler;
private int mClientIf;
private BluetoothDevice mDevice;
private boolean mAutoConnect;
@@ -154,8 +156,16 @@
}
mClientIf = clientIf;
if (status != GATT_SUCCESS) {
- mCallback.onConnectionStateChange(BluetoothGatt.this, GATT_FAILURE,
- BluetoothProfile.STATE_DISCONNECTED);
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (mCallback != null) {
+ mCallback.onConnectionStateChange(BluetoothGatt.this, GATT_FAILURE,
+ BluetoothProfile.STATE_DISCONNECTED);
+ }
+ }
+ });
+
synchronized(mStateLock) {
mConnState = CONN_STATE_IDLE;
}
@@ -181,11 +191,14 @@
return;
}
- try {
- mCallback.onPhyUpdate(BluetoothGatt.this, txPhy, rxPhy, status);
- } catch (Exception ex) {
- Log.w(TAG, "Unhandled exception in callback", ex);
- }
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (mCallback != null) {
+ mCallback.onPhyUpdate(BluetoothGatt.this, txPhy, rxPhy, status);
+ }
+ }
+ });
}
/**
@@ -200,11 +213,14 @@
return;
}
- try {
- mCallback.onPhyRead(BluetoothGatt.this, txPhy, rxPhy, status);
- } catch (Exception ex) {
- Log.w(TAG, "Unhandled exception in callback", ex);
- }
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (mCallback != null) {
+ mCallback.onPhyRead(BluetoothGatt.this, txPhy, rxPhy, status);
+ }
+ }
+ });
}
/**
@@ -221,11 +237,16 @@
}
int profileState = connected ? BluetoothProfile.STATE_CONNECTED :
BluetoothProfile.STATE_DISCONNECTED;
- try {
- mCallback.onConnectionStateChange(BluetoothGatt.this, status, profileState);
- } catch (Exception ex) {
- Log.w(TAG, "Unhandled exception in callback", ex);
- }
+
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (mCallback != null) {
+ mCallback.onConnectionStateChange(BluetoothGatt.this, status,
+ profileState);
+ }
+ }
+ });
synchronized(mStateLock) {
if (connected) {
@@ -279,11 +300,14 @@
}
}
- try {
- mCallback.onServicesDiscovered(BluetoothGatt.this, status);
- } catch (Exception ex) {
- Log.w(TAG, "Unhandled exception in callback", ex);
- }
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (mCallback != null) {
+ mCallback.onServicesDiscovered(BluetoothGatt.this, status);
+ }
+ }
+ });
}
/**
@@ -328,11 +352,15 @@
if (status == 0) characteristic.setValue(value);
- try {
- mCallback.onCharacteristicRead(BluetoothGatt.this, characteristic, status);
- } catch (Exception ex) {
- Log.w(TAG, "Unhandled exception in callback", ex);
- }
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (mCallback != null) {
+ mCallback.onCharacteristicRead(BluetoothGatt.this, characteristic,
+ status);
+ }
+ }
+ });
}
/**
@@ -373,11 +401,15 @@
mAuthRetryState = AUTH_RETRY_STATE_IDLE;
- try {
- mCallback.onCharacteristicWrite(BluetoothGatt.this, characteristic, status);
- } catch (Exception ex) {
- Log.w(TAG, "Unhandled exception in callback", ex);
- }
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (mCallback != null) {
+ mCallback.onCharacteristicWrite(BluetoothGatt.this, characteristic,
+ status);
+ }
+ }
+ });
}
/**
@@ -398,11 +430,14 @@
characteristic.setValue(value);
- try {
- mCallback.onCharacteristicChanged(BluetoothGatt.this, characteristic);
- } catch (Exception ex) {
- Log.w(TAG, "Unhandled exception in callback", ex);
- }
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (mCallback != null) {
+ mCallback.onCharacteristicChanged(BluetoothGatt.this, characteristic);
+ }
+ }
+ });
}
/**
@@ -442,11 +477,14 @@
mAuthRetryState = AUTH_RETRY_STATE_IDLE;
- try {
- mCallback.onDescriptorRead(BluetoothGatt.this, descriptor, status);
- } catch (Exception ex) {
- Log.w(TAG, "Unhandled exception in callback", ex);
- }
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (mCallback != null) {
+ mCallback.onDescriptorRead(BluetoothGatt.this, descriptor, status);
+ }
+ }
+ });
}
/**
@@ -485,11 +523,14 @@
mAuthRetryState = AUTH_RETRY_STATE_IDLE;
- try {
- mCallback.onDescriptorWrite(BluetoothGatt.this, descriptor, status);
- } catch (Exception ex) {
- Log.w(TAG, "Unhandled exception in callback", ex);
- }
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (mCallback != null) {
+ mCallback.onDescriptorWrite(BluetoothGatt.this, descriptor, status);
+ }
+ }
+ });
}
/**
@@ -508,11 +549,14 @@
mDeviceBusy = false;
}
- try {
- mCallback.onReliableWriteCompleted(BluetoothGatt.this, status);
- } catch (Exception ex) {
- Log.w(TAG, "Unhandled exception in callback", ex);
- }
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (mCallback != null) {
+ mCallback.onReliableWriteCompleted(BluetoothGatt.this, status);
+ }
+ }
+ });
}
/**
@@ -526,11 +570,14 @@
if (!address.equals(mDevice.getAddress())) {
return;
}
- try {
- mCallback.onReadRemoteRssi(BluetoothGatt.this, rssi, status);
- } catch (Exception ex) {
- Log.w(TAG, "Unhandled exception in callback", ex);
- }
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (mCallback != null) {
+ mCallback.onReadRemoteRssi(BluetoothGatt.this, rssi, status);
+ }
+ }
+ });
}
/**
@@ -544,11 +591,15 @@
if (!address.equals(mDevice.getAddress())) {
return;
}
- try {
- mCallback.onMtuChanged(BluetoothGatt.this, mtu, status);
- } catch (Exception ex) {
- Log.w(TAG, "Unhandled exception in callback", ex);
- }
+
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (mCallback != null) {
+ mCallback.onMtuChanged(BluetoothGatt.this, mtu, status);
+ }
+ }
+ });
}
/**
@@ -564,12 +615,16 @@
if (!address.equals(mDevice.getAddress())) {
return;
}
- try {
- mCallback.onConnectionUpdated(BluetoothGatt.this, interval, latency,
- timeout, status);
- } catch (Exception ex) {
- Log.w(TAG, "Unhandled exception in callback", ex);
- }
+
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (mCallback != null) {
+ mCallback.onConnectionUpdated(BluetoothGatt.this, interval, latency,
+ timeout, status);
+ }
+ }
+ });
}
};
@@ -659,11 +714,12 @@
* @return If true, the callback will be called to notify success or failure,
* false on immediate error
*/
- private boolean registerApp(BluetoothGattCallback callback) {
+ private boolean registerApp(BluetoothGattCallback callback, Handler handler) {
if (DBG) Log.d(TAG, "registerApp()");
if (mService == null) return false;
mCallback = callback;
+ mHandler = handler;
UUID uuid = UUID.randomUUID();
if (DBG) Log.d(TAG, "registerApp() - UUID=" + uuid);
@@ -716,7 +772,8 @@
* device becomes available (true).
* @return true, if the connection attempt was initiated successfully
*/
- /*package*/ boolean connect(Boolean autoConnect, BluetoothGattCallback callback) {
+ /*package*/ boolean connect(Boolean autoConnect, BluetoothGattCallback callback,
+ Handler handler) {
if (DBG) Log.d(TAG, "connect() - device: " + mDevice.getAddress() + ", auto: " + autoConnect);
synchronized(mStateLock) {
if (mConnState != CONN_STATE_IDLE) {
@@ -727,7 +784,7 @@
mAutoConnect = autoConnect;
- if (!registerApp(callback)) {
+ if (!registerApp(callback, handler)) {
synchronized(mStateLock) {
mConnState = CONN_STATE_IDLE;
}
@@ -947,6 +1004,41 @@
}
/**
+ * Reads the characteristic using its UUID from the associated remote device.
+ *
+ * <p>This is an asynchronous operation. The result of the read operation
+ * is reported by the {@link BluetoothGattCallback#onCharacteristicRead}
+ * callback.
+ *
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH} permission.
+ *
+ * @param uuid UUID of characteristic to read from the remote device
+ * @return true, if the read operation was initiated successfully
+ * @hide
+ */
+ public boolean readUsingCharacteristicUuid(UUID uuid, int startHandle, int endHandle) {
+ if (VDBG) Log.d(TAG, "readUsingCharacteristicUuid() - uuid: " + uuid);
+ if (mService == null || mClientIf == 0) return false;
+
+ synchronized(mDeviceBusy) {
+ if (mDeviceBusy) return false;
+ mDeviceBusy = true;
+ }
+
+ try {
+ mService.readUsingCharacteristicUuid(mClientIf, mDevice.getAddress(),
+ new ParcelUuid(uuid), startHandle, endHandle, AUTHENTICATION_NONE);
+ } catch (RemoteException e) {
+ Log.e(TAG,"",e);
+ mDeviceBusy = false;
+ return false;
+ }
+
+ return true;
+ }
+
+
+ /**
* Writes a given characteristic and its values to the associated remote device.
*
* <p>Once the write operation has been completed, the
diff --git a/core/java/android/bluetooth/BluetoothGattCallback.java b/core/java/android/bluetooth/BluetoothGattCallback.java
index 11a15c6..c6f82ff 100644
--- a/core/java/android/bluetooth/BluetoothGattCallback.java
+++ b/core/java/android/bluetooth/BluetoothGattCallback.java
@@ -30,7 +30,8 @@
* {@link BluetoothDevice#PHY_LE_2M}, and {@link BluetoothDevice#PHY_LE_CODED}.
* @param rxPhy the receiver PHY in use. One of {@link BluetoothDevice#PHY_LE_1M},
* {@link BluetoothDevice#PHY_LE_2M}, and {@link BluetoothDevice#PHY_LE_CODED}.
- * @param status status of the operation
+ * @param status Status of the PHY update operation.
+ * {@link BluetoothGatt#GATT_SUCCESS} if the operation succeeds.
*/
public void onPhyUpdate(BluetoothGatt gatt, int txPhy, int rxPhy, int status) {
}
@@ -43,7 +44,8 @@
* {@link BluetoothDevice#PHY_LE_2M}, and {@link BluetoothDevice#PHY_LE_CODED}.
* @param rxPhy the receiver PHY in use. One of {@link BluetoothDevice#PHY_LE_1M},
* {@link BluetoothDevice#PHY_LE_2M}, and {@link BluetoothDevice#PHY_LE_CODED}.
- * @param status status of the operation
+ * @param status Status of the PHY read operation.
+ * {@link BluetoothGatt#GATT_SUCCESS} if the operation succeeds.
*/
public void onPhyRead(BluetoothGatt gatt, int txPhy, int rxPhy, int status) {
}
diff --git a/core/java/android/bluetooth/BluetoothGattServerCallback.java b/core/java/android/bluetooth/BluetoothGattServerCallback.java
index 3b8f962..02307bd 100644
--- a/core/java/android/bluetooth/BluetoothGattServerCallback.java
+++ b/core/java/android/bluetooth/BluetoothGattServerCallback.java
@@ -167,7 +167,8 @@
* {@link BluetoothDevice#PHY_LE_2M}, and {@link BluetoothDevice#PHY_LE_CODED}
* @param rxPhy the receiver PHY in use. One of {@link BluetoothDevice#PHY_LE_1M},
* {@link BluetoothDevice#PHY_LE_2M}, and {@link BluetoothDevice#PHY_LE_CODED}
- * @param status status of the operation
+ * @param status Status of the PHY update operation.
+ * {@link BluetoothGatt#GATT_SUCCESS} if the operation succeeds.
*/
public void onPhyUpdate(BluetoothDevice device, int txPhy, int rxPhy, int status) {
}
@@ -180,7 +181,8 @@
* {@link BluetoothDevice#PHY_LE_2M}, and {@link BluetoothDevice#PHY_LE_CODED}
* @param rxPhy the receiver PHY in use. One of {@link BluetoothDevice#PHY_LE_1M},
* {@link BluetoothDevice#PHY_LE_2M}, and {@link BluetoothDevice#PHY_LE_CODED}
- * @param status status of the operation
+ * @param status Status of the PHY read operation.
+ * {@link BluetoothGatt#GATT_SUCCESS} if the operation succeeds.
*/
public void onPhyRead(BluetoothDevice device, int txPhy, int rxPhy, int status) {
}
diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl
index b337817..43c5ae4 100644
--- a/core/java/android/bluetooth/IBluetooth.aidl
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -97,7 +97,6 @@
ParcelFileDescriptor connectSocket(in BluetoothDevice device, int type, in ParcelUuid uuid, int port, int flag);
ParcelFileDescriptor createSocketChannel(int type, in String serviceName, in ParcelUuid uuid, int port, int flag);
- boolean configHciSnoopLog(boolean enable);
boolean factoryReset();
boolean isMultiAdvertisementSupported();
diff --git a/core/java/android/bluetooth/IBluetoothGatt.aidl b/core/java/android/bluetooth/IBluetoothGatt.aidl
index 334e88b..fb6b893 100644
--- a/core/java/android/bluetooth/IBluetoothGatt.aidl
+++ b/core/java/android/bluetooth/IBluetoothGatt.aidl
@@ -31,7 +31,6 @@
import android.bluetooth.IBluetoothGattCallback;
import android.bluetooth.IBluetoothGattServerCallback;
-import android.bluetooth.le.IAdvertiserCallback;
import android.bluetooth.le.IAdvertisingSetCallback;
import android.bluetooth.le.IPeriodicAdvertisingCallback;
import android.bluetooth.le.IScannerCallback;
@@ -56,6 +55,7 @@
in IAdvertisingSetCallback callback);
void stopAdvertisingSet(in IAdvertisingSetCallback callback);
+ void getOwnAddress(in int advertiserId);
void enableAdvertisingSet(in int advertiserId, in boolean enable, in int duration, in int maxExtAdvEvents);
void setAdvertisingData(in int advertiserId, in AdvertiseData data);
void setScanResponseData(in int advertiserId, in AdvertiseData data);
@@ -77,6 +77,8 @@
void refreshDevice(in int clientIf, in String address);
void discoverServices(in int clientIf, in String address);
void readCharacteristic(in int clientIf, in String address, in int handle, in int authReq);
+ void readUsingCharacteristicUuid(in int clientIf, in String address, in ParcelUuid uuid,
+ in int startHandle, in int endHandle, in int authReq);
void writeCharacteristic(in int clientIf, in String address, in int handle,
in int writeType, in int authReq, in byte[] value);
void readDescriptor(in int clientIf, in String address, in int handle, in int authReq);
diff --git a/core/java/android/bluetooth/le/AdvertisingSet.java b/core/java/android/bluetooth/le/AdvertisingSet.java
index 51571b2..1bc211c 100644
--- a/core/java/android/bluetooth/le/AdvertisingSet.java
+++ b/core/java/android/bluetooth/le/AdvertisingSet.java
@@ -172,7 +172,7 @@
*
* @param enable whether the periodic advertising should be enabled (true), or disabled (false).
*/
- public void setPeriodicAdvertisingEnable(boolean enable) {
+ public void setPeriodicAdvertisingEnabled(boolean enable) {
try {
gatt.setPeriodicAdvertisingEnable(this.advertiserId, enable);
} catch (RemoteException e) {
@@ -181,7 +181,23 @@
}
/**
- * Returns advertiserId associated with thsi advertising set.
+ * Returns address associated with this advertising set.
+ * This method is exposed only for Bluetooth PTS tests, no app or system service
+ * should ever use it.
+ *
+ * This method requires {@link android.Manifest.permission#BLUETOOTH_PRIVILEGED} permission.
+ * @hide
+ */
+ public void getOwnAddress(){
+ try {
+ gatt.getOwnAddress(this.advertiserId);
+ } catch (RemoteException e) {
+ Log.e(TAG, "remote exception - ", e);
+ }
+ }
+
+ /**
+ * Returns advertiserId associated with this advertising set.
*
* @hide
*/
diff --git a/core/java/android/bluetooth/le/AdvertisingSetCallback.java b/core/java/android/bluetooth/le/AdvertisingSetCallback.java
index fe3b1cd..c3c16a4 100644
--- a/core/java/android/bluetooth/le/AdvertisingSetCallback.java
+++ b/core/java/android/bluetooth/le/AdvertisingSetCallback.java
@@ -135,7 +135,7 @@
int status) {}
/**
- * Callback triggered in response to {@link AdvertisingSet#setPeriodicAdvertisingEnable}
+ * Callback triggered in response to {@link AdvertisingSet#setPeriodicAdvertisingEnabled}
* indicating result of the operation.
*
* @param advertisingSet The advertising set.
@@ -143,4 +143,15 @@
*/
public void onPeriodicAdvertisingEnabled(AdvertisingSet advertisingSet, boolean enable,
int status) {}
+
+ /**
+ * Callback triggered in response to {@link AdvertisingSet#getOwnAddress()}
+ * indicating result of the operation.
+ *
+ * @param advertisingSet The advertising set.
+ * @param addressType type of address.
+ * @param address advertising set bluetooth address.
+ * @hide
+ */
+ public void onOwnAddressRead(AdvertisingSet advertisingSet, int addressType, String address) {}
}
\ No newline at end of file
diff --git a/core/java/android/bluetooth/le/AdvertisingSetParameters.java b/core/java/android/bluetooth/le/AdvertisingSetParameters.java
index 31d8f48..71c4484 100644
--- a/core/java/android/bluetooth/le/AdvertisingSetParameters.java
+++ b/core/java/android/bluetooth/le/AdvertisingSetParameters.java
@@ -242,7 +242,7 @@
* non-connectable.
* Legacy advertisements can be both connectable and scannable. Non-legacy
* advertisements can be only scannable or only connectable.
- * @param connectable Controls whether the advertisment type will be
+ * @param connectable Controls whether the advertisement type will be
* connectable (true) or non-connectable (false).
*/
public Builder setConnectable(boolean connectable) {
@@ -254,7 +254,7 @@
* Set whether the advertisement type should be scannable.
* Legacy advertisements can be both connectable and scannable. Non-legacy
* advertisements can be only scannable or only connectable.
- * @param scannable Controls whether the advertisment type will be
+ * @param scannable Controls whether the advertisement type will be
* scannable (true) or non-scannable (false).
*/
public Builder setScannable(boolean scannable) {
@@ -386,6 +386,7 @@
/**
* Build the {@link AdvertisingSetParameters} object.
+ * @throws IllegalStateException if invalid combination of parameters is used.
*/
public AdvertisingSetParameters build() {
if (isLegacy) {
@@ -394,22 +395,22 @@
}
if (connectable == true && scannable == false) {
- throw new IllegalArgumentException(
+ throw new IllegalStateException(
"Legacy advertisement can't be connectable and non-scannable");
}
if (includeTxPower) {
- throw new IllegalArgumentException(
+ throw new IllegalStateException(
"Legacy advertising can't include TX power level in header");
}
} else {
if (connectable && scannable) {
- throw new IllegalArgumentException(
+ throw new IllegalStateException(
"Advertising can't be both connectable and scannable");
}
if (isAnonymous && connectable) {
- throw new IllegalArgumentException(
+ throw new IllegalStateException(
"Advertising can't be both connectable and anonymous");
}
}
diff --git a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
index ea3031b..67d56d5 100644
--- a/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
+++ b/core/java/android/bluetooth/le/BluetoothLeAdvertiser.java
@@ -22,7 +22,6 @@
import android.bluetooth.BluetoothUuid;
import android.bluetooth.IBluetoothGatt;
import android.bluetooth.IBluetoothManager;
-import android.bluetooth.le.IAdvertiserCallback;
import android.os.Handler;
import android.os.Looper;
import android.os.ParcelUuid;
@@ -545,6 +544,17 @@
}
@Override
+ public void onOwnAddressRead(int advertiserId, int addressType, String address) {
+ handler.post(new Runnable() {
+ @Override
+ public void run() {
+ AdvertisingSet advertisingSet = mAdvertisingSets.get(advertiserId);
+ callback.onOwnAddressRead(advertisingSet, addressType, address);
+ }
+ });
+ }
+
+ @Override
public void onAdvertisingSetStopped(int advertiserId) {
handler.post(new Runnable() {
@Override
diff --git a/core/java/android/bluetooth/le/IAdvertisingSetCallback.aidl b/core/java/android/bluetooth/le/IAdvertisingSetCallback.aidl
index 2c9f4ba..3628c77 100644
--- a/core/java/android/bluetooth/le/IAdvertisingSetCallback.aidl
+++ b/core/java/android/bluetooth/le/IAdvertisingSetCallback.aidl
@@ -21,6 +21,7 @@
*/
oneway interface IAdvertisingSetCallback {
void onAdvertisingSetStarted(in int advertiserId, in int tx_power, in int status);
+ void onOwnAddressRead(in int advertiserId, in int addressType, in String address);
void onAdvertisingSetStopped(in int advertiserId);
void onAdvertisingEnabled(in int advertiserId, in boolean enable, in int status);
void onAdvertisingDataSet(in int advertiserId, in int status);
diff --git a/core/java/android/bluetooth/le/ScanResult.java b/core/java/android/bluetooth/le/ScanResult.java
index 5b2fa40..e552398 100644
--- a/core/java/android/bluetooth/le/ScanResult.java
+++ b/core/java/android/bluetooth/le/ScanResult.java
@@ -52,6 +52,16 @@
public static final int SID_NOT_PRESENT = 0xFF;
/**
+ * TX power is not present in the packet.
+ */
+ public static final int TX_POWER_NOT_PRESENT = 0x7F;
+
+ /**
+ * Periodic advertising interval is not present in the packet.
+ */
+ public static final int PERIODIC_INTERVAL_NOT_PRESENT = 0x00;
+
+ /**
* Mask for checking whether event type represents legacy advertisement.
*/
private static final int ET_LEGACY_MASK = 0x10;
@@ -265,15 +275,16 @@
/**
* Returns the transmit power in dBm.
- * Valid range is [-127, 126]. A value of 127 indicates that the
- * advertisement did not indicate TX power.
+ * Valid range is [-127, 126]. A value of {@link ScanResult#TX_POWER_NOT_PRESENT}
+ * indicates that the TX power is not present.
*/
public int getTxPower() { return mTxPower; }
/**
* Returns the periodic advertising interval in units of 1.25ms.
- * Valid range is 6 (7.5ms) to 65536 (81918.75ms). A value of 0 means
- * periodic advertising is not used for this scan result.
+ * Valid range is 6 (7.5ms) to 65536 (81918.75ms). A value of
+ * {@link ScanResult#PERIODIC_INTERVAL_NOT_PRESENT} means periodic
+ * advertising interval is not present.
*/
public int getPeriodicAdvertisingInterval() {
return mPeriodicAdvertisingInterval;
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 2512854..b2f2cb7 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2762,9 +2762,6 @@
* <dt> {@link #CONNECTIVITY_SERVICE} ("connection")
* <dd> A {@link android.net.ConnectivityManager ConnectivityManager} for
* handling management of network connections.
- * <dt> {@link #IPSEC_SERVICE} ("ipsec")
- * <dd> A {@link android.net.IpSecManager IpSecManager} for managing IPSec on
- * sockets and networks.
* <dt> {@link #WIFI_SERVICE} ("wifi")
* <dd> A {@link android.net.wifi.WifiManager WifiManager} for management of Wi-Fi
* connectivity. On releases before NYC, it should only be obtained from an application
@@ -3099,6 +3096,7 @@
* {@link android.net.IpSecManager} for encrypting Sockets or Networks with
* IPSec.
*
+ * @hide
* @see #getSystemService
*/
public static final String IPSEC_SERVICE = "ipsec";
diff --git a/core/java/android/hardware/radio/RadioManager.java b/core/java/android/hardware/radio/RadioManager.java
index 14bb923..f079647 100644
--- a/core/java/android/hardware/radio/RadioManager.java
+++ b/core/java/android/hardware/radio/RadioManager.java
@@ -755,8 +755,9 @@
if (!(obj instanceof BandConfig))
return false;
BandConfig other = (BandConfig) obj;
- if (mDescriptor != other.getDescriptor())
- return false;
+ BandDescriptor otherDesc = other.getDescriptor();
+ if ((mDescriptor == null) != (otherDesc == null)) return false;
+ if (mDescriptor != null && !mDescriptor.equals(otherDesc)) return false;
return true;
}
}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 0e5d049..efa1959 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -48,7 +48,6 @@
import com.android.internal.telephony.ITelephony;
import com.android.internal.telephony.PhoneConstants;
-import com.android.internal.util.MessageUtils;
import com.android.internal.util.Preconditions;
import com.android.internal.util.Protocol;
@@ -302,7 +301,8 @@
/**
* Broadcast Action: A tetherable connection has come or gone.
* Uses {@code ConnectivityManager.EXTRA_AVAILABLE_TETHER},
- * {@code ConnectivityManager.EXTRA_ACTIVE_TETHER} and
+ * {@code ConnectivityManager.EXTRA_ACTIVE_LOCAL_ONLY},
+ * {@code ConnectivityManager.EXTRA_ACTIVE_TETHER}, and
* {@code ConnectivityManager.EXTRA_ERRORED_TETHER} to indicate
* the current state of tethering. Each include a list of
* interface names in that state (may be empty).
@@ -321,10 +321,17 @@
/**
* @hide
- * gives a String[] listing all the interfaces currently tethered
- * (ie, has dhcp support and packets potentially forwarded/NATed)
+ * gives a String[] listing all the interfaces currently in local-only
+ * mode (ie, has DHCPv4+IPv6-ULA support and no packet forwarding)
*/
- public static final String EXTRA_ACTIVE_TETHER = "activeArray";
+ public static final String EXTRA_ACTIVE_LOCAL_ONLY = "localOnlyArray";
+
+ /**
+ * @hide
+ * gives a String[] listing all the interfaces currently tethered
+ * (ie, has DHCPv4 support and packets potentially forwarded/NATed)
+ */
+ public static final String EXTRA_ACTIVE_TETHER = "tetherArray";
/**
* @hide
@@ -1863,8 +1870,12 @@
.getPackageNameForUid(context, uid), true /* throwException */);
}
- /** {@hide */
- public static final void enforceTetherChangePermission(Context context) {
+ /** {@hide} */
+ public static final void enforceTetherChangePermission(Context context, String callingPkg) {
+ if (null == context || null == callingPkg) {
+ throw new IllegalArgumentException("arguments should not be null");
+ }
+
if (context.getResources().getStringArray(
com.android.internal.R.array.config_mobile_hotspot_provision_app).length == 2) {
// Have a provisioning app - must only let system apps (which check this app)
@@ -1873,8 +1884,10 @@
android.Manifest.permission.TETHER_PRIVILEGED, "ConnectivityService");
} else {
int uid = Binder.getCallingUid();
- Settings.checkAndNoteWriteSettingsOperation(context, uid, Settings
- .getPackageNameForUid(context, uid), true /* throwException */);
+ // If callingPkg's uid is not same as Binder.getCallingUid(),
+ // AppOpsService throws SecurityException.
+ Settings.checkAndNoteWriteSettingsOperation(context, uid, callingPkg,
+ true /* throwException */);
}
}
@@ -1997,7 +2010,9 @@
*/
public int tether(String iface) {
try {
- return mService.tether(iface);
+ String pkgName = mContext.getOpPackageName();
+ Log.i(TAG, "tether caller:" + pkgName);
+ return mService.tether(iface, pkgName);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2023,7 +2038,9 @@
*/
public int untether(String iface) {
try {
- return mService.untether(iface);
+ String pkgName = mContext.getOpPackageName();
+ Log.i(TAG, "untether caller:" + pkgName);
+ return mService.untether(iface, pkgName);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2114,7 +2131,9 @@
};
try {
- mService.startTethering(type, wrappedCallback, showProvisioningUi);
+ String pkgName = mContext.getOpPackageName();
+ Log.i(TAG, "startTethering caller:" + pkgName);
+ mService.startTethering(type, wrappedCallback, showProvisioningUi, pkgName);
} catch (RemoteException e) {
Log.e(TAG, "Exception trying to start tethering.", e);
wrappedCallback.send(TETHER_ERROR_SERVICE_UNAVAIL, null);
@@ -2134,7 +2153,9 @@
@SystemApi
public void stopTethering(int type) {
try {
- mService.stopTethering(type);
+ String pkgName = mContext.getOpPackageName();
+ Log.i(TAG, "stopTethering caller:" + pkgName);
+ mService.stopTethering(type, pkgName);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2219,7 +2240,9 @@
*/
public int setUsbTethering(boolean enable) {
try {
- return mService.setUsbTethering(enable);
+ String pkgName = mContext.getOpPackageName();
+ Log.i(TAG, "setUsbTethering caller:" + pkgName);
+ return mService.setUsbTethering(enable, pkgName);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -2693,18 +2716,12 @@
public static final int CALLBACK_CAP_CHANGED = BASE + 6;
/** @hide */
public static final int CALLBACK_IP_CHANGED = BASE + 7;
- // TODO: consider deleting CALLBACK_RELEASED and shifting following enum codes down by 1.
- /** @hide */
- public static final int CALLBACK_RELEASED = BASE + 8;
- // TODO: consider deleting CALLBACK_EXIT and shifting following enum codes down by 1.
- /** @hide */
- public static final int CALLBACK_EXIT = BASE + 9;
/** @hide obj = NetworkCapabilities, arg1 = seq number */
- private static final int EXPIRE_LEGACY_REQUEST = BASE + 10;
+ private static final int EXPIRE_LEGACY_REQUEST = BASE + 8;
/** @hide */
- public static final int CALLBACK_SUSPENDED = BASE + 11;
+ public static final int CALLBACK_SUSPENDED = BASE + 9;
/** @hide */
- public static final int CALLBACK_RESUMED = BASE + 12;
+ public static final int CALLBACK_RESUMED = BASE + 10;
/** @hide */
public static String getCallbackName(int whichCallback) {
@@ -2716,8 +2733,6 @@
case CALLBACK_UNAVAIL: return "CALLBACK_UNAVAIL";
case CALLBACK_CAP_CHANGED: return "CALLBACK_CAP_CHANGED";
case CALLBACK_IP_CHANGED: return "CALLBACK_IP_CHANGED";
- case CALLBACK_RELEASED: return "CALLBACK_RELEASED";
- case CALLBACK_EXIT: return "CALLBACK_EXIT";
case EXPIRE_LEGACY_REQUEST: return "EXPIRE_LEGACY_REQUEST";
case CALLBACK_SUSPENDED: return "CALLBACK_SUSPENDED";
case CALLBACK_RESUMED: return "CALLBACK_RESUMED";
@@ -2743,46 +2758,46 @@
NetworkRequest request = getObject(message, NetworkRequest.class);
Network network = getObject(message, Network.class);
if (DBG) {
- Log.d(TAG, whatToString(message.what) + " for network " + network);
+ Log.d(TAG, getCallbackName(message.what) + " for network " + network);
}
switch (message.what) {
case CALLBACK_PRECHECK: {
- NetworkCallback callback = getCallback(request, "PRECHECK");
+ NetworkCallback callback = getCallback(message);
if (callback != null) {
callback.onPreCheck(network);
}
break;
}
case CALLBACK_AVAILABLE: {
- NetworkCallback callback = getCallback(request, "AVAILABLE");
+ NetworkCallback callback = getCallback(message);
if (callback != null) {
callback.onAvailable(network);
}
break;
}
case CALLBACK_LOSING: {
- NetworkCallback callback = getCallback(request, "LOSING");
+ NetworkCallback callback = getCallback(message);
if (callback != null) {
callback.onLosing(network, message.arg1);
}
break;
}
case CALLBACK_LOST: {
- NetworkCallback callback = getCallback(request, "LOST");
+ NetworkCallback callback = getCallback(message);
if (callback != null) {
callback.onLost(network);
}
break;
}
case CALLBACK_UNAVAIL: {
- NetworkCallback callback = getCallback(request, "UNAVAIL");
+ NetworkCallback callback = getCallback(message);
if (callback != null) {
callback.onUnavailable();
}
break;
}
case CALLBACK_CAP_CHANGED: {
- NetworkCallback callback = getCallback(request, "CAP_CHANGED");
+ NetworkCallback callback = getCallback(message);
if (callback != null) {
NetworkCapabilities cap = getObject(message, NetworkCapabilities.class);
callback.onCapabilitiesChanged(network, cap);
@@ -2790,7 +2805,7 @@
break;
}
case CALLBACK_IP_CHANGED: {
- NetworkCallback callback = getCallback(request, "IP_CHANGED");
+ NetworkCallback callback = getCallback(message);
if (callback != null) {
LinkProperties lp = getObject(message, LinkProperties.class);
callback.onLinkPropertiesChanged(network, lp);
@@ -2798,25 +2813,19 @@
break;
}
case CALLBACK_SUSPENDED: {
- NetworkCallback callback = getCallback(request, "SUSPENDED");
+ NetworkCallback callback = getCallback(message);
if (callback != null) {
callback.onNetworkSuspended(network);
}
break;
}
case CALLBACK_RESUMED: {
- NetworkCallback callback = getCallback(request, "RESUMED");
+ NetworkCallback callback = getCallback(message);
if (callback != null) {
callback.onNetworkResumed(network);
}
break;
}
- case CALLBACK_RELEASED: {
- break;
- }
- case CALLBACK_EXIT: {
- break;
- }
case EXPIRE_LEGACY_REQUEST: {
expireRequest((NetworkCapabilities)message.obj, message.arg1);
break;
@@ -2828,13 +2837,14 @@
return (T) msg.getData().getParcelable(c.getSimpleName());
}
- private NetworkCallback getCallback(NetworkRequest req, String name) {
+ private NetworkCallback getCallback(Message msg) {
+ final NetworkRequest req = getObject(msg, NetworkRequest.class);
final NetworkCallback callback;
synchronized(sCallbacks) {
callback = sCallbacks.get(req);
}
if (callback == null) {
- Log.w(TAG, "callback not found for " + name + " message");
+ Log.w(TAG, "callback not found for " + getCallbackName(msg.what) + " message");
}
return callback;
}
@@ -3721,32 +3731,4 @@
throw e.rethrowFromSystemServer();
}
}
-
- /**
- * A holder class for debug info (mapping CALLBACK values to field names). This is stored
- * in a holder for two reasons:
- * 1) The reflection necessary to establish the map can't be run at compile-time. Thus, this
- * code will make the enclosing class not compile-time initializeable, deferring its
- * initialization to zygote startup. This leads to dirty (but shared) memory.
- * As this is debug info, use a holder that isn't initialized by default. This way the map
- * will be created on demand, while ConnectivityManager can be compile-time initialized.
- * 2) Static initialization is still preferred for its strong thread safety guarantees without
- * requiring a lock.
- */
- private static class NoPreloadHolder {
- public static final SparseArray<String> sMagicDecoderRing = MessageUtils.findMessageNames(
- new Class[]{ConnectivityManager.class}, new String[]{"CALLBACK_"});
- }
-
- static {
- // When debug is enabled, aggressively initialize the holder by touching the field (which
- // will guarantee static initialization).
- if (CallbackHandler.DBG) {
- Object dummy = NoPreloadHolder.sMagicDecoderRing;
- }
- }
-
- private static final String whatToString(int what) {
- return NoPreloadHolder.sMagicDecoderRing.get(what, Integer.toString(what));
- }
}
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 425e494..63a1f051 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -69,17 +69,18 @@
boolean requestRouteToHostAddress(int networkType, in byte[] hostAddress);
- int tether(String iface);
+ int tether(String iface, String callerPkg);
- int untether(String iface);
+ int untether(String iface, String callerPkg);
int getLastTetherError(String iface);
boolean isTetheringSupported();
- void startTethering(int type, in ResultReceiver receiver, boolean showProvisioningUi);
+ void startTethering(int type, in ResultReceiver receiver, boolean showProvisioningUi,
+ String callerPkg);
- void stopTethering(int type);
+ void stopTethering(int type, String callerPkg);
String[] getTetherableIfaces();
@@ -95,7 +96,7 @@
String[] getTetherableBluetoothRegexs();
- int setUsbTethering(boolean enable);
+ int setUsbTethering(boolean enable, String callerPkg);
void reportInetCondition(int networkType, int percentage);
diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java
index ce7894f..48b095d 100644
--- a/core/java/android/net/IpSecAlgorithm.java
+++ b/core/java/android/net/IpSecAlgorithm.java
@@ -24,6 +24,8 @@
/**
* IpSecAlgorithm specifies a single algorithm that can be applied to an IpSec Transform. Refer to
* RFC 4301.
+ *
+ * @hide
*/
public final class IpSecAlgorithm implements Parcelable {
diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java
index f8702e2..114e46e 100644
--- a/core/java/android/net/IpSecManager.java
+++ b/core/java/android/net/IpSecManager.java
@@ -37,6 +37,8 @@
* <p>An IpSecManager may be obtained by calling {@link
* android.content.Context#getSystemService(String) Context#getSystemService(String)} with {@link
* android.content.Context#IPSEC_SERVICE Context#IPSEC_SERVICE}
+ *
+ * @hide
*/
public final class IpSecManager {
private static final String TAG = "IpSecManager";
@@ -245,6 +247,7 @@
*
* @param socket a stream socket
* @param transform an {@link IpSecTransform}, which must be an active Transport Mode transform.
+ * @hide
*/
public void applyTransportModeTransform(Socket socket, IpSecTransform transform)
throws IOException {
@@ -262,6 +265,7 @@
*
* @param socket a datagram socket
* @param transform an {@link IpSecTransform}, which must be an active Transport Mode transform.
+ * @hide
*/
public void applyTransportModeTransform(DatagramSocket socket, IpSecTransform transform)
throws IOException {
@@ -284,7 +288,7 @@
* address associated with that transform will throw an IOException. In addition, if the
* IpSecTransform is later deactivated, the socket will throw an IOException on any calls to
* send() or receive() until the transform is removed from the socket by calling {@link
- * #removeTransportModeTransform(Socket, IpSecTransform)};
+ * #removeTransportModeTransform(FileDescriptor, IpSecTransform)};
*
* @param socket a socket file descriptor
* @param transform an {@link IpSecTransform}, which must be an active Transport Mode transform.
@@ -316,8 +320,10 @@
*
* @param socket a socket that previously had a transform applied to it.
* @param transform the IPsec Transform that was previously applied to the given socket
+ * @hide
*/
- public void removeTransportModeTransform(Socket socket, IpSecTransform transform) {
+ public void removeTransportModeTransform(Socket socket, IpSecTransform transform)
+ throws IOException {
removeTransportModeTransform(ParcelFileDescriptor.fromSocket(socket), transform);
}
@@ -330,8 +336,10 @@
*
* @param socket a socket that previously had a transform applied to it.
* @param transform the IPsec Transform that was previously applied to the given socket
+ * @hide
*/
- public void removeTransportModeTransform(DatagramSocket socket, IpSecTransform transform) {
+ public void removeTransportModeTransform(DatagramSocket socket, IpSecTransform transform)
+ throws IOException {
removeTransportModeTransform(ParcelFileDescriptor.fromDatagramSocket(socket), transform);
}
@@ -345,7 +353,8 @@
* @param socket a socket file descriptor that previously had a transform applied to it.
* @param transform the IPsec Transform that was previously applied to the given socket
*/
- public void removeTransportModeTransform(FileDescriptor socket, IpSecTransform transform) {
+ public void removeTransportModeTransform(FileDescriptor socket, IpSecTransform transform)
+ throws IOException {
removeTransportModeTransform(new ParcelFileDescriptor(socket), transform);
}
@@ -419,7 +428,7 @@
*
* @param fd a file descriptor previously returned as a UDP Encapsulation socket.
*/
- public void close() {
+ public void close() throws IOException {
// TODO: Go close the socket
mCloseGuard.close();
}
diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java
index 801e98c..639d1f2 100644
--- a/core/java/android/net/IpSecTransform.java
+++ b/core/java/android/net/IpSecTransform.java
@@ -45,6 +45,8 @@
*
* <p>An IpSecTransform may either represent a tunnel mode transform that operates on a wide array
* of traffic or may represent a transport mode transform operating on a Socket or Sockets.
+ *
+ * @hide
*/
public final class IpSecTransform implements AutoCloseable {
private static final String TAG = "IpSecTransform";
diff --git a/core/java/android/net/NetworkCapabilities.java b/core/java/android/net/NetworkCapabilities.java
index c28294f..1da0d28 100644
--- a/core/java/android/net/NetworkCapabilities.java
+++ b/core/java/android/net/NetworkCapabilities.java
@@ -18,7 +18,9 @@
import android.os.Parcel;
import android.os.Parcelable;
-import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.BitUtils;
import java.util.Objects;
@@ -229,7 +231,8 @@
* Capabilities that suggest that a network is restricted.
* {@see #maybeMarkCapabilitiesRestricted}.
*/
- private static final long RESTRICTED_CAPABILITIES =
+ @VisibleForTesting
+ /* package */ static final long RESTRICTED_CAPABILITIES =
(1 << NET_CAPABILITY_CBS) |
(1 << NET_CAPABILITY_DUN) |
(1 << NET_CAPABILITY_EIMS) |
@@ -240,6 +243,17 @@
(1 << NET_CAPABILITY_XCAP);
/**
+ * Capabilities that suggest that a network is unrestricted.
+ * {@see #maybeMarkCapabilitiesRestricted}.
+ */
+ @VisibleForTesting
+ /* package */ static final long UNRESTRICTED_CAPABILITIES =
+ (1 << NET_CAPABILITY_INTERNET) |
+ (1 << NET_CAPABILITY_MMS) |
+ (1 << NET_CAPABILITY_SUPL) |
+ (1 << NET_CAPABILITY_WIFI_P2P);
+
+ /**
* Adds the given capability to this {@code NetworkCapability} instance.
* Multiple capabilities may be applied sequentially. Note that when searching
* for a network to satisfy a request, all capabilities requested must be satisfied.
@@ -279,7 +293,7 @@
* @hide
*/
public int[] getCapabilities() {
- return enumerateBits(mNetworkCapabilities);
+ return BitUtils.unpackBits(mNetworkCapabilities);
}
/**
@@ -295,19 +309,6 @@
return ((mNetworkCapabilities & (1 << capability)) != 0);
}
- private int[] enumerateBits(long val) {
- int size = Long.bitCount(val);
- int[] result = new int[size];
- int index = 0;
- int resource = 0;
- while (val > 0) {
- if ((val & 1) == 1) result[index++] = resource;
- val = val >> 1;
- resource++;
- }
- return result;
- }
-
private void combineNetCapabilities(NetworkCapabilities nc) {
this.mNetworkCapabilities |= nc.mNetworkCapabilities;
}
@@ -365,12 +366,16 @@
* @hide
*/
public void maybeMarkCapabilitiesRestricted() {
- // If all the capabilities are typically provided by restricted networks, conclude that this
- // network is restricted.
- if ((mNetworkCapabilities & ~(DEFAULT_CAPABILITIES | RESTRICTED_CAPABILITIES)) == 0 &&
- // Must have at least some restricted capabilities, otherwise a request for an
- // internet-less network will get marked restricted.
- (mNetworkCapabilities & RESTRICTED_CAPABILITIES) != 0) {
+ // Verify there aren't any unrestricted capabilities. If there are we say
+ // the whole thing is unrestricted.
+ final boolean hasUnrestrictedCapabilities =
+ ((mNetworkCapabilities & UNRESTRICTED_CAPABILITIES) != 0);
+
+ // Must have at least some restricted capabilities.
+ final boolean hasRestrictedCapabilities =
+ ((mNetworkCapabilities & RESTRICTED_CAPABILITIES) != 0);
+
+ if (hasRestrictedCapabilities && !hasUnrestrictedCapabilities) {
removeCapability(NET_CAPABILITY_NOT_RESTRICTED);
}
}
@@ -416,6 +421,15 @@
private static final int MIN_TRANSPORT = TRANSPORT_CELLULAR;
private static final int MAX_TRANSPORT = TRANSPORT_WIFI_AWARE;
+ private static final String[] TRANSPORT_NAMES = {
+ "CELLULAR",
+ "WIFI",
+ "BLUETOOTH",
+ "ETHERNET",
+ "VPN",
+ "WIFI_AWARE"
+ };
+
/**
* Adds the given transport type to this {@code NetworkCapability} instance.
* Multiple transports may be applied sequentially. Note that when searching
@@ -462,7 +476,7 @@
* @hide
*/
public int[] getTransportTypes() {
- return enumerateBits(mTransportTypes);
+ return BitUtils.unpackBits(mTransportTypes);
}
/**
@@ -869,18 +883,23 @@
* @hide
*/
public static String transportNamesOf(int[] types) {
- String transports = "";
- for (int i = 0; i < types.length;) {
- switch (types[i]) {
- case TRANSPORT_CELLULAR: transports += "CELLULAR"; break;
- case TRANSPORT_WIFI: transports += "WIFI"; break;
- case TRANSPORT_BLUETOOTH: transports += "BLUETOOTH"; break;
- case TRANSPORT_ETHERNET: transports += "ETHERNET"; break;
- case TRANSPORT_VPN: transports += "VPN"; break;
- case TRANSPORT_WIFI_AWARE: transports += "WIFI_AWARE"; break;
- }
- if (++i < types.length) transports += "|";
+ if (types == null || types.length == 0) {
+ return "";
}
- return transports;
+ StringBuilder transports = new StringBuilder();
+ for (int t : types) {
+ transports.append("|").append(transportNameOf(t));
+ }
+ return transports.substring(1);
+ }
+
+ /**
+ * @hide
+ */
+ public static String transportNameOf(int transport) {
+ if (transport < 0 || TRANSPORT_NAMES.length <= transport) {
+ return "UNKNOWN";
+ }
+ return TRANSPORT_NAMES[transport];
}
}
diff --git a/core/java/android/net/NetworkSpecifier.java b/core/java/android/net/NetworkSpecifier.java
index 87a2b05..9ce2a5b 100644
--- a/core/java/android/net/NetworkSpecifier.java
+++ b/core/java/android/net/NetworkSpecifier.java
@@ -33,4 +33,20 @@
* @hide
*/
public abstract boolean satisfiedBy(NetworkSpecifier other);
+
+ /**
+ * Optional method which can be overriden by concrete implementations of NetworkSpecifier to
+ * check a self-reported UID. A concrete implementation may contain a UID which would be self-
+ * reported by the caller (since NetworkSpecifier implementations should be non-mutable). This
+ * function is called by ConnectivityService and is passed the actual UID of the caller -
+ * allowing the verification of the self-reported UID. In cases of mismatch the implementation
+ * should throw a SecurityException.
+ *
+ * @param requestorUid The UID of the requestor as obtained from its binder.
+ *
+ * @hide
+ */
+ public void assertValidFromUid(int requestorUid) {
+ // empty
+ }
}
diff --git a/core/java/android/net/nsd/NsdManager.java b/core/java/android/net/nsd/NsdManager.java
index 1dde3ca..3fd9f19 100644
--- a/core/java/android/net/nsd/NsdManager.java
+++ b/core/java/android/net/nsd/NsdManager.java
@@ -31,6 +31,7 @@
import java.util.concurrent.CountDownLatch;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.AsyncChannel;
import com.android.internal.util.Protocol;
@@ -326,7 +327,8 @@
public void onServiceResolved(NsdServiceInfo serviceInfo);
}
- private class ServiceHandler extends Handler {
+ @VisibleForTesting
+ class ServiceHandler extends Handler {
ServiceHandler(Looper looper) {
super(looper);
}
@@ -370,6 +372,8 @@
((DiscoveryListener) listener).onServiceLost((NsdServiceInfo) message.obj);
break;
case STOP_DISCOVERY_FAILED:
+ // TODO: failure to stop discovery should be internal and retried internally, as
+ // the effect for the client is indistinguishable from STOP_DISCOVERY_SUCCEEDED
removeListener(message.arg2);
((DiscoveryListener) listener).onStopDiscoveryFailed(getNsdServiceInfoType(ns),
message.arg1);
@@ -391,6 +395,8 @@
((RegistrationListener) listener).onUnregistrationFailed(ns, message.arg1);
break;
case UNREGISTER_SERVICE_SUCCEEDED:
+ // TODO: do not unregister listener until service is unregistered, or provide
+ // alternative way for unregistering ?
removeListener(message.arg2);
((RegistrationListener) listener).onServiceUnregistered(ns);
break;
diff --git a/core/java/android/os/HwParcel.java b/core/java/android/os/HwParcel.java
index 94fd5b0..4ba1144 100644
--- a/core/java/android/os/HwParcel.java
+++ b/core/java/android/os/HwParcel.java
@@ -209,10 +209,11 @@
public native final IHwBinder readStrongBinder();
// Handle is stored as part of the blob.
- public native final HwBlob readBuffer();
+ public native final HwBlob readBuffer(long expectedSize);
public native final HwBlob readEmbeddedBuffer(
- long parentHandle, long offset, boolean nullable);
+ long expectedSize, long parentHandle, long offset,
+ boolean nullable);
public native final void writeBuffer(HwBlob blob);
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index dbe2f6d..c34de15 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -315,8 +315,6 @@
void setFirewallEnabled(boolean enabled);
boolean isFirewallEnabled();
void setFirewallInterfaceRule(String iface, boolean allow);
- void setFirewallEgressSourceRule(String addr, boolean allow);
- void setFirewallEgressDestRule(String addr, int port, boolean allow);
void setFirewallUidRule(int chain, int uid, int rule);
void setFirewallUidRules(int chain, in int[] uids, in int[] rules);
void setFirewallChainEnabled(int chain, boolean enable);
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index 4f4152c..2a8ae93 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -728,9 +728,11 @@
int timeTotal = -1;
int uncryptTime = -1;
int sourceVersion = -1;
- int temperature_start = -1;
- int temperature_end = -1;
- int temperature_max = -1;
+ int temperatureStart = -1;
+ int temperatureEnd = -1;
+ int temperatureMax = -1;
+ int errorCode = -1;
+ int causeCode = -1;
while ((line = in.readLine()) != null) {
// Here is an example of lines in last_install:
@@ -777,11 +779,15 @@
bytesStashedInMiB = (bytesStashedInMiB == -1) ? scaled :
bytesStashedInMiB + scaled;
} else if (line.startsWith("temperature_start")) {
- temperature_start = scaled;
+ temperatureStart = scaled;
} else if (line.startsWith("temperature_end")) {
- temperature_end = scaled;
+ temperatureEnd = scaled;
} else if (line.startsWith("temperature_max")) {
- temperature_max = scaled;
+ temperatureMax = scaled;
+ } else if (line.startsWith("error")) {
+ errorCode = scaled;
+ } else if (line.startsWith("cause")) {
+ causeCode = scaled;
}
}
@@ -801,14 +807,20 @@
if (bytesStashedInMiB != -1) {
MetricsLogger.histogram(context, "ota_stashed_in_MiBs", bytesStashedInMiB);
}
- if (temperature_start != -1) {
- MetricsLogger.histogram(context, "ota_temperature_start", temperature_start);
+ if (temperatureStart != -1) {
+ MetricsLogger.histogram(context, "ota_temperature_start", temperatureStart);
}
- if (temperature_end != -1) {
- MetricsLogger.histogram(context, "ota_temperature_end", temperature_end);
+ if (temperatureEnd != -1) {
+ MetricsLogger.histogram(context, "ota_temperature_end", temperatureEnd);
}
- if (temperature_max != -1) {
- MetricsLogger.histogram(context, "ota_temperature_max", temperature_max);
+ if (temperatureMax != -1) {
+ MetricsLogger.histogram(context, "ota_temperature_max", temperatureMax);
+ }
+ if (errorCode != -1) {
+ MetricsLogger.histogram(context, "ota_non_ab_error_code", errorCode);
+ }
+ if (causeCode != -1) {
+ MetricsLogger.histogram(context, "ota_non_ab_cause_code", causeCode);
}
} catch (IOException e) {
diff --git a/core/java/android/os/VintfRuntimeInfo.java b/core/java/android/os/VintfRuntimeInfo.java
new file mode 100644
index 0000000..29698b9
--- /dev/null
+++ b/core/java/android/os/VintfRuntimeInfo.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2017 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.os;
+
+/**
+ * Java API for ::android::vintf::RuntimeInfo. Methods return null / 0 on any error.
+ *
+ * @hide
+ */
+public class VintfRuntimeInfo {
+
+ private VintfRuntimeInfo() {}
+
+ /**
+ * @return /sys/fs/selinux/policyvers, via security_policyvers() native call
+ */
+ public static native long getKernelSepolicyVersion();
+ /**
+ * @return content of /proc/cpuinfo
+ */
+ public static native String getCpuInfo();
+ /**
+ * @return os name extracted from uname() native call
+ */
+ public static native String getOsName();
+ /**
+ * @return node name extracted from uname() native call
+ */
+ public static native String getNodeName();
+ /**
+ * @return os release extracted from uname() native call
+ */
+ public static native String getOsRelease();
+ /**
+ * @return os version extracted from uname() native call
+ */
+ public static native String getOsVersion();
+ /**
+ * @return hardware id extracted from uname() native call
+ */
+ public static native String getHardwareId();
+ /**
+ * @return kernel version extracted from uname() native call. Format is
+ * {@code x.y.z}.
+ */
+ public static native String getKernelVersion();
+ /**
+ * @return libavb version in OS. Format is {@code x.y}.
+ */
+ public static native String getBootAvbVersion();
+ /**
+ * @return libavb version in bootloader. Format is {@code x.y}.
+ */
+ public static native String getBootVbmetaAvbVersion();
+
+}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 3f3f859..35a3c0c 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -4720,13 +4720,6 @@
public static final String VOICE_INTERACTION_SERVICE = "voice_interaction_service";
/**
- * bluetooth HCI snoop log configuration
- * @hide
- */
- public static final String BLUETOOTH_HCI_LOG =
- "bluetooth_hci_log";
-
- /**
* @deprecated Use {@link android.provider.Settings.Global#DEVICE_PROVISIONED} instead
*/
@Deprecated
diff --git a/core/java/android/provider/VoicemailContract.java b/core/java/android/provider/VoicemailContract.java
index 1e54163..a8b094e 100644
--- a/core/java/android/provider/VoicemailContract.java
+++ b/core/java/android/provider/VoicemailContract.java
@@ -107,15 +107,7 @@
/**
* Broadcast intent to inform a new visual voicemail SMS has been received. This intent will
- * only be delivered to the voicemail client. The intent will have the following extra values:
- *
- * <ul>
- * <li><em>{@link #EXTRA_VOICEMAIL_SMS_TYPE}</em> - (String) The event type of the SMS. Common
- * values are "SYNC" or "STATUS"</li>
- * <li><em>{@link #EXTRA_VOICEMAIL_SMS_DATA}</em> - (Bundle) The fields sent by the SMS</li>
- * <li><em>{@link #EXTRA_VOICEMAIL_SMS_SUBID}</em> - (Integer) The subscription ID of the
- * phone account that received the SMS</li>
- * </ul>
+ * only be delivered to the telephony service. {@link #EXTRA_VOICEMAIL_SMS} will be included.
*/
/** @hide */
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
@@ -123,42 +115,11 @@
"android.intent.action.VOICEMAIL_SMS_RECEIVED";
/**
- * Optional extra included in {@link #ACTION_VOICEMAIL_SMS_RECEIVED} broadcast intents to
- * indicate the event type of the SMS. Common values are "SYNC" or "STATUS". The extra will not
- * exist if the framework cannot parse the SMS as voicemail but the carrier pattern indicates
- * it is.
- */
- /** @hide */
- public static final String EXTRA_VOICEMAIL_SMS_PREFIX =
- "com.android.voicemail.extra.VOICEMAIL_SMS_PREFIX";
-
- /**
- * Optional extra included in {@link #ACTION_VOICEMAIL_SMS_RECEIVED} broadcast intents to
- * indicate the fields sent by the SMS. The extra will not exist if the framework cannot
- * parse the SMS as voicemail but the carrier pattern indicates it is.
- */
- /** @hide */
- public static final String EXTRA_VOICEMAIL_SMS_FIELDS =
- "com.android.voicemail.extra.VOICEMAIL_SMS_FIELDS";
-
- /**
- * Extra included in {@link #ACTION_VOICEMAIL_SMS_RECEIVED} broadcast intents to indicate the
- * message body of the SMS. This extra is included if the framework cannot
- * parse the SMS as voicemail but the carrier pattern indicates it is.
- */
- /**
+ * Extra in {@link #ACTION_VOICEMAIL_SMS_RECEIVED} indicating the content of the SMS.
+ *
* @hide
*/
- public static final String EXTRA_VOICEMAIL_SMS_MESSAGE_BODY =
- "com.android.voicemail.extra.VOICEMAIL_SMS_MESSAGE_BODY";
-
- /**
- * Extra included in {@link #ACTION_VOICEMAIL_SMS_RECEIVED} broadcast intents to indicate he
- * subscription ID of the phone account that received the SMS.
- */
- /** @hide */
- public static final String EXTRA_VOICEMAIL_SMS_SUBID =
- "com.android.voicemail.extra.VOICEMAIL_SMS_SUBID";
+ public static final String EXTRA_VOICEMAIL_SMS = "android.provider.extra.VOICEMAIL_SMS";
/**
* Extra included in {@link Intent#ACTION_PROVIDER_CHANGED} broadcast intents to indicate if the
@@ -323,8 +284,6 @@
* not.
*
* <P>Type: INTEGER (boolean)</P>
- *
- * @hide
*/
public static final String BACKED_UP = "backed_up";
@@ -333,8 +292,6 @@
* restored, 0 if not.
*
* <P>Type: INTEGER (boolean)</P>
- *
- * @hide
*/
public static final String RESTORED = "restored";
@@ -344,19 +301,19 @@
* if not.
*
* <P>Type: INTEGER (boolean)</P>
- *
- * @hide
*/
public static final String ARCHIVED = "archived";
/**
* Flag to indicate the voicemail is a OMTP voicemail handled by the {@link
* android.telephony.VisualVoicemailService}. The UI should only show OMTP voicemails from
- * the current visual voicemail package.
+ * the current visual voicemail package. For example, the selection could be
+ * {@code WHERE (IS_OMTP_VOICEMAIL == 0) OR ( IS_OMTP_VOICEMAIL == 1 AND SOURCE_PACKAGE ==
+ * "current.vvm.package")}
*
* <P>Type: INTEGER (boolean)</P>
*
- * @hide
+ * @see android.telephony.TelephonyManager#getVisualVoicemailPackageName
*/
public static final String IS_OMTP_VOICEMAIL = "is_omtp_voicemail";
diff --git a/core/java/android/util/Log.java b/core/java/android/util/Log.java
index d857bf7..951aa8d 100644
--- a/core/java/android/util/Log.java
+++ b/core/java/android/util/Log.java
@@ -89,8 +89,9 @@
/**
* Exception class used to capture a stack trace in {@link #wtf}.
+ * @hide
*/
- private static class TerribleFailure extends Exception {
+ public static class TerribleFailure extends Exception {
TerribleFailure(String msg, Throwable cause) { super(msg, cause); }
}
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 2e9cbf2..eef1cf5 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -1920,7 +1920,7 @@
Trace.traceCounter(Trace.TRACE_TAG_INPUT, PENDING_EVENT_COUNTER,
mPendingEvents.size());
- Message msg = mH.obtainMessage(MSG_TIMEOUT_INPUT_EVENT, p);
+ Message msg = mH.obtainMessage(MSG_TIMEOUT_INPUT_EVENT, seq, 0, p);
msg.setAsynchronous(true);
mH.sendMessageDelayed(msg, INPUT_METHOD_NOT_RESPONDING_TIMEOUT);
return DISPATCH_IN_PROGRESS;
diff --git a/core/java/com/android/internal/util/BitUtils.java b/core/java/com/android/internal/util/BitUtils.java
new file mode 100644
index 0000000..1b354d0
--- /dev/null
+++ b/core/java/com/android/internal/util/BitUtils.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2017 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 com.android.internal.util;
+
+import android.annotation.Nullable;
+
+import libcore.util.Objects;
+
+import java.nio.ByteBuffer;
+import java.util.Arrays;
+import java.util.UUID;
+
+/**
+ * A utility class for handling unsigned integers and unsigned arithmetics, as well as syntactic
+ * sugar methods for ByteBuffer. Useful for networking and packet manipulations.
+ * {@hide}
+ */
+public final class BitUtils {
+ private BitUtils() {}
+
+ public static boolean maskedEquals(long a, long b, long mask) {
+ return (a & mask) == (b & mask);
+ }
+
+ public static boolean maskedEquals(byte a, byte b, byte mask) {
+ return (a & mask) == (b & mask);
+ }
+
+ public static boolean maskedEquals(byte[] a, byte[] b, @Nullable byte[] mask) {
+ if (a == null || b == null) return a == b;
+ Preconditions.checkArgument(a.length == b.length, "Inputs must be of same size");
+ if (mask == null) return Arrays.equals(a, b);
+ Preconditions.checkArgument(a.length == mask.length, "Mask must be of same size as inputs");
+ for (int i = 0; i < mask.length; i++) {
+ if (!maskedEquals(a[i], b[i], mask[i])) return false;
+ }
+ return true;
+ }
+
+ public static boolean maskedEquals(UUID a, UUID b, @Nullable UUID mask) {
+ if (mask == null) {
+ return Objects.equal(a, b);
+ }
+ return maskedEquals(a.getLeastSignificantBits(), b.getLeastSignificantBits(),
+ mask.getLeastSignificantBits())
+ && maskedEquals(a.getMostSignificantBits(), b.getMostSignificantBits(),
+ mask.getMostSignificantBits());
+ }
+
+ public static int[] unpackBits(long val) {
+ int size = Long.bitCount(val);
+ int[] result = new int[size];
+ int index = 0;
+ int bitPos = 0;
+ while (val > 0) {
+ if ((val & 1) == 1) result[index++] = bitPos;
+ val = val >> 1;
+ bitPos++;
+ }
+ return result;
+ }
+
+ public static long packBits(int[] bits) {
+ long packed = 0;
+ for (int b : bits) {
+ packed |= (1 << b);
+ }
+ return packed;
+ }
+
+ public static int uint8(byte b) {
+ return b & 0xff;
+ }
+
+ public static int uint16(short s) {
+ return s & 0xffff;
+ }
+
+ public static long uint32(int i) {
+ return i & 0xffffffffL;
+ }
+
+ public static int bytesToBEInt(byte[] bytes) {
+ return (uint8(bytes[0]) << 24)
+ + (uint8(bytes[1]) << 16)
+ + (uint8(bytes[2]) << 8)
+ + (uint8(bytes[3]));
+ }
+
+ public static int bytesToLEInt(byte[] bytes) {
+ return Integer.reverseBytes(bytesToBEInt(bytes));
+ }
+
+ public static int getUint8(ByteBuffer buffer, int position) {
+ return uint8(buffer.get(position));
+ }
+
+ public static int getUint16(ByteBuffer buffer, int position) {
+ return uint16(buffer.getShort(position));
+ }
+
+ public static long getUint32(ByteBuffer buffer, int position) {
+ return uint32(buffer.getInt(position));
+ }
+
+ public static void put(ByteBuffer buffer, int position, byte[] bytes) {
+ final int original = buffer.position();
+ buffer.position(position);
+ buffer.put(bytes);
+ buffer.position(original);
+ }
+}
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 0834625..7e867d7 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -91,6 +91,7 @@
android_os_Trace.cpp \
android_os_UEventObserver.cpp \
android_os_VintfObject.cpp \
+ android_os_VintfRuntimeInfo.cpp \
android_net_LocalSocketImpl.cpp \
android_net_NetUtils.cpp \
android_net_TrafficStats.cpp \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 898c27e..2b5c0d6 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -165,6 +165,7 @@
extern int register_android_os_Parcel(JNIEnv* env);
extern int register_android_os_SELinux(JNIEnv* env);
extern int register_android_os_VintfObject(JNIEnv *env);
+extern int register_android_os_VintfRuntimeInfo(JNIEnv *env);
extern int register_android_os_seccomp(JNIEnv* env);
extern int register_android_os_SystemProperties(JNIEnv *env);
extern int register_android_os_SystemClock(JNIEnv* env);
@@ -529,7 +530,7 @@
/*
* Reads a "property" into "buffer". If the property is non-empty, it
* is treated as a dex2oat compiler option that should be
- * passed as a quoted option, e.g. "-Ximage-compiler-option --compiler-filter=verify-none".
+ * passed as a quoted option, e.g. "-Ximage-compiler-option --compiler-filter=assume-verified".
*
* The "compilerArg" is a prefix for the option such as "--compiler-filter=".
*
@@ -605,6 +606,7 @@
{
JavaVMInitArgs initArgs;
char propBuf[PROPERTY_VALUE_MAX];
+ char stackTraceDirBuf[sizeof("-Xstacktracedir:")-1 + PROPERTY_VALUE_MAX];
char stackTraceFileBuf[sizeof("-Xstacktracefile:")-1 + PROPERTY_VALUE_MAX];
char jniOptsBuf[sizeof("-Xjniopts:")-1 + PROPERTY_VALUE_MAX];
char heapstartsizeOptsBuf[sizeof("-Xms")-1 + PROPERTY_VALUE_MAX];
@@ -682,7 +684,12 @@
executionMode = kEMJitCompiler;
}
- parseRuntimeOption("dalvik.vm.stack-trace-file", stackTraceFileBuf, "-Xstacktracefile:");
+ // If dalvik.vm.stack-trace-dir is set, it enables the "new" stack trace
+ // dump scheme and a new file is created for each stack dump. If it isn't set,
+ // the old scheme is enabled.
+ if (!parseRuntimeOption("dalvik.vm.stack-trace-dir", stackTraceDirBuf, "-Xstacktracedir:")) {
+ parseRuntimeOption("dalvik.vm.stack-trace-file", stackTraceFileBuf, "-Xstacktracefile:");
+ }
strcpy(jniOptsBuf, "-Xjniopts:");
if (parseRuntimeOption("dalvik.vm.jniopts", jniOptsBuf, "-Xjniopts:")) {
@@ -777,7 +784,7 @@
"-Xmx", "-Ximage-compiler-option");
if (skip_compilation) {
addOption("-Ximage-compiler-option");
- addOption("--compiler-filter=verify-none");
+ addOption("--compiler-filter=assume-verified");
} else {
parseCompilerOption("dalvik.vm.image-dex2oat-filter", dex2oatImageCompilerFilterBuf,
"--compiler-filter=", "-Ximage-compiler-option");
@@ -808,7 +815,7 @@
"-Xmx", "-Xcompiler-option");
if (skip_compilation) {
addOption("-Xcompiler-option");
- addOption("--compiler-filter=verify-none");
+ addOption("--compiler-filter=assume-verified");
// We skip compilation when a minimal runtime is brought up for decryption. In that case
// /data is temporarily backed by a tmpfs, which is usually small.
@@ -1308,6 +1315,7 @@
REG_JNI(register_android_os_HwParcel),
REG_JNI(register_android_os_HwRemoteBinder),
REG_JNI(register_android_os_VintfObject),
+ REG_JNI(register_android_os_VintfRuntimeInfo),
REG_JNI(register_android_nio_utils),
REG_JNI(register_android_graphics_Canvas),
REG_JNI(register_android_graphics_Graphics),
diff --git a/core/jni/android_os_HwParcel.cpp b/core/jni/android_os_HwParcel.cpp
index 678041f..b21ea828 100644
--- a/core/jni/android_os_HwParcel.cpp
+++ b/core/jni/android_os_HwParcel.cpp
@@ -574,7 +574,7 @@
size_t parentHandle;
const hidl_string *s;
- status_t err = parcel->readBuffer(&parentHandle,
+ status_t err = parcel->readBuffer(sizeof(*s), &parentHandle,
reinterpret_cast<const void**>(&s));
if (err != OK) {
@@ -583,7 +583,7 @@
}
err = ::android::hardware::readEmbeddedFromParcel(
- const_cast<hidl_string *>(s),
+ const_cast<hidl_string &>(*s),
*parcel, parentHandle, 0 /* parentOffset */);
if (err != OK) {
@@ -602,7 +602,7 @@
size_t parentHandle; \
\
const hidl_vec<Type> *vec; \
- status_t err = parcel->readBuffer(&parentHandle, \
+ status_t err = parcel->readBuffer(sizeof(*vec), &parentHandle, \
reinterpret_cast<const void**>(&vec)); \
\
if (err != OK) { \
@@ -613,7 +613,7 @@
size_t childHandle; \
\
err = ::android::hardware::readEmbeddedFromParcel( \
- const_cast<hidl_vec<Type> *>(vec), \
+ const_cast<hidl_vec<Type> &>(*vec), \
*parcel, \
parentHandle, \
0 /* parentOffset */, \
@@ -645,7 +645,7 @@
size_t parentHandle;
const hidl_vec<bool> *vec;
- status_t err = parcel->readBuffer(&parentHandle,
+ status_t err = parcel->readBuffer(sizeof(*vec), &parentHandle,
reinterpret_cast<const void**>(&vec));
if (err != OK) {
@@ -656,7 +656,7 @@
size_t childHandle;
err = ::android::hardware::readEmbeddedFromParcel(
- const_cast<hidl_vec<bool> *>(vec),
+ const_cast<hidl_vec<bool> &>(*vec),
*parcel,
parentHandle,
0 /* parentOffset */,
@@ -709,7 +709,7 @@
size_t parentHandle;
const string_vec *vec;
- status_t err = parcel->readBuffer(&parentHandle,
+ status_t err = parcel->readBuffer(sizeof(*vec), &parentHandle,
reinterpret_cast<const void **>(&vec));
if (err != OK) {
@@ -719,16 +719,15 @@
size_t childHandle;
err = ::android::hardware::readEmbeddedFromParcel(
- const_cast<string_vec *>(vec),
+ const_cast<string_vec &>(*vec),
*parcel, parentHandle, 0 /* parentOffset */, &childHandle);
for (size_t i = 0; (err == OK) && (i < vec->size()); ++i) {
err = android::hardware::readEmbeddedFromParcel(
- const_cast<hidl_vec<hidl_string> *>(vec),
+ const_cast<hidl_string &>((*vec)[i]),
*parcel,
childHandle,
- i * sizeof(hidl_string),
- nullptr /* childHandle */);
+ i * sizeof(hidl_string) /* parentOffset */);
}
if (err != OK) {
@@ -810,13 +809,20 @@
return JHwRemoteBinder::NewObject(env, binder);
}
-static jobject JHwParcel_native_readBuffer(JNIEnv *env, jobject thiz) {
+static jobject JHwParcel_native_readBuffer(JNIEnv *env, jobject thiz,
+ jlong expectedSize) {
hardware::Parcel *parcel =
JHwParcel::GetNativeContext(env, thiz)->getParcel();
size_t handle;
const void *ptr;
- status_t status = parcel->readBuffer(&handle, &ptr);
+
+ if (expectedSize < 0) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+ return nullptr;
+ }
+
+ status_t status = parcel->readBuffer(expectedSize, &handle, &ptr);
if (status != OK) {
jniThrowException(env, "java/util/NoSuchElementException", NULL);
@@ -827,8 +833,8 @@
}
static jobject JHwParcel_native_readEmbeddedBuffer(
- JNIEnv *env, jobject thiz, jlong parentHandle, jlong offset,
- jboolean nullable) {
+ JNIEnv *env, jobject thiz, jlong expectedSize,
+ jlong parentHandle, jlong offset, jboolean nullable) {
hardware::Parcel *parcel =
JHwParcel::GetNativeContext(env, thiz)->getParcel();
@@ -836,8 +842,13 @@
const void *ptr;
status_t status =
- parcel->readNullableEmbeddedBuffer(&childHandle, parentHandle, offset,
- &ptr);
+ parcel->readNullableEmbeddedBuffer(expectedSize,
+ &childHandle, parentHandle, offset, &ptr);
+
+ if (expectedSize < 0) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+ return nullptr;
+ }
if (status != OK) {
jniThrowException(env, "java/util/NoSuchElementException", NULL);
@@ -952,10 +963,10 @@
{ "send", "()V", (void *)JHwParcel_native_send },
- { "readBuffer", "()L" PACKAGE_PATH "/HwBlob;",
+ { "readBuffer", "(J)L" PACKAGE_PATH "/HwBlob;",
(void *)JHwParcel_native_readBuffer },
- { "readEmbeddedBuffer", "(JJZ)L" PACKAGE_PATH "/HwBlob;",
+ { "readEmbeddedBuffer", "(JJJZ)L" PACKAGE_PATH "/HwBlob;",
(void *)JHwParcel_native_readEmbeddedBuffer },
{ "writeBuffer", "(L" PACKAGE_PATH "/HwBlob;)V",
diff --git a/core/jni/android_os_VintfRuntimeInfo.cpp b/core/jni/android_os_VintfRuntimeInfo.cpp
new file mode 100644
index 0000000..ecb6854
--- /dev/null
+++ b/core/jni/android_os_VintfRuntimeInfo.cpp
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+#define LOG_TAG "VintfRuntimeInfo"
+//#define LOG_NDEBUG 0
+
+#include <JNIHelp.h>
+#include <vintf/VintfObject.h>
+#include <vintf/parse_string.h>
+#include <vintf/parse_xml.h>
+
+#include "core_jni_helpers.h"
+
+namespace android {
+
+using vintf::RuntimeInfo;
+using vintf::VintfObject;
+
+#define MAP_STRING_METHOD(javaMethod, cppString) \
+ static jstring android_os_VintfRuntimeInfo_##javaMethod(JNIEnv* env, jclass clazz) \
+ { \
+ const RuntimeInfo *info = VintfObject::GetRuntimeInfo(); \
+ if (info == nullptr) return nullptr; \
+ return env->NewStringUTF((cppString).c_str()); \
+ } \
+
+MAP_STRING_METHOD(getCpuInfo, info->cpuInfo());
+MAP_STRING_METHOD(getOsName, info->osName());
+MAP_STRING_METHOD(getNodeName, info->nodeName());
+MAP_STRING_METHOD(getOsRelease, info->osRelease());
+MAP_STRING_METHOD(getOsVersion, info->osVersion());
+MAP_STRING_METHOD(getHardwareId, info->hardwareId());
+MAP_STRING_METHOD(getKernelVersion, vintf::to_string(info->kernelVersion()));
+MAP_STRING_METHOD(getBootAvbVersion, vintf::to_string(info->bootAvbVersion()));
+MAP_STRING_METHOD(getBootVbmetaAvbVersion, vintf::to_string(info->bootVbmetaAvbVersion()));
+
+
+static jlong android_os_VintfRuntimeInfo_getKernelSepolicyVersion(JNIEnv *env, jclass clazz)
+{
+ const RuntimeInfo *info = VintfObject::GetRuntimeInfo();
+ if (info == nullptr) return 0;
+ return static_cast<jlong>(info->kernelSepolicyVersion());
+}
+
+// ----------------------------------------------------------------------------
+
+static const JNINativeMethod gVintfRuntimeInfoMethods[] = {
+ {"getKernelSepolicyVersion", "()J", (void*)android_os_VintfRuntimeInfo_getKernelSepolicyVersion},
+ {"getCpuInfo", "()Ljava/lang/String;", (void*)android_os_VintfRuntimeInfo_getCpuInfo},
+ {"getOsName", "()Ljava/lang/String;", (void*)android_os_VintfRuntimeInfo_getOsName},
+ {"getNodeName", "()Ljava/lang/String;", (void*)android_os_VintfRuntimeInfo_getNodeName},
+ {"getOsRelease", "()Ljava/lang/String;", (void*)android_os_VintfRuntimeInfo_getOsRelease},
+ {"getOsVersion", "()Ljava/lang/String;", (void*)android_os_VintfRuntimeInfo_getOsVersion},
+ {"getHardwareId", "()Ljava/lang/String;", (void*)android_os_VintfRuntimeInfo_getHardwareId},
+ {"getKernelVersion", "()Ljava/lang/String;", (void*)android_os_VintfRuntimeInfo_getKernelVersion},
+ {"getBootAvbVersion", "()Ljava/lang/String;", (void*)android_os_VintfRuntimeInfo_getBootAvbVersion},
+ {"getBootVbmetaAvbVersion", "()Ljava/lang/String;", (void*)android_os_VintfRuntimeInfo_getBootVbmetaAvbVersion},
+};
+
+const char* const kVintfRuntimeInfoPathName = "android/os/VintfRuntimeInfo";
+
+int register_android_os_VintfRuntimeInfo(JNIEnv* env)
+{
+ return RegisterMethodsOrDie(env, kVintfRuntimeInfoPathName, gVintfRuntimeInfoMethods, NELEM(gVintfRuntimeInfoMethods));
+}
+
+};
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index b95258b..6000fb5 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -685,11 +685,14 @@
// Grant CAP_WAKE_ALARM to the Bluetooth process.
// Additionally, allow bluetooth to open packet sockets so it can start the DHCP client.
+ // Grant CAP_SYS_NICE to allow Bluetooth to set RT priority for
+ // audio-related threads.
// TODO: consider making such functionality an RPC to netd.
if (multiuser_get_app_id(uid) == AID_BLUETOOTH) {
capabilities |= (1LL << CAP_WAKE_ALARM);
capabilities |= (1LL << CAP_NET_RAW);
capabilities |= (1LL << CAP_NET_BIND_SERVICE);
+ capabilities |= (1LL << CAP_SYS_NICE);
}
// Grant CAP_BLOCK_SUSPEND to processes that belong to GID "wakelock"
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index f43eb84..c2f27a9 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -122,6 +122,7 @@
<protected-broadcast android:name="android.bluetooth.adapter.action.DISCOVERY_STARTED" />
<protected-broadcast android:name="android.bluetooth.adapter.action.DISCOVERY_FINISHED" />
<protected-broadcast android:name="android.bluetooth.adapter.action.LOCAL_NAME_CHANGED" />
+ <protected-broadcast android:name="android.bluetooth.adapter.action.BLUETOOTH_ADDRESS_CHANGED" />
<protected-broadcast android:name="android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED" />
<protected-broadcast android:name="android.bluetooth.device.action.UUID" />
<protected-broadcast android:name="android.bluetooth.device.action.MAS_INSTANCE" />
@@ -787,16 +788,6 @@
android:description="@string/permdesc_callPhone"
android:protectionLevel="dangerous" />
- <!-- Allows an application to manage its own calls, but rely on the system to route focus to the
- currently active call.
- <p>Protection level: dangerous
- -->
- <permission android:name="android.permission.MANAGE_OWN_CALLS"
- android:permissionGroup="android.permission-group.PHONE"
- android:label="@string/permlab_manageOwnCalls"
- android:description="@string/permdesc_manageOwnCalls"
- android:protectionLevel="dangerous" />
-
<!-- Allows an application to access the IMS call service: making and
modifying a call
<p>Protection level: signature|privileged
@@ -874,6 +865,17 @@
android:description="@string/permdesc_processOutgoingCalls"
android:protectionLevel="dangerous" />
+ <!-- Allows a calling application which manages it own calls through the self-managed
+ {@link android.telecom.ConnectionService} APIs. See
+ {@link android.telecom.PhoneAccount#CAPABILITY_SELF_MANAGED for more information on the
+ self-managed ConnectionService APIs.
+ <p>Protection level: normal
+ -->
+ <permission android:name="android.permission.MANAGE_OWN_CALLS"
+ android:label="@string/permlab_manageOwnCalls"
+ android:description="@string/permdesc_manageOwnCalls"
+ android:protectionLevel="normal" />
+
<!-- ====================================================================== -->
<!-- Permissions for accessing the device microphone -->
<!-- ====================================================================== -->
@@ -1559,6 +1561,14 @@
<permission android:name="android.permission.BIND_INCALL_SERVICE"
android:protectionLevel="signature|privileged" />
+ <!-- Must be required by a link {@link android.telephony.VisualVoicemailService} to ensure that
+ only the system can bind to it.
+ <p>Protection level: signature|privileged
+ -->
+ <permission
+ android:name="android.permission.BIND_VISUAL_VOICEMAIL_SERVICE"
+ android:protectionLevel="signature|privileged"/>
+
<!-- Must be required by a {@link android.telecom.CallScreeningService},
to ensure that only the system can bind to it.
<p>Protection level: signature|privileged
diff --git a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothInstrumentation.java b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothInstrumentation.java
index 411a3f8..37b2a50 100644
--- a/core/tests/bluetoothtests/src/android/bluetooth/BluetoothInstrumentation.java
+++ b/core/tests/bluetoothtests/src/android/bluetooth/BluetoothInstrumentation.java
@@ -72,8 +72,6 @@
getAddress();
} else if ("getBondedDevices".equals(command)) {
getBondedDevices();
- } else if ("enableBtSnoop".equals(command)) {
- enableBtSnoop();
} else {
finish(null);
}
@@ -116,12 +114,6 @@
finish(mSuccessResult);
}
- public void enableBtSnoop() {
- Assert.assertTrue("failed to enable snoop log",
- getBluetoothAdapter().configHciSnoopLog(true));
- finish(mSuccessResult);
- }
-
public void finish(Bundle result) {
if (result == null) {
result = new Bundle();
diff --git a/libs/hwui/JankTracker.cpp b/libs/hwui/JankTracker.cpp
index 2132c2b..9c253c4 100644
--- a/libs/hwui/JankTracker.cpp
+++ b/libs/hwui/JankTracker.cpp
@@ -265,7 +265,6 @@
/ kSlowFrameBucketIntervalMs;
framebucket = std::min(framebucket,
static_cast<uint32_t>(mData->slowFrameCounts.size() - 1));
- framebucket = std::max(framebucket, 0u);
mData->slowFrameCounts[framebucket]++;
}
diff --git a/libs/input/Android.bp b/libs/input/Android.bp
new file mode 100644
index 0000000..84c6cf4
--- /dev/null
+++ b/libs/input/Android.bp
@@ -0,0 +1,43 @@
+// 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.
+
+cc_library_shared {
+ name: "libinputservice",
+
+ srcs: [
+ "PointerController.cpp",
+ "SpriteController.cpp",
+ ],
+
+ shared_libs: [
+ "libcutils",
+ "liblog",
+ "libutils",
+ "libskia",
+ "libgui",
+ "libui",
+ "libinput",
+ "libinputflinger",
+ ],
+
+ include_dirs: ["frameworks/native/services"],
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wunused",
+ "-Wunreachable-code",
+ ],
+
+}
diff --git a/libs/input/Android.mk b/libs/input/Android.mk
deleted file mode 100644
index 2bbfdcc..0000000
--- a/libs/input/Android.mk
+++ /dev/null
@@ -1,53 +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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
- PointerController.cpp \
- SpriteController.cpp
-
-LOCAL_SHARED_LIBRARIES := \
- libcutils \
- liblog \
- libutils \
- libskia \
- libgui \
- libui \
- libinput \
- libinputflinger
-
-LOCAL_C_INCLUDES := \
- frameworks/native/services
-
-
-LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
-
-LOCAL_MODULE:= libinputservice
-
-LOCAL_MODULE_TAGS := optional
-
-include $(BUILD_SHARED_LIBRARY)
-
-
-# Include subdirectory makefiles
-# ============================================================
-
-# If we're building with ONE_SHOT_MAKEFILE (mm, mmm), then what the framework
-# team really wants is to build the stuff defined by this makefile.
-ifeq (,$(ONE_SHOT_MAKEFILE))
-include $(call first-makefiles-under,$(LOCAL_PATH))
-endif
diff --git a/media/java/android/media/session/ICallback.aidl b/media/java/android/media/session/ICallback.aidl
new file mode 100644
index 0000000..bb8a3cc
--- /dev/null
+++ b/media/java/android/media/session/ICallback.aidl
@@ -0,0 +1,34 @@
+/* Copyright (C) 2016 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.media.session;
+
+import android.app.PendingIntent;
+import android.content.ComponentName;
+import android.media.session.MediaSession;
+import android.view.KeyEvent;
+
+/**
+ * @hide
+ */
+oneway interface ICallback {
+ void onMediaKeyEventDispatchedToMediaSession(in KeyEvent event,
+ in MediaSession.Token sessionToken);
+ void onMediaKeyEventDispatchedToMediaButtonReceiver(in KeyEvent event,
+ in ComponentName mediaButtonReceiver);
+
+ void onAddressedPlayerChangedToMediaSession(in MediaSession.Token sessionToken);
+ void onAddressedPlayerChangedToMediaButtonReceiver(in ComponentName mediaButtonReceiver);
+}
diff --git a/media/java/android/media/session/ISessionManager.aidl b/media/java/android/media/session/ISessionManager.aidl
index bb59e5b..575e7d7 100644
--- a/media/java/android/media/session/ISessionManager.aidl
+++ b/media/java/android/media/session/ISessionManager.aidl
@@ -18,6 +18,7 @@
import android.content.ComponentName;
import android.media.IRemoteVolumeController;
import android.media.session.IActiveSessionsListener;
+import android.media.session.ICallback;
import android.media.session.ISession;
import android.media.session.ISessionCallback;
import android.os.Bundle;
@@ -41,4 +42,6 @@
// For PhoneWindowManager to precheck media keys
boolean isGlobalPriorityActive();
-}
\ No newline at end of file
+
+ void setCallback(in ICallback callback);
+}
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index 2364a13..31e60da 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -57,6 +57,8 @@
private Context mContext;
+ private CallbackImpl mCallback;
+
/**
* @hide
*/
@@ -313,6 +315,36 @@
}
/**
+ * Set a {@link Callback}.
+ *
+ * <p>System can only have a single callback, and the callback can only be set by
+ * Bluetooth service process.
+ *
+ * @param callback A {@link Callback}. {@code null} to reset.
+ * @param handler The handler on which the callback should be invoked, or {@code null}
+ * if the callback should be invoked on the calling thread's looper.
+ * @hide
+ */
+ public void setCallback(@Nullable Callback callback, @Nullable Handler handler) {
+ synchronized (mLock) {
+ try {
+ if (callback == null) {
+ mCallback = null;
+ mService.setCallback(null);
+ } else {
+ if (handler == null) {
+ handler = new Handler();
+ }
+ mCallback = new CallbackImpl(callback, handler);
+ mService.setCallback(mCallback);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to set media key callback", e);
+ }
+ }
+ }
+
+ /**
* Listens for changes to the list of active sessions. This can be added
* using {@link #addOnActiveSessionsChangedListener}.
*/
@@ -320,6 +352,56 @@
public void onActiveSessionsChanged(@Nullable List<MediaController> controllers);
}
+ /**
+ * Callbacks for the media session service.
+ *
+ * <p>Called when a media key event is dispatched or the addressed player is changed.
+ * The addressed player is either the media session or the media button receiver that will
+ * receive media key events.
+ * @hide
+ */
+ public static abstract class Callback {
+ /**
+ * Called when a media key event is dispatched to the media session
+ * through the media session service.
+ *
+ * @param event Dispatched media key event.
+ * @param sessionToken The media session's token.
+ */
+ public abstract void onMediaKeyEventDispatched(KeyEvent event,
+ MediaSession.Token sessionToken);
+
+ /**
+ * Called when a media key event is dispatched to the media button receiver
+ * through the media session service.
+ * <p>MediaSessionService may broadcast key events to the media button receiver
+ * when reviving playback after the media session is released.
+ *
+ * @param event Dispatched media key event.
+ * @param mediaButtonReceiver The media button receiver.
+ */
+ public abstract void onMediaKeyEventDispatched(KeyEvent event,
+ ComponentName mediaButtonReceiver);
+
+ /**
+ * Called when the addressed player is changed to a media session.
+ * <p>One of the {@ #onAddressedPlayerChanged} will be also called immediately after
+ * {@link #setCallback} if the addressed player exists.
+ *
+ * @param sessionToken The media session's token.
+ */
+ public abstract void onAddressedPlayerChanged(MediaSession.Token sessionToken);
+
+ /**
+ * Called when the addressed player is changed to the media button receiver.
+ * <p>One of the {@ #onAddressedPlayerChanged} will be also called immediately after
+ * {@link #setCallback} if the addressed player exists.
+ *
+ * @param mediaButtonReceiver The media button receiver.
+ */
+ public abstract void onAddressedPlayerChanged(ComponentName mediaButtonReceiver);
+ }
+
private static final class SessionsChangedWrapper {
private Context mContext;
private OnActiveSessionsChangedListener mListener;
@@ -360,4 +442,57 @@
mHandler = null;
}
}
+
+ private static final class CallbackImpl extends ICallback.Stub {
+ private final Callback mCallback;
+ private final Handler mHandler;
+
+ public CallbackImpl(@NonNull Callback callback, @NonNull Handler handler) {
+ mCallback = callback;
+ mHandler = handler;
+ }
+
+ @Override
+ public void onMediaKeyEventDispatchedToMediaSession(KeyEvent event,
+ MediaSession.Token sessionToken) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mCallback.onMediaKeyEventDispatched(event, sessionToken);
+ }
+ });
+ }
+
+ @Override
+ public void onMediaKeyEventDispatchedToMediaButtonReceiver(KeyEvent event,
+ ComponentName mediaButtonReceiver) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mCallback.onMediaKeyEventDispatched(event, mediaButtonReceiver);
+ }
+ });
+ }
+
+ @Override
+ public void onAddressedPlayerChangedToMediaSession(MediaSession.Token sessionToken) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mCallback.onAddressedPlayerChanged(sessionToken);
+ }
+ });
+ }
+
+ @Override
+ public void onAddressedPlayerChangedToMediaButtonReceiver(
+ ComponentName mediaButtonReceiver) {
+ mHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ mCallback.onAddressedPlayerChanged(mediaButtonReceiver);
+ }
+ });
+ }
+ }
}
diff --git a/obex/javax/obex/ServerSession.java b/obex/javax/obex/ServerSession.java
index 3831cf7..dbfeefd 100644
--- a/obex/javax/obex/ServerSession.java
+++ b/obex/javax/obex/ServerSession.java
@@ -104,7 +104,6 @@
case ObexHelper.OBEX_OPCODE_DISCONNECT:
handleDisconnectRequest();
- done = true;
break;
case ObexHelper.OBEX_OPCODE_GET:
diff --git a/packages/CarrierDefaultApp/AndroidManifest.xml b/packages/CarrierDefaultApp/AndroidManifest.xml
index e450283..2ef1cf5 100644
--- a/packages/CarrierDefaultApp/AndroidManifest.xml
+++ b/packages/CarrierDefaultApp/AndroidManifest.xml
@@ -33,6 +33,7 @@
<receiver android:name="com.android.carrierdefaultapp.CarrierDefaultBroadcastReceiver">
<intent-filter>
<action android:name="com.android.internal.telephony.CARRIER_SIGNAL_REDIRECTED" />
+ <action android:name="com.android.internal.telephony.CARRIER_SIGNAL_RESET" />
</intent-filter>
</receiver>
<service android:name="com.android.carrierdefaultapp.ProvisionObserver"
diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CustomConfigLoader.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CustomConfigLoader.java
index e1125d9..d5d0b79 100644
--- a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CustomConfigLoader.java
+++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CustomConfigLoader.java
@@ -91,6 +91,10 @@
arg1 = intent.getStringExtra(TelephonyIntents.EXTRA_APN_TYPE_KEY);
arg2 = intent.getStringExtra(TelephonyIntents.EXTRA_ERROR_CODE_KEY);
break;
+ case TelephonyIntents.ACTION_CARRIER_SIGNAL_RESET:
+ configs = b.getStringArray(CarrierConfigManager
+ .KEY_CARRIER_DEFAULT_ACTIONS_ON_RESET);
+ break;
default:
Rlog.e(TAG, "load carrier config failure with un-configured key: " +
intent.getAction());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index cdfdad4..267dd3d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -188,9 +188,16 @@
if (mIcon == null) {
return false;
}
- Drawable drawable = getIcon(mIcon);
+ Drawable drawable;
+ try {
+ drawable = getIcon(mIcon);
+ } catch (OutOfMemoryError e) {
+ Log.w(TAG, "OOM while inflating " + mIcon.icon + " for slot " + mSlot);
+ return false;
+ }
+
if (drawable == null) {
- Log.w(TAG, "No icon for slot " + mSlot);
+ Log.w(TAG, "No icon for slot " + mSlot + "; " + mIcon.icon);
return false;
}
if (withClear) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index 03c46e8..024c1a0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -223,8 +223,7 @@
String contentDescription = getStringIfExists(getContentDescription());
String dataContentDescription = getStringIfExists(icons.mDataContentDescription);
- final boolean dataDisabled = mCurrentState.iconGroup == TelephonyIcons.DATA_DISABLED
- && mCurrentState.userSetup;
+ final boolean dataDisabled = isDataDisabled() && mCurrentState.userSetup;
// Show icon in QS when we are connected or data is disabled.
boolean showDataIcon = mCurrentState.dataConnected || dataDisabled;
@@ -404,7 +403,7 @@
mCurrentState.roaming = isRoaming();
if (isCarrierNetworkChangeActive()) {
mCurrentState.iconGroup = TelephonyIcons.CARRIER_NETWORK_CHANGE;
- } else if (isDataDisabled()) {
+ } else if (isDataDisabled() && !mConfig.alwaysShowDataRatIcon) {
mCurrentState.iconGroup = TelephonyIcons.DATA_DISABLED;
}
if (isEmergencyOnly() != mCurrentState.isEmergency) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index 2f7cd00..dd1a4c5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -28,7 +28,9 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
+import android.os.PersistableBundle;
import android.provider.Settings;
+import android.telephony.CarrierConfigManager;
import android.telephony.ServiceState;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
@@ -219,6 +221,7 @@
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
filter.addAction(ConnectivityManager.INET_CONDITION_ACTION);
filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+ filter.addAction(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED);
mContext.registerReceiver(this, filter, null, mReceiverHandler);
mListening = true;
@@ -396,6 +399,14 @@
// emergency state.
recalculateEmergency();
}
+ } else if (action.equals(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED)) {
+ mConfig = Config.readConfig(mContext);
+ mReceiverHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ handleConfigurationChanged();
+ }
+ });
} else {
int subId = intent.getIntExtra(PhoneConstants.SUBSCRIPTION_KEY,
SubscriptionManager.INVALID_SUBSCRIPTION_ID);
@@ -904,6 +915,7 @@
boolean show4gForLte = false;
boolean hideLtePlus = false;
boolean hspaDataDistinguishable;
+ boolean alwaysShowDataRatIcon = false;
static Config readConfig(Context context) {
Config config = new Config();
@@ -916,6 +928,14 @@
config.hspaDataDistinguishable =
res.getBoolean(R.bool.config_hspa_data_distinguishable);
config.hideLtePlus = res.getBoolean(R.bool.config_hideLtePlus);
+
+ CarrierConfigManager configMgr = (CarrierConfigManager)
+ context.getSystemService(Context.CARRIER_CONFIG_SERVICE);
+ PersistableBundle b = configMgr.getConfig();
+ if (b != null) {
+ config.alwaysShowDataRatIcon = b.getBoolean(
+ CarrierConfigManager.KEY_ALWAYS_SHOW_DATA_RAT_ICON_BOOL);
+ }
return config;
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
index fce1172..93e1e6c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
@@ -110,6 +110,21 @@
verifyDataIndicators(0, 0);
}
+ public void testAlwaysShowDataRatIcon() {
+ setupDefaultSignal();
+ Mockito.when(mMockTm.getDataEnabled(mSubId)).thenReturn(false);
+ updateDataConnectionState(TelephonyManager.DATA_DISCONNECTED,
+ TelephonyManager.NETWORK_TYPE_GSM);
+
+ // Switch to showing data RAT icon when data is diconnected
+ // and re-initialize the NetworkController.
+ mConfig.alwaysShowDataRatIcon = true;
+ mNetworkController.handleConfigurationChanged();
+
+ verifyDataIndicators(TelephonyIcons.DATA_G[1][0 /* No direction */],
+ TelephonyIcons.QS_DATA_G);
+ }
+
public void test4gDataIconConfigChange() {
setupDefaultSignal();
updateDataConnectionState(TelephonyManager.DATA_CONNECTED,
diff --git a/rs/java/android/renderscript/ScriptIntrinsicBlur.java b/rs/java/android/renderscript/ScriptIntrinsicBlur.java
index 7a702e8..a36873e 100644
--- a/rs/java/android/renderscript/ScriptIntrinsicBlur.java
+++ b/rs/java/android/renderscript/ScriptIntrinsicBlur.java
@@ -59,6 +59,9 @@
* @param ain The input allocation
*/
public void setInput(Allocation ain) {
+ if (ain.getType().getY() == 0) {
+ throw new RSIllegalArgumentException("Input set to a 1D Allocation");
+ }
mInput = ain;
setVar(1, ain);
}
@@ -85,6 +88,9 @@
* type.
*/
public void forEach(Allocation aout) {
+ if (aout.getType().getY() == 0) {
+ throw new RSIllegalArgumentException("Output is a 1D Allocation");
+ }
forEach(0, (Allocation) null, aout, null);
}
@@ -97,6 +103,9 @@
* @param opt LaunchOptions for clipping
*/
public void forEach(Allocation aout, Script.LaunchOptions opt) {
+ if (aout.getType().getY() == 0) {
+ throw new RSIllegalArgumentException("Output is a 1D Allocation");
+ }
forEach(0, (Allocation) null, aout, null, opt);
}
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index de4734f..1262d88 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -307,6 +307,14 @@
if (newName != null) {
storeNameAndAddress(newName, null);
}
+ } else if (BluetoothAdapter.ACTION_BLUETOOTH_ADDRESS_CHANGED.equals(action)) {
+ String newAddress = intent.getStringExtra(BluetoothAdapter.EXTRA_BLUETOOTH_ADDRESS);
+ if (newAddress != null) {
+ if (DBG) Slog.d(TAG, "Bluetooth Adapter address changed to " + newAddress);
+ storeNameAndAddress(null, newAddress);
+ } else {
+ if (DBG) Slog.e(TAG, "No Bluetooth Adapter address parameter found");
+ }
}
}
};
@@ -343,6 +351,9 @@
IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_LOCAL_NAME_CHANGED);
filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
mContext.registerReceiver(mReceiver, filter);
+ filter = new IntentFilter(BluetoothAdapter.ACTION_BLUETOOTH_ADDRESS_CHANGED);
+ filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
+ mContext.registerReceiver(mReceiver, filter);
loadStoredNameAndAddress();
if (isBluetoothPersistedStateOn()) {
if (DBG) Slog.d(TAG, "Startup: Bluetooth persisted state is ON.");
@@ -1485,16 +1496,6 @@
if (mGetNameAddressOnly) return;
}
- try {
- boolean enableHciSnoopLog = (Settings.Secure.getInt(mContentResolver,
- Settings.Secure.BLUETOOTH_HCI_LOG, 0) == 1);
- if (!mBluetooth.configHciSnoopLog(enableHciSnoopLog)) {
- Slog.e(TAG,"IBluetooth.configHciSnoopLog return false");
- }
- } catch (RemoteException e) {
- Slog.e(TAG,"Unable to call configHciSnoopLog", e);
- }
-
//Register callback object
try {
mBluetooth.registerCallback(mBluetoothCallback);
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index a2293a7..88bc54d 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -36,6 +36,7 @@
import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
import static android.net.NetworkPolicyManager.RULE_TEMPORARY_ALLOW_METERED;
import static android.net.NetworkPolicyManager.uidRulesToString;
+import static com.android.internal.util.Preconditions.checkNotNull;
import android.annotation.Nullable;
import android.app.BroadcastOptions;
@@ -48,7 +49,6 @@
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
-import android.content.res.Resources;
import android.database.ContentObserver;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.PacketKeepalive;
@@ -69,6 +69,7 @@
import android.net.NetworkMisc;
import android.net.NetworkQuotaInfo;
import android.net.NetworkRequest;
+import android.net.NetworkSpecifier;
import android.net.NetworkState;
import android.net.NetworkUtils;
import android.net.Proxy;
@@ -92,6 +93,7 @@
import android.os.Message;
import android.os.Messenger;
import android.os.ParcelFileDescriptor;
+import android.os.Parcelable;
import android.os.PowerManager;
import android.os.Process;
import android.os.RemoteException;
@@ -108,7 +110,6 @@
import android.util.LocalLog;
import android.util.LocalLog.ReadOnlyLocalLog;
import android.util.Log;
-import android.util.Pair;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
@@ -376,11 +377,6 @@
private static final int EVENT_SET_ACCEPT_UNVALIDATED = 28;
/**
- * used to specify whether a network should not be penalized when it becomes unvalidated.
- */
- private static final int EVENT_SET_AVOID_UNVALIDATED = 35;
-
- /**
* used to ask the user to confirm a connection to an unvalidated network.
* obj = network
*/
@@ -397,6 +393,16 @@
*/
private static final int EVENT_REGISTER_NETWORK_LISTENER_WITH_INTENT = 31;
+ /**
+ * used to specify whether a network should not be penalized when it becomes unvalidated.
+ */
+ private static final int EVENT_SET_AVOID_UNVALIDATED = 35;
+
+ /**
+ * used to trigger revalidation of a network.
+ */
+ private static final int EVENT_REVALIDATE_NETWORK = 36;
+
private static String eventName(int what) {
return sMagicDecoderRing.get(what, Integer.toString(what));
}
@@ -869,8 +875,8 @@
}
private void handleMobileDataAlwaysOn() {
- final boolean enable = (Settings.Global.getInt(
- mContext.getContentResolver(), Settings.Global.MOBILE_DATA_ALWAYS_ON, 1) == 1);
+ final boolean enable = toBool(Settings.Global.getInt(
+ mContext.getContentResolver(), Settings.Global.MOBILE_DATA_ALWAYS_ON, 1));
final boolean isEnabled = (mNetworkRequests.get(mDefaultMobileDataRequest) != null);
if (enable == isEnabled) {
return; // Nothing to do.
@@ -2223,7 +2229,7 @@
}
case NetworkMonitor.EVENT_PROVISIONING_NOTIFICATION: {
final int netId = msg.arg2;
- final boolean visible = (msg.arg1 != 0);
+ final boolean visible = toBool(msg.arg1);
final NetworkAgentInfo nai;
synchronized (mNetworkForNetId) {
nai = mNetworkForNetId.get(netId);
@@ -2549,25 +2555,32 @@
}
private void handleTimedOutNetworkRequest(final NetworkRequestInfo nri) {
- if (mNetworkRequests.get(nri.request) != null && mNetworkForRequestId.get(
- nri.request.requestId) == null) {
- handleRemoveNetworkRequest(nri, ConnectivityManager.CALLBACK_UNAVAIL);
+ if (mNetworkRequests.get(nri.request) == null) {
+ return;
}
+ if (mNetworkForRequestId.get(nri.request.requestId) != null) {
+ return;
+ }
+ if (VDBG || (DBG && nri.request.isRequest())) {
+ log("releasing " + nri.request + " (timeout)");
+ }
+ handleRemoveNetworkRequest(nri);
+ callCallbackForRequest(nri, null, ConnectivityManager.CALLBACK_UNAVAIL, 0);
}
private void handleReleaseNetworkRequest(NetworkRequest request, int callingUid) {
- final NetworkRequestInfo nri = getNriForAppRequest(
- request, callingUid, "release NetworkRequest");
- if (nri != null) {
- handleRemoveNetworkRequest(nri, ConnectivityManager.CALLBACK_RELEASED);
+ final NetworkRequestInfo nri =
+ getNriForAppRequest(request, callingUid, "release NetworkRequest");
+ if (nri == null) {
+ return;
}
+ if (VDBG || (DBG && nri.request.isRequest())) {
+ log("releasing " + nri.request + " (release request)");
+ }
+ handleRemoveNetworkRequest(nri);
}
- private void handleRemoveNetworkRequest(final NetworkRequestInfo nri, final int whichCallback) {
- final String logCallbackType = ConnectivityManager.getCallbackName(whichCallback);
- if (VDBG || (DBG && nri.request.isRequest())) {
- log("releasing " + nri.request + " (" + logCallbackType + ")");
- }
+ private void handleRemoveNetworkRequest(final NetworkRequestInfo nri) {
nri.unlinkDeathRecipient();
mNetworkRequests.remove(nri.request);
synchronized (mUidToNetworkRequestCount) {
@@ -2663,14 +2676,13 @@
}
}
}
- callCallbackForRequest(nri, null, whichCallback, 0);
}
@Override
public void setAcceptUnvalidated(Network network, boolean accept, boolean always) {
enforceConnectivityInternalPermission();
mHandler.sendMessage(mHandler.obtainMessage(EVENT_SET_ACCEPT_UNVALIDATED,
- accept ? 1 : 0, always ? 1: 0, network));
+ encodeBool(accept), encodeBool(always), network));
}
@Override
@@ -2707,7 +2719,7 @@
if (always) {
nai.asyncChannel.sendMessage(
- NetworkAgent.CMD_SAVE_ACCEPT_UNVALIDATED, accept ? 1 : 0);
+ NetworkAgent.CMD_SAVE_ACCEPT_UNVALIDATED, encodeBool(accept));
}
if (!accept) {
@@ -2908,7 +2920,8 @@
break;
}
case EVENT_SET_ACCEPT_UNVALIDATED: {
- handleSetAcceptUnvalidated((Network) msg.obj, msg.arg1 != 0, msg.arg2 != 0);
+ Network network = (Network) msg.obj;
+ handleSetAcceptUnvalidated(network, toBool(msg.arg1), toBool(msg.arg2));
break;
}
case EVENT_SET_AVOID_UNVALIDATED: {
@@ -2942,14 +2955,18 @@
}
break;
}
+ case EVENT_REVALIDATE_NETWORK: {
+ handleReportNetworkConnectivity((Network) msg.obj, msg.arg1, toBool(msg.arg2));
+ break;
+ }
}
}
}
// javadoc from interface
@Override
- public int tether(String iface) {
- ConnectivityManager.enforceTetherChangePermission(mContext);
+ public int tether(String iface, String callerPkg) {
+ ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg);
if (isTetheringSupported()) {
final int status = mTethering.tether(iface);
return status;
@@ -2960,8 +2977,8 @@
// javadoc from interface
@Override
- public int untether(String iface) {
- ConnectivityManager.enforceTetherChangePermission(mContext);
+ public int untether(String iface, String callerPkg) {
+ ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg);
if (isTetheringSupported()) {
final int status = mTethering.untether(iface);
@@ -3015,8 +3032,8 @@
}
@Override
- public int setUsbTethering(boolean enable) {
- ConnectivityManager.enforceTetherChangePermission(mContext);
+ public int setUsbTethering(boolean enable, String callerPkg) {
+ ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg);
if (isTetheringSupported()) {
return mTethering.setUsbTethering(enable);
} else {
@@ -3056,9 +3073,10 @@
@Override
public boolean isTetheringSupported() {
enforceTetherAccessPermission();
- int defaultVal = (mSystemProperties.get("ro.tether.denied").equals("true") ? 0 : 1);
- boolean tetherEnabledInSettings = (Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.TETHER_SUPPORTED, defaultVal) != 0)
+ int defaultVal = encodeBool(!mSystemProperties.get("ro.tether.denied").equals("true"));
+ boolean tetherSupported = toBool(Settings.Global.getInt(mContext.getContentResolver(),
+ Settings.Global.TETHER_SUPPORTED, defaultVal));
+ boolean tetherEnabledInSettings = tetherSupported
&& !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING);
// Elevate to system UID to avoid caller requiring MANAGE_USERS permission.
@@ -3070,13 +3088,13 @@
Binder.restoreCallingIdentity(token);
}
- return tetherEnabledInSettings && adminUser &&
- mTethering.hasTetherableConfiguration();
+ return tetherEnabledInSettings && adminUser && mTethering.hasTetherableConfiguration();
}
@Override
- public void startTethering(int type, ResultReceiver receiver, boolean showProvisioningUi) {
- ConnectivityManager.enforceTetherChangePermission(mContext);
+ public void startTethering(int type, ResultReceiver receiver, boolean showProvisioningUi,
+ String callerPkg) {
+ ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg);
if (!isTetheringSupported()) {
receiver.send(ConnectivityManager.TETHER_ERROR_UNSUPPORTED, null);
return;
@@ -3085,8 +3103,8 @@
}
@Override
- public void stopTethering(int type) {
- ConnectivityManager.enforceTetherChangePermission(mContext);
+ public void stopTethering(int type, String callerPkg) {
+ ConnectivityManager.enforceTetherChangePermission(mContext, callerPkg);
mTethering.stopTethering(type);
}
@@ -3148,8 +3166,14 @@
public void reportNetworkConnectivity(Network network, boolean hasConnectivity) {
enforceAccessPermission();
enforceInternetPermission();
+ final int uid = Binder.getCallingUid();
+ final int connectivityInfo = encodeBool(hasConnectivity);
+ mHandler.sendMessage(
+ mHandler.obtainMessage(EVENT_REVALIDATE_NETWORK, uid, connectivityInfo, network));
+ }
- // TODO: execute this logic on ConnectivityService handler.
+ private void handleReportNetworkConnectivity(
+ Network network, int uid, boolean hasConnectivity) {
final NetworkAgentInfo nai;
if (network == null) {
nai = getDefaultNetwork();
@@ -3164,10 +3188,9 @@
if (hasConnectivity == nai.lastValidated) {
return;
}
- final int uid = Binder.getCallingUid();
if (DBG) {
- log("reportNetworkConnectivity(" + nai.network.netId + ", " + hasConnectivity +
- ") by " + uid);
+ int netid = nai.network.netId;
+ log("reportNetworkConnectivity(" + netid + ", " + hasConnectivity + ") by " + uid);
}
// Validating a network that has not yet connected could result in a call to
// rematchNetworkAndRequests() which is not meant to work on such networks.
@@ -3450,13 +3473,6 @@
Slog.e(TAG, s);
}
- private static <T> T checkNotNull(T value, String message) {
- if (value == null) {
- throw new NullPointerException(message);
- }
- return value;
- }
-
/**
* Prepare for a VPN application.
* VPN permissions are checked in the {@link Vpn} class. If the caller is not {@code userId},
@@ -3679,17 +3695,9 @@
existing.shutdown();
}
- try {
- if (tracker != null) {
- mNetd.setFirewallEnabled(true);
- mNetd.setFirewallInterfaceRule("lo", true);
- mLockdownTracker = tracker;
- mLockdownTracker.init();
- } else {
- mNetd.setFirewallEnabled(false);
- }
- } catch (RemoteException e) {
- // ignored; NMS lives inside system_server
+ if (tracker != null) {
+ mLockdownTracker = tracker;
+ mLockdownTracker.init();
}
}
@@ -3885,7 +3893,7 @@
final long ident = Binder.clearCallingIdentity();
try {
final ContentResolver cr = mContext.getContentResolver();
- Settings.Global.putInt(cr, Settings.Global.AIRPLANE_MODE_ON, enable ? 1 : 0);
+ Settings.Global.putInt(cr, Settings.Global.AIRPLANE_MODE_ON, encodeBool(enable));
Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
intent.putExtra("state", enable);
mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
@@ -4122,6 +4130,18 @@
0, 0, thresholds);
}
+ private void ensureValidNetworkSpecifier(NetworkCapabilities nc) {
+ if (nc == null) {
+ return;
+ }
+ NetworkSpecifier ns = nc.getNetworkSpecifier();
+ if (ns == null) {
+ return;
+ }
+ MatchAllNetworkSpecifier.checkNotMatchAllNetworkSpecifier(ns);
+ ns.assertValidFromUid(Binder.getCallingUid());
+ }
+
@Override
public NetworkRequest requestNetwork(NetworkCapabilities networkCapabilities,
Messenger messenger, int timeoutMs, IBinder binder, int legacyType) {
@@ -4147,9 +4167,7 @@
if (timeoutMs < 0) {
throw new IllegalArgumentException("Bad timeout specified");
}
-
- MatchAllNetworkSpecifier.checkNotMatchAllNetworkSpecifier(
- networkCapabilities.getNetworkSpecifier());
+ ensureValidNetworkSpecifier(networkCapabilities);
NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, legacyType,
nextNetworkRequestId(), type);
@@ -4221,9 +4239,7 @@
enforceNetworkRequestPermissions(networkCapabilities);
enforceMeteredApnPolicy(networkCapabilities);
ensureRequestableCapabilities(networkCapabilities);
-
- MatchAllNetworkSpecifier.checkNotMatchAllNetworkSpecifier(
- networkCapabilities.getNetworkSpecifier());
+ ensureValidNetworkSpecifier(networkCapabilities);
NetworkRequest networkRequest = new NetworkRequest(networkCapabilities, TYPE_NONE,
nextNetworkRequestId(), NetworkRequest.Type.REQUEST);
@@ -4285,9 +4301,7 @@
// can't request networks.
nc.addCapability(NET_CAPABILITY_FOREGROUND);
}
-
- MatchAllNetworkSpecifier.checkNotMatchAllNetworkSpecifier(
- networkCapabilities.getNetworkSpecifier());
+ ensureValidNetworkSpecifier(networkCapabilities);
NetworkRequest networkRequest = new NetworkRequest(nc, TYPE_NONE, nextNetworkRequestId(),
NetworkRequest.Type.LISTEN);
@@ -4305,9 +4319,7 @@
if (!hasWifiNetworkListenPermission(networkCapabilities)) {
enforceAccessPermission();
}
-
- MatchAllNetworkSpecifier.checkNotMatchAllNetworkSpecifier(
- networkCapabilities.getNetworkSpecifier());
+ ensureValidNetworkSpecifier(networkCapabilities);
NetworkRequest networkRequest = new NetworkRequest(
new NetworkCapabilities(networkCapabilities), TYPE_NONE, nextNetworkRequestId(),
@@ -4728,16 +4740,17 @@
releasePendingNetworkRequestWithDelay(pendingIntent);
}
- private void callCallbackForRequest(NetworkRequestInfo nri,
+ private static void callCallbackForRequest(NetworkRequestInfo nri,
NetworkAgentInfo networkAgent, int notificationType, int arg1) {
- if (nri.messenger == null) return; // Default request has no msgr
+ if (nri.messenger == null) {
+ return; // Default request has no msgr
+ }
Bundle bundle = new Bundle();
- bundle.putParcelable(NetworkRequest.class.getSimpleName(),
- new NetworkRequest(nri.request));
+ // TODO: check if defensive copies of data is needed.
+ putParcelable(bundle, new NetworkRequest(nri.request));
Message msg = Message.obtain();
- if (notificationType != ConnectivityManager.CALLBACK_UNAVAIL &&
- notificationType != ConnectivityManager.CALLBACK_RELEASED) {
- bundle.putParcelable(Network.class.getSimpleName(), networkAgent.network);
+ if (notificationType != ConnectivityManager.CALLBACK_UNAVAIL) {
+ putParcelable(bundle, networkAgent.network);
}
switch (notificationType) {
case ConnectivityManager.CALLBACK_LOSING: {
@@ -4745,13 +4758,11 @@
break;
}
case ConnectivityManager.CALLBACK_CAP_CHANGED: {
- bundle.putParcelable(NetworkCapabilities.class.getSimpleName(),
- new NetworkCapabilities(networkAgent.networkCapabilities));
+ putParcelable(bundle, new NetworkCapabilities(networkAgent.networkCapabilities));
break;
}
case ConnectivityManager.CALLBACK_IP_CHANGED: {
- bundle.putParcelable(LinkProperties.class.getSimpleName(),
- new LinkProperties(networkAgent.linkProperties));
+ putParcelable(bundle, new LinkProperties(networkAgent.linkProperties));
break;
}
}
@@ -4759,8 +4770,8 @@
msg.setData(bundle);
try {
if (VDBG) {
- log("sending notification " + notifyTypeToName(notificationType) +
- " for " + nri.request);
+ String notification = ConnectivityManager.getCallbackName(notificationType);
+ log("sending notification " + notification + " for " + nri.request);
}
nri.messenger.send(msg);
} catch (RemoteException e) {
@@ -4769,6 +4780,10 @@
}
}
+ private static <T extends Parcelable> void putParcelable(Bundle bundle, T t) {
+ bundle.putParcelable(t.getClass().getSimpleName(), t);
+ }
+
private void teardownUnneededNetwork(NetworkAgentInfo nai) {
if (nai.numRequestNetworkRequests() != 0) {
for (int i = 0; i < nai.numNetworkRequests(); i++) {
@@ -5370,7 +5385,10 @@
}
protected void notifyNetworkCallbacks(NetworkAgentInfo networkAgent, int notifyType, int arg1) {
- if (VDBG) log("notifyType " + notifyTypeToName(notifyType) + " for " + networkAgent.name());
+ if (VDBG) {
+ String notification = ConnectivityManager.getCallbackName(notifyType);
+ log("notifyType " + notification + " for " + networkAgent.name());
+ }
for (int i = 0; i < networkAgent.numNetworkRequests(); i++) {
NetworkRequest nr = networkAgent.requestAt(i);
NetworkRequestInfo nri = mNetworkRequests.get(nr);
@@ -5389,20 +5407,6 @@
notifyNetworkCallbacks(networkAgent, notifyType, 0);
}
- private String notifyTypeToName(int notifyType) {
- switch (notifyType) {
- case ConnectivityManager.CALLBACK_PRECHECK: return "PRECHECK";
- case ConnectivityManager.CALLBACK_AVAILABLE: return "AVAILABLE";
- case ConnectivityManager.CALLBACK_LOSING: return "LOSING";
- case ConnectivityManager.CALLBACK_LOST: return "LOST";
- case ConnectivityManager.CALLBACK_UNAVAIL: return "UNAVAILABLE";
- case ConnectivityManager.CALLBACK_CAP_CHANGED: return "CAP_CHANGED";
- case ConnectivityManager.CALLBACK_IP_CHANGED: return "IP_CHANGED";
- case ConnectivityManager.CALLBACK_RELEASED: return "RELEASED";
- }
- return "UNKNOWN";
- }
-
/**
* Notify NetworkStatsService that the set of active ifaces has changed, or that one of the
* properties tracked by NetworkStatsService on an active iface has changed.
@@ -5482,8 +5486,9 @@
if (!mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING)) {
// Untether
+ String pkgName = mContext.getOpPackageName();
for (String tether : getTetheredIfaces()) {
- untether(tether);
+ untether(tether, pkgName);
}
}
@@ -5568,4 +5573,12 @@
private void logNetworkEvent(NetworkAgentInfo nai, int evtype) {
mMetricsLog.log(new NetworkEvent(nai.network.netId, evtype));
}
+
+ private static boolean toBool(int encodedBoolean) {
+ return encodedBoolean != 0; // Only 0 means false.
+ }
+
+ private static int encodeBool(boolean b) {
+ return b ? 1 : 0;
+ }
}
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 87938cb..7e1a1ca 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -95,7 +95,6 @@
import com.android.internal.util.Preconditions;
import com.android.server.NativeDaemonConnector.Command;
import com.android.server.NativeDaemonConnector.SensitiveArg;
-import com.android.server.net.LockdownVpnTracker;
import com.google.android.collect.Maps;
import java.io.BufferedReader;
@@ -628,7 +627,7 @@
}
}
- setFirewallEnabled(mFirewallEnabled || LockdownVpnTracker.isEnabled());
+ setFirewallEnabled(mFirewallEnabled);
syncFirewallChainLocked(FIREWALL_CHAIN_NONE, mUidFirewallRules, "");
syncFirewallChainLocked(FIREWALL_CHAIN_STANDBY, mUidFirewallStandbyRules, "standby ");
@@ -1897,30 +1896,6 @@
}
}
- @Override
- public void setFirewallEgressSourceRule(String addr, boolean allow) {
- enforceSystemUid();
- Preconditions.checkState(mFirewallEnabled);
- final String rule = allow ? "allow" : "deny";
- try {
- mConnector.execute("firewall", "set_egress_source_rule", addr, rule);
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
- }
- }
-
- @Override
- public void setFirewallEgressDestRule(String addr, int port, boolean allow) {
- enforceSystemUid();
- Preconditions.checkState(mFirewallEnabled);
- final String rule = allow ? "allow" : "deny";
- try {
- mConnector.execute("firewall", "set_egress_dest_rule", addr, port, rule);
- } catch (NativeDaemonConnectorException e) {
- throw e.rethrowAsParcelableException();
- }
- }
-
private void closeSocketsForFirewallChainLocked(int chain, String chainName) {
// UID ranges to close sockets on.
UidRange[] ranges;
diff --git a/services/core/java/com/android/server/NsdService.java b/services/core/java/com/android/server/NsdService.java
index a691af9..55bca64 100644
--- a/services/core/java/com/android/server/NsdService.java
+++ b/services/core/java/com/android/server/NsdService.java
@@ -26,6 +26,8 @@
import android.net.nsd.INsdManager;
import android.net.nsd.NsdManager;
import android.os.Binder;
+import android.os.HandlerThread;
+import android.os.Handler;
import android.os.Message;
import android.os.Messenger;
import android.os.UserHandle;
@@ -37,9 +39,11 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.net.InetAddress;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.concurrent.CountDownLatch;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.AsyncChannel;
import com.android.internal.util.Protocol;
import com.android.internal.util.State;
@@ -59,10 +63,10 @@
private static final boolean DBG = true;
private final Context mContext;
- private final ContentResolver mContentResolver;
+ private final NsdSettings mNsdSettings;
private final NsdStateMachine mNsdStateMachine;
- private final NativeDaemonConnector mNativeConnector;
- private final CountDownLatch mNativeDaemonConnected = new CountDownLatch(1);
+ private final DaemonConnection mDaemon;
+ private final NativeCallbackReceiver mDaemonCallback;
/**
* Clients receiving asynchronous messages
@@ -108,8 +112,8 @@
false, contentObserver);
}
- NsdStateMachine(String name) {
- super(name);
+ NsdStateMachine(String name, Handler handler) {
+ super(name, handler);
addState(mDefaultState);
addState(mDisabledState, mDefaultState);
addState(mEnabledState, mDefaultState);
@@ -541,36 +545,35 @@
return sb.toString();
}
- private NsdService(Context context) {
- mContext = context;
- mContentResolver = context.getContentResolver();
-
- mNativeConnector = new NativeDaemonConnector(new NativeCallbackReceiver(), "mdns", 10,
- MDNS_TAG, 25, null);
-
- mNsdStateMachine = new NsdStateMachine(TAG);
+ @VisibleForTesting
+ NsdService(Context ctx, NsdSettings settings, Handler handler, DaemonConnectionSupplier fn) {
+ mContext = ctx;
+ mNsdSettings = settings;
+ mNsdStateMachine = new NsdStateMachine(TAG, handler);
mNsdStateMachine.start();
-
- Thread th = new Thread(mNativeConnector, MDNS_TAG);
- th.start();
+ mDaemonCallback = new NativeCallbackReceiver();
+ mDaemon = fn.get(mDaemonCallback);
}
public static NsdService create(Context context) throws InterruptedException {
- NsdService service = new NsdService(context);
- service.mNativeDaemonConnected.await();
+ NsdSettings settings = NsdSettings.makeDefault(context);
+ HandlerThread thread = new HandlerThread(TAG);
+ thread.start();
+ Handler handler = new Handler(thread.getLooper());
+ NsdService service = new NsdService(context, settings, handler, DaemonConnection::new);
+ service.mDaemonCallback.awaitConnection();
return service;
}
public Messenger getMessenger() {
- mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INTERNET,
- "NsdService");
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INTERNET, "NsdService");
return new Messenger(mNsdStateMachine.getHandler());
}
public void setEnabled(boolean enable) {
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL,
"NsdService");
- Settings.Global.putInt(mContentResolver, Settings.Global.NSD_ON, enable ? 1 : 0);
+ mNsdSettings.putEnabledStatus(enable);
if (enable) {
mNsdStateMachine.sendMessage(NsdManager.ENABLE);
} else {
@@ -590,8 +593,10 @@
}
private boolean isNsdEnabled() {
- boolean ret = Settings.Global.getInt(mContentResolver, Settings.Global.NSD_ON, 1) == 1;
- if (DBG) Slog.d(TAG, "Network service discovery enabled " + ret);
+ boolean ret = mNsdSettings.isEnabled();
+ if (DBG) {
+ Slog.d(TAG, "Network service discovery is " + (ret ? "enabled" : "disabled"));
+ }
return ret;
}
@@ -655,14 +660,23 @@
}
class NativeCallbackReceiver implements INativeDaemonConnectorCallbacks {
- public void onDaemonConnected() {
- mNativeDaemonConnected.countDown();
+ private final CountDownLatch connected = new CountDownLatch(1);
+
+ public void awaitConnection() throws InterruptedException {
+ connected.await();
}
+ @Override
+ public void onDaemonConnected() {
+ connected.countDown();
+ }
+
+ @Override
public boolean onCheckHoldWakeLock(int code) {
return false;
}
+ @Override
public boolean onEvent(int code, String raw, String[] cooked) {
// TODO: NDC translates a message to a callback, we could enhance NDC to
// directly interact with a state machine through messages
@@ -672,132 +686,102 @@
}
}
- private boolean startMDnsDaemon() {
- if (DBG) Slog.d(TAG, "startMDnsDaemon");
- try {
- mNativeConnector.execute("mdnssd", "start-service");
- } catch(NativeDaemonConnectorException e) {
- Slog.e(TAG, "Failed to start daemon" + e);
- return false;
+ interface DaemonConnectionSupplier {
+ DaemonConnection get(NativeCallbackReceiver callback);
+ }
+
+ @VisibleForTesting
+ public static class DaemonConnection {
+ final NativeDaemonConnector mNativeConnector;
+
+ DaemonConnection(NativeCallbackReceiver callback) {
+ mNativeConnector = new NativeDaemonConnector(callback, "mdns", 10, MDNS_TAG, 25, null);
+ new Thread(mNativeConnector, MDNS_TAG).start();
}
- return true;
+
+ public boolean execute(Object... args) {
+ if (DBG) {
+ Slog.d(TAG, "mdnssd " + Arrays.toString(args));
+ }
+ try {
+ mNativeConnector.execute("mdnssd", args);
+ } catch (NativeDaemonConnectorException e) {
+ Slog.e(TAG, "Failed to execute mdnssd " + Arrays.toString(args), e);
+ return false;
+ }
+ return true;
+ }
+
+ public boolean execute(Command cmd) {
+ if (DBG) {
+ Slog.d(TAG, cmd.toString());
+ }
+ try {
+ mNativeConnector.execute(cmd);
+ } catch (NativeDaemonConnectorException e) {
+ Slog.e(TAG, "Failed to execute " + cmd, e);
+ return false;
+ }
+ return true;
+ }
+ }
+
+ private boolean startMDnsDaemon() {
+ return mDaemon.execute("start-service");
}
private boolean stopMDnsDaemon() {
- if (DBG) Slog.d(TAG, "stopMDnsDaemon");
- try {
- mNativeConnector.execute("mdnssd", "stop-service");
- } catch(NativeDaemonConnectorException e) {
- Slog.e(TAG, "Failed to start daemon" + e);
- return false;
- }
- return true;
+ return mDaemon.execute("stop-service");
}
private boolean registerService(int regId, NsdServiceInfo service) {
- if (DBG) Slog.d(TAG, "registerService: " + regId + " " + service);
- try {
- Command cmd = new Command("mdnssd", "register", regId, service.getServiceName(),
- service.getServiceType(), service.getPort(),
- Base64.encodeToString(service.getTxtRecord(), Base64.DEFAULT)
- .replace("\n", ""));
-
- mNativeConnector.execute(cmd);
- } catch(NativeDaemonConnectorException e) {
- Slog.e(TAG, "Failed to execute registerService " + e);
- return false;
+ if (DBG) {
+ Slog.d(TAG, "registerService: " + regId + " " + service);
}
- return true;
+ String name = service.getServiceName();
+ String type = service.getServiceType();
+ int port = service.getPort();
+ byte[] textRecord = service.getTxtRecord();
+ String record = Base64.encodeToString(textRecord, Base64.DEFAULT).replace("\n", "");
+ Command cmd = new Command("mdnssd", "register", regId, name, type, port, record);
+ return mDaemon.execute(cmd);
}
private boolean unregisterService(int regId) {
- if (DBG) Slog.d(TAG, "unregisterService: " + regId);
- try {
- mNativeConnector.execute("mdnssd", "stop-register", regId);
- } catch(NativeDaemonConnectorException e) {
- Slog.e(TAG, "Failed to execute unregisterService " + e);
- return false;
- }
- return true;
+ return mDaemon.execute("stop-register", regId);
}
private boolean updateService(int regId, DnsSdTxtRecord t) {
- if (DBG) Slog.d(TAG, "updateService: " + regId + " " + t);
- try {
- if (t == null) return false;
- mNativeConnector.execute("mdnssd", "update", regId, t.size(), t.getRawData());
- } catch(NativeDaemonConnectorException e) {
- Slog.e(TAG, "Failed to updateServices " + e);
+ if (t == null) {
return false;
}
- return true;
+ return mDaemon.execute("update", regId, t.size(), t.getRawData());
}
private boolean discoverServices(int discoveryId, String serviceType) {
- if (DBG) Slog.d(TAG, "discoverServices: " + discoveryId + " " + serviceType);
- try {
- mNativeConnector.execute("mdnssd", "discover", discoveryId, serviceType);
- } catch(NativeDaemonConnectorException e) {
- Slog.e(TAG, "Failed to discoverServices " + e);
- return false;
- }
- return true;
+ return mDaemon.execute("discover", discoveryId, serviceType);
}
private boolean stopServiceDiscovery(int discoveryId) {
- if (DBG) Slog.d(TAG, "stopServiceDiscovery: " + discoveryId);
- try {
- mNativeConnector.execute("mdnssd", "stop-discover", discoveryId);
- } catch(NativeDaemonConnectorException e) {
- Slog.e(TAG, "Failed to stopServiceDiscovery " + e);
- return false;
- }
- return true;
+ return mDaemon.execute("stop-discover", discoveryId);
}
private boolean resolveService(int resolveId, NsdServiceInfo service) {
- if (DBG) Slog.d(TAG, "resolveService: " + resolveId + " " + service);
- try {
- mNativeConnector.execute("mdnssd", "resolve", resolveId, service.getServiceName(),
- service.getServiceType(), "local.");
- } catch(NativeDaemonConnectorException e) {
- Slog.e(TAG, "Failed to resolveService " + e);
- return false;
- }
- return true;
+ String name = service.getServiceName();
+ String type = service.getServiceType();
+ return mDaemon.execute("resolve", resolveId, name, type, "local.");
}
private boolean stopResolveService(int resolveId) {
- if (DBG) Slog.d(TAG, "stopResolveService: " + resolveId);
- try {
- mNativeConnector.execute("mdnssd", "stop-resolve", resolveId);
- } catch(NativeDaemonConnectorException e) {
- Slog.e(TAG, "Failed to stop resolve " + e);
- return false;
- }
- return true;
+ return mDaemon.execute("stop-resolve", resolveId);
}
private boolean getAddrInfo(int resolveId, String hostname) {
- if (DBG) Slog.d(TAG, "getAdddrInfo: " + resolveId);
- try {
- mNativeConnector.execute("mdnssd", "getaddrinfo", resolveId, hostname);
- } catch(NativeDaemonConnectorException e) {
- Slog.e(TAG, "Failed to getAddrInfo " + e);
- return false;
- }
- return true;
+ return mDaemon.execute("getaddrinfo", resolveId, hostname);
}
private boolean stopGetAddrInfo(int resolveId) {
- if (DBG) Slog.d(TAG, "stopGetAdddrInfo: " + resolveId);
- try {
- mNativeConnector.execute("mdnssd", "stop-getaddrinfo", resolveId);
- } catch(NativeDaemonConnectorException e) {
- Slog.e(TAG, "Failed to stopGetAddrInfo " + e);
- return false;
- }
- return true;
+ return mDaemon.execute("stop-getaddrinfo", resolveId);
}
@Override
@@ -927,4 +911,25 @@
return -1;
}
}
+
+ @VisibleForTesting
+ public interface NsdSettings {
+ boolean isEnabled();
+ void putEnabledStatus(boolean isEnabled);
+
+ static NsdSettings makeDefault(Context context) {
+ ContentResolver resolver = context.getContentResolver();
+ return new NsdSettings() {
+ @Override
+ public boolean isEnabled() {
+ return Settings.Global.getInt(resolver, Settings.Global.NSD_ON, 1) == 1;
+ }
+
+ @Override
+ public void putEnabledStatus(boolean isEnabled) {
+ Settings.Global.putInt(resolver, Settings.Global.NSD_ON, isEnabled ? 1 : 0);
+ }
+ };
+ }
+ }
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 5ae4d67..c5fc038 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -5324,35 +5324,61 @@
return tracesFile;
}
+ public static class DumpStackFileObserver extends FileObserver {
+ // Keep in sync with frameworks/native/cmds/dumpstate/utils.cpp
+ private static final int TRACE_DUMP_TIMEOUT_MS = 10000; // 10 seconds
+ static final int TRACE_DUMP_TIMEOUT_SECONDS = TRACE_DUMP_TIMEOUT_MS / 1000;
+
+ private final String mTracesPath;
+ private boolean mClosed;
+
+ public DumpStackFileObserver(String tracesPath) {
+ super(tracesPath, FileObserver.CLOSE_WRITE);
+ mTracesPath = tracesPath;
+ }
+
+ @Override
+ public synchronized void onEvent(int event, String path) {
+ mClosed = true;
+ notify();
+ }
+
+ public void dumpWithTimeout(int pid) {
+ Process.sendSignal(pid, Process.SIGNAL_QUIT);
+ synchronized (this) {
+ try {
+ wait(TRACE_DUMP_TIMEOUT_MS); // Wait for traces file to be closed.
+ } catch (InterruptedException e) {
+ Slog.wtf(TAG, e);
+ }
+ }
+ if (!mClosed) {
+ Slog.w(TAG, "Didn't see close of " + mTracesPath + " for pid " + pid +
+ ". Attempting native stack collection.");
+ Debug.dumpNativeBacktraceToFileTimeout(pid, mTracesPath, TRACE_DUMP_TIMEOUT_SECONDS);
+ }
+ mClosed = false;
+ }
+ }
+
private static void dumpStackTraces(String tracesPath, ArrayList<Integer> firstPids,
ProcessCpuTracker processCpuTracker, SparseArray<Boolean> lastPids, String[] nativeProcs) {
// Use a FileObserver to detect when traces finish writing.
// The order of traces is considered important to maintain for legibility.
- FileObserver observer = new FileObserver(tracesPath, FileObserver.CLOSE_WRITE) {
- @Override
- public synchronized void onEvent(int event, String path) { notify(); }
- };
-
+ DumpStackFileObserver observer = new DumpStackFileObserver(tracesPath);
try {
observer.startWatching();
// First collect all of the stacks of the most important pids.
if (firstPids != null) {
- try {
- int num = firstPids.size();
- for (int i = 0; i < num; i++) {
- synchronized (observer) {
- if (DEBUG_ANR) Slog.d(TAG, "Collecting stacks for pid "
- + firstPids.get(i));
- final long sime = SystemClock.elapsedRealtime();
- Process.sendSignal(firstPids.get(i), Process.SIGNAL_QUIT);
- observer.wait(1000); // Wait for write-close, give up after 1 sec
- if (DEBUG_ANR) Slog.d(TAG, "Done with pid " + firstPids.get(i)
- + " in " + (SystemClock.elapsedRealtime()-sime) + "ms");
- }
- }
- } catch (InterruptedException e) {
- Slog.wtf(TAG, e);
+ int num = firstPids.size();
+ for (int i = 0; i < num; i++) {
+ if (DEBUG_ANR) Slog.d(TAG, "Collecting stacks for pid "
+ + firstPids.get(i));
+ final long sime = SystemClock.elapsedRealtime();
+ observer.dumpWithTimeout(firstPids.get(i));
+ if (DEBUG_ANR) Slog.d(TAG, "Done with pid " + firstPids.get(i)
+ + " in " + (SystemClock.elapsedRealtime()-sime) + "ms");
}
}
@@ -5364,7 +5390,8 @@
if (DEBUG_ANR) Slog.d(TAG, "Collecting stacks for native pid " + pid);
final long sime = SystemClock.elapsedRealtime();
- Debug.dumpNativeBacktraceToFileTimeout(pid, tracesPath, 10);
+ Debug.dumpNativeBacktraceToFileTimeout(
+ pid, tracesPath, DumpStackFileObserver.TRACE_DUMP_TIMEOUT_SECONDS);
if (DEBUG_ANR) Slog.d(TAG, "Done with native pid " + pid
+ " in " + (SystemClock.elapsedRealtime()-sime) + "ms");
}
@@ -5391,19 +5418,12 @@
ProcessCpuTracker.Stats stats = processCpuTracker.getWorkingStats(i);
if (lastPids.indexOfKey(stats.pid) >= 0) {
numProcs++;
- try {
- synchronized (observer) {
- if (DEBUG_ANR) Slog.d(TAG, "Collecting stacks for extra pid "
- + stats.pid);
- final long stime = SystemClock.elapsedRealtime();
- Process.sendSignal(stats.pid, Process.SIGNAL_QUIT);
- observer.wait(1000); // Wait for write-close, give up after 1 sec
- if (DEBUG_ANR) Slog.d(TAG, "Done with extra pid " + stats.pid
- + " in " + (SystemClock.elapsedRealtime()-stime) + "ms");
- }
- } catch (InterruptedException e) {
- Slog.wtf(TAG, e);
- }
+ if (DEBUG_ANR) Slog.d(TAG, "Collecting stacks for extra pid "
+ + stats.pid);
+ final long stime = SystemClock.elapsedRealtime();
+ observer.dumpWithTimeout(stats.pid);
+ if (DEBUG_ANR) Slog.d(TAG, "Done with extra pid " + stats.pid
+ + " in " + (SystemClock.elapsedRealtime()-stime) + "ms");
} else if (DEBUG_ANR) {
Slog.d(TAG, "Skipping next CPU consuming process, not a java proc: "
+ stats.pid);
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index 71c7fd3..2e74eb9 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -493,8 +493,9 @@
Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
runningIntent.setData(Uri.fromParts("package",
appInfo.packageName, null));
- PendingIntent pi = PendingIntent.getActivity(ams.mContext, 0,
- runningIntent, PendingIntent.FLAG_UPDATE_CURRENT);
+ PendingIntent pi = PendingIntent.getActivityAsUser(ams.mContext, 0,
+ runningIntent, PendingIntent.FLAG_UPDATE_CURRENT, null,
+ UserHandle.of(userId));
notiBuilder.setColor(ams.mContext.getColor(
com.android.internal
.R.color.system_notification_accent_color));
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index 460d5f9..9edc35e 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -136,7 +136,7 @@
public boolean isCurrentlyServing() {
switch (lastState) {
case IControlsTethering.STATE_TETHERED:
- case IControlsTethering.STATE_LOCAL_HOTSPOT:
+ case IControlsTethering.STATE_LOCAL_ONLY:
return true;
default:
return false;
@@ -219,6 +219,10 @@
return (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
}
+ private WifiManager getWifiManager() {
+ return (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
+ }
+
private void updateConfiguration() {
mConfig = new TetheringConfiguration(mContext);
}
@@ -409,15 +413,21 @@
}
private int setWifiTethering(final boolean enable) {
- synchronized (mPublicSync) {
- mWifiTetherRequested = enable;
- final WifiManager wifiManager =
- (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
- if (wifiManager.setWifiApEnabled(null /* use existing wifi config */, enable)) {
- return ConnectivityManager.TETHER_ERROR_NO_ERROR;
+ int rval = ConnectivityManager.TETHER_ERROR_MASTER_ERROR;
+ final long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (mPublicSync) {
+ mWifiTetherRequested = enable;
+ final WifiManager mgr = getWifiManager();
+ if ((enable && mgr.startSoftAp(null /* use existing wifi config */)) ||
+ (!enable && mgr.stopSoftAp())) {
+ rval = ConnectivityManager.TETHER_ERROR_NO_ERROR;
+ }
}
- return ConnectivityManager.TETHER_ERROR_MASTER_ERROR;
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
+ return rval;
}
private void setBluetoothTethering(final boolean enable, final ResultReceiver receiver) {
@@ -623,9 +633,10 @@
private void sendTetherStateChangedBroadcast() {
if (!getConnectivityManager().isTetheringSupported()) return;
- ArrayList<String> availableList = new ArrayList<String>();
- ArrayList<String> activeList = new ArrayList<String>();
- ArrayList<String> erroredList = new ArrayList<String>();
+ final ArrayList<String> availableList = new ArrayList<>();
+ final ArrayList<String> tetherList = new ArrayList<>();
+ final ArrayList<String> localOnlyList = new ArrayList<>();
+ final ArrayList<String> erroredList = new ArrayList<>();
boolean wifiTethered = false;
boolean usbTethered = false;
@@ -641,6 +652,8 @@
erroredList.add(iface);
} else if (tetherState.lastState == IControlsTethering.STATE_AVAILABLE) {
availableList.add(iface);
+ } else if (tetherState.lastState == IControlsTethering.STATE_LOCAL_ONLY) {
+ localOnlyList.add(iface);
} else if (tetherState.lastState == IControlsTethering.STATE_TETHERED) {
if (cfg.isUsb(iface)) {
usbTethered = true;
@@ -649,25 +662,25 @@
} else if (cfg.isBluetooth(iface)) {
bluetoothTethered = true;
}
- activeList.add(iface);
+ tetherList.add(iface);
}
}
}
- Intent broadcast = new Intent(ConnectivityManager.ACTION_TETHER_STATE_CHANGED);
- broadcast.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING |
+ final Intent bcast = new Intent(ConnectivityManager.ACTION_TETHER_STATE_CHANGED);
+ bcast.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING |
Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
- broadcast.putStringArrayListExtra(ConnectivityManager.EXTRA_AVAILABLE_TETHER,
- availableList);
- broadcast.putStringArrayListExtra(ConnectivityManager.EXTRA_ACTIVE_TETHER, activeList);
- broadcast.putStringArrayListExtra(ConnectivityManager.EXTRA_ERRORED_TETHER,
- erroredList);
- mContext.sendStickyBroadcastAsUser(broadcast, UserHandle.ALL);
+ bcast.putStringArrayListExtra(ConnectivityManager.EXTRA_AVAILABLE_TETHER, availableList);
+ bcast.putStringArrayListExtra(ConnectivityManager.EXTRA_ACTIVE_LOCAL_ONLY, localOnlyList);
+ bcast.putStringArrayListExtra(ConnectivityManager.EXTRA_ACTIVE_TETHER, tetherList);
+ bcast.putStringArrayListExtra(ConnectivityManager.EXTRA_ERRORED_TETHER, erroredList);
+ mContext.sendStickyBroadcastAsUser(bcast, UserHandle.ALL);
if (DBG) {
Log.d(TAG, String.format(
- "sendTetherStateChangedBroadcast avail=[%s] active=[%s] error=[%s]",
- TextUtils.join(",", availableList),
- TextUtils.join(",", activeList),
- TextUtils.join(",", erroredList)));
+ "sendTetherStateChangedBroadcast %s=[%s] %s=[%s] %s=[%s] %s=[%s]",
+ "avail", TextUtils.join(",", availableList),
+ "local_only", TextUtils.join(",", localOnlyList),
+ "tether", TextUtils.join(",", tetherList),
+ "error", TextUtils.join(",", erroredList)));
}
if (usbTethered) {
@@ -803,7 +816,7 @@
// Otherwise, assume it's a local-only hotspot request.
final int state = mWifiTetherRequested
? IControlsTethering.STATE_TETHERED
- : IControlsTethering.STATE_LOCAL_HOTSPOT;
+ : IControlsTethering.STATE_LOCAL_ONLY;
tetherMatchingInterfaces(state, ConnectivityManager.TETHERING_WIFI);
break;
case WifiManager.WIFI_AP_STATE_DISABLED:
@@ -873,7 +886,7 @@
result = untether(chosenIface);
break;
case IControlsTethering.STATE_TETHERED:
- case IControlsTethering.STATE_LOCAL_HOTSPOT:
+ case IControlsTethering.STATE_LOCAL_ONLY:
result = tether(chosenIface, requestedState);
break;
default:
@@ -1330,15 +1343,40 @@
} else {
mForwardedDownstreams.remove(who);
}
+
+ // If this is a Wi-Fi interface, notify WifiManager of the active serving state.
+ if (who.interfaceType() == ConnectivityManager.TETHERING_WIFI) {
+ final WifiManager mgr = getWifiManager();
+ final String iface = who.interfaceName();
+ switch (mode) {
+ case IControlsTethering.STATE_TETHERED:
+ mgr.updateInterfaceIpState(iface, WifiManager.IFACE_IP_MODE_TETHERED);
+ break;
+ case IControlsTethering.STATE_LOCAL_ONLY:
+ mgr.updateInterfaceIpState(iface, WifiManager.IFACE_IP_MODE_LOCAL_ONLY);
+ break;
+ default:
+ Log.wtf(TAG, "Unknown active serving mode: " + mode);
+ break;
+ }
+ }
}
private void handleInterfaceServingStateInactive(TetherInterfaceStateMachine who) {
mNotifyList.remove(who);
mIPv6TetheringCoordinator.removeActiveDownstream(who);
mForwardedDownstreams.remove(who);
+
+ // If this is a Wi-Fi interface, tell WifiManager of any errors.
+ if (who.interfaceType() == ConnectivityManager.TETHERING_WIFI) {
+ if (who.lastError() != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
+ getWifiManager().updateInterfaceIpState(
+ who.interfaceName(), WifiManager.IFACE_IP_MODE_CONFIGURATION_ERROR);
+ }
+ }
}
- class InitialState extends TetherMasterUtilState {
+ class InitialState extends State {
@Override
public boolean processMessage(Message message) {
maybeLogMessage(this, message.what);
@@ -1516,7 +1554,8 @@
}
class ErrorState extends State {
- int mErrorNotification;
+ private int mErrorNotification;
+
@Override
public boolean processMessage(Message message) {
boolean retValue = true;
@@ -1534,6 +1573,7 @@
}
return retValue;
}
+
void notify(int msgType) {
mErrorNotification = msgType;
for (TetherInterfaceStateMachine sm : mNotifyList) {
@@ -1542,6 +1582,7 @@
}
}
+
class SetIpForwardingEnabledErrorState extends ErrorState {
@Override
public void enter() {
@@ -1635,7 +1676,7 @@
case IControlsTethering.STATE_TETHERED:
pw.print("TetheredState");
break;
- case IControlsTethering.STATE_LOCAL_HOTSPOT:
+ case IControlsTethering.STATE_LOCAL_ONLY:
pw.print("LocalHotspotState");
break;
default:
@@ -1654,7 +1695,7 @@
public void notifyInterfaceStateChange(String iface, TetherInterfaceStateMachine who,
int state, int error) {
synchronized (mPublicSync) {
- TetherState tetherState = mTetherStates.get(iface);
+ final TetherState tetherState = mTetherStates.get(iface);
if (tetherState != null && tetherState.stateMachine.equals(who)) {
tetherState.lastState = state;
tetherState.lastError = error;
@@ -1690,7 +1731,7 @@
which = TetherMasterSM.EVENT_IFACE_SERVING_STATE_INACTIVE;
break;
case IControlsTethering.STATE_TETHERED:
- case IControlsTethering.STATE_LOCAL_HOTSPOT:
+ case IControlsTethering.STATE_LOCAL_ONLY:
which = TetherMasterSM.EVENT_IFACE_SERVING_STATE_ACTIVE;
break;
default:
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 584994a..5dc8640 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -264,6 +264,30 @@
}
/**
+ * Chooses whether to force all connections to go though VPN.
+ *
+ * Used to enable/disable legacy VPN lockdown.
+ *
+ * This uses the same ip rule mechanism as {@link #setAlwaysOnPackage(String, boolean)};
+ * previous settings from calling that function will be replaced and saved with the
+ * always-on state.
+ *
+ * @param lockdown whether to prevent all traffic outside of a VPN.
+ */
+ public synchronized void setLockdown(boolean lockdown) {
+ enforceControlPermissionOrInternalCaller();
+
+ setVpnForcedLocked(lockdown);
+ mLockdown = lockdown;
+
+ // Update app lockdown setting if it changed. Legacy VPN lockdown status is controlled by
+ // LockdownVpnTracker.isEnabled() which keeps track of its own state.
+ if (mAlwaysOn) {
+ saveAlwaysOnPackage();
+ }
+ }
+
+ /**
* Configures an always-on VPN connection through a specific application.
* This connection is automatically granted and persisted after a reboot.
*
@@ -376,7 +400,7 @@
mSystemServices.settingsSecurePutStringForUser(Settings.Secure.ALWAYS_ON_VPN_APP,
getAlwaysOnPackage(), mUserHandle);
mSystemServices.settingsSecurePutIntForUser(Settings.Secure.ALWAYS_ON_VPN_LOCKDOWN,
- (mLockdown ? 1 : 0), mUserHandle);
+ (mAlwaysOn && mLockdown ? 1 : 0), mUserHandle);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -557,6 +581,7 @@
mConfig = null;
updateState(DetailedState.IDLE, "prepare");
+ setVpnForcedLocked(mLockdown);
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -1003,9 +1028,7 @@
Log.wtf(TAG, "Failed to add restricted user to owner", e);
}
}
- if (mAlwaysOn) {
- setVpnForcedLocked(mLockdown);
- }
+ setVpnForcedLocked(mLockdown);
}
}
}
@@ -1022,9 +1045,7 @@
Log.wtf(TAG, "Failed to remove restricted user to owner", e);
}
}
- if (mAlwaysOn) {
- setVpnForcedLocked(mLockdown);
- }
+ setVpnForcedLocked(mLockdown);
}
}
}
@@ -1034,7 +1055,7 @@
*/
public synchronized void onUserStopped() {
// Switch off networking lockdown (if it was enabled)
- setVpnForcedLocked(false);
+ setLockdown(false);
mAlwaysOn = false;
unregisterPackageChangeReceiverLocked();
@@ -1061,20 +1082,31 @@
*/
@GuardedBy("this")
private void setVpnForcedLocked(boolean enforce) {
+ final List<String> exemptedPackages =
+ isNullOrLegacyVpn(mPackage) ? null : Collections.singletonList(mPackage);
+ setVpnForcedWithExemptionsLocked(enforce, exemptedPackages);
+ }
+
+ /**
+ * @see #setVpnForcedLocked
+ */
+ @GuardedBy("this")
+ private void setVpnForcedWithExemptionsLocked(boolean enforce,
+ @Nullable List<String> exemptedPackages) {
final Set<UidRange> removedRanges = new ArraySet<>(mBlockedUsers);
+
+ Set<UidRange> addedRanges = Collections.emptySet();
if (enforce) {
- final Set<UidRange> addedRanges = createUserAndRestrictedProfilesRanges(mUserHandle,
+ addedRanges = createUserAndRestrictedProfilesRanges(mUserHandle,
/* allowedApplications */ null,
- /* disallowedApplications */ Collections.singletonList(mPackage));
+ /* disallowedApplications */ exemptedPackages);
removedRanges.removeAll(addedRanges);
addedRanges.removeAll(mBlockedUsers);
-
- setAllowOnlyVpnForUids(false, removedRanges);
- setAllowOnlyVpnForUids(true, addedRanges);
- } else {
- setAllowOnlyVpnForUids(false, removedRanges);
}
+
+ setAllowOnlyVpnForUids(false, removedRanges);
+ setAllowOnlyVpnForUids(true, addedRanges);
}
/**
diff --git a/services/core/java/com/android/server/connectivity/tethering/IControlsTethering.java b/services/core/java/com/android/server/connectivity/tethering/IControlsTethering.java
index f3914b7..c5c86bd 100644
--- a/services/core/java/com/android/server/connectivity/tethering/IControlsTethering.java
+++ b/services/core/java/com/android/server/connectivity/tethering/IControlsTethering.java
@@ -23,9 +23,9 @@
*/
public interface IControlsTethering {
public final int STATE_UNAVAILABLE = 0;
- public final int STATE_AVAILABLE = 1;
- public final int STATE_TETHERED = 2;
- public final int STATE_LOCAL_HOTSPOT = 3;
+ public final int STATE_AVAILABLE = 1;
+ public final int STATE_TETHERED = 2;
+ public final int STATE_LOCAL_ONLY = 3;
/**
* Notify that |who| has changed its tethering state. This may be called from any thread.
diff --git a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java
index 5f496ca..2485654 100644
--- a/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java
+++ b/services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java
@@ -172,7 +172,7 @@
final Downstream ds = findDownstream(sm);
if (ds == null) return null;
- if (ds.mode == IControlsTethering.STATE_LOCAL_HOTSPOT) {
+ if (ds.mode == IControlsTethering.STATE_LOCAL_ONLY) {
// Build a Unique Locally-assigned Prefix configuration.
return getUniqueLocalConfig(mUniqueLocalPrefix, ds.subnetId);
}
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
index 601ed01..d3cfd87 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
@@ -117,9 +117,11 @@
setInitialState(mInitialState);
}
- public int interfaceType() {
- return mInterfaceType;
- }
+ public String interfaceName() { return mIfaceName; }
+
+ public int interfaceType() { return mInterfaceType; }
+
+ public int lastError() { return mLastError; }
// configured when we start tethering and unconfig'd on error or conclusion
private boolean configureIfaceIp(boolean enabled) {
@@ -194,7 +196,7 @@
case CMD_TETHER_REQUESTED:
mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
switch (message.arg1) {
- case IControlsTethering.STATE_LOCAL_HOTSPOT:
+ case IControlsTethering.STATE_LOCAL_ONLY:
transitionTo(mLocalHotspotState);
break;
case IControlsTethering.STATE_TETHERED:
@@ -304,7 +306,7 @@
}
if (DBG) Log.d(TAG, "Local hotspot " + mIfaceName);
- sendInterfaceState(IControlsTethering.STATE_LOCAL_HOTSPOT);
+ sendInterfaceState(IControlsTethering.STATE_LOCAL_ONLY);
}
@Override
diff --git a/services/core/java/com/android/server/lights/LightsService.java b/services/core/java/com/android/server/lights/LightsService.java
index eead114..6d64b12 100644
--- a/services/core/java/com/android/server/lights/LightsService.java
+++ b/services/core/java/com/android/server/lights/LightsService.java
@@ -129,10 +129,11 @@
brightnessMode = mLastBrightnessMode;
}
- if ((color != mColor || mode != mMode || onMS != mOnMS || offMS != mOffMS ||
- mBrightnessMode != brightnessMode)) {
+ if (!mInitialized || color != mColor || mode != mMode || onMS != mOnMS ||
+ offMS != mOffMS || mBrightnessMode != brightnessMode) {
if (DEBUG) Slog.v(TAG, "setLight #" + mId + ": color=#"
+ Integer.toHexString(color) + ": brightnessMode=" + brightnessMode);
+ mInitialized = true;
mLastColor = mColor;
mColor = color;
mMode = mode;
@@ -164,6 +165,7 @@
private int mLastColor;
private boolean mVrModeEnabled;
private boolean mUseLowPersistenceForVR;
+ private boolean mInitialized;
}
public LightsService(Context context) {
diff --git a/services/core/java/com/android/server/media/MediaSessionService.java b/services/core/java/com/android/server/media/MediaSessionService.java
index 4c58ffd..f97a672 100644
--- a/services/core/java/com/android/server/media/MediaSessionService.java
+++ b/services/core/java/com/android/server/media/MediaSessionService.java
@@ -36,6 +36,7 @@
import android.media.IAudioService;
import android.media.IRemoteVolumeController;
import android.media.session.IActiveSessionsListener;
+import android.media.session.ICallback;
import android.media.session.ISession;
import android.media.session.ISessionCallback;
import android.media.session.ISessionManager;
@@ -101,6 +102,7 @@
private AudioManagerInternal mAudioManagerInternal;
private ContentResolver mContentResolver;
private SettingsObserver mSettingsObserver;
+ private ICallback mCallback;
// List of user IDs running in the foreground.
// Multiple users can be in the foreground if the work profile is on.
@@ -485,6 +487,7 @@
if (size > 0 && records.get(0).isPlaybackActive(false)) {
rememberMediaButtonReceiverLocked(records.get(0));
}
+ pushAddressedPlayerChangedLocked();
ArrayList<MediaSession.Token> tokens = new ArrayList<MediaSession.Token>();
for (int i = 0; i < size; i++) {
tokens.add(new MediaSession.Token(records.get(i).getControllerBinder()));
@@ -516,6 +519,52 @@
}
}
+ private MediaSessionRecord getMediaButtonSessionLocked() {
+ // If we don't have a media button receiver to fall back on
+ // include non-playing sessions for dispatching.
+ boolean useNotPlayingSessions = true;
+ for (int userId : mCurrentUserIdList) {
+ UserRecord ur = mUserRecords.get(userId);
+ if (ur.mLastMediaButtonReceiver != null
+ || ur.mRestoredMediaButtonReceiver != null) {
+ useNotPlayingSessions = false;
+ break;
+ }
+ }
+ return mPriorityStack.getDefaultMediaButtonSession(
+ mCurrentUserIdList, useNotPlayingSessions);
+ }
+
+ private void pushAddressedPlayerChangedLocked() {
+ if (mCallback == null) {
+ return;
+ }
+ try {
+ MediaSessionRecord mediaButtonSession = getMediaButtonSessionLocked();
+ if (mediaButtonSession != null) {
+ mCallback.onAddressedPlayerChangedToMediaSession(
+ new MediaSession.Token(mediaButtonSession.getControllerBinder()));
+ } else {
+ for (int userId : mCurrentUserIdList) {
+ UserRecord user = mUserRecords.get(userId);
+ if (user.mLastMediaButtonReceiver == null
+ && user.mRestoredMediaButtonReceiver == null) {
+ continue;
+ }
+ ComponentName componentName = user.mLastMediaButtonReceiver != null
+ ? user.mLastMediaButtonReceiver.getIntent().getComponent()
+ : user.mRestoredMediaButtonReceiver;
+ mCallback.onAddressedPlayerChangedToMediaButtonReceiver(componentName);
+ return;
+ }
+ }
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to pushAddressedPlayerChangedLocked", e);
+ }
+ }
+
+ // Remember media button receiver and keep it in the persistent storage.
+ // This should be called whenever there's no media session to receive media button event.
private void rememberMediaButtonReceiverLocked(MediaSessionRecord record) {
PendingIntent receiver = record.getMediaButtonReceiver();
UserRecord user = mUserRecords.get(record.getUserId());
@@ -530,6 +579,14 @@
}
}
+ private String getCallingPackageName(int uid) {
+ String[] packages = getContext().getPackageManager().getPackagesForUid(uid);
+ if (packages != null && packages.length > 0) {
+ return packages[0];
+ }
+ return "";
+ }
+
/**
* Information about a particular user. The contents of this object is
* guarded by mLock.
@@ -792,12 +849,10 @@
Log.d(TAG, "dispatchMediaKeyEvent, useNotPlayingSessions="
+ useNotPlayingSessions);
}
- MediaSessionRecord session = mPriorityStack.getDefaultMediaButtonSession(
- mCurrentUserIdList, useNotPlayingSessions);
if (isVoiceKey(keyEvent.getKeyCode())) {
- handleVoiceKeyEventLocked(keyEvent, needWakeLock, session);
+ handleVoiceKeyEventLocked(keyEvent, needWakeLock);
} else {
- dispatchMediaKeyEventLocked(keyEvent, needWakeLock, session);
+ dispatchMediaKeyEventLocked(keyEvent, needWakeLock);
}
}
} finally {
@@ -806,6 +861,45 @@
}
@Override
+ public void setCallback(ICallback callback) {
+ final int pid = Binder.getCallingPid();
+ final int uid = Binder.getCallingUid();
+ final long token = Binder.clearCallingIdentity();
+ try {
+ if (!UserHandle.isSameApp(uid, Process.BLUETOOTH_UID)) {
+ throw new SecurityException("Only Bluetooth service processes can set"
+ + " Callback");
+ }
+ synchronized (mLock) {
+ Log.d(TAG, "Callback + " + mCallback
+ + " is set by " + getCallingPackageName(uid));
+ mCallback = callback;
+ if (mCallback == null) {
+ return;
+ }
+ try {
+ mCallback.asBinder().linkToDeath(
+ new IBinder.DeathRecipient() {
+ @Override
+ public void binderDied() {
+ synchronized (mLock) {
+ mCallback = null;
+ }
+ }
+ }, 0);
+ pushAddressedPlayerChangedLocked();
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to set callback", e);
+ mCallback = null;
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+
+ @Override
public void dispatchAdjustVolume(int suggestedStream, int delta, int flags) {
final long token = Binder.clearCallingIdentity();
try {
@@ -932,13 +1026,7 @@
}
}
- private void handleVoiceKeyEventLocked(KeyEvent keyEvent, boolean needWakeLock,
- MediaSessionRecord session) {
- if (session != null && session.hasFlag(MediaSession.FLAG_EXCLUSIVE_GLOBAL_PRIORITY)) {
- // If the phone app has priority just give it the event
- dispatchMediaKeyEventLocked(keyEvent, needWakeLock, session);
- return;
- }
+ private void handleVoiceKeyEventLocked(KeyEvent keyEvent, boolean needWakeLock) {
int action = keyEvent.getAction();
boolean isLongPress = (keyEvent.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0;
if (action == KeyEvent.ACTION_DOWN) {
@@ -955,15 +1043,15 @@
if (!mVoiceButtonHandled && !keyEvent.isCanceled()) {
// Resend the down then send this event through
KeyEvent downEvent = KeyEvent.changeAction(keyEvent, KeyEvent.ACTION_DOWN);
- dispatchMediaKeyEventLocked(downEvent, needWakeLock, session);
- dispatchMediaKeyEventLocked(keyEvent, needWakeLock, session);
+ dispatchMediaKeyEventLocked(downEvent, needWakeLock);
+ dispatchMediaKeyEventLocked(keyEvent, needWakeLock);
}
}
}
}
- private void dispatchMediaKeyEventLocked(KeyEvent keyEvent, boolean needWakeLock,
- MediaSessionRecord session) {
+ private void dispatchMediaKeyEventLocked(KeyEvent keyEvent, boolean needWakeLock) {
+ MediaSessionRecord session = getMediaButtonSessionLocked();
if (session != null) {
if (DEBUG_MEDIA_KEY_EVENT) {
Log.d(TAG, "Sending " + keyEvent + " to " + session);
@@ -977,6 +1065,14 @@
needWakeLock ? mKeyEventReceiver.mLastTimeoutId : -1,
mKeyEventReceiver, Process.SYSTEM_UID,
getContext().getPackageName());
+ if (mCallback != null) {
+ try {
+ mCallback.onMediaKeyEventDispatchedToMediaSession(keyEvent,
+ new MediaSession.Token(session.getControllerBinder()));
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to send callback", e);
+ }
+ }
} else {
// Launch the last PendingIntent we had with priority
for (int userId : mCurrentUserIdList) {
@@ -993,26 +1089,41 @@
mediaButtonIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
try {
if (user.mLastMediaButtonReceiver != null) {
+ PendingIntent receiver = user.mLastMediaButtonReceiver;
if (DEBUG_MEDIA_KEY_EVENT) {
Log.d(TAG, "Sending " + keyEvent
- + " to the last known pendingIntent "
- + user.mLastMediaButtonReceiver);
+ + " to the last known pendingIntent " + receiver);
}
- user.mLastMediaButtonReceiver.send(getContext(),
+ receiver.send(getContext(),
needWakeLock ? mKeyEventReceiver.mLastTimeoutId : -1,
mediaButtonIntent, mKeyEventReceiver, mHandler);
+ if (mCallback != null) {
+ ComponentName componentName =
+ user.mLastMediaButtonReceiver.getIntent().getComponent();
+ if (componentName != null) {
+ mCallback.onMediaKeyEventDispatchedToMediaButtonReceiver(
+ keyEvent, componentName);
+ }
+ }
} else {
+ ComponentName receiver = user.mRestoredMediaButtonReceiver;
if (DEBUG_MEDIA_KEY_EVENT) {
Log.d(TAG, "Sending " + keyEvent + " to the restored intent "
- + user.mRestoredMediaButtonReceiver);
+ + receiver);
}
- mediaButtonIntent.setComponent(user.mRestoredMediaButtonReceiver);
+ mediaButtonIntent.setComponent(receiver);
getContext().sendBroadcastAsUser(mediaButtonIntent,
UserHandle.of(userId));
+ if (mCallback != null) {
+ mCallback.onMediaKeyEventDispatchedToMediaButtonReceiver(
+ keyEvent, receiver);
+ }
}
} catch (CanceledException e) {
Log.i(TAG, "Error sending key event to media button receiver "
+ user.mLastMediaButtonReceiver, e);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed to send callback", e);
}
return;
}
diff --git a/services/core/java/com/android/server/net/LockdownVpnTracker.java b/services/core/java/com/android/server/net/LockdownVpnTracker.java
index 4a8539a..b40a7e5 100644
--- a/services/core/java/com/android/server/net/LockdownVpnTracker.java
+++ b/services/core/java/com/android/server/net/LockdownVpnTracker.java
@@ -139,7 +139,6 @@
" " + mAcceptedEgressIface + "->" + egressIface);
if (egressDisconnected || egressChanged) {
- clearSourceRulesLocked();
mAcceptedEgressIface = null;
mVpn.stopLegacyVpnPrivileged();
}
@@ -191,24 +190,6 @@
EventLogTags.writeLockdownVpnConnected(egressType);
showNotification(R.string.vpn_lockdown_connected, R.drawable.vpn_connected);
- try {
- clearSourceRulesLocked();
-
- mNetService.setFirewallInterfaceRule(iface, true);
- for (LinkAddress addr : sourceAddrs) {
- setFirewallEgressSourceRule(addr, true);
- }
-
- mNetService.setFirewallUidRule(FIREWALL_CHAIN_NONE, ROOT_UID, FIREWALL_RULE_ALLOW);
- mNetService.setFirewallUidRule(FIREWALL_CHAIN_NONE, Os.getuid(), FIREWALL_RULE_ALLOW);
-
- mErrorCount = 0;
- mAcceptedIface = iface;
- mAcceptedSourceAddr = sourceAddrs;
- } catch (RemoteException e) {
- throw new RuntimeException("Problem setting firewall rules", e);
- }
-
final NetworkInfo clone = new NetworkInfo(egressInfo);
augmentNetworkInfo(clone);
mConnService.sendConnectedBroadcast(clone);
@@ -225,19 +206,11 @@
Slog.d(TAG, "initLocked()");
mVpn.setEnableTeardown(false);
+ mVpn.setLockdown(true);
final IntentFilter resetFilter = new IntentFilter(ACTION_LOCKDOWN_RESET);
mContext.registerReceiver(mResetReceiver, resetFilter, CONNECTIVITY_INTERNAL, null);
- try {
- // TODO: support non-standard port numbers
- mNetService.setFirewallEgressDestRule(mProfile.server, 500, true);
- mNetService.setFirewallEgressDestRule(mProfile.server, 4500, true);
- mNetService.setFirewallEgressDestRule(mProfile.server, 1701, true);
- } catch (RemoteException e) {
- throw new RuntimeException("Problem setting firewall rules", e);
- }
-
handleStateChangedLocked();
}
@@ -254,14 +227,7 @@
mErrorCount = 0;
mVpn.stopLegacyVpnPrivileged();
- try {
- mNetService.setFirewallEgressDestRule(mProfile.server, 500, false);
- mNetService.setFirewallEgressDestRule(mProfile.server, 4500, false);
- mNetService.setFirewallEgressDestRule(mProfile.server, 1701, false);
- } catch (RemoteException e) {
- throw new RuntimeException("Problem setting firewall rules", e);
- }
- clearSourceRulesLocked();
+ mVpn.setLockdown(false);
hideNotification();
mContext.unregisterReceiver(mResetReceiver);
@@ -278,35 +244,6 @@
}
}
- private void clearSourceRulesLocked() {
- try {
- if (mAcceptedIface != null) {
- mNetService.setFirewallInterfaceRule(mAcceptedIface, false);
- mAcceptedIface = null;
- }
- if (mAcceptedSourceAddr != null) {
- for (LinkAddress addr : mAcceptedSourceAddr) {
- setFirewallEgressSourceRule(addr, false);
- }
-
- mNetService.setFirewallUidRule(FIREWALL_CHAIN_NONE, ROOT_UID, FIREWALL_RULE_DEFAULT);
- mNetService.setFirewallUidRule(FIREWALL_CHAIN_NONE,Os.getuid(), FIREWALL_RULE_DEFAULT);
-
- mAcceptedSourceAddr = null;
- }
- } catch (RemoteException e) {
- throw new RuntimeException("Problem setting firewall rules", e);
- }
- }
-
- private void setFirewallEgressSourceRule(
- LinkAddress address, boolean allow) throws RemoteException {
- // Our source address based firewall rules must only cover our own source address, not the
- // whole subnet
- final String addrString = address.getAddress().getHostAddress();
- mNetService.setFirewallEgressSourceRule(addrString, allow);
- }
-
public void onNetworkInfoChanged() {
synchronized (mStateLock) {
handleStateChangedLocked();
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index 4e14408..d93d620 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -139,7 +139,7 @@
// (by default is speed-profile) they will be interepreted/JITed. This in itself is
// not a problem as we will end up doing profile guided compilation. However, some
// core apps may be loaded by system server which doesn't JIT and we need to make
- // sure we don't interpret-only
+ // sure we are not interpreting all their code in that process.
int compilationReason = p.coreApp
? PackageManagerService.REASON_CORE_APP
: PackageManagerService.REASON_AB_OTA;
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index d9ea728..71eb137 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -150,10 +150,14 @@
// TODO(calin,jeffhao): shared library paths should be adjusted to include previous code
// paths (b/34169257).
- final String sharedLibrariesPath = getSharedLibrariesPath(sharedLibraries);
+ String sharedLibrariesPath = getSharedLibrariesPath(sharedLibraries);
+ // Get the dexopt flags after getRealCompilerFilter to make sure we get the correct flags.
final int dexoptFlags = getDexFlags(pkg, compilerFilter);
int result = DEX_OPT_SKIPPED;
+ // TODO: Iterate based on dependency hierarchy (currently alphabetically by name)
+ // (b/37480811).
+ String basePathCheck = null;
for (String path : paths) {
for (String dexCodeIsa : dexCodeInstructionSets) {
int newResult = dexOptPath(pkg, path, dexCodeIsa, compilerFilter, profileUpdated,
@@ -165,6 +169,22 @@
if ((result != DEX_OPT_FAILED) && (newResult != DEX_OPT_SKIPPED)) {
result = newResult;
}
+ // Add the relative path of code we just compiled to the shared libraries.
+ int slashIndex = path.lastIndexOf('/') + 1;
+ String relativePath = path.substring(slashIndex);
+ if (sharedLibrariesPath == null) {
+ sharedLibrariesPath = relativePath;
+ } else {
+ sharedLibrariesPath += ":" + relativePath;
+ }
+ // Sanity check that the base paths are all the same.
+ String basePath = path.substring(0, slashIndex);
+ if (basePathCheck == null) {
+ basePathCheck = basePath;
+ } else if (!basePath.equals(basePathCheck)) {
+ Slog.wtf(TAG, "Split paths have different base paths: " + basePath + " and " +
+ basePathCheck);
+ }
}
}
return result;
@@ -340,10 +360,10 @@
boolean vmSafeMode = (flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0;
if (vmSafeMode) {
// For the compilation, it doesn't really matter what we return here because installd
- // will replace the filter with interpret-only anyway.
+ // will replace the filter with 'quicken' anyway.
// However, we return a non profile guided filter so that we simplify the logic of
// merging profiles.
- // TODO(calin): safe mode path could be simplified if we pass interpret-only from
+ // TODO(calin): safe mode path could be simplified if we pass 'quicken' from
// here rather than letting installd decide on the filter.
return getNonProfileGuidedCompilerFilter(targetCompilerFilter);
}
@@ -529,9 +549,13 @@
@Override
protected int adjustDexoptNeeded(int dexoptNeeded) {
- // Ensure compilation, no matter the current state.
- // TODO: The return value is wrong when patchoat is needed.
- return DexFile.DEX2OAT_FROM_SCRATCH;
+ if (dexoptNeeded == DexFile.NO_DEXOPT_NEEDED) {
+ // Ensure compilation by pretending a compiler filter change on the
+ // apk/odex location (the reason for the '-'. A positive value means
+ // the 'oat' location).
+ return -DexFile.DEX2OAT_FOR_FILTER;
+ }
+ return dexoptNeeded;
}
@Override
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index b207b81..3196b09 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -7364,20 +7364,7 @@
// are verify-profile but for preopted apps there's no profile.
// Do a hacky check to ensure that if we have no profiles (a reasonable indication
// that before the OTA the app was preopted) the app gets compiled with a non-profile
- // filter (by default interpret-only).
- // Note that at this stage unused apps are already filtered.
- if (isSystemApp(pkg) &&
- DexFile.isProfileGuidedCompilerFilter(compilerFilter) &&
- !Environment.getReferenceProfile(pkg.packageName).exists()) {
- compilerFilter = getNonProfileGuidedCompilerFilter(compilerFilter);
- }
-
- // If the OTA updates a system app which was previously preopted to a non-preopted state
- // the app might end up being verified at runtime. That's because by default the apps
- // are verify-profile but for preopted apps there's no profile.
- // Do a hacky check to ensure that if we have no profiles (a reasonable indication
- // that before the OTA the app was preopted) the app gets compiled with a non-profile
- // filter (by default interpret-only).
+ // filter (by default 'quicken').
// Note that at this stage unused apps are already filtered.
if (isSystemApp(pkg) &&
DexFile.isProfileGuidedCompilerFilter(compilerFilter) &&
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 1bfc157..2f000c2 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -1454,10 +1454,10 @@
pw.println(" -f: force compilation even if not needed");
pw.println(" -m: select compilation mode");
pw.println(" MODE is one of the dex2oat compiler filters:");
- pw.println(" verify-none");
- pw.println(" verify-at-runtime");
- pw.println(" verify-profile");
- pw.println(" interpret-only");
+ pw.println(" assume-verified");
+ pw.println(" extract");
+ pw.println(" verify");
+ pw.println(" quicken");
pw.println(" space-profile");
pw.println(" space");
pw.println(" speed-profile");
diff --git a/services/net/java/android/net/apf/ApfCapabilities.java b/services/net/java/android/net/apf/ApfCapabilities.java
index b0e0230..703b415 100644
--- a/services/net/java/android/net/apf/ApfCapabilities.java
+++ b/services/net/java/android/net/apf/ApfCapabilities.java
@@ -46,7 +46,7 @@
}
public String toString() {
- return String.format("%s{version: %d, maxSize: %d format: %d}", getClass().getSimpleName(),
+ return String.format("%s{version: %d, maxSize: %d, format: %d}", getClass().getSimpleName(),
apfVersionSupported, maximumApfProgramSize, apfPacketFormat);
}
}
diff --git a/services/net/java/android/net/apf/ApfFilter.java b/services/net/java/android/net/apf/ApfFilter.java
index 0a90749..985a12c 100644
--- a/services/net/java/android/net/apf/ApfFilter.java
+++ b/services/net/java/android/net/apf/ApfFilter.java
@@ -18,6 +18,14 @@
import static android.system.OsConstants.*;
+import static com.android.internal.util.BitUtils.bytesToBEInt;
+import static com.android.internal.util.BitUtils.getUint16;
+import static com.android.internal.util.BitUtils.getUint32;
+import static com.android.internal.util.BitUtils.getUint8;
+import static com.android.internal.util.BitUtils.uint16;
+import static com.android.internal.util.BitUtils.uint32;
+import static com.android.internal.util.BitUtils.uint8;
+
import android.os.SystemClock;
import android.net.LinkAddress;
import android.net.LinkProperties;
@@ -1157,41 +1165,9 @@
}
}
- private static int uint8(byte b) {
- return b & 0xff;
- }
-
- private static int uint16(short s) {
- return s & 0xffff;
- }
-
- private static long uint32(int i) {
- return i & 0xffffffffL;
- }
-
- private static int getUint8(ByteBuffer buffer, int position) {
- return uint8(buffer.get(position));
- }
-
- private static int getUint16(ByteBuffer buffer, int position) {
- return uint16(buffer.getShort(position));
- }
-
- private static long getUint32(ByteBuffer buffer, int position) {
- return uint32(buffer.getInt(position));
- }
-
// TODO: move to android.net.NetworkUtils
@VisibleForTesting
public static int ipv4BroadcastAddress(byte[] addrBytes, int prefixLength) {
- return bytesToInt(addrBytes) | (int) (uint32(-1) >>> prefixLength);
- }
-
- @VisibleForTesting
- public static int bytesToInt(byte[] addrBytes) {
- return (uint8(addrBytes[0]) << 24)
- + (uint8(addrBytes[1]) << 16)
- + (uint8(addrBytes[2]) << 8)
- + (uint8(addrBytes[3]));
+ return bytesToBEInt(addrBytes) | (int) (uint32(-1) >>> prefixLength);
}
}
diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java
index 745764b..6608167 100644
--- a/services/net/java/android/net/ip/IpManager.java
+++ b/services/net/java/android/net/ip/IpManager.java
@@ -524,7 +524,7 @@
try {
mNwService.registerObserver(mNetlinkTracker);
} catch (RemoteException e) {
- Log.e(mTag, "Couldn't register NetlinkTracker: " + e.toString());
+ logError("Couldn't register NetlinkTracker: %s", e);
}
mMultinetworkPolicyTracker.start();
@@ -611,19 +611,36 @@
return;
}
+ // Thread-unsafe access to mApfFilter but just used for debugging.
+ final ApfFilter apfFilter = mApfFilter;
+ final ProvisioningConfiguration provisioningConfig = mConfiguration;
+ final ApfCapabilities apfCapabilities = (provisioningConfig != null)
+ ? provisioningConfig.mApfCapabilities : null;
+
IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ");
pw.println(mTag + " APF dump:");
pw.increaseIndent();
- // Thread-unsafe access to mApfFilter but just used for debugging.
- ApfFilter apfFilter = mApfFilter;
if (apfFilter != null) {
apfFilter.dump(pw);
} else {
- pw.println("No apf support");
+ pw.print("No active ApfFilter; ");
+ if (provisioningConfig == null) {
+ pw.println("IpManager not yet started.");
+ } else if (apfCapabilities == null || apfCapabilities.apfVersionSupported == 0) {
+ pw.println("Hardware does not support APF.");
+ } else {
+ pw.println("ApfFilter not yet started, APF capabilities: " + apfCapabilities);
+ }
}
pw.decreaseIndent();
pw.println();
+ pw.println(mTag + " current ProvisioningConfiguration:");
+ pw.increaseIndent();
+ pw.println(Objects.toString(provisioningConfig, "N/A"));
+ pw.decreaseIndent();
+
+ pw.println();
pw.println(mTag + " StateMachine dump:");
pw.increaseIndent();
mLocalLog.readOnlyLocalLog().dump(fd, pw, args);
@@ -684,7 +701,9 @@
// TODO: Migrate all Log.e(...) to logError(...).
private void logError(String fmt, Object... args) {
- mLocalLog.log("ERROR " + String.format(fmt, args));
+ final String msg = "ERROR " + String.format(fmt, args);
+ Log.e(mTag, msg);
+ mLocalLog.log(msg);
}
private void getNetworkInterface() {
@@ -692,7 +711,7 @@
mNetworkInterface = NetworkInterface.getByName(mInterfaceName);
} catch (SocketException | NullPointerException e) {
// TODO: throw new IllegalStateException.
- Log.e(mTag, "ALERT: Failed to get interface object: ", e);
+ logError("Failed to get interface object: %s", e);
}
}
@@ -948,7 +967,7 @@
ifcg.setLinkAddress(new LinkAddress("0.0.0.0/0"));
mNwService.setInterfaceConfig(mInterfaceName, ifcg);
} catch (IllegalStateException | RemoteException e) {
- Log.e(mTag, "ALERT: Failed to clear IPv4 address on interface " + mInterfaceName, e);
+ logError("Failed to clear IPv4 address on interface %s: %s", mInterfaceName, e);
}
}
@@ -1074,13 +1093,13 @@
try {
mNwService.disableIpv6(mInterfaceName);
} catch (Exception e) {
- Log.e(mTag, "Failed to disable IPv6" + e);
+ logError("Failed to disable IPv6: %s", e);
}
try {
mNwService.clearInterfaceAddresses(mInterfaceName);
} catch (Exception e) {
- Log.e(mTag, "Failed to clear addresses " + e);
+ logError("Failed to clear addresses: %s", e);
}
}
@@ -1404,7 +1423,7 @@
if (setIPv4Address(ipAddress)) {
mDhcpClient.sendMessage(DhcpClient.EVENT_LINKADDRESS_CONFIGURED);
} else {
- Log.e(mTag, "Failed to set IPv4 address!");
+ logError("Failed to set IPv4 address.");
dispatchCallback(ProvisioningChange.LOST_PROVISIONING,
new LinkProperties(mLinkProperties));
transitionTo(mStoppingState);
diff --git a/services/net/java/android/net/util/ConnectivityPacketSummary.java b/services/net/java/android/net/util/ConnectivityPacketSummary.java
index 5b068c0..dae93af 100644
--- a/services/net/java/android/net/util/ConnectivityPacketSummary.java
+++ b/services/net/java/android/net/util/ConnectivityPacketSummary.java
@@ -368,9 +368,9 @@
byte[] bytes = new byte[ETHER_ADDR_LEN];
mac.get(bytes, 0, bytes.length);
- Byte[] printableBytes = new Byte[bytes.length];
+ Object[] printableBytes = new Object[bytes.length];
int i = 0;
- for (byte b : bytes) printableBytes[i++] = b;
+ for (byte b : bytes) printableBytes[i++] = new Byte(b);
final String MAC48_FORMAT = "%02x:%02x:%02x:%02x:%02x:%02x";
return String.format(MAC48_FORMAT, printableBytes);
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 9822936..239cdcf 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -878,6 +878,7 @@
* {@link Call#sendRttRequest()}
*/
public static final class RttModifyStatus {
+ private RttModifyStatus() {}
/**
* Session modify request was successful.
*/
diff --git a/telecomm/java/android/telecom/PhoneAccount.java b/telecomm/java/android/telecom/PhoneAccount.java
index c42a835..5530cb7 100644
--- a/telecomm/java/android/telecom/PhoneAccount.java
+++ b/telecomm/java/android/telecom/PhoneAccount.java
@@ -43,6 +43,15 @@
/**
* {@link PhoneAccount} extras key (see {@link PhoneAccount#getExtras()}) which determines the
+ * sort order for {@link PhoneAccount}s from the same
+ * {@link android.telecom.ConnectionService}.
+ * @hide
+ */
+ public static final String EXTRA_SORT_ORDER =
+ "android.telecom.extra.SORT_ORDER";
+
+ /**
+ * {@link PhoneAccount} extras key (see {@link PhoneAccount#getExtras()}) which determines the
* maximum permitted length of a call subject specified via the
* {@link TelecomManager#EXTRA_CALL_SUBJECT} extra on an
* {@link android.content.Intent#ACTION_CALL} intent. Ultimately a {@link ConnectionService} is
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 7e0fbb9..e1239d0 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -604,6 +604,38 @@
"vvm_cellular_data_required_bool";
/**
+ * The default OMTP visual voicemail client prefix to use. Defaulted to "//VVM"
+ */
+ public static final String KEY_VVM_CLIENT_PREFIX_STRING =
+ "vvm_client_prefix_string";
+
+ /**
+ * Whether to use SSL to connect to the visual voicemail IMAP server. Defaulted to false.
+ */
+ public static final String KEY_VVM_SSL_ENABLED_BOOL = "vvm_ssl_enabled_bool";
+
+ /**
+ * A set of capabilities that should not be used even if it is reported by the visual voicemail
+ * IMAP CAPABILITY command.
+ */
+ public static final String KEY_VVM_DISABLED_CAPABILITIES_STRING_ARRAY =
+ "vvm_disabled_capabilities_string_array";
+
+ /**
+ * Whether legacy mode should be used when the visual voicemail client is disabled.
+ *
+ * <p>Legacy mode is a mode that on the carrier side visual voicemail is still activated, but on
+ * the client side all network operations are disabled. SMSs are still monitored so a new
+ * message SYNC SMS will be translated to show a message waiting indicator, like traditional
+ * voicemails.
+ *
+ * <p>This is for carriers that does not support VVM deactivation so voicemail can continue to
+ * function without the data cost.
+ */
+ public static final String KEY_VVM_LEGACY_MODE_ENABLED_BOOL =
+ "vvm_legacy_mode_enabled_bool";
+
+ /**
* Whether to prefetch audio data on new voicemail arrival, defaulted to true.
*/
public static final String KEY_VVM_PREFETCH_BOOL = "vvm_prefetch_bool";
@@ -611,10 +643,20 @@
/**
* The package name of the carrier's visual voicemail app to ensure that dialer visual voicemail
* and carrier visual voicemail are not active at the same time.
+ *
+ * @deprecated use {@link #KEY_CARRIER_VVM_PACKAGE_NAME_STRING_ARRAY}.
*/
+ @Deprecated
public static final String KEY_CARRIER_VVM_PACKAGE_NAME_STRING = "carrier_vvm_package_name_string";
/**
+ * A list of the carrier's visual voicemail app package names to ensure that dialer visual
+ * voicemail and carrier visual voicemail are not active at the same time.
+ */
+ public static final String KEY_CARRIER_VVM_PACKAGE_NAME_STRING_ARRAY =
+ "carrier_vvm_package_name_string_array";
+
+ /**
* Flag specifying whether ICCID is showed in SIM Status screen, default to false.
*/
public static final String KEY_SHOW_ICCID_IN_SIM_STATUS_BOOL = "show_iccid_in_sim_status_bool";
@@ -838,6 +880,12 @@
public static final String KEY_STK_DISABLE_LAUNCH_BROWSER_BOOL =
"stk_disable_launch_browser_bool";
+ /**
+ * Boolean indicating if show data RAT icon on status bar even when data is disabled
+ * @hide
+ */
+ public static final String KEY_ALWAYS_SHOW_DATA_RAT_ICON_BOOL =
+ "always_show_data_rat_icon_bool";
// These variables are used by the MMS service and exposed through another API, {@link
// SmsManager}. The variable names and string values are copied from there.
@@ -936,6 +984,20 @@
"carrier_default_actions_on_dcfailure_string_array";
/**
+ * Defines carrier-specific actions which act upon
+ * com.android.internal.telephony.CARRIER_SIGNAL_RESET, used for customization of the
+ * default carrier app
+ * Format: "CARRIER_ACTION_IDX, ..."
+ * Where {@code CARRIER_ACTION_IDX} is an integer defined in
+ * {@link com.android.carrierdefaultapp.CarrierActionUtils CarrierActionUtils}
+ * Example:
+ * {@link com.android.carrierdefaultapp.CarrierActionUtils
+ * #CARRIER_ACTION_CANCEL_ALL_NOTIFICATIONS clear all notifications on reset}
+ * @hide
+ */
+ public static final String KEY_CARRIER_DEFAULT_ACTIONS_ON_RESET =
+ "carrier_default_actions_on_reset_string_array";
+ /**
* Defines a list of acceptable redirection url for default carrier app
* @hides
*/
@@ -1338,8 +1400,13 @@
sDefaults.putInt(KEY_VVM_PORT_NUMBER_INT, 0);
sDefaults.putString(KEY_VVM_TYPE_STRING, "");
sDefaults.putBoolean(KEY_VVM_CELLULAR_DATA_REQUIRED_BOOL, false);
+ sDefaults.putString(KEY_VVM_CLIENT_PREFIX_STRING,"//VVM");
+ sDefaults.putBoolean(KEY_VVM_SSL_ENABLED_BOOL,false);
+ sDefaults.putStringArray(KEY_VVM_DISABLED_CAPABILITIES_STRING_ARRAY, null);
+ sDefaults.putBoolean(KEY_VVM_LEGACY_MODE_ENABLED_BOOL,false);
sDefaults.putBoolean(KEY_VVM_PREFETCH_BOOL, true);
sDefaults.putString(KEY_CARRIER_VVM_PACKAGE_NAME_STRING, "");
+ sDefaults.putStringArray(KEY_CARRIER_VVM_PACKAGE_NAME_STRING_ARRAY, null);
sDefaults.putBoolean(KEY_SHOW_ICCID_IN_SIM_STATUS_BOOL, false);
sDefaults.putBoolean(KEY_CI_ACTION_ON_SYS_UPDATE_BOOL, false);
sDefaults.putString(KEY_CI_ACTION_ON_SYS_UPDATE_INTENT_STRING, "");
@@ -1451,7 +1518,8 @@
sDefaults.putStringArray(KEY_CARRIER_APP_WAKE_SIGNAL_CONFIG_STRING_ARRAY,
new String[]{
"com.android.carrierdefaultapp/.CarrierDefaultBroadcastReceiver:" +
- "com.android.internal.telephony.CARRIER_SIGNAL_REDIRECTED"
+ "com.android.internal.telephony.CARRIER_SIGNAL_REDIRECTED," +
+ "com.android.internal.telephony.CARRIER_SIGNAL_RESET"
});
sDefaults.putStringArray(KEY_CARRIER_APP_NO_WAKE_SIGNAL_CONFIG_STRING_ARRAY, null);
@@ -1462,6 +1530,9 @@
//4: CARRIER_ACTION_DISABLE_METERED_APNS
//1: CARRIER_ACTION_SHOW_PORTAL_NOTIFICATION
});
+ sDefaults.putStringArray(KEY_CARRIER_DEFAULT_ACTIONS_ON_RESET, new String[]{
+ "6" //6: CARRIER_ACTION_CANCEL_ALL_NOTIFICATIONS
+ });
sDefaults.putStringArray(KEY_CARRIER_DEFAULT_REDIRECTION_URL_STRING_ARRAY, null);
// Rat families: {GPRS, EDGE}, {EVDO, EVDO_A, EVDO_B}, {UMTS, HSPA, HSDPA, HSUPA, HSPAP},
@@ -1491,6 +1562,7 @@
sDefaults.putInt(KEY_LTE_EARFCNS_RSRP_BOOST_INT, 0);
sDefaults.putStringArray(KEY_BOOSTED_LTE_EARFCNS_STRING_ARRAY, null);
sDefaults.putBoolean(KEY_DISABLE_VOICE_BARRING_NOTIFICATION_BOOL, false);
+ sDefaults.putBoolean(KEY_ALWAYS_SHOW_DATA_RAT_ICON_BOOL, false);
}
/**
diff --git a/telephony/java/android/telephony/MbmsDownloadManager.java b/telephony/java/android/telephony/MbmsDownloadManager.java
new file mode 100644
index 0000000..862c919
--- /dev/null
+++ b/telephony/java/android/telephony/MbmsDownloadManager.java
@@ -0,0 +1,325 @@
+/*
+ * Copyright (C) 2016 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.telephony;
+
+import android.content.Context;
+import android.net.Uri;
+import android.os.RemoteException;
+import android.telephony.mbms.DownloadCallback;
+import android.telephony.mbms.DownloadRequest;
+import android.telephony.mbms.DownloadStatus;
+import android.telephony.mbms.IMbmsDownloadManagerCallback;
+import android.telephony.mbms.MbmsInitializationException;
+import android.telephony.mbms.vendor.IMbmsDownloadService;
+import android.util.Log;
+
+import java.util.List;
+
+import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+
+/** @hide */
+public class MbmsDownloadManager {
+ private static final String LOG_TAG = MbmsDownloadManager.class.getSimpleName();
+
+ /**
+ * The MBMS middleware should send this when a download of single file has completed or
+ * failed. Mandatory extras are
+ * {@link #EXTRA_RESULT}
+ * {@link #EXTRA_INFO}
+ * {@link #EXTRA_REQUEST}
+ * {@link #EXTRA_TEMP_LIST}
+ * {@link #EXTRA_FINAL_URI}
+ *
+ * TODO: future systemapi
+ */
+ public static final String ACTION_DOWNLOAD_RESULT_INTERNAL =
+ "android.telephony.mbms.action.DOWNLOAD_RESULT_INTERNAL";
+
+ /**
+ * The MBMS middleware should send this when it wishes to request {@code content://} URIs to
+ * serve as temp files for downloads or when it wishes to resume paused downloads. Mandatory
+ * extras are
+ * {@link #EXTRA_REQUEST}
+ *
+ * Optional extras are
+ * {@link #EXTRA_FD_COUNT} (0 if not present)
+ * {@link #EXTRA_PAUSED_LIST} (empty if not present)
+ *
+ * TODO: future systemapi
+ */
+ public static final String ACTION_FILE_DESCRIPTOR_REQUEST =
+ "android.telephony.mbms.action.FILE_DESCRIPTOR_REQUEST";
+
+ /**
+ * The MBMS middleware should send this when it wishes to clean up temp files in the app's
+ * filesystem. Mandatory extras are:
+ * {@link #EXTRA_TEMP_FILES_IN_USE}
+ *
+ * TODO: future systemapi
+ */
+ public static final String ACTION_CLEANUP =
+ "android.telephony.mbms.action.CLEANUP";
+
+ /**
+ * Integer extra indicating the result code of the download.
+ * TODO: put in link to error list
+ * TODO: future systemapi (here and and all extras)
+ */
+ public static final String EXTRA_RESULT = "android.telephony.mbms.extra.RESULT";
+
+ /**
+ * Extra containing the {@link android.telephony.mbms.FileInfo} for which the download result
+ * is for. Must not be null.
+ */
+ public static final String EXTRA_INFO = "android.telephony.mbms.extra.INFO";
+
+ /**
+ * Extra containing the {@link DownloadRequest} for which the download result or file
+ * descriptor request is for. Must not be null.
+ */
+ public static final String EXTRA_REQUEST = "android.telephony.mbms.extra.REQUEST";
+
+ /**
+ * Extra containing a {@link List} of {@link Uri}s that were used as temp files for this
+ * completed file. These {@link Uri}s should have scheme {@code file://}, and the temp
+ * files will be deleted upon receipt of the intent.
+ * May be null.
+ */
+ public static final String EXTRA_TEMP_LIST = "android.telephony.mbms.extra.TEMP_LIST";
+
+ /**
+ * Extra containing a single {@link Uri} indicating the path to the temp file in which the
+ * decoded downloaded file resides. Must not be null.
+ */
+ public static final String EXTRA_FINAL_URI = "android.telephony.mbms.extra.FINAL_URI";
+
+ /**
+ * Extra containing an integer indicating the number of temp files requested.
+ */
+ public static final String EXTRA_FD_COUNT = "android.telephony.mbms.extra.FD_COUNT";
+
+ /**
+ * Extra containing a list of {@link Uri}s that the middleware is requesting access to via
+ * {@link #ACTION_FILE_DESCRIPTOR_REQUEST} in order to resume downloading. These {@link Uri}s
+ * should have scheme {@code file://}.
+ */
+ public static final String EXTRA_PAUSED_LIST = "android.telephony.mbms.extra.PAUSED_LIST";
+
+ /**
+ * Extra containing a list of {@link android.telephony.mbms.UriPathPair}s, used in the
+ * response to {@link #ACTION_FILE_DESCRIPTOR_REQUEST}. These are temp files that are meant
+ * to be used for new file downloads.
+ */
+ public static final String EXTRA_FREE_URI_LIST = "android.telephony.mbms.extra.FREE_URI_LIST";
+
+ /**
+ * Extra containing a list of {@link android.telephony.mbms.UriPathPair}s, used in the
+ * response to {@link #ACTION_FILE_DESCRIPTOR_REQUEST}. These
+ * {@link android.telephony.mbms.UriPathPair}s contain {@code content://} URIs that provide
+ * access to previously paused downloads.
+ */
+ public static final String EXTRA_PAUSED_URI_LIST =
+ "android.telephony.mbms.extra.PAUSED_URI_LIST";
+
+ /**
+ * Extra containing a list of {@link Uri}s indicating temp files which the middleware is
+ * still using.
+ */
+ public static final String EXTRA_TEMP_FILES_IN_USE =
+ "android.telephony.mbms.extra.TEMP_FILES_IN_USE";
+
+ public static final int RESULT_SUCCESSFUL = 1;
+ public static final int RESULT_CANCELLED = 2;
+ public static final int RESULT_EXPIRED = 3;
+ // TODO - more results!
+
+ private final Context mContext;
+ private int mSubId = INVALID_SUBSCRIPTION_ID;
+
+ private IMbmsDownloadService mService;
+ private final IMbmsDownloadManagerCallback mCallback;
+ private final String mDownloadAppName;
+
+ private MbmsDownloadManager(Context context, IMbmsDownloadManagerCallback callback,
+ String downloadAppName, int subId) {
+ mContext = context;
+ mCallback = callback;
+ mDownloadAppName = downloadAppName;
+ mSubId = subId;
+ }
+
+ /**
+ * Create a new MbmsDownloadManager using the system default data subscription ID.
+ *
+ * Note that this call will bind a remote service and that may take a bit. This
+ * may throw an Illegal ArgumentException or RemoteException.
+ *
+ * @hide
+ */
+ public static MbmsDownloadManager createManager(Context context,
+ IMbmsDownloadManagerCallback listener, String downloadAppName)
+ throws MbmsInitializationException{
+ MbmsDownloadManager mdm = new MbmsDownloadManager(context, listener, downloadAppName,
+ SubscriptionManager.getDefaultSubscriptionId());
+ mdm.bindAndInitialize();
+ return mdm;
+ }
+
+ /**
+ * Create a new MbmsDownloadManager using the given subscription ID.
+ *
+ * Note that this call will bind a remote service and that may take a bit. This
+ * may throw an Illegal ArgumentException or RemoteException.
+ *
+ * @hide
+ */
+
+ public static MbmsDownloadManager createManager(Context context,
+ IMbmsDownloadManagerCallback listener, String downloadAppName, int subId)
+ throws MbmsInitializationException {
+ MbmsDownloadManager mdm = new MbmsDownloadManager(context, listener, downloadAppName,
+ subId);
+ mdm.bindAndInitialize();
+ return mdm;
+ }
+
+ private void bindAndInitialize() throws MbmsInitializationException {
+ // TODO: bind
+ try {
+ mService.initialize(mDownloadAppName, mSubId, mCallback);
+ } catch (RemoteException e) {
+ throw new MbmsInitializationException(0); // TODO: proper error code
+ }
+ }
+
+ /**
+ * Gets the list of files published for download.
+ * They may occur at times far in the future.
+ * servicesClasses lets the app filter on types of files and is opaque data between
+ * the app and the carrier
+ *
+ * Multiple calls replace trhe list of serviceClasses of interest.
+ *
+ * May throw an IllegalArgumentException or RemoteException.
+ *
+ * Synchronous responses include
+ * <li>SUCCESS</li>
+ * <li>ERROR_MSDC_CONCURRENT_SERVICE_LIMIT_REACHED</li>
+ *
+ * Asynchronous errors through the listener include any of the errors except
+ * <li>ERROR_MSDC_UNABLE_TO_)START_SERVICE</li>
+ * <li>ERROR_MSDC_INVALID_SERVICE_ID</li>
+ * <li>ERROR_MSDC_END_OF_SESSION</li>
+ */
+ public int getFileServices(List<String> serviceClasses) {
+ return 0;
+ }
+
+
+ /**
+ * Requests a future download.
+ * returns a token which may be used to cancel a download.
+ * downloadListener is an optional callback object which can be used to get progress reports
+ * of a currently occuring download. Note this can only run while the calling app
+ * is running, so future downloads will simply result in resultIntents being sent
+ * for completed or errored-out downloads. A NULL indicates no callbacks are needed.
+ *
+ * May throw an IllegalArgumentException or RemoteExcpetion.
+ *
+ * Asynchronous errors through the listener include any of the errors
+ */
+ public DownloadRequest download(DownloadRequest downloadRequest, DownloadCallback listener) {
+ return null;
+ }
+
+ /**
+ * Returns a list DownloadRequests that originated from this application (UID).
+ *
+ * May throw a RemoteException.
+ *
+ * Asynchronous errors through the listener include any of the errors except
+ * <li>ERROR_UNABLED_TO_START_SERVICE</li>
+ * <li>ERROR_MSDC_INVALID_SERVICE_ID</li>
+ * <li>ERROR_MSDC_END_OF_SESSION</li>
+ */
+ public List<DownloadRequest> listPendingDownloads() {
+ return null;
+ }
+
+ /**
+ * Attempts to cancel the specified DownloadRequest.
+ *
+ * May throw a RemoteException.
+ *
+ * Synchronous responses may include
+ * <li>SUCCESS</li>
+ * <li>ERROR_MSDC_CONCURRENT_SERVICE_LIMIT_REACHED</li>
+ * <li>ERROR_MSDC_UNKNOWN_REQUEST</li>
+ */
+ public int cancelDownload(DownloadRequest downloadRequest) {
+ return 0;
+ }
+
+ /**
+ * Gets information about current and known upcoming downloads.
+ *
+ * Current is a straightforward count of the files being downloaded "now"
+ * for some definition of now (may be racey).
+ * Future downloads include counts of files with pending repair operations, counts of
+ * files with future downloads and indication of scheduled download times with unknown
+ * file details.
+ *
+ * May throw an IllegalArgumentException or RemoteException.
+ *
+ * If the DownloadRequest is unknown the results will be null.
+ */
+ public DownloadStatus getDownloadStatus(DownloadRequest downloadRequest) {
+ return null;
+ }
+
+ /**
+ * Resets middleware knowledge regarding this download request.
+ *
+ * This state consists of knowledge of what files have already been downloaded.
+ * Normally the middleware won't download files who's hash matches previously downloaded
+ * content, even if that content has since been deleted. If this function is called
+ * repeated content will be downloaded again when available. This does not interrupt
+ * in-progress downloads.
+ *
+ * May throw an IllegalArgumentException or RemoteException.
+ *
+ * <li>SUCCESS</li>
+ * <li>ERROR_MSDC_CONCURRENT_SERVICE_LIMIT_REACHED</li>
+ * <li>ERROR_MSDC_UNKNOWN_REQUEST</li>
+ */
+ public int resetDownloadKnowledge(DownloadRequest downloadRequest) {
+ return 0;
+ }
+
+ public void dispose() {
+ try {
+ if (mService != null) {
+ mService.dispose(mDownloadAppName, mSubId);
+ } else {
+ Log.i(LOG_TAG, "Service already dead");
+ }
+ } catch (RemoteException e) {
+ // Ignore
+ Log.i(LOG_TAG, "Remote exception while disposing of service");
+ }
+ }
+}
diff --git a/telephony/java/android/telephony/MbmsStreamingManager.java b/telephony/java/android/telephony/MbmsStreamingManager.java
new file mode 100644
index 0000000..770a04a
--- /dev/null
+++ b/telephony/java/android/telephony/MbmsStreamingManager.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2016 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.telephony;
+
+import android.content.Context;
+import android.os.RemoteException;
+import android.telephony.mbms.IMbmsStreamingManagerCallback;
+import android.telephony.mbms.IStreamingServiceCallback;
+import android.telephony.mbms.MbmsInitializationException;
+import android.telephony.mbms.StreamingService;
+import android.telephony.mbms.StreamingServiceInfo;
+import android.telephony.mbms.vendor.IMbmsStreamingService;
+import android.util.Log;
+
+import java.util.List;
+
+import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+
+/** @hide */
+public class MbmsStreamingManager {
+ private static final String LOG_TAG = "MbmsStreamingManager";
+ private static final boolean DEBUG = true;
+ private IMbmsStreamingService mService;
+ private IMbmsStreamingManagerCallback mCallbackToApp;
+ private final String mAppName;
+
+ private final Context mContext;
+ private int mSubscriptionId = INVALID_SUBSCRIPTION_ID;
+
+ /** @hide */
+ private MbmsStreamingManager(Context context, IMbmsStreamingManagerCallback listener,
+ String streamingAppName, int subscriptionId) {
+ mContext = context;
+ mAppName = streamingAppName;
+ mCallbackToApp = listener;
+ mSubscriptionId = subscriptionId;
+ }
+
+ /**
+ * Create a new MbmsStreamingManager using the given subscription ID.
+ *
+ * Note that this call will bind a remote service and that may take a bit. This
+ * may throw an IllegalArgumentException or RemoteException.
+ * TODO: document this and add exceptions that can be thrown for synchronous
+ * initialization/bind errors
+ *
+ * @param context
+ * @param listener
+ * @param streamingAppName
+ * @param subscriptionId
+ * @return
+ */
+ public static MbmsStreamingManager create(Context context,
+ IMbmsStreamingManagerCallback listener, String streamingAppName, int subscriptionId)
+ throws MbmsInitializationException {
+ MbmsStreamingManager manager = new MbmsStreamingManager(context, listener,
+ streamingAppName, subscriptionId);
+ manager.bindAndInitialize();
+ return manager;
+ }
+
+ /**
+ * Create a new MbmsStreamingManager using the system default data subscription ID.
+ *
+ * Note that this call will bind a remote service and that may take a bit. This
+ * may throw an IllegalArgumentException or RemoteException.
+ */
+ public static MbmsStreamingManager create(Context context,
+ IMbmsStreamingManagerCallback listener, String streamingAppName)
+ throws MbmsInitializationException {
+ // TODO: get default sub id
+ int subId = INVALID_SUBSCRIPTION_ID;
+ MbmsStreamingManager manager = new MbmsStreamingManager(context, listener,
+ streamingAppName, subId);
+ manager.bindAndInitialize();
+ return manager;
+ }
+
+ /**
+ * Terminates this instance, ending calls to the registered listener. Also terminates
+ * any streaming services spawned from this instance.
+ */
+ public void dispose() {
+ // service.dispose(streamingAppName);
+ }
+
+ /**
+ * An inspection API to retrieve the list of streaming media currently be advertised.
+ * The results are returned asynchronously through the previously registered callback.
+ * serviceClasses lets the app filter on types of programming and is opaque data between
+ * the app and the carrier.
+ *
+ * Multiple calls replace the list of serviceClasses of interest.
+ *
+ * May throw an IllegalArgumentException or RemoteException.
+ *
+ * Synchronous responses include
+ * <li>SUCCESS</li>
+ * <li>ERROR_MSDC_CONCURRENT_SERVICE_LIMIT_REACHED</li>
+ *
+ * Asynchronous errors through the listener include any of the errors except
+ * <li>ERROR_MSDC_UNABLE_TO_)START_SERVICE</li>
+ * <li>ERROR_MSDC_INVALID_SERVICE_ID</li>
+ * <li>ERROR_MSDC_END_OF_SESSION</li>
+ */
+ public int getStreamingServices(List<String> classList) {
+ return 0;
+ }
+
+ /**
+ * Starts streaming a requested service, reporting status to the indicated listener.
+ * Returns an object used to control that stream.
+ *
+ * May throw an IllegalArgumentException or RemoteException.
+ *
+ * Asynchronous errors through the listener include any of the errors
+ */
+ public StreamingService startStreaming(StreamingServiceInfo serviceInfo,
+ IStreamingServiceCallback listener) {
+ return null;
+ }
+
+ /**
+ * Lists all the services currently being streamed to the device by this application
+ * on this given subId. Results are returned asynchronously through the previously
+ * registered callback.
+ *
+ * May throw a RemoteException.
+ *
+ * The return value is a success/error-code with the following possible values:
+ * <li>SUCCESS</li>
+ * <li>ERROR_MSDC_CONCURRENT_SERVICE_LIMIT_REACHED</li>
+ *
+ * Asynchronous errors through the listener include any of the errors except
+ * <li>ERROR_UNABLED_TO_START_SERVICE</li>
+ * <li>ERROR_MSDC_INVALID_SERVICE_ID</li>
+ * <li>ERROR_MSDC_END_OF_SESSION</li>
+ *
+ */
+ public int getActiveStreamingServices() {
+ return 0;
+ }
+
+ private void logd(String str) {
+ Log.d(LOG_TAG, str);
+ }
+
+ private boolean isServiceConnected() {
+ return mService != null;
+ }
+
+ private void bindAndInitialize() throws MbmsInitializationException {
+ // TODO: bind to the service
+ try {
+ int returnCode = mService.initialize(mCallbackToApp, mAppName, mSubscriptionId);
+ if (returnCode != 0) {
+ throw new MbmsInitializationException(returnCode);
+ }
+ } catch (RemoteException e) {
+ throw new MbmsInitializationException(/* some error */ 0);
+ }
+ }
+}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 675b902..5985813 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -16,24 +16,32 @@
package android.telephony;
+import static com.android.internal.util.Preconditions.checkNotNull;
+
import android.annotation.IntDef;
import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.WorkerThread;
+import android.annotation.SystemApi;
import android.app.ActivityThread;
+import android.app.PendingIntent;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.Uri;
import android.os.BatteryStats;
-import android.os.ResultReceiver;
+import android.os.Binder;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
import android.os.Bundle;
+import android.os.Handler;
import android.os.PersistableBundle;
import android.os.RemoteException;
+import android.os.ResultReceiver;
import android.os.ServiceManager;
import android.os.SystemProperties;
import android.service.carrier.CarrierIdentifier;
@@ -61,6 +69,7 @@
import java.io.IOException;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -838,6 +847,29 @@
*/
public static final String VVM_TYPE_CVVM = "vvm_type_cvvm";
+ /**
+ * @hide
+ */
+ public static final String USSD_RESPONSE = "USSD_RESPONSE";
+
+ /**
+ * USSD return code success.
+ * @hide
+ */
+ public static final int USSD_RETURN_SUCCESS = 100;
+
+ /**
+ * USSD return code for failure case.
+ * @hide
+ */
+ public static final int USSD_RETURN_FAILURE = -1;
+
+ /**
+ * USSD return code for failure case.
+ * @hide
+ */
+ public static final int USSD_ERROR_SERVICE_UNAVAIL = -2;
+
//
//
// Device Info
@@ -853,7 +885,7 @@
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
*/
public String getDeviceSoftwareVersion() {
- return getDeviceSoftwareVersion(getDefaultSim());
+ return getDeviceSoftwareVersion(getSlotIndex());
}
/**
@@ -939,7 +971,7 @@
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
*/
public String getImei() {
- return getImei(getDefaultSim());
+ return getImei(getSlotIndex());
}
/**
@@ -971,7 +1003,7 @@
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
*/
public String getMeid() {
- return getMeid(getDefaultSim());
+ return getMeid(getSlotIndex());
}
/**
@@ -1001,7 +1033,7 @@
*/
/** {@hide}*/
public String getNai() {
- return getNai(getDefaultSim());
+ return getNai(getSlotIndex());
}
/**
@@ -1245,7 +1277,7 @@
}
private int getPhoneTypeFromProperty() {
- return getPhoneTypeFromProperty(getDefaultPhone());
+ return getPhoneTypeFromProperty(getPhoneId());
}
/** {@hide} */
@@ -1259,7 +1291,7 @@
}
private int getPhoneTypeFromNetworkType() {
- return getPhoneTypeFromNetworkType(getDefaultPhone());
+ return getPhoneTypeFromNetworkType(getPhoneId());
}
/** {@hide} */
@@ -1442,7 +1474,7 @@
* on a CDMA network).
*/
public String getNetworkOperator() {
- return getNetworkOperatorForPhone(getDefaultPhone());
+ return getNetworkOperatorForPhone(getPhoneId());
}
/**
@@ -1478,18 +1510,23 @@
/**
- * Returns the network specifier of the subscription ID pinned to the TelephonyManager.
+ * Returns the network specifier of the subscription ID pinned to the TelephonyManager. The
+ * network specifier is used by {@link
+ * android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} to create a {@link
+ * android.net.NetworkRequest} that connects through the subscription.
*
* @see android.net.NetworkRequest.Builder#setNetworkSpecifier(String)
* @see #createForSubscriptionId(int)
* @see #createForPhoneAccountHandle(PhoneAccountHandle)
*/
public String getNetworkSpecifier() {
- return String.valueOf(mSubId);
+ return String.valueOf(getSubId());
}
/**
- * Returns the carrier config of the subscription ID pinned to the TelephonyManager.
+ * Returns the carrier config of the subscription ID pinned to the TelephonyManager. If an
+ * invalid subscription ID is pinned to the TelephonyManager, the returned config will contain
+ * default values.
*
* <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE
* READ_PHONE_STATE}
@@ -1498,10 +1535,11 @@
* @see #createForSubscriptionId(int)
* @see #createForPhoneAccountHandle(PhoneAccountHandle)
*/
+ @WorkerThread
public PersistableBundle getCarrierConfig() {
CarrierConfigManager carrierConfigManager = mContext
.getSystemService(CarrierConfigManager.class);
- return carrierConfigManager.getConfigForSubId(mSubId);
+ return carrierConfigManager.getConfigForSubId(getSubId());
}
/**
@@ -1538,7 +1576,7 @@
* on a CDMA network).
*/
public String getNetworkCountryIso() {
- return getNetworkCountryIsoForPhone(getDefaultPhone());
+ return getNetworkCountryIsoForPhone(getPhoneId());
}
/**
@@ -1684,6 +1722,9 @@
* Returns a constant indicating the radio technology (network type)
* currently in use on the device for data transmission.
*
+ * If this object has been created with {@link #createForSubscriptionId}, applies to the given
+ * subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()}
+ *
* <p>
* Requires Permission:
* {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
@@ -1708,7 +1749,7 @@
* @see #NETWORK_TYPE_HSPAP
*/
public int getDataNetworkType() {
- return getDataNetworkType(getSubId());
+ return getDataNetworkType(getSubId(SubscriptionManager.getDefaultDataSubscriptionId()));
}
/**
@@ -1932,7 +1973,7 @@
* @return true if a ICC card is present
*/
public boolean hasIccCard() {
- return hasIccCard(getDefaultSim());
+ return hasIccCard(getSlotIndex());
}
/**
@@ -1973,7 +2014,7 @@
* @see #SIM_STATE_CARD_RESTRICTED
*/
public int getSimState() {
- int slotIndex = getDefaultSim();
+ int slotIndex = getSlotIndex();
// slotIndex may be invalid due to sim being absent. In that case query all slots to get
// sim state
if (slotIndex < 0) {
@@ -2102,7 +2143,7 @@
* @see #getSimState
*/
public String getSimOperatorName() {
- return getSimOperatorNameForPhone(getDefaultPhone());
+ return getSimOperatorNameForPhone(getPhoneId());
}
/**
@@ -2134,7 +2175,7 @@
* Returns the ISO country code equivalent for the SIM provider's country code.
*/
public String getSimCountryIso() {
- return getSimCountryIsoForPhone(getDefaultPhone());
+ return getSimCountryIsoForPhone(getPhoneId());
}
/**
@@ -2682,6 +2723,33 @@
return false;
}
+
+ /**
+ * Returns the package responsible of processing visual voicemail for the subscription ID pinned
+ * to the TelephonyManager. Returns {@code null} when there is no package responsible for
+ * processing visual voicemail for the subscription.
+ *
+ * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE
+ * READ_PHONE_STATE}
+ *
+ * @see #createForSubscriptionId(int)
+ * @see #createForPhoneAccountHandle(PhoneAccountHandle)
+ * @see VisualVoicemailService
+ */
+ @Nullable
+ public String getVisualVoicemailPackageName() {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ return telephony
+ .getVisualVoicemailPackageName(mContext.getOpPackageName(), getSubId());
+ }
+ } catch (RemoteException ex) {
+ } catch (NullPointerException ex) {
+ }
+ return null;
+ }
+
/**
* Enables the visual voicemail SMS filter for a phone account. When the filter is
* enabled, Incoming SMS messages matching the OMTP VVM SMS interface will be redirected to the
@@ -2758,18 +2826,17 @@
/**
* @returns the settings of the visual voicemail SMS filter for a phone account set by the
- * package, or {@code null} if the filter is disabled.
+ * current active visual voicemail client, or {@code null} if the filter is disabled.
*
* <p>Requires the calling app to have READ_PRIVILEGED_PHONE_STATE permission.
*/
/** @hide */
@Nullable
- public VisualVoicemailSmsFilterSettings getVisualVoicemailSmsFilterSettings(String packageName,
- int subId) {
+ public VisualVoicemailSmsFilterSettings getActiveVisualVoicemailSmsFilterSettings(int subId) {
try {
ITelephony telephony = getITelephony();
if (telephony != null) {
- return telephony.getSystemVisualVoicemailSmsFilterSettings(packageName, subId);
+ return telephony.getActiveVisualVoicemailSmsFilterSettings(subId);
}
} catch (RemoteException ex) {
} catch (NullPointerException ex) {
@@ -2779,6 +2846,35 @@
}
/**
+ * Send a visual voicemail SMS. The IPC caller must be the current default dialer.
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#SEND_SMS SEND_SMS}
+ *
+ * @param phoneAccountHandle The account to send the SMS with.
+ * @param number The destination number.
+ * @param port The destination port for data SMS, or 0 for text SMS.
+ * @param text The message content. For data sms, it will be encoded as a UTF-8 byte stream.
+ * @param sentIntent The sent intent passed to the {@link SmsManager}
+ *
+ * @see SmsManager#sendDataMessage(String, String, short, byte[], PendingIntent, PendingIntent)
+ * @see SmsManager#sendTextMessage(String, String, String, PendingIntent, PendingIntent)
+ *
+ * @hide
+ */
+ public void sendVisualVoicemailSmsForSubscriber(int subId, String number, int port,
+ String text, PendingIntent sentIntent) {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ telephony.sendVisualVoicemailSmsForSubscriber(
+ mContext.getOpPackageName(), subId, number, port, text, sentIntent);
+ }
+ } catch (RemoteException ex) {
+ }
+ }
+
+ /**
* Initial SIM activation state, unknown. Not set by any carrier apps.
* @hide
*/
@@ -3924,35 +4020,67 @@
* subId is returned. Otherwise, the default subId will be returned.
*/
private int getSubId() {
- if (mSubId == SubscriptionManager.DEFAULT_SUBSCRIPTION_ID) {
- return getDefaultSubscription();
+ if (SubscriptionManager.isUsableSubIdValue(mSubId)) {
+ return mSubId;
}
- return mSubId;
+ return SubscriptionManager.getDefaultSubscriptionId();
}
/**
- * Returns Default subscription.
+ * Return an appropriate subscription ID for any situation.
+ *
+ * If this object has been created with {@link #createForSubscriptionId}, then the provided
+ * subId is returned. Otherwise, the preferred subId which is based on caller's context is
+ * returned.
+ * {@see SubscriptionManager#getDefaultDataSubscriptionId()}
+ * {@see SubscriptionManager#getDefaultVoiceSubscriptionId()}
+ * {@see SubscriptionManager#getDefaultSmsSubscriptionId()}
*/
- private static int getDefaultSubscription() {
- return SubscriptionManager.getDefaultSubscriptionId();
+ private int getSubId(int preferredSubId) {
+ if (SubscriptionManager.isUsableSubIdValue(mSubId)) {
+ return mSubId;
+ }
+ return preferredSubId;
}
/**
- * Returns Default phone.
+ * Return an appropriate phone ID for any situation.
+ *
+ * If this object has been created with {@link #createForSubscriptionId}, then the phoneId
+ * associated with the provided subId is returned. Otherwise, the default phoneId associated
+ * with the default subId will be returned.
*/
- private static int getDefaultPhone() {
- return SubscriptionManager.getPhoneId(SubscriptionManager.getDefaultSubscriptionId());
+ private int getPhoneId() {
+ return SubscriptionManager.getPhoneId(getSubId());
}
/**
- * @return default SIM's slot index. If SIM is not inserted, return default SIM slot index.
+ * Return an appropriate phone ID for any situation.
+ *
+ * If this object has been created with {@link #createForSubscriptionId}, then the phoneId
+ * associated with the provided subId is returned. Otherwise, return the phoneId associated
+ * with the preferred subId based on caller's context.
+ * {@see SubscriptionManager#getDefaultDataSubscriptionId()}
+ * {@see SubscriptionManager#getDefaultVoiceSubscriptionId()}
+ * {@see SubscriptionManager#getDefaultSmsSubscriptionId()}
+ */
+ private int getPhoneId(int preferredSubId) {
+ return SubscriptionManager.getPhoneId(getSubId(preferredSubId));
+ }
+
+ /**
+ * Return an appropriate slot index for any situation.
+ *
+ * if this object has been created with {@link #createForSubscriptionId}, then the slot index
+ * associated with the provided subId is returned. Otherwise, return the slot index associated
+ * with the default subId.
+ * If SIM is not inserted, return default SIM slot index.
*
* {@hide}
*/
@VisibleForTesting
- public int getDefaultSim() {
- int slotIndex = SubscriptionManager.getSlotIndex(
- SubscriptionManager.getDefaultSubscriptionId());
+ public int getSlotIndex() {
+ int slotIndex = SubscriptionManager.getSlotIndex(getSubId());
if (slotIndex == SubscriptionManager.SIM_NOT_INSERTED) {
slotIndex = SubscriptionManager.DEFAULT_SIM_SLOT_INDEX;
}
@@ -4769,7 +4897,7 @@
/** @hide */
@SystemApi
public List<String> getCarrierPackageNamesForIntent(Intent intent) {
- return getCarrierPackageNamesForIntentAndPhone(intent, getDefaultPhone());
+ return getCarrierPackageNamesForIntentAndPhone(intent, getPhoneId());
}
/** @hide */
@@ -4965,6 +5093,80 @@
return new int[0];
}
+ public static abstract class OnReceiveUssdResponseCallback {
+ /**
+ ** Called when USSD has succeeded.
+ **/
+ public void onReceiveUssdResponse(String request, CharSequence response) {};
+
+ /**
+ ** Called when USSD has failed.
+ **/
+ public void onReceiveUssdResponseFailed(String request, int failureCode) {};
+ }
+
+ /**
+ * Sends an Unstructured Supplementary Service Data (USSD) request to the cellular network and
+ * informs the caller of the response via {@code callback}.
+ * <p>Carriers define USSD codes which can be sent by the user to request information such as
+ * the user's current data balance or minutes balance.
+ * <p>Requires permission:
+ * {@link android.Manifest.permission#CALL_PHONE}
+ * @param ussdRequest the USSD command to be executed.
+ * @param callback called by the framework to inform the caller of the result of executing the
+ * USSD request (see {@link OnReceiveUssdResponseCallback}).
+ * @param handler the {@link Handler} to run the request on.
+ */
+ @RequiresPermission(android.Manifest.permission.CALL_PHONE)
+ public void sendUssdRequest(String ussdRequest,
+ final OnReceiveUssdResponseCallback callback, Handler handler) {
+ checkNotNull(callback, "OnReceiveUssdResponseCallback cannot be null.");
+
+ ResultReceiver wrappedCallback = new ResultReceiver(handler) {
+ @Override
+ protected void onReceiveResult(int resultCode, Bundle ussdResponse) {
+ Rlog.d(TAG, "USSD:" + resultCode);
+ checkNotNull(ussdResponse, "ussdResponse cannot be null.");
+ UssdResponse response = ussdResponse.getParcelable(USSD_RESPONSE);
+
+ if (resultCode == USSD_RETURN_SUCCESS) {
+ callback.onReceiveUssdResponse(response.getUssdRequest(),
+ response.getReturnMessage());
+ } else {
+ callback.onReceiveUssdResponseFailed(response.getUssdRequest(), resultCode);
+ }
+ }
+ };
+
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ telephony.handleUssdRequest(getSubId(), ussdRequest, wrappedCallback);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling ITelephony#sendUSSDCode", e);
+ UssdResponse response = new UssdResponse(ussdRequest, "");
+ Bundle returnData = new Bundle();
+ returnData.putParcelable(USSD_RESPONSE, response);
+ wrappedCallback.send(USSD_ERROR_SERVICE_UNAVAIL, returnData);
+ }
+ }
+
+ /*
+ * @return true, if the device is currently on a technology (e.g. UMTS or LTE) which can support
+ * voice and data simultaneously. This can change based on location or network condition.
+ */
+ public boolean isConcurrentVoiceAndDataAllowed() {
+ try {
+ ITelephony telephony = getITelephony();
+ return (telephony == null ? false : telephony.isConcurrentVoiceAndDataAllowed(
+ getSubId()));
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling ITelephony#isConcurrentVoiceAndDataAllowed", e);
+ }
+ return false;
+ }
+
/** @hide */
@SystemApi
public boolean handlePinMmi(String dialString) {
@@ -5095,6 +5297,8 @@
/**
* Turns mobile data on or off.
+ * If this object has been created with {@link #createForSubscriptionId}, applies to the given
+ * subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()}
*
* <p>Requires Permission:
* {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE} or that the
@@ -5105,7 +5309,7 @@
* @see #hasCarrierPrivileges
*/
public void setDataEnabled(boolean enable) {
- setDataEnabled(getSubId(), enable);
+ setDataEnabled(getSubId(SubscriptionManager.getDefaultDataSubscriptionId()), enable);
}
/** @hide */
@@ -5121,23 +5325,45 @@
}
}
+
+ /**
+ * @deprecated use {@link #isDataEnabled()} instead.
+ * @hide
+ */
+ @SystemApi
+ @Deprecated
+ public boolean getDataEnabled() {
+ return isDataEnabled();
+ }
+
/**
* Returns whether mobile data is enabled or not.
*
- * <p>Requires Permission:
- * {@link android.Manifest.permission#ACCESS_NETWORK_STATE ACCESS_NETWORK_STATE},
- * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}, or that the
- * calling app has carrier privileges.
+ * If this object has been created with {@link #createForSubscriptionId}, applies to the given
+ * subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()}
+ *
+ * <p>Requires one of the following permissions:
+ * {@link android.Manifest.permission#ACCESS_NETWORK_STATE ACCESS_NETWORK_STATE},
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}, or that the
+ * calling app has carrier privileges.
+ *
+ * <p>Note that this does not take into account any data restrictions that may be present on the
+ * calling app. Such restrictions may be inspected with
+ * {@link ConnectivityManager#getRestrictBackgroundStatus}.
*
* @return true if mobile data is enabled.
*
* @see #hasCarrierPrivileges
*/
- public boolean getDataEnabled() {
- return getDataEnabled(getSubId());
+ @SuppressWarnings("deprecation")
+ public boolean isDataEnabled() {
+ return getDataEnabled(getSubId(SubscriptionManager.getDefaultDataSubscriptionId()));
}
- /** @hide */
+ /**
+ * @deprecated use {@link #isDataEnabled(int)} instead.
+ * @hide
+ */
@SystemApi
public boolean getDataEnabled(int subId) {
boolean retVal = false;
@@ -5381,7 +5607,7 @@
* @hide
*/
public void setSimOperatorNumeric(String numeric) {
- int phoneId = getDefaultPhone();
+ int phoneId = getPhoneId();
setSimOperatorNumericForPhone(phoneId, numeric);
}
@@ -5401,7 +5627,7 @@
* @hide
*/
public void setSimOperatorName(String name) {
- int phoneId = getDefaultPhone();
+ int phoneId = getPhoneId();
setSimOperatorNameForPhone(phoneId, name);
}
@@ -5421,7 +5647,7 @@
* @hide
*/
public void setSimCountryIso(String iso) {
- int phoneId = getDefaultPhone();
+ int phoneId = getPhoneId();
setSimCountryIsoForPhone(phoneId, iso);
}
@@ -5441,7 +5667,7 @@
* @hide
*/
public void setSimState(String state) {
- int phoneId = getDefaultPhone();
+ int phoneId = getPhoneId();
setSimStateForPhone(phoneId, state);
}
@@ -5466,7 +5692,7 @@
* @hide
**/
public void setSimPowerState(boolean powerUp) {
- setSimPowerStateForSlot(getDefaultSim(), powerUp);
+ setSimPowerStateForSlot(getSlotIndex(), powerUp);
}
/**
@@ -5500,7 +5726,7 @@
* @hide
*/
public void setBasebandVersion(String version) {
- int phoneId = getDefaultPhone();
+ int phoneId = getPhoneId();
setBasebandVersionForPhone(phoneId, version);
}
@@ -5527,7 +5753,7 @@
* @hide
*/
public void setPhoneType(int type) {
- int phoneId = getDefaultPhone();
+ int phoneId = getPhoneId();
setPhoneType(phoneId, type);
}
@@ -5555,7 +5781,7 @@
* @hide
*/
public String getOtaSpNumberSchema(String defaultValue) {
- int phoneId = getDefaultPhone();
+ int phoneId = getPhoneId();
return getOtaSpNumberSchemaForPhone(phoneId, defaultValue);
}
@@ -5586,7 +5812,7 @@
* @hide
*/
public boolean getSmsReceiveCapable(boolean defaultValue) {
- int phoneId = getDefaultPhone();
+ int phoneId = getPhoneId();
return getSmsReceiveCapableForPhone(phoneId, defaultValue);
}
@@ -5617,7 +5843,7 @@
* @hide
*/
public boolean getSmsSendCapable(boolean defaultValue) {
- int phoneId = getDefaultPhone();
+ int phoneId = getPhoneId();
return getSmsSendCapableForPhone(phoneId, defaultValue);
}
@@ -5645,7 +5871,7 @@
* @hide
*/
public void setNetworkOperatorName(String name) {
- int phoneId = getDefaultPhone();
+ int phoneId = getPhoneId();
setNetworkOperatorNameForPhone(phoneId, name);
}
@@ -5667,7 +5893,7 @@
* @hide
*/
public void setNetworkOperatorNumeric(String numeric) {
- int phoneId = getDefaultPhone();
+ int phoneId = getPhoneId();
setNetworkOperatorNumericForPhone(phoneId, numeric);
}
@@ -5687,7 +5913,7 @@
* @hide
*/
public void setNetworkRoaming(boolean isRoaming) {
- int phoneId = getDefaultPhone();
+ int phoneId = getPhoneId();
setNetworkRoamingForPhone(phoneId, isRoaming);
}
@@ -5711,7 +5937,7 @@
* @hide
*/
public void setNetworkCountryIso(String iso) {
- int phoneId = getDefaultPhone();
+ int phoneId = getPhoneId();
setNetworkCountryIsoForPhone(phoneId, iso);
}
@@ -5731,11 +5957,15 @@
/**
* Set the network type currently in use on the device for data transmission.
+ *
+ * If this object has been created with {@link #createForSubscriptionId}, applies to the
+ * phoneId associated with the given subId. Otherwise, applies to the phoneId associated with
+ * {@link SubscriptionManager#getDefaultDataSubscriptionId()}
* @param type the network type currently in use on the device for data transmission
* @hide
*/
public void setDataNetworkType(int type) {
- int phoneId = getDefaultPhone();
+ int phoneId = getPhoneId(SubscriptionManager.getDefaultDataSubscriptionId());
setDataNetworkTypeForPhone(phoneId, type);
}
@@ -5907,7 +6137,7 @@
* @hide
*/
public String getAidForAppType(int appType) {
- return getAidForAppType(getDefaultSubscription(), appType);
+ return getAidForAppType(getSubId(), appType);
}
/**
@@ -5941,7 +6171,7 @@
* @hide
*/
public String getEsn() {
- return getEsn(getDefaultSubscription());
+ return getEsn(getSubId());
}
/**
@@ -5974,7 +6204,7 @@
* @hide
*/
public String getCdmaPrlVersion() {
- return getCdmaPrlVersion(getDefaultSubscription());
+ return getCdmaPrlVersion(getSubId());
}
/**
@@ -6072,7 +6302,7 @@
} catch (RemoteException e) {
Log.e(TAG, "Error calling ITelephony#getAllowedCarriers", e);
} catch (NullPointerException e) {
- Log.e(TAG, "Error calling ITelephony#setAllowedCarriers", e);
+ Log.e(TAG, "Error calling ITelephony#getAllowedCarriers", e);
}
return new ArrayList<CarrierIdentifier>(0);
}
diff --git a/telephony/java/android/telephony/UssdResponse.aidl b/telephony/java/android/telephony/UssdResponse.aidl
new file mode 100644
index 0000000..add28a0
--- /dev/null
+++ b/telephony/java/android/telephony/UssdResponse.aidl
@@ -0,0 +1,20 @@
+/*
+**
+** Copyright 2007, 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.telephony;
+
+parcelable UssdResponse;
diff --git a/telephony/java/android/telephony/UssdResponse.java b/telephony/java/android/telephony/UssdResponse.java
new file mode 100644
index 0000000..5df681d
--- /dev/null
+++ b/telephony/java/android/telephony/UssdResponse.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2006 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.telephony;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+
+/**
+ * Represents the Ussd response, including
+ * the message and the return code.
+ * @hide
+ */
+public final class UssdResponse implements Parcelable {
+ private CharSequence mReturnMessage;
+ private String mUssdRequest;
+
+
+ /**
+ * Implement the Parcelable interface
+ */
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(mUssdRequest);
+ TextUtils.writeToParcel(mReturnMessage, dest, 0);
+ }
+
+ public String getUssdRequest() {
+ return mUssdRequest;
+ }
+
+ public CharSequence getReturnMessage() {
+ return mReturnMessage;
+ }
+
+ /**
+ * Implement the Parcelable interface
+ */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * * Initialize the object from the request and return message.
+ */
+ public UssdResponse(String ussdRequest, CharSequence returnMessage) {
+ mUssdRequest = ussdRequest;
+ mReturnMessage = returnMessage;
+ }
+
+ public static final Parcelable.Creator<UssdResponse> CREATOR = new Creator<UssdResponse>() {
+
+ @Override
+ public UssdResponse createFromParcel(Parcel in) {
+ String request = in.readString();
+ CharSequence message = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+ return new UssdResponse(request, message);
+ }
+
+ @Override
+ public UssdResponse[] newArray(int size) {
+ return new UssdResponse[size];
+ }
+ };
+}
diff --git a/telephony/java/android/telephony/VisualVoicemailService.java b/telephony/java/android/telephony/VisualVoicemailService.java
new file mode 100644
index 0000000..84833e3
--- /dev/null
+++ b/telephony/java/android/telephony/VisualVoicemailService.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2016 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.telephony;
+
+import android.annotation.MainThread;
+import android.annotation.SdkConstant;
+import android.app.PendingIntent;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+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.telecom.PhoneAccountHandle;
+import android.telecom.TelecomManager;
+import android.util.Log;
+
+/**
+ * This service is implemented by dialer apps that wishes to handle OMTP or similar visual
+ * voicemails. Telephony binds to this service when the cell service is first connected, a visual
+ * voicemail SMS has been received, or when a SIM has been removed. Telephony will only bind to the
+ * default dialer for such events (See {@link TelecomManager#getDefaultDialerPackage()}). The
+ * {@link android.service.carrier.CarrierMessagingService} precedes the VisualVoicemailService in
+ * the SMS filtering chain and may intercept the visual voicemail SMS before it reaches this
+ * service.
+ * <p>
+ * Below is an example manifest registration for a {@code VisualVoicemailService}.
+ * <pre>
+ * {@code
+ * <service android:name="your.package.YourVisualVoicemailServiceImplementation"
+ * android:permission="android.permission.BIND_VISUAL_VOICEMAIL_SERVICE">
+ * <intent-filter>
+ * <action android:name="android.telephony.VisualVoicemailService"/>
+ * </intent-filter>
+ * </service>
+ * }
+ * </pre>
+ */
+public abstract class VisualVoicemailService extends Service {
+
+ private static final String TAG = "VvmService";
+
+ /**
+ * The {@link Intent} that must be declared as handled by the service.
+ */
+ @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
+ public static final String SERVICE_INTERFACE = "android.telephony.VisualVoicemailService";
+
+ /**
+ * @hide
+ */
+ public static final int MSG_ON_CELL_SERVICE_CONNECTED = 1;
+ /**
+ * @hide
+ */
+ public static final int MSG_ON_SMS_RECEIVED = 2;
+ /**
+ * @hide
+ */
+ public static final int MSG_ON_SIM_REMOVED = 3;
+ /**
+ * @hide
+ */
+ public static final int MSG_TASK_ENDED = 4;
+ /**
+ * @hide
+ */
+ public static final int MSG_TASK_STOPPED = 5;
+
+ /**
+ * @hide
+ */
+ public static final String DATA_PHONE_ACCOUNT_HANDLE = "data_phone_account_handle";
+ /**
+ * @hide
+ */
+ public static final String DATA_SMS = "data_sms";
+
+ /**
+ * Represents a visual voicemail event which needs to be handled. While the task is being
+ * processed telephony will hold a wakelock for the VisualVoicemailService. The service can
+ * unblock the main thread and pass the task to a worker thread. Once the task is finished,
+ * {@link VisualVoicemailTask#finish()} should be called to signal telephony to release the
+ * resources. Telephony will call {@link VisualVoicemailService#onStopped(VisualVoicemailTask)}
+ * when the task is going to be terminated before completion.
+ *
+ * @see #onCellServiceConnected(VisualVoicemailTask, PhoneAccountHandle)
+ * @see #onSmsReceived(VisualVoicemailTask, VisualVoicemailSms)
+ * @see #onSimRemoved(VisualVoicemailTask, PhoneAccountHandle)
+ * @see #onStopped(VisualVoicemailTask)
+ */
+ public static class VisualVoicemailTask {
+
+ private final int mTaskId;
+ private final Messenger mReplyTo;
+
+ private VisualVoicemailTask(Messenger replyTo, int taskId) {
+ mTaskId = taskId;
+ mReplyTo = replyTo;
+ }
+
+ /**
+ * Call to signal telephony the task has completed. Must be called for every task.
+ */
+ public final void finish() {
+ Message message = Message.obtain();
+ try {
+ message.what = MSG_TASK_ENDED;
+ message.arg1 = mTaskId;
+ mReplyTo.send(message);
+ } catch (RemoteException e) {
+ Log.e(TAG,
+ "Cannot send MSG_TASK_ENDED, remote handler no longer exist");
+ }
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof VisualVoicemailTask)) {
+ return false;
+ }
+ return mTaskId == ((VisualVoicemailTask) obj).mTaskId;
+ }
+
+ @Override
+ public int hashCode() {
+ return mTaskId;
+ }
+ }
+
+ /**
+ * Handles messages sent by telephony.
+ */
+ private final Messenger mMessenger = new Messenger(new Handler() {
+ @Override
+ public void handleMessage(final Message msg) {
+ final PhoneAccountHandle handle = msg.getData()
+ .getParcelable(DATA_PHONE_ACCOUNT_HANDLE);
+ VisualVoicemailTask task = new VisualVoicemailTask(msg.replyTo, msg.arg1);
+ switch (msg.what) {
+ case MSG_ON_CELL_SERVICE_CONNECTED:
+ onCellServiceConnected(task, handle);
+ break;
+ case MSG_ON_SMS_RECEIVED:
+ VisualVoicemailSms sms = msg.getData().getParcelable(DATA_SMS);
+ onSmsReceived(task, sms);
+ break;
+ case MSG_ON_SIM_REMOVED:
+ onSimRemoved(task, handle);
+ break;
+ case MSG_TASK_STOPPED:
+ onStopped(task);
+ break;
+ default:
+ super.handleMessage(msg);
+ break;
+ }
+ }
+ });
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return mMessenger.getBinder();
+ }
+
+ /**
+ * Called when the cellular service is connected on a {@link PhoneAccountHandle} for the first
+ * time, or when the carrier config has changed. It will not be called when the signal is lost
+ * then restored.
+ *
+ * @param task The task representing this event. {@link VisualVoicemailTask#finish()} must be
+ * called when the task is completed.
+ * @param phoneAccountHandle The {@link PhoneAccountHandle} triggering this event.
+ */
+ @MainThread
+ public abstract void onCellServiceConnected(VisualVoicemailTask task,
+ PhoneAccountHandle phoneAccountHandle);
+
+ /**
+ * Called when a SMS matching the {@link VisualVoicemailSmsFilterSettings} set by
+ * {@link #setSmsFilterSettings(Context, PhoneAccountHandle, VisualVoicemailSmsFilterSettings)}
+ * is received.
+ *
+ * @param task The task representing this event. {@link VisualVoicemailTask#finish()} must be
+ * called when the task is completed.
+ * @param sms The content of the received SMS.
+ */
+ @MainThread
+ public abstract void onSmsReceived(VisualVoicemailTask task,
+ VisualVoicemailSms sms);
+
+ /**
+ * Called when a SIM is removed.
+ *
+ * @param task The task representing this event. {@link VisualVoicemailTask#finish()} must be
+ * called when the task is completed.
+ * @param phoneAccountHandle The {@link PhoneAccountHandle} triggering this event.
+ */
+ @MainThread
+ public abstract void onSimRemoved(VisualVoicemailTask task,
+ PhoneAccountHandle phoneAccountHandle);
+
+ /**
+ * Called before the system is about to terminate a task. The service should persist any
+ * necessary data and call finish on the task immediately.
+ */
+ @MainThread
+ public abstract void onStopped(VisualVoicemailTask task);
+
+ /**
+ * Set the visual voicemail SMS filter settings for the VisualVoicemailService.
+ * {@link #onSmsReceived(VisualVoicemailTask, VisualVoicemailSms)} will be called when
+ * a SMS matching the settings is received. The caller should have
+ * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE} and implements a
+ * VisualVoicemailService.
+ * <p>
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+ *
+ * @param phoneAccountHandle The account to apply the settings to.
+ * @param settings The settings for the filter, or {@code null} to disable the filter.
+ */
+ public final static void setSmsFilterSettings(Context context,
+ PhoneAccountHandle phoneAccountHandle,
+ VisualVoicemailSmsFilterSettings settings) {
+ TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class);
+ int subId = getSubId(context, phoneAccountHandle);
+ if (settings == null) {
+ telephonyManager.disableVisualVoicemailSmsFilter(subId);
+ } else {
+ telephonyManager.enableVisualVoicemailSmsFilter(subId, settings);
+ }
+ }
+
+ /**
+ * Send a visual voicemail SMS. The caller must be the current default dialer.
+ * <p>
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#SEND_SMS SEND_SMS}
+ *
+ * @param phoneAccountHandle The account to send the SMS with.
+ * @param number The destination number.
+ * @param port The destination port for data SMS, or 0 for text SMS.
+ * @param text The message content. For data sms, it will be encoded as a UTF-8 byte stream.
+ * @param sentIntent The sent intent passed to the {@link SmsManager}
+ * @see SmsManager#sendDataMessage(String, String, short, byte[], PendingIntent, PendingIntent)
+ * @see SmsManager#sendTextMessage(String, String, String, PendingIntent, PendingIntent)
+ */
+ public final static void sendVisualVoicemailSms(Context context,
+ PhoneAccountHandle phoneAccountHandle, String number,
+ short port, String text, PendingIntent sentIntent) {
+ TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class);
+ telephonyManager.sendVisualVoicemailSmsForSubscriber(getSubId(context, phoneAccountHandle),
+ number, port, text, sentIntent);
+ }
+
+ private static int getSubId(Context context, PhoneAccountHandle phoneAccountHandle) {
+ TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class);
+ TelecomManager telecomManager = context.getSystemService(TelecomManager.class);
+ return telephonyManager
+ .getSubIdForPhoneAccount(telecomManager.getPhoneAccount(phoneAccountHandle));
+ }
+
+}
diff --git a/telephony/java/android/telephony/VisualVoicemailSms.java b/telephony/java/android/telephony/VisualVoicemailSms.java
new file mode 100644
index 0000000..1e6ea4b
--- /dev/null
+++ b/telephony/java/android/telephony/VisualVoicemailSms.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2016 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.telephony;
+
+import android.annotation.Nullable;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.telecom.PhoneAccountHandle;
+import android.telephony.VisualVoicemailService.VisualVoicemailTask;
+
+/**
+ * Represents the content of a visual voicemail SMS. If a incoming SMS matches the {@link
+ * VisualVoicemailSmsFilterSettings} set by the default dialer, {@link
+ * VisualVoicemailService#onSmsReceived(VisualVoicemailTask, VisualVoicemailSms)} will be called.
+ */
+public final class VisualVoicemailSms implements Parcelable {
+
+ private final PhoneAccountHandle mPhoneAccountHandle;
+ @Nullable
+ private final String mPrefix;
+
+ @Nullable
+ private final Bundle mFields;
+
+ private final String mMessageBody;
+
+ VisualVoicemailSms(Builder builder) {
+ mPhoneAccountHandle = builder.mPhoneAccountHandle;
+ mPrefix = builder.mPrefix;
+ mFields = builder.mFields;
+ mMessageBody = builder.mMessageBody;
+ }
+
+ /**
+ * The {@link PhoneAccountHandle} that received the SMS.
+ */
+ public PhoneAccountHandle getPhoneAccountHandle() {
+ return mPhoneAccountHandle;
+ }
+
+ /**
+ * The event type of the SMS or {@code null} if the framework cannot parse the SMS as voicemail
+ * but the carrier pattern indicates it is. Common values are "SYNC" or "STATUS".
+ */
+ public String getPrefix() {
+ return mPrefix;
+ }
+
+ /**
+ * The key-value pairs sent by the SMS, or {@code null} if the framework cannot parse the SMS as
+ * voicemail but the carrier pattern indicates it is. The interpretation of the fields is
+ * carrier dependent.
+ */
+ public Bundle getFields() {
+ return mFields;
+ }
+
+ /**
+ * Raw message body of the received SMS.
+ */
+ public String getMessageBody() {
+ return mMessageBody;
+ }
+
+ /**
+ * Builder for the {@link VisualVoicemailSms}. Internal use only.
+ *
+ * @hide
+ */
+ public static class Builder {
+
+ private PhoneAccountHandle mPhoneAccountHandle;
+ private String mPrefix;
+ private Bundle mFields;
+ private String mMessageBody;
+
+ public VisualVoicemailSms build() {
+ return new VisualVoicemailSms(this);
+ }
+
+ public Builder setPhoneAccountHandle(PhoneAccountHandle phoneAccountHandle) {
+ this.mPhoneAccountHandle = phoneAccountHandle;
+ return this;
+ }
+
+ public Builder setPrefix(String prefix) {
+ this.mPrefix = prefix;
+ return this;
+ }
+
+ public Builder setFields(Bundle fields) {
+ this.mFields = fields;
+ return this;
+ }
+
+ public Builder setMessageBody(String messageBody) {
+ this.mMessageBody = messageBody;
+ return this;
+ }
+
+ }
+
+
+ public static final Creator<VisualVoicemailSms> CREATOR =
+ new Creator<VisualVoicemailSms>() {
+ @Override
+ public VisualVoicemailSms createFromParcel(Parcel in) {
+ return new Builder()
+ .setPhoneAccountHandle((PhoneAccountHandle) in.readParcelable(null))
+ .setPrefix(in.readString())
+ .setFields(in.readBundle())
+ .setMessageBody(in.readString())
+ .build();
+ }
+
+ @Override
+ public VisualVoicemailSms[] newArray(int size) {
+ return new VisualVoicemailSms[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeParcelable(getPhoneAccountHandle(), flags);
+ dest.writeString(getPrefix());
+ dest.writeBundle(getFields());
+ dest.writeString(getMessageBody());
+ }
+}
diff --git a/telephony/java/android/telephony/VisualVoicemailSmsFilterSettings.java b/telephony/java/android/telephony/VisualVoicemailSmsFilterSettings.java
index 5b81027..56a8c62 100644
--- a/telephony/java/android/telephony/VisualVoicemailSmsFilterSettings.java
+++ b/telephony/java/android/telephony/VisualVoicemailSmsFilterSettings.java
@@ -15,9 +15,12 @@
*/
package android.telephony;
+import android.content.Context;
import android.os.Parcel;
import android.os.Parcelable;
+import android.telecom.PhoneAccountHandle;
+import android.telephony.VisualVoicemailService.VisualVoicemailTask;
import java.util.Collections;
import java.util.List;
@@ -28,42 +31,44 @@
* <p>[clientPrefix]:[prefix]:([key]=[value];)*
*
* <p>will be regarded as a visual voicemail SMS, and removed before reaching the SMS provider. The
- * intent {@link android.provider.VoicemailContract#ACTION_VOICEMAIL_SMS_RECEIVED} will then be sent
- * to the default dialer with the information extracted from the SMS.
+ * {@link VisualVoicemailService} in the current default dialer will be bound and
+ * {@link VisualVoicemailService#onSmsReceived(VisualVoicemailTask, VisualVoicemailSms)}
+ * will called with the information extracted from the SMS.
*
* <p>Use {@link android.telephony.VisualVoicemailSmsFilterSettings.Builder} to construct this
* class.
*
- * @see android.telephony.TelephonyManager#enableVisualVoicemailSmsFilter
- *
- * @hide
+ * @see VisualVoicemailService#setSmsFilterSettings(Context, PhoneAccountHandle, VisualVoicemailSmsFilterSettings)
*/
-public class VisualVoicemailSmsFilterSettings implements Parcelable {
+public final class VisualVoicemailSmsFilterSettings implements Parcelable {
/**
* The visual voicemail SMS message does not have to be a data SMS, and can be directed to any
* port.
- *
- * @hide
*/
public static final int DESTINATION_PORT_ANY = -1;
/**
* The visual voicemail SMS message can be directed to any port, but must be a data SMS.
- *
- * @hide
*/
public static final int DESTINATION_PORT_DATA_SMS = -2;
+ /**
+ * @hide
+ */
public static final String DEFAULT_CLIENT_PREFIX = "//VVM";
+ /**
+ * @hide
+ */
public static final List<String> DEFAULT_ORIGINATING_NUMBERS = Collections.emptyList();
+ /**
+ * @hide
+ */
public static final int DEFAULT_DESTINATION_PORT = DESTINATION_PORT_ANY;
/**
* Builder class for {@link VisualVoicemailSmsFilterSettings} objects.
- *
- * @hide
*/
public static class Builder {
@@ -171,4 +176,13 @@
dest.writeInt(destinationPort);
}
+ @Override
+ public String toString(){
+ return "[VisualVoicemailSmsFilterSettings "
+ + "clientPrefix=" + clientPrefix
+ + ", originatingNumbers=" + originatingNumbers
+ + ", destinationPort=" + destinationPort
+ + "]";
+ }
+
}
diff --git a/telephony/java/android/telephony/ims/ImsServiceProxy.java b/telephony/java/android/telephony/ims/ImsServiceProxy.java
index 38ea6e6f..a75cd86 100644
--- a/telephony/java/android/telephony/ims/ImsServiceProxy.java
+++ b/telephony/java/android/telephony/ims/ImsServiceProxy.java
@@ -120,7 +120,7 @@
public int startSession(PendingIntent incomingCallIntent, IImsRegistrationListener listener)
throws RemoteException {
synchronized (mLock) {
- checkBinderConnection();
+ checkServiceIsReady();
return getServiceInterface(mBinder).startSession(mSlotId, mSupportedFeature,
incomingCallIntent, listener);
}
@@ -129,7 +129,7 @@
@Override
public void endSession(int sessionId) throws RemoteException {
synchronized (mLock) {
- checkBinderConnection();
+ checkServiceIsReady();
getServiceInterface(mBinder).endSession(mSlotId, mSupportedFeature, sessionId);
}
}
@@ -138,7 +138,7 @@
public boolean isConnected(int callServiceType, int callType)
throws RemoteException {
synchronized (mLock) {
- checkBinderConnection();
+ checkServiceIsReady();
return getServiceInterface(mBinder).isConnected(mSlotId, mSupportedFeature,
callServiceType, callType);
}
@@ -147,7 +147,7 @@
@Override
public boolean isOpened() throws RemoteException {
synchronized (mLock) {
- checkBinderConnection();
+ checkServiceIsReady();
return getServiceInterface(mBinder).isOpened(mSlotId, mSupportedFeature);
}
}
@@ -156,7 +156,7 @@
public void addRegistrationListener(IImsRegistrationListener listener)
throws RemoteException {
synchronized (mLock) {
- checkBinderConnection();
+ checkServiceIsReady();
getServiceInterface(mBinder).addRegistrationListener(mSlotId, mSupportedFeature,
listener);
}
@@ -166,7 +166,7 @@
public void removeRegistrationListener(IImsRegistrationListener listener)
throws RemoteException {
synchronized (mLock) {
- checkBinderConnection();
+ checkServiceIsReady();
getServiceInterface(mBinder).removeRegistrationListener(mSlotId, mSupportedFeature,
listener);
}
@@ -176,7 +176,7 @@
public ImsCallProfile createCallProfile(int sessionId, int callServiceType, int callType)
throws RemoteException {
synchronized (mLock) {
- checkBinderConnection();
+ checkServiceIsReady();
return getServiceInterface(mBinder).createCallProfile(mSlotId, mSupportedFeature,
sessionId, callServiceType, callType);
}
@@ -186,7 +186,7 @@
public IImsCallSession createCallSession(int sessionId, ImsCallProfile profile,
IImsCallSessionListener listener) throws RemoteException {
synchronized (mLock) {
- checkBinderConnection();
+ checkServiceIsReady();
return getServiceInterface(mBinder).createCallSession(mSlotId, mSupportedFeature,
sessionId, profile, listener);
}
@@ -196,7 +196,7 @@
public IImsCallSession getPendingCallSession(int sessionId, String callId)
throws RemoteException {
synchronized (mLock) {
- checkBinderConnection();
+ checkServiceIsReady();
return getServiceInterface(mBinder).getPendingCallSession(mSlotId, mSupportedFeature,
sessionId, callId);
}
@@ -205,7 +205,7 @@
@Override
public IImsUt getUtInterface() throws RemoteException {
synchronized (mLock) {
- checkBinderConnection();
+ checkServiceIsReady();
return getServiceInterface(mBinder).getUtInterface(mSlotId, mSupportedFeature);
}
}
@@ -213,7 +213,7 @@
@Override
public IImsConfig getConfigInterface() throws RemoteException {
synchronized (mLock) {
- checkBinderConnection();
+ checkServiceIsReady();
return getServiceInterface(mBinder).getConfigInterface(mSlotId, mSupportedFeature);
}
}
@@ -221,7 +221,7 @@
@Override
public void turnOnIms() throws RemoteException {
synchronized (mLock) {
- checkBinderConnection();
+ checkServiceIsReady();
getServiceInterface(mBinder).turnOnIms(mSlotId, mSupportedFeature);
}
}
@@ -229,7 +229,7 @@
@Override
public void turnOffIms() throws RemoteException {
synchronized (mLock) {
- checkBinderConnection();
+ checkServiceIsReady();
getServiceInterface(mBinder).turnOffIms(mSlotId, mSupportedFeature);
}
}
@@ -237,7 +237,7 @@
@Override
public IImsEcbm getEcbmInterface() throws RemoteException {
synchronized (mLock) {
- checkBinderConnection();
+ checkServiceIsReady();
return getServiceInterface(mBinder).getEcbmInterface(mSlotId, mSupportedFeature);
}
}
@@ -246,7 +246,7 @@
public void setUiTTYMode(int uiTtyMode, Message onComplete)
throws RemoteException {
synchronized (mLock) {
- checkBinderConnection();
+ checkServiceIsReady();
getServiceInterface(mBinder).setUiTTYMode(mSlotId, mSupportedFeature, uiTtyMode,
onComplete);
}
@@ -255,7 +255,7 @@
@Override
public IImsMultiEndpoint getMultiEndpointInterface() throws RemoteException {
synchronized (mLock) {
- checkBinderConnection();
+ checkServiceIsReady();
return getServiceInterface(mBinder).getMultiEndpointInterface(mSlotId,
mSupportedFeature);
}
@@ -264,7 +264,8 @@
@Override
public int getFeatureStatus() {
synchronized (mLock) {
- if (mFeatureStatusCached != null) {
+ if (isBinderAlive() && mFeatureStatusCached != null) {
+ Log.i(LOG_TAG, "getFeatureStatus - returning cached: " + mFeatureStatusCached);
return mFeatureStatusCached;
}
}
@@ -277,6 +278,7 @@
// Cache only non-null value for feature status.
mFeatureStatusCached = status;
}
+ Log.i(LOG_TAG, "getFeatureStatus - returning " + status);
return status;
}
@@ -301,10 +303,28 @@
mStatusCallback = c;
}
+ /**
+ * @return Returns true if the ImsService is ready to take commands, false otherwise. If this
+ * method returns false, it doesn't mean that the Binder connection is not available (use
+ * {@link #isBinderReady()} to check that), but that the ImsService is not accepting commands
+ * at this time.
+ *
+ * For example, for DSDS devices, only one slot can be {@link ImsFeature#STATE_READY} to take
+ * commands at a time, so the other slot must stay at {@link ImsFeature#STATE_NOT_AVAILABLE}.
+ */
+ public boolean isBinderReady() {
+ return isBinderAlive() && getFeatureStatus() == ImsFeature.STATE_READY;
+ }
+
@Override
public boolean isBinderAlive() {
- return mIsAvailable && getFeatureStatus() == ImsFeature.STATE_READY && mBinder != null &&
- mBinder.isBinderAlive();
+ return mIsAvailable && mBinder != null && mBinder.isBinderAlive();
+ }
+
+ protected void checkServiceIsReady() throws RemoteException {
+ if (!isBinderReady()) {
+ throw new RemoteException("ImsServiceProxy is not ready to accept commands.");
+ }
}
private IImsServiceController getServiceInterface(IBinder b) {
diff --git a/telephony/java/android/telephony/ims/feature/ImsFeature.java b/telephony/java/android/telephony/ims/feature/ImsFeature.java
index 988dd58..395f1cc 100644
--- a/telephony/java/android/telephony/ims/feature/ImsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/ImsFeature.java
@@ -150,7 +150,7 @@
private void notifyFeatureState(@ImsState int state) {
if (mStatusCallback != null) {
try {
- Log.i(LOG_TAG, "notifying ImsFeatureState");
+ Log.i(LOG_TAG, "notifying ImsFeatureState=" + state);
mStatusCallback.notifyImsFeatureStatus(state);
} catch (RemoteException e) {
mStatusCallback = null;
diff --git a/telephony/java/android/telephony/mbms/DownloadCallback.java b/telephony/java/android/telephony/mbms/DownloadCallback.java
new file mode 100644
index 0000000..0c6fec4
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/DownloadCallback.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2016 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.telephony.mbms;
+
+/**
+ * A optional listener class used by download clients to track progress.
+ * @hide
+ */
+public class DownloadCallback extends IDownloadCallback.Stub {
+ /**
+ * Gives process callbacks for a given DownloadRequest.
+ * request indicates which download is being referenced.
+ * fileInfo gives information about the file being downloaded. Note that
+ * the request may result in many files being downloaded and the client
+ * may not have been able to get a list of them in advance.
+ * downloadSize is the final amount to be downloaded. This may be different
+ * from the decoded final size, but is useful in gauging download progress.
+ * currentSize is the amount currently downloaded.
+ * decodedPercent is the percent from 0 to 100 of the file decoded. After the
+ * download completes the contents needs to be processed. It is perhaps
+ * uncompressed, transcoded and/or decrypted. Generally the download completes
+ * before the decode is started, but that's not required.
+ */
+ public void progress(DownloadRequest request, FileInfo fileInfo,
+ int downloadSize, int currentSize, int decodedPercent) {
+ }
+}
diff --git a/telephony/java/android/telephony/mbms/DownloadRequest.aidl b/telephony/java/android/telephony/mbms/DownloadRequest.aidl
new file mode 100755
index 0000000..ece577d
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/DownloadRequest.aidl
@@ -0,0 +1,19 @@
+/*
+** Copyright 2017, 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.telephony.mbms;
+
+parcelable DownloadRequest;
diff --git a/telephony/java/android/telephony/mbms/DownloadRequest.java b/telephony/java/android/telephony/mbms/DownloadRequest.java
new file mode 100644
index 0000000..dbaf10bb
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/DownloadRequest.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2017 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.telephony.mbms;
+
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.net.URISyntaxException;
+
+/**
+ * A Parcelable class describing a pending Cell-Broadcast download request
+ * @hide
+ */
+public class DownloadRequest implements Parcelable {
+ /** @hide */
+ public static class Builder {
+ private int id;
+ private FileServiceInfo serviceInfo;
+ private Uri source;
+ private Uri dest;
+ private int sub;
+ private String appIntent;
+
+ public Builder setId(int id) {
+ this.id = id;
+ return this;
+ }
+
+ public Builder setServiceInfo(FileServiceInfo serviceInfo) {
+ this.serviceInfo = serviceInfo;
+ return this;
+ }
+
+ public Builder setSource(Uri source) {
+ this.source = source;
+ return this;
+ }
+
+ public Builder setDest(Uri dest) {
+ this.dest = dest;
+ return this;
+ }
+
+ public Builder setSub(int sub) {
+ this.sub = sub;
+ return this;
+ }
+
+ public Builder setAppIntent(Intent intent) {
+ this.appIntent = intent.toUri(0);
+ return this;
+ }
+
+ public DownloadRequest build() {
+ return new DownloadRequest(id, serviceInfo, source, dest, sub, appIntent);
+ }
+ }
+
+ private final int downloadId;
+ private final FileServiceInfo fileServiceInfo;
+ private final Uri sourceUri;
+ private final Uri destinationUri;
+ private final int subId;
+ private final String serializedResultIntentForApp;
+
+ private DownloadRequest(int id, FileServiceInfo serviceInfo,
+ Uri source, Uri dest,
+ int sub, String appIntent) {
+ downloadId = id;
+ fileServiceInfo = serviceInfo;
+ sourceUri = source;
+ destinationUri = dest;
+ subId = sub;
+ serializedResultIntentForApp = appIntent;
+ }
+
+ public static DownloadRequest copy(DownloadRequest other) {
+ return new DownloadRequest(other);
+ }
+
+ private DownloadRequest(DownloadRequest dr) {
+ downloadId = dr.downloadId;
+ fileServiceInfo = dr.fileServiceInfo;
+ sourceUri = dr.sourceUri;
+ destinationUri = dr.destinationUri;
+ subId = dr.subId;
+ serializedResultIntentForApp = dr.serializedResultIntentForApp;
+ }
+
+ private DownloadRequest(Parcel in) {
+ downloadId = in.readInt();
+ fileServiceInfo = in.readParcelable(getClass().getClassLoader());
+ sourceUri = in.readParcelable(getClass().getClassLoader());
+ destinationUri = in.readParcelable(getClass().getClassLoader());
+ subId = in.readInt();
+ serializedResultIntentForApp = in.readString();
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeInt(downloadId);
+ out.writeParcelable(fileServiceInfo, flags);
+ out.writeParcelable(sourceUri, flags);
+ out.writeParcelable(destinationUri, flags);
+ out.writeInt(subId);
+ out.writeString(serializedResultIntentForApp);
+ }
+
+ public int getDownloadId() {
+ return downloadId;
+ }
+
+ public FileServiceInfo getFileServiceInfo() {
+ return fileServiceInfo;
+ }
+
+ public Uri getSourceUri() {
+ return sourceUri;
+ }
+
+ public Uri getDestinationUri() {
+ return destinationUri;
+ }
+
+ public int getSubId() {
+ return subId;
+ }
+
+ public Intent getIntentForApp() {
+ try {
+ return Intent.parseUri(serializedResultIntentForApp, 0);
+ } catch (URISyntaxException e) {
+ return null;
+ }
+ }
+
+ public static final Parcelable.Creator<DownloadRequest> CREATOR =
+ new Parcelable.Creator<DownloadRequest>() {
+ public DownloadRequest createFromParcel(Parcel in) {
+ return new DownloadRequest(in);
+ }
+ public DownloadRequest[] newArray(int size) {
+ return new DownloadRequest[size];
+ }
+ };
+
+}
diff --git a/telephony/java/android/telephony/mbms/DownloadStatus.aidl b/telephony/java/android/telephony/mbms/DownloadStatus.aidl
new file mode 100755
index 0000000..e7cfd39
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/DownloadStatus.aidl
@@ -0,0 +1,19 @@
+/*
+** Copyright 2017, 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.telephony.mbms;
+
+parcelable DownloadStatus;
diff --git a/telephony/java/android/telephony/mbms/DownloadStatus.java b/telephony/java/android/telephony/mbms/DownloadStatus.java
new file mode 100644
index 0000000..90eb53f
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/DownloadStatus.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2017 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.telephony.mbms;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * A Parcelable class describing the status of a Cell-Broadcast download request
+ * @hide
+ */
+public class DownloadStatus implements Parcelable {
+ // includes downloads and active repair work
+ public final int activelyDownloading;
+
+ // files scheduled for future broadcast
+ public final int pendingDownloads;
+
+ // files scheduled for future repairs
+ public final int pendingRepairs;
+
+ // is a future download window scheduled with unknown
+ // number of files
+ public final boolean windowPending;
+
+ public DownloadStatus(int downloading, int downloads, int repairs, boolean window) {
+ activelyDownloading = downloading;
+ pendingDownloads = downloads;
+ pendingRepairs = repairs;
+ windowPending = window;
+ }
+
+ public static final Parcelable.Creator<DownloadStatus> CREATOR =
+ new Parcelable.Creator<DownloadStatus>() {
+ @Override
+ public DownloadStatus createFromParcel(Parcel in) {
+ return new DownloadStatus(in);
+ }
+
+ @Override
+ public DownloadStatus[] newArray(int size) {
+ return new DownloadStatus[size];
+ }
+ };
+
+ DownloadStatus(Parcel in) {
+ activelyDownloading = in.readInt();
+ pendingDownloads = in.readInt();
+ pendingRepairs = in.readInt();
+ windowPending = (in.readInt() == 1);
+ }
+
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(activelyDownloading);
+ dest.writeInt(pendingDownloads);
+ dest.writeInt(pendingRepairs);
+ dest.writeInt((windowPending ? 1 : 0));
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+}
diff --git a/telephony/java/android/telephony/mbms/FileInfo.aidl b/telephony/java/android/telephony/mbms/FileInfo.aidl
new file mode 100755
index 0000000..62926e1
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/FileInfo.aidl
@@ -0,0 +1,20 @@
+/*
+**
+** Copyright 2016, 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.telephony.mbms;
+
+parcelable FileInfo;
diff --git a/telephony/java/android/telephony/mbms/FileInfo.java b/telephony/java/android/telephony/mbms/FileInfo.java
new file mode 100644
index 0000000..d3888bd
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/FileInfo.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2016 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.telephony.mbms;
+
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * A Parcelable class Cell-Broadcast downloadable file information.
+ * @hide
+ */
+public class FileInfo implements Parcelable {
+
+ /**
+ * The URI into the carriers infrastructure which points to this file.
+ * This is used internally but is also one of the few pieces of data about the content that is
+ * exposed and may be needed for disambiguation by the application.
+ */
+ final Uri uri;
+
+ /**
+ * The mime type of the content.
+ */
+ final String mimeType;
+
+ /**
+ * The size of the file in bytes.
+ */
+ final long size;
+
+ /**
+ * The MD5 hash of the file.
+ */
+ final byte md5Hash[];
+
+ /**
+ * Gets the parent service for this file.
+ */
+ public FileServiceInfo getFileServiceInfo() {
+ return null;
+ }
+
+ public static final Parcelable.Creator<FileInfo> CREATOR =
+ new Parcelable.Creator<FileInfo>() {
+ @Override
+ public FileInfo createFromParcel(Parcel source) {
+ return new FileInfo(source);
+ }
+
+ @Override
+ public FileInfo[] newArray(int size) {
+ return new FileInfo[size];
+ }
+ };
+
+ private FileInfo(Parcel in) {
+ uri = in.readParcelable(null);
+ mimeType = in.readString();
+ size = in.readLong();
+ int arraySize = in.readInt();
+ md5Hash = new byte[arraySize];
+ in.readByteArray(md5Hash);
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeParcelable(uri, flags);
+ dest.writeString(mimeType);
+ dest.writeLong(size);
+ dest.writeInt(md5Hash.length);
+ dest.writeByteArray(md5Hash);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+}
diff --git a/telephony/java/android/telephony/mbms/FileServiceInfo.aidl b/telephony/java/android/telephony/mbms/FileServiceInfo.aidl
new file mode 100755
index 0000000..4646bad
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/FileServiceInfo.aidl
@@ -0,0 +1,20 @@
+/*
+**
+** Copyright 2016, 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.telephony.mbms;
+
+parcelable FileServiceInfo;
diff --git a/telephony/java/android/telephony/mbms/FileServiceInfo.java b/telephony/java/android/telephony/mbms/FileServiceInfo.java
new file mode 100644
index 0000000..8bda370
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/FileServiceInfo.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2016 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.telephony.mbms;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * A Parcelable class Cell-Broadcast downloadable file information.
+ * @hide
+ */
+public class FileServiceInfo extends ServiceInfo implements Parcelable {
+ public List<FileInfo> files;
+
+ public FileServiceInfo(Map<Locale, String> newNames, String newClassName, Locale newLocale,
+ String newServiceId, Date start, Date end, List<FileInfo> newFiles) {
+ super(newNames, newClassName, newLocale, newServiceId, start, end);
+ files = new ArrayList(newFiles);
+ }
+
+ public static final Parcelable.Creator<FileServiceInfo> CREATOR =
+ new Parcelable.Creator<FileServiceInfo>() {
+ @Override
+ public FileServiceInfo createFromParcel(Parcel source) {
+ return new FileServiceInfo(source);
+ }
+
+ @Override
+ public FileServiceInfo[] newArray(int size) {
+ return new FileServiceInfo[size];
+ }
+ };
+
+ FileServiceInfo(Parcel in) {
+ super(in);
+ files = new ArrayList<FileInfo>();
+ in.readList(files, null);
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
+ dest.writeList(files);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+}
diff --git a/telephony/java/android/telephony/mbms/IDownloadCallback.aidl b/telephony/java/android/telephony/mbms/IDownloadCallback.aidl
new file mode 100755
index 0000000..a6bd7e5
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/IDownloadCallback.aidl
@@ -0,0 +1,34 @@
+/*
+** Copyright 2017, 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.telephony.mbms;
+
+import android.telephony.mbms.DownloadRequest;
+import android.telephony.mbms.FileInfo;
+
+/**
+ * The optional interface used by download clients to track progress.
+ * @hide
+ */
+interface IDownloadCallback
+{
+ /**
+ * Gives progress callbacks for a given DownloadRequest. Includes a FileInfo
+ * as the list of files may not have been known at request-time.
+ */
+ void progress(in DownloadRequest request, in FileInfo fileInfo, int downloadSize,
+ int currentSize, int decodedPercent);
+}
diff --git a/telephony/java/android/telephony/mbms/IMbmsDownloadManagerCallback.aidl b/telephony/java/android/telephony/mbms/IMbmsDownloadManagerCallback.aidl
new file mode 100755
index 0000000..03227d0
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/IMbmsDownloadManagerCallback.aidl
@@ -0,0 +1,42 @@
+/*
+** Copyright 2017, 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.telephony.mbms;
+
+import android.telephony.mbms.FileServiceInfo;
+
+import java.util.List;
+
+/**
+ * The interface the clients top-level file download listener will satisfy.
+ * @hide
+ */
+interface IMbmsDownloadManagerCallback
+{
+ void error(int errorCode, String message);
+
+ /**
+ * Called to indicate published File Services have changed.
+ *
+ * This will only be called after the application has requested
+ * a list of file services and specified a service class list
+ * of interest AND the results of a subsequent getFileServices
+ * call with the same service class list would
+ * return different
+ * results.
+ */
+ void fileServicesUpdated(in List<FileServiceInfo> services);
+}
diff --git a/telephony/java/android/telephony/mbms/IMbmsStreamingManagerCallback.aidl b/telephony/java/android/telephony/mbms/IMbmsStreamingManagerCallback.aidl
new file mode 100755
index 0000000..cbf0fca
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/IMbmsStreamingManagerCallback.aidl
@@ -0,0 +1,53 @@
+/*
+** Copyright 2017, 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.telephony.mbms;
+
+import android.telephony.mbms.StreamingServiceInfo;
+
+import java.util.List;
+
+/**
+ * The interface the clients top-level streaming listener will satisfy.
+ * @hide
+ */
+interface IMbmsStreamingManagerCallback
+{
+ void error(int errorCode, String message);
+
+ /**
+ * Called to indicate published Streaming Services have changed.
+ *
+ * This will only be called after the application has requested
+ * a list of streaming services and specified a service class list
+ * of interest AND the results of a subsequent getStreamServices
+ * call with the same service class list would
+ * return different
+ * results.
+ */
+ void streamingServicesUpdated(in List<StreamingServiceInfo> services);
+
+ /**
+ * Called to indicate the active Streaming Services have changed.
+ *
+ * This will be caused whenever a new service starts streaming or whenever
+ * MbmsStreamServiceManager.getActiveStreamingServices is called.
+ *
+ * @param services a list of StreamingServiceInfos. May be empty if
+ * there are no active StreamingServices
+ */
+ void activeStreamingServicesUpdated(in List<StreamingServiceInfo> services);
+}
diff --git a/core/java/android/bluetooth/le/IAdvertiserCallback.aidl b/telephony/java/android/telephony/mbms/IStreamingServiceCallback.aidl
old mode 100644
new mode 100755
similarity index 60%
rename from core/java/android/bluetooth/le/IAdvertiserCallback.aidl
rename to telephony/java/android/telephony/mbms/IStreamingServiceCallback.aidl
index c58b1df..7b4ecf2
--- a/core/java/android/bluetooth/le/IAdvertiserCallback.aidl
+++ b/telephony/java/android/telephony/mbms/IStreamingServiceCallback.aidl
@@ -13,17 +13,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.bluetooth.le;
-import android.bluetooth.le.AdvertiseSettings;
+package android.telephony.mbms;
+
+import android.net.Uri;
+import android.telephony.SignalStrength;
+import android.telephony.mbms.StreamingService;
/**
- * Callback definitions for interacting with Advertiser
* @hide
*/
-oneway interface IAdvertiserCallback {
- void onAdvertiserRegistered(in int status, in int advertiserId);
-
- void onMultiAdvertiseCallback(in int status, boolean isStart,
- in AdvertiseSettings advertiseSettings);
+oneway interface IStreamingServiceCallback {
+ void error(int errorCode, String message);
+ void streamStateChanged(in StreamingService service, int state);
+ void uriUpdated(in Uri uri);
+ void signalStrengthUpdated(in SignalStrength signalStrength);
}
diff --git a/telephony/java/android/telephony/mbms/MbmsDownloadManagerCallback.java b/telephony/java/android/telephony/mbms/MbmsDownloadManagerCallback.java
new file mode 100644
index 0000000..16fafe4
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/MbmsDownloadManagerCallback.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2016 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.telephony.mbms;
+
+import java.util.List;
+
+/**
+ * A Parcelable class with Cell-Broadcast service information.
+ * @hide
+ */
+public class MbmsDownloadManagerCallback extends IMbmsDownloadManagerCallback.Stub {
+
+ public final static int ERROR_CARRIER_NOT_SUPPORTED = 1;
+ public final static int ERROR_UNABLE_TO_INITIALIZE = 2;
+ public final static int ERROR_UNABLE_TO_ALLOCATE_MEMORY = 3;
+
+
+ public void error(int errorCode, String message) {
+ // default implementation empty
+ }
+
+ /**
+ * Called to indicate published File Services have changed.
+ *
+ * This will only be called after the application has requested
+ * a list of file services and specified a service class list
+ * of interest AND the results of a subsequent getFileServices
+ * call with the same service class list would return different
+ * results.
+ *
+ * @param services a List of FileServiceInfos
+ *
+ */
+ public void fileServicesUpdated(List<FileServiceInfo> services) {
+ // default implementation empty
+ }
+}
diff --git a/telephony/java/android/telephony/mbms/MbmsInitializationException.java b/telephony/java/android/telephony/mbms/MbmsInitializationException.java
new file mode 100644
index 0000000..1612bc9
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/MbmsInitializationException.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2017 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.telephony.mbms;
+
+/** @hide */
+public class MbmsInitializationException extends Exception {
+ private final int mErrorCode;
+
+ /** @hide */
+ public MbmsInitializationException(int errorCode) {
+ super();
+ mErrorCode = errorCode;
+ }
+
+ public int getErrorCode() {
+ return mErrorCode;
+ }
+}
diff --git a/telephony/java/android/telephony/mbms/MbmsStreamingManagerCallback.java b/telephony/java/android/telephony/mbms/MbmsStreamingManagerCallback.java
new file mode 100644
index 0000000..b3bc814
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/MbmsStreamingManagerCallback.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2016 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.telephony.mbms;
+
+import java.util.List;
+
+/**
+ * A Parcelable class with Cell-Broadcast service information.
+ * @hide
+ */
+public class MbmsStreamingManagerCallback extends IMbmsStreamingManagerCallback.Stub {
+
+ public final static int ERROR_CARRIER_NOT_SUPPORTED = 1;
+ public final static int ERROR_UNABLE_TO_INITIALIZE = 2;
+ public final static int ERROR_UNABLE_TO_ALLOCATE_MEMORY = 3;
+
+
+ public void error(int errorCode, String message) {
+ // default implementation empty
+ }
+
+ /**
+ * Called to indicate published Streaming Services have changed.
+ *
+ * This will only be called after the application has requested
+ * a list of streaming services and specified a service class list
+ * of interest AND the results of a subsequent getStreamServices
+ * call with the same service class list would return different
+ * results.
+ *
+ * @param services a List of StreamingServiceInfos
+ *
+ */
+ public void streamingServicesUpdated(List<StreamingServiceInfo> services) {
+ // default implementation empty
+ }
+
+ /**
+ * Called to indicate the active Streaming Services have changed.
+ *
+ * This will be caused whenever a new service starts streaming or whenever
+ * MbmsStreamServiceManager.getActiveStreamingServices is called.
+ *
+ * @param services a list of StreamingServiceInfos. May be empty if
+ * there are no active StreamingServices
+ */
+ public void activeStreamingServicesUpdated(List<StreamingServiceInfo> services) {
+ // default implementation empty
+ }
+}
diff --git a/telephony/java/android/telephony/mbms/ServiceInfo.aidl b/telephony/java/android/telephony/mbms/ServiceInfo.aidl
new file mode 100755
index 0000000..6661c26
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/ServiceInfo.aidl
@@ -0,0 +1,20 @@
+/*
+**
+** Copyright 2016, 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.telephony.mbms;
+
+parcelable ServiceInfo;
diff --git a/telephony/java/android/telephony/mbms/ServiceInfo.java b/telephony/java/android/telephony/mbms/ServiceInfo.java
new file mode 100644
index 0000000..cd2e46c
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/ServiceInfo.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2016 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.telephony.mbms;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * A Parcelable class with Cell-Broadcast service information.
+ * @hide
+ */
+public class ServiceInfo implements Parcelable {
+ // arbitrary limit on the number of locale -> name pairs we support
+ final static int MAP_LIMIT = 50;
+ /**
+ * User displayable names listed by language. Unmodifiable.
+ */
+ final Map<Locale, String> names;
+
+ /**
+ * The class name for this service - used to catagorize and filter
+ */
+ final String className;
+
+ /**
+ * The language for this service content
+ */
+ final Locale locale;
+
+ /**
+ * The carrier's identifier for the service.
+ */
+ final String serviceId;
+
+ /**
+ * The start time indicating when this service will be available.
+ */
+ final Date sessionStartTime;
+
+ /**
+ * The end time indicating when this sesion stops being available.
+ */
+ final Date sessionEndTime;
+
+
+ public ServiceInfo(Map<Locale, String> newNames, String newClassName, Locale newLocale,
+ String newServiceId, Date start, Date end) {
+ if (newNames == null || newNames.isEmpty() || TextUtils.isEmpty(newClassName)
+ || newLocale == null || TextUtils.isEmpty(newServiceId)
+ || start == null || end == null) {
+ throw new IllegalArgumentException("Bad ServiceInfo construction");
+ }
+ if (newNames.size() > MAP_LIMIT) {
+ throw new RuntimeException("bad map length" + newNames.size());
+ }
+ names = new HashMap(newNames.size());
+ names.putAll(newNames);
+ className = newClassName;
+ locale = (Locale)newLocale.clone();
+ serviceId = newServiceId;
+ sessionStartTime = (Date)start.clone();
+ sessionEndTime = (Date)end.clone();
+ }
+
+ public static final Parcelable.Creator<FileServiceInfo> CREATOR =
+ new Parcelable.Creator<FileServiceInfo>() {
+ @Override
+ public FileServiceInfo createFromParcel(Parcel source) {
+ return new FileServiceInfo(source);
+ }
+
+ @Override
+ public FileServiceInfo[] newArray(int size) {
+ return new FileServiceInfo[size];
+ }
+ };
+
+ ServiceInfo(Parcel in) {
+ int mapCount = in.readInt();
+ if (mapCount > MAP_LIMIT || mapCount < 0) {
+ throw new RuntimeException("bad map length" + mapCount);
+ }
+ names = new HashMap(mapCount);
+ while (mapCount-- > 0) {
+ Locale locale = (java.util.Locale) in.readSerializable();
+ String name = in.readString();
+ names.put(locale, name);
+ }
+ className = in.readString();
+ locale = (java.util.Locale) in.readSerializable();
+ serviceId = in.readString();
+ sessionStartTime = (java.util.Date) in.readSerializable();
+ sessionEndTime = (java.util.Date) in.readSerializable();
+ }
+
+ public void writeToParcel(Parcel dest, int flags) {
+ Set<Locale> keySet = names.keySet();
+ dest.writeInt(keySet.size());
+ for (Locale l : keySet) {
+ dest.writeSerializable(l);
+ dest.writeString(names.get(l));
+ }
+ dest.writeString(className);
+ dest.writeSerializable(locale);
+ dest.writeString(serviceId);
+ dest.writeSerializable(sessionStartTime);
+ dest.writeSerializable(sessionEndTime);
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+}
diff --git a/telephony/java/android/telephony/mbms/StreamingService.aidl b/telephony/java/android/telephony/mbms/StreamingService.aidl
new file mode 100755
index 0000000..0c286f3
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/StreamingService.aidl
@@ -0,0 +1,19 @@
+/*
+** Copyright 2017, 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.telephony.mbms;
+
+parcelable StreamingService;
diff --git a/telephony/java/android/telephony/mbms/StreamingService.java b/telephony/java/android/telephony/mbms/StreamingService.java
new file mode 100644
index 0000000..8cc6043
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/StreamingService.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2016 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.telephony.mbms;
+
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.telephony.SignalStrength;
+
+/**
+ * @hide
+ */
+public class StreamingService {
+
+ public final static int STATE_STOPPED = 1;
+ public final static int STATE_STARTED = 2;
+ public final static int STATE_STALLED = 3;
+
+ /**
+ */
+ StreamingService(StreamingServiceInfo streamingServiceInfo,
+ IStreamingServiceCallback listener) {
+ }
+
+ /**
+ * Retreive the Uri used to play this stream.
+ *
+ * This may throw a RemoteException.
+ */
+ public Uri getPlaybackUri() {
+ return null;
+ }
+
+ /**
+ * Retreive the info for this StreamingService.
+ */
+ public StreamingServiceInfo getInfo() {
+ return null;
+ }
+
+ /**
+ * Retreive the current state of this stream.
+ *
+ * This may throw a RemoteException.
+ */
+ public int getState() {
+ return STATE_STOPPED;
+ }
+
+ /**
+ * Stop streaming this service. Terminal.
+ *
+ * This may throw a RemoteException.
+ */
+ public void stopStreaming() {
+ }
+
+ /**
+ * Switch this stream to a different service. Used for smooth transitions.
+ *
+ * This may throw a RemoteException.
+ *
+ * Asynchronous errors through the listener include any of the errors except
+ * <li>ERROR_MSDC_UNABLE_TO_INITIALIZE</li>
+ */
+ public void switchStream(StreamingServiceInfo streamingServiceInfo) {
+ }
+
+ public void dispose() {
+ }
+
+ public static final Parcelable.Creator<StreamingService> CREATOR =
+ new Parcelable.Creator<StreamingService>() {
+ @Override
+ public StreamingService createFromParcel(Parcel in) {
+ return new StreamingService(in);
+ }
+
+ @Override
+ public StreamingService[] newArray(int size) {
+ return new StreamingService[size];
+ }
+ };
+
+ private StreamingService(Parcel in) {
+ }
+
+ public void writeToParcel(Parcel dest, int flags) {
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+}
+
diff --git a/telephony/java/android/telephony/mbms/StreamingServiceCallback.java b/telephony/java/android/telephony/mbms/StreamingServiceCallback.java
new file mode 100644
index 0000000..7f5c486
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/StreamingServiceCallback.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2016 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.telephony.mbms;
+
+import android.net.Uri;
+import android.telephony.SignalStrength;
+
+/**
+ * A Callback class for use when the applicaiton is actively streaming content.
+ * @hide
+ */
+public class StreamingServiceCallback extends IStreamingServiceCallback.Stub {
+
+
+ public void error(int errorCode, String message) {
+ // default implementation empty
+ }
+
+ /**
+ * Called to indicate this stream has changed state.
+ *
+ * See {@link StreamingService#STATE_STOPPED}, {@link StreamingService#STATE_STARTED}
+ * and {@link StreamingService#STATE_STALLED}.
+ */
+ public void streamStateChanged(StreamingService service, int state) {
+ // default implementation empty
+ }
+
+ /**
+ * Called to indicate published Download Services have changed.
+ *
+ * This may be called when a looping stream hits the end or
+ * when the a new URI should be used to correct for time drift.
+ */
+ public void uriUpdated(Uri uri) {
+ // default implementation empty
+ }
+
+ /**
+ * Signal Strength updated.
+ *
+ * This signal strength is the BROADCAST signal strength which,
+ * depending on technology in play and it's deployment, may be
+ * stronger or weaker than the traditional UNICAST signal
+ * strength.
+ *
+ * A {@link android.telephony.SignalStrength#getLevel} result of 0 means
+ * you don't have coverage for this stream, either due to geographic
+ * restrictions, poor tower coverage or something (yards of concrete?)
+ * interferring with the signal.
+ */
+ public void signalStrengthUpdated(SignalStrength signalStrength) {
+ // default implementation empty
+ }
+}
diff --git a/telephony/java/android/telephony/mbms/StreamingServiceInfo.aidl b/telephony/java/android/telephony/mbms/StreamingServiceInfo.aidl
new file mode 100755
index 0000000..b902f27
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/StreamingServiceInfo.aidl
@@ -0,0 +1,20 @@
+/*
+**
+** Copyright 2016, 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.telephony.mbms;
+
+parcelable StreamingServiceInfo;
diff --git a/telephony/java/android/telephony/mbms/StreamingServiceInfo.java b/telephony/java/android/telephony/mbms/StreamingServiceInfo.java
new file mode 100644
index 0000000..f559585
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/StreamingServiceInfo.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2016 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.telephony.mbms;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Date;
+import java.util.Locale;
+import java.util.Map;
+
+/**
+ * A Parcelable class Cell-Broadcast media stream information.
+ * This may not have any more info than ServiceInfo, but kept for completeness.
+ * @hide
+ */
+public class StreamingServiceInfo extends ServiceInfo implements Parcelable {
+
+ public StreamingServiceInfo(Map<Locale, String> newNames, String newClassName,
+ Locale newLocale, String newServiceId, Date start, Date end) {
+ super(newNames, newClassName, newLocale, newServiceId, start, end);
+ }
+
+ public static final Parcelable.Creator<StreamingServiceInfo> CREATOR =
+ new Parcelable.Creator<StreamingServiceInfo>() {
+ @Override
+ public StreamingServiceInfo createFromParcel(Parcel source) {
+ return new StreamingServiceInfo(source);
+ }
+
+ @Override
+ public StreamingServiceInfo[] newArray(int size) {
+ return new StreamingServiceInfo[size];
+ }
+ };
+
+ StreamingServiceInfo(Parcel in) {
+ super(in);
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+}
diff --git a/telephony/java/android/telephony/mbms/UriPathPair.aidl b/telephony/java/android/telephony/mbms/UriPathPair.aidl
new file mode 100755
index 0000000..8bf76824
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/UriPathPair.aidl
@@ -0,0 +1,20 @@
+/*
+**
+** Copyright 2016, 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.telephony.mbms;
+
+parcelable UriPathPair;
diff --git a/telephony/java/android/telephony/mbms/UriPathPair.java b/telephony/java/android/telephony/mbms/UriPathPair.java
new file mode 100644
index 0000000..7acc270
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/UriPathPair.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2017 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.telephony.mbms;
+
+import android.content.ContentResolver;
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/** @hide */
+public class UriPathPair implements Parcelable {
+ private final Uri mFilePathUri;
+ private final Uri mContentUri;
+
+ /** @hide */
+ public UriPathPair(Uri fileUri, Uri contentUri) {
+ if (fileUri == null || !ContentResolver.SCHEME_FILE.equals(fileUri.getScheme())) {
+ throw new IllegalArgumentException("File URI must have file scheme");
+ }
+ if (contentUri == null || !ContentResolver.SCHEME_CONTENT.equals(contentUri.getScheme())) {
+ throw new IllegalArgumentException("Content URI must have content scheme");
+ }
+
+ mFilePathUri = fileUri;
+ mContentUri = contentUri;
+ }
+
+ /** @hide */
+ protected UriPathPair(Parcel in) {
+ mFilePathUri = in.readParcelable(Uri.class.getClassLoader());
+ mContentUri = in.readParcelable(Uri.class.getClassLoader());
+ }
+
+ public static final Creator<UriPathPair> CREATOR = new Creator<UriPathPair>() {
+ @Override
+ public UriPathPair createFromParcel(Parcel in) {
+ return new UriPathPair(in);
+ }
+
+ @Override
+ public UriPathPair[] newArray(int size) {
+ return new UriPathPair[size];
+ }
+ };
+
+ /** future systemapi */
+ public Uri getFilePathUri() {
+ return mFilePathUri;
+ }
+
+ /** future systemapi */
+ public Uri getContentUri() {
+ return mContentUri;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeParcelable(mFilePathUri, flags);
+ dest.writeParcelable(mContentUri, flags);
+ }
+}
diff --git a/telephony/java/android/telephony/mbms/vendor/IMbmsDownloadService.aidl b/telephony/java/android/telephony/mbms/vendor/IMbmsDownloadService.aidl
new file mode 100755
index 0000000..3090e12
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/vendor/IMbmsDownloadService.aidl
@@ -0,0 +1,73 @@
+/*
+** Copyright 2017, 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.telephony.mbms.vendor;
+
+import android.app.PendingIntent;
+import android.net.Uri;
+import android.telephony.mbms.DownloadRequest;
+import android.telephony.mbms.DownloadStatus;
+import android.telephony.mbms.IMbmsDownloadManagerCallback;
+import android.telephony.mbms.IDownloadCallback;
+
+/**
+ * The interface the opaque MbmsStreamingService will satisfy.
+ * @hide
+ */
+interface IMbmsDownloadService
+{
+ /**
+ * Initialize download service
+ * Registers this listener, subId with this appName
+ *
+ * No return value. Async errors may be reported, but none expected (not doing anything yet).
+ */
+ void initialize(String appName, int subId, IMbmsDownloadManagerCallback listener);
+
+ /**
+ * - Registers serviceClasses of interest with the uid/appName/subId key.
+ * - Starts asynch fetching data on download services of matching classes to be reported
+ * later by callback.
+ *
+ * Note that subsequent calls with the same callback, appName, subId and uid will replace
+ * the service class list.
+ */
+ int getFileServices(String appName, int subId, in List<String> serviceClasses);
+
+ /**
+ * should move the params into a DownloadRequest parcelable
+ */
+ int download(String appName, in DownloadRequest downloadRequest, IDownloadCallback listener);
+
+ List<DownloadRequest> listPendingDownloads(String appName);
+
+ int cancelDownload(String appName, in DownloadRequest downloadRequest);
+
+ DownloadStatus getDownloadStatus(String appName, in DownloadRequest downloadRequest);
+
+ /*
+ * named this for 2 reasons:
+ * 1 don't want 'State' here as it conflicts with 'Status' of the previous function
+ * 2 want to perfect typing 'Knowledge'
+ */
+ void resetDownloadKnowledge(String appName, in DownloadRequest downloadRequest);
+
+ /**
+ * End of life for this MbmsDownloadManager.
+ * Any pending downloads remain in affect and may start up independently in the future.
+ */
+ void dispose(String appName, int subId);
+}
diff --git a/telephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.aidl b/telephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.aidl
new file mode 100755
index 0000000..fbc0931
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/vendor/IMbmsStreamingService.aidl
@@ -0,0 +1,88 @@
+/*
+** Copyright 2017, 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.telephony.mbms.vendor;
+
+import android.net.Uri;
+import android.telephony.mbms.IMbmsStreamingManagerCallback;
+import android.telephony.mbms.IStreamingServiceCallback;
+import android.telephony.mbms.StreamingService;
+import android.telephony.mbms.StreamingServiceInfo;
+import android.telephony.SignalStrength;
+
+/**
+ * The interface the opaque MbmsStreamingService will satisfy.
+ * @hide
+ */
+interface IMbmsStreamingService
+{
+ /**
+ * Initialize streaming service
+ * Registers this listener, subId with this appName
+ *
+ */
+ int initialize(IMbmsStreamingManagerCallback listener, String appName, int subId);
+
+
+ /**
+ * - Registers serviceClasses of interest with the uid/appName/subId key.
+ * - Starts asynch fetching data on streaming services of matching classes to be reported
+ * later by callback.
+ *
+ * Note that subsequent calls with the same callback, appName, subId and uid will replace
+ * the service class list.
+ */
+ int getStreamingServices(String appName, int subId, in List<String> serviceClasses);
+
+ /**
+ * - Starts streaming the serviceId given.
+ * - if the uid/appName/subId don't match a previously registered callback an error will
+ * be returned
+ * - Streaming status will be sent via the included listener, including an initial
+ * URL-change and State-change pair.
+ */
+ StreamingService startStreaming(String appName, int subId, String serviceId,
+ IStreamingServiceCallback listener);
+
+ /**
+ * Asynchronously fetches all Services being streamed by this uid/appName/subId.
+ */
+ int getActiveStreamingServices(String appName, int subId);
+
+
+ /**
+ * Per-stream api. Note each specifies what stream they apply to.
+ */
+
+ Uri getPlaybackUri(String appName, int subId, String serviceId);
+
+ void switchStreams(String appName, int subId, String oldServiceId, String newServiceId);
+
+ int getState(String appName, int subId, String serviceId);
+
+ void stopStreaming(String appName, int subId, String serviceId);
+
+ void disposeStream(String appName, int subId, String serviceId);
+
+
+ /**
+ * End of life for all MbmsStreamingManager's created by this uid/appName/subId.
+ * Ends any streams run under this uid/appname/subId and calls the disposed methods
+ * an callbacks registered for this uid/appName/subId and the disposed methods on any
+ * listeners registered with startStreaming.
+ */
+ void dispose(String appName, int subId);
+}
diff --git a/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java b/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java
new file mode 100644
index 0000000..369aef1
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/vendor/MbmsDownloadServiceBase.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2017 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.telephony.mbms.vendor;
+
+import android.os.RemoteException;
+import android.telephony.mbms.DownloadRequest;
+import android.telephony.mbms.DownloadStatus;
+import android.telephony.mbms.IDownloadCallback;
+import android.telephony.mbms.IMbmsDownloadManagerCallback;
+
+import java.util.List;
+
+/**
+ * Base class for MbmsDownloadService. The middleware should extend this base class rather than
+ * the aidl stub for compatibility
+ * @hide
+ * TODO: future systemapi
+ */
+public class MbmsDownloadServiceBase extends IMbmsDownloadService.Stub {
+ @Override
+ public void initialize(String appName, int subId, IMbmsDownloadManagerCallback listener)
+ throws RemoteException {
+ }
+
+ @Override
+ public int getFileServices(String appName, int subId, List<String> serviceClasses) throws
+ RemoteException {
+ return 0;
+ }
+
+ @Override
+ public int download(String appName, DownloadRequest downloadRequest, IDownloadCallback listener)
+ throws RemoteException {
+ return 0;
+ }
+
+ @Override
+ public List<DownloadRequest> listPendingDownloads(String appName) throws RemoteException {
+ return null;
+ }
+
+ @Override
+ public int cancelDownload(String appName, DownloadRequest downloadRequest)
+ throws RemoteException {
+ return 0;
+ }
+
+ @Override
+ public DownloadStatus getDownloadStatus(String appName, DownloadRequest downloadRequest)
+ throws RemoteException {
+ return null;
+ }
+
+ @Override
+ public void resetDownloadKnowledge(String appName, DownloadRequest downloadRequest)
+ throws RemoteException {
+ }
+
+ @Override
+ public void dispose(String appName, int subId) throws RemoteException {
+ }
+}
diff --git a/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java b/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java
new file mode 100644
index 0000000..1c8ab7c
--- /dev/null
+++ b/telephony/java/android/telephony/mbms/vendor/MbmsStreamingServiceBase.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2017 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.telephony.mbms.vendor;
+
+import android.net.Uri;
+import android.os.RemoteException;
+import android.telephony.mbms.IMbmsStreamingManagerCallback;
+import android.telephony.mbms.IStreamingServiceCallback;
+import android.telephony.mbms.StreamingService;
+
+import java.util.List;
+
+/**
+ * @hide
+ * TODO: future systemapi
+ */
+public class MbmsStreamingServiceBase extends IMbmsStreamingService.Stub {
+
+ @Override
+ public int initialize(IMbmsStreamingManagerCallback listener, String appName, int subId)
+ throws RemoteException {
+ return 0;
+ }
+
+ @Override
+ public int getStreamingServices(String appName, int subId, List<String> serviceClasses)
+ throws RemoteException {
+ return 0;
+ }
+
+ @Override
+ public StreamingService startStreaming(String appName, int subId,
+ String serviceId, IStreamingServiceCallback listener) throws RemoteException {
+ return null;
+ }
+
+ @Override
+ public int getActiveStreamingServices(String appName, int subId) throws RemoteException {
+ return 0;
+ }
+
+ @Override
+ public Uri getPlaybackUri(String appName, int subId, String serviceId) throws RemoteException {
+ return null;
+ }
+
+ @Override
+ public void switchStreams(String appName, int subId, String oldServiceId, String newServiceId)
+ throws RemoteException {
+ }
+
+ @Override
+ public int getState(String appName, int subId, String serviceId) throws RemoteException {
+ return 0;
+ }
+
+ @Override
+ public void stopStreaming(String appName, int subId, String serviceId) throws RemoteException {
+ }
+
+ @Override
+ public void disposeStream(String appName, int subId, String serviceId) throws RemoteException {
+ }
+
+ @Override
+ public void dispose(String appName, int subId) throws RemoteException {
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index c6b750e..f2e1e26 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -16,6 +16,7 @@
package com.android.internal.telephony;
+import android.app.PendingIntent;
import android.content.Intent;
import android.os.Bundle;
import android.os.ResultReceiver;
@@ -273,6 +274,16 @@
*/
boolean handlePinMmi(String dialString);
+
+ /**
+ * Handles USSD commands.
+ *
+ * @param subId The subscription to use.
+ * @param ussdRequest the USSD command to be executed.
+ * @param wrappedCallback receives a callback result.
+ */
+ void handleUssdRequest(int subId, String ussdRequest, in ResultReceiver wrappedCallback);
+
/**
* Handles PIN MMI commands (PIN/PIN2/PUK/PUK2), which are initiated
* without SEND (so <code>dial</code> is not appropriate) for
@@ -481,12 +492,20 @@
*/
int getVoiceMessageCountForSubscriber(int subId);
+ /**
+ * Returns true if current state supports both voice and data
+ * simultaneously. This can change based on location or network condition.
+ */
+ boolean isConcurrentVoiceAndDataAllowed(int subId);
+
oneway void setVisualVoicemailEnabled(String callingPackage,
in PhoneAccountHandle accountHandle, boolean enabled);
boolean isVisualVoicemailEnabled(String callingPackage,
in PhoneAccountHandle accountHandle);
+ String getVisualVoicemailPackageName(String callingPackage, int subId);
+
// Not oneway, caller needs to make sure the vaule is set before receiving a SMS
void enableVisualVoicemailSmsFilter(String callingPackage, int subId,
in VisualVoicemailSmsFilterSettings settings);
@@ -497,9 +516,18 @@
VisualVoicemailSmsFilterSettings getVisualVoicemailSmsFilterSettings(String callingPackage,
int subId);
- // Get settings set by the package, requires READ_PRIVILEGED_PHONE_STATE permission
- VisualVoicemailSmsFilterSettings getSystemVisualVoicemailSmsFilterSettings(String packageName,
- int subId);
+ /**
+ * Get settings set by the current default dialer, Internal use only.
+ * Requires READ_PRIVILEGED_PHONE_STATE permission.
+ */
+ VisualVoicemailSmsFilterSettings getActiveVisualVoicemailSmsFilterSettings(int subId);
+
+ /**
+ * Send a visual voicemail SMS. Internal use only.
+ * Requires caller to be the default dialer and have SEND_SMS permission
+ */
+ oneway void sendVisualVoicemailSmsForSubscriber(in String callingPackage, in int subId,
+ in String number, in int port, in String text, in PendingIntent sentIntent);
/**
* Returns the network type for data transmission
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 1e1d7a6..954b17f 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -414,6 +414,7 @@
int RIL_REQUEST_SEND_DEVICE_STATE = 138;
int RIL_REQUEST_SET_UNSOLICITED_RESPONSE_FILTER = 139;
int RIL_REQUEST_SET_SIM_CARD_POWER = 140;
+ int RIL_REQUEST_SET_CARRIER_INFO_IMSI_ENCRYPTION = 141;
int RIL_RESPONSE_ACKNOWLEDGEMENT = 800;
@@ -465,4 +466,5 @@
int RIL_UNSOL_STK_CC_ALPHA_NOTIFY = 1044;
int RIL_UNSOL_LCEDATA_RECV = 1045;
int RIL_UNSOL_PCO_DATA = 1046;
+ int RIL_UNSOL_CARRIER_INFO_IMSI_ENCRYPTION = 1047;
}
diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
index ce4e7e2..55a8b0b 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
@@ -402,7 +402,7 @@
* <ul>
* <li>apnType</li><dd>A string with the apn type.</dd>
* <li>redirectionUrl</li><dd>redirection url string</dd>
- * <li>subId</dt><li>Sub Id which associated the data connection failure.</dd>
+ * <li>subId</li><dd>Sub Id which associated the data connection failure.</dd>
* </ul>
* <p class="note">This is a protected intent that can only be sent by the system.</p>
*/
@@ -415,7 +415,7 @@
* <ul>
* <li>apnType</li><dd>A string with the apn type.</dd>
* <li>errorCode</li><dd>A integer with dataFailCause.</dd>
- * <li>subId</dt><li>Sub Id which associated the data connection failure.</dd>
+ * <li>subId</li><dd>Sub Id which associated the data connection failure.</dd>
* </ul>
* <p class="note">This is a protected intent that can only be sent by the system. </p>
*/
@@ -432,13 +432,25 @@
* IPV4V6)</dd>
* <li>pcoId</li><dd>An integer indicating the pco id for the data.</dd>
* <li>pcoValue</li><dd>A byte array of pco data read from modem.</dd>
- * <li>subId</dt><li>Sub Id which associated the data connection.</dd>
+ * <li>subId</li><dd>Sub Id which associated the data connection.</dd>
* </ul>
* <p class="note">This is a protected intent that can only be sent by the system. </p>
*/
public static final String ACTION_CARRIER_SIGNAL_PCO_VALUE =
"com.android.internal.telephony.CARRIER_SIGNAL_PCO_VALUE";
+ /**
+ * <p>Broadcast Action: when framework reset all carrier actions on sim load or absent.
+ * intended for carrier apps clean up (clear UI e.g.) and only sent to the specified carrier app
+ * The intent will have the following extra values:</p>
+ * <ul>
+ * <li>subId</li><dd>Sub Id which associated the data connection failure.</dd>
+ * </ul>
+ * <p class="note">This is a protected intent that can only be sent by the system.</p>
+ */
+ public static final String ACTION_CARRIER_SIGNAL_RESET =
+ "com.android.internal.telephony.CARRIER_SIGNAL_RESET";
+
// CARRIER_SIGNAL_ACTION extra keys
public static final String EXTRA_REDIRECTION_URL_KEY = "redirectionUrl";
public static final String EXTRA_ERROR_CODE_KEY = "errorCode";
diff --git a/tests/net/java/android/net/NetworkCapabilitiesTest.java b/tests/net/java/android/net/NetworkCapabilitiesTest.java
new file mode 100644
index 0000000..e3b06c8
--- /dev/null
+++ b/tests/net/java/android/net/NetworkCapabilitiesTest.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2017 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 static android.net.NetworkCapabilities.NET_CAPABILITY_CBS;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_EIMS;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
+import static android.net.NetworkCapabilities.RESTRICTED_CAPABILITIES;
+import static android.net.NetworkCapabilities.UNRESTRICTED_CAPABILITIES;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+
+import android.net.NetworkCapabilities;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class NetworkCapabilitiesTest {
+ @Test
+ public void testMaybeMarkCapabilitiesRestricted() {
+ // verify EIMS is restricted
+ assertEquals((1 << NET_CAPABILITY_EIMS) & RESTRICTED_CAPABILITIES,
+ (1 << NET_CAPABILITY_EIMS));
+
+ // verify CBS is also restricted
+ assertEquals((1 << NET_CAPABILITY_CBS) & RESTRICTED_CAPABILITIES,
+ (1 << NET_CAPABILITY_CBS));
+
+ // verify default is not restricted
+ assertEquals((1 << NET_CAPABILITY_INTERNET) & RESTRICTED_CAPABILITIES, 0);
+
+ // just to see
+ assertEquals(RESTRICTED_CAPABILITIES & UNRESTRICTED_CAPABILITIES, 0);
+
+ // check that internet does not get restricted
+ NetworkCapabilities netCap = new NetworkCapabilities();
+ netCap.addCapability(NET_CAPABILITY_INTERNET);
+ netCap.maybeMarkCapabilitiesRestricted();
+ assertTrue(netCap.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
+
+ // metered-ness shouldn't matter
+ netCap = new NetworkCapabilities();
+ netCap.addCapability(NET_CAPABILITY_INTERNET);
+ netCap.addCapability(NET_CAPABILITY_NOT_METERED);
+ netCap.maybeMarkCapabilitiesRestricted();
+ assertTrue(netCap.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
+ netCap = new NetworkCapabilities();
+ netCap.addCapability(NET_CAPABILITY_INTERNET);
+ netCap.removeCapability(NET_CAPABILITY_NOT_METERED);
+ netCap.maybeMarkCapabilitiesRestricted();
+ assertTrue(netCap.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
+
+ // add EIMS - bundled with unrestricted means it's unrestricted
+ netCap = new NetworkCapabilities();
+ netCap.addCapability(NET_CAPABILITY_INTERNET);
+ netCap.addCapability(NET_CAPABILITY_EIMS);
+ netCap.addCapability(NET_CAPABILITY_NOT_METERED);
+ netCap.maybeMarkCapabilitiesRestricted();
+ assertTrue(netCap.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
+ netCap = new NetworkCapabilities();
+ netCap.addCapability(NET_CAPABILITY_INTERNET);
+ netCap.addCapability(NET_CAPABILITY_EIMS);
+ netCap.removeCapability(NET_CAPABILITY_NOT_METERED);
+ netCap.maybeMarkCapabilitiesRestricted();
+ assertTrue(netCap.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
+
+ // just a restricted cap should be restricted regardless of meteredness
+ netCap = new NetworkCapabilities();
+ netCap.addCapability(NET_CAPABILITY_EIMS);
+ netCap.addCapability(NET_CAPABILITY_NOT_METERED);
+ netCap.maybeMarkCapabilitiesRestricted();
+ assertFalse(netCap.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
+ netCap = new NetworkCapabilities();
+ netCap.addCapability(NET_CAPABILITY_EIMS);
+ netCap.removeCapability(NET_CAPABILITY_NOT_METERED);
+ netCap.maybeMarkCapabilitiesRestricted();
+ assertFalse(netCap.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
+
+ // try 2 restricted caps
+ netCap = new NetworkCapabilities();
+ netCap.addCapability(NET_CAPABILITY_CBS);
+ netCap.addCapability(NET_CAPABILITY_EIMS);
+ netCap.addCapability(NET_CAPABILITY_NOT_METERED);
+ netCap.maybeMarkCapabilitiesRestricted();
+ assertFalse(netCap.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
+ netCap = new NetworkCapabilities();
+ netCap.addCapability(NET_CAPABILITY_CBS);
+ netCap.addCapability(NET_CAPABILITY_EIMS);
+ netCap.removeCapability(NET_CAPABILITY_NOT_METERED);
+ netCap.maybeMarkCapabilitiesRestricted();
+ assertFalse(netCap.hasCapability(NET_CAPABILITY_NOT_RESTRICTED));
+ }
+
+}
diff --git a/tests/net/java/android/net/apf/ApfTest.java b/tests/net/java/android/net/apf/ApfTest.java
index 91d6c68..d4896264 100644
--- a/tests/net/java/android/net/apf/ApfTest.java
+++ b/tests/net/java/android/net/apf/ApfTest.java
@@ -39,6 +39,8 @@
import com.android.frameworks.tests.net.R;
import com.android.internal.util.HexDump;
+import static com.android.internal.util.BitUtils.bytesToBEInt;
+import static com.android.internal.util.BitUtils.put;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
@@ -65,7 +67,7 @@
* Tests for APF program generator and interpreter.
*
* Build, install and run with:
- * runtest frameworks-services -c android.net.apf.ApfTest
+ * runtest frameworks-net -c android.net.apf.ApfTest
*/
public class ApfTest extends AndroidTestCase {
private static final int TIMEOUT_MS = 500;
@@ -1235,15 +1237,6 @@
byte[] apf_program);
@SmallTest
- public void testBytesToInt() {
- assertEquals(0x00000000, ApfFilter.bytesToInt(IPV4_ANY_HOST_ADDR));
- assertEquals(0xffffffff, ApfFilter.bytesToInt(IPV4_BROADCAST_ADDRESS));
- assertEquals(0x0a000001, ApfFilter.bytesToInt(MOCK_IPV4_ADDR));
- assertEquals(0x0a000002, ApfFilter.bytesToInt(ANOTHER_IPV4_ADDR));
- assertEquals(0x0a001fff, ApfFilter.bytesToInt(MOCK_BROADCAST_IPV4_ADDR));
- assertEquals(0xe0000001, ApfFilter.bytesToInt(MOCK_MULTICAST_IPV4_ADDR));
- }
-
public void testBroadcastAddress() throws Exception {
assertEqualsIp("255.255.255.255", ApfFilter.ipv4BroadcastAddress(IPV4_ANY_HOST_ADDR, 0));
assertEqualsIp("0.0.0.0", ApfFilter.ipv4BroadcastAddress(IPV4_ANY_HOST_ADDR, 32));
@@ -1257,7 +1250,7 @@
}
public void assertEqualsIp(String expected, int got) throws Exception {
- int want = ApfFilter.bytesToInt(InetAddress.getByName(expected).getAddress());
+ int want = bytesToBEInt(InetAddress.getByName(expected).getAddress());
assertEquals(want, got);
}
}
diff --git a/tests/net/java/android/net/nsd/NsdManagerTest.java b/tests/net/java/android/net/nsd/NsdManagerTest.java
new file mode 100644
index 0000000..063cd5dc
--- /dev/null
+++ b/tests/net/java/android/net/nsd/NsdManagerTest.java
@@ -0,0 +1,361 @@
+/*
+ * Copyright (C) 2017 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.nsd;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.os.HandlerThread;
+import android.os.Handler;
+import android.os.Looper;
+import android.content.Context;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.os.Message;
+import android.os.Messenger;
+import com.android.internal.util.AsyncChannel;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.function.Consumer;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class NsdManagerTest {
+
+ static final int PROTOCOL = NsdManager.PROTOCOL_DNS_SD;
+
+ @Mock Context mContext;
+ @Mock INsdManager mService;
+ MockServiceHandler mServiceHandler;
+
+ long mTimeoutMs = 100; // non-final so that tests can adjust the value.
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+
+ mServiceHandler = spy(MockServiceHandler.create(mContext));
+ when(mService.getMessenger()).thenReturn(new Messenger(mServiceHandler));
+ }
+
+ @Test
+ public void testResolveService() {
+ NsdManager manager = makeManager();
+
+ NsdServiceInfo request = new NsdServiceInfo("a_name", "a_type");
+ NsdServiceInfo reply = new NsdServiceInfo("resolved_name", "resolved_type");
+ NsdManager.ResolveListener listener = mock(NsdManager.ResolveListener.class);
+
+ manager.resolveService(request, listener);
+ int key1 = verifyRequest(NsdManager.RESOLVE_SERVICE);
+ int err = 33;
+ sendResponse(NsdManager.RESOLVE_SERVICE_FAILED, err, key1, null);
+ verify(listener, timeout(mTimeoutMs).times(1)).onResolveFailed(request, err);
+
+ manager.resolveService(request, listener);
+ int key2 = verifyRequest(NsdManager.RESOLVE_SERVICE);
+ sendResponse(NsdManager.RESOLVE_SERVICE_SUCCEEDED, 0, key2, reply);
+ verify(listener, timeout(mTimeoutMs).times(1)).onServiceResolved(reply);
+ }
+
+ @Test
+ public void testParallelResolveService() {
+ NsdManager manager = makeManager();
+
+ NsdServiceInfo request = new NsdServiceInfo("a_name", "a_type");
+ NsdServiceInfo reply = new NsdServiceInfo("resolved_name", "resolved_type");
+
+ NsdManager.ResolveListener listener1 = mock(NsdManager.ResolveListener.class);
+ NsdManager.ResolveListener listener2 = mock(NsdManager.ResolveListener.class);
+
+ manager.resolveService(request, listener1);
+ int key1 = verifyRequest(NsdManager.RESOLVE_SERVICE);
+
+ manager.resolveService(request, listener2);
+ int key2 = verifyRequest(NsdManager.RESOLVE_SERVICE);
+
+ sendResponse(NsdManager.RESOLVE_SERVICE_SUCCEEDED, 0, key2, reply);
+ sendResponse(NsdManager.RESOLVE_SERVICE_SUCCEEDED, 0, key1, reply);
+
+ verify(listener1, timeout(mTimeoutMs).times(1)).onServiceResolved(reply);
+ verify(listener2, timeout(mTimeoutMs).times(1)).onServiceResolved(reply);
+ }
+
+ @Test
+ public void testRegisterService() {
+ NsdManager manager = makeManager();
+
+ NsdServiceInfo request1 = new NsdServiceInfo("a_name", "a_type");
+ NsdServiceInfo request2 = new NsdServiceInfo("another_name", "another_type");
+ request1.setPort(2201);
+ request2.setPort(2202);
+ NsdManager.RegistrationListener listener1 = mock(NsdManager.RegistrationListener.class);
+ NsdManager.RegistrationListener listener2 = mock(NsdManager.RegistrationListener.class);
+
+ // Register two services
+ manager.registerService(request1, PROTOCOL, listener1);
+ int key1 = verifyRequest(NsdManager.REGISTER_SERVICE);
+
+ manager.registerService(request2, PROTOCOL, listener2);
+ int key2 = verifyRequest(NsdManager.REGISTER_SERVICE);
+
+ // First reques fails, second request succeeds
+ sendResponse(NsdManager.REGISTER_SERVICE_SUCCEEDED, 0, key2, request2);
+ verify(listener2, timeout(mTimeoutMs).times(1)).onServiceRegistered(request2);
+
+ int err = 1;
+ sendResponse(NsdManager.REGISTER_SERVICE_FAILED, err, key1, request1);
+ verify(listener1, timeout(mTimeoutMs).times(1)).onRegistrationFailed(request1, err);
+
+ // Client retries first request, it succeeds
+ manager.registerService(request1, PROTOCOL, listener1);
+ int key3 = verifyRequest(NsdManager.REGISTER_SERVICE);
+
+ sendResponse(NsdManager.REGISTER_SERVICE_SUCCEEDED, 0, key3, request1);
+ verify(listener1, timeout(mTimeoutMs).times(1)).onServiceRegistered(request1);
+
+ // First request is unregistered, it succeeds
+ manager.unregisterService(listener1);
+ int key3again = verifyRequest(NsdManager.UNREGISTER_SERVICE);
+ assertEquals(key3, key3again);
+
+ sendResponse(NsdManager.UNREGISTER_SERVICE_SUCCEEDED, 0, key3again, null);
+ verify(listener1, timeout(mTimeoutMs).times(1)).onServiceUnregistered(request1);
+
+ // Second request is unregistered, it fails
+ manager.unregisterService(listener2);
+ int key2again = verifyRequest(NsdManager.UNREGISTER_SERVICE);
+ assertEquals(key2, key2again);
+
+ sendResponse(NsdManager.UNREGISTER_SERVICE_FAILED, err, key2again, null);
+ verify(listener2, timeout(mTimeoutMs).times(1)).onUnregistrationFailed(request2, err);
+
+ // TODO: do not unregister listener until service is unregistered
+ // Client retries unregistration of second request, it succeeds
+ //manager.unregisterService(listener2);
+ //int key2yetAgain = verifyRequest(NsdManager.UNREGISTER_SERVICE);
+ //assertEquals(key2, key2yetAgain);
+
+ //sendResponse(NsdManager.UNREGISTER_SERVICE_SUCCEEDED, 0, key2yetAgain, null);
+ //verify(listener2, timeout(mTimeoutMs).times(1)).onServiceUnregistered(request2);
+ }
+
+ @Test
+ public void testDiscoverService() {
+ NsdManager manager = makeManager();
+
+ NsdServiceInfo reply1 = new NsdServiceInfo("a_name", "a_type");
+ NsdServiceInfo reply2 = new NsdServiceInfo("another_name", "a_type");
+ NsdServiceInfo reply3 = new NsdServiceInfo("a_third_name", "a_type");
+
+ NsdManager.DiscoveryListener listener = mock(NsdManager.DiscoveryListener.class);
+
+ // Client registers for discovery, request fails
+ manager.discoverServices("a_type", PROTOCOL, listener);
+ int key1 = verifyRequest(NsdManager.DISCOVER_SERVICES);
+
+ int err = 1;
+ sendResponse(NsdManager.DISCOVER_SERVICES_FAILED, err, key1, null);
+ verify(listener, timeout(mTimeoutMs).times(1)).onStartDiscoveryFailed("a_type", err);
+
+ // Client retries, request succeeds
+ manager.discoverServices("a_type", PROTOCOL, listener);
+ int key2 = verifyRequest(NsdManager.DISCOVER_SERVICES);
+
+ sendResponse(NsdManager.DISCOVER_SERVICES_STARTED, 0, key2, reply1);
+ verify(listener, timeout(mTimeoutMs).times(1)).onDiscoveryStarted("a_type");
+
+
+ // mdns notifies about services
+ sendResponse(NsdManager.SERVICE_FOUND, 0, key2, reply1);
+ verify(listener, timeout(mTimeoutMs).times(1)).onServiceFound(reply1);
+
+ sendResponse(NsdManager.SERVICE_FOUND, 0, key2, reply2);
+ verify(listener, timeout(mTimeoutMs).times(1)).onServiceFound(reply2);
+
+ sendResponse(NsdManager.SERVICE_LOST, 0, key2, reply2);
+ verify(listener, timeout(mTimeoutMs).times(1)).onServiceLost(reply2);
+
+
+ // Client unregisters its listener
+ manager.stopServiceDiscovery(listener);
+ int key2again = verifyRequest(NsdManager.STOP_DISCOVERY);
+ assertEquals(key2, key2again);
+
+ // TODO: unregister listener immediately and stop notifying it about services
+ // Notifications are still passed to the client's listener
+ sendResponse(NsdManager.SERVICE_LOST, 0, key2, reply1);
+ verify(listener, timeout(mTimeoutMs).times(1)).onServiceLost(reply1);
+
+ // Client is notified of complete unregistration
+ sendResponse(NsdManager.STOP_DISCOVERY_SUCCEEDED, 0, key2again, "a_type");
+ verify(listener, timeout(mTimeoutMs).times(1)).onDiscoveryStopped("a_type");
+
+ // Notifications are not passed to the client anymore
+ sendResponse(NsdManager.SERVICE_FOUND, 0, key2, reply3);
+ verify(listener, timeout(mTimeoutMs).times(0)).onServiceLost(reply3);
+
+
+ // Client registers for service discovery
+ reset(listener);
+ manager.discoverServices("a_type", PROTOCOL, listener);
+ int key3 = verifyRequest(NsdManager.DISCOVER_SERVICES);
+
+ sendResponse(NsdManager.DISCOVER_SERVICES_STARTED, 0, key3, reply1);
+ verify(listener, timeout(mTimeoutMs).times(1)).onDiscoveryStarted("a_type");
+
+ // Client unregisters immediately, it fails
+ manager.stopServiceDiscovery(listener);
+ int key3again = verifyRequest(NsdManager.STOP_DISCOVERY);
+ assertEquals(key3, key3again);
+
+ err = 2;
+ sendResponse(NsdManager.STOP_DISCOVERY_FAILED, err, key3again, "a_type");
+ verify(listener, timeout(mTimeoutMs).times(1)).onStopDiscoveryFailed("a_type", err);
+
+ // New notifications are not passed to the client anymore
+ sendResponse(NsdManager.SERVICE_FOUND, 0, key3, reply1);
+ verify(listener, timeout(mTimeoutMs).times(0)).onServiceFound(reply1);
+ }
+
+ @Test
+ public void testInvalidCalls() {
+ NsdManager manager = new NsdManager(mContext, mService);
+
+ NsdManager.RegistrationListener listener1 = mock(NsdManager.RegistrationListener.class);
+ NsdManager.DiscoveryListener listener2 = mock(NsdManager.DiscoveryListener.class);
+ NsdManager.ResolveListener listener3 = mock(NsdManager.ResolveListener.class);
+
+ NsdServiceInfo invalidService = new NsdServiceInfo(null, null);
+ NsdServiceInfo validService = new NsdServiceInfo("a_name", "a_type");
+ validService.setPort(2222);
+
+ // Service registration
+ // - invalid arguments
+ mustFail(() -> { manager.unregisterService(null); });
+ mustFail(() -> { manager.registerService(null, -1, null); });
+ mustFail(() -> { manager.registerService(null, PROTOCOL, listener1); });
+ mustFail(() -> { manager.registerService(invalidService, PROTOCOL, listener1); });
+ mustFail(() -> { manager.registerService(validService, -1, listener1); });
+ mustFail(() -> { manager.registerService(validService, PROTOCOL, null); });
+ manager.registerService(validService, PROTOCOL, listener1);
+ // - listener already registered
+ mustFail(() -> { manager.registerService(validService, PROTOCOL, listener1); });
+ manager.unregisterService(listener1);
+ // TODO: make listener immediately reusable
+ //mustFail(() -> { manager.unregisterService(listener1); });
+ //manager.registerService(validService, PROTOCOL, listener1);
+
+ // Discover service
+ // - invalid arguments
+ mustFail(() -> { manager.stopServiceDiscovery(null); });
+ mustFail(() -> { manager.discoverServices(null, -1, null); });
+ mustFail(() -> { manager.discoverServices(null, PROTOCOL, listener2); });
+ mustFail(() -> { manager.discoverServices("a_service", -1, listener2); });
+ mustFail(() -> { manager.discoverServices("a_service", PROTOCOL, null); });
+ manager.discoverServices("a_service", PROTOCOL, listener2);
+ // - listener already registered
+ mustFail(() -> { manager.discoverServices("another_service", PROTOCOL, listener2); });
+ manager.stopServiceDiscovery(listener2);
+ // TODO: make listener immediately reusable
+ //mustFail(() -> { manager.stopServiceDiscovery(listener2); });
+ //manager.discoverServices("another_service", PROTOCOL, listener2);
+
+ // Resolver service
+ // - invalid arguments
+ mustFail(() -> { manager.resolveService(null, null); });
+ mustFail(() -> { manager.resolveService(null, listener3); });
+ mustFail(() -> { manager.resolveService(invalidService, listener3); });
+ mustFail(() -> { manager.resolveService(validService, null); });
+ manager.resolveService(validService, listener3);
+ // - listener already registered:w
+ mustFail(() -> { manager.resolveService(validService, listener3); });
+ }
+
+ public void mustFail(Runnable fn) {
+ try {
+ fn.run();
+ fail();
+ } catch (Exception expected) {
+ }
+ }
+
+ NsdManager makeManager() {
+ NsdManager manager = new NsdManager(mContext, mService);
+ // Acknowledge first two messages connecting the AsyncChannel.
+ verify(mServiceHandler, timeout(mTimeoutMs).times(2)).handleMessage(any());
+ reset(mServiceHandler);
+ assertNotNull(mServiceHandler.chan);
+ return manager;
+ }
+
+ int verifyRequest(int expectedMessageType) {
+ verify(mServiceHandler, timeout(mTimeoutMs)).handleMessage(any());
+ reset(mServiceHandler);
+ Message received = mServiceHandler.lastMessage;
+ assertEquals(NsdManager.nameOf(expectedMessageType), NsdManager.nameOf(received.what));
+ return received.arg2;
+ }
+
+ void sendResponse(int replyType, int arg, int key, Object obj) {
+ mServiceHandler.chan.sendMessage(replyType, arg, key, obj);
+ }
+
+ // Implements the server side of AsyncChannel connection protocol
+ public static class MockServiceHandler extends Handler {
+ public Context mContext;
+ public AsyncChannel chan;
+ public Message lastMessage;
+
+ MockServiceHandler(Looper looper, Context context) {
+ super(looper);
+ mContext = context;
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ lastMessage = obtainMessage();
+ lastMessage.copyFrom(msg);
+ if (msg.what == AsyncChannel.CMD_CHANNEL_FULL_CONNECTION) {
+ chan = new AsyncChannel();
+ chan.connect(mContext, this, msg.replyTo);
+ chan.sendMessage(AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED);
+ }
+
+ }
+
+ public static MockServiceHandler create(Context context) {
+ HandlerThread t = new HandlerThread("mock-service-handler");
+ t.start();
+ return new MockServiceHandler(t.getLooper(), context);
+ }
+ }
+}
diff --git a/tests/net/java/android/net/nsd/NsdServiceTest.java b/tests/net/java/android/net/nsd/NsdServiceTest.java
new file mode 100644
index 0000000..acc390c
--- /dev/null
+++ b/tests/net/java/android/net/nsd/NsdServiceTest.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2017 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 com.android.server;
+
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.test.TestLooper;
+import android.content.Context;
+import android.content.ContentResolver;
+import android.net.nsd.NsdManager;
+import com.android.server.NsdService.DaemonConnection;
+import com.android.server.NsdService.DaemonConnectionSupplier;
+import com.android.server.NsdService.NativeCallbackReceiver;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+// TODOs:
+// - test client disconnects
+// - test client can send requests and receive replies
+// - test NSD_ON ENABLE/DISABLED listening
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class NsdServiceTest {
+
+ @Mock Context mContext;
+ @Mock ContentResolver mResolver;
+ @Mock NsdService.NsdSettings mSettings;
+ @Mock DaemonConnection mDaemon;
+ NativeCallbackReceiver mDaemonCallback;
+ TestLooper mLooper;
+ TestHandler mHandler;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ mLooper = new TestLooper();
+ mHandler = new TestHandler(mLooper.getLooper());
+ when(mContext.getContentResolver()).thenReturn(mResolver);
+ }
+
+ @Test
+ public void testClientsCanConnect() {
+ when(mSettings.isEnabled()).thenReturn(true);
+
+ NsdService service = makeService();
+
+ NsdManager client1 = connectClient(service);
+ verify(mDaemon, timeout(100).times(1)).execute("start-service");
+
+ NsdManager client2 = connectClient(service);
+
+ // TODO: disconnect client1
+ // TODO: disconnect client2
+ }
+
+ NsdService makeService() {
+ DaemonConnectionSupplier supplier = (callback) -> {
+ mDaemonCallback = callback;
+ return mDaemon;
+ };
+ NsdService service = new NsdService(mContext, mSettings, mHandler, supplier);
+ verify(mDaemon, never()).execute(any(String.class));
+ return service;
+ }
+
+ NsdManager connectClient(NsdService service) {
+ mLooper.startAutoDispatch();
+ NsdManager client = new NsdManager(mContext, service);
+ mLooper.stopAutoDispatch();
+ return client;
+ }
+
+ public static class TestHandler extends Handler {
+ public Message lastMessage;
+
+ TestHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ lastMessage = obtainMessage();
+ lastMessage.copyFrom(msg);
+ }
+ }
+}
diff --git a/tests/net/java/com/android/internal/util/BitUtilsTest.java b/tests/net/java/com/android/internal/util/BitUtilsTest.java
new file mode 100644
index 0000000..0ad8a21
--- /dev/null
+++ b/tests/net/java/com/android/internal/util/BitUtilsTest.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2017 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 com.android.internal.util;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import java.nio.ByteBuffer;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.assertEquals;
+import static com.android.internal.util.BitUtils.*;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class BitUtilsTest {
+
+ @Test
+ public void testUnsignedByteWideningConversions() {
+ byte b0 = 0;
+ byte b1 = 1;
+ byte bm1 = -1;
+ assertEquals(0, uint8(b0));
+ assertEquals(1, uint8(b1));
+ assertEquals(127, uint8(Byte.MAX_VALUE));
+ assertEquals(128, uint8(Byte.MIN_VALUE));
+ assertEquals(255, uint8(bm1));
+ assertEquals(255, uint8((byte)255));
+ }
+
+ @Test
+ public void testUnsignedShortWideningConversions() {
+ short s0 = 0;
+ short s1 = 1;
+ short sm1 = -1;
+ assertEquals(0, uint16(s0));
+ assertEquals(1, uint16(s1));
+ assertEquals(32767, uint16(Short.MAX_VALUE));
+ assertEquals(32768, uint16(Short.MIN_VALUE));
+ assertEquals(65535, uint16(sm1));
+ assertEquals(65535, uint16((short)65535));
+ }
+
+ @Test
+ public void testUnsignedIntWideningConversions() {
+ assertEquals(0, uint32(0));
+ assertEquals(1, uint32(1));
+ assertEquals(2147483647L, uint32(Integer.MAX_VALUE));
+ assertEquals(2147483648L, uint32(Integer.MIN_VALUE));
+ assertEquals(4294967295L, uint32(-1));
+ assertEquals(4294967295L, uint32((int)4294967295L));
+ }
+
+ @Test
+ public void testBytesToInt() {
+ assertEquals(0x00000000, bytesToBEInt(bytes(0, 0, 0, 0)));
+ assertEquals(0xffffffff, bytesToBEInt(bytes(255, 255, 255, 255)));
+ assertEquals(0x0a000001, bytesToBEInt(bytes(10, 0, 0, 1)));
+ assertEquals(0x0a000002, bytesToBEInt(bytes(10, 0, 0, 2)));
+ assertEquals(0x0a001fff, bytesToBEInt(bytes(10, 0, 31, 255)));
+ assertEquals(0xe0000001, bytesToBEInt(bytes(224, 0, 0, 1)));
+
+ assertEquals(0x00000000, bytesToLEInt(bytes(0, 0, 0, 0)));
+ assertEquals(0x01020304, bytesToLEInt(bytes(4, 3, 2, 1)));
+ assertEquals(0xffff0000, bytesToLEInt(bytes(0, 0, 255, 255)));
+ }
+
+ @Test
+ public void testUnsignedGetters() {
+ ByteBuffer b = ByteBuffer.allocate(4);
+ b.putInt(0xffff);
+
+ assertEquals(0x0, getUint8(b, 0));
+ assertEquals(0x0, getUint8(b, 1));
+ assertEquals(0xff, getUint8(b, 2));
+ assertEquals(0xff, getUint8(b, 3));
+
+ assertEquals(0x0, getUint16(b, 0));
+ assertEquals(0xffff, getUint16(b, 2));
+
+ b.rewind();
+ b.putInt(0xffffffff);
+ assertEquals(0xffffffffL, getUint32(b, 0));
+ }
+
+ static byte[] bytes(int b1, int b2, int b3, int b4) {
+ return new byte[] {b(b1), b(b2), b(b3), b(b4)};
+ }
+
+ static byte b(int i) {
+ return (byte) i;
+ }
+}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 1be8d5e..5173278 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -1993,6 +1993,40 @@
}
@SmallTest
+ public void testNetworkSpecifierUidSpoofSecurityException() {
+ class UidAwareNetworkSpecifier extends NetworkSpecifier implements Parcelable {
+ @Override
+ public boolean satisfiedBy(NetworkSpecifier other) {
+ return true;
+ }
+
+ @Override
+ public void assertValidFromUid(int requestorUid) {
+ throw new SecurityException("failure");
+ }
+
+ @Override
+ public int describeContents() { return 0; }
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {}
+ }
+
+ mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+ mWiFiNetworkAgent.connect(false);
+
+ UidAwareNetworkSpecifier networkSpecifier = new UidAwareNetworkSpecifier();
+ NetworkRequest networkRequest = newWifiRequestBuilder().setNetworkSpecifier(
+ networkSpecifier).build();
+ TestNetworkCallback networkCallback = new TestNetworkCallback();
+ try {
+ mCm.requestNetwork(networkRequest, networkCallback);
+ fail("Network request with spoofed UID did not throw a SecurityException");
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+
+ @SmallTest
public void testRegisterDefaultNetworkCallback() throws Exception {
final TestNetworkCallback defaultNetworkCallback = new TestNetworkCallback();
mCm.registerDefaultNetworkCallback(defaultNetworkCallback);
diff --git a/tests/net/java/com/android/server/connectivity/TetheringTest.java b/tests/net/java/com/android/server/connectivity/TetheringTest.java
index e527d57..7a1c239 100644
--- a/tests/net/java/com/android/server/connectivity/TetheringTest.java
+++ b/tests/net/java/com/android/server/connectivity/TetheringTest.java
@@ -29,9 +29,11 @@
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
+import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
+import android.content.IntentFilter;
import android.content.res.Resources;
import android.hardware.usb.UsbManager;
import android.net.ConnectivityManager;
@@ -53,12 +55,16 @@
import com.android.internal.util.test.BroadcastInterceptingContext;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.ArrayList;
+import java.util.Vector;
+
@RunWith(AndroidJUnit4.class)
@SmallTest
public class TetheringTest {
@@ -81,7 +87,9 @@
private final TestLooper mLooper = new TestLooper();
private final String mTestIfname = "test_wlan0";
+ private Vector<Intent> mIntents;
private BroadcastInterceptingContext mServiceContext;
+ private BroadcastReceiver mBroadcastReceiver;
private Tethering mTethering;
private class MockContext extends BroadcastInterceptingContext {
@@ -100,7 +108,8 @@
}
}
- @Before public void setUp() throws Exception {
+ @Before
+ public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
when(mResources.getStringArray(com.android.internal.R.array.config_tether_dhcp_range))
.thenReturn(new String[0]);
@@ -118,10 +127,24 @@
.thenReturn(new InterfaceConfiguration());
mServiceContext = new MockContext(mContext);
+ mIntents = new Vector<>();
+ mBroadcastReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ mIntents.addElement(intent);
+ }
+ };
+ mServiceContext.registerReceiver(mBroadcastReceiver,
+ new IntentFilter(ConnectivityManager.ACTION_TETHER_STATE_CHANGED));
mTethering = new Tethering(mServiceContext, mNMService, mStatsService, mPolicyManager,
mLooper.getLooper(), mSystemProperties);
}
+ @After
+ public void tearDown() {
+ mServiceContext.unregisterReceiver(mBroadcastReceiver);
+ }
+
private void setupForRequiredProvisioning() {
// Produce some acceptable looking provision app setting if requested.
when(mResources.getStringArray(
@@ -180,11 +203,26 @@
mServiceContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
}
+ private void verifyInterfaceServingModeStarted() throws Exception {
+ verify(mNMService, times(1)).listInterfaces();
+ verify(mNMService, times(1)).getInterfaceConfig(mTestIfname);
+ verify(mNMService, times(1))
+ .setInterfaceConfig(eq(mTestIfname), any(InterfaceConfiguration.class));
+ verify(mNMService, times(1)).tetherInterface(mTestIfname);
+ }
+
+ private void verifyTetheringBroadcast(String ifname, String whichExtra) {
+ // Verify that ifname is in the whichExtra array of the tether state changed broadcast.
+ final Intent bcast = mIntents.get(0);
+ assertEquals(ConnectivityManager.ACTION_TETHER_STATE_CHANGED, bcast.getAction());
+ final ArrayList<String> ifnames = bcast.getStringArrayListExtra(whichExtra);
+ assertTrue(ifnames.contains(ifname));
+ mIntents.remove(bcast);
+ }
+
@Test
public void workingLocalOnlyHotspot() throws Exception {
when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
- when(mWifiManager.setWifiApEnabled(any(WifiConfiguration.class), anyBoolean()))
- .thenReturn(true);
// Emulate externally-visible WifiManager effects, causing the
// per-interface state machine to start up, and telling us that
@@ -193,14 +231,15 @@
sendWifiApStateChanged(WifiManager.WIFI_AP_STATE_ENABLED);
mLooper.dispatchAll();
- verify(mNMService, times(1)).listInterfaces();
- verify(mNMService, times(1)).getInterfaceConfig(mTestIfname);
- verify(mNMService, times(1))
- .setInterfaceConfig(eq(mTestIfname), any(InterfaceConfiguration.class));
- verify(mNMService, times(1)).tetherInterface(mTestIfname);
+ verifyInterfaceServingModeStarted();
+ verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
verify(mNMService, times(1)).setIpForwardingEnabled(true);
verify(mNMService, times(1)).startTethering(any(String[].class));
verifyNoMoreInteractions(mNMService);
+ verify(mWifiManager).updateInterfaceIpState(
+ mTestIfname, WifiManager.IFACE_IP_MODE_LOCAL_ONLY);
+ verifyNoMoreInteractions(mWifiManager);
+ verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_ACTIVE_LOCAL_ONLY);
// UpstreamNetworkMonitor will be started, and will register two callbacks:
// a "listen all" and a "track default".
verify(mConnectivityManager, times(1)).registerNetworkCallback(
@@ -225,6 +264,7 @@
verify(mNMService, times(1)).stopTethering();
verify(mNMService, times(1)).setIpForwardingEnabled(false);
verifyNoMoreInteractions(mNMService);
+ verifyNoMoreInteractions(mWifiManager);
// Asking for the last error after the per-interface state machine
// has been reaped yields an unknown interface error.
assertEquals(ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE,
@@ -234,13 +274,12 @@
@Test
public void workingWifiTethering() throws Exception {
when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
- when(mWifiManager.setWifiApEnabled(any(WifiConfiguration.class), anyBoolean()))
- .thenReturn(true);
+ when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
// Emulate pressing the WiFi tethering button.
mTethering.startTethering(ConnectivityManager.TETHERING_WIFI, null, false);
mLooper.dispatchAll();
- verify(mWifiManager, times(1)).setWifiApEnabled(null, true);
+ verify(mWifiManager, times(1)).startSoftAp(null);
verifyNoMoreInteractions(mWifiManager);
verifyNoMoreInteractions(mConnectivityManager);
verifyNoMoreInteractions(mNMService);
@@ -252,14 +291,15 @@
sendWifiApStateChanged(WifiManager.WIFI_AP_STATE_ENABLED);
mLooper.dispatchAll();
- verify(mNMService, times(1)).listInterfaces();
- verify(mNMService, times(1)).getInterfaceConfig(mTestIfname);
- verify(mNMService, times(1))
- .setInterfaceConfig(eq(mTestIfname), any(InterfaceConfiguration.class));
- verify(mNMService, times(1)).tetherInterface(mTestIfname);
+ verifyInterfaceServingModeStarted();
+ verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_AVAILABLE_TETHER);
verify(mNMService, times(1)).setIpForwardingEnabled(true);
verify(mNMService, times(1)).startTethering(any(String[].class));
verifyNoMoreInteractions(mNMService);
+ verify(mWifiManager).updateInterfaceIpState(
+ mTestIfname, WifiManager.IFACE_IP_MODE_TETHERED);
+ verifyNoMoreInteractions(mWifiManager);
+ verifyTetheringBroadcast(mTestIfname, ConnectivityManager.EXTRA_ACTIVE_TETHER);
// UpstreamNetworkMonitor will be started, and will register two callbacks:
// a "listen all" and a "track default".
verify(mConnectivityManager, times(1)).registerNetworkCallback(
@@ -286,7 +326,7 @@
// Emulate pressing the WiFi tethering button.
mTethering.stopTethering(ConnectivityManager.TETHERING_WIFI);
mLooper.dispatchAll();
- verify(mWifiManager, times(1)).setWifiApEnabled(null, false);
+ verify(mWifiManager, times(1)).stopSoftAp();
verifyNoMoreInteractions(mWifiManager);
verifyNoMoreInteractions(mConnectivityManager);
verifyNoMoreInteractions(mNMService);
@@ -305,6 +345,7 @@
verify(mNMService, times(1)).stopTethering();
verify(mNMService, times(1)).setIpForwardingEnabled(false);
verifyNoMoreInteractions(mNMService);
+ verifyNoMoreInteractions(mWifiManager);
// Asking for the last error after the per-interface state machine
// has been reaped yields an unknown interface error.
assertEquals(ConnectivityManager.TETHER_ERROR_UNKNOWN_IFACE,
diff --git a/tests/net/java/com/android/server/connectivity/VpnTest.java b/tests/net/java/com/android/server/connectivity/VpnTest.java
index efe6fec..506d9e5 100644
--- a/tests/net/java/com/android/server/connectivity/VpnTest.java
+++ b/tests/net/java/com/android/server/connectivity/VpnTest.java
@@ -27,6 +27,7 @@
import android.app.AppOpsManager;
import android.app.NotificationManager;
import android.content.Context;
+import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
@@ -42,6 +43,8 @@
import android.util.ArrayMap;
import android.util.ArraySet;
+import com.android.internal.net.VpnConfig;
+
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Map;
@@ -101,8 +104,10 @@
@Override
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
+
when(mContext.getPackageManager()).thenReturn(mPackageManager);
setMockedPackages(mPackages);
+
when(mContext.getPackageName()).thenReturn(Vpn.class.getPackage().getName());
when(mContext.getSystemService(eq(Context.USER_SERVICE))).thenReturn(mUserManager);
when(mContext.getSystemService(eq(Context.APP_OPS_SERVICE))).thenReturn(mAppOps);
@@ -258,6 +263,58 @@
}
@SmallTest
+ public void testLockdownRuleRepeatability() throws Exception {
+ final Vpn vpn = createVpn(primaryUser.id);
+
+ // Given legacy lockdown is already enabled,
+ vpn.setLockdown(true);
+ verify(mNetService, times(1)).setAllowOnlyVpnForUids(
+ eq(true), aryEq(new UidRange[] {UidRange.createForUser(primaryUser.id)}));
+
+ // Enabling legacy lockdown twice should do nothing.
+ vpn.setLockdown(true);
+ verify(mNetService, times(1)).setAllowOnlyVpnForUids(anyBoolean(), any(UidRange[].class));
+
+ // And disabling should remove the rules exactly once.
+ vpn.setLockdown(false);
+ verify(mNetService, times(1)).setAllowOnlyVpnForUids(
+ eq(false), aryEq(new UidRange[] {UidRange.createForUser(primaryUser.id)}));
+
+ // Removing the lockdown again should have no effect.
+ vpn.setLockdown(false);
+ verify(mNetService, times(2)).setAllowOnlyVpnForUids(anyBoolean(), any(UidRange[].class));
+ }
+
+ @SmallTest
+ public void testLockdownRuleReversibility() throws Exception {
+ final Vpn vpn = createVpn(primaryUser.id);
+
+ final UidRange[] entireUser = {
+ UidRange.createForUser(primaryUser.id)
+ };
+ final UidRange[] exceptPkg0 = {
+ new UidRange(entireUser[0].start, entireUser[0].start + PKG_UIDS[0] - 1),
+ new UidRange(entireUser[0].start + PKG_UIDS[0] + 1, entireUser[0].stop)
+ };
+
+ final InOrder order = inOrder(mNetService);
+
+ // Given lockdown is enabled with no package (legacy VPN),
+ vpn.setLockdown(true);
+ order.verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(entireUser));
+
+ // When a new VPN package is set the rules should change to cover that package.
+ vpn.prepare(null, PKGS[0]);
+ order.verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(entireUser));
+ order.verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(exceptPkg0));
+
+ // When that VPN package is unset, everything should be undone again in reverse.
+ vpn.prepare(null, VpnConfig.LEGACY_VPN);
+ order.verify(mNetService).setAllowOnlyVpnForUids(eq(false), aryEq(exceptPkg0));
+ order.verify(mNetService).setAllowOnlyVpnForUids(eq(true), aryEq(entireUser));
+ }
+
+ @SmallTest
public void testNotificationShownForAlwaysOnApp() {
final UserHandle userHandle = UserHandle.of(primaryUser.id);
final Vpn vpn = createVpn(primaryUser.id);
diff --git a/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java b/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
index caf1a55..a3f33dc 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
@@ -32,7 +32,6 @@
import static android.net.ConnectivityManager.TETHERING_USB;
import static android.net.ConnectivityManager.TETHERING_WIFI;
import static com.android.server.connectivity.tethering.IControlsTethering.STATE_AVAILABLE;
-import static com.android.server.connectivity.tethering.IControlsTethering.STATE_LOCAL_HOTSPOT;
import static com.android.server.connectivity.tethering.IControlsTethering.STATE_TETHERED;
import static com.android.server.connectivity.tethering.IControlsTethering.STATE_UNAVAILABLE;
diff --git a/tools/aapt2/ResourceParser.cpp b/tools/aapt2/ResourceParser.cpp
index a84c306..e2ee603 100644
--- a/tools/aapt2/ResourceParser.cpp
+++ b/tools/aapt2/ResourceParser.cpp
@@ -802,7 +802,7 @@
}
struct SymbolComparator {
- bool operator()(const Attribute::Symbol& a, const Attribute::Symbol& b) {
+ bool operator()(const Attribute::Symbol& a, const Attribute::Symbol& b) const {
return a.symbol.name.value() < b.symbol.name.value();
}
};
diff --git a/tools/aapt2/compile/Png.cpp b/tools/aapt2/compile/Png.cpp
index bbf7f41..65c4eb8 100644
--- a/tools/aapt2/compile/Png.cpp
+++ b/tools/aapt2/compile/Png.cpp
@@ -1080,6 +1080,10 @@
newRows[i] = image->rows[i + 1];
memmove(newRows[i], newRows[i] + 4, (W - 2) * 4);
}
+ delete[] image->rows[0];
+ if (H - 1 > 0) {
+ delete[] image->rows[H - 1];
+ }
image->rows.swap(newRows);
image->width -= 2;
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 69e1029..ad9f9b8 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -125,6 +125,8 @@
void setWifiApEnabled(in WifiConfiguration wifiConfig, boolean enable);
+ void updateInterfaceIpState(String ifaceName, int mode);
+
boolean startSoftAp(in WifiConfiguration wifiConfig);
boolean stopSoftAp();
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index ae8a224..b7fe9c7 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -20,7 +20,6 @@
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
import android.annotation.SystemApi;
-import android.bluetooth.BluetoothAdapter;
import android.content.Context;
import android.content.pm.ParceledListSlice;
import android.net.ConnectivityManager;
@@ -46,9 +45,9 @@
import com.android.server.net.NetworkPinner;
import java.net.InetAddress;
+import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;
-import java.util.Collections;
/**
* This class provides the primary API for managing all aspects of Wi-Fi
@@ -446,6 +445,35 @@
* @hide
*/
public static final int SAP_START_FAILURE_NO_CHANNEL = 1;
+
+ /**
+ * Interface IP mode for configuration error.
+ *
+ * @see updateInterfaceIpState(String, int)
+ *
+ * @hide
+ */
+ public static final int IFACE_IP_MODE_CONFIGURATION_ERROR = 0;
+
+ /**
+ * Interface IP mode for tethering.
+ *
+ * @see updateInterfaceIpState(String, int)
+ *
+ * @hide
+ */
+ public static final int IFACE_IP_MODE_TETHERED = 1;
+
+ /**
+ * Interface IP mode for Local Only Hotspot.
+ *
+ * @see updateInterfaceIpState(String, int)
+ *
+ * @hide
+ */
+ public static final int IFACE_IP_MODE_LOCAL_ONLY = 2;
+
+
/**
* Broadcast intent action indicating that a connection to the supplicant has
* been established (and it is now possible
@@ -1718,6 +1746,26 @@
}
/**
+ * Call allowing ConnectivityService to update WifiService with interface mode changes.
+ *
+ * The possible modes include: {@link IFACE_IP_MODE_TETHERED},
+ * {@link IFACE_IP_MODE_LOCAL_ONLY},
+ * {@link IFACE_IP_MODE_CONFIGURATION_ERROR}
+ *
+ * @param ifaceName String name of the updated interface
+ * @param mode int representing the new mode
+ *
+ * @hide
+ */
+ public void updateInterfaceIpState(String ifaceName, int mode) {
+ try {
+ mService.updateInterfaceIpState(ifaceName, mode);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
* Start SoftAp mode with the specified configuration.
* Note that starting in access point mode disables station
* mode operation
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareManager.java b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
index 3fcbd4b..b9ce61c 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareManager.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
@@ -31,6 +31,7 @@
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
+import android.os.Process;
import android.os.RemoteException;
import android.util.Log;
import android.util.SparseArray;
@@ -453,7 +454,8 @@
peerHandle != null ? peerHandle.peerId : 0, // 0 is an invalid peer ID
null, // peerMac (not used in this method)
pmk,
- passphrase);
+ passphrase,
+ Process.myUid());
}
/** @hide */
@@ -490,7 +492,8 @@
0, // 0 is an invalid peer ID
peer,
pmk,
- passphrase);
+ passphrase,
+ Process.myUid());
}
private static class WifiAwareEventCallbackProxy extends IWifiAwareEventCallback.Stub {
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareNetworkSpecifier.java b/wifi/java/android/net/wifi/aware/WifiAwareNetworkSpecifier.java
index 5993480..e152f6c 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareNetworkSpecifier.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareNetworkSpecifier.java
@@ -19,6 +19,7 @@
import android.net.NetworkSpecifier;
import android.os.Parcel;
import android.os.Parcelable;
+import android.util.Log;
import java.util.Arrays;
import java.util.Objects;
@@ -115,9 +116,18 @@
*/
public final String passphrase;
+ /**
+ * The UID of the process initializing this network specifier. Validated by receiver using
+ * checkUidIfNecessary() and is used by satisfiedBy() to determine whether matches the
+ * offered network.
+ *
+ * @hide
+ */
+ public final int requestorUid;
+
/** @hide */
public WifiAwareNetworkSpecifier(int type, int role, int clientId, int sessionId, int peerId,
- byte[] peerMac, byte[] pmk, String passphrase) {
+ byte[] peerMac, byte[] pmk, String passphrase, int requestorUid) {
this.type = type;
this.role = role;
this.clientId = clientId;
@@ -126,6 +136,7 @@
this.peerMac = peerMac;
this.pmk = pmk;
this.passphrase = passphrase;
+ this.requestorUid = requestorUid;
}
public static final Creator<WifiAwareNetworkSpecifier> CREATOR =
@@ -140,7 +151,8 @@
in.readInt(), // peerId
in.createByteArray(), // peerMac
in.createByteArray(), // pmk
- in.readString()); // passphrase
+ in.readString(), // passphrase
+ in.readInt()); // requestorUid
}
@Override
@@ -164,6 +176,7 @@
dest.writeByteArray(peerMac);
dest.writeByteArray(pmk);
dest.writeString(passphrase);
+ dest.writeInt(requestorUid);
}
/** @hide */
@@ -186,6 +199,7 @@
result = 31 * result + Arrays.hashCode(peerMac);
result = 31 * result + Arrays.hashCode(pmk);
result = 31 * result + Objects.hashCode(passphrase);
+ result = 31 * result + requestorUid;
return result;
}
@@ -210,7 +224,8 @@
&& peerId == lhs.peerId
&& Arrays.equals(peerMac, lhs.peerMac)
&& Arrays.equals(pmk, lhs.pmk)
- && Objects.equals(passphrase, lhs.passphrase);
+ && Objects.equals(passphrase, lhs.passphrase)
+ && requestorUid == lhs.requestorUid;
}
/** @hide */
@@ -228,7 +243,16 @@
.append(", pmk=").append((pmk == null) ? "<null>" : "<non-null>")
// masking PII
.append(", passphrase=").append((passphrase == null) ? "<null>" : "<non-null>")
+ .append(", requestorUid=").append(requestorUid)
.append("]");
return sb.toString();
}
+
+ /** @hide */
+ @Override
+ public void assertValidFromUid(int requestorUid) {
+ if (this.requestorUid != requestorUid) {
+ throw new SecurityException("mismatched UIDs");
+ }
+ }
}