Merge "Support for showing self-managed calls in IncallService."
diff --git a/Android.mk b/Android.mk
index a798a31..4e1479a 100644
--- a/Android.mk
+++ b/Android.mk
@@ -435,6 +435,7 @@
telephony/java/com/android/ims/internal/IImsEcbm.aidl \
telephony/java/com/android/ims/internal/IImsEcbmListener.aidl \
telephony/java/com/android/ims/internal/IImsExternalCallStateListener.aidl \
+ telephony/java/com/android/ims/internal/IImsFeatureStatusCallback.aidl \
telephony/java/com/android/ims/internal/IImsMultiEndpoint.aidl \
telephony/java/com/android/ims/internal/IImsService.aidl \
telephony/java/com/android/ims/internal/IImsServiceController.aidl \
@@ -513,6 +514,7 @@
LOCAL_MODULE := framework
+LOCAL_DX_FLAGS := --core-library --multi-dex
LOCAL_JACK_FLAGS := --multi-dex native
LOCAL_RMTYPEDEFS := true
@@ -1348,6 +1350,8 @@
LOCAL_MODULE_TAGS := optional
LOCAL_MODULE := ext
+LOCAL_DX_FLAGS := --core-library
+
ifneq ($(INCREMENTAL_BUILDS),)
LOCAL_PROGUARD_ENABLED := disabled
LOCAL_JACK_ENABLED := incremental
diff --git a/api/current.txt b/api/current.txt
index 3e10bbf..0c202401 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -8188,6 +8188,7 @@
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";
@@ -8553,6 +8554,7 @@
field public static final java.lang.String ACTION_CALL = "android.intent.action.CALL";
field public static final java.lang.String ACTION_CALL_BUTTON = "android.intent.action.CALL_BUTTON";
field public static final java.lang.String ACTION_CAMERA_BUTTON = "android.intent.action.CAMERA_BUTTON";
+ field public static final java.lang.String ACTION_CARRIER_SETUP = "android.intent.action.CARRIER_SETUP";
field public static final java.lang.String ACTION_CHOOSER = "android.intent.action.CHOOSER";
field public static final java.lang.String ACTION_CLOSE_SYSTEM_DIALOGS = "android.intent.action.CLOSE_SYSTEM_DIALOGS";
field public static final java.lang.String ACTION_CONFIGURATION_CHANGED = "android.intent.action.CONFIGURATION_CHANGED";
@@ -23723,6 +23725,68 @@
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 ALGO_AUTH_HMAC_MD5 = "hmac(md5)";
+ field public static final java.lang.String ALGO_AUTH_HMAC_SHA1 = "hmac(sha1)";
+ field public static final java.lang.String ALGO_AUTH_HMAC_SHA256 = "hmac(sha256)";
+ field public static final java.lang.String ALGO_AUTH_HMAC_SHA384 = "hmac(sha384)";
+ field public static final java.lang.String ALGO_AUTH_HMAC_SHA512 = "hmac(sha512)";
+ field public static final java.lang.String ALGO_CRYPT_AES_CBC = "cbc(aes)";
+ field public static final android.os.Parcelable.Creator<android.net.IpSecAlgorithm> CREATOR;
+ }
+
+ 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 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 android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(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, 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();
@@ -24737,11 +24801,14 @@
}
public static final class WifiEnterpriseConfig.Phase2 {
+ field public static final int AKA = 6; // 0x6
+ field public static final int AKA_PRIME = 7; // 0x7
field public static final int GTC = 4; // 0x4
field public static final int MSCHAP = 2; // 0x2
field public static final int MSCHAPV2 = 3; // 0x3
field public static final int NONE = 0; // 0x0
field public static final int PAP = 1; // 0x1
+ field public static final int SIM = 5; // 0x5
}
public class WifiInfo implements android.os.Parcelable {
@@ -24912,8 +24979,6 @@
public class DiscoverySession {
method public java.lang.String createNetworkSpecifier(android.net.wifi.aware.PeerHandle, byte[]);
method public void destroy();
- method public static int getMaxSendRetryCount();
- method public void sendMessage(android.net.wifi.aware.PeerHandle, int, byte[], int);
method public void sendMessage(android.net.wifi.aware.PeerHandle, int, byte[]);
}
@@ -25027,7 +25092,7 @@
method public java.lang.String getSubscriptionType();
method public android.net.wifi.hotspot2.pps.UpdateParameter getSubscriptionUpdate();
method public java.util.Map<java.lang.String, byte[]> getTrustRootCertList();
- method public int getUpdateIdentififer();
+ method public int getUpdateIdentifier();
method public long getUsageLimitDataLimit();
method public long getUsageLimitStartTimeInMs();
method public long getUsageLimitTimeLimitInMinutes();
@@ -25069,7 +25134,7 @@
method public int describeContents();
method public java.security.cert.X509Certificate getCaCertificate();
method public android.net.wifi.hotspot2.pps.Credential.CertificateCredential getCertCredential();
- method public boolean getCheckAaaServerStatus();
+ method public boolean getCheckAaaServerCertStatus();
method public java.security.cert.X509Certificate[] getClientCertificateChain();
method public java.security.PrivateKey getClientPrivateKey();
method public long getCreationTimeInMs();
@@ -25150,7 +25215,7 @@
method public java.util.Map<java.lang.String, java.lang.Long> getHomeNetworkIds();
method public java.lang.String getIconUrl();
method public long[] getMatchAllOis();
- method public long[] getMatchAnysOis();
+ method public long[] getMatchAnyOis();
method public java.lang.String[] getOtherHomePartners();
method public long[] getRoamingConsortiumOis();
method public void setFqdn(java.lang.String);
@@ -25172,7 +25237,7 @@
method public int describeContents();
method public java.lang.String[] getExcludedSsidList();
method public int getMaximumBssLoadValue();
- method public long getMinHomeDownlinkBandWidht();
+ method public long getMinHomeDownlinkBandwidth();
method public long getMinHomeUplinkBandwidth();
method public long getMinRoamingDownlinkBandwidth();
method public long getMinRoamingUplinkBandwidth();
@@ -36578,9 +36643,11 @@
method public android.telecom.Call.Details getDetails();
method public android.telecom.Call getParent();
method public java.lang.String getRemainingPostDialSequence();
+ method public android.telecom.Call.RttCall getRttCall();
method public int getState();
method public android.telecom.InCallService.VideoCall getVideoCall();
method public void hold();
+ method public boolean isRttActive();
method public void mergeConference();
method public void phoneAccountSelected(android.telecom.PhoneAccountHandle, boolean);
method public void playDtmfTone(char);
@@ -36592,9 +36659,12 @@
method public void reject(boolean, java.lang.String);
method public final void removeExtras(java.util.List<java.lang.String>);
method public final void removeExtras(java.lang.String...);
+ method public void respondToRttRequest(int, boolean);
method public void sendCallEvent(java.lang.String, android.os.Bundle);
+ method public void sendRttRequest();
method public void splitFromConference();
method public void stopDtmfTone();
+ method public void stopRtt();
method public void swapConference();
method public void unhold();
method public void unregisterCallback(android.telecom.Call.Callback);
@@ -36621,6 +36691,9 @@
method public void onDetailsChanged(android.telecom.Call, android.telecom.Call.Details);
method public void onParentChanged(android.telecom.Call, android.telecom.Call);
method public void onPostDialWait(android.telecom.Call, java.lang.String);
+ method public void onRttModeChanged(android.telecom.Call, int);
+ method public void onRttRequest(android.telecom.Call, int);
+ method public void onRttStatusChanged(android.telecom.Call, boolean, android.telecom.Call.RttCall);
method public void onStateChanged(android.telecom.Call, int);
method public void onVideoCallChanged(android.telecom.Call, android.telecom.InCallService.VideoCall);
}
@@ -36675,6 +36748,16 @@
field public static final int PROPERTY_WIFI = 8; // 0x8
}
+ public static final class Call.RttCall {
+ method public int getRttAudioMode();
+ method public java.lang.String read();
+ method public void setRttMode(int);
+ method public void write(java.lang.String) throws java.io.IOException;
+ field public static final int RTT_MODE_FULL = 1; // 0x1
+ field public static final int RTT_MODE_HCO = 2; // 0x2
+ field public static final int RTT_MODE_VCO = 3; // 0x3
+ }
+
public final class CallAudioState implements android.os.Parcelable {
ctor public CallAudioState(boolean, int, int);
method public static java.lang.String audioRouteToString(int);
@@ -37046,6 +37129,7 @@
field public static final int CAPABILITY_CALL_SUBJECT = 64; // 0x40
field public static final int CAPABILITY_CONNECTION_MANAGER = 1; // 0x1
field public static final int CAPABILITY_PLACE_EMERGENCY_CALLS = 16; // 0x10
+ field public static final int CAPABILITY_RTT = 4096; // 0x1000
field public static final int CAPABILITY_SELF_MANAGED = 2048; // 0x800
field public static final int CAPABILITY_SIM_SUBSCRIPTION = 4; // 0x4
field public static final int CAPABILITY_SUPPORTS_VIDEO_CALLING = 1024; // 0x400
@@ -37259,6 +37343,7 @@
field public static final java.lang.String EXTRA_NOTIFICATION_PHONE_NUMBER = "android.telecom.extra.NOTIFICATION_PHONE_NUMBER";
field public static final java.lang.String EXTRA_OUTGOING_CALL_EXTRAS = "android.telecom.extra.OUTGOING_CALL_EXTRAS";
field public static final java.lang.String EXTRA_PHONE_ACCOUNT_HANDLE = "android.telecom.extra.PHONE_ACCOUNT_HANDLE";
+ field public static final java.lang.String EXTRA_START_CALL_WITH_RTT = "android.telecom.extra.START_CALL_WITH_RTT";
field public static final java.lang.String EXTRA_START_CALL_WITH_SPEAKERPHONE = "android.telecom.extra.START_CALL_WITH_SPEAKERPHONE";
field public static final java.lang.String EXTRA_START_CALL_WITH_VIDEO_STATE = "android.telecom.extra.START_CALL_WITH_VIDEO_STATE";
field public static final java.lang.String GATEWAY_ORIGINAL_ADDRESS = "android.telecom.extra.GATEWAY_ORIGINAL_ADDRESS";
@@ -37413,6 +37498,7 @@
field public static final java.lang.String KEY_SHOW_ONSCREEN_DIAL_BUTTON_BOOL = "show_onscreen_dial_button_bool";
field public static final java.lang.String KEY_SIMPLIFIED_NETWORK_SETTINGS_BOOL = "simplified_network_settings_bool";
field public static final java.lang.String KEY_SIM_NETWORK_UNLOCK_ALLOW_DISMISS_BOOL = "sim_network_unlock_allow_dismiss_bool";
+ field public static final java.lang.String KEY_SUPPORT_3GPP_CALL_FORWARDING_WHILE_ROAMING_BOOL = "support_3gpp_call_forwarding_while_roaming_bool";
field public static final java.lang.String KEY_SUPPORT_CONFERENCE_CALL_BOOL = "support_conference_call_bool";
field public static final java.lang.String KEY_SUPPORT_PAUSE_IMS_VIDEO_CALLS_BOOL = "support_pause_ims_video_calls_bool";
field public static final java.lang.String KEY_SUPPORT_SWAP_AFTER_MERGE_BOOL = "support_swap_after_merge_bool";
@@ -37932,6 +38018,7 @@
method public java.lang.String getDeviceId();
method public java.lang.String getDeviceId(int);
method public java.lang.String getDeviceSoftwareVersion();
+ method public java.lang.String[] getForbiddenPlmns();
method public java.lang.String getGroupIdLevel1();
method public java.lang.String getIccAuthentication(int, int, java.lang.String);
method public java.lang.String getLine1Number();
@@ -38737,7 +38824,7 @@
package android.test.suitebuilder {
- public class TestMethod {
+ public deprecated class TestMethod {
ctor public TestMethod(java.lang.reflect.Method, java.lang.Class<? extends junit.framework.TestCase>);
ctor public TestMethod(java.lang.String, java.lang.Class<? extends junit.framework.TestCase>);
ctor public TestMethod(junit.framework.TestCase);
@@ -38748,7 +38835,7 @@
method public java.lang.String getName();
}
- public class TestSuiteBuilder {
+ public deprecated class TestSuiteBuilder {
ctor public TestSuiteBuilder(java.lang.Class);
ctor public TestSuiteBuilder(java.lang.String, java.lang.ClassLoader);
method public android.test.suitebuilder.TestSuiteBuilder addRequirements(java.util.List<com.android.internal.util.Predicate<android.test.suitebuilder.TestMethod>>);
@@ -38761,7 +38848,7 @@
method public android.test.suitebuilder.TestSuiteBuilder named(java.lang.String);
}
- public static class TestSuiteBuilder.FailedToCreateTests extends junit.framework.TestCase {
+ public static deprecated class TestSuiteBuilder.FailedToCreateTests extends junit.framework.TestCase {
ctor public TestSuiteBuilder.FailedToCreateTests(java.lang.Exception);
method public void testSuiteConstructionFailed();
}
@@ -49131,7 +49218,7 @@
package com.android.internal.util {
- public abstract interface Predicate<T> {
+ public abstract deprecated interface Predicate<T> {
method public abstract boolean apply(T);
}
@@ -49269,6 +49356,8 @@
field public static final int OP_INT_TO_FLOAT = 130; // 0x82
field public static final int OP_INT_TO_LONG = 129; // 0x81
field public static final int OP_INT_TO_SHORT = 143; // 0x8f
+ field public static final int OP_INVOKE_CUSTOM = 252; // 0xfc
+ field public static final int OP_INVOKE_CUSTOM_RANGE = 253; // 0xfd
field public static final int OP_INVOKE_DIRECT = 112; // 0x70
field public static final deprecated int OP_INVOKE_DIRECT_EMPTY = 240; // 0xf0
field public static final int OP_INVOKE_DIRECT_JUMBO = 9471; // 0x24ff
@@ -49459,7 +49548,7 @@
method public static dalvik.system.DexFile loadDex(java.lang.String, java.lang.String, int) throws java.io.IOException;
}
- public final class InMemoryDexClassLoader extends java.lang.ClassLoader {
+ public final class InMemoryDexClassLoader extends dalvik.system.BaseDexClassLoader {
ctor public InMemoryDexClassLoader(java.nio.ByteBuffer, java.lang.ClassLoader);
}
@@ -50677,6 +50766,13 @@
field public static final java.lang.Class<java.lang.Boolean> TYPE;
}
+ public class BootstrapMethodError extends java.lang.LinkageError {
+ ctor public BootstrapMethodError();
+ ctor public BootstrapMethodError(java.lang.String);
+ ctor public BootstrapMethodError(java.lang.String, java.lang.Throwable);
+ ctor public BootstrapMethodError(java.lang.Throwable);
+ }
+
public final class Byte extends java.lang.Number implements java.lang.Comparable {
ctor public Byte(byte);
ctor public Byte(java.lang.String) throws java.lang.NumberFormatException;
@@ -52563,6 +52659,21 @@
package java.lang.invoke {
+ public abstract class CallSite {
+ method public abstract java.lang.invoke.MethodHandle dynamicInvoker();
+ method public abstract java.lang.invoke.MethodHandle getTarget();
+ method public abstract void setTarget(java.lang.invoke.MethodHandle);
+ method public java.lang.invoke.MethodType type();
+ }
+
+ public class ConstantCallSite extends java.lang.invoke.CallSite {
+ ctor public ConstantCallSite(java.lang.invoke.MethodHandle);
+ ctor protected ConstantCallSite(java.lang.invoke.MethodType, java.lang.invoke.MethodHandle) throws java.lang.Throwable;
+ method public final java.lang.invoke.MethodHandle dynamicInvoker();
+ method public final java.lang.invoke.MethodHandle getTarget();
+ method public final void setTarget(java.lang.invoke.MethodHandle);
+ }
+
public class LambdaConversionException extends java.lang.Exception {
ctor public LambdaConversionException();
ctor public LambdaConversionException(java.lang.String);
@@ -52648,7 +52759,6 @@
method public java.lang.Class<?> lookupClass();
method public int lookupModes();
method public java.lang.invoke.MethodHandleInfo revealDirect(java.lang.invoke.MethodHandle);
- method public void throwMakeAccessException(java.lang.String, java.lang.Object) throws java.lang.IllegalAccessException;
method public java.lang.invoke.MethodHandle unreflect(java.lang.reflect.Method) throws java.lang.IllegalAccessException;
method public java.lang.invoke.MethodHandle unreflectConstructor(java.lang.reflect.Constructor<?>) throws java.lang.IllegalAccessException;
method public java.lang.invoke.MethodHandle unreflectGetter(java.lang.reflect.Field) throws java.lang.IllegalAccessException;
@@ -52691,6 +52801,22 @@
method public java.lang.invoke.MethodType wrap();
}
+ public class MutableCallSite extends java.lang.invoke.CallSite {
+ ctor public MutableCallSite(java.lang.invoke.MethodType);
+ ctor public MutableCallSite(java.lang.invoke.MethodHandle);
+ method public final java.lang.invoke.MethodHandle dynamicInvoker();
+ method public final java.lang.invoke.MethodHandle getTarget();
+ method public void setTarget(java.lang.invoke.MethodHandle);
+ }
+
+ public class VolatileCallSite extends java.lang.invoke.CallSite {
+ ctor public VolatileCallSite(java.lang.invoke.MethodType);
+ ctor public VolatileCallSite(java.lang.invoke.MethodHandle);
+ method public final java.lang.invoke.MethodHandle dynamicInvoker();
+ method public final java.lang.invoke.MethodHandle getTarget();
+ method public void setTarget(java.lang.invoke.MethodHandle);
+ }
+
public class WrongMethodTypeException extends java.lang.RuntimeException {
ctor public WrongMethodTypeException();
ctor public WrongMethodTypeException(java.lang.String);
diff --git a/api/system-current.txt b/api/system-current.txt
index c6226b0..d6b6ad4a 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -8522,6 +8522,7 @@
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";
@@ -8895,6 +8896,7 @@
field public static final java.lang.String ACTION_CALL = "android.intent.action.CALL";
field public static final java.lang.String ACTION_CALL_BUTTON = "android.intent.action.CALL_BUTTON";
field public static final java.lang.String ACTION_CAMERA_BUTTON = "android.intent.action.CAMERA_BUTTON";
+ field public static final java.lang.String ACTION_CARRIER_SETUP = "android.intent.action.CARRIER_SETUP";
field public static final java.lang.String ACTION_CHOOSER = "android.intent.action.CHOOSER";
field public static final java.lang.String ACTION_CLOSE_SYSTEM_DIALOGS = "android.intent.action.CLOSE_SYSTEM_DIALOGS";
field public static final java.lang.String ACTION_CONFIGURATION_CHANGED = "android.intent.action.CONFIGURATION_CHANGED";
@@ -25560,6 +25562,73 @@
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 ALGO_AUTH_HMAC_MD5 = "hmac(md5)";
+ field public static final java.lang.String ALGO_AUTH_HMAC_SHA1 = "hmac(sha1)";
+ field public static final java.lang.String ALGO_AUTH_HMAC_SHA256 = "hmac(sha256)";
+ field public static final java.lang.String ALGO_AUTH_HMAC_SHA384 = "hmac(sha384)";
+ field public static final java.lang.String ALGO_AUTH_HMAC_SHA512 = "hmac(sha512)";
+ field public static final java.lang.String ALGO_CRYPT_AES_CBC = "cbc(aes)";
+ field public static final android.os.Parcelable.Creator<android.net.IpSecAlgorithm> CREATOR;
+ }
+
+ 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 applyTunnelModeTransform(android.net.Network, android.net.IpSecTransform);
+ 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 removeTunnelModeTransform(android.net.Network, android.net.IpSecTransform);
+ method public android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(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 buildTunnelModeTransform(java.net.InetAddress, java.net.InetAddress);
+ 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, 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();
@@ -27110,11 +27179,14 @@
}
public static final class WifiEnterpriseConfig.Phase2 {
+ field public static final int AKA = 6; // 0x6
+ field public static final int AKA_PRIME = 7; // 0x7
field public static final int GTC = 4; // 0x4
field public static final int MSCHAP = 2; // 0x2
field public static final int MSCHAPV2 = 3; // 0x3
field public static final int NONE = 0; // 0x0
field public static final int PAP = 1; // 0x1
+ field public static final int SIM = 5; // 0x5
}
public class WifiInfo implements android.os.Parcelable {
@@ -27465,8 +27537,6 @@
public class DiscoverySession {
method public java.lang.String createNetworkSpecifier(android.net.wifi.aware.PeerHandle, byte[]);
method public void destroy();
- method public static int getMaxSendRetryCount();
- method public void sendMessage(android.net.wifi.aware.PeerHandle, int, byte[], int);
method public void sendMessage(android.net.wifi.aware.PeerHandle, int, byte[]);
}
@@ -27580,7 +27650,7 @@
method public java.lang.String getSubscriptionType();
method public android.net.wifi.hotspot2.pps.UpdateParameter getSubscriptionUpdate();
method public java.util.Map<java.lang.String, byte[]> getTrustRootCertList();
- method public int getUpdateIdentififer();
+ method public int getUpdateIdentifier();
method public long getUsageLimitDataLimit();
method public long getUsageLimitStartTimeInMs();
method public long getUsageLimitTimeLimitInMinutes();
@@ -27622,7 +27692,7 @@
method public int describeContents();
method public java.security.cert.X509Certificate getCaCertificate();
method public android.net.wifi.hotspot2.pps.Credential.CertificateCredential getCertCredential();
- method public boolean getCheckAaaServerStatus();
+ method public boolean getCheckAaaServerCertStatus();
method public java.security.cert.X509Certificate[] getClientCertificateChain();
method public java.security.PrivateKey getClientPrivateKey();
method public long getCreationTimeInMs();
@@ -27703,7 +27773,7 @@
method public java.util.Map<java.lang.String, java.lang.Long> getHomeNetworkIds();
method public java.lang.String getIconUrl();
method public long[] getMatchAllOis();
- method public long[] getMatchAnysOis();
+ method public long[] getMatchAnyOis();
method public java.lang.String[] getOtherHomePartners();
method public long[] getRoamingConsortiumOis();
method public void setFqdn(java.lang.String);
@@ -27725,7 +27795,7 @@
method public int describeContents();
method public java.lang.String[] getExcludedSsidList();
method public int getMaximumBssLoadValue();
- method public long getMinHomeDownlinkBandWidht();
+ method public long getMinHomeDownlinkBandwidth();
method public long getMinHomeUplinkBandwidth();
method public long getMinRoamingDownlinkBandwidth();
method public long getMinRoamingUplinkBandwidth();
@@ -39545,9 +39615,11 @@
method public android.telecom.Call.Details getDetails();
method public android.telecom.Call getParent();
method public java.lang.String getRemainingPostDialSequence();
+ method public android.telecom.Call.RttCall getRttCall();
method public int getState();
method public android.telecom.InCallService.VideoCall getVideoCall();
method public void hold();
+ method public boolean isRttActive();
method public void mergeConference();
method public void phoneAccountSelected(android.telecom.PhoneAccountHandle, boolean);
method public void playDtmfTone(char);
@@ -39560,9 +39632,12 @@
method public final void removeExtras(java.util.List<java.lang.String>);
method public final void removeExtras(java.lang.String...);
method public deprecated void removeListener(android.telecom.Call.Listener);
+ method public void respondToRttRequest(int, boolean);
method public void sendCallEvent(java.lang.String, android.os.Bundle);
+ method public void sendRttRequest();
method public void splitFromConference();
method public void stopDtmfTone();
+ method public void stopRtt();
method public void swapConference();
method public void unhold();
method public void unregisterCallback(android.telecom.Call.Callback);
@@ -39590,6 +39665,9 @@
method public void onDetailsChanged(android.telecom.Call, android.telecom.Call.Details);
method public void onParentChanged(android.telecom.Call, android.telecom.Call);
method public void onPostDialWait(android.telecom.Call, java.lang.String);
+ method public void onRttModeChanged(android.telecom.Call, int);
+ method public void onRttRequest(android.telecom.Call, int);
+ method public void onRttStatusChanged(android.telecom.Call, boolean, android.telecom.Call.RttCall);
method public void onStateChanged(android.telecom.Call, int);
method public void onVideoCallChanged(android.telecom.Call, android.telecom.InCallService.VideoCall);
}
@@ -39648,6 +39726,16 @@
ctor public Call.Listener();
}
+ public static final class Call.RttCall {
+ method public int getRttAudioMode();
+ method public java.lang.String read();
+ method public void setRttMode(int);
+ method public void write(java.lang.String) throws java.io.IOException;
+ field public static final int RTT_MODE_FULL = 1; // 0x1
+ field public static final int RTT_MODE_HCO = 2; // 0x2
+ field public static final int RTT_MODE_VCO = 3; // 0x3
+ }
+
public final class CallAudioState implements android.os.Parcelable {
ctor public CallAudioState(boolean, int, int);
method public static java.lang.String audioRouteToString(int);
@@ -40150,6 +40238,7 @@
field public static final int CAPABILITY_CONNECTION_MANAGER = 1; // 0x1
field public static final int CAPABILITY_MULTI_USER = 32; // 0x20
field public static final int CAPABILITY_PLACE_EMERGENCY_CALLS = 16; // 0x10
+ field public static final int CAPABILITY_RTT = 4096; // 0x1000
field public static final int CAPABILITY_SELF_MANAGED = 2048; // 0x800
field public static final int CAPABILITY_SIM_SUBSCRIPTION = 4; // 0x4
field public static final int CAPABILITY_SUPPORTS_VIDEO_CALLING = 1024; // 0x400
@@ -40427,6 +40516,7 @@
field public static final java.lang.String EXTRA_NOTIFICATION_PHONE_NUMBER = "android.telecom.extra.NOTIFICATION_PHONE_NUMBER";
field public static final java.lang.String EXTRA_OUTGOING_CALL_EXTRAS = "android.telecom.extra.OUTGOING_CALL_EXTRAS";
field public static final java.lang.String EXTRA_PHONE_ACCOUNT_HANDLE = "android.telecom.extra.PHONE_ACCOUNT_HANDLE";
+ field public static final java.lang.String EXTRA_START_CALL_WITH_RTT = "android.telecom.extra.START_CALL_WITH_RTT";
field public static final java.lang.String EXTRA_START_CALL_WITH_SPEAKERPHONE = "android.telecom.extra.START_CALL_WITH_SPEAKERPHONE";
field public static final java.lang.String EXTRA_START_CALL_WITH_VIDEO_STATE = "android.telecom.extra.START_CALL_WITH_VIDEO_STATE";
field public static final java.lang.String GATEWAY_ORIGINAL_ADDRESS = "android.telecom.extra.GATEWAY_ORIGINAL_ADDRESS";
@@ -40583,6 +40673,7 @@
field public static final java.lang.String KEY_SHOW_ONSCREEN_DIAL_BUTTON_BOOL = "show_onscreen_dial_button_bool";
field public static final java.lang.String KEY_SIMPLIFIED_NETWORK_SETTINGS_BOOL = "simplified_network_settings_bool";
field public static final java.lang.String KEY_SIM_NETWORK_UNLOCK_ALLOW_DISMISS_BOOL = "sim_network_unlock_allow_dismiss_bool";
+ field public static final java.lang.String KEY_SUPPORT_3GPP_CALL_FORWARDING_WHILE_ROAMING_BOOL = "support_3gpp_call_forwarding_while_roaming_bool";
field public static final java.lang.String KEY_SUPPORT_CONFERENCE_CALL_BOOL = "support_conference_call_bool";
field public static final java.lang.String KEY_SUPPORT_PAUSE_IMS_VIDEO_CALLS_BOOL = "support_pause_ims_video_calls_bool";
field public static final java.lang.String KEY_SUPPORT_SWAP_AFTER_MERGE_BOOL = "support_swap_after_merge_bool";
@@ -40933,7 +41024,9 @@
method public void sendDataMessage(java.lang.String, java.lang.String, short, byte[], android.app.PendingIntent, android.app.PendingIntent);
method public void sendMultimediaMessage(android.content.Context, android.net.Uri, java.lang.String, android.os.Bundle, android.app.PendingIntent);
method public void sendMultipartTextMessage(java.lang.String, java.lang.String, java.util.ArrayList<java.lang.String>, java.util.ArrayList<android.app.PendingIntent>, java.util.ArrayList<android.app.PendingIntent>);
+ method public void sendMultipartTextMessageWithoutPersisting(java.lang.String, java.lang.String, java.util.List<java.lang.String>, java.util.List<android.app.PendingIntent>, java.util.List<android.app.PendingIntent>);
method public void sendTextMessage(java.lang.String, java.lang.String, java.lang.String, android.app.PendingIntent, android.app.PendingIntent);
+ method public void sendTextMessageWithoutPersisting(java.lang.String, java.lang.String, java.lang.String, android.app.PendingIntent, android.app.PendingIntent);
field public static final java.lang.String EXTRA_MMS_DATA = "android.telephony.extra.MMS_DATA";
field public static final java.lang.String EXTRA_MMS_HTTP_STATUS = "android.telephony.extra.MMS_HTTP_STATUS";
field public static final java.lang.String MMS_CONFIG_ALIAS_ENABLED = "aliasEnabled";
@@ -41141,6 +41234,7 @@
method public java.lang.String getDeviceId();
method public java.lang.String getDeviceId(int);
method public java.lang.String getDeviceSoftwareVersion();
+ method public java.lang.String[] getForbiddenPlmns();
method public java.lang.String getGroupIdLevel1();
method public java.lang.String getIccAuthentication(int, int, java.lang.String);
method public java.lang.String getImei();
@@ -42001,7 +42095,7 @@
package android.test.suitebuilder {
- public class TestMethod {
+ public deprecated class TestMethod {
ctor public TestMethod(java.lang.reflect.Method, java.lang.Class<? extends junit.framework.TestCase>);
ctor public TestMethod(java.lang.String, java.lang.Class<? extends junit.framework.TestCase>);
ctor public TestMethod(junit.framework.TestCase);
@@ -42012,7 +42106,7 @@
method public java.lang.String getName();
}
- public class TestSuiteBuilder {
+ public deprecated class TestSuiteBuilder {
ctor public TestSuiteBuilder(java.lang.Class);
ctor public TestSuiteBuilder(java.lang.String, java.lang.ClassLoader);
method public android.test.suitebuilder.TestSuiteBuilder addRequirements(java.util.List<com.android.internal.util.Predicate<android.test.suitebuilder.TestMethod>>);
@@ -42025,7 +42119,7 @@
method public android.test.suitebuilder.TestSuiteBuilder named(java.lang.String);
}
- public static class TestSuiteBuilder.FailedToCreateTests extends junit.framework.TestCase {
+ public static deprecated class TestSuiteBuilder.FailedToCreateTests extends junit.framework.TestCase {
ctor public TestSuiteBuilder.FailedToCreateTests(java.lang.Exception);
method public void testSuiteConstructionFailed();
}
@@ -52752,7 +52846,7 @@
package com.android.internal.util {
- public abstract interface Predicate<T> {
+ public abstract deprecated interface Predicate<T> {
method public abstract boolean apply(T);
}
@@ -52890,6 +52984,8 @@
field public static final int OP_INT_TO_FLOAT = 130; // 0x82
field public static final int OP_INT_TO_LONG = 129; // 0x81
field public static final int OP_INT_TO_SHORT = 143; // 0x8f
+ field public static final int OP_INVOKE_CUSTOM = 252; // 0xfc
+ field public static final int OP_INVOKE_CUSTOM_RANGE = 253; // 0xfd
field public static final int OP_INVOKE_DIRECT = 112; // 0x70
field public static final deprecated int OP_INVOKE_DIRECT_EMPTY = 240; // 0xf0
field public static final int OP_INVOKE_DIRECT_JUMBO = 9471; // 0x24ff
@@ -53080,7 +53176,7 @@
method public static dalvik.system.DexFile loadDex(java.lang.String, java.lang.String, int) throws java.io.IOException;
}
- public final class InMemoryDexClassLoader extends java.lang.ClassLoader {
+ public final class InMemoryDexClassLoader extends dalvik.system.BaseDexClassLoader {
ctor public InMemoryDexClassLoader(java.nio.ByteBuffer, java.lang.ClassLoader);
}
@@ -54298,6 +54394,13 @@
field public static final java.lang.Class<java.lang.Boolean> TYPE;
}
+ public class BootstrapMethodError extends java.lang.LinkageError {
+ ctor public BootstrapMethodError();
+ ctor public BootstrapMethodError(java.lang.String);
+ ctor public BootstrapMethodError(java.lang.String, java.lang.Throwable);
+ ctor public BootstrapMethodError(java.lang.Throwable);
+ }
+
public final class Byte extends java.lang.Number implements java.lang.Comparable {
ctor public Byte(byte);
ctor public Byte(java.lang.String) throws java.lang.NumberFormatException;
@@ -56184,6 +56287,21 @@
package java.lang.invoke {
+ public abstract class CallSite {
+ method public abstract java.lang.invoke.MethodHandle dynamicInvoker();
+ method public abstract java.lang.invoke.MethodHandle getTarget();
+ method public abstract void setTarget(java.lang.invoke.MethodHandle);
+ method public java.lang.invoke.MethodType type();
+ }
+
+ public class ConstantCallSite extends java.lang.invoke.CallSite {
+ ctor public ConstantCallSite(java.lang.invoke.MethodHandle);
+ ctor protected ConstantCallSite(java.lang.invoke.MethodType, java.lang.invoke.MethodHandle) throws java.lang.Throwable;
+ method public final java.lang.invoke.MethodHandle dynamicInvoker();
+ method public final java.lang.invoke.MethodHandle getTarget();
+ method public final void setTarget(java.lang.invoke.MethodHandle);
+ }
+
public class LambdaConversionException extends java.lang.Exception {
ctor public LambdaConversionException();
ctor public LambdaConversionException(java.lang.String);
@@ -56269,7 +56387,6 @@
method public java.lang.Class<?> lookupClass();
method public int lookupModes();
method public java.lang.invoke.MethodHandleInfo revealDirect(java.lang.invoke.MethodHandle);
- method public void throwMakeAccessException(java.lang.String, java.lang.Object) throws java.lang.IllegalAccessException;
method public java.lang.invoke.MethodHandle unreflect(java.lang.reflect.Method) throws java.lang.IllegalAccessException;
method public java.lang.invoke.MethodHandle unreflectConstructor(java.lang.reflect.Constructor<?>) throws java.lang.IllegalAccessException;
method public java.lang.invoke.MethodHandle unreflectGetter(java.lang.reflect.Field) throws java.lang.IllegalAccessException;
@@ -56312,6 +56429,22 @@
method public java.lang.invoke.MethodType wrap();
}
+ public class MutableCallSite extends java.lang.invoke.CallSite {
+ ctor public MutableCallSite(java.lang.invoke.MethodType);
+ ctor public MutableCallSite(java.lang.invoke.MethodHandle);
+ method public final java.lang.invoke.MethodHandle dynamicInvoker();
+ method public final java.lang.invoke.MethodHandle getTarget();
+ method public void setTarget(java.lang.invoke.MethodHandle);
+ }
+
+ public class VolatileCallSite extends java.lang.invoke.CallSite {
+ ctor public VolatileCallSite(java.lang.invoke.MethodType);
+ ctor public VolatileCallSite(java.lang.invoke.MethodHandle);
+ method public final java.lang.invoke.MethodHandle dynamicInvoker();
+ method public final java.lang.invoke.MethodHandle getTarget();
+ method public void setTarget(java.lang.invoke.MethodHandle);
+ }
+
public class WrongMethodTypeException extends java.lang.RuntimeException {
ctor public WrongMethodTypeException();
ctor public WrongMethodTypeException(java.lang.String);
diff --git a/api/test-current.txt b/api/test-current.txt
index c650872..7aaab5b 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -8199,6 +8199,7 @@
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";
@@ -8565,6 +8566,7 @@
field public static final java.lang.String ACTION_CALL = "android.intent.action.CALL";
field public static final java.lang.String ACTION_CALL_BUTTON = "android.intent.action.CALL_BUTTON";
field public static final java.lang.String ACTION_CAMERA_BUTTON = "android.intent.action.CAMERA_BUTTON";
+ field public static final java.lang.String ACTION_CARRIER_SETUP = "android.intent.action.CARRIER_SETUP";
field public static final java.lang.String ACTION_CHOOSER = "android.intent.action.CHOOSER";
field public static final java.lang.String ACTION_CLOSE_SYSTEM_DIALOGS = "android.intent.action.CLOSE_SYSTEM_DIALOGS";
field public static final java.lang.String ACTION_CONFIGURATION_CHANGED = "android.intent.action.CONFIGURATION_CHANGED";
@@ -23796,6 +23798,68 @@
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 ALGO_AUTH_HMAC_MD5 = "hmac(md5)";
+ field public static final java.lang.String ALGO_AUTH_HMAC_SHA1 = "hmac(sha1)";
+ field public static final java.lang.String ALGO_AUTH_HMAC_SHA256 = "hmac(sha256)";
+ field public static final java.lang.String ALGO_AUTH_HMAC_SHA384 = "hmac(sha384)";
+ field public static final java.lang.String ALGO_AUTH_HMAC_SHA512 = "hmac(sha512)";
+ field public static final java.lang.String ALGO_CRYPT_AES_CBC = "cbc(aes)";
+ field public static final android.os.Parcelable.Creator<android.net.IpSecAlgorithm> CREATOR;
+ }
+
+ 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 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 android.net.IpSecManager.SecurityParameterIndex reserveSecurityParameterIndex(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, 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();
@@ -24810,11 +24874,14 @@
}
public static final class WifiEnterpriseConfig.Phase2 {
+ field public static final int AKA = 6; // 0x6
+ field public static final int AKA_PRIME = 7; // 0x7
field public static final int GTC = 4; // 0x4
field public static final int MSCHAP = 2; // 0x2
field public static final int MSCHAPV2 = 3; // 0x3
field public static final int NONE = 0; // 0x0
field public static final int PAP = 1; // 0x1
+ field public static final int SIM = 5; // 0x5
}
public class WifiInfo implements android.os.Parcelable {
@@ -24985,8 +25052,6 @@
public class DiscoverySession {
method public java.lang.String createNetworkSpecifier(android.net.wifi.aware.PeerHandle, byte[]);
method public void destroy();
- method public static int getMaxSendRetryCount();
- method public void sendMessage(android.net.wifi.aware.PeerHandle, int, byte[], int);
method public void sendMessage(android.net.wifi.aware.PeerHandle, int, byte[]);
}
@@ -25100,7 +25165,7 @@
method public java.lang.String getSubscriptionType();
method public android.net.wifi.hotspot2.pps.UpdateParameter getSubscriptionUpdate();
method public java.util.Map<java.lang.String, byte[]> getTrustRootCertList();
- method public int getUpdateIdentififer();
+ method public int getUpdateIdentifier();
method public long getUsageLimitDataLimit();
method public long getUsageLimitStartTimeInMs();
method public long getUsageLimitTimeLimitInMinutes();
@@ -25142,7 +25207,7 @@
method public int describeContents();
method public java.security.cert.X509Certificate getCaCertificate();
method public android.net.wifi.hotspot2.pps.Credential.CertificateCredential getCertCredential();
- method public boolean getCheckAaaServerStatus();
+ method public boolean getCheckAaaServerCertStatus();
method public java.security.cert.X509Certificate[] getClientCertificateChain();
method public java.security.PrivateKey getClientPrivateKey();
method public long getCreationTimeInMs();
@@ -25223,7 +25288,7 @@
method public java.util.Map<java.lang.String, java.lang.Long> getHomeNetworkIds();
method public java.lang.String getIconUrl();
method public long[] getMatchAllOis();
- method public long[] getMatchAnysOis();
+ method public long[] getMatchAnyOis();
method public java.lang.String[] getOtherHomePartners();
method public long[] getRoamingConsortiumOis();
method public void setFqdn(java.lang.String);
@@ -25245,7 +25310,7 @@
method public int describeContents();
method public java.lang.String[] getExcludedSsidList();
method public int getMaximumBssLoadValue();
- method public long getMinHomeDownlinkBandWidht();
+ method public long getMinHomeDownlinkBandwidth();
method public long getMinHomeUplinkBandwidth();
method public long getMinRoamingDownlinkBandwidth();
method public long getMinRoamingUplinkBandwidth();
@@ -36660,9 +36725,11 @@
method public android.telecom.Call.Details getDetails();
method public android.telecom.Call getParent();
method public java.lang.String getRemainingPostDialSequence();
+ method public android.telecom.Call.RttCall getRttCall();
method public int getState();
method public android.telecom.InCallService.VideoCall getVideoCall();
method public void hold();
+ method public boolean isRttActive();
method public void mergeConference();
method public void phoneAccountSelected(android.telecom.PhoneAccountHandle, boolean);
method public void playDtmfTone(char);
@@ -36674,9 +36741,12 @@
method public void reject(boolean, java.lang.String);
method public final void removeExtras(java.util.List<java.lang.String>);
method public final void removeExtras(java.lang.String...);
+ method public void respondToRttRequest(int, boolean);
method public void sendCallEvent(java.lang.String, android.os.Bundle);
+ method public void sendRttRequest();
method public void splitFromConference();
method public void stopDtmfTone();
+ method public void stopRtt();
method public void swapConference();
method public void unhold();
method public void unregisterCallback(android.telecom.Call.Callback);
@@ -36703,6 +36773,9 @@
method public void onDetailsChanged(android.telecom.Call, android.telecom.Call.Details);
method public void onParentChanged(android.telecom.Call, android.telecom.Call);
method public void onPostDialWait(android.telecom.Call, java.lang.String);
+ method public void onRttModeChanged(android.telecom.Call, int);
+ method public void onRttRequest(android.telecom.Call, int);
+ method public void onRttStatusChanged(android.telecom.Call, boolean, android.telecom.Call.RttCall);
method public void onStateChanged(android.telecom.Call, int);
method public void onVideoCallChanged(android.telecom.Call, android.telecom.InCallService.VideoCall);
}
@@ -36757,6 +36830,16 @@
field public static final int PROPERTY_WIFI = 8; // 0x8
}
+ public static final class Call.RttCall {
+ method public int getRttAudioMode();
+ method public java.lang.String read();
+ method public void setRttMode(int);
+ method public void write(java.lang.String) throws java.io.IOException;
+ field public static final int RTT_MODE_FULL = 1; // 0x1
+ field public static final int RTT_MODE_HCO = 2; // 0x2
+ field public static final int RTT_MODE_VCO = 3; // 0x3
+ }
+
public final class CallAudioState implements android.os.Parcelable {
ctor public CallAudioState(boolean, int, int);
method public static java.lang.String audioRouteToString(int);
@@ -37128,6 +37211,7 @@
field public static final int CAPABILITY_CALL_SUBJECT = 64; // 0x40
field public static final int CAPABILITY_CONNECTION_MANAGER = 1; // 0x1
field public static final int CAPABILITY_PLACE_EMERGENCY_CALLS = 16; // 0x10
+ field public static final int CAPABILITY_RTT = 4096; // 0x1000
field public static final int CAPABILITY_SELF_MANAGED = 2048; // 0x800
field public static final int CAPABILITY_SIM_SUBSCRIPTION = 4; // 0x4
field public static final int CAPABILITY_SUPPORTS_VIDEO_CALLING = 1024; // 0x400
@@ -37341,6 +37425,7 @@
field public static final java.lang.String EXTRA_NOTIFICATION_PHONE_NUMBER = "android.telecom.extra.NOTIFICATION_PHONE_NUMBER";
field public static final java.lang.String EXTRA_OUTGOING_CALL_EXTRAS = "android.telecom.extra.OUTGOING_CALL_EXTRAS";
field public static final java.lang.String EXTRA_PHONE_ACCOUNT_HANDLE = "android.telecom.extra.PHONE_ACCOUNT_HANDLE";
+ field public static final java.lang.String EXTRA_START_CALL_WITH_RTT = "android.telecom.extra.START_CALL_WITH_RTT";
field public static final java.lang.String EXTRA_START_CALL_WITH_SPEAKERPHONE = "android.telecom.extra.START_CALL_WITH_SPEAKERPHONE";
field public static final java.lang.String EXTRA_START_CALL_WITH_VIDEO_STATE = "android.telecom.extra.START_CALL_WITH_VIDEO_STATE";
field public static final java.lang.String GATEWAY_ORIGINAL_ADDRESS = "android.telecom.extra.GATEWAY_ORIGINAL_ADDRESS";
@@ -37495,6 +37580,7 @@
field public static final java.lang.String KEY_SHOW_ONSCREEN_DIAL_BUTTON_BOOL = "show_onscreen_dial_button_bool";
field public static final java.lang.String KEY_SIMPLIFIED_NETWORK_SETTINGS_BOOL = "simplified_network_settings_bool";
field public static final java.lang.String KEY_SIM_NETWORK_UNLOCK_ALLOW_DISMISS_BOOL = "sim_network_unlock_allow_dismiss_bool";
+ field public static final java.lang.String KEY_SUPPORT_3GPP_CALL_FORWARDING_WHILE_ROAMING_BOOL = "support_3gpp_call_forwarding_while_roaming_bool";
field public static final java.lang.String KEY_SUPPORT_CONFERENCE_CALL_BOOL = "support_conference_call_bool";
field public static final java.lang.String KEY_SUPPORT_PAUSE_IMS_VIDEO_CALLS_BOOL = "support_pause_ims_video_calls_bool";
field public static final java.lang.String KEY_SUPPORT_SWAP_AFTER_MERGE_BOOL = "support_swap_after_merge_bool";
@@ -38014,6 +38100,7 @@
method public java.lang.String getDeviceId();
method public java.lang.String getDeviceId(int);
method public java.lang.String getDeviceSoftwareVersion();
+ method public java.lang.String[] getForbiddenPlmns();
method public java.lang.String getGroupIdLevel1();
method public java.lang.String getIccAuthentication(int, int, java.lang.String);
method public java.lang.String getLine1Number();
@@ -38821,7 +38908,7 @@
package android.test.suitebuilder {
- public class TestMethod {
+ public deprecated class TestMethod {
ctor public TestMethod(java.lang.reflect.Method, java.lang.Class<? extends junit.framework.TestCase>);
ctor public TestMethod(java.lang.String, java.lang.Class<? extends junit.framework.TestCase>);
ctor public TestMethod(junit.framework.TestCase);
@@ -38832,7 +38919,7 @@
method public java.lang.String getName();
}
- public class TestSuiteBuilder {
+ public deprecated class TestSuiteBuilder {
ctor public TestSuiteBuilder(java.lang.Class);
ctor public TestSuiteBuilder(java.lang.String, java.lang.ClassLoader);
method public android.test.suitebuilder.TestSuiteBuilder addRequirements(java.util.List<com.android.internal.util.Predicate<android.test.suitebuilder.TestMethod>>);
@@ -38845,7 +38932,7 @@
method public android.test.suitebuilder.TestSuiteBuilder named(java.lang.String);
}
- public static class TestSuiteBuilder.FailedToCreateTests extends junit.framework.TestCase {
+ public static deprecated class TestSuiteBuilder.FailedToCreateTests extends junit.framework.TestCase {
ctor public TestSuiteBuilder.FailedToCreateTests(java.lang.Exception);
method public void testSuiteConstructionFailed();
}
@@ -49222,7 +49309,7 @@
package com.android.internal.util {
- public abstract interface Predicate<T> {
+ public abstract deprecated interface Predicate<T> {
method public abstract boolean apply(T);
}
@@ -49360,6 +49447,8 @@
field public static final int OP_INT_TO_FLOAT = 130; // 0x82
field public static final int OP_INT_TO_LONG = 129; // 0x81
field public static final int OP_INT_TO_SHORT = 143; // 0x8f
+ field public static final int OP_INVOKE_CUSTOM = 252; // 0xfc
+ field public static final int OP_INVOKE_CUSTOM_RANGE = 253; // 0xfd
field public static final int OP_INVOKE_DIRECT = 112; // 0x70
field public static final deprecated int OP_INVOKE_DIRECT_EMPTY = 240; // 0xf0
field public static final int OP_INVOKE_DIRECT_JUMBO = 9471; // 0x24ff
@@ -49550,7 +49639,7 @@
method public static dalvik.system.DexFile loadDex(java.lang.String, java.lang.String, int) throws java.io.IOException;
}
- public final class InMemoryDexClassLoader extends java.lang.ClassLoader {
+ public final class InMemoryDexClassLoader extends dalvik.system.BaseDexClassLoader {
ctor public InMemoryDexClassLoader(java.nio.ByteBuffer, java.lang.ClassLoader);
}
@@ -50768,6 +50857,13 @@
field public static final java.lang.Class<java.lang.Boolean> TYPE;
}
+ public class BootstrapMethodError extends java.lang.LinkageError {
+ ctor public BootstrapMethodError();
+ ctor public BootstrapMethodError(java.lang.String);
+ ctor public BootstrapMethodError(java.lang.String, java.lang.Throwable);
+ ctor public BootstrapMethodError(java.lang.Throwable);
+ }
+
public final class Byte extends java.lang.Number implements java.lang.Comparable {
ctor public Byte(byte);
ctor public Byte(java.lang.String) throws java.lang.NumberFormatException;
@@ -52654,6 +52750,21 @@
package java.lang.invoke {
+ public abstract class CallSite {
+ method public abstract java.lang.invoke.MethodHandle dynamicInvoker();
+ method public abstract java.lang.invoke.MethodHandle getTarget();
+ method public abstract void setTarget(java.lang.invoke.MethodHandle);
+ method public java.lang.invoke.MethodType type();
+ }
+
+ public class ConstantCallSite extends java.lang.invoke.CallSite {
+ ctor public ConstantCallSite(java.lang.invoke.MethodHandle);
+ ctor protected ConstantCallSite(java.lang.invoke.MethodType, java.lang.invoke.MethodHandle) throws java.lang.Throwable;
+ method public final java.lang.invoke.MethodHandle dynamicInvoker();
+ method public final java.lang.invoke.MethodHandle getTarget();
+ method public final void setTarget(java.lang.invoke.MethodHandle);
+ }
+
public class LambdaConversionException extends java.lang.Exception {
ctor public LambdaConversionException();
ctor public LambdaConversionException(java.lang.String);
@@ -52739,7 +52850,6 @@
method public java.lang.Class<?> lookupClass();
method public int lookupModes();
method public java.lang.invoke.MethodHandleInfo revealDirect(java.lang.invoke.MethodHandle);
- method public void throwMakeAccessException(java.lang.String, java.lang.Object) throws java.lang.IllegalAccessException;
method public java.lang.invoke.MethodHandle unreflect(java.lang.reflect.Method) throws java.lang.IllegalAccessException;
method public java.lang.invoke.MethodHandle unreflectConstructor(java.lang.reflect.Constructor<?>) throws java.lang.IllegalAccessException;
method public java.lang.invoke.MethodHandle unreflectGetter(java.lang.reflect.Field) throws java.lang.IllegalAccessException;
@@ -52782,6 +52892,22 @@
method public java.lang.invoke.MethodType wrap();
}
+ public class MutableCallSite extends java.lang.invoke.CallSite {
+ ctor public MutableCallSite(java.lang.invoke.MethodType);
+ ctor public MutableCallSite(java.lang.invoke.MethodHandle);
+ method public final java.lang.invoke.MethodHandle dynamicInvoker();
+ method public final java.lang.invoke.MethodHandle getTarget();
+ method public void setTarget(java.lang.invoke.MethodHandle);
+ }
+
+ public class VolatileCallSite extends java.lang.invoke.CallSite {
+ ctor public VolatileCallSite(java.lang.invoke.MethodType);
+ ctor public VolatileCallSite(java.lang.invoke.MethodHandle);
+ method public final java.lang.invoke.MethodHandle dynamicInvoker();
+ method public final java.lang.invoke.MethodHandle getTarget();
+ method public void setTarget(java.lang.invoke.MethodHandle);
+ }
+
public class WrongMethodTypeException extends java.lang.RuntimeException {
ctor public WrongMethodTypeException();
ctor public WrongMethodTypeException(java.lang.String);
diff --git a/cmds/svc/src/com/android/commands/svc/UsbCommand.java b/cmds/svc/src/com/android/commands/svc/UsbCommand.java
index 4dcb05e..adbe9d0 100644
--- a/cmds/svc/src/com/android/commands/svc/UsbCommand.java
+++ b/cmds/svc/src/com/android/commands/svc/UsbCommand.java
@@ -36,8 +36,8 @@
public String longHelp() {
return shortHelp() + "\n"
+ "\n"
- + "usage: svc usb setFunction [function]\n"
- + " Set the current usb function.\n\n"
+ + "usage: svc usb setFunction [function] [usbDataUnlocked=false]\n"
+ + " Set the current usb function and optionally the data lock state.\n\n"
+ " svc usb getFunction\n"
+ " Gets the list of currently enabled functions\n";
}
@@ -49,8 +49,12 @@
if ("setFunction".equals(args[1])) {
IUsbManager usbMgr = IUsbManager.Stub.asInterface(ServiceManager.getService(
Context.USB_SERVICE));
+ boolean unlockData = false;
+ if (args.length >= 4) {
+ unlockData = Boolean.valueOf(args[3]);
+ }
try {
- usbMgr.setCurrentFunction((args.length >=3 ? args[2] : null), false);
+ usbMgr.setCurrentFunction((args.length >=3 ? args[2] : null), unlockData);
} catch (RemoteException e) {
System.err.println("Error communicating with UsbManager: " + e);
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index cae4be6..c7fc860 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -974,6 +974,10 @@
sendMessage(H.DUMP_HEAP, dhd, managed ? 1 : 0, 0, true /*async*/);
}
+ public void attachAgent(String agent) {
+ sendMessage(H.ATTACH_AGENT, agent);
+ }
+
public void setSchedulingGroup(int group) {
// Note: do this immediately, since going into the foreground
// should happen regardless of what pending work we have to do
@@ -1408,6 +1412,7 @@
public static final int MULTI_WINDOW_MODE_CHANGED = 152;
public static final int PICTURE_IN_PICTURE_MODE_CHANGED = 153;
public static final int LOCAL_VOICE_INTERACTION_STARTED = 154;
+ public static final int ATTACH_AGENT = 155;
String codeToString(int code) {
if (DEBUG_MESSAGES) {
@@ -1464,6 +1469,7 @@
case MULTI_WINDOW_MODE_CHANGED: return "MULTI_WINDOW_MODE_CHANGED";
case PICTURE_IN_PICTURE_MODE_CHANGED: return "PICTURE_IN_PICTURE_MODE_CHANGED";
case LOCAL_VOICE_INTERACTION_STARTED: return "LOCAL_VOICE_INTERACTION_STARTED";
+ case ATTACH_AGENT: return "ATTACH_AGENT";
}
}
return Integer.toString(code);
@@ -1719,6 +1725,9 @@
handleLocalVoiceInteractionStarted((IBinder) ((SomeArgs) msg.obj).arg1,
(IVoiceInteractor) ((SomeArgs) msg.obj).arg2);
break;
+ case ATTACH_AGENT:
+ handleAttachAgent((String) msg.obj);
+ break;
}
Object obj = msg.obj;
if (obj instanceof SomeArgs) {
@@ -2987,6 +2996,14 @@
}
}
+ static final void handleAttachAgent(String agent) {
+ try {
+ VMDebug.attachAgent(agent);
+ } catch (IOException e) {
+ Slog.e(TAG, "Attaching agent failed: " + agent);
+ }
+ }
+
private static final ThreadLocal<Intent> sCurrentBroadcastIntent = new ThreadLocal<Intent>();
/**
diff --git a/core/java/android/app/ApplicationThreadNative.java b/core/java/android/app/ApplicationThreadNative.java
index 05d9d7e..ad7f577 100644
--- a/core/java/android/app/ApplicationThreadNative.java
+++ b/core/java/android/app/ApplicationThreadNative.java
@@ -502,6 +502,14 @@
return true;
}
+ case ATTACH_AGENT_TRANSACTION:
+ {
+ data.enforceInterface(IApplicationThread.descriptor);
+ String agent = data.readString();
+ attachAgent(agent);
+ return true;
+ }
+
case DUMP_ACTIVITY_TRANSACTION: {
data.enforceInterface(IApplicationThread.descriptor);
ParcelFileDescriptor fd = data.readFileDescriptor();
@@ -1305,6 +1313,14 @@
data.recycle();
}
+ public void attachAgent(String agent) throws RemoteException {
+ Parcel data = Parcel.obtain();
+ data.writeInterfaceToken(IApplicationThread.descriptor);
+ data.writeString(agent);
+ mRemote.transact(ATTACH_AGENT_TRANSACTION, data, null, IBinder.FLAG_ONEWAY);
+ data.recycle();
+ }
+
public void setCoreSettings(Bundle coreSettings) throws RemoteException {
Parcel data = Parcel.obtain();
data.writeInterfaceToken(IApplicationThread.descriptor);
diff --git a/core/java/android/app/IApplicationThread.java b/core/java/android/app/IApplicationThread.java
index 3fa88ae..bfd97f8 100644
--- a/core/java/android/app/IApplicationThread.java
+++ b/core/java/android/app/IApplicationThread.java
@@ -123,6 +123,7 @@
throws RemoteException;
void dumpHeap(boolean managed, String path, ParcelFileDescriptor fd)
throws RemoteException;
+ void attachAgent(String path) throws RemoteException;
void setSchedulingGroup(int group) throws RemoteException;
// the package has been removed, clean up internal references
static final int PACKAGE_REMOVED = 0;
@@ -225,4 +226,5 @@
int SCHEDULE_MULTI_WINDOW_CHANGED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+58;
int SCHEDULE_PICTURE_IN_PICTURE_CHANGED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+59;
int SCHEDULE_LOCAL_VOICE_INTERACTION_STARTED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+60;
+ int ATTACH_AGENT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+61;
}
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index afe9651..e00a7f0 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -266,7 +266,7 @@
setApplicationInfo(aInfo);
final List<String> newPaths = new ArrayList<>();
- makePaths(mActivityThread, aInfo, newPaths, null /*libPaths*/);
+ makePaths(mActivityThread, aInfo, newPaths);
final List<String> addedPaths = new ArrayList<>(newPaths.size());
if (oldPaths != null) {
@@ -314,8 +314,17 @@
mCredentialProtectedDataDirFile = FileUtils.newFileOrNull(aInfo.credentialProtectedDataDir);
}
- public static void makePaths(ActivityThread activityThread, ApplicationInfo aInfo,
- List<String> outZipPaths, List<String> outLibPaths) {
+ public static void makePaths(ActivityThread activityThread,
+ ApplicationInfo aInfo,
+ List<String> outZipPaths) {
+ makePaths(activityThread, false, aInfo, outZipPaths, null);
+ }
+
+ public static void makePaths(ActivityThread activityThread,
+ boolean isBundledApp,
+ ApplicationInfo aInfo,
+ List<String> outZipPaths,
+ List<String> outLibPaths) {
final String appDir = aInfo.sourceDir;
final String[] splitAppDirs = aInfo.splitSourceDirs;
final String libDir = aInfo.nativeLibraryDir;
@@ -398,7 +407,7 @@
}
}
- if (aInfo.isSystemApp() && !aInfo.isUpdatedSystemApp()) {
+ if (isBundledApp) {
// Add path to system libraries to libPaths;
// Access to system libs should be limited
// to bundled applications; this is why updated
@@ -471,11 +480,12 @@
// space and initialize to a small value (instead of incurring growth code).
final List<String> zipPaths = new ArrayList<>(10);
final List<String> libPaths = new ArrayList<>(10);
- makePaths(mActivityThread, mApplicationInfo, zipPaths, libPaths);
final boolean isBundledApp = mApplicationInfo.isSystemApp()
&& !mApplicationInfo.isUpdatedSystemApp();
+ makePaths(mActivityThread, isBundledApp, mApplicationInfo, zipPaths, libPaths);
+
String libraryPermittedPath = mDataDir;
if (isBundledApp) {
// This is necessary to grant bundled apps access to
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 02b86fe..46d3835 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -2662,6 +2662,7 @@
VIBRATOR_SERVICE,
//@hide: STATUS_BAR_SERVICE,
CONNECTIVITY_SERVICE,
+ IPSEC_SERVICE,
//@hide: UPDATE_LOCK_SERVICE,
//@hide: NETWORKMANAGEMENT_SERVICE,
NETWORK_STATS_SERVICE,
@@ -2763,6 +2764,9 @@
* <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
@@ -3093,6 +3097,15 @@
public static final String CONNECTIVITY_SERVICE = "connectivity";
/**
+ * Use with {@link #getSystemService} to retrieve a
+ * {@link android.net.IpSecManager} for encrypting Sockets or Networks with
+ * IPSec.
+ *
+ * @see #getSystemService
+ */
+ public static final String IPSEC_SERVICE = "ipsec";
+
+ /**
* Use with {@link #getSystemService} to retrieve a {@link
* android.os.IUpdateLock} for managing runtime sequences that
* must not be interrupted by headless OTA application or similar.
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index c6aaa48..b7876d9 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1096,6 +1096,15 @@
public static final String ACTION_SIM_ACTIVATION_REQUEST =
"android.intent.action.SIM_ACTIVATION_REQUEST";
/**
+ * Activity Action: Main entry point for carrier setup apps.
+ * <p>Carrier apps that provide an implementation for this action may be invoked to configure
+ * carrier service and typically require
+ * {@link android.telephony.TelephonyManager#hasCarrierPrivileges() carrier privileges} to
+ * fulfill their duties.
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_CARRIER_SETUP = "android.intent.action.CARRIER_SETUP";
+ /**
* Activity Action: Send a message to someone specified by the data.
* <p>Input: {@link #getData} is URI describing the target.
* <p>Output: nothing.
diff --git a/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java b/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
index bb0a042..5423ca9 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
@@ -646,7 +646,7 @@
// Special case where the only scene mode listed is AUTO => no scene mode
if (sceneModes != null && sceneModes.size() == 1 &&
- sceneModes.get(0) == Parameters.SCENE_MODE_AUTO) {
+ sceneModes.get(0).equals(Parameters.SCENE_MODE_AUTO)) {
supportedSceneModes = null;
}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 82e3093..30afdc2 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -1421,8 +1421,8 @@
l.networkCapabilities = netCap;
l.delay = delay;
l.expireSequenceNumber = 0;
- l.networkRequest = sendRequestForNetwork(netCap, l.networkCallback, 0,
- REQUEST, type);
+ l.networkRequest = sendRequestForNetwork(
+ netCap, l.networkCallback, 0, REQUEST, type, getDefaultHandler());
if (l.networkRequest == null) return null;
sLegacyRequests.put(netCap, l);
sendExpireMsgForFeature(netCap, l.expireSequenceNumber, delay);
@@ -1432,8 +1432,9 @@
private void sendExpireMsgForFeature(NetworkCapabilities netCap, int seqNum, int delay) {
if (delay >= 0) {
Log.d(TAG, "sending expire msg with seqNum " + seqNum + " and delay " + delay);
- Message msg = sCallbackHandler.obtainMessage(EXPIRE_LEGACY_REQUEST, seqNum, 0, netCap);
- sCallbackHandler.sendMessageDelayed(msg, delay);
+ CallbackHandler handler = getDefaultHandler();
+ Message msg = handler.obtainMessage(EXPIRE_LEGACY_REQUEST, seqNum, 0, netCap);
+ handler.sendMessageDelayed(msg, delay);
}
}
@@ -2750,6 +2751,10 @@
super(looper);
}
+ CallbackHandler(Handler handler) {
+ this(handler.getLooper());
+ }
+
@Override
public void handleMessage(Message message) {
NetworkRequest request = getObject(message, NetworkRequest.class);
@@ -2859,7 +2864,7 @@
}
}
- private CallbackHandler getHandler() {
+ private CallbackHandler getDefaultHandler() {
synchronized (sCallbacks) {
if (sCallbackHandler == null) {
sCallbackHandler = new CallbackHandler(ConnectivityThread.getInstanceLooper());
@@ -2868,19 +2873,14 @@
}
}
- static final HashMap<NetworkRequest, NetworkCallback> sCallbacks = new HashMap<>();
- static CallbackHandler sCallbackHandler;
+ private static final HashMap<NetworkRequest, NetworkCallback> sCallbacks = new HashMap<>();
+ private static CallbackHandler sCallbackHandler;
- private final static int LISTEN = 1;
- private final static int REQUEST = 2;
+ private static final int LISTEN = 1;
+ private static final int REQUEST = 2;
- private NetworkRequest sendRequestForNetwork(NetworkCapabilities need,
- NetworkCallback callback, int timeoutMs, int action, int legacyType) {
- return sendRequestForNetwork(need, callback, getHandler(), timeoutMs, action, legacyType);
- }
-
- private NetworkRequest sendRequestForNetwork(NetworkCapabilities need,
- NetworkCallback callback, Handler handler, int timeoutMs, int action, int legacyType) {
+ private NetworkRequest sendRequestForNetwork(NetworkCapabilities need, NetworkCallback callback,
+ int timeoutMs, int action, int legacyType, CallbackHandler handler) {
if (callback == null) {
throw new IllegalArgumentException("null NetworkCallback");
}
@@ -2923,9 +2923,10 @@
* @hide
*/
public void requestNetwork(NetworkRequest request, NetworkCallback networkCallback,
- int timeoutMs, int legacyType) {
- sendRequestForNetwork(request.networkCapabilities, networkCallback, timeoutMs, REQUEST,
- legacyType);
+ int timeoutMs, int legacyType, Handler handler) {
+ CallbackHandler cbHandler = new CallbackHandler(handler);
+ NetworkCapabilities nc = request.networkCapabilities;
+ sendRequestForNetwork(nc, networkCallback, timeoutMs, REQUEST, legacyType, cbHandler);
}
/**
@@ -2951,15 +2952,51 @@
* {@link android.provider.Settings.System#canWrite}.</p>
*
* @param request {@link NetworkRequest} describing this request.
- * @param networkCallback The {@link NetworkCallback} to be utilized for this
- * request. Note the callback must not be shared - they
- * uniquely specify this request.
+ * @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note
+ * the callback must not be shared - it uniquely specifies this request.
+ * The callback is invoked on the default internal Handler.
* @throws IllegalArgumentException if {@code request} specifies any mutable
* {@code NetworkCapabilities}.
*/
public void requestNetwork(NetworkRequest request, NetworkCallback networkCallback) {
- requestNetwork(request, networkCallback, 0,
- inferLegacyTypeForNetworkCapabilities(request.networkCapabilities));
+ requestNetwork(request, networkCallback, getDefaultHandler());
+ }
+
+ /**
+ * Request a network to satisfy a set of {@link android.net.NetworkCapabilities}.
+ *
+ * This {@link NetworkRequest} will live until released via
+ * {@link #unregisterNetworkCallback(NetworkCallback)} or the calling application exits.
+ * Status of the request can be followed by listening to the various
+ * callbacks described in {@link NetworkCallback}. The {@link Network}
+ * can be used to direct traffic to the network.
+ * <p>It is presently unsupported to request a network with mutable
+ * {@link NetworkCapabilities} such as
+ * {@link NetworkCapabilities#NET_CAPABILITY_VALIDATED} or
+ * {@link NetworkCapabilities#NET_CAPABILITY_CAPTIVE_PORTAL}
+ * as these {@code NetworkCapabilities} represent states that a particular
+ * network may never attain, and whether a network will attain these states
+ * is unknown prior to bringing up the network so the framework does not
+ * know how to go about satisfing a request with these capabilities.
+ *
+ * <p>This method requires the caller to hold either the
+ * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission
+ * or the ability to modify system settings as determined by
+ * {@link android.provider.Settings.System#canWrite}.</p>
+ *
+ * @param request {@link NetworkRequest} describing this request.
+ * @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note
+ * the callback must not be shared - it uniquely specifies this request.
+ * @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
+ * @throws IllegalArgumentException if {@code request} specifies any mutable
+ * {@code NetworkCapabilities}.
+ * @hide
+ */
+ public void requestNetwork(
+ NetworkRequest request, NetworkCallback networkCallback, Handler handler) {
+ int legacyType = inferLegacyTypeForNetworkCapabilities(request.networkCapabilities);
+ CallbackHandler cbHandler = new CallbackHandler(handler);
+ requestNetwork(request, networkCallback, 0, legacyType, cbHandler);
}
/**
@@ -2968,7 +3005,36 @@
*
* This function behaves identically to the non-timedout version, but if a suitable
* network is not found within the given time (in milliseconds) the
- * {@link NetworkCallback#unavailable} callback is called. The request must
+ * {@link NetworkCallback#onUnavailable()} callback is called. The request must
+ * still be released normally by calling {@link #unregisterNetworkCallback(NetworkCallback)}.
+ *
+ * <p>This method requires the caller to hold either the
+ * {@link android.Manifest.permission#CHANGE_NETWORK_STATE} permission
+ * or the ability to modify system settings as determined by
+ * {@link android.provider.Settings.System#canWrite}.</p>
+ *
+ * @param request {@link NetworkRequest} describing this request.
+ * @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note
+ * the callback must not be shared - it uniquely specifies this request.
+ * The callback is invoked on the default internal Handler.
+ * @param timeoutMs The time in milliseconds to attempt looking for a suitable network
+ * before {@link NetworkCallback#onUnavailable()} is called.
+ * @hide
+ */
+ public void requestNetwork(NetworkRequest request, NetworkCallback networkCallback,
+ int timeoutMs) {
+ int legacyType = inferLegacyTypeForNetworkCapabilities(request.networkCapabilities);
+ requestNetwork(request, networkCallback, timeoutMs, legacyType, getDefaultHandler());
+ }
+
+
+ /**
+ * Request a network to satisfy a set of {@link android.net.NetworkCapabilities}, limited
+ * by a timeout.
+ *
+ * This function behaves identically to the non-timedout version, but if a suitable
+ * network is not found within the given time (in milliseconds) the
+ * {@link NetworkCallback#onUnavailable} callback is called. The request must
* still be released normally by calling {@link unregisterNetworkCallback(NetworkCallback)}.
*
* <p>This method requires the caller to hold either the
@@ -2977,30 +3043,22 @@
* {@link android.provider.Settings.System#canWrite}.</p>
*
* @param request {@link NetworkRequest} describing this request.
- * @param networkCallback The callbacks to be utilized for this request. Note
- * the callbacks must not be shared - they uniquely specify
- * this request.
+ * @param networkCallback The {@link NetworkCallback} to be utilized for this request. Note
+ * the callback must not be shared - it uniquely specifies this request.
* @param timeoutMs The time in milliseconds to attempt looking for a suitable network
- * before {@link NetworkCallback#unavailable} is called.
- *
- * TODO: Make timeouts work and then unhide this method.
+ * before {@link NetworkCallback#onUnavailable} is called.
+ * @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
*
* @hide
*/
public void requestNetwork(NetworkRequest request, NetworkCallback networkCallback,
- int timeoutMs) {
- requestNetwork(request, networkCallback, timeoutMs,
- inferLegacyTypeForNetworkCapabilities(request.networkCapabilities));
+ int timeoutMs, Handler handler) {
+ int legacyType = inferLegacyTypeForNetworkCapabilities(request.networkCapabilities);
+ CallbackHandler cbHandler = new CallbackHandler(handler);
+ requestNetwork(request, networkCallback, timeoutMs, legacyType, cbHandler);
}
/**
- * The maximum number of milliseconds the framework will look for a suitable network
- * during a timeout-equiped call to {@link requestNetwork}.
- * {@hide}
- */
- public final static int MAX_NETWORK_REQUEST_TIMEOUT_MS = 100 * 60 * 1000;
-
- /**
* The lookup key for a {@link Network} object included with the intent after
* successfully finding a network for the applications request. Retrieve it with
* {@link android.content.Intent#getParcelableExtra(String)}.
@@ -3111,9 +3169,30 @@
* @param request {@link NetworkRequest} describing this request.
* @param networkCallback The {@link NetworkCallback} that the system will call as suitable
* networks change state.
+ * The callback is invoked on the default internal Handler.
*/
public void registerNetworkCallback(NetworkRequest request, NetworkCallback networkCallback) {
- sendRequestForNetwork(request.networkCapabilities, networkCallback, 0, LISTEN, TYPE_NONE);
+ registerNetworkCallback(request, networkCallback, getDefaultHandler());
+ }
+
+ /**
+ * Registers to receive notifications about all networks which satisfy the given
+ * {@link NetworkRequest}. The callbacks will continue to be called until
+ * either the application exits or link #unregisterNetworkCallback(NetworkCallback)} is called.
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
+ *
+ * @param request {@link NetworkRequest} describing this request.
+ * @param networkCallback The {@link NetworkCallback} that the system will call as suitable
+ * networks change state.
+ * @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
+ * @hide
+ */
+ public void registerNetworkCallback(
+ NetworkRequest request, NetworkCallback networkCallback, Handler handler) {
+ CallbackHandler cbHandler = new CallbackHandler(handler);
+ NetworkCapabilities nc = request.networkCapabilities;
+ sendRequestForNetwork(nc, networkCallback, 0, LISTEN, TYPE_NONE, cbHandler);
}
/**
@@ -3165,8 +3244,25 @@
*
* @param networkCallback The {@link NetworkCallback} that the system will call as the
* system default network changes.
+ * The callback is invoked on the default internal Handler.
*/
public void registerDefaultNetworkCallback(NetworkCallback networkCallback) {
+ registerDefaultNetworkCallback(networkCallback, getDefaultHandler());
+ }
+
+ /**
+ * Registers to receive notifications about changes in the system default network. The callbacks
+ * will continue to be called until either the application exits or
+ * {@link #unregisterNetworkCallback(NetworkCallback)} is called.
+ * <p>This method requires the caller to hold the permission
+ * {@link android.Manifest.permission#ACCESS_NETWORK_STATE}.
+ *
+ * @param networkCallback The {@link NetworkCallback} that the system will call as the
+ * system default network changes.
+ * @param handler {@link Handler} to specify the thread upon which the callback will be invoked.
+ * @hide
+ */
+ public void registerDefaultNetworkCallback(NetworkCallback networkCallback, Handler handler) {
// This works because if the NetworkCapabilities are null,
// ConnectivityService takes them from the default request.
//
@@ -3174,7 +3270,8 @@
// capabilities, this request is guaranteed, at all times, to be
// satisfied by the same network, if any, that satisfies the default
// request, i.e., the system default network.
- sendRequestForNetwork(null, networkCallback, 0, REQUEST, TYPE_NONE);
+ CallbackHandler cbHandler = new CallbackHandler(handler);
+ sendRequestForNetwork(null, networkCallback, 0, REQUEST, TYPE_NONE, cbHandler);
}
/**
diff --git a/core/java/android/net/ConnectivityMetricsLogger.java b/core/java/android/net/ConnectivityMetricsLogger.java
index 9a2d4e0..67b6908 100644
--- a/core/java/android/net/ConnectivityMetricsLogger.java
+++ b/core/java/android/net/ConnectivityMetricsLogger.java
@@ -46,32 +46,7 @@
public static final String DATA_KEY_EVENTS_COUNT = "count";
- /** {@hide} */ protected IConnectivityMetricsLogger mService;
- /** {@hide} */ protected volatile long mServiceUnblockedTimestampMillis;
- private int mNumSkippedEvents;
-
public ConnectivityMetricsLogger() {
- // TODO: consider not initializing mService in constructor
- this(IConnectivityMetricsLogger.Stub.asInterface(
- ServiceManager.getService(CONNECTIVITY_METRICS_LOGGER_SERVICE)));
- }
-
- /** {@hide} */
- @VisibleForTesting
- public ConnectivityMetricsLogger(IConnectivityMetricsLogger service) {
- mService = service;
- }
-
- /** {@hide} */
- protected boolean checkLoggerService() {
- if (mService != null) {
- return true;
- }
- // Two threads racing here will write the same pointer because getService
- // is idempotent once MetricsLoggerService is initialized.
- mService = IConnectivityMetricsLogger.Stub.asInterface(
- ServiceManager.getService(CONNECTIVITY_METRICS_LOGGER_SERVICE));
- return mService != null;
}
/**
@@ -88,62 +63,6 @@
* @param data is a Parcelable instance representing the event.
*/
public void logEvent(long timestamp, int componentTag, int eventTag, Parcelable data) {
- if (mService == null) {
- if (DBG) {
- Log.d(TAG, "logEvent(" + componentTag + "," + eventTag + ") Service not ready");
- }
- return;
- }
-
- if (mServiceUnblockedTimestampMillis > 0) {
- if (System.currentTimeMillis() < mServiceUnblockedTimestampMillis) {
- // Service is throttling events.
- // Don't send new events because they will be dropped.
- mNumSkippedEvents++;
- return;
- }
- }
-
- ConnectivityMetricsEvent skippedEventsEvent = null;
- if (mNumSkippedEvents > 0) {
- // Log number of skipped events
- Bundle b = new Bundle();
- b.putInt(DATA_KEY_EVENTS_COUNT, mNumSkippedEvents);
-
- // Log the skipped event.
- // TODO: Note that some of the clients push all states events into the server,
- // If we lose some states logged here, we might mess up the statistics happened at the
- // backend. One of the options is to introduce a non-skippable flag for important events
- // that are logged.
- skippedEventsEvent = new ConnectivityMetricsEvent(mServiceUnblockedTimestampMillis,
- componentTag, TAG_SKIPPED_EVENTS, b);
-
- mServiceUnblockedTimestampMillis = 0;
- }
-
- ConnectivityMetricsEvent event = new ConnectivityMetricsEvent(timestamp, componentTag,
- eventTag, data);
-
- try {
- long result;
- if (skippedEventsEvent == null) {
- result = mService.logEvent(event);
- } else {
- result = mService.logEvents(new ConnectivityMetricsEvent[]
- {skippedEventsEvent, event});
- }
-
- if (result == 0) {
- mNumSkippedEvents = 0;
- } else {
- mNumSkippedEvents++;
- if (result > 0) { // events are throttled
- mServiceUnblockedTimestampMillis = result;
- }
- }
- } catch (RemoteException e) {
- Log.e(TAG, "Error logging event", e);
- }
}
/**
@@ -157,33 +76,17 @@
* @return events
*/
public ConnectivityMetricsEvent[] getEvents(ConnectivityMetricsEvent.Reference reference) {
- try {
- return mService.getEvents(reference);
- } catch (RemoteException e) {
- Log.e(TAG, "IConnectivityMetricsLogger.getEvents", e);
- return null;
- }
+ return new ConnectivityMetricsEvent[0];
}
/**
* Register PendingIntent which will be sent when new events are ready to be retrieved.
*/
public boolean register(PendingIntent newEventsIntent) {
- try {
- return mService.register(newEventsIntent);
- } catch (RemoteException e) {
- Log.e(TAG, "IConnectivityMetricsLogger.register", e);
- return false;
- }
+ return false;
}
public boolean unregister(PendingIntent newEventsIntent) {
- try {
- mService.unregister(newEventsIntent);
- return true;
- } catch (RemoteException e) {
- Log.e(TAG, "IConnectivityMetricsLogger.unregister", e);
- return false;
- }
+ return false;
}
}
diff --git a/core/java/android/net/IpSecAlgorithm.java b/core/java/android/net/IpSecAlgorithm.java
new file mode 100644
index 0000000..da5cb37
--- /dev/null
+++ b/core/java/android/net/IpSecAlgorithm.java
@@ -0,0 +1,181 @@
+/*
+ * 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 android.annotation.StringDef;
+import android.os.Parcel;
+import android.os.Parcelable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * IpSecAlgorithm specifies a single algorithm that can be applied to an IpSec Transform. Refer to
+ * RFC 4301.
+ */
+public final class IpSecAlgorithm implements Parcelable {
+
+ /**
+ * AES-CBC Encryption/Ciphering Algorithm.
+ *
+ * <p>Valid lengths for this key are {128, 192, 256}.
+ */
+ public static final String ALGO_CRYPT_AES_CBC = "cbc(aes)";
+
+ /**
+ * MD5 HMAC Authentication/Integrity Algorithm. This algorithm is not recommended for use in new
+ * applications and is provided for legacy compatibility with 3gpp infrastructure.
+ *
+ * <p>Valid truncation lengths are multiples of 8 bits from 96 to (default) 128.
+ */
+ public static final String ALGO_AUTH_HMAC_MD5 = "hmac(md5)";
+
+ /**
+ * SHA1 HMAC Authentication/Integrity Algorithm. This algorithm is not recommended for use in
+ * new applications and is provided for legacy compatibility with 3gpp infrastructure.
+ *
+ * <p>Valid truncation lengths are multiples of 8 bits from 96 to (default) 160.
+ */
+ public static final String ALGO_AUTH_HMAC_SHA1 = "hmac(sha1)";
+
+ /**
+ * SHA256 HMAC Authentication/Integrity Algorithm.
+ *
+ * <p>Valid truncation lengths are multiples of 8 bits from 96 to (default) 256.
+ */
+ public static final String ALGO_AUTH_HMAC_SHA256 = "hmac(sha256)";
+
+ /**
+ * SHA384 HMAC Authentication/Integrity Algorithm.
+ *
+ * <p>Valid truncation lengths are multiples of 8 bits from 192 to (default) 384.
+ */
+ public static final String ALGO_AUTH_HMAC_SHA384 = "hmac(sha384)";
+ /**
+ * SHA512 HMAC Authentication/Integrity Algorithm
+ *
+ * <p>Valid truncation lengths are multiples of 8 bits from 256 to (default) 512.
+ */
+ public static final String ALGO_AUTH_HMAC_SHA512 = "hmac(sha512)";
+
+ /** @hide */
+ @StringDef({
+ ALGO_CRYPT_AES_CBC,
+ ALGO_AUTH_HMAC_MD5,
+ ALGO_AUTH_HMAC_SHA1,
+ ALGO_AUTH_HMAC_SHA256,
+ ALGO_AUTH_HMAC_SHA512
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface AlgorithmName {}
+
+ private final String mName;
+ private final byte[] mKey;
+ private final int mTruncLenBits;
+
+ /**
+ * Specify a IpSecAlgorithm of one of the supported types including the truncation length of the
+ * algorithm
+ *
+ * @param algorithm type for IpSec.
+ * @param key non-null Key padded to a multiple of 8 bits.
+ */
+ public IpSecAlgorithm(String algorithm, byte[] key) {
+ this(algorithm, key, key.length * 8);
+ }
+
+ /**
+ * Specify a IpSecAlgorithm of one of the supported types including the truncation length of the
+ * algorithm
+ *
+ * @param algoName precise name of the algorithm to be used.
+ * @param key non-null Key padded to a multiple of 8 bits.
+ * @param truncLenBits the number of bits of output hash to use; only meaningful for
+ * Authentication.
+ */
+ public IpSecAlgorithm(@AlgorithmName String algoName, byte[] key, int truncLenBits) {
+ if (!isTruncationLengthValid(algoName, truncLenBits)) {
+ throw new IllegalArgumentException("Unknown algorithm or invalid length");
+ }
+ mName = algoName;
+ mKey = key.clone();
+ mTruncLenBits = Math.min(truncLenBits, key.length * 8);
+ }
+
+ /** Retrieve the algorithm name */
+ public String getName() {
+ return mName;
+ }
+
+ /** Retrieve the key for this algorithm */
+ public byte[] getKey() {
+ return mKey.clone();
+ }
+
+ /**
+ * Retrieve the truncation length, in bits, for the key in this algo. By default this will be
+ * the length in bits of the key.
+ */
+ public int getTruncationLengthBits() {
+ return mTruncLenBits;
+ }
+
+ /* Parcelable Implementation */
+ public int describeContents() {
+ return 0;
+ }
+
+ /** Write to parcel */
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(mName);
+ out.writeByteArray(mKey);
+ out.writeInt(mTruncLenBits);
+ }
+
+ /** Parcelable Creator */
+ public static final Parcelable.Creator<IpSecAlgorithm> CREATOR =
+ new Parcelable.Creator<IpSecAlgorithm>() {
+ public IpSecAlgorithm createFromParcel(Parcel in) {
+ return new IpSecAlgorithm(in);
+ }
+
+ public IpSecAlgorithm[] newArray(int size) {
+ return new IpSecAlgorithm[size];
+ }
+ };
+
+ private IpSecAlgorithm(Parcel in) {
+ mName = in.readString();
+ mKey = in.createByteArray();
+ mTruncLenBits = in.readInt();
+ }
+
+ private static boolean isTruncationLengthValid(String algo, int truncLenBits) {
+ switch (algo) {
+ case ALGO_AUTH_HMAC_MD5:
+ return (truncLenBits >= 96 && truncLenBits <= 128);
+ case ALGO_AUTH_HMAC_SHA1:
+ return (truncLenBits >= 96 && truncLenBits <= 160);
+ case ALGO_AUTH_HMAC_SHA256:
+ return (truncLenBits >= 96 && truncLenBits <= 256);
+ case ALGO_AUTH_HMAC_SHA384:
+ return (truncLenBits >= 192 && truncLenBits <= 384);
+ case ALGO_AUTH_HMAC_SHA512:
+ return (truncLenBits >= 256 && truncLenBits <= 512);
+ default:
+ return false;
+ }
+ }
+};
diff --git a/core/java/android/net/IpSecConfig.aidl b/core/java/android/net/IpSecConfig.aidl
new file mode 100644
index 0000000..eaefca7
--- /dev/null
+++ b/core/java/android/net/IpSecConfig.aidl
@@ -0,0 +1,20 @@
+/*
+ * 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;
+
+/** @hide */
+parcelable IpSecConfig;
diff --git a/core/java/android/net/IpSecConfig.java b/core/java/android/net/IpSecConfig.java
new file mode 100644
index 0000000..b58bf42
--- /dev/null
+++ b/core/java/android/net/IpSecConfig.java
@@ -0,0 +1,197 @@
+/*
+ * 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 android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+/** @hide */
+public final class IpSecConfig implements Parcelable {
+ private static final String TAG = IpSecConfig.class.getSimpleName();
+
+ //MODE_TRANSPORT or MODE_TUNNEL
+ int mode;
+
+ // For tunnel mode
+ InetAddress localAddress;
+
+ InetAddress remoteAddress;
+
+ // Limit selection by network interface
+ Network network;
+
+ public static class Flow {
+ // Minimum requirements for identifying a transform
+ // SPI identifying the IPsec flow in packet processing
+ // and a remote IP address
+ int spi;
+
+ // Encryption Algorithm
+ IpSecAlgorithm encryptionAlgo;
+
+ // Authentication Algorithm
+ IpSecAlgorithm authenticationAlgo;
+ }
+
+ Flow[] flow = new Flow[2];
+
+ // For tunnel mode IPv4 UDP Encapsulation
+ // IpSecTransform#ENCAP_ESP_*, such as ENCAP_ESP_OVER_UDP_IKE
+ int encapType;
+ int encapLocalPort;
+ int encapRemotePort;
+
+ // An optional protocol to match with the selector
+ int selectorProto;
+
+ // A bitmask of FEATURE_* indicating which of the fields
+ // of this class are valid.
+ long features;
+
+ // An interval, in seconds between the NattKeepalive packets
+ int nattKeepaliveInterval;
+
+ public InetAddress getLocalIp() {
+ return localAddress;
+ }
+
+ public int getSpi(int direction) {
+ return flow[direction].spi;
+ }
+
+ public InetAddress getRemoteIp() {
+ return remoteAddress;
+ }
+
+ public IpSecAlgorithm getEncryptionAlgo(int direction) {
+ return flow[direction].encryptionAlgo;
+ }
+
+ public IpSecAlgorithm getAuthenticationAlgo(int direction) {
+ return flow[direction].authenticationAlgo;
+ }
+
+ Network getNetwork() {
+ return network;
+ }
+
+ public int getEncapType() {
+ return encapType;
+ }
+
+ public int getEncapLocalPort() {
+ return encapLocalPort;
+ }
+
+ public int getEncapRemotePort() {
+ return encapRemotePort;
+ }
+
+ public int getSelectorProto() {
+ return selectorProto;
+ }
+
+ int getNattKeepaliveInterval() {
+ return nattKeepaliveInterval;
+ }
+
+ public boolean hasProperty(int featureBits) {
+ return (features & featureBits) == featureBits;
+ }
+
+ // Parcelable Methods
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeLong(features);
+ // TODO: Use a byte array or other better method for storing IPs that can also include scope
+ out.writeString((localAddress != null) ? localAddress.getHostAddress() : null);
+ // TODO: Use a byte array or other better method for storing IPs that can also include scope
+ out.writeString((remoteAddress != null) ? remoteAddress.getHostAddress() : null);
+ out.writeParcelable(network, flags);
+ out.writeInt(flow[IpSecTransform.DIRECTION_IN].spi);
+ out.writeParcelable(flow[IpSecTransform.DIRECTION_IN].encryptionAlgo, flags);
+ out.writeParcelable(flow[IpSecTransform.DIRECTION_IN].authenticationAlgo, flags);
+ out.writeInt(flow[IpSecTransform.DIRECTION_OUT].spi);
+ out.writeParcelable(flow[IpSecTransform.DIRECTION_OUT].encryptionAlgo, flags);
+ out.writeParcelable(flow[IpSecTransform.DIRECTION_OUT].authenticationAlgo, flags);
+ out.writeInt(encapType);
+ out.writeInt(encapLocalPort);
+ out.writeInt(encapRemotePort);
+ out.writeInt(selectorProto);
+ }
+
+ // Package Private: Used by the IpSecTransform.Builder;
+ // there should be no public constructor for this object
+ IpSecConfig() {
+ flow[IpSecTransform.DIRECTION_IN].spi = 0;
+ flow[IpSecTransform.DIRECTION_OUT].spi = 0;
+ nattKeepaliveInterval = 0; //FIXME constant
+ }
+
+ private static InetAddress readInetAddressFromParcel(Parcel in) {
+ String addrString = in.readString();
+ if (addrString == null) {
+ return null;
+ }
+ try {
+ return InetAddress.getByName(addrString);
+ } catch (UnknownHostException e) {
+ Log.wtf(TAG, "Invalid IpAddress " + addrString);
+ return null;
+ }
+ }
+
+ private IpSecConfig(Parcel in) {
+ features = in.readLong();
+ localAddress = readInetAddressFromParcel(in);
+ remoteAddress = readInetAddressFromParcel(in);
+ network = (Network) in.readParcelable(Network.class.getClassLoader());
+ flow[IpSecTransform.DIRECTION_IN].spi = in.readInt();
+ flow[IpSecTransform.DIRECTION_IN].encryptionAlgo =
+ (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader());
+ flow[IpSecTransform.DIRECTION_IN].authenticationAlgo =
+ (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader());
+ flow[IpSecTransform.DIRECTION_OUT].spi = in.readInt();
+ flow[IpSecTransform.DIRECTION_OUT].encryptionAlgo =
+ (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader());
+ flow[IpSecTransform.DIRECTION_OUT].authenticationAlgo =
+ (IpSecAlgorithm) in.readParcelable(IpSecAlgorithm.class.getClassLoader());
+ encapType = in.readInt();
+ encapLocalPort = in.readInt();
+ encapRemotePort = in.readInt();
+ selectorProto = in.readInt();
+ }
+
+ public static final Parcelable.Creator<IpSecConfig> CREATOR =
+ new Parcelable.Creator<IpSecConfig>() {
+ public IpSecConfig createFromParcel(Parcel in) {
+ return new IpSecConfig(in);
+ }
+
+ public IpSecConfig[] newArray(int size) {
+ return new IpSecConfig[size];
+ }
+ };
+}
diff --git a/core/java/android/net/IpSecManager.java b/core/java/android/net/IpSecManager.java
new file mode 100644
index 0000000..2c544e9
--- /dev/null
+++ b/core/java/android/net/IpSecManager.java
@@ -0,0 +1,379 @@
+/*
+ * 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 com.android.internal.util.Preconditions.checkNotNull;
+
+import android.annotation.SystemApi;
+import android.content.Context;
+import android.os.INetworkManagementService;
+import android.os.ParcelFileDescriptor;
+import android.util.AndroidException;
+import dalvik.system.CloseGuard;
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+import java.net.Socket;
+
+/**
+ * This class contains methods for managing IPsec sessions, which will perform kernel-space
+ * encryption and decryption of socket or Network traffic.
+ *
+ * <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}
+ */
+public final class IpSecManager {
+ private static final String TAG = "IpSecManager";
+
+ /**
+ * Indicates that the combination of remote InetAddress and SPI was non-unique for a given
+ * request. If encountered, selection of a new SPI is required before a transform may be
+ * created. Note, this should happen very rarely if the SPI is chosen to be sufficiently random
+ * or reserved using reserveSecurityParameterIndex.
+ */
+ public static final class SpiUnavailableException extends AndroidException {
+ private final int mSpi;
+
+ /**
+ * Construct an exception indicating that a transform with the given SPI is already in use
+ * or otherwise unavailable.
+ *
+ * @param msg Description indicating the colliding SPI
+ * @param spi the SPI that could not be used due to a collision
+ */
+ SpiUnavailableException(String msg, int spi) {
+ super(msg + "(spi: " + spi + ")");
+ mSpi = spi;
+ }
+
+ /** Retrieve the SPI that caused a collision */
+ public int getSpi() {
+ return mSpi;
+ }
+ }
+
+ /**
+ * Indicates that the requested system resource for IPsec, such as a socket or other system
+ * resource is unavailable. If this exception is thrown, try releasing allocated objects of the
+ * type requested.
+ */
+ public static final class ResourceUnavailableException extends AndroidException {
+
+ ResourceUnavailableException(String msg) {
+ super(msg);
+ }
+ }
+
+ private final Context mContext;
+ private final INetworkManagementService mService;
+
+ public static final class SecurityParameterIndex implements AutoCloseable {
+ private final Context mContext;
+ private final InetAddress mDestinationAddress;
+ private final CloseGuard mCloseGuard = CloseGuard.get();
+ private int mSpi;
+
+ /** Return the underlying SPI held by this object */
+ public int getSpi() {
+ return mSpi;
+ }
+
+ private SecurityParameterIndex(Context context, InetAddress destinationAddress, int spi)
+ throws ResourceUnavailableException, SpiUnavailableException {
+ mContext = context;
+ mDestinationAddress = destinationAddress;
+ mSpi = spi;
+ mCloseGuard.open("open");
+ }
+
+ /**
+ * Release an SPI that was previously reserved.
+ *
+ * <p>Release an SPI for use by other users in the system. This will fail if the SPI is
+ * currently in use by an IpSecTransform.
+ *
+ * @param destinationAddress SPIs must be unique for each combination of SPI and destination
+ * address. Thus, the destinationAddress to which the SPI will communicate must be
+ * supplied.
+ * @param spi the previously reserved SPI to be freed.
+ */
+ @Override
+ public void close() {
+ mSpi = INVALID_SECURITY_PARAMETER_INDEX; // TODO: Invalid SPI
+ mCloseGuard.close();
+ }
+
+ @Override
+ protected void finalize() {
+ if (mCloseGuard != null) {
+ mCloseGuard.warnIfOpen();
+ }
+
+ close();
+ }
+ }
+
+ /**
+ * The Security Parameter Index, SPI, 0 indicates an unknown or invalid index.
+ *
+ * <p>No IPsec packet may contain an SPI of 0.
+ */
+ public static final int INVALID_SECURITY_PARAMETER_INDEX = 0;
+
+ /**
+ * Reserve an SPI for traffic bound towards the specified destination address.
+ *
+ * <p>If successful, this SPI is guaranteed available until released by a call to {@link
+ * SecurityParameterIndex#close()}.
+ *
+ * @param destinationAddress SPIs must be unique for each combination of SPI and destination
+ * address.
+ * @param requestedSpi the requested SPI, or '0' to allocate a random SPI.
+ * @return the reserved SecurityParameterIndex
+ * @throws ResourceUnavailableException indicating that too many SPIs are currently allocated
+ * for this user
+ * @throws SpiUnavailableException indicating that a particular SPI cannot be reserved
+ */
+ public SecurityParameterIndex reserveSecurityParameterIndex(
+ InetAddress destinationAddress, int requestedSpi)
+ throws SpiUnavailableException, ResourceUnavailableException {
+ return new SecurityParameterIndex(mContext, destinationAddress, requestedSpi);
+ }
+
+ /**
+ * Apply an active Transport Mode IPsec Transform to a stream socket to perform IPsec
+ * encapsulation of the traffic flowing between the socket and the remote InetAddress of that
+ * transform. For security reasons, attempts to send traffic to any IP address other than the
+ * 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)};
+ *
+ * @param socket a stream socket
+ * @param transform an {@link IpSecTransform}, which must be an active Transport Mode transform.
+ */
+ public void applyTransportModeTransform(Socket socket, IpSecTransform transform)
+ throws IOException {
+ applyTransportModeTransform(ParcelFileDescriptor.fromSocket(socket), transform);
+ }
+
+ /**
+ * Apply an active Transport Mode IPsec Transform to a datagram socket to perform IPsec
+ * encapsulation of the traffic flowing between the socket and the remote InetAddress of that
+ * transform. For security reasons, attempts to send traffic to any IP address other than the
+ * 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(DatagramSocket, IpSecTransform)};
+ *
+ * @param socket a datagram socket
+ * @param transform an {@link IpSecTransform}, which must be an active Transport Mode transform.
+ */
+ public void applyTransportModeTransform(DatagramSocket socket, IpSecTransform transform)
+ throws IOException {
+ applyTransportModeTransform(ParcelFileDescriptor.fromDatagramSocket(socket), transform);
+ }
+
+ /* Call down to activate a transform */
+ private void applyTransportModeTransform(ParcelFileDescriptor pfd, IpSecTransform transform) {}
+
+ /**
+ * Apply an active Tunnel Mode IPsec Transform to a network, which will tunnel all traffic to
+ * and from that network's interface with IPsec (applies an outer IP header and IPsec Header to
+ * all traffic, and expects an additional IP header and IPsec Header on all inbound traffic).
+ * Applications should probably not use this API directly. Instead, they should use {@link
+ * VpnService} to provide VPN capability in a more generic fashion.
+ *
+ * @param net a {@link Network} that will be tunneled via IP Sec.
+ * @param transform an {@link IpSecTransform}, which must be an active Tunnel Mode transform.
+ * @hide
+ */
+ @SystemApi
+ public void applyTunnelModeTransform(Network net, IpSecTransform transform) {}
+
+ /**
+ * Remove a transform from a given stream socket. Once removed, traffic on the socket will not
+ * be encypted. This allows sockets that have been used for IPsec to be reclaimed for
+ * communication in the clear in the event socket reuse is desired. This operation will succeed
+ * regardless of the underlying state of a transform. If a transform is removed, communication
+ * on all sockets to which that transform was applied will fail until this method is called.
+ *
+ * @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
+ */
+ public void removeTransportModeTransform(Socket socket, IpSecTransform transform) {
+ removeTransportModeTransform(ParcelFileDescriptor.fromSocket(socket), transform);
+ }
+
+ /**
+ * Remove a transform from a given datagram socket. Once removed, traffic on the socket will not
+ * be encypted. This allows sockets that have been used for IPsec to be reclaimed for
+ * communication in the clear in the event socket reuse is desired. This operation will succeed
+ * regardless of the underlying state of a transform. If a transform is removed, communication
+ * on all sockets to which that transform was applied will fail until this method is called.
+ *
+ * @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
+ */
+ public void removeTransportModeTransform(DatagramSocket socket, IpSecTransform transform) {
+ removeTransportModeTransform(ParcelFileDescriptor.fromDatagramSocket(socket), transform);
+ }
+
+ /* Call down to activate a transform */
+ private void removeTransportModeTransform(ParcelFileDescriptor pfd, IpSecTransform transform) {}
+
+ /**
+ * Remove a Tunnel Mode IPsec Transform from a {@link Network}. This must be used as part of
+ * cleanup if a tunneled Network experiences a change in default route. The Network will drop
+ * all traffic that cannot be routed to the Tunnel's outbound interface. If that interface is
+ * lost, all traffic will drop.
+ *
+ * @param net a network that currently has transform applied to it.
+ * @param transform a Tunnel Mode IPsec Transform that has been previously applied to the given
+ * network
+ * @hide
+ */
+ @SystemApi
+ public void removeTunnelModeTransform(Network net, IpSecTransform transform) {}
+
+ /**
+ * Class providing access to a system-provided UDP Encapsulation Socket, which may be used for
+ * IKE signalling as well as for inbound and outbound UDP encapsulated IPsec traffic.
+ *
+ * <p>The socket provided by this class cannot be re-bound or closed via the inner
+ * FileDescriptor. Instead, disposing of this socket requires a call to close().
+ */
+ public static final class UdpEncapsulationSocket implements AutoCloseable {
+ private final FileDescriptor mFd;
+ private final Context mContext;
+ private final CloseGuard mCloseGuard = CloseGuard.get();
+
+ private UdpEncapsulationSocket(Context context, int port)
+ throws ResourceUnavailableException {
+ mContext = context;
+ mCloseGuard.open("constructor");
+ // TODO: go down to the kernel and get a socket on the specified
+ mFd = new FileDescriptor();
+ }
+
+ private UdpEncapsulationSocket(Context context) throws ResourceUnavailableException {
+ mContext = context;
+ mCloseGuard.open("constructor");
+ // TODO: go get a random socket on a random port
+ mFd = new FileDescriptor();
+ }
+
+ /** Access the inner UDP Encapsulation Socket */
+ public FileDescriptor getSocket() {
+ return mFd;
+ }
+
+ /** Retrieve the port number of the inner encapsulation socket */
+ public int getPort() {
+ return 0; // TODO get the port number from the Socket;
+ }
+
+ @Override
+ /**
+ * Release the resources that have been reserved for this Socket.
+ *
+ * <p>This method closes the underlying socket, reducing a user's allocated sockets in the
+ * system. This must be done as part of cleanup following use of a socket. Failure to do so
+ * will cause the socket to count against a total allocation limit for IpSec and eventually
+ * fail due to resource limits.
+ *
+ * @param fd a file descriptor previously returned as a UDP Encapsulation socket.
+ */
+ public void close() {
+ // TODO: Go close the socket
+ mCloseGuard.close();
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ if (mCloseGuard != null) {
+ mCloseGuard.warnIfOpen();
+ }
+
+ close();
+ }
+ };
+
+ /**
+ * Open a socket that is bound to a free UDP port on the system.
+ *
+ * <p>By binding in this manner and holding the FileDescriptor, the socket cannot be un-bound by
+ * the caller. This provides safe access to a socket on a port that can later be used as a UDP
+ * Encapsulation port.
+ *
+ * <p>This socket reservation works in conjunction with IpSecTransforms, which may re-use the
+ * socket port. Explicitly opening this port is only necessary if communication is desired on
+ * that port.
+ *
+ * @param port a local UDP port to be reserved for UDP Encapsulation. is provided, then this
+ * method will bind to the specified port or fail. To retrieve the port number, call {@link
+ * android.system.Os#getsockname(FileDescriptor)}.
+ * @return a {@link UdpEncapsulationSocket} that is bound to the requested port for the lifetime
+ * of the object.
+ */
+ // Returning a socket in this fashion that has been created and bound by the system
+ // is the only safe way to ensure that a socket is both accessible to the user and
+ // safely usable for Encapsulation without allowing a user to possibly unbind from/close
+ // the port, which could potentially impact the traffic of the next user who binds to that
+ // socket.
+ public UdpEncapsulationSocket openUdpEncapsulationSocket(int port)
+ throws IOException, ResourceUnavailableException {
+ // Temporary code
+ return new UdpEncapsulationSocket(mContext, port);
+ }
+
+ /**
+ * Open a socket that is bound to a port selected by the system.
+ *
+ * <p>By binding in this manner and holding the FileDescriptor, the socket cannot be un-bound by
+ * the caller. This provides safe access to a socket on a port that can later be used as a UDP
+ * Encapsulation port.
+ *
+ * <p>This socket reservation works in conjunction with IpSecTransforms, which may re-use the
+ * socket port. Explicitly opening this port is only necessary if communication is desired on
+ * that port.
+ *
+ * @return a {@link UdpEncapsulationSocket} that is bound to an arbitrarily selected port
+ */
+ // Returning a socket in this fashion that has been created and bound by the system
+ // is the only safe way to ensure that a socket is both accessible to the user and
+ // safely usable for Encapsulation without allowing a user to possibly unbind from/close
+ // the port, which could potentially impact the traffic of the next user who binds to that
+ // socket.
+ public UdpEncapsulationSocket openUdpEncapsulationSocket()
+ throws IOException, ResourceUnavailableException {
+ // Temporary code
+ return new UdpEncapsulationSocket(mContext);
+ }
+
+ /**
+ * Retrieve an instance of an IpSecManager within you application context
+ *
+ * @param context the application context for this manager
+ * @hide
+ */
+ public IpSecManager(Context context, INetworkManagementService service) {
+ mContext = checkNotNull(context, "missing context");
+ mService = checkNotNull(service, "missing service");
+ }
+}
diff --git a/core/java/android/net/IpSecTransform.java b/core/java/android/net/IpSecTransform.java
new file mode 100644
index 0000000..d6dd28b
--- /dev/null
+++ b/core/java/android/net/IpSecTransform.java
@@ -0,0 +1,471 @@
+/*
+ * 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 android.annotation.IntDef;
+import android.annotation.SystemApi;
+import android.content.Context;
+import android.system.ErrnoException;
+import android.util.Log;
+import dalvik.system.CloseGuard;
+import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.net.InetAddress;
+
+/**
+ * This class represents an IpSecTransform, which encapsulates both properties and state of IPsec.
+ *
+ * <p>IpSecTransforms must be built from an IpSecTransform.Builder, and they must persist throughout
+ * the lifetime of the underlying transform. If a transform object leaves scope, the underlying
+ * transform may be disabled automatically, with likely undesirable results.
+ *
+ * <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.
+ */
+public final class IpSecTransform implements AutoCloseable {
+ private static final String TAG = "IpSecTransform";
+
+ /**
+ * For direction-specific attributes of an IpSecTransform, indicates that an attribute applies
+ * to traffic towards the host.
+ */
+ public static final int DIRECTION_IN = 0;
+
+ /**
+ * For direction-specific attributes of an IpSecTransform, indicates that an attribute applies
+ * to traffic from the host.
+ */
+ public static final int DIRECTION_OUT = 1;
+
+ /** @hide */
+ @IntDef(value = {DIRECTION_IN, DIRECTION_OUT})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface TransformDirection {}
+
+ /** @hide */
+ private static final int MODE_TUNNEL = 0;
+
+ /** @hide */
+ private static final int MODE_TRANSPORT = 1;
+
+ /** @hide */
+ public static final int ENCAP_NONE = 0;
+
+ /**
+ * IpSec traffic will be encapsulated within UDP as per <a
+ * href="https://tools.ietf.org/html/rfc3948">RFC3498</a>.
+ *
+ * @hide
+ */
+ public static final int ENCAP_ESPINUDP = 1;
+
+ /**
+ * IpSec traffic will be encapsulated within a UDP header with an additional 8-byte header pad
+ * (of '0'-value bytes) that prevents traffic from being interpreted as IKE or as ESP over UDP.
+ *
+ * @hide
+ */
+ public static final int ENCAP_ESPINUDP_NONIKE = 2;
+
+ /** @hide */
+ @IntDef(value = {ENCAP_NONE, ENCAP_ESPINUDP, ENCAP_ESPINUDP_NONIKE})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface EncapType {}
+
+ /**
+ * Sentinel for an invalid transform (means that this transform is inactive).
+ *
+ * @hide
+ */
+ public static final int INVALID_TRANSFORM_ID = -1;
+
+ private IpSecTransform(Context context, IpSecConfig config) {
+ mContext = context;
+ mConfig = config;
+ mTransformId = INVALID_TRANSFORM_ID;
+ }
+
+ private IpSecTransform activate()
+ throws IOException, IpSecManager.ResourceUnavailableException,
+ IpSecManager.SpiUnavailableException {
+ int transformId;
+ synchronized (this) {
+ //try {
+ transformId = INVALID_TRANSFORM_ID;
+ //} catch (RemoteException e) {
+ // throw e.rethrowFromSystemServer();
+ //}
+
+ if (transformId < 0) {
+ throw new ErrnoException("addTransform", -transformId).rethrowAsIOException();
+ }
+
+ startKeepalive(mContext); // Will silently fail if not required
+ mTransformId = transformId;
+ Log.d(TAG, "Added Transform with Id " + transformId);
+ }
+ mCloseGuard.open("build");
+
+ return this;
+ }
+
+ /**
+ * Deactivate an IpSecTransform and free all resources for that transform that are managed by
+ * the system for this Transform.
+ *
+ * <p>Deactivating a transform while it is still applied to any Socket will result in sockets
+ * refusing to send or receive data. This method will silently succeed if the specified
+ * transform has already been removed; thus, it is always safe to attempt cleanup when a
+ * transform is no longer needed.
+ */
+ public void close() {
+ Log.d(TAG, "Removing Transform with Id " + mTransformId);
+
+ // Always safe to attempt cleanup
+ if (mTransformId == INVALID_TRANSFORM_ID) {
+ return;
+ }
+ //try {
+ stopKeepalive();
+ //} catch (RemoteException e) {
+ // transform.setTransformId(transformId);
+ // throw e.rethrowFromSystemServer();
+ //} finally {
+ mTransformId = INVALID_TRANSFORM_ID;
+ //}
+ mCloseGuard.close();
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ if (mCloseGuard != null) {
+ mCloseGuard.warnIfOpen();
+ }
+ close();
+ }
+
+ /* Package */
+ IpSecConfig getConfig() {
+ return mConfig;
+ }
+
+ private final IpSecConfig mConfig;
+ private int mTransformId;
+ private final Context mContext;
+ private final CloseGuard mCloseGuard = CloseGuard.get();
+ private ConnectivityManager.PacketKeepalive mKeepalive;
+ private int mKeepaliveStatus = ConnectivityManager.PacketKeepalive.NO_KEEPALIVE;
+ private Object mKeepaliveSyncLock = new Object();
+ private ConnectivityManager.PacketKeepaliveCallback mKeepaliveCallback =
+ new ConnectivityManager.PacketKeepaliveCallback() {
+
+ @Override
+ public void onStarted() {
+ synchronized (mKeepaliveSyncLock) {
+ mKeepaliveStatus = ConnectivityManager.PacketKeepalive.SUCCESS;
+ mKeepaliveSyncLock.notifyAll();
+ }
+ }
+
+ @Override
+ public void onStopped() {
+ synchronized (mKeepaliveSyncLock) {
+ mKeepaliveStatus = ConnectivityManager.PacketKeepalive.NO_KEEPALIVE;
+ mKeepaliveSyncLock.notifyAll();
+ }
+ }
+
+ @Override
+ public void onError(int error) {
+ synchronized (mKeepaliveSyncLock) {
+ mKeepaliveStatus = error;
+ mKeepaliveSyncLock.notifyAll();
+ }
+ }
+ };
+
+ /* Package */
+ void startKeepalive(Context c) {
+ if (mConfig.getNattKeepaliveInterval() == 0) {
+ return;
+ }
+
+ ConnectivityManager cm =
+ (ConnectivityManager) c.getSystemService(Context.CONNECTIVITY_SERVICE);
+
+ if (mKeepalive != null) {
+ Log.e(TAG, "Keepalive already started for this IpSecTransform.");
+ return;
+ }
+
+ synchronized (mKeepaliveSyncLock) {
+ mKeepalive =
+ cm.startNattKeepalive(
+ mConfig.getNetwork(),
+ mConfig.getNattKeepaliveInterval(),
+ mKeepaliveCallback,
+ mConfig.getLocalIp(),
+ mConfig.getEncapLocalPort(),
+ mConfig.getRemoteIp());
+ try {
+ mKeepaliveSyncLock.wait(2000);
+ } catch (InterruptedException e) {
+ }
+ }
+ if (mKeepaliveStatus != ConnectivityManager.PacketKeepalive.SUCCESS) {
+ throw new UnsupportedOperationException("Packet Keepalive cannot be started");
+ }
+ }
+
+ /* Package */
+ void stopKeepalive() {
+ if (mKeepalive == null) {
+ return;
+ }
+ mKeepalive.stop();
+ synchronized (mKeepaliveSyncLock) {
+ if (mKeepaliveStatus == ConnectivityManager.PacketKeepalive.SUCCESS) {
+ try {
+ mKeepaliveSyncLock.wait(2000);
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+ }
+
+ /* Package */
+ void setTransformId(int transformId) {
+ mTransformId = transformId;
+ }
+
+ /* Package */
+ int getTransformId() {
+ return mTransformId;
+ }
+
+ /**
+ * Builder object to facilitate the creation of IpSecTransform objects.
+ *
+ * <p>Apply additional properties to the transform and then call a build() method to return an
+ * IpSecTransform object.
+ *
+ * @see Builder#buildTransportModeTransform(InetAddress)
+ */
+ public static class Builder {
+ private Context mContext;
+ private IpSecConfig mConfig;
+
+ /**
+ * Add an encryption algorithm to the transform for the given direction.
+ *
+ * <p>If encryption is set for a given direction without also providing an SPI for that
+ * direction, creation of an IpSecTransform will fail upon calling a build() method.
+ *
+ * @param direction either {@link #DIRECTION_IN or #DIRECTION_OUT}
+ * @param algo {@link IpSecAlgorithm} specifying the encryption to be applied.
+ */
+ public IpSecTransform.Builder setEncryption(
+ @TransformDirection int direction, IpSecAlgorithm algo) {
+ mConfig.flow[direction].encryptionAlgo = algo;
+ return this;
+ }
+
+ /**
+ * Add an authentication/integrity algorithm to the transform.
+ *
+ * <p>If authentication is set for a given direction without also providing an SPI for that
+ * direction, creation of an IpSecTransform will fail upon calling a build() method.
+ *
+ * @param direction either {@link #DIRECTION_IN or #DIRECTION_OUT}
+ * @param algo {@link IpSecAlgorithm} specifying the authentication to be applied.
+ */
+ public IpSecTransform.Builder setAuthentication(
+ @TransformDirection int direction, IpSecAlgorithm algo) {
+ mConfig.flow[direction].authenticationAlgo = algo;
+ return this;
+ }
+
+ /**
+ * Set the SPI, which uniquely identifies a particular IPsec session from others. Because
+ * IPsec operates at the IP layer, this 32-bit identifier uniquely identifies packets to a
+ * given destination address.
+ *
+ * <p>Care should be chosen when selecting an SPI to ensure that is is as unique as
+ * possible. Random number generation is a reasonable approach to selecting an SPI. For
+ * outbound SPIs, they must be reserved by calling {@link
+ * IpSecManager#reserveSecurityParameterIndex(InetAddress, int)}. Otherwise, Transforms will
+ * fail to build.
+ *
+ * <p>Unless an SPI is set for a given direction, traffic in that direction will be
+ * sent/received without any IPsec applied.
+ *
+ * @param direction either {@link #DIRECTION_IN or #DIRECTION_OUT}
+ * @param spi a unique 32-bit integer to identify transformed traffic
+ */
+ public IpSecTransform.Builder setSpi(@TransformDirection int direction, int spi) {
+ mConfig.flow[direction].spi = spi;
+ return this;
+ }
+
+ /**
+ * Set the SPI, which uniquely identifies a particular IPsec session from others. Because
+ * IPsec operates at the IP layer, this 32-bit identifier uniquely identifies packets to a
+ * given destination address.
+ *
+ * <p>Care should be chosen when selecting an SPI to ensure that is is as unique as
+ * possible. Random number generation is a reasonable approach to selecting an SPI. For
+ * outbound SPIs, they must be reserved by calling {@link
+ * IpSecManager#reserveSecurityParameterIndex(InetAddress, int)}. Otherwise, Transforms will
+ * fail to activate.
+ *
+ * <p>Unless an SPI is set for a given direction, traffic in that direction will be
+ * sent/received without any IPsec applied.
+ *
+ * @param direction either {@link #DIRECTION_IN or #DIRECTION_OUT}
+ * @param spi a unique {@link IpSecManager.SecurityParameterIndex} to identify transformed
+ * traffic
+ */
+ public IpSecTransform.Builder setSpi(
+ @TransformDirection int direction, IpSecManager.SecurityParameterIndex spi) {
+ mConfig.flow[direction].spi = spi.getSpi();
+ return this;
+ }
+
+ /**
+ * Specify the network on which this transform will emit its traffic; (otherwise it will
+ * emit on the default network).
+ *
+ * <p>Restricts the transformed traffic to a particular {@link Network}. This is required in
+ * tunnel mode.
+ *
+ * @hide
+ */
+ @SystemApi
+ public IpSecTransform.Builder setUnderlyingNetwork(Network net) {
+ mConfig.network = net;
+ return this;
+ }
+
+ /**
+ * Add UDP encapsulation to an IPv4 transform
+ *
+ * <p>This option allows IPsec traffic to pass through NAT. Refer to RFC 3947 and 3948 for
+ * details on how UDP should be applied to IPsec.
+ *
+ * @param localSocket a {@link IpSecManager.UdpEncapsulationSocket} for sending and
+ * receiving encapsulating traffic.
+ * @param remotePort the UDP port number of the remote that will send and receive
+ * encapsulated traffic. In the case of IKE, this is likely port 4500.
+ */
+ public IpSecTransform.Builder setIpv4Encapsulation(
+ IpSecManager.UdpEncapsulationSocket localSocket, int remotePort) {
+ // TODO: check encap type is valid.
+ mConfig.encapType = ENCAP_ESPINUDP;
+ mConfig.encapLocalPort = localSocket.getPort(); // TODO: plug in the encap socket
+ mConfig.encapRemotePort = remotePort;
+ return this;
+ }
+
+ // TODO: Decrease the minimum keepalive to maybe 10?
+ // TODO: Probably a better exception to throw for NATTKeepalive failure
+ // TODO: Specify the needed NATT keepalive permission.
+ /**
+ * Send a NATT Keepalive packet with a given maximum interval. This will create an offloaded
+ * request to do power-efficient NATT Keepalive. If NATT keepalive is requested but cannot
+ * be activated, then the transform will fail to activate and throw an IOException.
+ *
+ * @param intervalSeconds the maximum number of seconds between keepalive packets, no less
+ * than 20s and no more than 3600s.
+ * @hide
+ */
+ @SystemApi
+ public IpSecTransform.Builder setNattKeepalive(int intervalSeconds) {
+ mConfig.nattKeepaliveInterval = intervalSeconds;
+ return this;
+ }
+
+ /**
+ * Build and return an active {@link IpSecTransform} object as a Transport Mode Transform.
+ * Some parameters have interdependencies that are checked at build time. If a well-formed
+ * transform cannot be created from the supplied parameters, this method will throw an
+ * Exception.
+ *
+ * <p>Upon a successful return from this call, the provided IpSecTransform will be active
+ * and may be applied to sockets. If too many IpSecTransform objects are active for a given
+ * user this operation will fail and throw ResourceUnavailableException. To avoid these
+ * exceptions, unused Transform objects must be cleaned up by calling {@link
+ * IpSecTransform#close()} when they are no longer needed.
+ *
+ * @param remoteAddress the {@link InetAddress} that, when matched on traffic to/from this
+ * socket will cause the transform to be applied.
+ * <p>Note that an active transform will not impact any network traffic until it has
+ * been applied to one or more Sockets. Calling this method is a necessary precondition
+ * for applying it to a socket, but is not sufficient to actually apply IPsec.
+ * @throws IllegalArgumentException indicating that a particular combination of transform
+ * properties is invalid.
+ * @throws IpSecManager.ResourceUnavailableException in the event that no more Transforms
+ * may be allocated
+ * @throws SpiUnavailableException if the SPI collides with an existing transform
+ * (unlikely).
+ * @throws ResourceUnavailableException if the current user currently has exceeded the
+ * number of allowed active transforms.
+ */
+ public IpSecTransform buildTransportModeTransform(InetAddress remoteAddress)
+ throws IpSecManager.ResourceUnavailableException,
+ IpSecManager.SpiUnavailableException, IOException {
+ //FIXME: argument validation here
+ //throw new IllegalArgumentException("Natt Keepalive requires UDP Encapsulation");
+ mConfig.mode = MODE_TRANSPORT;
+ mConfig.remoteAddress = remoteAddress;
+ return new IpSecTransform(mContext, mConfig).activate();
+ }
+
+ /**
+ * Build and return an {@link IpSecTransform} object as a Tunnel Mode Transform. Some
+ * parameters have interdependencies that are checked at build time.
+ *
+ * @param localAddress the {@link InetAddress} that provides the local endpoint for this
+ * IPsec tunnel. This is almost certainly an address belonging to the {@link Network}
+ * that will originate the traffic, which is set as the {@link #setUnderlyingNetwork}.
+ * @param remoteAddress the {@link InetAddress} representing the remote endpoint of this
+ * IPsec tunnel.
+ * @throws IllegalArgumentException indicating that a particular combination of transform
+ * properties is invalid.
+ * @hide
+ */
+ @SystemApi
+ public IpSecTransform buildTunnelModeTransform(
+ InetAddress localAddress, InetAddress remoteAddress) {
+ //FIXME: argument validation here
+ //throw new IllegalArgumentException("Natt Keepalive requires UDP Encapsulation");
+ mConfig.localAddress = localAddress;
+ mConfig.remoteAddress = remoteAddress;
+ mConfig.mode = MODE_TUNNEL;
+ return new IpSecTransform(mContext, mConfig);
+ }
+
+ /**
+ * Create a new IpSecTransform.Builder to construct an IpSecTransform
+ *
+ * @param context current Context
+ */
+ public Builder(Context context) {
+ mContext = context;
+ mConfig = new IpSecConfig();
+ }
+ }
+}
diff --git a/core/java/android/os/ShellCommand.java b/core/java/android/os/ShellCommand.java
index fc804e5..0b4c4c1 100644
--- a/core/java/android/os/ShellCommand.java
+++ b/core/java/android/os/ShellCommand.java
@@ -274,7 +274,7 @@
/**
* Implement parsing and execution of a command. If it isn't a command you understand,
* call {@link #handleDefaultCommands(String)} and return its result as a last resort.
- * User {@link #getNextOption()}, {@link #getNextArg()}, and {@link #getNextArgRequired()}
+ * Use {@link #getNextOption()}, {@link #getNextArg()}, and {@link #getNextArgRequired()}
* to process additional command line arguments. Command output can be written to
* {@link #getOutPrintWriter()} and errors to {@link #getErrPrintWriter()}.
*
diff --git a/core/java/android/preference/SeekBarVolumizer.java b/core/java/android/preference/SeekBarVolumizer.java
index 1ec00db..f1d59e2 100644
--- a/core/java/android/preference/SeekBarVolumizer.java
+++ b/core/java/android/preference/SeekBarVolumizer.java
@@ -348,8 +348,8 @@
if (msg.what == UPDATE_SLIDER) {
if (mSeekBar != null) {
mLastProgress = msg.arg1;
- mLastAudibleStreamVolume = Math.abs(msg.arg2);
- final boolean muted = msg.arg2 < 0;
+ mLastAudibleStreamVolume = msg.arg2;
+ final boolean muted = ((Boolean)msg.obj).booleanValue();
if (muted != mMuted) {
mMuted = muted;
if (mCallback != null) {
@@ -362,8 +362,7 @@
}
public void postUpdateSlider(int volume, int lastAudibleVolume, boolean mute) {
- final int arg2 = lastAudibleVolume * (mute ? -1 : 1);
- obtainMessage(UPDATE_SLIDER, volume, arg2).sendToTarget();
+ obtainMessage(UPDATE_SLIDER, volume, lastAudibleVolume, new Boolean(mute)).sendToTarget();
}
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index b1dcb81..38ad68d 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6416,6 +6416,12 @@
public static final String DEVICE_PAIRED = "device_paired";
/**
+ * Specifies additional package name for broadcasting the CMAS messages.
+ * @hide
+ */
+ public static final String CMAS_ADDITIONAL_BROADCAST_PKG = "cmas_additional_broadcast_pkg";
+
+ /**
* This are the settings to be backed up.
*
* NOTE: Settings are backed up and restored in the order they appear
@@ -7692,6 +7698,16 @@
public static final String NETWORK_RECOMMENDATION_REQUEST_TIMEOUT_MS =
"network_recommendation_request_timeout_ms";
+ /**
+ * The expiration time in milliseconds for the {@link android.net.WifiKey} request cache in
+ * {@link com.android.server.wifi.RecommendedNetworkEvaluator}.
+ *
+ * Type: long
+ * @hide
+ */
+ public static final String RECOMMENDED_NETWORK_EVALUATOR_CACHE_EXPIRY_MS =
+ "recommended_network_evaluator_cache_expiry_ms";
+
/**
* Settings to allow BLE scans to be enabled even when Bluetooth is turned off for
* connectivity.
diff --git a/core/java/android/text/Hyphenator.java b/core/java/android/text/Hyphenator.java
index 356804e..80ec03e 100644
--- a/core/java/android/text/Hyphenator.java
+++ b/core/java/android/text/Hyphenator.java
@@ -189,7 +189,9 @@
// TODO: replace this with a discovery-based method that looks into /system/usr/hyphen-data
String[] availableLanguages = {
"as",
+ "bg",
"bn",
+ "cu",
"cy",
"da",
"de-1901", "de-1996", "de-CH-1901",
diff --git a/core/java/android/webkit/WebViewZygote.java b/core/java/android/webkit/WebViewZygote.java
index 2d6f443..f9d7332 100644
--- a/core/java/android/webkit/WebViewZygote.java
+++ b/core/java/android/webkit/WebViewZygote.java
@@ -176,7 +176,7 @@
// paths and pass them to the zygote as strings.
final List<String> zipPaths = new ArrayList<>(10);
final List<String> libPaths = new ArrayList<>(10);
- LoadedApk.makePaths(null, sPackage.applicationInfo, zipPaths, libPaths);
+ LoadedApk.makePaths(null, false, sPackage.applicationInfo, zipPaths, libPaths);
final String librarySearchPath = TextUtils.join(File.pathSeparator, libPaths);
final String zip = (zipPaths.size() == 1) ? zipPaths.get(0) :
TextUtils.join(File.pathSeparator, zipPaths);
diff --git a/core/java/com/android/internal/util/Predicate.java b/core/java/com/android/internal/util/Predicate.java
index bc6d6b3..1b5eaff 100644
--- a/core/java/com/android/internal/util/Predicate.java
+++ b/core/java/com/android/internal/util/Predicate.java
@@ -25,7 +25,10 @@
* <p/>
* Implementors of Predicate which may cause side effects upon evaluation are
* strongly encouraged to state this fact clearly in their API documentation.
+ *
+ * @deprecated Use {@code java.util.function.Predicate} instead.
*/
+@Deprecated
public interface Predicate<T> {
boolean apply(T t);
diff --git a/core/java/com/android/internal/util/StateMachine.java b/core/java/com/android/internal/util/StateMachine.java
index be10608df..d67cef3 100644
--- a/core/java/com/android/internal/util/StateMachine.java
+++ b/core/java/com/android/internal/util/StateMachine.java
@@ -23,6 +23,8 @@
import android.text.TextUtils;
import android.util.Log;
+import com.android.internal.annotations.VisibleForTesting;
+
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.io.StringWriter;
@@ -1495,7 +1497,7 @@
}
/**
- * @return number of log records
+ * @return the number of log records currently readable
*/
public final int getLogRecSize() {
// mSmHandler can be null if the state machine has quit.
@@ -1505,6 +1507,17 @@
}
/**
+ * @return the number of log records we can store
+ */
+ @VisibleForTesting
+ public final int getLogRecMaxSize() {
+ // mSmHandler can be null if the state machine has quit.
+ SmHandler smh = mSmHandler;
+ if (smh == null) return 0;
+ return smh.mLogRecords.mMaxSize;
+ }
+
+ /**
* @return the total number of records processed
*/
public final int getLogRecCount() {
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index e940732..a9ca12b 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -273,6 +273,7 @@
libhidlbase \
libhidltransport \
libhwbinder \
+ libvintf \
LOCAL_SHARED_LIBRARIES += \
libhwui \
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index 3a2df75..a758489 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -1027,17 +1027,13 @@
env->ReleaseStringCritical(fileName, str);
}
- int fd = open(fileName8.string(), O_CREAT | O_WRONLY | O_NOFOLLOW, 0666); /* -rw-rw-rw- */
+ int fd = open(fileName8.string(), O_CREAT | O_WRONLY | O_NOFOLLOW | O_CLOEXEC | O_APPEND, 0666);
if (fd < 0) {
fprintf(stderr, "Can't open %s: %s\n", fileName8.string(), strerror(errno));
return;
}
- if (lseek(fd, 0, SEEK_END) < 0) {
- fprintf(stderr, "lseek: %s\n", strerror(errno));
- } else {
- dump_backtrace_to_file_timeout(pid, fd, timeoutSecs);
- }
+ dump_backtrace_to_file_timeout(pid, fd, timeoutSecs);
close(fd);
}
diff --git a/core/jni/android_os_HwBinder.cpp b/core/jni/android_os_HwBinder.cpp
index 1f7efa1..c1d4251 100644
--- a/core/jni/android_os_HwBinder.cpp
+++ b/core/jni/android_os_HwBinder.cpp
@@ -33,6 +33,7 @@
#include <hidl/HidlTransportSupport.h>
#include <hwbinder/ProcessState.h>
#include <nativehelper/ScopedLocalRef.h>
+#include <vintf/parse_string.h>
#include "core_jni_helpers.h"
@@ -300,6 +301,8 @@
jstring ifaceNameObj,
jstring serviceNameObj) {
+ using ::android::vintf::operator<<;
+
if (ifaceNameObj == NULL) {
jniThrowException(env, "java/lang/NullPointerException", NULL);
return NULL;
@@ -317,27 +320,41 @@
return NULL;
}
- const char *ifaceName = env->GetStringUTFChars(ifaceNameObj, NULL);
- if (ifaceName == NULL) {
+ const char *ifaceNameCStr = env->GetStringUTFChars(ifaceNameObj, NULL);
+ if (ifaceNameCStr == NULL) {
return NULL; // XXX exception already pending?
}
- const char *serviceName = env->GetStringUTFChars(serviceNameObj, NULL);
- if (serviceName == NULL) {
- env->ReleaseStringUTFChars(ifaceNameObj, ifaceName);
+ std::string ifaceName(ifaceNameCStr);
+ env->ReleaseStringUTFChars(ifaceNameObj, ifaceNameCStr);
+ ::android::hardware::hidl_string ifaceNameHStr;
+ ifaceNameHStr.setToExternal(ifaceName.c_str(), ifaceName.size());
+
+ const char *serviceNameCStr = env->GetStringUTFChars(serviceNameObj, NULL);
+ if (serviceNameCStr == NULL) {
return NULL; // XXX exception already pending?
}
+ std::string serviceName(serviceNameCStr);
+ env->ReleaseStringUTFChars(serviceNameObj, serviceNameCStr);
+ ::android::hardware::hidl_string serviceNameHStr;
+ serviceNameHStr.setToExternal(serviceName.c_str(), serviceName.size());
LOG(INFO) << "Looking for service "
<< ifaceName
<< "/"
<< serviceName;
- Return<sp<hidl::base::V1_0::IBase>> ret = manager->get(ifaceName, serviceName);
+ ::android::vintf::Transport transport =
+ ::android::hardware::getTransport(ifaceName);
+ if ( transport != ::android::vintf::Transport::EMPTY
+ && transport != ::android::vintf::Transport::HWBINDER) {
+ LOG(ERROR) << "service " << ifaceName << " declares transport method "
+ << transport << " but framework expects "
+ << ::android::vintf::Transport::HWBINDER;
+ signalExceptionForError(env, UNKNOWN_ERROR, true /* canThrowRemoteException */);
+ return NULL;
+ }
- env->ReleaseStringUTFChars(ifaceNameObj, ifaceName);
- ifaceName = NULL;
- env->ReleaseStringUTFChars(serviceNameObj, serviceName);
- serviceName = NULL;
+ Return<sp<hidl::base::V1_0::IBase>> ret = manager->get(ifaceNameHStr, serviceNameHStr);
if (!ret.isOk()) {
signalExceptionForError(env, UNKNOWN_ERROR, true /* canThrowRemoteException */);
diff --git a/core/jni/android_os_seccomp.cpp b/core/jni/android_os_seccomp.cpp
index 3f021ae..dd5622d 100644
--- a/core/jni/android_os_seccomp.cpp
+++ b/core/jni/android_os_seccomp.cpp
@@ -14,216 +14,11 @@
* limitations under the License.
*/
-#include "JNIHelp.h"
#include "core_jni_helpers.h"
#include "JniConstants.h"
#include "utils/Log.h"
-#include "utils/misc.h"
-
-#if defined __arm__ || defined __aarch64__
-
-#include <vector>
-
-#include <sys/prctl.h>
-
-#include <linux/unistd.h>
-#include <linux/audit.h>
-#include <linux/filter.h>
-#include <linux/seccomp.h>
-
#include "seccomp_policy.h"
-#define syscall_nr (offsetof(struct seccomp_data, nr))
-#define arch_nr (offsetof(struct seccomp_data, arch))
-
-typedef std::vector<sock_filter> filter;
-
-// We want to keep the below inline functions for debugging and future
-// development even though they are not all sed currently.
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wunused-function"
-
-static inline void Kill(filter& f) {
- f.push_back(BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL));
-}
-
-static inline void Trap(filter& f) {
- f.push_back(BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRAP));
-}
-
-static inline void Error(filter& f, __u16 retcode) {
- f.push_back(BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ERRNO + retcode));
-}
-
-inline static void Trace(filter& f) {
- f.push_back(BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_TRACE));
-}
-
-inline static void Allow(filter& f) {
- f.push_back(BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW));
-}
-
-#pragma clang diagnostic pop
-
-inline static void AllowSyscall(filter& f, __u32 num) {
- f.push_back(BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, num, 0, 1));
- Allow(f);
-}
-
-inline static void ExamineSyscall(filter& f) {
- f.push_back(BPF_STMT(BPF_LD|BPF_W|BPF_ABS, syscall_nr));
-}
-
-inline static int SetValidateArchitectureJumpTarget(size_t offset, filter& f) {
- size_t jump_length = f.size() - offset - 1;
- auto u8_jump_length = (__u8) jump_length;
- if (u8_jump_length != jump_length) {
- ALOGE("Can't set jump greater than 255 - actual jump is %zu",
- jump_length);
- return -1;
- }
- f[offset] = BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, AUDIT_ARCH_ARM, u8_jump_length, 0);
- return 0;
-}
-
-inline static size_t ValidateArchitectureAndJumpIfNeeded(filter& f) {
- f.push_back(BPF_STMT(BPF_LD|BPF_W|BPF_ABS, arch_nr));
-
- f.push_back(BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, AUDIT_ARCH_AARCH64, 2, 0));
- f.push_back(BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, AUDIT_ARCH_ARM, 1, 0));
- Trap(f);
- return f.size() - 2;
-}
-
-static bool install_filter(filter const& f) {
- struct sock_fprog prog = {
- (unsigned short) f.size(),
- (struct sock_filter*) &f[0],
- };
-
- if (prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog) < 0) {
- ALOGE("SECCOMP: Could not set seccomp filter of size %zu: %s", f.size(), strerror(errno));
- return false;
- }
-
- ALOGI("SECCOMP: Global filter of size %zu installed", f.size());
- return true;
-}
-
-bool set_seccomp_filter() {
- filter f;
-
- // Note that for mixed 64/32 bit architectures, ValidateArchitecture inserts a
- // jump that must be changed to point to the start of the 32-bit policy
- // 32 bit syscalls will not hit the policy between here and the call to SetJump
- auto offset_to_32bit_filter =
- ValidateArchitectureAndJumpIfNeeded(f);
-
- // 64-bit filter
- ExamineSyscall(f);
-
- // arm64-only filter - autogenerated from bionic syscall usage
- for (size_t i = 0; i < arm64_filter_size; ++i)
- f.push_back(arm64_filter[i]);
-
- // Syscalls needed to boot Android
- AllowSyscall(f, 41); // __NR_pivot_root
- AllowSyscall(f, 31); // __NR_ioprio_get
- AllowSyscall(f, 30); // __NR_ioprio_set
- AllowSyscall(f, 178); // __NR_gettid
- AllowSyscall(f, 98); // __NR_futex
- AllowSyscall(f, 220); // __NR_clone
- AllowSyscall(f, 139); // __NR_rt_sigreturn
- AllowSyscall(f, 240); // __NR_rt_tgsigqueueinfo
- AllowSyscall(f, 128); // __NR_restart_syscall
- AllowSyscall(f, 278); // __NR_getrandom
-
- // Needed for performance tools
- AllowSyscall(f, 241); // __NR_perf_event_open
-
- // Needed for strace
- AllowSyscall(f, 130); // __NR_tkill
-
- // Needed for kernel to restart syscalls
- AllowSyscall(f, 128); // __NR_restart_syscall
-
- // b/35034743
- AllowSyscall(f, 267); // __NR_fstatfs64
-
- Trap(f);
-
- if (SetValidateArchitectureJumpTarget(offset_to_32bit_filter, f) != 0)
- return -1;
-
- // 32-bit filter
- ExamineSyscall(f);
-
- // arm32 filter - autogenerated from bionic syscall usage
- for (size_t i = 0; i < arm_filter_size; ++i)
- f.push_back(arm_filter[i]);
-
- // Syscalls needed to boot android
- AllowSyscall(f, 120); // __NR_clone
- AllowSyscall(f, 240); // __NR_futex
- AllowSyscall(f, 119); // __NR_sigreturn
- AllowSyscall(f, 173); // __NR_rt_sigreturn
- AllowSyscall(f, 363); // __NR_rt_tgsigqueueinfo
- AllowSyscall(f, 224); // __NR_gettid
-
- // Syscalls needed to run Chrome
- AllowSyscall(f, 383); // __NR_seccomp - needed to start Chrome
- AllowSyscall(f, 384); // __NR_getrandom - needed to start Chrome
-
- // Syscalls needed to run GFXBenchmark
- AllowSyscall(f, 190); // __NR_vfork
-
- // Needed for strace
- AllowSyscall(f, 238); // __NR_tkill
-
- // Needed for kernel to restart syscalls
- AllowSyscall(f, 0); // __NR_restart_syscall
-
- // Needed for debugging 32-bit Chrome
- AllowSyscall(f, 42); // __NR_pipe
-
- // b/34732712
- AllowSyscall(f, 364); // __NR_perf_event_open
-
- // b/34651972
- AllowSyscall(f, 33); // __NR_access
- AllowSyscall(f, 195); // __NR_stat64
-
- // b/34813887
- AllowSyscall(f, 5); // __NR_open
- AllowSyscall(f, 141); // __NR_getdents
- AllowSyscall(f, 217); // __NR_getdents64
-
- // b/34719286
- AllowSyscall(f, 351); // __NR_eventfd
-
- // b/34817266
- AllowSyscall(f, 252); // __NR_epoll_wait
-
- // Needed by sanitizers (b/34606909)
- // 5 (__NR_open) and 195 (__NR_stat64) are also required, but they are
- // already allowed.
- AllowSyscall(f, 85); // __NR_readlink
-
- // b/34908783
- AllowSyscall(f, 250); // __NR_epoll_create
-
- // b/34979910
- AllowSyscall(f, 8); // __NR_creat
- AllowSyscall(f, 10); // __NR_unlink
-
- // b/35059702
- AllowSyscall(f, 196); // __NR_lstat64
-
- Trap(f);
-
- return install_filter(f);
-}
-
static void Seccomp_setPolicy(JNIEnv* /*env*/) {
if (!set_seccomp_filter()) {
ALOGE("Failed to set seccomp policy - killing");
@@ -231,13 +26,6 @@
}
}
-#else // #if defined __arm__ || defined __aarch64__
-
-static void Seccomp_setPolicy(JNIEnv* /*env*/) {
-}
-
-#endif
-
static const JNINativeMethod method_table[] = {
NATIVE_METHOD(Seccomp, setPolicy, "()V"),
};
diff --git a/core/jni/android_util_Process.cpp b/core/jni/android_util_Process.cpp
index b57f2362..a03d3c5 100644
--- a/core/jni/android_util_Process.cpp
+++ b/core/jni/android_util_Process.cpp
@@ -252,25 +252,26 @@
if (t_pri >= ANDROID_PRIORITY_BACKGROUND) {
// This task wants to stay at background
// update its cpuset so it doesn't only run on bg core(s)
-#ifdef ENABLE_CPUSETS
- int err = set_cpuset_policy(t_pid, sp);
- if (err != NO_ERROR) {
- signalExceptionForGroupError(env, -err, t_pid);
- break;
+ if (cpusets_enabled()) {
+ int err = set_cpuset_policy(t_pid, sp);
+ if (err != NO_ERROR) {
+ signalExceptionForGroupError(env, -err, t_pid);
+ break;
+ }
}
-#endif
continue;
}
}
int err;
-#ifdef ENABLE_CPUSETS
- // set both cpuset and cgroup for general threads
- err = set_cpuset_policy(t_pid, sp);
- if (err != NO_ERROR) {
- signalExceptionForGroupError(env, -err, t_pid);
- break;
+
+ if (cpusets_enabled()) {
+ // set both cpuset and cgroup for general threads
+ err = set_cpuset_policy(t_pid, sp);
+ if (err != NO_ERROR) {
+ signalExceptionForGroupError(env, -err, t_pid);
+ break;
+ }
}
-#endif
err = set_sched_policy(t_pid, sp);
if (err != NO_ERROR) {
@@ -291,7 +292,6 @@
return (int) sp;
}
-#ifdef ENABLE_CPUSETS
/** Sample CPUset list format:
* 0-3,4,6-8
*/
@@ -367,7 +367,6 @@
}
return;
}
-#endif
/**
@@ -376,22 +375,21 @@
* them in the passed in cpu_set_t
*/
void get_exclusive_cpuset_cores(SchedPolicy policy, cpu_set_t *cpu_set) {
-#ifdef ENABLE_CPUSETS
- int i;
- cpu_set_t tmp_set;
- get_cpuset_cores_for_policy(policy, cpu_set);
- for (i = 0; i < SP_CNT; i++) {
- if ((SchedPolicy) i == policy) continue;
- get_cpuset_cores_for_policy((SchedPolicy)i, &tmp_set);
- // First get cores exclusive to one set or the other
- CPU_XOR(&tmp_set, cpu_set, &tmp_set);
- // Then get the ones only in cpu_set
- CPU_AND(cpu_set, cpu_set, &tmp_set);
+ if (cpusets_enabled()) {
+ int i;
+ cpu_set_t tmp_set;
+ get_cpuset_cores_for_policy(policy, cpu_set);
+ for (i = 0; i < SP_CNT; i++) {
+ if ((SchedPolicy) i == policy) continue;
+ get_cpuset_cores_for_policy((SchedPolicy)i, &tmp_set);
+ // First get cores exclusive to one set or the other
+ CPU_XOR(&tmp_set, cpu_set, &tmp_set);
+ // Then get the ones only in cpu_set
+ CPU_AND(cpu_set, cpu_set, &tmp_set);
+ }
+ } else {
+ CPU_ZERO(cpu_set);
}
-#else
- (void) policy;
- CPU_ZERO(cpu_set);
-#endif
return;
}
diff --git a/core/jni/android_view_InputChannel.cpp b/core/jni/android_view_InputChannel.cpp
index c7998a1..1c6ead0 100644
--- a/core/jni/android_view_InputChannel.cpp
+++ b/core/jni/android_view_InputChannel.cpp
@@ -111,11 +111,12 @@
}
static jobject android_view_InputChannel_createInputChannel(JNIEnv* env,
- NativeInputChannel* nativeInputChannel) {
+ std::unique_ptr<NativeInputChannel> nativeInputChannel) {
jobject inputChannelObj = env->NewObject(gInputChannelClassInfo.clazz,
gInputChannelClassInfo.ctor);
if (inputChannelObj) {
- android_view_InputChannel_setNativeInputChannel(env, inputChannelObj, nativeInputChannel);
+ android_view_InputChannel_setNativeInputChannel(env, inputChannelObj,
+ nativeInputChannel.release());
}
return inputChannelObj;
}
@@ -143,13 +144,13 @@
}
jobject serverChannelObj = android_view_InputChannel_createInputChannel(env,
- new NativeInputChannel(serverChannel));
+ std::make_unique<NativeInputChannel>(serverChannel));
if (env->ExceptionCheck()) {
return NULL;
}
jobject clientChannelObj = android_view_InputChannel_createInputChannel(env,
- new NativeInputChannel(clientChannel));
+ std::make_unique<NativeInputChannel>(clientChannel));
if (env->ExceptionCheck()) {
return NULL;
}
diff --git a/core/res/res/layout/resolver_list.xml b/core/res/res/layout/resolver_list.xml
index c4e8e9c..40c9941 100644
--- a/core/res/res/layout/resolver_list.xml
+++ b/core/res/res/layout/resolver_list.xml
@@ -45,7 +45,7 @@
android:textColor="?attr/colorAccent"
android:gravity="center_vertical"
android:layout_alignParentTop="true"
- android:layout_alignParentRight="true"
+ android:layout_alignParentEnd="true"
android:singleLine="true" />
<TextView
@@ -59,7 +59,7 @@
android:paddingEnd="?attr/dialogPreferredPadding"
android:paddingTop="8dp"
android:layout_below="@id/profile_button"
- android:layout_alignParentLeft="true"
+ android:layout_alignParentStart="true"
android:paddingBottom="8dp" />
</RelativeLayout>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 4ff78ea..2b2e18b 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -236,6 +236,7 @@
<item>"mobile,0,0,0,-1,true"</item>
<item>"mobile_mms,2,0,2,60000,true"</item>
<item>"mobile_supl,3,0,2,60000,true"</item>
+ <item>"mobile_dun,4,0,2,60000,true"</item>
<item>"mobile_hipri,5,0,3,60000,true"</item>
<item>"mobile_fota,10,0,2,60000,true"</item>
<item>"mobile_ims,11,0,2,60000,true"</item>
@@ -2683,6 +2684,6 @@
<!-- An array of packages for which notifications cannot be blocked. -->
<string-array translatable="false" name="config_nonBlockableNotificationPackages" />
- <!-- Component name of the default cell broadcast receiver -->
- <string name="config_defaultCellBroadcastReceiverComponent" translatable="false">com.android.cellbroadcastreceiver/.PrivilegedCellBroadcastReceiver</string>
+ <!-- Package name of the default cell broadcast receiver -->
+ <string name="config_defaultCellBroadcastReceiverPkg" translatable="false">com.android.cellbroadcastreceiver</string>
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 426d2eb..4231698 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -101,6 +101,8 @@
<!-- Displayed when the user dialed an MMI code whose function
could not be performed because FDN is enabled. This will be displayed in a toast. -->
<string name="mmiFdnError">Operation is restricted to fixed dialing numbers only.</string>
+ <!-- Displayed when a carrier does not support call forwarding queries when roaming. -->
+ <string name="mmiErrorWhileRoaming">Can not change call forwarding settings from your phone while you are roaming.</string>
<!-- Displayed when a phone feature such as call barring was activated. -->
<string name="serviceEnabled">Service was enabled.</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index bdac134..dbeda0b 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -725,6 +725,7 @@
<java-symbol type="string" name="mmiComplete" />
<java-symbol type="string" name="mmiError" />
<java-symbol type="string" name="mmiFdnError" />
+ <java-symbol type="string" name="mmiErrorWhileRoaming" />
<java-symbol type="string" name="month_day_year" />
<java-symbol type="string" name="more_item_label" />
<java-symbol type="string" name="needPuk" />
@@ -2740,5 +2741,5 @@
<!-- Network Recommendation -->
<java-symbol type="array" name="config_networkRecommendationPackageNames" />
- <java-symbol type="string" name="config_defaultCellBroadcastReceiverComponent" />
+ <java-symbol type="string" name="config_defaultCellBroadcastReceiverPkg" />
</resources>
diff --git a/core/tests/coretests/Android.mk b/core/tests/coretests/Android.mk
index 33a9265..8ac5252 100644
--- a/core/tests/coretests/Android.mk
+++ b/core/tests/coretests/Android.mk
@@ -21,6 +21,7 @@
$(call all-java-files-under, DisabledTestApp/src) \
$(call all-java-files-under, EnabledTestApp/src)
+LOCAL_DX_FLAGS := --core-library
LOCAL_AAPT_FLAGS = -0 dat -0 gld -c fa
LOCAL_STATIC_JAVA_LIBRARIES := \
core-tests-support \
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/Android.mk
index 836ede6..14b032e 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyAndException/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyAndException/Android.mk
@@ -31,9 +31,28 @@
LOCAL_JAVACFLAGS := -nowarn
+mainDexList:= \
+ $(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list
+
+LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList) --minimal-main-dex
LOCAL_JACK_FLAGS := -D jack.dex.output.policy=minimal-multidex -D jack.preprocessor=true\
-D jack.preprocessor.file=$(LOCAL_PATH)/test.jpp -D jack.dex.output.multidex.legacy=true
+#################################
+include $(BUILD_SYSTEM)/configure_local_jack.mk
+#################################
+
+ifdef LOCAL_JACK_ENABLED
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/test.jpp
+endif
include $(BUILD_PACKAGE)
+
+ifndef LOCAL_JACK_ENABLED
+$(mainDexList): $(full_classes_proguard_jar) | $(MAINDEXCLASSES)
+ $(hide) mkdir -p $(dir $@)
+ $(MAINDEXCLASSES) $< 1>$@
+ echo "com/android/multidexlegacyandexception/Test.class" >> $@
+
+$(built_dex_intermediate): $(mainDexList)
+endif
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk
index 2915914..208eceb 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestApp/Android.mk
@@ -29,13 +29,32 @@
LOCAL_DEX_PREOPT := false
+mainDexList:= \
+ $(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list
+
+LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList) --minimal-main-dex
LOCAL_JACK_FLAGS := -D jack.dex.output.policy=minimal-multidex -D jack.preprocessor=true\
-D jack.preprocessor.file=$(LOCAL_PATH)/test.jpp -D jack.dex.output.multidex.legacy=true
+#################################
+include $(BUILD_SYSTEM)/configure_local_jack.mk
+#################################
+
+ifdef LOCAL_JACK_ENABLED
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/test.jpp
+endif
include $(BUILD_PACKAGE)
+ifndef LOCAL_JACK_ENABLED
+$(mainDexList): $(full_classes_proguard_jar) | $(MAINDEXCLASSES)
+ $(hide) mkdir -p $(dir $@)
+ $(MAINDEXCLASSES) $< 1>$@
+ echo "com/android/multidexlegacytestapp/Test.class" >> $@
+
+$(built_dex_intermediate): $(mainDexList)
+endif
+
## The application with a full main dex
include $(CLEAR_VARS)
@@ -51,9 +70,28 @@
LOCAL_DEX_PREOPT := false
+mainDexList2:= \
+ $(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list
+
+LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList2)
LOCAL_JACK_FLAGS := -D jack.dex.output.policy=multidex -D jack.preprocessor=true\
-D jack.preprocessor.file=$(LOCAL_PATH)/test.jpp -D jack.dex.output.multidex.legacy=true
+#################################
+include $(BUILD_SYSTEM)/configure_local_jack.mk
+#################################
+
+ifdef LOCAL_JACK_ENABLED
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/test.jpp
+endif
include $(BUILD_PACKAGE)
+
+ifndef LOCAL_JACK_ENABLED
+$(mainDexList2): $(full_classes_proguard_jar) | $(MAINDEXCLASSES)
+ $(hide) mkdir -p $(dir $@)
+ $(MAINDEXCLASSES) $< 1>$@
+ echo "com/android/multidexlegacytestapp/Test.class" >> $@
+
+$(built_dex_intermediate): $(mainDexList2)
+endif
\ No newline at end of file
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/Android.mk
index 2732372..99bcd6c 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyTestServices/Android.mk
@@ -26,8 +26,20 @@
LOCAL_STATIC_JAVA_LIBRARIES := android-support-multidex
+mainDexList:= \
+ $(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list
+
+LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList) --minimal-main-dex
LOCAL_JACK_FLAGS := -D jack.dex.output.policy=minimal-multidex -D jack.dex.output.multidex.legacy=true
LOCAL_DEX_PREOPT := false
include $(BUILD_PACKAGE)
+
+ifndef LOCAL_JACK_ENABLED
+$(mainDexList): $(full_classes_proguard_jar) | $(MAINDEXCLASSES)
+ $(hide) mkdir -p $(dir $@)
+ $(MAINDEXCLASSES) $< 1>$@
+
+$(built_dex_intermediate): $(mainDexList)
+endif
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/Android.mk
index b4a666f..1c7d807 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v1/Android.mk
@@ -28,9 +28,28 @@
LOCAL_DEX_PREOPT := false
+mainDexList:= \
+ $(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list
+
+LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList) --minimal-main-dex
LOCAL_JACK_FLAGS := -D jack.dex.output.policy=minimal-multidex -D jack.preprocessor=true\
-D jack.preprocessor.file=$(LOCAL_PATH)/test.jpp -D jack.dex.output.multidex.legacy=true
+#################################
+include $(BUILD_SYSTEM)/configure_local_jack.mk
+#################################
+
+ifdef LOCAL_JACK_ENABLED
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/test.jpp
+endif
include $(BUILD_PACKAGE)
+
+ifndef LOCAL_JACK_ENABLED
+$(mainDexList): $(full_classes_proguard_jar) | $(MAINDEXCLASSES)
+ $(hide) mkdir -p $(dir $@)
+ $(MAINDEXCLASSES) $< 1>$@
+ echo "com/android/framework/multidexlegacyversionedtestapp/MultiDexUpdateTest.class" >> $@
+
+$(built_dex_intermediate): $(mainDexList)
+endif
\ No newline at end of file
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/Android.mk
index f38bd4f..b77cf31 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v2/Android.mk
@@ -28,9 +28,28 @@
LOCAL_DEX_PREOPT := false
+mainDexList:= \
+ $(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list
+
+LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList) --minimal-main-dex
LOCAL_JACK_FLAGS := -D jack.dex.output.policy=minimal-multidex -D jack.preprocessor=true\
-D jack.preprocessor.file=$(LOCAL_PATH)/test.jpp -D jack.dex.output.multidex.legacy=true
+#################################
+include $(BUILD_SYSTEM)/configure_local_jack.mk
+#################################
+
+ifdef LOCAL_JACK_ENABLED
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/test.jpp
+endif
include $(BUILD_PACKAGE)
+
+ifndef LOCAL_JACK_ENABLED
+$(mainDexList): $(full_classes_proguard_jar) | $(MAINDEXCLASSES)
+ $(hide) mkdir -p $(dir $@)
+ $(MAINDEXCLASSES) $< 1>$@
+ echo "com/android/framework/multidexlegacyversionedtestapp/MultiDexUpdateTest.class" >> $@
+
+$(built_dex_intermediate): $(mainDexList)
+endif
diff --git a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/Android.mk b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/Android.mk
index 5bc2c95..3631626 100644
--- a/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/Android.mk
+++ b/core/tests/hosttests/test-apps/MultiDexLegacyVersionedTestApp_v3/Android.mk
@@ -26,11 +26,31 @@
LOCAL_STATIC_JAVA_LIBRARIES := android-support-multidex
+mainDexList:= \
+ $(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),$(LOCAL_IS_HOST_MODULE),common)/maindex.list
+
LOCAL_DEX_PREOPT := false
+LOCAL_DX_FLAGS := --multi-dex --main-dex-list=$(mainDexList) --minimal-main-dex
LOCAL_JACK_FLAGS := -D jack.dex.output.policy=minimal-multidex -D jack.preprocessor=true\
-D jack.preprocessor.file=$(LOCAL_PATH)/test.jpp -D jack.dex.output.multidex.legacy=true
+#################################
+include $(BUILD_SYSTEM)/configure_local_jack.mk
+#################################
+
+ifdef LOCAL_JACK_ENABLED
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/test.jpp
+endif
include $(BUILD_PACKAGE)
+
+ifndef LOCAL_JACK_ENABLED
+$(mainDexList): $(full_classes_proguard_jar) | $(MAINDEXCLASSES)
+ $(hide) mkdir -p $(dir $@)
+ $(MAINDEXCLASSES) $< 1>$@
+ echo "com/android/framework/multidexlegacyversionedtestapp/MultiDexUpdateTest.class" >> $@
+
+$(built_dex_intermediate): $(mainDexList)
+endif
+
diff --git a/core/tests/systemproperties/Android.mk b/core/tests/systemproperties/Android.mk
index e16c367..4c2e224 100644
--- a/core/tests/systemproperties/Android.mk
+++ b/core/tests/systemproperties/Android.mk
@@ -8,6 +8,7 @@
LOCAL_SRC_FILES := \
$(call all-java-files-under, src)
+LOCAL_DX_FLAGS := --core-library
LOCAL_STATIC_JAVA_LIBRARIES := android-common frameworks-core-util-lib
LOCAL_JAVA_LIBRARIES := android.test.runner
LOCAL_PACKAGE_NAME := FrameworksCoreSystemPropertiesTests
diff --git a/legacy-test/Android.mk b/legacy-test/Android.mk
index 0a814f3..05fec5e 100644
--- a/legacy-test/Android.mk
+++ b/legacy-test/Android.mk
@@ -50,5 +50,5 @@
LOCAL_SRC_FILES := src/android/test/PerformanceTestCase.java
LOCAL_MODULE := legacy-performance-test-hostdex
-include $(BUILD_HOST_DALVIK_JAVA_LIBRARY)
+include $(BUILD_HOST_DALVIK_STATIC_JAVA_LIBRARY)
endif # HOST_OS == linux
diff --git a/obex/javax/obex/ServerSession.java b/obex/javax/obex/ServerSession.java
index acee5dd..3831cf7 100644
--- a/obex/javax/obex/ServerSession.java
+++ b/obex/javax/obex/ServerSession.java
@@ -658,6 +658,11 @@
*/
byte[] sendData = new byte[totalLength];
int maxRxLength = ObexHelper.getMaxRxPacketSize(mTransport);
+ if (maxRxLength > mMaxPacketLength) {
+ if(V) Log.v(TAG,"Set maxRxLength to min of maxRxServrLen:" + maxRxLength +
+ " and MaxNegotiated from Client: " + mMaxPacketLength);
+ maxRxLength = mMaxPacketLength;
+ }
sendData[0] = (byte)code;
sendData[1] = length[2];
sendData[2] = length[3];
diff --git a/packages/CarrierDefaultApp/AndroidManifest.xml b/packages/CarrierDefaultApp/AndroidManifest.xml
index e2080b0..d910920 100644
--- a/packages/CarrierDefaultApp/AndroidManifest.xml
+++ b/packages/CarrierDefaultApp/AndroidManifest.xml
@@ -31,7 +31,7 @@
<application android:label="@string/app_name" >
<receiver android:name="com.android.carrierdefaultapp.CarrierDefaultBroadcastReceiver">
<intent-filter>
- <action android:name="android.intent.action.CARRIER_SIGNAL_REDIRECTED" />
+ <action android:name="com.android.internal.telephony.CARRIER_SIGNAL_REDIRECTED" />
</intent-filter>
</receiver>
<activity android:name="com.android.carrierdefaultapp.CaptivePortalLaunchActivity"
diff --git a/packages/DocumentsUI/Android.mk b/packages/DocumentsUI/Android.mk
index 9d44a6d..29035ab 100644
--- a/packages/DocumentsUI/Android.mk
+++ b/packages/DocumentsUI/Android.mk
@@ -12,6 +12,7 @@
LOCAL_STATIC_JAVA_LIBRARIES += android-support-v13
# Supplies material design components, e.g. Snackbar.
LOCAL_STATIC_JAVA_LIBRARIES += android-support-design
+LOCAL_STATIC_JAVA_LIBRARIES += android-support-transition
LOCAL_STATIC_JAVA_LIBRARIES += android-support-v7-recyclerview
LOCAL_STATIC_JAVA_LIBRARIES += guava
@@ -22,6 +23,7 @@
LOCAL_RESOURCE_DIR += \
frameworks/support/v7/appcompat/res \
frameworks/support/design/res \
+ frameworks/support/transition/res \
frameworks/support/v7/recyclerview/res
# Again, required to pull in appcompat resources. See abovementioned demo code.
@@ -29,6 +31,7 @@
--auto-add-overlay \
--extra-packages android.support.v7.appcompat \
--extra-packages android.support.design \
+ --extra-packages android.support.transition \
--extra-packages android.support.v7.recyclerview
LOCAL_JACK_FLAGS := \
diff --git a/packages/ExternalStorageProvider/Android.mk b/packages/ExternalStorageProvider/Android.mk
index ec6af2f..fbf3782 100644
--- a/packages/ExternalStorageProvider/Android.mk
+++ b/packages/ExternalStorageProvider/Android.mk
@@ -5,7 +5,10 @@
LOCAL_SRC_FILES := $(call all-subdir-java-files)
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-documents-archive
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ android-support-documents-archive \
+ android-support-annotations
+
LOCAL_PACKAGE_NAME := ExternalStorageProvider
LOCAL_CERTIFICATE := platform
LOCAL_PRIVILEGED_MODULE := true
diff --git a/packages/PrintSpooler/res/layout/no_print_services_message.xml b/packages/PrintSpooler/res/layout/no_print_services_message.xml
new file mode 100644
index 0000000..7872658
--- /dev/null
+++ b/packages/PrintSpooler/res/layout/no_print_services_message.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="?android:attr/listPreferredItemHeightSmall"
+ android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+ android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+ android:orientation="horizontal"
+ android:gravity="start|center_vertical">
+
+ <RelativeLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="32dip">
+ <HorizontalScrollView
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content">
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:textAppearance="?android:attr/textAppearanceListItem"
+ android:text="@string/print_no_print_services"
+ android:scrollHorizontally="true"
+ android:singleLine="true" />
+ </HorizontalScrollView>
+ </RelativeLayout>
+
+</LinearLayout>
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/AddPrinterActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/AddPrinterActivity.java
index c06e849..72004ef 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/AddPrinterActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/AddPrinterActivity.java
@@ -26,6 +26,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.Loader;
+import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.database.DataSetObserver;
import android.net.Uri;
@@ -95,20 +96,39 @@
*/
private RecommendedServicesAdapter mRecommendedServicesAdapter;
+ private static final String PKG_NAME_VENDING = "com.android.vending";
+ private boolean mHasVending;
+ private NoPrintServiceMessageAdapter mNoPrintServiceMessageAdapter;
+
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.add_printer_activity);
+ try {
+ getPackageManager().getPackageInfo(PKG_NAME_VENDING, 0);
+ mHasVending = true;
+ } catch (PackageManager.NameNotFoundException e) {
+ mHasVending = false;
+ }
mEnabledServicesAdapter = new EnabledServicesAdapter();
mDisabledServicesAdapter = new DisabledServicesAdapter();
- mRecommendedServicesAdapter = new RecommendedServicesAdapter();
+ if (mHasVending) {
+ mRecommendedServicesAdapter = new RecommendedServicesAdapter();
+ } else {
+ mNoPrintServiceMessageAdapter = new NoPrintServiceMessageAdapter();
+ }
ArrayList<ActionAdapter> adapterList = new ArrayList<>(3);
adapterList.add(mEnabledServicesAdapter);
- adapterList.add(mRecommendedServicesAdapter);
+ if (mHasVending) {
+ adapterList.add(mRecommendedServicesAdapter);
+ }
adapterList.add(mDisabledServicesAdapter);
+ if (!mHasVending) {
+ adapterList.add(mNoPrintServiceMessageAdapter);
+ }
setListAdapter(new CombinedAdapter(adapterList));
@@ -119,8 +139,10 @@
getLoaderManager().initLoader(LOADER_ID_ENABLED_SERVICES, null, printServiceLoaderCallbacks);
getLoaderManager().initLoader(LOADER_ID_DISABLED_SERVICES, null, printServiceLoaderCallbacks);
- getLoaderManager().initLoader(LOADER_ID_RECOMMENDED_SERVICES, null,
- new PrintServicePrintServiceRecommendationLoaderCallbacks());
+ if (mHasVending) {
+ getLoaderManager().initLoader(LOADER_ID_RECOMMENDED_SERVICES, null,
+ new PrintServicePrintServiceRecommendationLoaderCallbacks());
+ }
getLoaderManager().initLoader(LOADER_ID_ALL_SERVICES, null, printServiceLoaderCallbacks);
}
@@ -162,7 +184,11 @@
mDisabledServicesAdapter.updateData(data);
break;
case LOADER_ID_ALL_SERVICES:
- mRecommendedServicesAdapter.updateInstalledServices(data);
+ if (mHasVending) {
+ mRecommendedServicesAdapter.updateInstalledServices(data);
+ } else {
+ mNoPrintServiceMessageAdapter.updateInstalledServices(data);
+ }
default:
// not reached
}
@@ -179,7 +205,11 @@
mDisabledServicesAdapter.updateData(null);
break;
case LOADER_ID_ALL_SERVICES:
- mRecommendedServicesAdapter.updateInstalledServices(null);
+ if (mHasVending) {
+ mRecommendedServicesAdapter.updateInstalledServices(null);
+ } else {
+ mNoPrintServiceMessageAdapter.updateInstalledServices(null);
+ }
break;
default:
// not reached
@@ -788,4 +818,61 @@
filterRecommendations();
}
}
+
+ private class NoPrintServiceMessageAdapter extends ActionAdapter {
+ private boolean mHasPrintService;
+
+ void updateInstalledServices(@Nullable List<PrintServiceInfo> services) {
+ if (services == null || services.isEmpty()) {
+ mHasPrintService = false;
+ } else {
+ mHasPrintService = true;
+ }
+ notifyDataSetChanged();
+ }
+
+ @Override
+ public int getCount() {
+ return mHasPrintService ? 0 : 1;
+ }
+
+ @Override
+ public int getViewTypeCount() {
+ return 1;
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ return 0;
+ }
+
+ @Override
+ public Object getItem(int position) {
+ return null;
+ }
+
+ @Override
+ public long getItemId(int position) {
+ return position;
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ if (convertView == null) {
+ convertView = getLayoutInflater().inflate(R.layout.no_print_services_message,
+ parent, false);
+ }
+ return convertView;
+ }
+
+ @Override
+ public boolean isEnabled(int position) {
+ return position != 0;
+ }
+
+ @Override
+ public void performAction(@IntRange(from = 0) int position) {
+ return;
+ }
+ }
}
diff --git a/packages/SettingsLib/common.mk b/packages/SettingsLib/common.mk
index cf0ba6c..0815534 100644
--- a/packages/SettingsLib/common.mk
+++ b/packages/SettingsLib/common.mk
@@ -24,5 +24,9 @@
LOCAL_STATIC_JAVA_LIBRARIES += \
android-support-annotations \
android-support-v4 \
+ android-support-v7-appcompat \
+ android-support-v7-preference \
+ android-support-v7-recyclerview \
+ android-support-v14-preference \
SettingsLib
endif
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 3627c29..064059b 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -57,6 +57,8 @@
<string name="wifi_disabled_generic">Disabled</string>
<!-- Status for networked disabled from a DNS or DHCP failure -->
<string name="wifi_disabled_network_failure">IP Configuration Failure</string>
+ <!-- Status for networks disabled by the network recommendation provider -->
+ <string name="wifi_disabled_by_recommendation_provider">Not connected due to low quality network</string>
<!-- Status for networked disabled from a wifi association failure -->
<string name="wifi_disabled_wifi_failure">WiFi Connection Failure</string>
<!-- Status for networks disabled from authentication failure (wrong password
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index 252aaab..6166cd8 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -422,7 +422,8 @@
// This is the active connection on non-passpoint network
summary.append(getSummary(mContext, getDetailedState(),
mInfo != null && mInfo.isEphemeral()));
- } else if (config != null && config.isPasspoint()) {
+ } else if (config != null && config.isPasspoint()
+ && config.getNetworkSelectionStatus().isNetworkEnabled()) {
String format = mContext.getString(R.string.available_via_passpoint);
summary.append(String.format(format, config.providerFriendlyName));
} else if (config != null && config.hasNoInternetAccess()) {
@@ -445,6 +446,8 @@
summary.append(mContext.getString(R.string.wifi_disabled_generic));
break;
}
+ } else if (config != null && config.getNetworkSelectionStatus().isNotRecommended()) {
+ summary.append(mContext.getString(R.string.wifi_disabled_by_recommendation_provider));
} else if (mRssi == Integer.MAX_VALUE) { // Wifi out of range
summary.append(mContext.getString(R.string.wifi_not_in_range));
} else { // In range, not disabled.
@@ -682,11 +685,7 @@
}
void loadConfig(WifiConfiguration config) {
- if (config.isPasspoint())
- ssid = config.providerFriendlyName;
- else
- ssid = (config.SSID == null ? "" : removeDoubleQuotes(config.SSID));
-
+ ssid = (config.SSID == null ? "" : removeDoubleQuotes(config.SSID));
bssid = config.BSSID;
security = getSecurity(config);
networkId = config.networkId;
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
index 7d279eb..3435d1d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java
@@ -344,29 +344,22 @@
}
AccessPoint accessPoint = getCachedOrCreate(config, cachedAccessPoints);
if (mLastInfo != null && mLastNetworkInfo != null) {
- if (config.isPasspoint() == false) {
- accessPoint.update(connectionConfig, mLastInfo, mLastNetworkInfo);
- }
+ accessPoint.update(connectionConfig, mLastInfo, mLastNetworkInfo);
}
if (mIncludeSaved) {
- if (!config.isPasspoint() || mIncludePasspoints) {
- // If saved network not present in scan result then set its Rssi to MAX_VALUE
- boolean apFound = false;
- for (ScanResult result : results) {
- if (result.SSID.equals(accessPoint.getSsidStr())) {
- apFound = true;
- break;
- }
+ // If saved network not present in scan result then set its Rssi to MAX_VALUE
+ boolean apFound = false;
+ for (ScanResult result : results) {
+ if (result.SSID.equals(accessPoint.getSsidStr())) {
+ apFound = true;
+ break;
}
- if (!apFound) {
- accessPoint.setRssi(Integer.MAX_VALUE);
- }
- accessPoints.add(accessPoint);
}
-
- if (config.isPasspoint() == false) {
- apMap.put(accessPoint.getSsidStr(), accessPoint);
+ if (!apFound) {
+ accessPoint.setRssi(Integer.MAX_VALUE);
}
+ accessPoints.add(accessPoint);
+ apMap.put(accessPoint.getSsidStr(), accessPoint);
} else {
// If we aren't using saved networks, drop them into the cache so that
// we have access to their saved info.
@@ -397,20 +390,16 @@
}
if (result.isPasspointNetwork()) {
+ // Retrieve a WifiConfiguration for a Passpoint provider that matches
+ // the given ScanResult. This is used for showing that a given AP
+ // (ScanResult) is available via a Passpoint provider (provider friendly
+ // name).
WifiConfiguration config = mWifiManager.getMatchingWifiConfig(result);
if (config != null) {
accessPoint.update(config);
}
}
- if (mLastInfo != null && mLastInfo.getBSSID() != null
- && mLastInfo.getBSSID().equals(result.BSSID)
- && connectionConfig != null && connectionConfig.isPasspoint()) {
- /* This network is connected via this passpoint config */
- /* SSID match is not going to work for it; so update explicitly */
- accessPoint.update(connectionConfig);
- }
-
accessPoints.add(accessPoint);
apMap.put(accessPoint.getSsidStr(), accessPoint);
}
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 227d0e9..4f7a826 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -41,6 +41,7 @@
<uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY" />
+ <uses-permission android:name="android.permission.MANAGE_USB" />
<!-- System tool permissions granted to the shell. -->
<uses-permission android:name="android.permission.REAL_GET_TASKS" />
<uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_in.xml b/packages/SystemUI/res/drawable/stat_sys_signal_in.xml
new file mode 100644
index 0000000..7e6e09b
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_signal_in.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:autoMirrored="true"
+ android:width="17dp"
+ android:height="17dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:name="in"
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M8.7,12.2l-2.0,3.5l-2.0,-3.5z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_inout.xml b/packages/SystemUI/res/drawable/stat_sys_signal_inout.xml
new file mode 100644
index 0000000..b7b6f0f
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_signal_inout.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:autoMirrored="true"
+ android:width="17dp"
+ android:height="17dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:name="in"
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M8.7,12.2l-2.0,3.5l-2.0,-3.5z" />
+ <path
+ android:name="out"
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M0.5,15.7l2.0,-3.5l2.0,3.5z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_out.xml b/packages/SystemUI/res/drawable/stat_sys_signal_out.xml
new file mode 100644
index 0000000..910c035
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_signal_out.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:autoMirrored="true"
+ android:width="17dp"
+ android:height="17dp"
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ <path
+ android:name="out"
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M0.5,15.7l2.0,-3.5l2.0,3.5z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_wifi_in.xml b/packages/SystemUI/res/drawable/stat_sys_wifi_in.xml
new file mode 100644
index 0000000..666127b
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_wifi_in.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:autoMirrored="true"
+ android:width="18.41dp"
+ android:height="17dp"
+ android:viewportWidth="26.0"
+ android:viewportHeight="24.0">
+ <path
+ android:name="in"
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M8.7,18.3l-2.0,3.5l-2.0,-3.5z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_wifi_inout.xml b/packages/SystemUI/res/drawable/stat_sys_wifi_inout.xml
new file mode 100644
index 0000000..eeba030
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_wifi_inout.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:autoMirrored="true"
+ android:width="18.41dp"
+ android:height="17dp"
+ android:viewportWidth="26.0"
+ android:viewportHeight="24.0">
+ <path
+ android:name="in"
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M8.7,18.3l-2.0,3.5l-2.0,-3.5z" />
+ <path
+ android:name="out"
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M0.5,21.8l2.0,-3.5l2.0,3.5z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_wifi_out.xml b/packages/SystemUI/res/drawable/stat_sys_wifi_out.xml
new file mode 100644
index 0000000..d577d1a
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_wifi_out.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:autoMirrored="true"
+ android:width="18.41dp"
+ android:height="17dp"
+ android:viewportWidth="26.0"
+ android:viewportHeight="24.0">
+ <path
+ android:name="out"
+ android:fillColor="#FFFFFFFF"
+ android:pathData="M0.5,21.8l2.0,-3.5l2.0,3.5z" />
+</vector>
diff --git a/packages/SystemUI/res/layout/mobile_signal_group.xml b/packages/SystemUI/res/layout/mobile_signal_group.xml
index a20ec8e..f597785 100644
--- a/packages/SystemUI/res/layout/mobile_signal_group.xml
+++ b/packages/SystemUI/res/layout/mobile_signal_group.xml
@@ -43,4 +43,10 @@
android:layout_height="wrap_content"
android:layout_width="wrap_content"
/>
+ <ImageView
+ android:id="@+id/mobile_inout"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:visibility="gone"
+ />
</FrameLayout>
diff --git a/packages/SystemUI/res/layout/signal_cluster_view.xml b/packages/SystemUI/res/layout/signal_cluster_view.xml
index d17601c..f0bfb92 100644
--- a/packages/SystemUI/res/layout/signal_cluster_view.xml
+++ b/packages/SystemUI/res/layout/signal_cluster_view.xml
@@ -70,6 +70,11 @@
android:layout_width="wrap_content"
android:alpha="0.0"
/>
+ <ImageView
+ android:id="@+id/wifi_inout"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ />
</FrameLayout>
<View
android:id="@+id/wifi_signal_spacer"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
index 74caa53..d36f572 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
@@ -75,6 +75,8 @@
private boolean mWifiVisible = false;
private int mWifiStrengthId = 0;
private int mLastWifiStrengthId = -1;
+ private int mWifiActivityId = 0;
+ private int mLastWifiActivityId = -1;
private boolean mIsAirplaneMode = false;
private int mAirplaneIconId = 0;
private int mLastAirplaneIconId = -1;
@@ -89,6 +91,7 @@
ViewGroup mEthernetGroup, mWifiGroup;
View mNoSimsCombo;
ImageView mVpn, mEthernet, mWifi, mAirplane, mNoSims, mEthernetDark, mWifiDark, mNoSimsDark;
+ ImageView mWifiActivity;
View mWifiAirplaneSpacer;
View mWifiSignalSpacer;
LinearLayout mMobileSignalGroup;
@@ -180,6 +183,7 @@
mWifiGroup = (ViewGroup) findViewById(R.id.wifi_combo);
mWifi = (ImageView) findViewById(R.id.wifi_signal);
mWifiDark = (ImageView) findViewById(R.id.wifi_signal_dark);
+ mWifiActivity = (ImageView) findViewById(R.id.wifi_inout);
mAirplane = (ImageView) findViewById(R.id.airplane);
mNoSims = (ImageView) findViewById(R.id.no_sims);
mNoSimsDark = (ImageView) findViewById(R.id.no_sims_dark);
@@ -264,6 +268,10 @@
mWifiVisible = statusIcon.visible && !mBlockWifi;
mWifiStrengthId = statusIcon.icon;
mWifiDescription = statusIcon.contentDescription;
+ mWifiActivityId = activityIn && activityOut ? R.drawable.stat_sys_wifi_inout
+ : activityIn ? R.drawable.stat_sys_wifi_in
+ : activityOut ? R.drawable.stat_sys_wifi_out
+ : 0;
apply();
}
@@ -282,6 +290,10 @@
state.mMobileDescription = statusIcon.contentDescription;
state.mMobileTypeDescription = typeContentDescription;
state.mIsMobileTypeIconWide = statusType != 0 && isWide;
+ state.mMobileActivityId = activityIn && activityOut ? R.drawable.stat_sys_signal_inout
+ : activityIn ? R.drawable.stat_sys_signal_in
+ : activityOut ? R.drawable.stat_sys_signal_out
+ : 0;
apply();
}
@@ -404,6 +416,10 @@
mWifiDark.setImageDrawable(null);
mLastWifiStrengthId = -1;
}
+ if (mWifiActivity != null) {
+ mWifiActivity.setImageDrawable(null);
+ mLastWifiActivityId = -1;
+ }
for (PhoneState state : mPhoneStates) {
if (state.mMobile != null) {
@@ -420,6 +436,10 @@
state.mMobileType.setImageDrawable(null);
state.mLastMobileTypeId = -1;
}
+ if (state.mMobileActivity != null) {
+ state.mMobileActivity.setImageDrawable(null);
+ state.mLastMobileActivityId = -1;
+ }
}
if (mAirplane != null) {
@@ -473,6 +493,12 @@
setIconForView(mWifiDark, mWifiStrengthId);
mLastWifiStrengthId = mWifiStrengthId;
}
+ if (mWifiActivityId != mLastWifiActivityId) {
+ if (mWifiActivityId != 0) {
+ setIconForView(mWifiActivity, mWifiActivityId);
+ }
+ mLastWifiActivityId = mWifiActivityId;
+ }
mWifiGroup.setContentDescription(mWifiDescription);
mWifiGroup.setVisibility(View.VISIBLE);
} else {
@@ -484,6 +510,8 @@
(mWifiVisible ? "VISIBLE" : "GONE"),
mWifiStrengthId));
+ mWifiActivity.setVisibility(mWifiActivityId != 0 ? View.VISIBLE : View.GONE);
+
boolean anyMobileVisible = false;
int firstMobileTypeId = 0;
for (PhoneState state : mPhoneStates) {
@@ -560,6 +588,8 @@
applyDarkIntensity(
StatusBarIconController.getDarkIntensity(mTintArea, mWifi, mDarkIntensity),
mWifi, mWifiDark);
+ setTint(mWifiActivity,
+ StatusBarIconController.getTint(mTintArea, mWifiActivity, mIconTint));
applyDarkIntensity(
StatusBarIconController.getDarkIntensity(mTintArea, mEthernet, mDarkIntensity),
mEthernet, mEthernetDark);
@@ -584,14 +614,16 @@
private class PhoneState {
private final int mSubId;
private boolean mMobileVisible = false;
- private int mMobileStrengthId = 0, mMobileTypeId = 0;
+ private int mMobileStrengthId = 0, mMobileTypeId = 0, mMobileActivityId = 0;
private int mLastMobileStrengthId = -1;
private int mLastMobileTypeId = -1;
+ private int mLastMobileActivityId = -1;
private boolean mIsMobileTypeIconWide;
private String mMobileDescription, mMobileTypeDescription;
private ViewGroup mMobileGroup;
private ImageView mMobile, mMobileDark, mMobileType;
+ private ImageView mMobileActivity;
public PhoneState(int subId, Context context) {
ViewGroup root = (ViewGroup) LayoutInflater.from(context)
@@ -605,6 +637,7 @@
mMobile = (ImageView) root.findViewById(R.id.mobile_signal);
mMobileDark = (ImageView) root.findViewById(R.id.mobile_signal_dark);
mMobileType = (ImageView) root.findViewById(R.id.mobile_type);
+ mMobileActivity = (ImageView) root.findViewById(R.id.mobile_inout);
}
public boolean apply(boolean isSecondaryIcon) {
@@ -619,6 +652,11 @@
mMobileType.setImageResource(mMobileTypeId);
mLastMobileTypeId = mMobileTypeId;
}
+
+ if (mLastMobileActivityId != mMobileActivityId) {
+ mMobileActivity.setImageResource(mMobileActivityId);
+ mLastMobileActivityId = mMobileActivityId;
+ }
mMobileGroup.setContentDescription(mMobileTypeDescription
+ " " + mMobileDescription);
mMobileGroup.setVisibility(View.VISIBLE);
@@ -640,6 +678,7 @@
(mMobileVisible ? "VISIBLE" : "GONE"), mMobileStrengthId, mMobileTypeId));
mMobileType.setVisibility(mMobileTypeId != 0 ? View.VISIBLE : View.GONE);
+ mMobileActivity.setVisibility(mMobileActivityId != 0 ? View.VISIBLE : View.GONE);
return mMobileVisible;
}
@@ -699,6 +738,8 @@
StatusBarIconController.getDarkIntensity(tintArea, mMobile, darkIntensity),
mMobile, mMobileDark);
setTint(mMobileType, StatusBarIconController.getTint(tintArea, mMobileType, tint));
+ setTint(mMobileActivity,
+ StatusBarIconController.getTint(tintArea, mMobileActivity, tint));
}
}
}
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 37e6a2a..9380c45 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -690,6 +690,7 @@
mDemoMode = true;
mDemoInetCondition = mInetCondition;
mDemoWifiState = mWifiSignalController.getState();
+ mDemoWifiState.ssid = "DemoMode";
} else if (mDemoMode && command.equals(COMMAND_EXIT)) {
if (DEBUG) Log.d(TAG, "Exiting demo mode");
mDemoMode = false;
@@ -735,6 +736,25 @@
: Math.min(Integer.parseInt(level), WifiIcons.WIFI_LEVEL_COUNT - 1);
mDemoWifiState.connected = mDemoWifiState.level >= 0;
}
+ String activity = args.getString("activity");
+ if (activity != null) {
+ switch (activity) {
+ case "inout":
+ mWifiSignalController.setActivity(WifiManager.DATA_ACTIVITY_INOUT);
+ break;
+ case "in":
+ mWifiSignalController.setActivity(WifiManager.DATA_ACTIVITY_IN);
+ break;
+ case "out":
+ mWifiSignalController.setActivity(WifiManager.DATA_ACTIVITY_OUT);
+ break;
+ default:
+ mWifiSignalController.setActivity(WifiManager.DATA_ACTIVITY_NONE);
+ break;
+ }
+ } else {
+ mWifiSignalController.setActivity(WifiManager.DATA_ACTIVITY_NONE);
+ }
mDemoWifiState.enabled = show;
mWifiSignalController.notifyListeners();
}
@@ -797,6 +817,26 @@
: Math.min(Integer.parseInt(level), icons[0].length - 1);
controller.getState().connected = controller.getState().level >= 0;
}
+ String activity = args.getString("activity");
+ if (activity != null) {
+ controller.getState().dataConnected = true;
+ switch (activity) {
+ case "inout":
+ controller.setActivity(TelephonyManager.DATA_ACTIVITY_INOUT);
+ break;
+ case "in":
+ controller.setActivity(TelephonyManager.DATA_ACTIVITY_IN);
+ break;
+ case "out":
+ controller.setActivity(TelephonyManager.DATA_ACTIVITY_OUT);
+ break;
+ default:
+ controller.setActivity(TelephonyManager.DATA_ACTIVITY_NONE);
+ break;
+ }
+ } else {
+ controller.setActivity(TelephonyManager.DATA_ACTIVITY_NONE);
+ }
controller.getState().enabled = show;
controller.notifyListeners();
}
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java
index 0a3197c..1b520b4 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java
@@ -163,7 +163,7 @@
intent.putExtra("sims", "1");
intent.putExtra("nosim", "false");
intent.putExtra("level", "4");
- intent.putExtra("datatypel", "");
+ intent.putExtra("datatype", "lte");
getContext().sendBroadcast(intent);
// Need to send this after so that the sim controller already exists.
diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk
index bf4d88c..51c7e55 100644
--- a/packages/SystemUI/tests/Android.mk
+++ b/packages/SystemUI/tests/Android.mk
@@ -18,6 +18,7 @@
LOCAL_MODULE_TAGS := tests
LOCAL_JACK_FLAGS := --multi-dex native
+LOCAL_DX_FLAGS := --multi-dex
LOCAL_PROTOC_OPTIMIZE_TYPE := nano
LOCAL_PROTOC_FLAGS := -I$(LOCAL_PATH)/..
diff --git a/packages/WallpaperCropper/Android.mk b/packages/WallpaperCropper/Android.mk
index d8fb7a4..09b41fd 100644
--- a/packages/WallpaperCropper/Android.mk
+++ b/packages/WallpaperCropper/Android.mk
@@ -6,7 +6,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_JAVA_LIBRARIES := telephony-common
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4 junit
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4
LOCAL_PACKAGE_NAME := WallpaperCropper
LOCAL_CERTIFICATE := platform
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/BitmapTexture.java b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/BitmapTexture.java
index 100b0b3b..f8b01cb 100644
--- a/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/BitmapTexture.java
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/BitmapTexture.java
@@ -18,7 +18,7 @@
import android.graphics.Bitmap;
-import junit.framework.Assert;
+import com.android.gallery3d.common.Utils;
// BitmapTexture is a texture whose content is specified by a fixed Bitmap.
//
@@ -34,7 +34,7 @@
public BitmapTexture(Bitmap bitmap, boolean hasBorder) {
super(hasBorder);
- Assert.assertTrue(bitmap != null && !bitmap.isRecycled());
+ Utils.assertTrue(bitmap != null && !bitmap.isRecycled());
mContentBitmap = bitmap;
}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/GLPaint.java b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/GLPaint.java
index 16b2206..b26e9ab 100644
--- a/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/GLPaint.java
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/GLPaint.java
@@ -16,7 +16,7 @@
package com.android.gallery3d.glrenderer;
-import junit.framework.Assert;
+import com.android.gallery3d.common.Utils;
public class GLPaint {
private float mLineWidth = 1f;
@@ -31,7 +31,7 @@
}
public void setLineWidth(float width) {
- Assert.assertTrue(width >= 0);
+ Utils.assertTrue(width >= 0);
mLineWidth = width;
}
diff --git a/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/UploadedTexture.java b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/UploadedTexture.java
index f41a979..417102a 100644
--- a/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/UploadedTexture.java
+++ b/packages/WallpaperCropper/src/com/android/gallery3d/glrenderer/UploadedTexture.java
@@ -20,7 +20,7 @@
import android.graphics.Bitmap.Config;
import android.opengl.GLUtils;
-import junit.framework.Assert;
+import com.android.gallery3d.common.Utils;
import java.util.HashMap;
@@ -144,7 +144,7 @@
}
private void freeBitmap() {
- Assert.assertTrue(mBitmap != null);
+ Utils.assertTrue(mBitmap != null);
onFreeBitmap(mBitmap);
mBitmap = null;
}
@@ -219,7 +219,7 @@
int texWidth = getTextureWidth();
int texHeight = getTextureHeight();
- Assert.assertTrue(bWidth <= texWidth && bHeight <= texHeight);
+ Utils.assertTrue(bWidth <= texWidth && bHeight <= texHeight);
// Upload the bitmap to a new texture.
mId = canvas.getGLId().generateTexture();
diff --git a/proto/src/wifi.proto b/proto/src/wifi.proto
new file mode 100644
index 0000000..9aa6490
--- /dev/null
+++ b/proto/src/wifi.proto
@@ -0,0 +1,462 @@
+/*
+ * 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.
+ */
+
+syntax = "proto2";
+
+package clearcut.connectivity;
+
+option java_package = "com.android.server.wifi";
+option java_outer_classname = "WifiMetricsProto";
+
+// The information about the Wifi events.
+message WifiLog {
+
+ // Session information that gets logged for every Wifi connection.
+ repeated ConnectionEvent connection_event = 1;
+
+ // Number of saved networks in the user profile.
+ optional int32 num_saved_networks = 2;
+
+ // Number of open networks in the saved networks.
+ optional int32 num_open_networks = 3;
+
+ // Number of personal networks.
+ optional int32 num_personal_networks = 4;
+
+ // Number of enterprise networks.
+ optional int32 num_enterprise_networks = 5;
+
+ // Does the user have location setting enabled.
+ optional bool is_location_enabled = 6;
+
+ // Does the user have scanning enabled.
+ optional bool is_scanning_always_enabled = 7;
+
+ // Number of times user toggled wifi using the settings menu.
+ optional int32 num_wifi_toggled_via_settings = 8;
+
+ // Number of times user toggled wifi using the airplane menu.
+ optional int32 num_wifi_toggled_via_airplane = 9;
+
+ // Number of networks added by the user.
+ optional int32 num_networks_added_by_user = 10;
+
+ // Number of networks added by applications.
+ optional int32 num_networks_added_by_apps = 11;
+
+ // Number scans that returned empty results.
+ optional int32 num_empty_scan_results = 12;
+
+ // Number scans that returned at least one result.
+ optional int32 num_non_empty_scan_results = 13;
+
+ // Number of scans that were one time.
+ optional int32 num_oneshot_scans = 14;
+
+ // Number of repeated background scans that were scheduled to the chip.
+ optional int32 num_background_scans = 15;
+
+ // Error codes that a scan can result in.
+ enum ScanReturnCode {
+
+ // Return Code is unknown.
+ SCAN_UNKNOWN = 0;
+
+ // Scan was successful.
+ SCAN_SUCCESS = 1;
+
+ // Scan was successfully started, but was interrupted.
+ SCAN_FAILURE_INTERRUPTED = 2;
+
+ // Scan failed to start because of invalid configuration
+ // (bad channel, etc).
+ SCAN_FAILURE_INVALID_CONFIGURATION = 3;
+
+ // Could not start a scan because wifi is disabled.
+ FAILURE_WIFI_DISABLED = 4;
+
+ }
+
+ // Mapping of error codes to the number of times that scans resulted
+ // in that error.
+ repeated ScanReturnEntry scan_return_entries = 16;
+
+ message ScanReturnEntry {
+
+ // Return code of the scan.
+ optional ScanReturnCode scan_return_code = 1;
+
+ // Number of entries that were found in the scan.
+ optional int32 scan_results_count = 2;
+ }
+
+ // State of the Wifi.
+ enum WifiState {
+
+ // State is unknown.
+ WIFI_UNKNOWN = 0;
+
+ // Wifi is disabled.
+ WIFI_DISABLED = 1;
+
+ // Wifi is enabled.
+ WIFI_DISCONNECTED = 2;
+
+ // Wifi is enabled and associated with an AP.
+ WIFI_ASSOCIATED = 3;
+ }
+
+ // Mapping of system state to the number of times that scans were requested in
+ // that state
+ repeated WifiSystemStateEntry wifi_system_state_entries = 17;
+
+ message WifiSystemStateEntry {
+
+ // Current WiFi state.
+ optional WifiState wifi_state = 1;
+
+ // Count of scans in state.
+ optional int32 wifi_state_count = 2;
+
+ // Is screen on.
+ optional bool is_screen_on = 3;
+ }
+
+ // Mapping of Error/Success codes to the number of background scans that resulted in it
+ repeated ScanReturnEntry background_scan_return_entries = 18;
+
+ // Mapping of system state to the number of times that Background scans were requested in that
+ // state
+ repeated WifiSystemStateEntry background_scan_request_state = 19;
+
+ // Total number of times the Watchdog of Last Resort triggered, resetting the wifi stack
+ optional int32 num_last_resort_watchdog_triggers = 20;
+
+ // Total number of networks over bad association threshold when watchdog triggered
+ optional int32 num_last_resort_watchdog_bad_association_networks_total = 21;
+
+ // Total number of networks over bad authentication threshold when watchdog triggered
+ optional int32 num_last_resort_watchdog_bad_authentication_networks_total = 22;
+
+ // Total number of networks over bad dhcp threshold when watchdog triggered
+ optional int32 num_last_resort_watchdog_bad_dhcp_networks_total = 23;
+
+ // Total number of networks over bad other threshold when watchdog triggered
+ optional int32 num_last_resort_watchdog_bad_other_networks_total = 24;
+
+ // Total count of networks seen when watchdog triggered
+ optional int32 num_last_resort_watchdog_available_networks_total = 25;
+
+ // Total count of triggers with atleast one bad association network
+ optional int32 num_last_resort_watchdog_triggers_with_bad_association = 26;
+
+ // Total count of triggers with atleast one bad authentication network
+ optional int32 num_last_resort_watchdog_triggers_with_bad_authentication = 27;
+
+ // Total count of triggers with atleast one bad dhcp network
+ optional int32 num_last_resort_watchdog_triggers_with_bad_dhcp = 28;
+
+ // Total count of triggers with atleast one bad other network
+ optional int32 num_last_resort_watchdog_triggers_with_bad_other = 29;
+
+ // Count of times connectivity watchdog confirmed pno is working
+ optional int32 num_connectivity_watchdog_pno_good = 30;
+
+ // Count of times connectivity watchdog found pno not working
+ optional int32 num_connectivity_watchdog_pno_bad = 31;
+
+ // Count of times connectivity watchdog confirmed background scan is working
+ optional int32 num_connectivity_watchdog_background_good = 32;
+
+ // Count of times connectivity watchdog found background scan not working
+ optional int32 num_connectivity_watchdog_background_bad = 33;
+
+ // The time duration represented by this wifi log, from start to end of capture
+ optional int32 record_duration_sec = 34;
+
+ // Counts the occurrences of each individual RSSI poll level
+ repeated RssiPollCount rssi_poll_rssi_count = 35;
+
+ // Total number of times WiFi connected immediately after a Last Resort Watchdog trigger,
+ // without new networks becoming available.
+ optional int32 num_last_resort_watchdog_successes = 36;
+
+ // Total number of saved hidden networks
+ optional int32 num_hidden_networks = 37;
+
+ // Total number of saved passpoint / hotspot 2.0 networks
+ optional int32 num_passpoint_networks = 38;
+
+ // Total number of scan results
+ optional int32 num_total_scan_results = 39;
+
+ // Total number of scan results for open networks
+ optional int32 num_open_network_scan_results = 40;
+
+ // Total number of scan results for personal networks
+ optional int32 num_personal_network_scan_results = 41;
+
+ // Total number of scan results for enterprise networks
+ optional int32 num_enterprise_network_scan_results = 42;
+
+ // Total number of scan results for hidden networks
+ optional int32 num_hidden_network_scan_results = 43;
+
+ // Total number of scan results for hotspot 2.0 r1 networks
+ optional int32 num_hotspot2_r1_network_scan_results = 44;
+
+ // Total number of scan results for hotspot 2.0 r2 networks
+ optional int32 num_hotspot2_r2_network_scan_results = 45;
+
+ // Total number of scans handled by framework (oneshot or otherwise)
+ optional int32 num_scans = 46;
+
+ // Counts the occurrences of each alert reason.
+ repeated AlertReasonCount alert_reason_count = 47;
+
+ // Counts the occurrences of each Wifi score
+ repeated WifiScoreCount wifi_score_count = 48;
+
+ // Histogram of Soft AP Durations
+ repeated SoftApDurationBucket soft_ap_duration = 49;
+
+ // Histogram of Soft AP ReturnCode
+ repeated SoftApReturnCodeCount soft_ap_return_code = 50;
+
+ // Histogram of the delta between scan result RSSI and RSSI polls
+ repeated RssiPollCount rssi_poll_delta_count = 51;
+}
+
+// Information that gets logged for every WiFi connection.
+message RouterFingerPrint {
+
+ enum RoamType {
+
+ // Type is unknown.
+ ROAM_TYPE_UNKNOWN = 0;
+
+ // No roaming - usually happens on a single band (2.4 GHz) router.
+ ROAM_TYPE_NONE = 1;
+
+ // Enterprise router.
+ ROAM_TYPE_ENTERPRISE = 2;
+
+ // DBDC => Dual Band Dual Concurrent essentially a router that
+ // supports both 2.4 GHz and 5 GHz bands.
+ ROAM_TYPE_DBDC = 3;
+ }
+
+ enum Auth {
+
+ // Auth is unknown.
+ AUTH_UNKNOWN = 0;
+
+ // No authentication.
+ AUTH_OPEN = 1;
+
+ // If the router uses a personal authentication.
+ AUTH_PERSONAL = 2;
+
+ // If the router is setup for enterprise authentication.
+ AUTH_ENTERPRISE = 3;
+ }
+
+ enum RouterTechnology {
+
+ // Router is unknown.
+ ROUTER_TECH_UNKNOWN = 0;
+
+ // Router Channel A.
+ ROUTER_TECH_A = 1;
+
+ // Router Channel B.
+ ROUTER_TECH_B = 2;
+
+ // Router Channel G.
+ ROUTER_TECH_G = 3;
+
+ // Router Channel N.
+ ROUTER_TECH_N = 4;
+
+ // Router Channel AC.
+ ROUTER_TECH_AC = 5;
+
+ // When the channel is not one of the above.
+ ROUTER_TECH_OTHER = 6;
+ }
+
+ optional RoamType roam_type = 1;
+
+ // Channel on which the connection takes place.
+ optional int32 channel_info = 2;
+
+ // DTIM setting of the router.
+ optional int32 dtim = 3;
+
+ // Authentication scheme of the router.
+ optional Auth authentication = 4;
+
+ // If the router is hidden.
+ optional bool hidden = 5;
+
+ // Channel information.
+ optional RouterTechnology router_technology = 6;
+
+ // whether ipv6 is supported.
+ optional bool supports_ipv6 = 7;
+
+ // If the router is a passpoint / hotspot 2.0 network
+ optional bool passpoint = 8;
+}
+
+message ConnectionEvent {
+
+ // Roam Type.
+ enum RoamType {
+
+ // Type is unknown.
+ ROAM_UNKNOWN = 0;
+
+ // No roaming.
+ ROAM_NONE = 1;
+
+ // DBDC roaming.
+ ROAM_DBDC = 2;
+
+ // Enterprise roaming.
+ ROAM_ENTERPRISE = 3;
+
+ // User selected roaming.
+ ROAM_USER_SELECTED = 4;
+
+ // Unrelated.
+ ROAM_UNRELATED = 5;
+ }
+
+ // Connectivity Level Failure.
+ enum ConnectivityLevelFailure {
+
+ // Failure is unknown.
+ HLF_UNKNOWN = 0;
+
+ // No failure.
+ HLF_NONE = 1;
+
+ // DHCP failure.
+ HLF_DHCP = 2;
+
+ // No internet connection.
+ HLF_NO_INTERNET = 3;
+
+ // No internet connection.
+ HLF_UNWANTED = 4;
+ }
+
+ // Start time of the connection.
+ optional int64 start_time_millis = 1;// [(datapol.semantic_type) = ST_TIMESTAMP];
+
+ // Duration to connect.
+ optional int32 duration_taken_to_connect_millis = 2;
+
+ // Router information.
+ optional RouterFingerPrint router_fingerprint = 3;
+
+ // RSSI at the start of the connection.
+ optional int32 signal_strength = 4;
+
+ // Roam Type.
+ optional RoamType roam_type = 5;
+
+ // Result of the connection.
+ optional int32 connection_result = 6;
+
+ // Reasons for level 2 failure (needs to be coordinated with wpa-supplicant).
+ optional int32 level_2_failure_code = 7;
+
+ // Failures that happen at the connectivity layer.
+ optional ConnectivityLevelFailure connectivity_level_failure_code = 8;
+
+ // Has bug report been taken.
+ optional bool automatic_bug_report_taken = 9;
+}
+
+// Number of occurrences of a specific RSSI poll rssi value
+message RssiPollCount {
+ // RSSI
+ optional int32 rssi = 1;
+
+ // Number of RSSI polls with 'rssi'
+ optional int32 count = 2;
+}
+
+// Number of occurrences of a specific alert reason value
+message AlertReasonCount {
+ // Alert reason
+ optional int32 reason = 1;
+
+ // Number of alerts with |reason|.
+ optional int32 count = 2;
+}
+
+// Counts the number of instances of a specific Wifi Score calculated by WifiScoreReport
+message WifiScoreCount {
+ // Wifi Score
+ optional int32 score = 1;
+
+ // Number of Wifi score reports with this score
+ optional int32 count = 2;
+}
+
+// Number of occurrences of Soft AP session durations
+message SoftApDurationBucket {
+ // Bucket covers duration : [duration_sec, duration_sec + bucket_size_sec)
+ // The (inclusive) lower bound of Soft AP session duration represented by this bucket
+ optional int32 duration_sec = 1;
+
+ // The size of this bucket
+ optional int32 bucket_size_sec = 2;
+
+ // Number of soft AP session durations that fit into this bucket
+ optional int32 count = 3;
+}
+
+// Number of occurrences of a soft AP session return code
+message SoftApReturnCodeCount {
+
+ enum SoftApStartResult {
+
+ // SoftApManager return code unknown
+ SOFT_AP_RETURN_CODE_UNKNOWN = 0;
+
+ // SoftAp started successfully
+ SOFT_AP_STARTED_SUCCESSFULLY = 1;
+
+ // Catch all for failures with no specific failure reason
+ SOFT_AP_FAILED_GENERAL_ERROR = 2;
+
+ // SoftAp failed to start due to NO_CHANNEL error
+ SOFT_AP_FAILED_NO_CHANNEL = 3;
+ }
+
+ // Historical, no longer used for writing as of 01/2017.
+ optional int32 return_code = 1 [deprecated = true];
+
+ // Occurences of this soft AP return code
+ optional int32 count = 2;
+
+ // Result of attempt to start SoftAp
+ optional SoftApStartResult start_result = 3;
+}
diff --git a/rs/jni/Android.mk b/rs/jni/Android.mk
index bf3681b..447a47d 100644
--- a/rs/jni/Android.mk
+++ b/rs/jni/Android.mk
@@ -19,22 +19,17 @@
LOCAL_STATIC_LIBRARIES :=
-rs_generated_include_dir := $(call intermediates-dir-for,SHARED_LIBRARIES,libRS,,)
-
LOCAL_C_INCLUDES += \
$(JNI_H_INCLUDE) \
frameworks/rs \
frameworks/base/core/jni \
- frameworks/base/libs/hwui \
- $(rs_generated_include_dir)
+ frameworks/base/libs/hwui
LOCAL_CFLAGS += -Wno-unused-parameter
LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
-LOCAL_ADDITIONAL_DEPENDENCIES := $(addprefix $(rs_generated_include_dir)/,rsgApiFuncDecl.h)
LOCAL_MODULE:= librs_jni
-LOCAL_ADDITIONAL_DEPENDENCIES += $(rs_generated_source)
LOCAL_MODULE_TAGS := optional
-LOCAL_REQUIRED_MODULES := libRS libRSDriver
+LOCAL_REQUIRED_MODULES := libRS
include $(BUILD_SHARED_LIBRARY)
diff --git a/rs/jni/android_renderscript_RenderScript.cpp b/rs/jni/android_renderscript_RenderScript.cpp
index af370ff..2300da3 100644
--- a/rs/jni/android_renderscript_RenderScript.cpp
+++ b/rs/jni/android_renderscript_RenderScript.cpp
@@ -35,8 +35,8 @@
#include "android_runtime/android_util_AssetManager.h"
#include "android/graphics/GraphicsJNI.h"
-#include <rs.h>
#include <rsEnv.h>
+#include <rsApiStubs.h>
#include <gui/Surface.h>
#include <gui/GLConsumer.h>
#include <android_runtime/android_graphics_SurfaceTexture.h>
@@ -1134,7 +1134,7 @@
// we will pack mType; mKind; mNormalized; mVectorSize; NumSubElements
assert(dataSize == 5);
- uintptr_t elementData[5];
+ uint32_t elementData[5];
rsaElementGetNativeData((RsContext)con, (RsElement)id, elementData, dataSize);
for(jint i = 0; i < dataSize; i ++) {
@@ -1157,7 +1157,7 @@
uintptr_t *ids = (uintptr_t*)malloc(dataSize * sizeof(uintptr_t));
const char **names = (const char **)malloc(dataSize * sizeof(const char *));
- uint32_t *arraySizes = (uint32_t *)malloc(dataSize * sizeof(uint32_t));
+ size_t *arraySizes = (size_t *)malloc(dataSize * sizeof(size_t));
rsaElementGetSubElements((RsContext)con, (RsElement)id, ids, names, arraySizes,
(uint32_t)dataSize);
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index 3b3ce07..66576b5 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -166,7 +166,7 @@
}
public String toString() {
- return android.text.format.DateFormat.format("MM-dd hh:mm:ss ", mTimestamp) +
+ return android.text.format.DateFormat.format("MM-dd HH:mm:ss ", mTimestamp) +
(mEnable ? " Enabled " : " Disabled ") + " by " + mPackageName;
}
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index dfca02e..954a94e 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -815,6 +815,8 @@
intentFilter.addAction(Intent.ACTION_USER_UNLOCKED);
mContext.registerReceiverAsUser(
mUserIntentReceiver, UserHandle.ALL, intentFilter, null, null);
+ mContext.registerReceiverAsUser(mUserPresentReceiver, UserHandle.SYSTEM,
+ new IntentFilter(Intent.ACTION_USER_PRESENT), null, null);
try {
mNetd.registerObserver(mTethering);
@@ -3661,7 +3663,12 @@
// Tear down existing lockdown if profile was removed
mLockdownEnabled = LockdownVpnTracker.isEnabled();
if (mLockdownEnabled) {
- final String profileName = new String(mKeyStore.get(Credentials.LOCKDOWN_VPN));
+ byte[] profileTag = mKeyStore.get(Credentials.LOCKDOWN_VPN);
+ if (profileTag == null) {
+ Slog.e(TAG, "Lockdown VPN configured but cannot be read from keystore");
+ return false;
+ }
+ String profileName = new String(profileTag);
final VpnProfile profile = VpnProfile.decode(
profileName, mKeyStore.get(Credentials.VPN + profileName));
if (profile == null) {
@@ -4000,6 +4007,16 @@
}
};
+ private BroadcastReceiver mUserPresentReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ // Try creating lockdown tracker, since user present usually means
+ // unlocked keystore.
+ updateLockdownVpn();
+ mContext.unregisterReceiver(this);
+ }
+ };
+
private final HashMap<Messenger, NetworkFactoryInfo> mNetworkFactoryInfos =
new HashMap<Messenger, NetworkFactoryInfo>();
private final HashMap<NetworkRequest, NetworkRequestInfo> mNetworkRequests =
@@ -4163,7 +4180,7 @@
}
ensureRequestableCapabilities(networkCapabilities);
- if (timeoutMs < 0 || timeoutMs > ConnectivityManager.MAX_NETWORK_REQUEST_TIMEOUT_MS) {
+ if (timeoutMs < 0) {
throw new IllegalArgumentException("Bad timeout specified");
}
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 62f4f19..82e6b42 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -16,7 +16,6 @@
package com.android.server;
-import android.Manifest;
import android.app.ActivityManager;
import android.app.AppOpsManager;
import android.content.BroadcastReceiver;
@@ -142,6 +141,10 @@
private ServiceState[] mServiceState;
+ private int[] mVoiceActivationState;
+
+ private int[] mDataActivationState;
+
private SignalStrength[] mSignalStrength;
private boolean[] mMessageWaiting;
@@ -301,6 +304,8 @@
mDataConnectionNetworkType = new int[numPhones];
mCallIncomingNumber = new String[numPhones];
mServiceState = new ServiceState[numPhones];
+ mVoiceActivationState = new int[numPhones];
+ mDataActivationState = new int[numPhones];
mSignalStrength = new SignalStrength[numPhones];
mMessageWaiting = new boolean[numPhones];
mDataConnectionPossible = new boolean[numPhones];
@@ -315,6 +320,8 @@
mCallState[i] = TelephonyManager.CALL_STATE_IDLE;
mDataActivity[i] = TelephonyManager.DATA_ACTIVITY_NONE;
mDataConnectionState[i] = TelephonyManager.DATA_UNKNOWN;
+ mVoiceActivationState[i] = TelephonyManager.SIM_ACTIVATION_STATE_UNKNOWN;
+ mDataActivationState[i] = TelephonyManager.SIM_ACTIVATION_STATE_UNKNOWN;
mCallIncomingNumber[i] = "";
mServiceState[i] = new ServiceState();
mSignalStrength[i] = new SignalStrength();
@@ -644,6 +651,20 @@
remove(r.binder);
}
}
+ if ((events & PhoneStateListener.LISTEN_VOICE_ACTIVATION_STATE) !=0) {
+ try {
+ r.callback.onVoiceActivationStateChanged(mVoiceActivationState[phoneId]);
+ } catch (RemoteException ex) {
+ remove(r.binder);
+ }
+ }
+ if ((events & PhoneStateListener.LISTEN_DATA_ACTIVATION_STATE) !=0) {
+ try {
+ r.callback.onDataActivationStateChanged(mDataActivationState[phoneId]);
+ } catch (RemoteException ex) {
+ remove(r.binder);
+ }
+ }
}
}
} else {
@@ -795,6 +816,67 @@
broadcastServiceStateChanged(state, phoneId, subId);
}
+ public void notifySimActivationStateChangedForPhoneId(int phoneId, int subId,
+ int activationType, int activationState) {
+ if (!checkNotifyPermission("notifySimActivationState()")){
+ return;
+ }
+ if (VDBG) {
+ log("notifySimActivationStateForPhoneId: subId=" + subId + " phoneId=" + phoneId
+ + "type=" + activationType + " state=" + activationState);
+ }
+ synchronized (mRecords) {
+ if (validatePhoneId(phoneId)) {
+ switch (activationType) {
+ case PhoneConstants.SIM_ACTIVATION_TYPE_VOICE:
+ mVoiceActivationState[phoneId] = activationState;
+ break;
+ case PhoneConstants.SIM_ACTIVATION_TYPE_DATA:
+ mDataActivationState[phoneId] = activationState;
+ break;
+ default:
+ return;
+ }
+ for (Record r : mRecords) {
+ if (VDBG) {
+ log("notifySimActivationStateForPhoneId: r=" + r + " subId=" + subId
+ + " phoneId=" + phoneId + "type=" + activationType
+ + " state=" + activationState);
+ }
+ try {
+ if ((activationType == PhoneConstants.SIM_ACTIVATION_TYPE_VOICE) &&
+ r.matchPhoneStateListenerEvent(
+ PhoneStateListener.LISTEN_VOICE_ACTIVATION_STATE) &&
+ idMatch(r.subId, subId, phoneId)) {
+ if (DBG) {
+ log("notifyVoiceActivationStateForPhoneId: callback.onVASC r=" + r
+ + " subId=" + subId + " phoneId=" + phoneId
+ + " state=" + activationState);
+ }
+ r.callback.onVoiceActivationStateChanged(activationState);
+ }
+ if ((activationType == PhoneConstants.SIM_ACTIVATION_TYPE_DATA) &&
+ r.matchPhoneStateListenerEvent(
+ PhoneStateListener.LISTEN_DATA_ACTIVATION_STATE) &&
+ idMatch(r.subId, subId, phoneId)) {
+ if (DBG) {
+ log("notifyDataActivationStateForPhoneId: callback.onDASC r=" + r
+ + " subId=" + subId + " phoneId=" + phoneId
+ + " state=" + activationState);
+ }
+ r.callback.onDataActivationStateChanged(activationState);
+ }
+ } catch (RemoteException ex) {
+ mRemoveList.add(r.binder);
+ }
+ }
+ } else {
+ log("notifySimActivationStateForPhoneId: INVALID phoneId=" + phoneId);
+ }
+ handleRemoveListLocked();
+ }
+ }
+
public void notifySignalStrengthForPhoneId(int phoneId, int subId,
SignalStrength signalStrength) {
if (!checkNotifyPermission("notifySignalStrength()")) {
@@ -1324,6 +1406,8 @@
pw.println(" mCallState=" + mCallState[i]);
pw.println(" mCallIncomingNumber=" + mCallIncomingNumber[i]);
pw.println(" mServiceState=" + mServiceState[i]);
+ pw.println(" mVoiceActivationState= " + mVoiceActivationState[i]);
+ pw.println(" mDataActivationState= " + mDataActivationState[i]);
pw.println(" mSignalStrength=" + mSignalStrength[i]);
pw.println(" mMessageWaiting=" + mMessageWaiting[i]);
pw.println(" mCallForwarding=" + mCallForwarding[i]);
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 00fe337..1feaa72 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -22278,4 +22278,29 @@
// before the profile user is unlocked.
return rInfo != null && rInfo.activityInfo != null;
}
+
+ /**
+ * Attach an agent to the specified process (proces name or PID)
+ */
+ public void attachAgent(String process, String path) {
+ try {
+ synchronized (this) {
+ ProcessRecord proc = findProcessLocked(process, UserHandle.USER_SYSTEM, "attachAgent");
+ if (proc == null || proc.thread == null) {
+ throw new IllegalArgumentException("Unknown process: " + process);
+ }
+
+ boolean isDebuggable = "1".equals(SystemProperties.get(SYSTEM_DEBUGGABLE, "0"));
+ if (!isDebuggable) {
+ if ((proc.info.flags & ApplicationInfo.FLAG_DEBUGGABLE) == 0) {
+ throw new SecurityException("Process not debuggable: " + proc);
+ }
+ }
+
+ proc.thread.attachAgent(path);
+ }
+ } catch (RemoteException e) {
+ throw new IllegalStateException("Process disappeared");
+ }
+ }
}
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index adf6d36..2d0ccbd 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -66,6 +66,8 @@
return runLenientBackgroundCheck(pw);
case "get-uid-state":
return getUidState(pw);
+ case "attach-agent":
+ return runAttachAgent(pw);
default:
return handleDefaultCommands(cmd);
}
@@ -183,6 +185,21 @@
return 0;
}
+ int runAttachAgent(PrintWriter pw) {
+ // TODO: revisit the permissions required for attaching agents
+ mInternal.enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
+ "attach-agent");
+ String process = getNextArgRequired();
+ String agent = getNextArgRequired();
+ String opt;
+ if ((opt = getNextArg()) != null) {
+ pw.println("Error: Unknown option: " + opt);
+ return -1;
+ }
+ mInternal.attachAgent(process, agent);
+ return 0;
+ }
+
@Override
public void onHelp() {
PrintWriter pw = getOutPrintWriter();
@@ -241,6 +258,8 @@
pw.println(" Optionally controls lenient background check mode, returns current mode.");
pw.println(" get-uid-state <UID>");
pw.println(" Gets the process state of an app given its <UID>.");
+ pw.println(" attach-agent <PROCESS> <FILE>");
+ pw.println(" Attach an agent to the specified <PROCESS>, which may be either a process name or a PID.");
}
}
}
diff --git a/services/core/java/com/android/server/connectivity/MetricsLoggerService.java b/services/core/java/com/android/server/connectivity/MetricsLoggerService.java
deleted file mode 100644
index 1c9feb2..0000000
--- a/services/core/java/com/android/server/connectivity/MetricsLoggerService.java
+++ /dev/null
@@ -1,375 +0,0 @@
-/*
- * 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 com.android.server.connectivity;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.server.SystemService;
-
-import android.app.PendingIntent;
-import android.content.Context;
-import android.content.pm.PackageManager;
-import android.net.ConnectivityMetricsEvent;
-import android.net.ConnectivityMetricsLogger;
-import android.net.IConnectivityMetricsLogger;
-import android.os.Binder;
-import android.os.Parcel;
-import android.text.format.DateUtils;
-import android.util.Log;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.ArrayDeque;
-import java.util.ArrayList;
-
-/** {@hide} */
-public class MetricsLoggerService extends SystemService {
- private static String TAG = "ConnectivityMetricsLoggerService";
- private static final boolean DBG = true;
- private static final boolean VDBG = false;
-
- public MetricsLoggerService(Context context) {
- super(context);
- }
-
- @Override
- public void onStart() {
- resetThrottlingCounters(System.currentTimeMillis());
- }
-
- @Override
- public void onBootPhase(int phase) {
- if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
- if (DBG) Log.d(TAG, "onBootPhase: PHASE_SYSTEM_SERVICES_READY");
- publishBinderService(ConnectivityMetricsLogger.CONNECTIVITY_METRICS_LOGGER_SERVICE,
- mBinder);
- }
- }
-
- // TODO: read these constants from system property
- private final int EVENTS_NOTIFICATION_THRESHOLD = 300;
- private final int MAX_NUMBER_OF_EVENTS = 1000;
- private final int THROTTLING_MAX_NUMBER_OF_MESSAGES_PER_COMPONENT = 1000;
- private final long THROTTLING_TIME_INTERVAL_MILLIS = DateUtils.HOUR_IN_MILLIS;
-
- private int mEventCounter = 0;
-
- /**
- * Reference of the last event in the list of cached events.
- *
- * When client of this service retrieves events by calling getEvents, it is passing
- * ConnectivityMetricsEvent.Reference object. After getEvents returns, that object will
- * contain this reference. The client can save it and use next time it calls getEvents.
- * This way only new events will be returned.
- */
- private long mLastEventReference = 0;
-
- private final int mThrottlingCounters[] =
- new int[ConnectivityMetricsLogger.NUMBER_OF_COMPONENTS];
-
- private long mThrottlingIntervalBoundaryMillis;
-
- private final ArrayDeque<ConnectivityMetricsEvent> mEvents = new ArrayDeque<>();
-
- private void enforceConnectivityInternalPermission() {
- getContext().enforceCallingOrSelfPermission(
- android.Manifest.permission.CONNECTIVITY_INTERNAL,
- "MetricsLoggerService");
- }
-
- private void enforceDumpPermission() {
- getContext().enforceCallingOrSelfPermission(
- android.Manifest.permission.DUMP,
- "MetricsLoggerService");
- }
-
- private void resetThrottlingCounters(long currentTimeMillis) {
- synchronized (mThrottlingCounters) {
- for (int i = 0; i < mThrottlingCounters.length; i++) {
- mThrottlingCounters[i] = 0;
- }
- mThrottlingIntervalBoundaryMillis =
- currentTimeMillis + THROTTLING_TIME_INTERVAL_MILLIS;
- }
- }
-
- private void addEvent(ConnectivityMetricsEvent e) {
- if (VDBG) {
- Log.v(TAG, "writeEvent(" + e.toString() + ")");
- }
-
- while (mEvents.size() >= MAX_NUMBER_OF_EVENTS) {
- mEvents.removeFirst();
- }
-
- mEvents.addLast(e);
- }
-
- @VisibleForTesting
- final MetricsLoggerImpl mBinder = new MetricsLoggerImpl();
-
- /**
- * Implementation of the IConnectivityMetricsLogger interface.
- */
- final class MetricsLoggerImpl extends IConnectivityMetricsLogger.Stub {
-
- private final ArrayList<PendingIntent> mPendingIntents = new ArrayList<>();
-
- @Override
- protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
- != PackageManager.PERMISSION_GRANTED) {
- pw.println("Permission Denial: can't dump ConnectivityMetricsLoggerService " +
- "from from pid=" + Binder.getCallingPid() + ", uid=" +
- Binder.getCallingUid());
- return;
- }
-
- boolean dumpSerializedSize = false;
- boolean dumpEvents = false;
- boolean dumpDebugInfo = false;
- for (String arg : args) {
- switch (arg) {
- case "--debug":
- dumpDebugInfo = true;
- break;
-
- case "--events":
- dumpEvents = true;
- break;
-
- case "--size":
- dumpSerializedSize = true;
- break;
-
- case "--all":
- dumpDebugInfo = true;
- dumpEvents = true;
- dumpSerializedSize = true;
- break;
- }
- }
-
- synchronized (mEvents) {
- pw.println("Number of events: " + mEvents.size());
- pw.println("Counter: " + mEventCounter);
- if (mEvents.size() > 0) {
- pw.println("Time span: " +
- DateUtils.formatElapsedTime(
- (System.currentTimeMillis() - mEvents.peekFirst().timestamp)
- / 1000));
- }
-
- if (dumpSerializedSize) {
- Parcel p = Parcel.obtain();
- for (ConnectivityMetricsEvent e : mEvents) {
- p.writeParcelable(e, 0);
- }
- pw.println("Serialized data size: " + p.dataSize());
- p.recycle();
- }
-
- if (dumpEvents) {
- pw.println();
- pw.println("Events:");
- for (ConnectivityMetricsEvent e : mEvents) {
- pw.println(e.toString());
- }
- }
- }
-
- if (dumpDebugInfo) {
- synchronized (mThrottlingCounters) {
- pw.println();
- for (int i = 0; i < ConnectivityMetricsLogger.NUMBER_OF_COMPONENTS; i++) {
- if (mThrottlingCounters[i] > 0) {
- pw.println("Throttling Counter #" + i + ": " + mThrottlingCounters[i]);
- }
- }
- pw.println("Throttling Time Remaining: " +
- DateUtils.formatElapsedTime(
- (mThrottlingIntervalBoundaryMillis - System.currentTimeMillis())
- / 1000));
- }
- }
-
- synchronized (mPendingIntents) {
- if (!mPendingIntents.isEmpty()) {
- pw.println();
- pw.println("Pending intents:");
- for (PendingIntent pi : mPendingIntents) {
- pw.println(pi.toString());
- }
- }
- }
- }
-
- public long logEvent(ConnectivityMetricsEvent event) {
- ConnectivityMetricsEvent[] events = new ConnectivityMetricsEvent[]{event};
- return logEvents(events);
- }
-
- /**
- * @param events
- *
- * Note: All events must belong to the same component.
- *
- * @return 0 on success
- * <0 if error happened
- * >0 timestamp after which new events will be accepted
- */
- public long logEvents(ConnectivityMetricsEvent[] events) {
- enforceConnectivityInternalPermission();
-
- if (events == null || events.length == 0) {
- Log.wtf(TAG, "No events passed to logEvents()");
- return -1;
- }
-
- int componentTag = events[0].componentTag;
- if (componentTag < 0 ||
- componentTag >= ConnectivityMetricsLogger.NUMBER_OF_COMPONENTS) {
- Log.wtf(TAG, "Unexpected tag: " + componentTag);
- return -1;
- }
-
- synchronized (mThrottlingCounters) {
- long currentTimeMillis = System.currentTimeMillis();
- if (currentTimeMillis > mThrottlingIntervalBoundaryMillis) {
- resetThrottlingCounters(currentTimeMillis);
- }
-
- mThrottlingCounters[componentTag] += events.length;
-
- if (mThrottlingCounters[componentTag] >
- THROTTLING_MAX_NUMBER_OF_MESSAGES_PER_COMPONENT) {
- Log.w(TAG, "Too many events from #" + componentTag +
- ". Block until " + mThrottlingIntervalBoundaryMillis);
-
- return mThrottlingIntervalBoundaryMillis;
- }
- }
-
- boolean sendPendingIntents = false;
-
- synchronized (mEvents) {
- for (ConnectivityMetricsEvent e : events) {
- if (e.componentTag != componentTag) {
- Log.wtf(TAG, "Unexpected tag: " + e.componentTag);
- return -1;
- }
-
- addEvent(e);
- }
-
- mLastEventReference += events.length;
-
- mEventCounter += events.length;
- if (mEventCounter >= EVENTS_NOTIFICATION_THRESHOLD) {
- mEventCounter = 0;
- sendPendingIntents = true;
- }
- }
-
- if (sendPendingIntents) {
- synchronized (mPendingIntents) {
- for (PendingIntent pi : mPendingIntents) {
- if (VDBG) Log.v(TAG, "Send pending intent");
- try {
- pi.send(getContext(), 0, null, null, null);
- } catch (PendingIntent.CanceledException e) {
- Log.e(TAG, "Pending intent canceled: " + pi);
- mPendingIntents.remove(pi);
- }
- }
- }
- }
-
- return 0;
- }
-
- /**
- * Retrieve events
- *
- * @param reference of the last event previously returned. The function will return
- * events following it.
- * If 0 then all events will be returned.
- * After the function call it will contain reference of the
- * last returned event.
- * @return events
- */
- public ConnectivityMetricsEvent[] getEvents(ConnectivityMetricsEvent.Reference reference) {
- enforceDumpPermission();
- long ref = reference.getValue();
- if (VDBG) Log.v(TAG, "getEvents(" + ref + ")");
-
- ConnectivityMetricsEvent[] result;
- synchronized (mEvents) {
- if (ref > mLastEventReference) {
- Log.e(TAG, "Invalid reference");
- reference.setValue(mLastEventReference);
- return null;
- }
- if (ref < mLastEventReference - mEvents.size()) {
- ref = mLastEventReference - mEvents.size();
- }
-
- int numEventsToSkip =
- mEvents.size() // Total number of events
- - (int)(mLastEventReference - ref); // Number of events to return
-
- result = new ConnectivityMetricsEvent[mEvents.size() - numEventsToSkip];
- int i = 0;
- for (ConnectivityMetricsEvent e : mEvents) {
- if (numEventsToSkip > 0) {
- numEventsToSkip--;
- } else {
- result[i++] = e;
- }
- }
-
- reference.setValue(mLastEventReference);
- }
-
- return result;
- }
-
- public boolean register(PendingIntent newEventsIntent) {
- enforceDumpPermission();
- if (VDBG) Log.v(TAG, "register(" + newEventsIntent + ")");
-
- synchronized (mPendingIntents) {
- if (mPendingIntents.remove(newEventsIntent)) {
- Log.w(TAG, "Replacing registered pending intent");
- }
- mPendingIntents.add(newEventsIntent);
- }
-
- return true;
- }
-
- public void unregister(PendingIntent newEventsIntent) {
- enforceDumpPermission();
- if (VDBG) Log.v(TAG, "unregister(" + newEventsIntent + ")");
-
- synchronized (mPendingIntents) {
- if (!mPendingIntents.remove(newEventsIntent)) {
- Log.e(TAG, "Pending intent is not registered");
- }
- }
- }
- };
-}
diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
index 9ffe2b7..c40780e 100644
--- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
@@ -809,19 +809,26 @@
// portal. If it is considered a captive portal, a different sign-in URL
// is needed (i.e. can't browse a 204). This could be the result of an HTTP
// proxy server.
-
- // Consider 200 response with "Content-length=0" to not be a captive portal.
- // There's no point in considering this a captive portal as the user cannot
- // sign-in to an empty page. Probably the result of a broken transparent proxy.
- // See http://b/9972012.
- if (httpResponseCode == 200 && urlConnection.getContentLength() == 0) {
- validationLog("Empty 200 response interpreted as 204 response.");
- httpResponseCode = 204;
- }
-
- if (httpResponseCode == 200 && probeType == ValidationProbeEvent.PROBE_PAC) {
- validationLog("PAC fetch 200 response interpreted as 204 response.");
- httpResponseCode = 204;
+ if (httpResponseCode == 200) {
+ if (probeType == ValidationProbeEvent.PROBE_PAC) {
+ validationLog("PAC fetch 200 response interpreted as 204 response.");
+ httpResponseCode = 204;
+ } else if (urlConnection.getContentLengthLong() == 0) {
+ // Consider 200 response with "Content-length=0" to not be a captive portal.
+ // There's no point in considering this a captive portal as the user cannot
+ // sign-in to an empty page. Probably the result of a broken transparent proxy.
+ // See http://b/9972012.
+ validationLog(
+ "200 response with Content-length=0 interpreted as 204 response.");
+ httpResponseCode = 204;
+ } else if (urlConnection.getContentLengthLong() == -1) {
+ // When no Content-length (default value == -1), attempt to read a byte from the
+ // response. Do not use available() as it is unreliable. See http://b/33498325.
+ if (urlConnection.getInputStream().read() == -1) {
+ validationLog("Empty 200 response interpreted as 204 response.");
+ httpResponseCode = 204;
+ }
+ }
}
} catch (IOException e) {
validationLog("Probably not a portal: exception " + e);
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index b0e4509..1da5e69 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -950,6 +950,8 @@
// Events from NetworkCallbacks that we process on the master state
// machine thread on behalf of the UpstreamNetworkMonitor.
static final int EVENT_UPSTREAM_CALLBACK = BASE_MASTER + 5;
+ // we treated the error and want now to clear it
+ static final int CMD_CLEAR_ERROR = BASE_MASTER + 6;
private State mInitialState;
private State mTetherModeAliveState;
@@ -1008,10 +1010,9 @@
return false;
}
- protected boolean requestUpstreamMobileConnection() {
+ protected void requestUpstreamMobileConnection() {
mUpstreamNetworkMonitor.updateMobileRequiresDun(mConfig.isDunRequired);
mUpstreamNetworkMonitor.registerMobileNetworkRequest();
- return true;
}
protected void unrequestUpstreamMobileConnection() {
@@ -1058,9 +1059,13 @@
}
protected void chooseUpstreamType(boolean tryCell) {
+ final int upstreamType = findPreferredUpstreamType(tryCell);
+ setUpstreamByType(upstreamType);
+ }
+
+ protected int findPreferredUpstreamType(boolean tryCell) {
final ConnectivityManager cm = getConnectivityManager();
int upType = ConnectivityManager.TYPE_NONE;
- String iface = null;
updateConfiguration(); // TODO - remove?
@@ -1100,7 +1105,8 @@
requestUpstreamMobileConnection();
break;
case ConnectivityManager.TYPE_NONE:
- if (tryCell && requestUpstreamMobileConnection()) {
+ if (tryCell) {
+ requestUpstreamMobileConnection();
// We think mobile should be coming up; don't set a retry.
} else {
sendMessageDelayed(CMD_RETRY_UPSTREAM, UPSTREAM_SETTLE_TIME_MS);
@@ -1117,7 +1123,13 @@
break;
}
+ return upType;
+ }
+
+ protected void setUpstreamByType(int upType) {
+ final ConnectivityManager cm = getConnectivityManager();
Network network = null;
+ String iface = null;
if (upType != ConnectivityManager.TYPE_NONE) {
LinkProperties linkProperties = cm.getLinkProperties(upType);
if (linkProperties != null) {
@@ -1359,9 +1371,9 @@
simChange.startListening();
mUpstreamNetworkMonitor.start();
- mTryCell = true; // better try something first pass or crazy tests cases will fail
- chooseUpstreamType(mTryCell);
- mTryCell = !mTryCell;
+ // Better try something first pass or crazy tests cases will fail.
+ chooseUpstreamType(true);
+ mTryCell = false;
}
@Override
@@ -1412,10 +1424,9 @@
break;
}
case CMD_UPSTREAM_CHANGED:
- // need to try DUN immediately if Wifi goes down
- mTryCell = true;
- chooseUpstreamType(mTryCell);
- mTryCell = !mTryCell;
+ // Need to try DUN immediately if Wi-Fi goes down.
+ chooseUpstreamType(true);
+ mTryCell = false;
break;
case CMD_RETRY_UPSTREAM:
chooseUpstreamType(mTryCell);
@@ -1487,6 +1498,10 @@
TetherInterfaceStateMachine who = (TetherInterfaceStateMachine)message.obj;
who.sendMessage(mErrorNotification);
break;
+ case CMD_CLEAR_ERROR:
+ mErrorNotification = ConnectivityManager.TETHER_ERROR_NO_ERROR;
+ transitionTo(mInitialState);
+ break;
default:
retValue = false;
}
@@ -1631,6 +1646,12 @@
// Not really very much we can do here.
}
+ // If TetherMasterSM is in ErrorState, TetherMasterSM stays there.
+ // Thus we give a chance for TetherMasterSM to recover to InitialState
+ // by sending CMD_CLEAR_ERROR
+ if (error == ConnectivityManager.TETHER_ERROR_MASTER_ERROR) {
+ mTetherMasterSM.sendMessage(TetherMasterSM.CMD_CLEAR_ERROR, who);
+ }
switch (state) {
case IControlsTethering.STATE_UNAVAILABLE:
case IControlsTethering.STATE_AVAILABLE:
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 37221a9..710ab33 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java
@@ -167,7 +167,8 @@
private void maybeLogMessage(State state, int what) {
if (DBG) {
Log.d(TAG, state.getName() + " got " +
- sMagicDecoderRing.get(what, Integer.toString(what)));
+ sMagicDecoderRing.get(what, Integer.toString(what)) + ", Iface = " +
+ mIfaceName);
}
}
@@ -250,31 +251,33 @@
}
private void cleanupUpstream() {
- if (mMyUpstreamIfaceName != null) {
- // note that we don't care about errors here.
- // sometimes interfaces are gone before we get
- // to remove their rules, which generates errors.
- // just do the best we can.
- try {
- // about to tear down NAT; gather remaining statistics
- mStatsService.forceUpdate();
- } catch (Exception e) {
- if (VDBG) Log.e(TAG, "Exception in forceUpdate: " + e.toString());
- }
- try {
- mNMService.stopInterfaceForwarding(mIfaceName, mMyUpstreamIfaceName);
- } catch (Exception e) {
- if (VDBG) Log.e(
- TAG, "Exception in removeInterfaceForward: " + e.toString());
- }
- try {
- mNMService.disableNat(mIfaceName, mMyUpstreamIfaceName);
- } catch (Exception e) {
- if (VDBG) Log.e(TAG, "Exception in disableNat: " + e.toString());
- }
- mMyUpstreamIfaceName = null;
+ if (mMyUpstreamIfaceName == null) return;
+
+ cleanupUpstreamInterface(mMyUpstreamIfaceName);
+ mMyUpstreamIfaceName = null;
+ }
+
+ private void cleanupUpstreamInterface(String upstreamIface) {
+ // Note that we don't care about errors here.
+ // Sometimes interfaces are gone before we get
+ // to remove their rules, which generates errors.
+ // Just do the best we can.
+ try {
+ // About to tear down NAT; gather remaining statistics.
+ mStatsService.forceUpdate();
+ } catch (Exception e) {
+ if (VDBG) Log.e(TAG, "Exception in forceUpdate: " + e.toString());
}
- return;
+ try {
+ mNMService.stopInterfaceForwarding(mIfaceName, upstreamIface);
+ } catch (Exception e) {
+ if (VDBG) Log.e(TAG, "Exception in removeInterfaceForward: " + e.toString());
+ }
+ try {
+ mNMService.disableNat(mIfaceName, upstreamIface);
+ } catch (Exception e) {
+ if (VDBG) Log.e(TAG, "Exception in disableNat: " + e.toString());
+ }
}
@Override
@@ -306,6 +309,7 @@
newUpstreamIfaceName);
} catch (Exception e) {
Log.e(TAG, "Exception enabling Nat: " + e.toString());
+ cleanupUpstreamInterface(newUpstreamIfaceName);
mLastError = ConnectivityManager.TETHER_ERROR_ENABLE_NAT_ERROR;
transitionTo(mInitialState);
return true;
diff --git a/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java b/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
index 017c5fb..6106093 100644
--- a/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
@@ -20,6 +20,8 @@
import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI;
import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback;
import android.net.LinkProperties;
@@ -72,6 +74,7 @@
private final Context mContext;
private final StateMachine mTarget;
+ private final Handler mHandler;
private final int mWhat;
private final HashMap<Network, NetworkState> mNetworkMap = new HashMap<>();
private ConnectivityManager mCM;
@@ -84,6 +87,7 @@
public UpstreamNetworkMonitor(Context ctx, StateMachine tgt, int what) {
mContext = ctx;
mTarget = tgt;
+ mHandler = mTarget.getHandler();
mWhat = what;
}
@@ -99,10 +103,10 @@
final NetworkRequest listenAllRequest = new NetworkRequest.Builder()
.clearCapabilities().build();
mListenAllCallback = new UpstreamNetworkCallback(CALLBACK_LISTEN_ALL);
- cm().registerNetworkCallback(listenAllRequest, mListenAllCallback);
+ cm().registerNetworkCallback(listenAllRequest, mListenAllCallback, mHandler);
mDefaultNetworkCallback = new UpstreamNetworkCallback(CALLBACK_TRACK_DEFAULT);
- cm().registerDefaultNetworkCallback(mDefaultNetworkCallback);
+ cm().registerDefaultNetworkCallback(mDefaultNetworkCallback, mHandler);
}
public void stop() {
@@ -154,7 +158,7 @@
// Additionally, we log a message to aid in any subsequent debugging.
Log.d(TAG, "requesting mobile upstream network: " + mobileUpstreamRequest);
- cm().requestNetwork(mobileUpstreamRequest, mMobileNetworkCallback, 0, legacyType);
+ cm().requestNetwork(mobileUpstreamRequest, mMobileNetworkCallback, 0, legacyType, mHandler);
}
public void releaseMobileNetworkRequest() {
@@ -183,11 +187,35 @@
case CALLBACK_LISTEN_ALL:
break;
case CALLBACK_TRACK_DEFAULT:
+ if (mDefaultNetworkCallback == null) {
+ // The callback was unregistered in the interval between
+ // ConnectivityService enqueueing onAvailable() and our
+ // handling of it here on the mHandler thread.
+ //
+ // Clean-up of this network entry is deferred to the
+ // handling of onLost() by other callbacks.
+ //
+ // These request*() calls can be deleted post oag/339444.
+ return;
+ }
+
cm().requestNetworkCapabilities(mDefaultNetworkCallback);
cm().requestLinkProperties(mDefaultNetworkCallback);
mCurrentDefault = network;
break;
case CALLBACK_MOBILE_REQUEST:
+ if (mMobileNetworkCallback == null) {
+ // The callback was unregistered in the interval between
+ // ConnectivityService enqueueing onAvailable() and our
+ // handling of it here on the mHandler thread.
+ //
+ // Clean-up of this network entry is deferred to the
+ // handling of onLost() by other callbacks.
+ //
+ // These request*() calls can be deleted post oag/339444.
+ return;
+ }
+
cm().requestNetworkCapabilities(mMobileNetworkCallback);
cm().requestLinkProperties(mMobileNetworkCallback);
break;
@@ -292,8 +320,9 @@
}
/**
- * A NetworkCallback class that relays information of interest to the
- * tethering master state machine thread for subsequent processing.
+ * A NetworkCallback class that handles information of interest directly
+ * in the thread on which it is invoked. To avoid locking, this MUST be
+ * run on the same thread as the target state machine's handler.
*/
private class UpstreamNetworkCallback extends NetworkCallback {
private final int mCallbackType;
@@ -304,22 +333,35 @@
@Override
public void onAvailable(Network network) {
- mTarget.getHandler().post(() -> handleAvailable(mCallbackType, network));
+ checkExpectedThread();
+ handleAvailable(mCallbackType, network);
}
@Override
public void onCapabilitiesChanged(Network network, NetworkCapabilities newNc) {
- mTarget.getHandler().post(() -> handleNetCap(network, newNc));
+ checkExpectedThread();
+ handleNetCap(network, newNc);
}
@Override
public void onLinkPropertiesChanged(Network network, LinkProperties newLp) {
- mTarget.getHandler().post(() -> handleLinkProp(network, newLp));
+ checkExpectedThread();
+ handleLinkProp(network, newLp);
}
+ // TODO: Handle onNetworkSuspended();
+ // TODO: Handle onNetworkResumed();
+
@Override
public void onLost(Network network) {
- mTarget.getHandler().post(() -> handleLost(mCallbackType, network));
+ checkExpectedThread();
+ handleLost(mCallbackType, network);
+ }
+
+ private void checkExpectedThread() {
+ if (Looper.myLooper() != mHandler.getLooper()) {
+ Log.wtf(TAG, "Handling callback in unexpected thread.");
+ }
}
}
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index ae98077..e2e834d 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -477,12 +477,6 @@
public void onLost(Network network) {
releaseSuplConnection(GPS_RELEASE_AGPS_DATA_CONN);
}
-
- @Override
- public void onUnavailable() {
- // timeout, it was not possible to establish the required connection
- releaseSuplConnection(GPS_AGPS_DATA_CONN_FAILED);
- }
};
private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@@ -902,8 +896,7 @@
NetworkRequest request = requestBuilder.build();
mConnMgr.requestNetwork(
request,
- mSuplConnectivityCallback,
- ConnectivityManager.MAX_NETWORK_REQUEST_TIMEOUT_MS);
+ mSuplConnectivityCallback);
}
private void handleReleaseSuplConnection(int agpsDataConnStatus) {
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index d31c7b5..22c5e85 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2078,12 +2078,14 @@
Slog.w(TAG, "getBackupPayload: cannot backup policy for user " + user);
return null;
}
- final ByteArrayOutputStream baos = new ByteArrayOutputStream();
- try {
- writePolicyXml(baos, true /*forBackup*/);
- return baos.toByteArray();
- } catch (IOException e) {
- Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
+ synchronized(mPolicyFile) {
+ final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ try {
+ writePolicyXml(baos, true /*forBackup*/);
+ return baos.toByteArray();
+ } catch (IOException e) {
+ Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
+ }
}
return null;
}
@@ -2101,12 +2103,14 @@
Slog.w(TAG, "applyRestore: cannot restore policy for user " + user);
return;
}
- final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
- try {
- readPolicyXml(bais, true /*forRestore*/);
- savePolicyFile();
- } catch (NumberFormatException | XmlPullParserException | IOException e) {
- Slog.w(TAG, "applyRestore: error reading payload", e);
+ synchronized(mPolicyFile) {
+ final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
+ try {
+ readPolicyXml(bais, true /*forRestore*/);
+ savePolicyFile();
+ } catch (NumberFormatException | XmlPullParserException | IOException e) {
+ Slog.w(TAG, "applyRestore: error reading payload", e);
+ }
}
}
diff --git a/services/core/java/com/android/server/pm/SELinuxMMAC.java b/services/core/java/com/android/server/pm/SELinuxMMAC.java
index 0fe1539..522c2e8 100644
--- a/services/core/java/com/android/server/pm/SELinuxMMAC.java
+++ b/services/core/java/com/android/server/pm/SELinuxMMAC.java
@@ -69,6 +69,9 @@
// Append autoplay to existing seinfo label
private static final String AUTOPLAY_APP_STR = ":autoplayapp";
+ // Append targetSdkVersion=n to existing seinfo label where n is the app's targetSdkVersion
+ private static final String TARGETSDKVERSION_STR = ":targetSdkVersion=";
+
/**
* Load the mac_permissions.xml file containing all seinfo assignments used to
* label apps. The loaded mac_permissions.xml file is determined by the
@@ -290,6 +293,8 @@
if (pkg.applicationInfo.isPrivilegedApp())
pkg.applicationInfo.seinfo += PRIVILEGED_APP_STR;
+ pkg.applicationInfo.seinfo += TARGETSDKVERSION_STR + pkg.applicationInfo.targetSdkVersion;
+
if (DEBUG_POLICY_INSTALL) {
Slog.i(TAG, "package (" + pkg.packageName + ") labeled with " +
"seinfo=" + pkg.applicationInfo.seinfo);
diff --git a/services/core/java/com/android/server/updates/TzDataInstallReceiver.java b/services/core/java/com/android/server/updates/TzDataInstallReceiver.java
index b704eb1..3c73c88 100644
--- a/services/core/java/com/android/server/updates/TzDataInstallReceiver.java
+++ b/services/core/java/com/android/server/updates/TzDataInstallReceiver.java
@@ -20,7 +20,7 @@
import java.io.File;
import java.io.IOException;
-import libcore.tzdata.update2.TimeZoneBundleInstaller;
+import libcore.tzdata.update2.TimeZoneDistroInstaller;
/**
* An install receiver responsible for installing timezone data updates.
@@ -34,14 +34,14 @@
private static final String UPDATE_DIR_NAME = TZ_DATA_DIR.getPath() + "/updates/";
private static final String UPDATE_METADATA_DIR_NAME = "metadata/";
private static final String UPDATE_VERSION_FILE_NAME = "version";
- private static final String UPDATE_CONTENT_FILE_NAME = "tzdata_bundle.zip";
+ private static final String UPDATE_CONTENT_FILE_NAME = "tzdata_distro.zip";
- private final TimeZoneBundleInstaller installer;
+ private final TimeZoneDistroInstaller installer;
public TzDataInstallReceiver() {
super(UPDATE_DIR_NAME, UPDATE_CONTENT_FILE_NAME, UPDATE_METADATA_DIR_NAME,
UPDATE_VERSION_FILE_NAME);
- installer = new TimeZoneBundleInstaller(TAG, SYSTEM_TZ_DATA_FILE, TZ_DATA_DIR);
+ installer = new TimeZoneDistroInstaller(TAG, SYSTEM_TZ_DATA_FILE, TZ_DATA_DIR);
}
@Override
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 27d95a4..de4a55b 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -61,7 +61,6 @@
import com.android.server.camera.CameraService;
import com.android.server.clipboard.ClipboardService;
import com.android.server.connectivity.IpConnectivityMetrics;
-import com.android.server.connectivity.MetricsLoggerService;
import com.android.server.devicepolicy.DevicePolicyManagerService;
import com.android.server.display.DisplayManagerService;
import com.android.server.display.NightDisplayService;
@@ -662,10 +661,6 @@
mSystemServiceManager.startService(BluetoothService.class);
}
- traceBeginAndSlog("ConnectivityMetricsLoggerService");
- mSystemServiceManager.startService(MetricsLoggerService.class);
- Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
-
traceBeginAndSlog("IpConnectivityMetrics");
mSystemServiceManager.startService(IpConnectivityMetrics.class);
Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 00c36f9..99eb3d2 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -32,6 +32,7 @@
import android.hardware.usb.UsbManager;
import android.hardware.usb.UsbPort;
import android.hardware.usb.UsbPortStatus;
+import android.os.BatteryManager;
import android.os.FileUtils;
import android.os.Handler;
import android.os.Looper;
@@ -111,6 +112,7 @@
private static final int MSG_USER_SWITCHED = 5;
private static final int MSG_UPDATE_USER_RESTRICTIONS = 6;
private static final int MSG_UPDATE_HOST_STATE = 7;
+ private static final int MSG_UPDATE_CHARGING_STATE = 9;
private static final int AUDIO_MODE_SOURCE = 1;
@@ -192,6 +194,15 @@
}
};
+ private final BroadcastReceiver mChargingReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ int chargePlug = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
+ boolean usbCharging = chargePlug == BatteryManager.BATTERY_PLUGGED_USB;
+ mHandler.sendMessage(MSG_UPDATE_CHARGING_STATE, usbCharging);
+ }
+ };
+
public UsbDeviceManager(Context context, UsbAlsaManager alsaManager) {
mContext = context;
mUsbAlsaManager = alsaManager;
@@ -216,6 +227,8 @@
}
mContext.registerReceiver(mHostReceiver,
new IntentFilter(UsbManager.ACTION_USB_PORT_CHANGED));
+ mContext.registerReceiver(mChargingReceiver,
+ new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
}
private UsbSettingsManager getCurrentSettings() {
@@ -330,6 +343,7 @@
private int mUsbNotificationId;
private boolean mAdbNotificationShown;
private int mCurrentUser = UserHandle.USER_NULL;
+ private boolean mUsbCharging;
public UsbHandler(Looper looper) {
super(looper);
@@ -428,7 +442,10 @@
args.argi2 = sourcePower ? 1 :0;
args.argi3 = sinkPower ? 1 :0;
- obtainMessage(MSG_UPDATE_HOST_STATE, args).sendToTarget();
+ removeMessages(MSG_UPDATE_HOST_STATE);
+ Message msg = obtainMessage(MSG_UPDATE_HOST_STATE, args);
+ // debounce rapid transitions of connect/disconnect on type-c ports
+ sendMessageDelayed(msg, UPDATE_DELAY);
}
private boolean waitForState(String state) {
@@ -766,6 +783,10 @@
mPendingBootBroadcast = true;
}
break;
+ case MSG_UPDATE_CHARGING_STATE:
+ mUsbCharging = (msg.arg1 == 1);
+ updateUsbNotification();
+ break;
case MSG_ENABLE_ADB:
setAdbEnabled(msg.arg1 == 1);
break;
@@ -850,7 +871,7 @@
}
} else if (mSourcePower) {
id = com.android.internal.R.string.usb_supplying_notification_title;
- } else if (mHostConnected && mSinkPower) {
+ } else if (mHostConnected && mSinkPower && mUsbCharging) {
id = com.android.internal.R.string.usb_charging_notification_title;
}
if (id != mUsbNotificationId) {
@@ -954,6 +975,7 @@
pw.println(" mHostConnected: " + mHostConnected);
pw.println(" mSourcePower: " + mSourcePower);
pw.println(" mSinkPower: " + mSinkPower);
+ pw.println(" mUsbCharging: " + mUsbCharging);
try {
pw.println(" Kernel state: "
+ FileUtils.readTextFile(new File(STATE_PATH), 0, null).trim());
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index f129c33..e939b2e 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -16,12 +16,21 @@
package android.telecom;
+import android.annotation.IntDef;
+import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
+import android.os.ParcelFileDescriptor;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
import java.lang.String;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -835,6 +844,143 @@
* @param extras Extras associated with the connection event.
*/
public void onConnectionEvent(Call call, String event, Bundle extras) {}
+
+ /**
+ * Invoked when the RTT mode changes for this call.
+ * @param call The call whose RTT mode has changed.
+ * @param mode the new RTT mode, one of
+ * {@link RttCall#RTT_MODE_FULL}, {@link RttCall#RTT_MODE_HCO},
+ * or {@link RttCall#RTT_MODE_VCO}
+ */
+ public void onRttModeChanged(Call call, int mode) {}
+
+ /**
+ * Invoked when the call's RTT status changes, either from off to on or from on to off.
+ * @param call The call whose RTT status has changed.
+ * @param enabled whether RTT is now enabled or disabled
+ * @param rttCall the {@link RttCall} object to use for reading and writing if RTT is now
+ * on, null otherwise.
+ */
+ public void onRttStatusChanged(Call call, boolean enabled, RttCall rttCall) {}
+
+ /**
+ * Invoked when the remote end of the connection has requested that an RTT communication
+ * channel be opened. A response to this should be sent via {@link #respondToRttRequest}
+ * with the same ID that this method is invoked with.
+ * @param call The call which the RTT request was placed on
+ * @param id The ID of the request.
+ */
+ public void onRttRequest(Call call, int id) {}
+ }
+
+ /**
+ * A class that holds the state that describes the state of the RTT channel to the remote
+ * party, if it is active.
+ */
+ public static final class RttCall {
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({RTT_MODE_INVALID, RTT_MODE_FULL, RTT_MODE_HCO, RTT_MODE_VCO})
+ public @interface RttAudioMode {}
+
+ /**
+ * For metrics use. Default value in the proto.
+ * @hide
+ */
+ public static final int RTT_MODE_INVALID = 0;
+
+ /**
+ * Indicates that there should be a bidirectional audio stream between the two parties
+ * on the call.
+ */
+ public static final int RTT_MODE_FULL = 1;
+
+ /**
+ * Indicates that the local user should be able to hear the audio stream from the remote
+ * user, but not vice versa. Equivalent to muting the microphone.
+ */
+ public static final int RTT_MODE_HCO = 2;
+
+ /**
+ * Indicates that the remote user should be able to hear the audio stream from the local
+ * user, but not vice versa. Equivalent to setting the volume to zero.
+ */
+ public static final int RTT_MODE_VCO = 3;
+
+ private static final int READ_BUFFER_SIZE = 1000;
+
+ private InputStreamReader mReceiveStream;
+ private OutputStreamWriter mTransmitStream;
+ private int mRttMode;
+ private final InCallAdapter mInCallAdapter;
+ private char[] mReadBuffer = new char[READ_BUFFER_SIZE];
+
+ /**
+ * @hide
+ */
+ public RttCall(InputStreamReader receiveStream, OutputStreamWriter transmitStream,
+ int mode, InCallAdapter inCallAdapter) {
+ mReceiveStream = receiveStream;
+ mTransmitStream = transmitStream;
+ mRttMode = mode;
+ mInCallAdapter = inCallAdapter;
+ }
+
+ /**
+ * Returns the current RTT audio mode.
+ * @return Current RTT audio mode. One of {@link #RTT_MODE_FULL}, {@link #RTT_MODE_VCO}, or
+ * {@link #RTT_MODE_HCO}.
+ */
+ public int getRttAudioMode() {
+ return mRttMode;
+ }
+
+ /**
+ * Sets the RTT audio mode. The requested mode change will be communicated through
+ * {@link Callback#onRttModeChanged(Call, int)}.
+ * @param mode The desired RTT audio mode, one of {@link #RTT_MODE_FULL},
+ * {@link #RTT_MODE_VCO}, or {@link #RTT_MODE_HCO}.
+ */
+ public void setRttMode(@RttAudioMode int mode) {
+ mInCallAdapter.setRttMode(mode);
+ }
+
+ /**
+ * Writes the string {@param input} into the outgoing text stream for this RTT call. Since
+ * RTT transmits text in real-time, this method should be called once for each character
+ * the user enters into the device.
+ *
+ * This method is not thread-safe -- calling it from multiple threads simultaneously may
+ * lead to interleaved text.
+ * @param input The message to send to the remote user.
+ */
+ public void write(String input) throws IOException {
+ mTransmitStream.write(input);
+ mTransmitStream.flush();
+ }
+
+ /**
+ * Reads a string from the remote user, blocking if there is no data available. Returns
+ * {@code null} if the RTT conversation has been terminated and there is no further data
+ * to read.
+ *
+ * This method is not thread-safe -- calling it from multiple threads simultaneously may
+ * lead to interleaved text.
+ * @return A string containing text sent by the remote user, or {@code null} if the
+ * conversation has been terminated or if there was an error while reading.
+ */
+ public String read() {
+ try {
+ int numRead = mReceiveStream.read(mReadBuffer, 0, READ_BUFFER_SIZE);
+ if (numRead < 0) {
+ return null;
+ }
+ return new String(mReadBuffer, 0, numRead);
+ } catch (IOException e) {
+ Log.w(this, "Exception encountered when reading from InputStreamReader: %s", e);
+ return null;
+ }
+ }
}
/**
@@ -863,6 +1009,7 @@
private String mCallingPackage;
private String mRemainingPostDialSequence;
private VideoCallImpl mVideoCallImpl;
+ private RttCall mRttCall;
private Details mDetails;
private Bundle mExtras;
@@ -1061,6 +1208,34 @@
}
/**
+ * Sends an RTT upgrade request to the remote end of the connection. Success is not
+ * guaranteed, and notification of success will be via the
+ * {@link Callback#onRttStatusChanged(Call, boolean, RttCall)} callback.
+ */
+ public void sendRttRequest() {
+ mInCallAdapter.sendRttRequest();
+ }
+
+ /**
+ * Responds to an RTT request received via the {@link Callback#onRttRequest(Call, int)} )}
+ * callback.
+ * The ID used here should be the same as the ID that was received via the callback.
+ * @param id The request ID received via {@link Callback#onRttRequest(Call, int)}
+ * @param accept {@code true} if the RTT request should be accepted, {@code false} otherwise.
+ */
+ public void respondToRttRequest(int id, boolean accept) {
+ mInCallAdapter.respondToRttRequest(id, accept);
+ }
+
+ /**
+ * Terminate the RTT session on this call. The resulting state change will be notified via
+ * the {@link Callback#onRttStatusChanged(Call, boolean, RttCall)} callback.
+ */
+ public void stopRtt() {
+ mInCallAdapter.stopRtt();
+ }
+
+ /**
* Adds some extras to this {@link Call}. Existing keys are replaced and new ones are
* added.
* <p>
@@ -1240,6 +1415,23 @@
}
/**
+ * Returns this call's RttCall object. The {@link RttCall} instance is used to send and
+ * receive RTT text data, as well as to change the RTT mode.
+ * @return A {@link Call.RttCall}. {@code null} if there is no active RTT connection.
+ */
+ public @Nullable RttCall getRttCall() {
+ return mRttCall;
+ }
+
+ /**
+ * Returns whether this call has an active RTT connection.
+ * @return true if there is a connection, false otherwise.
+ */
+ public boolean isRttActive() {
+ return mRttCall != null;
+ }
+
+ /**
* Registers a callback to this {@code Call}.
*
* @param callback A {@code Callback}.
@@ -1433,6 +1625,32 @@
fireConferenceableCallsChanged();
}
+ boolean isRttChanged = false;
+ boolean rttModeChanged = false;
+ if (parcelableCall.getParcelableRttCall() != null && parcelableCall.getIsRttCallChanged()) {
+ ParcelableRttCall parcelableRttCall = parcelableCall.getParcelableRttCall();
+ InputStreamReader receiveStream = new InputStreamReader(
+ new ParcelFileDescriptor.AutoCloseInputStream(
+ parcelableRttCall.getReceiveStream()),
+ StandardCharsets.UTF_8);
+ OutputStreamWriter transmitStream = new OutputStreamWriter(
+ new ParcelFileDescriptor.AutoCloseOutputStream(
+ parcelableRttCall.getTransmitStream()),
+ StandardCharsets.UTF_8);
+ RttCall newRttCall = new Call.RttCall(
+ receiveStream, transmitStream, parcelableRttCall.getRttMode(), mInCallAdapter);
+ if (mRttCall == null) {
+ isRttChanged = true;
+ } else if (mRttCall.getRttAudioMode() != newRttCall.getRttAudioMode()) {
+ rttModeChanged = true;
+ }
+ mRttCall = newRttCall;
+ } else if (mRttCall != null && parcelableCall.getParcelableRttCall() == null
+ && parcelableCall.getIsRttCallChanged()) {
+ isRttChanged = true;
+ mRttCall = null;
+ }
+
// Now we fire updates, ensuring that any client who listens to any of these notifications
// gets the most up-to-date state.
@@ -1454,6 +1672,12 @@
if (childrenChanged) {
fireChildrenChanged(getChildren());
}
+ if (isRttChanged) {
+ fireOnIsRttChanged(mRttCall != null, mRttCall);
+ }
+ if (rttModeChanged) {
+ fireOnRttModeChanged(mRttCall.getRttAudioMode());
+ }
// If we have transitioned to DISCONNECTED, that means we need to notify clients and
// remove ourselves from the Phone. Note that we do this after completing all state updates
@@ -1484,6 +1708,15 @@
fireOnConnectionEvent(event, extras);
}
+ /** {@hide} */
+ final void internalOnRttUpgradeRequest(final int requestId) {
+ for (CallbackRecord<Callback> record : mCallbackRecords) {
+ final Call call = this;
+ final Callback callback = record.getCallback();
+ record.getHandler().post(() -> callback.onRttRequest(call, requestId));
+ }
+ }
+
private void fireStateChanged(final int newState) {
for (CallbackRecord<Callback> record : mCallbackRecords) {
final Call call = this;
@@ -1652,6 +1885,32 @@
}
/**
+ * Notifies listeners of an RTT on/off change
+ *
+ * @param enabled True if RTT is now enabled, false otherwise
+ */
+ private void fireOnIsRttChanged(final boolean enabled, final RttCall rttCall) {
+ for (CallbackRecord<Callback> record : mCallbackRecords) {
+ final Call call = this;
+ final Callback callback = record.getCallback();
+ record.getHandler().post(() -> callback.onRttStatusChanged(call, enabled, rttCall));
+ }
+ }
+
+ /**
+ * Notifies listeners of a RTT mode change
+ *
+ * @param mode The new RTT mode
+ */
+ private void fireOnRttModeChanged(final int mode) {
+ for (CallbackRecord<Callback> record : mCallbackRecords) {
+ final Call call = this;
+ final Callback callback = record.getCallback();
+ record.getHandler().post(() -> callback.onRttModeChanged(call, mode));
+ }
+ }
+
+ /**
* Determines if two bundles are equal.
*
* @param bundle The original bundle.
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index b7391b4..3e690b9 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -31,10 +31,14 @@
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
+import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.util.ArraySet;
import android.view.Surface;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -385,8 +389,14 @@
*/
public static final int PROPERTY_SELF_MANAGED = 1<<7;
+ /**
+ * When set, indicates that a connection has an active RTT session associated with it.
+ * @hide
+ */
+ public static final int PROPERTY_IS_RTT = 1 << 8;
+
//**********************************************************************************************
- // Next PROPERTY value: 1<<8
+ // Next PROPERTY value: 1<<9
//**********************************************************************************************
/**
@@ -757,6 +767,65 @@
}
/**
+ * Provides methods to read and write RTT data to/from the in-call app.
+ * @hide
+ */
+ public static final class RttTextStream {
+ private static final int READ_BUFFER_SIZE = 1000;
+ private final InputStreamReader mPipeFromInCall;
+ private final OutputStreamWriter mPipeToInCall;
+ private char[] mReadBuffer = new char[READ_BUFFER_SIZE];
+
+ /**
+ * @hide
+ */
+ public RttTextStream(ParcelFileDescriptor toInCall, ParcelFileDescriptor fromInCall) {
+ mPipeFromInCall = new InputStreamReader(
+ new ParcelFileDescriptor.AutoCloseInputStream(fromInCall));
+ mPipeToInCall = new OutputStreamWriter(
+ new ParcelFileDescriptor.AutoCloseOutputStream(toInCall));
+ }
+
+ /**
+ * Writes the string {@param input} into the text stream to the UI for this RTT call. Since
+ * RTT transmits text in real-time, this method should be called as often as text snippets
+ * are received from the remote user, even if it is only one character.
+ *
+ * This method is not thread-safe -- calling it from multiple threads simultaneously may
+ * lead to interleaved text.
+ * @param input The message to send to the in-call app.
+ */
+ public void write(String input) throws IOException {
+ mPipeToInCall.write(input);
+ mPipeToInCall.flush();
+ }
+
+
+ /**
+ * Reads a string from the in-call app, blocking if there is no data available. Returns
+ * {@code null} if the RTT conversation has been terminated and there is no further data
+ * to read.
+ *
+ * This method is not thread-safe -- calling it from multiple threads simultaneously may
+ * lead to interleaved text.
+ * @return A string containing text entered by the user, or {@code null} if the
+ * conversation has been terminated or if there was an error while reading.
+ */
+ public String read() {
+ try {
+ int numRead = mPipeFromInCall.read(mReadBuffer, 0, READ_BUFFER_SIZE);
+ if (numRead < 0) {
+ return null;
+ }
+ return new String(mReadBuffer, 0, numRead);
+ } catch (IOException e) {
+ Log.w(this, "Exception encountered when reading from InputStreamReader: %s", e);
+ return null;
+ }
+ }
+ }
+
+ /**
* Provides a means of controlling the video session associated with a {@link Connection}.
* <p>
* Implementations create a custom subclass of {@link VideoProvider} and the
diff --git a/telecomm/java/android/telecom/ConnectionRequest.java b/telecomm/java/android/telecom/ConnectionRequest.java
index 2343462..054de4c 100644
--- a/telecomm/java/android/telecom/ConnectionRequest.java
+++ b/telecomm/java/android/telecom/ConnectionRequest.java
@@ -19,6 +19,7 @@
import android.net.Uri;
import android.os.Bundle;
import android.os.Parcel;
+import android.os.ParcelFileDescriptor;
import android.os.Parcelable;
/**
@@ -27,13 +28,121 @@
*/
public final class ConnectionRequest implements Parcelable {
- // TODO: Token to limit recursive invocations
+ /**
+ * Builder class for {@link ConnectionRequest}
+ * @hide
+ */
+ public static final class Builder {
+ private PhoneAccountHandle mAccountHandle;
+ private Uri mAddress;
+ private Bundle mExtras;
+ private int mVideoState = VideoProfile.STATE_AUDIO_ONLY;
+ private String mTelecomCallId;
+ private boolean mShouldShowIncomingCallUi = false;
+ private ParcelFileDescriptor mRttPipeToInCall;
+ private ParcelFileDescriptor mRttPipeFromInCall;
+
+ public Builder() { }
+
+ /**
+ * Sets the phone account handle for the resulting {@link ConnectionRequest}
+ * @param accountHandle The accountHandle which should be used to place the call.
+ */
+ public Builder setAccountHandle(PhoneAccountHandle accountHandle) {
+ this.mAccountHandle = accountHandle;
+ return this;
+ }
+
+ /**
+ * Sets the address for the resulting {@link ConnectionRequest}
+ * @param address The address(e.g., phone number) to which the {@link Connection} is to
+ * connect.
+ */
+ public Builder setAddress(Uri address) {
+ this.mAddress = address;
+ return this;
+ }
+
+ /**
+ * Sets the extras bundle for the resulting {@link ConnectionRequest}
+ * @param extras Application-specific extra data.
+ */
+ public Builder setExtras(Bundle extras) {
+ this.mExtras = extras;
+ return this;
+ }
+
+ /**
+ * Sets the video state for the resulting {@link ConnectionRequest}
+ * @param videoState Determines the video state for the connection.
+ */
+ public Builder setVideoState(int videoState) {
+ this.mVideoState = videoState;
+ return this;
+ }
+
+ /**
+ * Sets the Telecom call ID for the resulting {@link ConnectionRequest}
+ * @param telecomCallId The telecom call ID.
+ */
+ public Builder setTelecomCallId(String telecomCallId) {
+ this.mTelecomCallId = telecomCallId;
+ return this;
+ }
+
+ /**
+ * Sets shouldShowIncomingUi for the resulting {@link ConnectionRequest}
+ * @param shouldShowIncomingCallUi For a self-managed {@link ConnectionService}, will be
+ * {@code true} if the {@link ConnectionService} should show
+ * its own incoming call UI for an incoming call. When
+ * {@code false}, Telecom shows the incoming call UI.
+ */
+ public Builder setShouldShowIncomingCallUi(boolean shouldShowIncomingCallUi) {
+ this.mShouldShowIncomingCallUi = shouldShowIncomingCallUi;
+ return this;
+ }
+
+ /**
+ * Sets the RTT pipe for transferring text into the {@link ConnectionService} for the
+ * resulting {@link ConnectionRequest}
+ * @param rttPipeFromInCall The data pipe to read from.
+ */
+ public Builder setRttPipeFromInCall(ParcelFileDescriptor rttPipeFromInCall) {
+ this.mRttPipeFromInCall = rttPipeFromInCall;
+ return this;
+ }
+
+ /**
+ * Sets the RTT pipe for transferring text out of {@link ConnectionService} for the
+ * resulting {@link ConnectionRequest}
+ * @param rttPipeToInCall The data pipe to write to.
+ */
+ public Builder setRttPipeToInCall(ParcelFileDescriptor rttPipeToInCall) {
+ this.mRttPipeToInCall = rttPipeToInCall;
+ return this;
+ }
+
+ public ConnectionRequest build() {
+ return new ConnectionRequest(
+ mAccountHandle,
+ mAddress,
+ mExtras,
+ mVideoState,
+ mTelecomCallId,
+ mShouldShowIncomingCallUi,
+ mRttPipeFromInCall,
+ mRttPipeToInCall);
+ }
+ }
+
private final PhoneAccountHandle mAccountHandle;
private final Uri mAddress;
private final Bundle mExtras;
private final int mVideoState;
private final String mTelecomCallId;
private final boolean mShouldShowIncomingCallUi;
+ private final ParcelFileDescriptor mRttPipeToInCall;
+ private final ParcelFileDescriptor mRttPipeFromInCall;
/**
* @param accountHandle The accountHandle which should be used to place the call.
@@ -44,7 +153,7 @@
PhoneAccountHandle accountHandle,
Uri handle,
Bundle extras) {
- this(accountHandle, handle, extras, VideoProfile.STATE_AUDIO_ONLY, null, false);
+ this(accountHandle, handle, extras, VideoProfile.STATE_AUDIO_ONLY, null, false, null, null);
}
/**
@@ -58,7 +167,7 @@
Uri handle,
Bundle extras,
int videoState) {
- this(accountHandle, handle, extras, videoState, null, false);
+ this(accountHandle, handle, extras, videoState, null, false, null, null);
}
/**
@@ -80,12 +189,27 @@
int videoState,
String telecomCallId,
boolean shouldShowIncomingCallUi) {
+ this(accountHandle, handle, extras, videoState, telecomCallId,
+ shouldShowIncomingCallUi, null, null);
+ }
+
+ private ConnectionRequest(
+ PhoneAccountHandle accountHandle,
+ Uri handle,
+ Bundle extras,
+ int videoState,
+ String telecomCallId,
+ boolean shouldShowIncomingCallUi,
+ ParcelFileDescriptor rttPipeFromInCall,
+ ParcelFileDescriptor rttPipeToInCall) {
mAccountHandle = accountHandle;
mAddress = handle;
mExtras = extras;
mVideoState = videoState;
mTelecomCallId = telecomCallId;
mShouldShowIncomingCallUi = shouldShowIncomingCallUi;
+ mRttPipeFromInCall = rttPipeFromInCall;
+ mRttPipeToInCall = rttPipeToInCall;
}
private ConnectionRequest(Parcel in) {
@@ -95,6 +219,8 @@
mVideoState = in.readInt();
mTelecomCallId = in.readString();
mShouldShowIncomingCallUi = in.readInt() == 1;
+ mRttPipeFromInCall = in.readParcelable(getClass().getClassLoader());
+ mRttPipeToInCall = in.readParcelable(getClass().getClassLoader());
}
/**
@@ -149,6 +275,59 @@
return mShouldShowIncomingCallUi;
}
+ /**
+ * Gets the {@link ParcelFileDescriptor} that is used to send RTT text from the connection
+ * service to the in-call UI. In order to obtain an
+ * {@link java.io.InputStream} from this {@link ParcelFileDescriptor}, use
+ * {@link android.os.ParcelFileDescriptor.AutoCloseInputStream}.
+ * Only text data encoded using UTF-8 should be written into this {@link ParcelFileDescriptor}.
+ * @return The {@link ParcelFileDescriptor} that should be used for communication.
+ * Do not un-hide -- only for use by Telephony
+ * @hide
+ */
+ public ParcelFileDescriptor getRttPipeToInCall() {
+ return mRttPipeToInCall;
+ }
+
+ /**
+ * Gets the {@link ParcelFileDescriptor} that is used to send RTT text from the in-call UI to
+ * the connection service. In order to obtain an
+ * {@link java.io.OutputStream} from this {@link ParcelFileDescriptor}, use
+ * {@link android.os.ParcelFileDescriptor.AutoCloseOutputStream}.
+ * The contents of this {@link ParcelFileDescriptor} will consist solely of text encoded in
+ * UTF-8.
+ * @return The {@link ParcelFileDescriptor} that should be used for communication
+ * Do not un-hide -- only for use by Telephony
+ * @hide
+ */
+ public ParcelFileDescriptor getRttPipeFromInCall() {
+ return mRttPipeFromInCall;
+ }
+
+ /**
+ * Gets the {@link android.telecom.Connection.RttTextStream} object that should be used to
+ * send and receive RTT text to/from the in-call app.
+ * @return An instance of {@link android.telecom.Connection.RttTextStream}, or {@code null}
+ * if this connection request is not requesting an RTT session upon connection establishment.
+ * @hide
+ */
+ public Connection.RttTextStream getRttTextStream() {
+ if (isRequestingRtt()) {
+ return new Connection.RttTextStream(mRttPipeToInCall, mRttPipeFromInCall);
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Convenience method for determining whether the ConnectionRequest is requesting an RTT session
+ * @return {@code true} if RTT is requested, {@code false} otherwise.
+ * @hide
+ */
+ public boolean isRequestingRtt() {
+ return mRttPipeFromInCall != null && mRttPipeToInCall != null;
+ }
+
@Override
public String toString() {
return String.format("ConnectionRequest %s %s",
@@ -186,5 +365,7 @@
destination.writeInt(mVideoState);
destination.writeString(mTelecomCallId);
destination.writeInt(mShouldShowIncomingCallUi ? 1 : 0);
+ destination.writeParcelable(mRttPipeFromInCall, 0);
+ destination.writeParcelable(mRttPipeToInCall, 0);
}
}
diff --git a/telecomm/java/android/telecom/InCallAdapter.java b/telecomm/java/android/telecom/InCallAdapter.java
index 3f270d9..d640b1d 100644
--- a/telecomm/java/android/telecom/InCallAdapter.java
+++ b/telecomm/java/android/telecom/InCallAdapter.java
@@ -34,7 +34,7 @@
* <p>
* The adapter will stop functioning when there are no more calls.
*
- * {@hide}
+ * @hide
*/
public final class InCallAdapter {
private final IInCallAdapter mAdapter;
@@ -375,4 +375,48 @@
} catch (RemoteException ignored) {
}
}
+
+ /**
+ * Sends an RTT upgrade request to the remote end of the connection.
+ */
+ public void sendRttRequest() {
+ try {
+ mAdapter.sendRttRequest();
+ } catch (RemoteException ignored) {
+ }
+ }
+
+ /**
+ * Responds to an RTT upgrade request initiated from the remote end.
+ *
+ * @param id the ID of the request as specified by Telecom
+ * @param accept Whether the request should be accepted.
+ */
+ public void respondToRttRequest(int id, boolean accept) {
+ try {
+ mAdapter.respondToRttRequest(id, accept);
+ } catch (RemoteException ignored) {
+ }
+ }
+
+ /**
+ * Instructs Telecom to shut down the RTT communication channel.
+ */
+ public void stopRtt() {
+ try {
+ mAdapter.stopRtt();
+ } catch (RemoteException ignored) {
+ }
+ }
+
+ /**
+ * Sets the RTT audio mode.
+ * @param mode the desired RTT audio mode
+ */
+ public void setRttMode(int mode) {
+ try {
+ mAdapter.setRttMode(mode);
+ } catch (RemoteException ignored) {
+ }
+ }
}
diff --git a/telecomm/java/android/telecom/InCallService.java b/telecomm/java/android/telecom/InCallService.java
index 5d68aae..4bc64c0 100644
--- a/telecomm/java/android/telecom/InCallService.java
+++ b/telecomm/java/android/telecom/InCallService.java
@@ -76,6 +76,7 @@
private static final int MSG_ON_CAN_ADD_CALL_CHANGED = 7;
private static final int MSG_SILENCE_RINGER = 8;
private static final int MSG_ON_CONNECTION_EVENT = 9;
+ private static final int MSG_ON_RTT_UPGRADE_REQUEST = 10;
/** Default Handler used to consolidate binder method calls onto a single thread. */
private final Handler mHandler = new Handler(Looper.getMainLooper()) {
@@ -133,6 +134,12 @@
}
break;
}
+ case MSG_ON_RTT_UPGRADE_REQUEST: {
+ String callId = (String) msg.obj;
+ int requestId = msg.arg1;
+ mPhone.internalOnRttUpgradeRequest(callId, requestId);
+ break;
+ }
default:
break;
}
@@ -198,6 +205,11 @@
args.arg3 = extras;
mHandler.obtainMessage(MSG_ON_CONNECTION_EVENT, args).sendToTarget();
}
+
+ @Override
+ public void onRttUpgradeRequest(String callId, int id) {
+ mHandler.obtainMessage(MSG_ON_RTT_UPGRADE_REQUEST, id, 0, callId).sendToTarget();
+ }
}
private Phone.Listener mPhoneListener = new Phone.Listener() {
diff --git a/telecomm/java/android/telecom/ParcelableCall.java b/telecomm/java/android/telecom/ParcelableCall.java
index a3fce9c..975aa5a 100644
--- a/telecomm/java/android/telecom/ParcelableCall.java
+++ b/telecomm/java/android/telecom/ParcelableCall.java
@@ -50,6 +50,8 @@
private final boolean mIsVideoCallProviderChanged;
private final IVideoProvider mVideoCallProvider;
private VideoCallImpl mVideoCall;
+ private final boolean mIsRttCallChanged;
+ private final ParcelableRttCall mRttCall;
private final String mParentCallId;
private final List<String> mChildCallIds;
private final StatusHints mStatusHints;
@@ -75,6 +77,8 @@
PhoneAccountHandle accountHandle,
boolean isVideoCallProviderChanged,
IVideoProvider videoCallProvider,
+ boolean isRttCallChanged,
+ ParcelableRttCall rttCall,
String parentCallId,
List<String> childCallIds,
StatusHints statusHints,
@@ -98,6 +102,8 @@
mAccountHandle = accountHandle;
mIsVideoCallProviderChanged = isVideoCallProviderChanged;
mVideoCallProvider = videoCallProvider;
+ mIsRttCallChanged = isRttCallChanged;
+ mRttCall = rttCall;
mParentCallId = parentCallId;
mChildCallIds = childCallIds;
mStatusHints = statusHints;
@@ -202,6 +208,18 @@
return mVideoCall;
}
+ public boolean getIsRttCallChanged() {
+ return mIsRttCallChanged;
+ }
+
+ /**
+ * RTT communication channel information
+ * @return The ParcelableRttCall
+ */
+ public ParcelableRttCall getParcelableRttCall() {
+ return mRttCall;
+ }
+
/**
* The conference call to which this call is conferenced. Null if not conferenced.
*/
@@ -301,6 +319,8 @@
Bundle intentExtras = source.readBundle(classLoader);
Bundle extras = source.readBundle(classLoader);
int supportedAudioRoutes = source.readInt();
+ boolean isRttCallChanged = source.readByte() == 1;
+ ParcelableRttCall rttCall = source.readParcelable(classLoader);
return new ParcelableCall(
id,
state,
@@ -318,6 +338,8 @@
accountHandle,
isVideoCallProviderChanged,
videoCallProvider,
+ isRttCallChanged,
+ rttCall,
parentCallId,
childCallIds,
statusHints,
@@ -366,6 +388,8 @@
destination.writeBundle(mIntentExtras);
destination.writeBundle(mExtras);
destination.writeInt(mSupportedAudioRoutes);
+ destination.writeByte((byte) (mIsRttCallChanged ? 1 : 0));
+ destination.writeParcelable(mRttCall, 0);
}
@Override
diff --git a/telecomm/java/android/telecom/ParcelableRttCall.aidl b/telecomm/java/android/telecom/ParcelableRttCall.aidl
new file mode 100644
index 0000000..4480710
--- /dev/null
+++ b/telecomm/java/android/telecom/ParcelableRttCall.aidl
@@ -0,0 +1,22 @@
+/*
+ * 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.telecom;
+
+/**
+ * {@hide}
+ */
+parcelable ParcelableRttCall;
diff --git a/telecomm/java/android/telecom/ParcelableRttCall.java b/telecomm/java/android/telecom/ParcelableRttCall.java
new file mode 100644
index 0000000..763e48b
--- /dev/null
+++ b/telecomm/java/android/telecom/ParcelableRttCall.java
@@ -0,0 +1,88 @@
+/*
+ * 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.telecom;
+
+import android.os.Parcel;
+import android.os.ParcelFileDescriptor;
+import android.os.Parcelable;
+
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * Data container for information associated with the RTT connection on a call.
+ * @hide
+ */
+public class ParcelableRttCall implements Parcelable {
+ private final int mRttMode;
+ private final ParcelFileDescriptor mTransmitStream;
+ private final ParcelFileDescriptor mReceiveStream;
+
+ public ParcelableRttCall(
+ int rttMode,
+ ParcelFileDescriptor transmitStream,
+ ParcelFileDescriptor receiveStream) {
+ mRttMode = rttMode;
+ mTransmitStream = transmitStream;
+ mReceiveStream = receiveStream;
+ }
+
+ protected ParcelableRttCall(Parcel in) {
+ mRttMode = in.readInt();
+ mTransmitStream = in.readParcelable(ParcelFileDescriptor.class.getClassLoader());
+ mReceiveStream = in.readParcelable(ParcelFileDescriptor.class.getClassLoader());
+ }
+
+ public static final Creator<ParcelableRttCall> CREATOR = new Creator<ParcelableRttCall>() {
+ @Override
+ public ParcelableRttCall createFromParcel(Parcel in) {
+ return new ParcelableRttCall(in);
+ }
+
+ @Override
+ public ParcelableRttCall[] newArray(int size) {
+ return new ParcelableRttCall[size];
+ }
+ };
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(mRttMode);
+ dest.writeParcelable(mTransmitStream, flags);
+ dest.writeParcelable(mReceiveStream, flags);
+ }
+
+ public int getRttMode() {
+ return mRttMode;
+ }
+
+ public ParcelFileDescriptor getReceiveStream() {
+ return mReceiveStream;
+ }
+
+ public ParcelFileDescriptor getTransmitStream() {
+ return mTransmitStream;
+ }
+}
diff --git a/telecomm/java/android/telecom/Phone.java b/telecomm/java/android/telecom/Phone.java
index 30ec5b3..ebd04c7 100644
--- a/telecomm/java/android/telecom/Phone.java
+++ b/telecomm/java/android/telecom/Phone.java
@@ -201,6 +201,13 @@
}
}
+ final void internalOnRttUpgradeRequest(String callId, int requestId) {
+ Call call = mCallByTelecomCallId.get(callId);
+ if (call != null) {
+ call.internalOnRttUpgradeRequest(requestId);
+ }
+ }
+
/**
* Called to destroy the phone and cleanup any lingering calls.
*/
diff --git a/telecomm/java/android/telecom/PhoneAccount.java b/telecomm/java/android/telecom/PhoneAccount.java
index 845a103..3926e20 100644
--- a/telecomm/java/android/telecom/PhoneAccount.java
+++ b/telecomm/java/android/telecom/PhoneAccount.java
@@ -204,6 +204,18 @@
public static final int CAPABILITY_SELF_MANAGED = 0x800;
/**
+ * Flag indicating that this {@link PhoneAccount} is capable of making a call with an
+ * RTT (Real-time text) session.
+ * When set, Telecom will attempt to open an RTT session on outgoing calls that specify
+ * that they should be placed with an RTT session , and the in-call app will be displayed
+ * with text entry fields for RTT. Likewise, the in-call app can request that an RTT
+ * session be opened during a call if this bit is set.
+ */
+ public static final int CAPABILITY_RTT = 0x1000;
+
+ /* NEXT CAPABILITY: 0x2000 */
+
+ /**
* URI scheme for telephone number URIs.
*/
public static final String SCHEME_TEL = "tel";
diff --git a/telecomm/java/android/telecom/RemoteConnectionService.java b/telecomm/java/android/telecom/RemoteConnectionService.java
index 0c7404a..60a40f5 100644
--- a/telecomm/java/android/telecom/RemoteConnectionService.java
+++ b/telecomm/java/android/telecom/RemoteConnectionService.java
@@ -450,11 +450,14 @@
ConnectionRequest request,
boolean isIncoming) {
final String id = UUID.randomUUID().toString();
- final ConnectionRequest newRequest = new ConnectionRequest(
- request.getAccountHandle(),
- request.getAddress(),
- request.getExtras(),
- request.getVideoState());
+ final ConnectionRequest newRequest = new ConnectionRequest.Builder()
+ .setAccountHandle(request.getAccountHandle())
+ .setAddress(request.getAddress())
+ .setExtras(request.getExtras())
+ .setVideoState(request.getVideoState())
+ .setRttPipeFromInCall(request.getRttPipeFromInCall())
+ .setRttPipeToInCall(request.getRttPipeToInCall())
+ .build();
try {
if (mConnectionById.isEmpty()) {
mOutgoingConnectionServiceRpc.addConnectionServiceAdapter(mServant.getStub(),
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 5ce9c50..e21b4db 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -317,6 +317,23 @@
public static final String EXTRA_CALL_BACK_NUMBER = "android.telecom.extra.CALL_BACK_NUMBER";
/**
+ * The number of milliseconds that Telecom should wait after disconnecting a call via the
+ * ACTION_NEW_OUTGOING_CALL broadcast, in order to wait for the app which cancelled the call
+ * to make a new one.
+ * @hide
+ */
+ public static final String EXTRA_NEW_OUTGOING_CALL_CANCEL_TIMEOUT =
+ "android.telecom.extra.NEW_OUTGOING_CALL_CANCEL_TIMEOUT";
+
+ /**
+ * A boolean extra, which when set on the {@link Intent#ACTION_CALL} intent or on the bundle
+ * passed into {@link #placeCall(Uri, Bundle)}, indicates that the call should be initiated with
+ * an RTT session open. See {@link android.telecom.Call.RttCall} for more information on RTT.
+ */
+ public static final String EXTRA_START_CALL_WITH_RTT =
+ "android.telecom.extra.START_CALL_WITH_RTT";
+
+ /**
* A boolean meta-data value indicating whether an {@link InCallService} implements an
* in-call user interface. Dialer implementations (see {@link #getDefaultDialerPackage()}) which
* would also like to replace the in-call interface should set this meta-data to {@code true} in
diff --git a/telecomm/java/android/telecom/VideoProfile.java b/telecomm/java/android/telecom/VideoProfile.java
index 216603c..e0e3a08 100644
--- a/telecomm/java/android/telecom/VideoProfile.java
+++ b/telecomm/java/android/telecom/VideoProfile.java
@@ -235,7 +235,7 @@
StringBuilder sb = new StringBuilder();
sb.append("Audio");
- if (isAudioOnly(videoState)) {
+ if (videoState == STATE_AUDIO_ONLY) {
sb.append(" Only");
} else {
if (isTransmissionEnabled(videoState)) {
@@ -256,6 +256,9 @@
/**
* Indicates whether the video state is audio only.
+ * <p>
+ * Note: Considers only whether either both the {@link #STATE_RX_ENABLED} or
+ * {@link #STATE_TX_ENABLED} bits are off, but not {@link #STATE_PAUSED}.
*
* @param videoState The video state.
* @return {@code True} if the video state is audio only, {@code false} otherwise.
diff --git a/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl b/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
index 49f9b3b..47c3e6c 100644
--- a/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
+++ b/telecomm/java/com/android/internal/telecom/IInCallAdapter.aidl
@@ -69,4 +69,12 @@
void putExtras(String callId, in Bundle extras);
void removeExtras(String callId, in List<String> keys);
+
+ void sendRttRequest();
+
+ void respondToRttRequest(int id, boolean accept);
+
+ void stopRtt();
+
+ void setRttMode(int mode);
}
diff --git a/telecomm/java/com/android/internal/telecom/IInCallService.aidl b/telecomm/java/com/android/internal/telecom/IInCallService.aidl
index 3e43fe2..1f92e0c 100644
--- a/telecomm/java/com/android/internal/telecom/IInCallService.aidl
+++ b/telecomm/java/com/android/internal/telecom/IInCallService.aidl
@@ -50,4 +50,6 @@
void silenceRinger();
void onConnectionEvent(String callId, String event, in Bundle extras);
+
+ void onRttUpgradeRequest(String callId, int id);
}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 04c10d2..1076afc 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -817,7 +817,7 @@
/**
* Defines carrier-specific actions which act upon
- * android.intent.action.CARRIER_SIGNAL_REDIRECTED, used for customization of the
+ * com.android.internal.telephony.CARRIER_SIGNAL_REDIRECTED, used for customization of the
* default carrier app
* Format: "CARRIER_ACTION_IDX, ..."
* Where {@code CARRIER_ACTION_IDX} is an integer defined in
@@ -832,7 +832,7 @@
/**
* Defines carrier-specific actions which act upon
- * android.intent.action.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED
+ * com.android.internal.telephony.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED
* and configured signal args:
* {@link com.android.internal.telephony.TelephonyIntents#EXTRA_APN_TYPE_KEY apnType},
* {@link com.android.internal.telephony.TelephonyIntents#EXTRA_ERROR_CODE_KEY errorCode}
@@ -873,11 +873,11 @@
* @see com.android.internal.telephony.TelephonyIntents
* Example:
* <item>com.google.android.carrierAPK/.CarrierSignalReceiverA:
- * android.intent.action.CARRIER_SIGNAL_REDIRECTED,
- * android.intent.action.CARRIER_SIGNAL_PCO_VALUE
+ * com.android.internal.telephony.CARRIER_SIGNAL_REDIRECTED,
+ * com.android.internal.telephony.CARRIER_SIGNAL_PCO_VALUE
* </item>
* <item>com.google.android.carrierAPK/.CarrierSignalReceiverB:
- * android.intent.action.CARRIER_SIGNAL_PCO_VALUE
+ * com.android.internal.telephony.CARRIER_SIGNAL_PCO_VALUE
* </item>
* @hide
*/
@@ -892,11 +892,11 @@
* @see com.android.internal.telephony.TelephonyIntents
* Example:
* <item>com.google.android.carrierAPK/.CarrierSignalReceiverA:
- * android.intent.action.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED,
- * android.intent.action.CARRIER_SIGNAL_PCO_VALUE
+ * com.android.internal.telephony.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED,
+ * com.android.internal.telephony.CARRIER_SIGNAL_PCO_VALUE
* </item>
* <item>com.google.android.carrierAPK/.CarrierSignalReceiverB:
- * android.intent.action.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED
+ * com.android.internal.telephony.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED
* </item>
* @hide
*/
@@ -1119,6 +1119,22 @@
public static final String KEY_EDITABLE_WFC_ROAMING_MODE_BOOL =
"editable_wfc_roaming_mode_bool";
+ /**
+ * Indicates whether the carrier supports 3gpp call forwarding MMI codes while roaming. If
+ * false, the user will be notified that call forwarding is not available when the MMI code
+ * fails.
+ */
+ public static final String KEY_SUPPORT_3GPP_CALL_FORWARDING_WHILE_ROAMING_BOOL =
+ "support_3gpp_call_forwarding_while_roaming_bool";
+
+ /**
+ * When {@code true}, the user will be notified when they attempt to place an international call
+ * when the call is placed using wifi calling.
+ * @hide
+ */
+ public static final String KEY_NOTIFY_INTERNATIONAL_CALL_ON_WFC_BOOL =
+ "notify_international_call_on_wfc_bool";
+
/** The default value for every variable. */
private final static PersistableBundle sDefaults;
@@ -1293,7 +1309,7 @@
sDefaults.putStringArray(KEY_CARRIER_APP_WAKE_SIGNAL_CONFIG_STRING_ARRAY,
new String[]{
"com.android.carrierdefaultapp/.CarrierDefaultBroadcastReceiver:" +
- "android.intent.action.CARRIER_SIGNAL_REDIRECTED"
+ "com.android.internal.telephony.CARRIER_SIGNAL_REDIRECTED"
});
sDefaults.putStringArray(KEY_CARRIER_APP_NO_WAKE_SIGNAL_CONFIG_STRING_ARRAY, null);
@@ -1323,6 +1339,8 @@
sDefaults.putBoolean(KEY_NOTIFY_VT_HANDOVER_TO_WIFI_FAILURE_BOOL, false);
sDefaults.putStringArray(KEY_FILTERED_CNAP_NAMES_STRING_ARRAY, null);
sDefaults.putBoolean(KEY_EDITABLE_WFC_ROAMING_MODE_BOOL, false);
+ sDefaults.putBoolean(KEY_SUPPORT_3GPP_CALL_FORWARDING_WHILE_ROAMING_BOOL, true);
+ sDefaults.putBoolean(KEY_NOTIFY_INTERNATIONAL_CALL_ON_WFC_BOOL, false);
}
/**
diff --git a/telephony/java/android/telephony/PhoneNumberUtils.java b/telephony/java/android/telephony/PhoneNumberUtils.java
index 152b868..2eba402 100644
--- a/telephony/java/android/telephony/PhoneNumberUtils.java
+++ b/telephony/java/android/telephony/PhoneNumberUtils.java
@@ -1139,6 +1139,8 @@
private static final String KOREA_ISO_COUNTRY_CODE = "KR";
+ private static final String JAPAN_ISO_COUNTRY_CODE = "JP";
+
/**
* Breaks the given number down and formats it according to the rules
* for the country the number is from.
@@ -1437,6 +1439,30 @@
}
/**
+ * Determines if a {@param phoneNumber} is international if dialed from
+ * {@param defaultCountryIso}.
+ *
+ * @param phoneNumber The phone number.
+ * @param defaultCountryIso The current country ISO.
+ * @return {@code true} if the number is international, {@code false} otherwise.
+ * @hide
+ */
+ public static boolean isInternationalNumber(String phoneNumber, String defaultCountryIso) {
+ // If it starts with # or * its not international.
+ if (phoneNumber.startsWith("#") || phoneNumber.startsWith("*")) {
+ return false;
+ }
+
+ PhoneNumberUtil util = PhoneNumberUtil.getInstance();
+ try {
+ PhoneNumber pn = util.parseAndKeepRawInput(phoneNumber, defaultCountryIso);
+ return pn.getCountryCode() != util.getCountryCodeForRegion(defaultCountryIso);
+ } catch (NumberParseException e) {
+ return false;
+ }
+ }
+
+ /**
* Format a phone number.
* <p>
* If the given number doesn't have the country code, the phone will be
@@ -1459,15 +1485,25 @@
String result = null;
try {
PhoneNumber pn = util.parseAndKeepRawInput(phoneNumber, defaultCountryIso);
- /**
- * Need to reformat any local Korean phone numbers (when the user is in Korea) with
- * country code to corresponding national format which would replace the leading
- * +82 with 0.
- */
- if (KOREA_ISO_COUNTRY_CODE.equals(defaultCountryIso) &&
+
+ if (KOREA_ISO_COUNTRY_CODE.equalsIgnoreCase(defaultCountryIso) &&
(pn.getCountryCode() == util.getCountryCodeForRegion(KOREA_ISO_COUNTRY_CODE)) &&
(pn.getCountryCodeSource() ==
PhoneNumber.CountryCodeSource.FROM_NUMBER_WITH_PLUS_SIGN)) {
+ /**
+ * Need to reformat any local Korean phone numbers (when the user is in Korea) with
+ * country code to corresponding national format which would replace the leading
+ * +82 with 0.
+ */
+ result = util.format(pn, PhoneNumberUtil.PhoneNumberFormat.NATIONAL);
+ } else if (JAPAN_ISO_COUNTRY_CODE.equalsIgnoreCase(defaultCountryIso) &&
+ pn.getCountryCode() == util.getCountryCodeForRegion(JAPAN_ISO_COUNTRY_CODE) &&
+ (pn.getCountryCodeSource() ==
+ PhoneNumber.CountryCodeSource.FROM_NUMBER_WITH_PLUS_SIGN)) {
+ /**
+ * Need to reformat Japanese phone numbers (when user is in Japan) with the national
+ * dialing format.
+ */
result = util.format(pn, PhoneNumberUtil.PhoneNumberFormat.NATIONAL);
} else {
result = util.formatInOriginalFormat(pn, defaultCountryIso);
diff --git a/telephony/java/android/telephony/PhoneStateListener.java b/telephony/java/android/telephony/PhoneStateListener.java
index 32f487b..afff6d5 100644
--- a/telephony/java/android/telephony/PhoneStateListener.java
+++ b/telephony/java/android/telephony/PhoneStateListener.java
@@ -20,17 +20,9 @@
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
-import android.telephony.SubscriptionManager;
-import android.telephony.CellLocation;
-import android.telephony.CellInfo;
-import android.telephony.VoLteServiceState;
-import android.telephony.Rlog;
-import android.telephony.ServiceState;
-import android.telephony.SignalStrength;
-import android.telephony.PreciseCallState;
-import android.telephony.PreciseDataConnectionState;
import com.android.internal.telephony.IPhoneStateListener;
+
import java.util.List;
import java.lang.ref.WeakReference;
@@ -216,7 +208,9 @@
*
* @see #onOemHookRawEvent
* @hide
+ * @deprecated OEM needs a vendor-extension hal and their apps should use that instead
*/
+ @Deprecated
public static final int LISTEN_OEM_HOOK_RAW_EVENT = 0x00008000;
/**
@@ -228,6 +222,38 @@
*/
public static final int LISTEN_CARRIER_NETWORK_CHANGE = 0x00010000;
+ /**
+ * Listen for changes to the sim voice activation state
+ * @see TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATING
+ * @see TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATED
+ * @see TelephonyManager#SIM_ACTIVATION_STATE_DEACTIVATED
+ * @see TelephonyManager#SIM_ACTIVATION_STATE_RESTRICTED
+ * @see TelephonyManager#SIM_ACTIVATION_STATE_UNKNOWN
+ * {@more}
+ * Example: TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATED indicates voice service has been
+ * fully activated
+ *
+ * @see #onVoiceActivationStateChanged
+ * @hide
+ */
+ public static final int LISTEN_VOICE_ACTIVATION_STATE = 0x00020000;
+
+ /**
+ * Listen for changes to the sim data activation state
+ * @see TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATING
+ * @see TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATED
+ * @see TelephonyManager#SIM_ACTIVATION_STATE_DEACTIVATED
+ * @see TelephonyManager#SIM_ACTIVATION_STATE_RESTRICTED
+ * @see TelephonyManager#SIM_ACTIVATION_STATE_UNKNOWN
+ * {@more}
+ * Example: TelephonyManager#SIM_ACTIVATION_STATE_ACTIVATED indicates data service has been
+ * fully activated
+ *
+ * @see #onDataActivationStateChanged
+ * @hide
+ */
+ public static final int LISTEN_DATA_ACTIVATION_STATE = 0x00040000;
+
/*
* Subscription used to listen to the phone state changes
* @hide
@@ -327,6 +353,12 @@
case LISTEN_VOLTE_STATE:
PhoneStateListener.this.onVoLteServiceStateChanged((VoLteServiceState)msg.obj);
break;
+ case LISTEN_VOICE_ACTIVATION_STATE:
+ PhoneStateListener.this.onVoiceActivationStateChanged((int)msg.obj);
+ break;
+ case LISTEN_DATA_ACTIVATION_STATE:
+ PhoneStateListener.this.onDataActivationStateChanged((int)msg.obj);
+ break;
case LISTEN_OEM_HOOK_RAW_EVENT:
PhoneStateListener.this.onOemHookRawEvent((byte[])msg.obj);
break;
@@ -506,6 +538,24 @@
}
/**
+ * Callback invoked when the SIM voice activation state has changed
+ * @param state is the current SIM voice activation state
+ * @hide
+ */
+ public void onVoiceActivationStateChanged(int state) {
+
+ }
+
+ /**
+ * Callback invoked when the SIM data activation state has changed
+ * @param state is the current SIM data activation state
+ * @hide
+ */
+ public void onDataActivationStateChanged(int state) {
+
+ }
+
+ /**
* Callback invoked when OEM hook raw event is received. Requires
* the READ_PRIVILEGED_PHONE_STATE permission.
* @param rawData is the byte array of the OEM hook raw data.
@@ -619,6 +669,14 @@
send(LISTEN_VOLTE_STATE, 0, 0, lteState);
}
+ public void onVoiceActivationStateChanged(int activationState) {
+ send(LISTEN_VOICE_ACTIVATION_STATE, 0, 0, activationState);
+ }
+
+ public void onDataActivationStateChanged(int activationState) {
+ send(LISTEN_DATA_ACTIVATION_STATE, 0, 0, activationState);
+ }
+
public void onOemHookRawEvent(byte[] rawData) {
send(LISTEN_OEM_HOOK_RAW_EVENT, 0, 0, rawData);
}
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index fcae4c3..7775a34 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -780,6 +780,21 @@
"android.telephony.event.EVENT_DOWNGRADE_DATA_DISABLED";
/**
+ * {@link android.telecom.Connection} event used to indicate that the InCall UI should notify
+ * the user when an international call is placed while on WFC only.
+ * <p>
+ * Used when the carrier config value
+ * {@link CarrierConfigManager#KEY_NOTIFY_INTERNATIONAL_CALL_ON_WFC_BOOL} is true, the device
+ * is on WFC (VoLTE not available) and an international number is dialed.
+ * <p>
+ * Sent via {@link android.telecom.Connection#sendConnectionEvent(String, Bundle)}.
+ * The {@link Bundle} parameter is expected to be null when this connection event is used.
+ * @hide
+ */
+ public static final String EVENT_NOTIFY_INTERNATIONAL_CALL_ON_WFC =
+ "android.telephony.event.EVENT_NOTIFY_INTERNATIONAL_CALL_ON_WFC";
+
+ /**
* Response codes for sim activation. Activation completed successfully.
* @hide
*/
@@ -2726,6 +2741,148 @@
}
/**
+ * Initial SIM activation state, unknown. Not set by any carrier apps.
+ * @hide
+ */
+ public static final int SIM_ACTIVATION_STATE_UNKNOWN = 0;
+
+ /**
+ * indicate SIM is under activation procedure now.
+ * intermediate state followed by another state update with activation procedure result:
+ * @see #SIM_ACTIVATION_STATE_ACTIVATED
+ * @see #SIM_ACTIVATION_STATE_DEACTIVATED
+ * @see #SIM_ACTIVATION_STATE_RESTRICTED
+ * @hide
+ */
+ public static final int SIM_ACTIVATION_STATE_ACTIVATING = 1;
+
+ /**
+ * Indicate SIM has been successfully activated with full service
+ * @hide
+ */
+ public static final int SIM_ACTIVATION_STATE_ACTIVATED = 2;
+
+ /**
+ * Indicate SIM has been deactivated by the carrier so that service is not available
+ * and requires activation service to enable services.
+ * Carrier apps could be signalled to set activation state to deactivated if detected
+ * deactivated sim state and set it back to activated after successfully run activation service.
+ * @hide
+ */
+ public static final int SIM_ACTIVATION_STATE_DEACTIVATED = 3;
+
+ /**
+ * Restricted state indicate SIM has been activated but service are restricted.
+ * note this is currently available for data activation state. For example out of byte sim.
+ * @hide
+ */
+ public static final int SIM_ACTIVATION_STATE_RESTRICTED = 4;
+
+ /**
+ * Sets the voice activation state for the given subscriber.
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+ * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+ *
+ * @param subId The subscription id.
+ * @param activationState The voice activation state of the given subscriber.
+ * @see #SIM_ACTIVATION_STATE_UNKNOWN
+ * @see #SIM_ACTIVATION_STATE_ACTIVATING
+ * @see #SIM_ACTIVATION_STATE_ACTIVATED
+ * @see #SIM_ACTIVATION_STATE_DEACTIVATED
+ * @hide
+ */
+ public void setVoiceActivationState(int subId, int activationState) {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null)
+ telephony.setVoiceActivationState(subId, activationState);
+ } catch (RemoteException ex) {
+ } catch (NullPointerException ex) {
+ }
+ }
+
+ /**
+ * Sets the data activation state for the given subscriber.
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE}
+ * Or the calling app has carrier privileges. @see #hasCarrierPrivileges
+ *
+ * @param subId The subscription id.
+ * @param activationState The data activation state of the given subscriber.
+ * @see #SIM_ACTIVATION_STATE_UNKNOWN
+ * @see #SIM_ACTIVATION_STATE_ACTIVATING
+ * @see #SIM_ACTIVATION_STATE_ACTIVATED
+ * @see #SIM_ACTIVATION_STATE_DEACTIVATED
+ * @see #SIM_ACTIVATION_STATE_RESTRICTED
+ * @hide
+ */
+ public void setDataActivationState(int subId, int activationState) {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null)
+ telephony.setDataActivationState(subId, activationState);
+ } catch (RemoteException ex) {
+ } catch (NullPointerException ex) {
+ }
+ }
+
+ /**
+ * Returns the voice activation state for the given subscriber.
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#READ_PHONE_STATE}
+ *
+ * @param subId The subscription id.
+ *
+ * @return voiceActivationState for the given subscriber
+ * @see #SIM_ACTIVATION_STATE_UNKNOWN
+ * @see #SIM_ACTIVATION_STATE_ACTIVATING
+ * @see #SIM_ACTIVATION_STATE_ACTIVATED
+ * @see #SIM_ACTIVATION_STATE_DEACTIVATED
+ * @hide
+ */
+ public int getVoiceActivationState(int subId) {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null)
+ return telephony.getVoiceActivationState(subId, getOpPackageName());
+ } catch (RemoteException ex) {
+ } catch (NullPointerException ex) {
+ }
+ return SIM_ACTIVATION_STATE_UNKNOWN;
+ }
+
+ /**
+ * Returns the data activation state for the given subscriber.
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#READ_PHONE_STATE}
+ *
+ * @param subId The subscription id.
+ *
+ * @return dataActivationState for the given subscriber
+ * @see #SIM_ACTIVATION_STATE_UNKNOWN
+ * @see #SIM_ACTIVATION_STATE_ACTIVATING
+ * @see #SIM_ACTIVATION_STATE_ACTIVATED
+ * @see #SIM_ACTIVATION_STATE_DEACTIVATED
+ * @see #SIM_ACTIVATION_STATE_RESTRICTED
+ * @hide
+ */
+ public int getDataActivationState(int subId) {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null)
+ return telephony.getDataActivationState(subId, getOpPackageName());
+ } catch (RemoteException ex) {
+ } catch (NullPointerException ex) {
+ }
+ return SIM_ACTIVATION_STATE_UNKNOWN;
+ }
+
+ /**
* Returns the voice mail count. Return 0 if unavailable, -1 if there are unread voice messages
* but the count is unknown.
* <p>
@@ -4032,6 +4189,45 @@
}
/**
+ * Returns an array of Forbidden PLMNs from the USIM App
+ * Returns null if the query fails.
+ *
+ *
+ * <p>Requires that the caller has READ_PRIVILEGED_PHONE_STATE
+ *
+ * @return an array of forbidden PLMNs or null if not available
+ */
+ public String[] getForbiddenPlmns() {
+ return getForbiddenPlmns(getSubId(), APPTYPE_USIM);
+ }
+
+ /**
+ * Returns an array of Forbidden PLMNs from the specified SIM App
+ * Returns null if the query fails.
+ *
+ *
+ * <p>Requires that the calling app has READ_PRIVILEGED_PHONE_STATE
+ *
+ * @param subId subscription ID used for authentication
+ * @param appType the icc application type, like {@link #APPTYPE_USIM}
+ * @return fplmns an array of forbidden PLMNs
+ * @hide
+ */
+ public String[] getForbiddenPlmns(int subId, int appType) {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony == null)
+ return null;
+ return telephony.getForbiddenPlmns(subId, appType);
+ } catch (RemoteException ex) {
+ return null;
+ } catch (NullPointerException ex) {
+ // This could happen before phone starts
+ return null;
+ }
+ }
+
+ /**
* Get P-CSCF address from PCO after data connection is established or modified.
* @param apnType the apnType, "ims" for IMS APN, "emergency" for EMERGENCY APN
* @return array of P-CSCF address
@@ -4898,7 +5094,9 @@
* 0 request was handled succesfully, but no response data
* positive value success, data length of response
* @hide
+ * @deprecated OEM needs a vendor-extension hal and their apps should use that instead
*/
+ @Deprecated
public int invokeOemRilRequestRaw(byte[] oemReq, byte[] oemResp) {
try {
ITelephony telephony = getITelephony();
@@ -5191,6 +5389,44 @@
}
/**
+ * Set SIM card power state. Request is equivalent to inserting or removing the card.
+ *
+ * @param powerUp True if powering up the SIM, otherwise powering down
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+ *
+ * @hide
+ **/
+ public void setSimPowerState(boolean powerUp) {
+ setSimPowerStateForSlot(getDefaultSim(), powerUp);
+ }
+
+ /**
+ * Set SIM card power state. Request is equivalent to inserting or removing the card.
+ *
+ * @param slotId SIM slot id
+ * @param powerUp True if powering up the SIM, otherwise powering down
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}
+ *
+ * @hide
+ **/
+ public void setSimPowerStateForSlot(int slotId, boolean powerUp) {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ telephony.setSimPowerStateForSlot(slotId, powerUp);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling ITelephony#setSimPowerStateForSlot", e);
+ } catch (SecurityException e) {
+ Log.e(TAG, "Permission error calling ITelephony#setSimPowerStateForSlot", e);
+ }
+ }
+
+ /**
* Set baseband version for the default phone.
*
* @param version baseband version
diff --git a/telephony/java/android/telephony/ims/ImsService.java b/telephony/java/android/telephony/ims/ImsService.java
new file mode 100644
index 0000000..f1f683c
--- /dev/null
+++ b/telephony/java/android/telephony/ims/ImsService.java
@@ -0,0 +1,467 @@
+/*
+ * 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.ims;
+
+import android.app.PendingIntent;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.RemoteException;
+import android.telephony.CarrierConfigManager;
+import android.telephony.ims.feature.ImsFeature;
+import android.telephony.ims.feature.MMTelFeature;
+import android.telephony.ims.feature.RcsFeature;
+import android.util.Log;
+import android.util.SparseArray;
+
+import com.android.ims.ImsCallProfile;
+import com.android.ims.internal.IImsCallSession;
+import com.android.ims.internal.IImsCallSessionListener;
+import com.android.ims.internal.IImsConfig;
+import com.android.ims.internal.IImsEcbm;
+import com.android.ims.internal.IImsFeatureStatusCallback;
+import com.android.ims.internal.IImsMultiEndpoint;
+import com.android.ims.internal.IImsRegistrationListener;
+import com.android.ims.internal.IImsServiceController;
+import com.android.ims.internal.IImsServiceFeatureListener;
+import com.android.ims.internal.IImsUt;
+import com.android.internal.annotations.VisibleForTesting;
+
+import static android.Manifest.permission.MODIFY_PHONE_STATE;
+import static android.Manifest.permission.READ_PHONE_STATE;
+import static android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE;
+
+/**
+ * Main ImsService implementation, which binds via the Telephony ImsResolver. Services that extend
+ * ImsService must register the service in their AndroidManifest to be detected by the framework.
+ * First, the application must declare that they use the "android.permission.BIND_IMS_SERVICE"
+ * permission. Then, the ImsService definition in the manifest must follow the following format:
+ *
+ * ...
+ * <service android:name=".EgImsService"
+ * android:permission="android.permission.BIND_IMS_SERVICE" >
+ * <!-- Apps must declare which features they support as metadata. The different categories are
+ * defined below. In this example, the RCS_FEATURE feature is supported. -->
+ * <meta-data android:name="android.telephony.ims.RCS_FEATURE" android:value="true" />
+ * <intent-filter>
+ * <action android:name="android.telephony.ims.ImsService" />
+ * </intent-filter>
+ * </service>
+ * ...
+ *
+ * The telephony framework will then bind to the ImsService you have defined in your manifest
+ * if you are either:
+ * 1) Defined as the default ImsService for the device in the device overlay using
+ * "config_ims_package".
+ * 2) Defined as a Carrier Provided ImsService in the Carrier Configuration using
+ * {@link CarrierConfigManager#KEY_CONFIG_IMS_PACKAGE_OVERRIDE_STRING}.
+ *
+ * The features that are currently supported in an ImsService are:
+ * - RCS_FEATURE: This ImsService implements the {@link RcsFeature} class.
+ * - MMTEL_FEATURE: This ImsService implements the {@link MMTelFeature} class.
+ * - EMERGENCY_MMTEL_FEATURE: This ImsService implements the {@link MMTelFeature} class and will be
+ * available to place emergency calls at all times. This MUST be implemented by the default
+ * ImsService provided in the device overlay.
+ *
+ * @hide
+ */
+public abstract class ImsService extends ImsServiceBase {
+
+ private static final String LOG_TAG = "ImsService";
+
+ /**
+ * The intent that must be defined as an intent-filter in the AndroidManifest of the ImsService.
+ */
+ public static final String SERVICE_INTERFACE = "android.telephony.ims.ImsService";
+
+ // A map of slot Id -> Set of features corresponding to that slot.
+ private final SparseArray<SparseArray<ImsFeature>> mFeatures = new SparseArray<>();
+
+ // Implements all supported features as a flat interface.
+ protected final IBinder mImsServiceController = new IImsServiceController.Stub() {
+
+ @Override
+ public void createImsFeature(int slotId, int feature, IImsFeatureStatusCallback c)
+ throws RemoteException {
+ synchronized (mFeatures) {
+ enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "createImsFeature");
+ onCreateImsFeatureInternal(slotId, feature, c);
+ }
+ }
+
+ @Override
+ public void removeImsFeature(int slotId, int feature) throws RemoteException {
+ synchronized (mFeatures) {
+ enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "removeImsFeature");
+ onRemoveImsFeatureInternal(slotId, feature);
+ }
+ }
+
+ @Override
+ public int startSession(int slotId, int featureType, PendingIntent incomingCallIntent,
+ IImsRegistrationListener listener) throws RemoteException {
+ enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "startSession");
+ synchronized (mFeatures) {
+ MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
+ if (feature != null) {
+ return feature.startSession(incomingCallIntent, listener);
+ }
+ }
+ return 0;
+ }
+
+ @Override
+ public void endSession(int slotId, int featureType, int sessionId) throws RemoteException {
+ synchronized (mFeatures) {
+ enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "endSession");
+ MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
+ if (feature != null) {
+ feature.endSession(sessionId);
+ }
+ }
+ }
+
+ @Override
+ public boolean isConnected(int slotId, int featureType, int callSessionType, int callType)
+ throws RemoteException {
+ enforceReadPhoneStatePermission("isConnected");
+ synchronized (mFeatures) {
+ MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
+ if (feature != null) {
+ return feature.isConnected(callSessionType, callType);
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean isOpened(int slotId, int featureType) throws RemoteException {
+ enforceReadPhoneStatePermission("isOpened");
+ synchronized (mFeatures) {
+ MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
+ if (feature != null) {
+ return feature.isOpened();
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public int getFeatureStatus(int slotId, int featureType) throws RemoteException {
+ enforceReadPhoneStatePermission("getFeatureStatus");
+ int status = ImsFeature.STATE_NOT_AVAILABLE;
+ synchronized (mFeatures) {
+ SparseArray<ImsFeature> featureMap = mFeatures.get(slotId);
+ if (featureMap != null) {
+ ImsFeature feature = getImsFeatureFromType(featureMap, featureType);
+ if (feature != null) {
+ status = feature.getFeatureState();
+ }
+ }
+ }
+ return status;
+ }
+
+ @Override
+ public void addRegistrationListener(int slotId, int featureType,
+ IImsRegistrationListener listener) throws RemoteException {
+ enforceReadPhoneStatePermission("addRegistrationListener");
+ synchronized (mFeatures) {
+ MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
+ if (feature != null) {
+ feature.addRegistrationListener(listener);
+ }
+ }
+ }
+
+ @Override
+ public void removeRegistrationListener(int slotId, int featureType,
+ IImsRegistrationListener listener) throws RemoteException {
+ enforceReadPhoneStatePermission("removeRegistrationListener");
+ synchronized (mFeatures) {
+ MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
+ if (feature != null) {
+ feature.removeRegistrationListener(listener);
+ }
+ }
+ }
+
+ @Override
+ public ImsCallProfile createCallProfile(int slotId, int featureType, int sessionId,
+ int callSessionType, int callType) throws RemoteException {
+ enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "createCallProfile");
+ synchronized (mFeatures) {
+ MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
+ if (feature != null) {
+ return feature.createCallProfile(sessionId, callSessionType, callType);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public IImsCallSession createCallSession(int slotId, int featureType, int sessionId,
+ ImsCallProfile profile, IImsCallSessionListener listener) throws RemoteException {
+ enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "createCallSession");
+ synchronized (mFeatures) {
+ MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
+ if (feature != null) {
+ return feature.createCallSession(sessionId, profile, listener);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public IImsCallSession getPendingCallSession(int slotId, int featureType, int sessionId,
+ String callId) throws RemoteException {
+ enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "getPendingCallSession");
+ synchronized (mFeatures) {
+ MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
+ if (feature != null) {
+ return feature.getPendingCallSession(sessionId, callId);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public IImsUt getUtInterface(int slotId, int featureType)
+ throws RemoteException {
+ enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "getUtInterface");
+ synchronized (mFeatures) {
+ MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
+ if (feature != null) {
+ return feature.getUtInterface();
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public IImsConfig getConfigInterface(int slotId, int featureType)
+ throws RemoteException {
+ enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "getConfigInterface");
+ synchronized (mFeatures) {
+ MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
+ if (feature != null) {
+ return feature.getConfigInterface();
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public void turnOnIms(int slotId, int featureType) throws RemoteException {
+ enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "turnOnIms");
+ synchronized (mFeatures) {
+ MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
+ if (feature != null) {
+ feature.turnOnIms();
+ }
+ }
+ }
+
+ @Override
+ public void turnOffIms(int slotId, int featureType) throws RemoteException {
+ enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "turnOffIms");
+ synchronized (mFeatures) {
+ MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
+ if (feature != null) {
+ feature.turnOffIms();
+ }
+ }
+ }
+
+ @Override
+ public IImsEcbm getEcbmInterface(int slotId, int featureType)
+ throws RemoteException {
+ enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "getEcbmInterface");
+ synchronized (mFeatures) {
+ MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
+ if (feature != null) {
+ return feature.getEcbmInterface();
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public void setUiTTYMode(int slotId, int featureType, int uiTtyMode, Message onComplete)
+ throws RemoteException {
+ enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "setUiTTYMode");
+ synchronized (mFeatures) {
+ MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
+ if (feature != null) {
+ feature.setUiTTYMode(uiTtyMode, onComplete);
+ }
+ }
+ }
+
+ @Override
+ public IImsMultiEndpoint getMultiEndpointInterface(int slotId, int featureType)
+ throws RemoteException {
+ enforceCallingOrSelfPermission(MODIFY_PHONE_STATE, "getMultiEndpointInterface");
+ synchronized (mFeatures) {
+ MMTelFeature feature = resolveMMTelFeature(slotId, featureType);
+ if (feature != null) {
+ return feature.getMultiEndpointInterface();
+ }
+ }
+ return null;
+ }
+
+ };
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ if(SERVICE_INTERFACE.equals(intent.getAction())) {
+ return mImsServiceController;
+ }
+ return null;
+ }
+
+ /**
+ * Called from the ImsResolver to create the requested ImsFeature, as defined by the slot and
+ * featureType
+ * @param slotId An integer representing which SIM slot the ImsFeature is assigned to.
+ * @param featureType An integer representing the type of ImsFeature being created. This is
+ * defined in {@link ImsFeature}.
+ */
+ // Be sure to lock on mFeatures before accessing this method
+ private void onCreateImsFeatureInternal(int slotId, int featureType,
+ IImsFeatureStatusCallback c) {
+ SparseArray<ImsFeature> featureMap = mFeatures.get(slotId);
+ if (featureMap == null) {
+ featureMap = new SparseArray<>();
+ mFeatures.put(slotId, featureMap);
+ }
+ ImsFeature f = makeImsFeature(slotId, featureType);
+ if (f != null) {
+ f.setContext(this);
+ f.setSlotId(slotId);
+ f.setImsFeatureStatusCallback(c);
+ featureMap.put(featureType, f);
+ }
+
+ }
+ /**
+ * Called from the ImsResolver to remove an existing ImsFeature, as defined by the slot and
+ * featureType.
+ * @param slotId An integer representing which SIM slot the ImsFeature is assigned to.
+ * @param featureType An integer representing the type of ImsFeature being removed. This is
+ * defined in {@link ImsFeature}.
+ */
+ // Be sure to lock on mFeatures before accessing this method
+ private void onRemoveImsFeatureInternal(int slotId, int featureType) {
+ SparseArray<ImsFeature> featureMap = mFeatures.get(slotId);
+ if (featureMap == null) {
+ return;
+ }
+
+ ImsFeature featureToRemove = getImsFeatureFromType(featureMap, featureType);
+ if (featureToRemove != null) {
+ featureMap.remove(featureType);
+ featureToRemove.notifyFeatureRemoved(slotId);
+ // Remove reference to Binder
+ featureToRemove.setImsFeatureStatusCallback(null);
+ }
+ }
+
+ // Be sure to lock on mFeatures before accessing this method
+ private MMTelFeature resolveMMTelFeature(int slotId, int featureType) {
+ SparseArray<ImsFeature> features = getImsFeatureMap(slotId);
+ MMTelFeature feature = null;
+ if (features != null) {
+ feature = resolveImsFeature(features, featureType, MMTelFeature.class);
+ }
+ return feature;
+ }
+
+ // Be sure to lock on mFeatures before accessing this method
+ private <T extends ImsFeature> T resolveImsFeature(SparseArray<ImsFeature> set, int featureType,
+ Class<T> className) {
+ ImsFeature feature = getImsFeatureFromType(set, featureType);
+ if (feature == null) {
+ return null;
+ }
+ try {
+ return className.cast(feature);
+ } catch (ClassCastException e)
+ {
+ Log.e(LOG_TAG, "Can not cast ImsFeature! Exception: " + e.getMessage());
+ }
+ return null;
+ }
+
+ @VisibleForTesting
+ // Be sure to lock on mFeatures before accessing this method
+ public SparseArray<ImsFeature> getImsFeatureMap(int slotId) {
+ return mFeatures.get(slotId);
+ }
+
+ @VisibleForTesting
+ // Be sure to lock on mFeatures before accessing this method
+ public ImsFeature getImsFeatureFromType(SparseArray<ImsFeature> set, int featureType) {
+ return set.get(featureType);
+ }
+
+ private ImsFeature makeImsFeature(int slotId, int feature) {
+ switch (feature) {
+ case ImsFeature.EMERGENCY_MMTEL: {
+ return onCreateEmergencyMMTelImsFeature(slotId);
+ }
+ case ImsFeature.MMTEL: {
+ return onCreateMMTelImsFeature(slotId);
+ }
+ case ImsFeature.RCS: {
+ return onCreateRcsFeature(slotId);
+ }
+ }
+ // Tried to create feature that is not defined.
+ return null;
+ }
+
+ /**
+ * Check for both READ_PHONE_STATE and READ_PRIVILEGED_PHONE_STATE. READ_PHONE_STATE is a
+ * public permission and READ_PRIVILEGED_PHONE_STATE is only granted to system apps.
+ */
+ private void enforceReadPhoneStatePermission(String fn) {
+ if (checkCallingOrSelfPermission(READ_PRIVILEGED_PHONE_STATE)
+ != PackageManager.PERMISSION_GRANTED) {
+ enforceCallingOrSelfPermission(READ_PHONE_STATE, fn);
+ }
+ }
+
+ /**
+ * @return An implementation of MMTelFeature that will be used by the system for MMTel
+ * functionality. Must be able to handle emergency calls at any time as well.
+ */
+ public abstract MMTelFeature onCreateEmergencyMMTelImsFeature(int slotId);
+
+ /**
+ * @return An implementation of MMTelFeature that will be used by the system for MMTel
+ * functionality.
+ */
+ public abstract MMTelFeature onCreateMMTelImsFeature(int slotId);
+
+ /**
+ * @return An implementation of RcsFeature that will be used by the system for RCS.
+ */
+ public abstract RcsFeature onCreateRcsFeature(int slotId);
+}
diff --git a/telephony/java/android/telephony/ims/ImsServiceBase.java b/telephony/java/android/telephony/ims/ImsServiceBase.java
index 0b50eca..0878db8 100644
--- a/telephony/java/android/telephony/ims/ImsServiceBase.java
+++ b/telephony/java/android/telephony/ims/ImsServiceBase.java
@@ -22,7 +22,9 @@
import android.os.IBinder;
/**
- * Base ImsService Implementation, which is used by the ImsResolver to bind.
+ * Base ImsService Implementation, which is used by the ImsResolver to bind. ImsServices that do not
+ * need to provide an ImsService implementation but still wish to be managed by the ImsResolver
+ * lifecycle may implement this class directly.
* @hide
*/
@SystemApi
diff --git a/telephony/java/android/telephony/ims/ImsServiceProxy.java b/telephony/java/android/telephony/ims/ImsServiceProxy.java
new file mode 100644
index 0000000..38ea6e6f
--- /dev/null
+++ b/telephony/java/android/telephony/ims/ImsServiceProxy.java
@@ -0,0 +1,313 @@
+/*
+ * 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.ims;
+
+import android.app.PendingIntent;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.RemoteException;
+import android.telephony.ims.feature.IRcsFeature;
+import android.telephony.ims.feature.ImsFeature;
+import android.util.Log;
+
+import com.android.ims.ImsCallProfile;
+import com.android.ims.internal.IImsCallSession;
+import com.android.ims.internal.IImsCallSessionListener;
+import com.android.ims.internal.IImsConfig;
+import com.android.ims.internal.IImsEcbm;
+import com.android.ims.internal.IImsMultiEndpoint;
+import com.android.ims.internal.IImsRegistrationListener;
+import com.android.ims.internal.IImsServiceController;
+import com.android.ims.internal.IImsServiceFeatureListener;
+import com.android.ims.internal.IImsUt;
+
+/**
+ * A container of the IImsServiceController binder, which implements all of the ImsFeatures that
+ * the platform currently supports: MMTel and RCS.
+ * @hide
+ */
+
+public class ImsServiceProxy extends ImsServiceProxyCompat implements IRcsFeature {
+
+ protected String LOG_TAG = "ImsServiceProxy";
+ private final int mSupportedFeature;
+
+ // Start by assuming the proxy is available for usage.
+ private boolean mIsAvailable = true;
+ // ImsFeature Status from the ImsService. Cached.
+ private Integer mFeatureStatusCached = null;
+ private ImsServiceProxy.INotifyStatusChanged mStatusCallback;
+ private final Object mLock = new Object();
+
+ public interface INotifyStatusChanged {
+ void notifyStatusChanged();
+ }
+
+ private final IImsServiceFeatureListener mListenerBinder =
+ new IImsServiceFeatureListener.Stub() {
+
+ @Override
+ public void imsFeatureCreated(int slotId, int feature) throws RemoteException {
+ // The feature has been re-enabled. This may happen when the service crashes.
+ synchronized (mLock) {
+ if (!mIsAvailable && mSlotId == slotId && feature == mSupportedFeature) {
+ Log.i(LOG_TAG, "Feature enabled on slotId: " + slotId + " for feature: " +
+ feature);
+ mIsAvailable = true;
+ }
+ }
+ }
+
+ @Override
+ public void imsFeatureRemoved(int slotId, int feature) throws RemoteException {
+ synchronized (mLock) {
+ if (mIsAvailable && mSlotId == slotId && feature == mSupportedFeature) {
+ Log.i(LOG_TAG, "Feature disabled on slotId: " + slotId + " for feature: " +
+ feature);
+ mIsAvailable = false;
+ }
+ }
+ }
+
+ @Override
+ public void imsStatusChanged(int slotId, int feature, int status) throws RemoteException {
+ synchronized (mLock) {
+ Log.i(LOG_TAG, "imsStatusChanged: slot: " + slotId + " feature: " + feature +
+ " status: " + status);
+ if (mSlotId == slotId && feature == mSupportedFeature) {
+ mFeatureStatusCached = status;
+ }
+ }
+ if (mStatusCallback != null) {
+ mStatusCallback.notifyStatusChanged();
+ }
+ }
+ };
+
+ public ImsServiceProxy(int slotId, IBinder binder, int featureType) {
+ super(slotId, binder);
+ mSupportedFeature = featureType;
+ }
+
+ public ImsServiceProxy(int slotId, int featureType) {
+ super(slotId, null /*IBinder*/);
+ mSupportedFeature = featureType;
+ }
+
+ public IImsServiceFeatureListener getListener() {
+ return mListenerBinder;
+ }
+
+ public void setBinder(IBinder binder) {
+ mBinder = binder;
+ }
+
+ @Override
+ public int startSession(PendingIntent incomingCallIntent, IImsRegistrationListener listener)
+ throws RemoteException {
+ synchronized (mLock) {
+ checkBinderConnection();
+ return getServiceInterface(mBinder).startSession(mSlotId, mSupportedFeature,
+ incomingCallIntent, listener);
+ }
+ }
+
+ @Override
+ public void endSession(int sessionId) throws RemoteException {
+ synchronized (mLock) {
+ checkBinderConnection();
+ getServiceInterface(mBinder).endSession(mSlotId, mSupportedFeature, sessionId);
+ }
+ }
+
+ @Override
+ public boolean isConnected(int callServiceType, int callType)
+ throws RemoteException {
+ synchronized (mLock) {
+ checkBinderConnection();
+ return getServiceInterface(mBinder).isConnected(mSlotId, mSupportedFeature,
+ callServiceType, callType);
+ }
+ }
+
+ @Override
+ public boolean isOpened() throws RemoteException {
+ synchronized (mLock) {
+ checkBinderConnection();
+ return getServiceInterface(mBinder).isOpened(mSlotId, mSupportedFeature);
+ }
+ }
+
+ @Override
+ public void addRegistrationListener(IImsRegistrationListener listener)
+ throws RemoteException {
+ synchronized (mLock) {
+ checkBinderConnection();
+ getServiceInterface(mBinder).addRegistrationListener(mSlotId, mSupportedFeature,
+ listener);
+ }
+ }
+
+ @Override
+ public void removeRegistrationListener(IImsRegistrationListener listener)
+ throws RemoteException {
+ synchronized (mLock) {
+ checkBinderConnection();
+ getServiceInterface(mBinder).removeRegistrationListener(mSlotId, mSupportedFeature,
+ listener);
+ }
+ }
+
+ @Override
+ public ImsCallProfile createCallProfile(int sessionId, int callServiceType, int callType)
+ throws RemoteException {
+ synchronized (mLock) {
+ checkBinderConnection();
+ return getServiceInterface(mBinder).createCallProfile(mSlotId, mSupportedFeature,
+ sessionId, callServiceType, callType);
+ }
+ }
+
+ @Override
+ public IImsCallSession createCallSession(int sessionId, ImsCallProfile profile,
+ IImsCallSessionListener listener) throws RemoteException {
+ synchronized (mLock) {
+ checkBinderConnection();
+ return getServiceInterface(mBinder).createCallSession(mSlotId, mSupportedFeature,
+ sessionId, profile, listener);
+ }
+ }
+
+ @Override
+ public IImsCallSession getPendingCallSession(int sessionId, String callId)
+ throws RemoteException {
+ synchronized (mLock) {
+ checkBinderConnection();
+ return getServiceInterface(mBinder).getPendingCallSession(mSlotId, mSupportedFeature,
+ sessionId, callId);
+ }
+ }
+
+ @Override
+ public IImsUt getUtInterface() throws RemoteException {
+ synchronized (mLock) {
+ checkBinderConnection();
+ return getServiceInterface(mBinder).getUtInterface(mSlotId, mSupportedFeature);
+ }
+ }
+
+ @Override
+ public IImsConfig getConfigInterface() throws RemoteException {
+ synchronized (mLock) {
+ checkBinderConnection();
+ return getServiceInterface(mBinder).getConfigInterface(mSlotId, mSupportedFeature);
+ }
+ }
+
+ @Override
+ public void turnOnIms() throws RemoteException {
+ synchronized (mLock) {
+ checkBinderConnection();
+ getServiceInterface(mBinder).turnOnIms(mSlotId, mSupportedFeature);
+ }
+ }
+
+ @Override
+ public void turnOffIms() throws RemoteException {
+ synchronized (mLock) {
+ checkBinderConnection();
+ getServiceInterface(mBinder).turnOffIms(mSlotId, mSupportedFeature);
+ }
+ }
+
+ @Override
+ public IImsEcbm getEcbmInterface() throws RemoteException {
+ synchronized (mLock) {
+ checkBinderConnection();
+ return getServiceInterface(mBinder).getEcbmInterface(mSlotId, mSupportedFeature);
+ }
+ }
+
+ @Override
+ public void setUiTTYMode(int uiTtyMode, Message onComplete)
+ throws RemoteException {
+ synchronized (mLock) {
+ checkBinderConnection();
+ getServiceInterface(mBinder).setUiTTYMode(mSlotId, mSupportedFeature, uiTtyMode,
+ onComplete);
+ }
+ }
+
+ @Override
+ public IImsMultiEndpoint getMultiEndpointInterface() throws RemoteException {
+ synchronized (mLock) {
+ checkBinderConnection();
+ return getServiceInterface(mBinder).getMultiEndpointInterface(mSlotId,
+ mSupportedFeature);
+ }
+ }
+
+ @Override
+ public int getFeatureStatus() {
+ synchronized (mLock) {
+ if (mFeatureStatusCached != null) {
+ return mFeatureStatusCached;
+ }
+ }
+ // Don't synchronize on Binder call.
+ Integer status = retrieveFeatureStatus();
+ synchronized (mLock) {
+ if (status == null) {
+ return ImsFeature.STATE_NOT_AVAILABLE;
+ }
+ // Cache only non-null value for feature status.
+ mFeatureStatusCached = status;
+ }
+ return status;
+ }
+
+ /**
+ * Internal method used to retrieve the feature status from the corresponding ImsService.
+ */
+ private Integer retrieveFeatureStatus() {
+ if (mBinder != null) {
+ try {
+ return getServiceInterface(mBinder).getFeatureStatus(mSlotId, mSupportedFeature);
+ } catch (RemoteException e) {
+ // Status check failed, don't update cache
+ }
+ }
+ return null;
+ }
+
+ /**
+ * @param c Callback that will fire when the feature status has changed.
+ */
+ public void setStatusCallback(INotifyStatusChanged c) {
+ mStatusCallback = c;
+ }
+
+ @Override
+ public boolean isBinderAlive() {
+ return mIsAvailable && getFeatureStatus() == ImsFeature.STATE_READY && mBinder != null &&
+ mBinder.isBinderAlive();
+ }
+
+ private IImsServiceController getServiceInterface(IBinder b) {
+ return IImsServiceController.Stub.asInterface(b);
+ }
+}
diff --git a/telephony/java/android/telephony/ims/ImsServiceProxyCompat.java b/telephony/java/android/telephony/ims/ImsServiceProxyCompat.java
new file mode 100644
index 0000000..bbd5f02
--- /dev/null
+++ b/telephony/java/android/telephony/ims/ImsServiceProxyCompat.java
@@ -0,0 +1,183 @@
+/*
+ * 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.ims;
+
+import android.app.PendingIntent;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.RemoteException;
+import android.telephony.ims.feature.IMMTelFeature;
+import android.telephony.ims.feature.ImsFeature;
+
+import com.android.ims.ImsCallProfile;
+import com.android.ims.internal.IImsCallSession;
+import com.android.ims.internal.IImsCallSessionListener;
+import com.android.ims.internal.IImsConfig;
+import com.android.ims.internal.IImsEcbm;
+import com.android.ims.internal.IImsMultiEndpoint;
+import com.android.ims.internal.IImsRegistrationListener;
+import com.android.ims.internal.IImsService;
+import com.android.ims.internal.IImsUt;
+
+/**
+ * Compatibility class that implements the new ImsService IMMTelFeature interface, but
+ * uses the old IImsService interface to support older devices that implement the deprecated
+ * opt/net/ims interface.
+ * @hide
+ */
+
+public class ImsServiceProxyCompat implements IMMTelFeature {
+
+ private static final int SERVICE_ID = ImsFeature.MMTEL;
+
+ protected final int mSlotId;
+ protected IBinder mBinder;
+
+ public ImsServiceProxyCompat(int slotId, IBinder binder) {
+ mSlotId = slotId;
+ mBinder = binder;
+ }
+
+ @Override
+ public int startSession(PendingIntent incomingCallIntent, IImsRegistrationListener listener)
+ throws RemoteException {
+ checkBinderConnection();
+ return getServiceInterface(mBinder).open(mSlotId, ImsFeature.MMTEL, incomingCallIntent,
+ listener);
+ }
+
+ @Override
+ public void endSession(int sessionId) throws RemoteException {
+ checkBinderConnection();
+ getServiceInterface(mBinder).close(sessionId);
+ }
+
+ @Override
+ public boolean isConnected(int callServiceType, int callType)
+ throws RemoteException {
+ checkBinderConnection();
+ return getServiceInterface(mBinder).isConnected(SERVICE_ID, callServiceType, callType);
+ }
+
+ @Override
+ public boolean isOpened() throws RemoteException {
+ checkBinderConnection();
+ return getServiceInterface(mBinder).isOpened(SERVICE_ID);
+ }
+
+ @Override
+ public void addRegistrationListener(IImsRegistrationListener listener)
+ throws RemoteException {
+ checkBinderConnection();
+ getServiceInterface(mBinder).addRegistrationListener(mSlotId, ImsFeature.MMTEL, listener);
+ }
+
+ @Override
+ public void removeRegistrationListener(IImsRegistrationListener listener)
+ throws RemoteException {
+ // Not Implemented in old ImsService. If the registration listener becomes invalid, the
+ // ImsService will remove.
+ }
+
+ @Override
+ public ImsCallProfile createCallProfile(int sessionId, int callServiceType, int callType)
+ throws RemoteException {
+ checkBinderConnection();
+ return getServiceInterface(mBinder).createCallProfile(sessionId, callServiceType, callType);
+ }
+
+ @Override
+ public IImsCallSession createCallSession(int sessionId, ImsCallProfile profile,
+ IImsCallSessionListener listener) throws RemoteException {
+ checkBinderConnection();
+ return getServiceInterface(mBinder).createCallSession(sessionId, profile, listener);
+ }
+
+ @Override
+ public IImsCallSession getPendingCallSession(int sessionId, String callId)
+ throws RemoteException {
+ checkBinderConnection();
+ return getServiceInterface(mBinder).getPendingCallSession(sessionId, callId);
+ }
+
+ @Override
+ public IImsUt getUtInterface() throws RemoteException {
+ checkBinderConnection();
+ return getServiceInterface(mBinder).getUtInterface(SERVICE_ID);
+ }
+
+ @Override
+ public IImsConfig getConfigInterface() throws RemoteException {
+ checkBinderConnection();
+ return getServiceInterface(mBinder).getConfigInterface(mSlotId);
+ }
+
+ @Override
+ public void turnOnIms() throws RemoteException {
+ checkBinderConnection();
+ getServiceInterface(mBinder).turnOnIms(mSlotId);
+ }
+
+ @Override
+ public void turnOffIms() throws RemoteException {
+ checkBinderConnection();
+ getServiceInterface(mBinder).turnOffIms(mSlotId);
+ }
+
+ @Override
+ public IImsEcbm getEcbmInterface() throws RemoteException {
+ checkBinderConnection();
+ return getServiceInterface(mBinder).getEcbmInterface(SERVICE_ID);
+ }
+
+ @Override
+ public void setUiTTYMode(int uiTtyMode, Message onComplete)
+ throws RemoteException {
+ checkBinderConnection();
+ getServiceInterface(mBinder).setUiTTYMode(SERVICE_ID, uiTtyMode, onComplete);
+ }
+
+ @Override
+ public IImsMultiEndpoint getMultiEndpointInterface() throws RemoteException {
+ checkBinderConnection();
+ return getServiceInterface(mBinder).getMultiEndpointInterface(SERVICE_ID);
+ }
+
+ /**
+ * Base implementation, always returns READY for compatibility with old ImsService.
+ */
+ public int getFeatureStatus() {
+ return ImsFeature.STATE_READY;
+ }
+
+ /**
+ * @return false if the binder connection is no longer alive.
+ */
+ public boolean isBinderAlive() {
+ return mBinder != null && mBinder.isBinderAlive();
+ }
+
+ private IImsService getServiceInterface(IBinder b) {
+ return IImsService.Stub.asInterface(b);
+ }
+
+ protected void checkBinderConnection() throws RemoteException {
+ if (!isBinderAlive()) {
+ throw new RemoteException("ImsServiceProxy is not available for that feature.");
+ }
+ }
+}
diff --git a/telephony/java/android/telephony/ims/feature/IMMTelFeature.java b/telephony/java/android/telephony/ims/feature/IMMTelFeature.java
new file mode 100644
index 0000000..d65e27e
--- /dev/null
+++ b/telephony/java/android/telephony/ims/feature/IMMTelFeature.java
@@ -0,0 +1,187 @@
+/*
+ * 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.ims.feature;
+
+import android.app.PendingIntent;
+import android.os.Message;
+import android.os.RemoteException;
+
+import com.android.ims.ImsCallProfile;
+import com.android.ims.internal.IImsCallSession;
+import com.android.ims.internal.IImsCallSessionListener;
+import com.android.ims.internal.IImsConfig;
+import com.android.ims.internal.IImsEcbm;
+import com.android.ims.internal.IImsMultiEndpoint;
+import com.android.ims.internal.IImsRegistrationListener;
+import com.android.ims.internal.IImsUt;
+
+/**
+ * MMTel interface for an ImsService. When updating this interface, ensure that base implementations
+ * of your changes are also present in MMTelFeature for compatibility with older versions of the
+ * MMTel feature.
+ * @hide
+ */
+
+public interface IMMTelFeature {
+
+ /**
+ * Notifies the MMTel feature that you would like to start a session. This should always be
+ * done before making/receiving IMS calls. The IMS service will register the device to the
+ * operator's network with the credentials (from ISIM) periodically in order to receive calls
+ * from the operator's network. When the IMS service receives a new call, it will send out an
+ * intent with the provided action string. The intent contains a call ID extra
+ * {@link IImsCallSession#getCallId} and it can be used to take a call.
+ *
+ * @param incomingCallIntent When an incoming call is received, the IMS service will call
+ * {@link PendingIntent#send} to send back the intent to the caller with
+ * {@link #INCOMING_CALL_RESULT_CODE} as the result code and the intent to fill in the call ID;
+ * It cannot be null.
+ * @param listener To listen to IMS registration events; It cannot be null
+ * @return an integer (greater than 0) representing the session id associated with the session
+ * that has been started.
+ */
+ int startSession(PendingIntent incomingCallIntent, IImsRegistrationListener listener)
+ throws RemoteException;
+
+ /**
+ * End a previously started session using the associated sessionId.
+ * @param sessionId an integer (greater than 0) representing the ongoing session. See
+ * {@link #startSession}.
+ */
+ void endSession(int sessionId) throws RemoteException;
+
+ /**
+ * Checks if the IMS service has successfully registered to the IMS network with the specified
+ * service & call type.
+ *
+ * @param callServiceType a service type that is specified in {@link ImsCallProfile}
+ * {@link ImsCallProfile#SERVICE_TYPE_NORMAL}
+ * {@link ImsCallProfile#SERVICE_TYPE_EMERGENCY}
+ * @param callType a call type that is specified in {@link ImsCallProfile}
+ * {@link ImsCallProfile#CALL_TYPE_VOICE_N_VIDEO}
+ * {@link ImsCallProfile#CALL_TYPE_VOICE}
+ * {@link ImsCallProfile#CALL_TYPE_VT}
+ * {@link ImsCallProfile#CALL_TYPE_VS}
+ * @return true if the specified service id is connected to the IMS network; false otherwise
+ * @throws RemoteException
+ */
+ boolean isConnected(int callServiceType, int callType) throws RemoteException;
+
+ /**
+ * Checks if the specified IMS service is opened.
+ *
+ * @return true if the specified service id is opened; false otherwise
+ */
+ boolean isOpened() throws RemoteException;
+
+ /**
+ * Add a new registration listener for the client associated with the session Id.
+ * @param listener An implementation of IImsRegistrationListener.
+ */
+ void addRegistrationListener(IImsRegistrationListener listener)
+ throws RemoteException;
+
+ /**
+ * Remove a previously registered listener using {@link #addRegistrationListener} for the client
+ * associated with the session Id.
+ * @param listener A previously registered IImsRegistrationListener
+ */
+ void removeRegistrationListener(IImsRegistrationListener listener)
+ throws RemoteException;
+
+ /**
+ * Creates a {@link ImsCallProfile} from the service capabilities & IMS registration state.
+ *
+ * @param sessionId a session id which is obtained from {@link #startSession}
+ * @param callServiceType a service type that is specified in {@link ImsCallProfile}
+ * {@link ImsCallProfile#SERVICE_TYPE_NONE}
+ * {@link ImsCallProfile#SERVICE_TYPE_NORMAL}
+ * {@link ImsCallProfile#SERVICE_TYPE_EMERGENCY}
+ * @param callType a call type that is specified in {@link ImsCallProfile}
+ * {@link ImsCallProfile#CALL_TYPE_VOICE}
+ * {@link ImsCallProfile#CALL_TYPE_VT}
+ * {@link ImsCallProfile#CALL_TYPE_VT_TX}
+ * {@link ImsCallProfile#CALL_TYPE_VT_RX}
+ * {@link ImsCallProfile#CALL_TYPE_VT_NODIR}
+ * {@link ImsCallProfile#CALL_TYPE_VS}
+ * {@link ImsCallProfile#CALL_TYPE_VS_TX}
+ * {@link ImsCallProfile#CALL_TYPE_VS_RX}
+ * @return a {@link ImsCallProfile} object
+ */
+ ImsCallProfile createCallProfile(int sessionId, int callServiceType, int callType)
+ throws RemoteException;
+
+ /**
+ * Creates a {@link ImsCallSession} with the specified call profile.
+ * Use other methods, if applicable, instead of interacting with
+ * {@link ImsCallSession} directly.
+ *
+ * @param sessionId a session id which is obtained from {@link #startSession}
+ * @param profile a call profile to make the call
+ * @param listener An implementation of IImsCallSessionListener.
+ */
+ IImsCallSession createCallSession(int sessionId, ImsCallProfile profile,
+ IImsCallSessionListener listener) throws RemoteException;
+
+ /**
+ * Retrieves the call session associated with a pending call.
+ *
+ * @param sessionId a session id which is obtained from {@link #startSession}
+ * @param callId a call id to make the call
+ */
+ IImsCallSession getPendingCallSession(int sessionId, String callId) throws RemoteException;
+
+ /**
+ * @return The Ut interface for the supplementary service configuration.
+ */
+ IImsUt getUtInterface() throws RemoteException;
+
+ /**
+ * @return The config interface for IMS Configuration
+ */
+ IImsConfig getConfigInterface() throws RemoteException;
+
+ /**
+ * Signal the MMTelFeature to turn on IMS when it has been turned off using {@link #turnOffIms}
+ * @param sessionId a session id which is obtained from {@link #startSession}
+ */
+ void turnOnIms() throws RemoteException;
+
+ /**
+ * Signal the MMTelFeature to turn off IMS when it has been turned on using {@link #turnOnIms}
+ * @param sessionId a session id which is obtained from {@link #startSession}
+ */
+ void turnOffIms() throws RemoteException;
+
+ /**
+ * @return The Emergency call-back mode interface for emergency VoLTE calls that support it.
+ */
+ IImsEcbm getEcbmInterface() throws RemoteException;
+
+ /**
+ * Sets the current UI TTY mode for the MMTelFeature.
+ * @param uiTtyMode An integer containing the new UI TTY Mode.
+ * @param onComplete A {@link Message} to be used when the mode has been set.
+ * @throws RemoteException
+ */
+ void setUiTTYMode(int uiTtyMode, Message onComplete) throws RemoteException;
+
+ /**
+ * @return MultiEndpoint interface for DEP notifications
+ */
+ IImsMultiEndpoint getMultiEndpointInterface() throws RemoteException;
+}
diff --git a/telephony/java/android/telephony/ims/feature/IRcsFeature.java b/telephony/java/android/telephony/ims/feature/IRcsFeature.java
new file mode 100644
index 0000000..e28e1b3
--- /dev/null
+++ b/telephony/java/android/telephony/ims/feature/IRcsFeature.java
@@ -0,0 +1,26 @@
+/*
+ * 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.ims.feature;
+
+/**
+ * Feature interface that provides access to RCS APIs. Currently empty until RCS support is added
+ * in the framework.
+ * @hide
+ */
+
+public interface IRcsFeature {
+}
diff --git a/telephony/java/android/telephony/ims/feature/ImsFeature.java b/telephony/java/android/telephony/ims/feature/ImsFeature.java
index 0509d60..988dd58 100644
--- a/telephony/java/android/telephony/ims/feature/ImsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/ImsFeature.java
@@ -16,18 +16,175 @@
package android.telephony.ims.feature;
+import android.annotation.IntDef;
+import android.content.Context;
+import android.content.Intent;
+import android.os.RemoteException;
+import android.telephony.SubscriptionManager;
+import android.util.Log;
+
+import com.android.ims.internal.IImsFeatureStatusCallback;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
+
/**
* Base class for all IMS features that are supported by the framework.
* @hide
*/
-public class ImsFeature {
+public abstract class ImsFeature {
+
+ private static final String LOG_TAG = "ImsFeature";
+
+ /**
+ * Action to broadcast when ImsService is up.
+ * Internal use only.
+ * Only defined here separately compatibility purposes with the old ImsService.
+ * @hide
+ */
+ public static final String ACTION_IMS_SERVICE_UP =
+ "com.android.ims.IMS_SERVICE_UP";
+
+ /**
+ * Action to broadcast when ImsService is down.
+ * Internal use only.
+ * Only defined here separately for compatibility purposes with the old ImsService.
+ * @hide
+ */
+ public static final String ACTION_IMS_SERVICE_DOWN =
+ "com.android.ims.IMS_SERVICE_DOWN";
+
+ /**
+ * Part of the ACTION_IMS_SERVICE_UP or _DOWN intents.
+ * A long value; the phone ID corresponding to the IMS service coming up or down.
+ * Only defined here separately for compatibility purposes with the old ImsService.
+ * @hide
+ */
+ public static final String EXTRA_PHONE_ID = "android:phone_id";
// Invalid feature value
public static final int INVALID = -1;
- // ImsFeatures that are defined in the Manifests
+ // ImsFeatures that are defined in the Manifests. Ensure that these values match the previously
+ // defined values in ImsServiceClass for compatibility purposes.
public static final int EMERGENCY_MMTEL = 0;
public static final int MMTEL = 1;
public static final int RCS = 2;
// Total number of features defined
public static final int MAX = 3;
+
+ // Integer values defining the state of the ImsFeature at any time.
+ @IntDef(flag = true,
+ value = {
+ STATE_NOT_AVAILABLE,
+ STATE_INITIALIZING,
+ STATE_READY,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ImsState {}
+ public static final int STATE_NOT_AVAILABLE = 0;
+ public static final int STATE_INITIALIZING = 1;
+ public static final int STATE_READY = 2;
+
+ private List<INotifyFeatureRemoved> mRemovedListeners = new ArrayList<>();
+ private IImsFeatureStatusCallback mStatusCallback;
+ private @ImsState int mState = STATE_NOT_AVAILABLE;
+ private int mSlotId = SubscriptionManager.INVALID_SIM_SLOT_INDEX;
+ private Context mContext;
+
+ public interface INotifyFeatureRemoved {
+ void onFeatureRemoved(int slotId);
+ }
+
+ public void setContext(Context context) {
+ mContext = context;
+ }
+
+ public void setSlotId(int slotId) {
+ mSlotId = slotId;
+ }
+
+ public void addFeatureRemovedListener(INotifyFeatureRemoved listener) {
+ synchronized (mRemovedListeners) {
+ mRemovedListeners.add(listener);
+ }
+ }
+
+ public void removeFeatureRemovedListener(INotifyFeatureRemoved listener) {
+ synchronized (mRemovedListeners) {
+ mRemovedListeners.remove(listener);
+ }
+ }
+
+ // Not final for testing.
+ public void notifyFeatureRemoved(int slotId) {
+ synchronized (mRemovedListeners) {
+ mRemovedListeners.forEach(l -> l.onFeatureRemoved(slotId));
+ onFeatureRemoved();
+ }
+ }
+
+ public int getFeatureState() {
+ return mState;
+ }
+
+ protected final void setFeatureState(@ImsState int state) {
+ if (mState != state) {
+ mState = state;
+ notifyFeatureState(state);
+ }
+ }
+
+ // Not final for testing.
+ public void setImsFeatureStatusCallback(IImsFeatureStatusCallback c) {
+ mStatusCallback = c;
+ // If we have just connected, send queued status.
+ notifyFeatureState(mState);
+ }
+
+ /**
+ * Internal method called by ImsFeature when setFeatureState has changed.
+ * @param state
+ */
+ private void notifyFeatureState(@ImsState int state) {
+ if (mStatusCallback != null) {
+ try {
+ Log.i(LOG_TAG, "notifying ImsFeatureState");
+ mStatusCallback.notifyImsFeatureStatus(state);
+ } catch (RemoteException e) {
+ mStatusCallback = null;
+ Log.w(LOG_TAG, "Couldn't notify feature state: " + e.getMessage());
+ }
+ }
+ sendImsServiceIntent(state);
+ }
+
+ /**
+ * Provide backwards compatibility using deprecated service UP/DOWN intents.
+ */
+ private void sendImsServiceIntent(@ImsState int state) {
+ if(mContext == null || mSlotId == SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
+ return;
+ }
+ Intent intent;
+ switch (state) {
+ case ImsFeature.STATE_NOT_AVAILABLE:
+ case ImsFeature.STATE_INITIALIZING:
+ intent = new Intent(ACTION_IMS_SERVICE_DOWN);
+ break;
+ case ImsFeature.STATE_READY:
+ intent = new Intent(ACTION_IMS_SERVICE_UP);
+ break;
+ default:
+ intent = new Intent(ACTION_IMS_SERVICE_DOWN);
+ }
+ intent.putExtra(EXTRA_PHONE_ID, mSlotId);
+ mContext.sendBroadcast(intent);
+ }
+
+ /**
+ * Called when the feature is being removed and must be cleaned up.
+ */
+ public abstract void onFeatureRemoved();
}
diff --git a/telephony/java/android/telephony/ims/feature/MMTelFeature.java b/telephony/java/android/telephony/ims/feature/MMTelFeature.java
new file mode 100644
index 0000000..a71f0bf
--- /dev/null
+++ b/telephony/java/android/telephony/ims/feature/MMTelFeature.java
@@ -0,0 +1,122 @@
+/*
+ * 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.ims.feature;
+
+import android.app.PendingIntent;
+import android.os.Message;
+
+import com.android.ims.ImsCallProfile;
+import com.android.ims.internal.IImsCallSession;
+import com.android.ims.internal.IImsCallSessionListener;
+import com.android.ims.internal.IImsConfig;
+import com.android.ims.internal.IImsEcbm;
+import com.android.ims.internal.IImsMultiEndpoint;
+import com.android.ims.internal.IImsRegistrationListener;
+import com.android.ims.internal.IImsUt;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Base implementation, which implements all methods in IMMTelFeature. Any class wishing to use
+ * MMTelFeature should extend this class and implement all methods that the service supports.
+ *
+ * @hide
+ */
+
+public class MMTelFeature extends ImsFeature implements IMMTelFeature {
+
+ @Override
+ public int startSession(PendingIntent incomingCallIntent, IImsRegistrationListener listener) {
+ return 0;
+ }
+
+ @Override
+ public void endSession(int sessionId) {
+ }
+
+ @Override
+ public boolean isConnected(int callSessionType, int callType) {
+ return false;
+ }
+
+ @Override
+ public boolean isOpened() {
+ return false;
+ }
+
+ @Override
+ public void addRegistrationListener(IImsRegistrationListener listener) {
+ }
+
+ @Override
+ public void removeRegistrationListener(IImsRegistrationListener listener) {
+ }
+
+ @Override
+ public ImsCallProfile createCallProfile(int sessionId, int callSessionType, int callType) {
+ return null;
+ }
+
+ @Override
+ public IImsCallSession createCallSession(int sessionId, ImsCallProfile profile,
+ IImsCallSessionListener listener) {
+ return null;
+ }
+
+ @Override
+ public IImsCallSession getPendingCallSession(int sessionId, String callId) {
+ return null;
+ }
+
+ @Override
+ public IImsUt getUtInterface() {
+ return null;
+ }
+
+ @Override
+ public IImsConfig getConfigInterface() {
+ return null;
+ }
+
+ @Override
+ public void turnOnIms() {
+ }
+
+ @Override
+ public void turnOffIms() {
+ }
+
+ @Override
+ public IImsEcbm getEcbmInterface() {
+ return null;
+ }
+
+ @Override
+ public void setUiTTYMode(int uiTtyMode, Message onComplete) {
+ }
+
+ @Override
+ public IImsMultiEndpoint getMultiEndpointInterface() {
+ return null;
+ }
+
+ @Override
+ public void onFeatureRemoved() {
+
+ }
+}
diff --git a/telephony/java/android/telephony/ims/feature/RcsFeature.java b/telephony/java/android/telephony/ims/feature/RcsFeature.java
new file mode 100644
index 0000000..9cddc1b
--- /dev/null
+++ b/telephony/java/android/telephony/ims/feature/RcsFeature.java
@@ -0,0 +1,35 @@
+/*
+ * 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.ims.feature;
+
+/**
+ * Base implementation of the RcsFeature APIs. Any ImsService wishing to support RCS should extend
+ * this class and provide implementations of the IRcsFeature methods that they support.
+ * @hide
+ */
+
+public class RcsFeature extends ImsFeature implements IRcsFeature {
+
+ public RcsFeature() {
+ super();
+ }
+
+ @Override
+ public void onFeatureRemoved() {
+
+ }
+}
diff --git a/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java b/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java
new file mode 100644
index 0000000..69b8acc
--- /dev/null
+++ b/telephony/java/android/telephony/ims/stub/ImsCallSessionImplBase.java
@@ -0,0 +1,348 @@
+/*
+ * 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.ims.stub;
+
+import android.os.Message;
+import android.os.RemoteException;
+
+import com.android.ims.ImsCallProfile;
+import com.android.ims.ImsStreamMediaProfile;
+import com.android.ims.internal.ImsCallSession;
+import com.android.ims.internal.IImsCallSession;
+import com.android.ims.internal.IImsCallSessionListener;
+import com.android.ims.internal.IImsVideoCallProvider;
+
+/**
+ * Base implementation of IImsCallSession, which implements stub versions of the methods in the
+ * IImsCallSession AIDL. Override the methods that your implementation of ImsCallSession supports.
+ *
+ * DO NOT remove or change the existing APIs, only add new ones to this Base implementation or you
+ * will break other implementations of ImsCallSession maintained by other ImsServices.
+ *
+ * @hide
+ */
+
+public class ImsCallSessionImplBase extends IImsCallSession.Stub {
+
+ /**
+ * Closes the object. This object is not usable after being closed.
+ */
+ @Override
+ public void close() throws RemoteException {
+
+ }
+
+ /**
+ * Gets the call ID of the session.
+ *
+ * @return the call ID
+ */
+ @Override
+ public String getCallId() throws RemoteException {
+ return null;
+ }
+
+ /**
+ * Gets the call profile that this session is associated with
+ *
+ * @return the {@link ImsCallProfile} that this session is associated with
+ */
+ @Override
+ public ImsCallProfile getCallProfile() throws RemoteException {
+ return null;
+ }
+
+ /**
+ * Gets the local call profile that this session is associated with
+ *
+ * @return the local {@link ImsCallProfile} that this session is associated with
+ */
+ @Override
+ public ImsCallProfile getLocalCallProfile() throws RemoteException {
+ return null;
+ }
+
+ /**
+ * Gets the remote call profile that this session is associated with
+ *
+ * @return the remote {@link ImsCallProfile} that this session is associated with
+ */
+ @Override
+ public ImsCallProfile getRemoteCallProfile() throws RemoteException {
+ return null;
+ }
+
+ /**
+ * Gets the value associated with the specified property of this session.
+ *
+ * @return the string value associated with the specified property
+ */
+ @Override
+ public String getProperty(String name) throws RemoteException {
+ return null;
+ }
+
+ /**
+ * Gets the session state.
+ * The value returned must be one of the states in {@link ImsCallSession.State}.
+ *
+ * @return the session state
+ */
+ @Override
+ public int getState() throws RemoteException {
+ return ImsCallSession.State.INVALID;
+ }
+
+ /**
+ * Checks if the session is in call.
+ *
+ * @return true if the session is in call, false otherwise
+ */
+ @Override
+ public boolean isInCall() throws RemoteException {
+ return false;
+ }
+
+ /**
+ * Sets the listener to listen to the session events. An {@link ImsCallSession}
+ * can only hold one listener at a time. Subsequent calls to this method
+ * override the previous listener.
+ *
+ * @param listener to listen to the session events of this object
+ */
+ @Override
+ public void setListener(IImsCallSessionListener listener) throws RemoteException {
+ }
+
+ /**
+ * Mutes or unmutes the mic for the active call.
+ *
+ * @param muted true if the call is muted, false otherwise
+ */
+ @Override
+ public void setMute(boolean muted) throws RemoteException {
+ }
+
+ /**
+ * Initiates an IMS call with the specified target and call profile.
+ * The session listener set in {@link #setListener} is called back upon defined session events.
+ * The method is only valid to call when the session state is in
+ * {@link ImsCallSession.State#IDLE}.
+ *
+ * @param callee dialed string to make the call to
+ * @param profile call profile to make the call with the specified service type,
+ * call type and media information
+ * @see {@link ImsCallSession.Listener#callSessionStarted},
+ * {@link ImsCallSession.Listener#callSessionStartFailed}
+ */
+ @Override
+ public void start(String callee, ImsCallProfile profile) throws RemoteException {
+ }
+
+ /**
+ * Initiates an IMS call with the specified participants and call profile.
+ * The session listener set in {@link #setListener} is called back upon defined session events.
+ * The method is only valid to call when the session state is in
+ * {@link ImsCallSession.State#IDLE}.
+ *
+ * @param participants participant list to initiate an IMS conference call
+ * @param profile call profile to make the call with the specified service type,
+ * call type and media information
+ * @see {@link ImsCallSession.Listener#callSessionStarted},
+ * {@link ImsCallSession.Listener#callSessionStartFailed}
+ */
+ @Override
+ public void startConference(String[] participants, ImsCallProfile profile)
+ throws RemoteException {
+ }
+
+ /**
+ * Accepts an incoming call or session update.
+ *
+ * @param callType call type specified in {@link ImsCallProfile} to be answered
+ * @param profile stream media profile {@link ImsStreamMediaProfile} to be answered
+ * @see {@link ImsCallSession.Listener#callSessionStarted}
+ */
+ @Override
+ public void accept(int callType, ImsStreamMediaProfile profile) throws RemoteException {
+ }
+
+ /**
+ * Rejects an incoming call or session update.
+ *
+ * @param reason reason code to reject an incoming call, defined in
+ * com.android.ims.ImsReasonInfo
+ * {@link ImsCallSession.Listener#callSessionStartFailed}
+ */
+ @Override
+ public void reject(int reason) throws RemoteException {
+ }
+
+ /**
+ * Terminates a call.
+ *
+ * @param reason reason code to terminate a call, defined in
+ * com.android.ims.ImsReasonInfo
+ *
+ * @see {@link ImsCallSession.Listener#callSessionTerminated}
+ */
+ @Override
+ public void terminate(int reason) throws RemoteException {
+ }
+
+ /**
+ * Puts a call on hold. When it succeeds, {@link ImsCallSession.Listener#callSessionHeld} is
+ * called.
+ *
+ * @param profile stream media profile {@link ImsStreamMediaProfile} to hold the call
+ * @see {@link ImsCallSession.Listener#callSessionHeld},
+ * {@link ImsCallSession.Listener#callSessionHoldFailed}
+ */
+ @Override
+ public void hold(ImsStreamMediaProfile profile) throws RemoteException {
+ }
+
+ /**
+ * Continues a call that's on hold. When it succeeds,
+ * {@link ImsCallSession.Listener#callSessionResumed} is called.
+ *
+ * @param profile stream media profile with {@link ImsStreamMediaProfile} to resume the call
+ * @see {@link ImsCallSession.Listener#callSessionResumed},
+ * {@link ImsCallSession.Listener#callSessionResumeFailed}
+ */
+ @Override
+ public void resume(ImsStreamMediaProfile profile) throws RemoteException {
+ }
+
+ /**
+ * Merges the active & hold call. When the merge starts,
+ * {@link ImsCallSession.Listener#callSessionMergeStarted} is called.
+ * {@link ImsCallSession.Listener#callSessionMergeComplete} is called if the merge is
+ * successful, and {@link ImsCallSession.Listener#callSessionMergeFailed} is called if the merge
+ * fails.
+ *
+ * @see {@link ImsCallSession.Listener#callSessionMergeStarted},
+ * {@link ImsCallSession.Listener#callSessionMergeComplete},
+ * {@link ImsCallSession.Listener#callSessionMergeFailed}
+ */
+ @Override
+ public void merge() throws RemoteException {
+ }
+
+ /**
+ * Updates the current call's properties (ex. call mode change: video upgrade / downgrade).
+ *
+ * @param callType call type specified in {@link ImsCallProfile} to be updated
+ * @param profile stream media profile {@link ImsStreamMediaProfile} to be updated
+ * @see {@link ImsCallSession.Listener#callSessionUpdated},
+ * {@link ImsCallSession.Listener#callSessionUpdateFailed}
+ */
+ @Override
+ public void update(int callType, ImsStreamMediaProfile profile) throws RemoteException {
+ }
+
+ /**
+ * Extends this call to the conference call with the specified recipients.
+ *
+ * @param participants participant list to be invited to the conference call after extending the
+ * call
+ * @see {@link ImsCallSession.Listener#callSessionConferenceExtended},
+ * {@link ImsCallSession.Listener#callSessionConferenceExtendFailed}
+ */
+ @Override
+ public void extendToConference(String[] participants) throws RemoteException {
+ }
+
+ /**
+ * Requests the conference server to invite an additional participants to the conference.
+ *
+ * @param participants participant list to be invited to the conference call
+ * @see {@link ImsCallSession.Listener#callSessionInviteParticipantsRequestDelivered},
+ * {@link ImsCallSession.Listener#callSessionInviteParticipantsRequestFailed}
+ */
+ @Override
+ public void inviteParticipants(String[] participants) throws RemoteException {
+ }
+
+ /**
+ * Requests the conference server to remove the specified participants from the conference.
+ *
+ * @param participants participant list to be removed from the conference call
+ * @see {@link ImsCallSession.Listener#callSessionRemoveParticipantsRequestDelivered},
+ * {@link ImsCallSession.Listener#callSessionRemoveParticipantsRequestFailed}
+ */
+ @Override
+ public void removeParticipants(String[] participants) throws RemoteException {
+ }
+
+ /**
+ * Sends a DTMF code. According to <a href="http://tools.ietf.org/html/rfc2833">RFC 2833</a>,
+ * event 0 ~ 9 maps to decimal value 0 ~ 9, '*' to 10, '#' to 11, event 'A' ~ 'D' to 12 ~ 15,
+ * and event flash to 16. Currently, event flash is not supported.
+ *
+ * @param c the DTMF to send. '0' ~ '9', 'A' ~ 'D', '*', '#' are valid inputs.
+ */
+ @Override
+ public void sendDtmf(char c, Message result) throws RemoteException {
+ }
+
+ /**
+ * Start a DTMF code. According to <a href="http://tools.ietf.org/html/rfc2833">RFC 2833</a>,
+ * event 0 ~ 9 maps to decimal value 0 ~ 9, '*' to 10, '#' to 11, event 'A' ~ 'D' to 12 ~ 15,
+ * and event flash to 16. Currently, event flash is not supported.
+ *
+ * @param c the DTMF to send. '0' ~ '9', 'A' ~ 'D', '*', '#' are valid inputs.
+ */
+ @Override
+ public void startDtmf(char c) throws RemoteException {
+ }
+
+ /**
+ * Stop a DTMF code.
+ */
+ @Override
+ public void stopDtmf() throws RemoteException {
+ }
+
+ /**
+ * Sends an USSD message.
+ *
+ * @param ussdMessage USSD message to send
+ */
+ @Override
+ public void sendUssd(String ussdMessage) throws RemoteException {
+ }
+
+ /**
+ * Returns a binder for the video call provider implementation contained within the IMS service
+ * process. This binder is used by the VideoCallProvider subclass in Telephony which
+ * intermediates between the propriety implementation and Telecomm/InCall.
+ */
+ @Override
+ public IImsVideoCallProvider getVideoCallProvider() throws RemoteException {
+ return null;
+ }
+
+ /**
+ * Determines if the current session is multiparty.
+ * @return {@code True} if the session is multiparty.
+ */
+ @Override
+ public boolean isMultiparty() throws RemoteException {
+ return false;
+ }
+}
diff --git a/telephony/java/android/telephony/ims/stub/ImsCallSessionListenerImplBase.java b/telephony/java/android/telephony/ims/stub/ImsCallSessionListenerImplBase.java
new file mode 100644
index 0000000..46f8f80
--- /dev/null
+++ b/telephony/java/android/telephony/ims/stub/ImsCallSessionListenerImplBase.java
@@ -0,0 +1,251 @@
+/*
+ * 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.ims.stub;
+
+import com.android.ims.ImsCallProfile;
+import com.android.ims.ImsConferenceState;
+import com.android.ims.ImsReasonInfo;
+import com.android.ims.ImsStreamMediaProfile;
+import com.android.ims.ImsSuppServiceNotification;
+import com.android.ims.internal.IImsCallSession;
+import com.android.ims.internal.IImsCallSessionListener;
+
+/**
+ * Base implementation of ImsCallSessionListenerBase, which implements stub versions of the methods
+ * in the IImsCallSessionListener AIDL. Override the methods that your implementation of
+ * ImsCallSessionListener supports.
+ *
+ * DO NOT remove or change the existing APIs, only add new ones to this Base implementation or you
+ * will break other implementations of ImsCallSessionListener maintained by other ImsServices.
+ *
+ * @hide
+ */
+public class ImsCallSessionListenerImplBase extends IImsCallSessionListener.Stub {
+ /**
+ * Notifies the result of the basic session operation (setup / terminate).
+ */
+ @Override
+ public void callSessionProgressing(IImsCallSession session, ImsStreamMediaProfile profile) {
+ // no-op
+ }
+
+ @Override
+ public void callSessionStarted(IImsCallSession session, ImsCallProfile profile) {
+ // no-op
+ }
+
+ @Override
+ public void callSessionStartFailed(IImsCallSession session, ImsReasonInfo reasonInfo) {
+ // no-op
+ }
+
+ @Override
+ public void callSessionTerminated(IImsCallSession session, ImsReasonInfo reasonInfo) {
+ // no-op
+ }
+
+ /**
+ * Notifies the result of the call hold/resume operation.
+ */
+ @Override
+ public void callSessionHeld(IImsCallSession session, ImsCallProfile profile) {
+ // no-op
+ }
+
+ @Override
+ public void callSessionHoldFailed(IImsCallSession session, ImsReasonInfo reasonInfo) {
+ // no-op
+ }
+
+ @Override
+ public void callSessionHoldReceived(IImsCallSession session, ImsCallProfile profile) {
+ // no-op
+ }
+
+ @Override
+ public void callSessionResumed(IImsCallSession session, ImsCallProfile profile) {
+ // no-op
+ }
+
+ @Override
+ public void callSessionResumeFailed(IImsCallSession session, ImsReasonInfo reasonInfo) {
+ // no-op
+ }
+
+ @Override
+ public void callSessionResumeReceived(IImsCallSession session, ImsCallProfile profile) {
+ // no-op
+ }
+
+ /**
+ * Notifies the result of call merge operation.
+ */
+ @Override
+ public void callSessionMergeStarted(IImsCallSession session, IImsCallSession newSession,
+ ImsCallProfile profile) {
+ // no-op
+ }
+
+ @Override
+ public void callSessionMergeComplete(IImsCallSession session) {
+ // no-op
+ }
+
+ @Override
+ public void callSessionMergeFailed(IImsCallSession session, ImsReasonInfo reasonInfo) {
+ // no-op
+ }
+
+ /**
+ * Notifies the result of call upgrade / downgrade or any other call
+ * updates.
+ */
+ @Override
+ public void callSessionUpdated(IImsCallSession session, ImsCallProfile profile) {
+ // no-op
+ }
+
+ @Override
+ public void callSessionUpdateFailed(IImsCallSession session, ImsReasonInfo reasonInfo) {
+ // no-op
+ }
+
+ @Override
+ public void callSessionUpdateReceived(IImsCallSession session, ImsCallProfile profile) {
+ // no-op
+ }
+
+ /**
+ * Notifies the result of conference extension.
+ */
+ @Override
+ public void callSessionConferenceExtended(IImsCallSession session, IImsCallSession newSession,
+ ImsCallProfile profile) {
+ // no-op
+ }
+
+ @Override
+ public void callSessionConferenceExtendFailed(IImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ // no-op
+ }
+
+ @Override
+ public void callSessionConferenceExtendReceived(IImsCallSession session,
+ IImsCallSession newSession,
+ ImsCallProfile profile) {
+ // no-op
+ }
+
+ /**
+ * Notifies the result of the participant invitation / removal to/from the
+ * conference session.
+ */
+ @Override
+ public void callSessionInviteParticipantsRequestDelivered(IImsCallSession session) {
+ // no-op
+ }
+
+ @Override
+ public void callSessionInviteParticipantsRequestFailed(IImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ // no-op
+ }
+
+ @Override
+ public void callSessionRemoveParticipantsRequestDelivered(IImsCallSession session) {
+ // no-op
+ }
+
+ @Override
+ public void callSessionRemoveParticipantsRequestFailed(IImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ // no-op
+ }
+
+ /**
+ * Notifies the changes of the conference info. the conference session.
+ */
+ @Override
+ public void callSessionConferenceStateUpdated(IImsCallSession session,
+ ImsConferenceState state) {
+ // no-op
+ }
+
+ /**
+ * Notifies the incoming USSD message.
+ */
+ @Override
+ public void callSessionUssdMessageReceived(IImsCallSession session, int mode,
+ String ussdMessage) {
+ // no-op
+ }
+
+ /**
+ * Notifies of handover information for this call
+ */
+ @Override
+ public void callSessionHandover(IImsCallSession session, int srcAccessTech,
+ int targetAccessTech,
+ ImsReasonInfo reasonInfo) {
+ // no-op
+ }
+
+ @Override
+ public void callSessionHandoverFailed(IImsCallSession session, int srcAccessTech,
+ int targetAccessTech,
+ ImsReasonInfo reasonInfo) {
+ // no-op
+ }
+
+ /**
+ * Notifies the TTY mode change by remote party.
+ *
+ * @param mode one of the following: -
+ * {@link com.android.internal.telephony.Phone#TTY_MODE_OFF} -
+ * {@link com.android.internal.telephony.Phone#TTY_MODE_FULL} -
+ * {@link com.android.internal.telephony.Phone#TTY_MODE_HCO} -
+ * {@link com.android.internal.telephony.Phone#TTY_MODE_VCO}
+ */
+ @Override
+ public void callSessionTtyModeReceived(IImsCallSession session, int mode) {
+ // no-op
+ }
+
+ /**
+ * Notifies of a change to the multiparty state for this
+ * {@code ImsCallSession}.
+ *
+ * @param session The call session.
+ * @param isMultiParty {@code true} if the session became multiparty,
+ * {@code false} otherwise.
+ */
+ @Override
+ public void callSessionMultipartyStateChanged(IImsCallSession session, boolean isMultiParty) {
+ // no-op
+ }
+
+ /**
+ * Notifies the supplementary service information for the current session.
+ */
+ @Override
+ public void callSessionSuppServiceReceived(IImsCallSession session,
+ ImsSuppServiceNotification suppSrvNotification) {
+ // no-op
+ }
+}
+
diff --git a/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
new file mode 100644
index 0000000..5a4db99
--- /dev/null
+++ b/telephony/java/android/telephony/ims/stub/ImsConfigImplBase.java
@@ -0,0 +1,150 @@
+/*
+ * 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.ims.stub;
+
+import android.os.RemoteException;
+
+import com.android.ims.ImsConfig;
+import com.android.ims.ImsConfigListener;
+import com.android.ims.internal.IImsConfig;
+
+/**
+ * Base implementation of ImsConfig, which implements stub versions of the methods
+ * in the IImsConfig AIDL. Override the methods that your implementation of ImsConfig supports.
+ *
+ * DO NOT remove or change the existing APIs, only add new ones to this Base implementation or you
+ * will break other implementations of ImsConfig maintained by other ImsServices.
+ *
+ * Provides APIs to get/set the IMS service feature/capability/parameters.
+ * The config items include:
+ * 1) Items provisioned by the operator.
+ * 2) Items configured by user. Mainly service feature class.
+ *
+ * @hide
+ */
+
+public class ImsConfigImplBase extends IImsConfig.Stub {
+
+ /**
+ * Gets the value for ims service/capabilities parameters from the provisioned
+ * value storage. Synchronous blocking call.
+ *
+ * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
+ * @return value in Integer format.
+ */
+ @Override
+ public int getProvisionedValue(int item) throws RemoteException {
+ return -1;
+ }
+
+ /**
+ * Gets the value for ims service/capabilities parameters from the provisioned
+ * value storage. Synchronous blocking call.
+ *
+ * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
+ * @return value in String format.
+ */
+ @Override
+ public String getProvisionedStringValue(int item) throws RemoteException {
+ return null;
+ }
+
+ /**
+ * Sets the value for IMS service/capabilities parameters by the operator device
+ * management entity. It sets the config item value in the provisioned storage
+ * from which the master value is derived. Synchronous blocking call.
+ *
+ * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
+ * @param value in Integer format.
+ * @return as defined in com.android.ims.ImsConfig#OperationStatusConstants.
+ */
+ @Override
+ public int setProvisionedValue(int item, int value) throws RemoteException {
+ return ImsConfig.OperationStatusConstants.FAILED;
+ }
+
+ /**
+ * Sets the value for IMS service/capabilities parameters by the operator device
+ * management entity. It sets the config item value in the provisioned storage
+ * from which the master value is derived. Synchronous blocking call.
+ *
+ * @param item as defined in com.android.ims.ImsConfig#ConfigConstants.
+ * @param value in String format.
+ * @return as defined in com.android.ims.ImsConfig#OperationStatusConstants.
+ */
+ @Override
+ public int setProvisionedStringValue(int item, String value) throws RemoteException {
+ return ImsConfig.OperationStatusConstants.FAILED;
+ }
+
+ /**
+ * Gets the value of the specified IMS feature item for specified network type.
+ * This operation gets the feature config value from the master storage (i.e. final
+ * value). Asynchronous non-blocking call.
+ *
+ * @param feature as defined in com.android.ims.ImsConfig#FeatureConstants.
+ * @param network as defined in android.telephony.TelephonyManager#NETWORK_TYPE_XXX.
+ * @param listener feature value returned asynchronously through listener.
+ */
+ @Override
+ public void getFeatureValue(int feature, int network, ImsConfigListener listener)
+ throws RemoteException {
+ }
+
+ /**
+ * Sets the value for IMS feature item for specified network type.
+ * This operation stores the user setting in setting db from which master db
+ * is derived.
+ *
+ * @param feature as defined in com.android.ims.ImsConfig#FeatureConstants.
+ * @param network as defined in android.telephony.TelephonyManager#NETWORK_TYPE_XXX.
+ * @param value as defined in com.android.ims.ImsConfig#FeatureValueConstants.
+ * @param listener, provided if caller needs to be notified for set result.
+ */
+ @Override
+ public void setFeatureValue(int feature, int network, int value, ImsConfigListener listener)
+ throws RemoteException {
+ }
+
+ /**
+ * Gets the value for IMS VoLTE provisioned.
+ * This should be the same as the operator provisioned value if applies.
+ */
+ @Override
+ public boolean getVolteProvisioned() throws RemoteException {
+ return false;
+ }
+
+ /**
+ * Gets the value for IMS feature item video quality.
+ *
+ * @param listener Video quality value returned asynchronously through listener.
+ */
+ @Override
+ public void getVideoQuality(ImsConfigListener listener) throws RemoteException {
+ }
+
+ /**
+ * Sets the value for IMS feature item video quality.
+ *
+ * @param quality, defines the value of video quality.
+ * @param listener, provided if caller needs to be notified for set result.
+ */
+ @Override
+ public void setVideoQuality(int quality, ImsConfigListener listener) throws RemoteException {
+ }
+}
diff --git a/telephony/java/android/telephony/ims/stub/ImsEcbmImplBase.java b/telephony/java/android/telephony/ims/stub/ImsEcbmImplBase.java
new file mode 100644
index 0000000..89f95ff
--- /dev/null
+++ b/telephony/java/android/telephony/ims/stub/ImsEcbmImplBase.java
@@ -0,0 +1,51 @@
+/*
+ * 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.ims.stub;
+
+import android.os.RemoteException;
+
+import com.android.ims.internal.IImsEcbm;
+import com.android.ims.internal.IImsEcbmListener;
+
+/**
+ * Base implementation of ImsEcbm, which implements stub versions of the methods
+ * in the IImsEcbm AIDL. Override the methods that your implementation of ImsEcbm supports.
+ *
+ * DO NOT remove or change the existing APIs, only add new ones to this Base implementation or you
+ * will break other implementations of ImsEcbm maintained by other ImsServices.
+ *
+ * @hide
+ */
+
+public class ImsEcbmImplBase extends IImsEcbm.Stub {
+
+ /**
+ * Sets the listener.
+ */
+ @Override
+ public void setListener(IImsEcbmListener listener) throws RemoteException {
+
+ }
+
+ /**
+ * Requests Modem to come out of ECBM mode
+ */
+ @Override
+ public void exitEmergencyCallbackMode() throws RemoteException {
+
+ }
+}
diff --git a/telephony/java/android/telephony/ims/stub/ImsMultiEndpointImplBase.java b/telephony/java/android/telephony/ims/stub/ImsMultiEndpointImplBase.java
new file mode 100644
index 0000000..05da9da
--- /dev/null
+++ b/telephony/java/android/telephony/ims/stub/ImsMultiEndpointImplBase.java
@@ -0,0 +1,53 @@
+/*
+ * 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.ims.stub;
+
+import android.os.RemoteException;
+
+import com.android.ims.internal.IImsExternalCallStateListener;
+import com.android.ims.internal.IImsMultiEndpoint;
+
+/**
+ * Base implementation of ImsMultiEndpoint, which implements stub versions of the methods
+ * in the IImsMultiEndpoint AIDL. Override the methods that your implementation of
+ * ImsMultiEndpoint supports.
+ *
+ * DO NOT remove or change the existing APIs, only add new ones to this Base implementation or you
+ * will break other implementations of ImsMultiEndpoint maintained by other ImsServices.
+ *
+ * @hide
+ */
+
+public class ImsMultiEndpointImplBase extends IImsMultiEndpoint.Stub {
+
+ /**
+ * Sets the listener.
+ */
+ @Override
+ public void setListener(IImsExternalCallStateListener listener) throws RemoteException {
+
+ }
+
+ /**
+ * Query API to get the latest Dialog Event Package information
+ * Should be invoked only after setListener is done
+ */
+ @Override
+ public void requestImsExternalCallStateInfo() throws RemoteException {
+
+ }
+}
diff --git a/telephony/java/android/telephony/ims/stub/ImsStreamMediaSessionImplBase.java b/telephony/java/android/telephony/ims/stub/ImsStreamMediaSessionImplBase.java
new file mode 100644
index 0000000..92f1a01
--- /dev/null
+++ b/telephony/java/android/telephony/ims/stub/ImsStreamMediaSessionImplBase.java
@@ -0,0 +1,40 @@
+/*
+ * 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.ims.stub;
+
+import android.os.RemoteException;
+
+import com.android.ims.internal.IImsStreamMediaSession;
+
+/**
+ * Base implementation of ImsStreamMediaSession, which implements stub versions of the methods
+ * in the IImsStreamMediaSession AIDL. Override the methods that your implementation of
+ * ImsStreamMediaSession supports.
+ *
+ * DO NOT remove or change the existing APIs, only add new ones to this Base implementation or you
+ * will break other implementations of ImsStreamMediaSession maintained by other ImsServices.
+ *
+ * @hide
+ */
+
+public class ImsStreamMediaSessionImplBase extends IImsStreamMediaSession.Stub {
+
+ @Override
+ public void close() throws RemoteException {
+
+ }
+}
diff --git a/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java b/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java
new file mode 100644
index 0000000..dc74094
--- /dev/null
+++ b/telephony/java/android/telephony/ims/stub/ImsUtImplBase.java
@@ -0,0 +1,174 @@
+/*
+ * 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.ims.stub;
+
+import android.os.Bundle;
+import android.os.RemoteException;
+
+import com.android.ims.internal.IImsUt;
+import com.android.ims.internal.IImsUtListener;
+
+/**
+ * Base implementation of ImsUt, which implements stub versions of the methods
+ * in the IImsUt AIDL. Override the methods that your implementation of ImsUt supports.
+ *
+ * DO NOT remove or change the existing APIs, only add new ones to this Base implementation or you
+ * will break other implementations of ImsUt maintained by other ImsServices.
+ *
+ * Provides the Ut interface interworking to get/set the supplementary service configuration.
+ *
+ * @hide
+ */
+
+public class ImsUtImplBase extends IImsUt.Stub {
+
+ /**
+ * Closes the object. This object is not usable after being closed.
+ */
+ @Override
+ public void close() throws RemoteException {
+
+ }
+
+ /**
+ * Retrieves the configuration of the call barring.
+ */
+ @Override
+ public int queryCallBarring(int cbType) throws RemoteException {
+ return -1;
+ }
+
+ /**
+ * Retrieves the configuration of the call forward.
+ */
+ @Override
+ public int queryCallForward(int condition, String number) throws RemoteException {
+ return -1;
+ }
+
+ /**
+ * Retrieves the configuration of the call waiting.
+ */
+ @Override
+ public int queryCallWaiting() throws RemoteException {
+ return -1;
+ }
+
+ /**
+ * Retrieves the default CLIR setting.
+ */
+ @Override
+ public int queryCLIR() throws RemoteException {
+ return -1;
+ }
+
+ /**
+ * Retrieves the CLIP call setting.
+ */
+ @Override
+ public int queryCLIP() throws RemoteException {
+ return -1;
+ }
+
+ /**
+ * Retrieves the COLR call setting.
+ */
+ @Override
+ public int queryCOLR() throws RemoteException {
+ return -1;
+ }
+
+ /**
+ * Retrieves the COLP call setting.
+ */
+ @Override
+ public int queryCOLP() throws RemoteException {
+ return -1;
+ }
+
+ /**
+ * Updates or retrieves the supplementary service configuration.
+ */
+ @Override
+ public int transact(Bundle ssInfo) throws RemoteException {
+ return -1;
+ }
+
+ /**
+ * Updates the configuration of the call barring.
+ */
+ @Override
+ public int updateCallBarring(int cbType, int action, String[] barrList) throws RemoteException {
+ return -1;
+ }
+
+ /**
+ * Updates the configuration of the call forward.
+ */
+ @Override
+ public int updateCallForward(int action, int condition, String number, int serviceClass,
+ int timeSeconds) throws RemoteException {
+ return 0;
+ }
+
+ /**
+ * Updates the configuration of the call waiting.
+ */
+ @Override
+ public int updateCallWaiting(boolean enable, int serviceClass) throws RemoteException {
+ return -1;
+ }
+
+ /**
+ * Updates the configuration of the CLIR supplementary service.
+ */
+ @Override
+ public int updateCLIR(int clirMode) throws RemoteException {
+ return -1;
+ }
+
+ /**
+ * Updates the configuration of the CLIP supplementary service.
+ */
+ @Override
+ public int updateCLIP(boolean enable) throws RemoteException {
+ return -1;
+ }
+
+ /**
+ * Updates the configuration of the COLR supplementary service.
+ */
+ @Override
+ public int updateCOLR(int presentation) throws RemoteException {
+ return -1;
+ }
+
+ /**
+ * Updates the configuration of the COLP supplementary service.
+ */
+ @Override
+ public int updateCOLP(boolean enable) throws RemoteException {
+ return -1;
+ }
+
+ /**
+ * Sets the listener.
+ */
+ @Override
+ public void setListener(IImsUtListener listener) throws RemoteException {
+ }
+}
diff --git a/telephony/java/android/telephony/ims/stub/ImsUtListenerImplBase.java b/telephony/java/android/telephony/ims/stub/ImsUtListenerImplBase.java
new file mode 100644
index 0000000..b371efb
--- /dev/null
+++ b/telephony/java/android/telephony/ims/stub/ImsUtListenerImplBase.java
@@ -0,0 +1,88 @@
+/*
+ * 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.ims.stub;
+
+import android.os.Bundle;
+import android.os.RemoteException;
+
+import com.android.ims.ImsCallForwardInfo;
+import com.android.ims.ImsReasonInfo;
+import com.android.ims.ImsSsInfo;
+import com.android.ims.internal.IImsUt;
+import com.android.ims.internal.IImsUtListener;
+
+/**
+ * Base implementation of ImsUtListener, which implements stub versions of the methods
+ * in the IImsUtListener AIDL. Override the methods that your implementation of
+ * ImsUtListener supports.
+ *
+ * DO NOT remove or change the existing APIs, only add new ones to this Base implementation or you
+ * will break other implementations of ImsUtListener maintained by other ImsServices.
+ *
+ * @hide
+ */
+
+public class ImsUtListenerImplBase extends IImsUtListener.Stub {
+
+ /**
+ * Notifies the result of the supplementary service configuration udpate.
+ */
+ @Override
+ public void utConfigurationUpdated(IImsUt ut, int id) throws RemoteException {
+ }
+
+ @Override
+ public void utConfigurationUpdateFailed(IImsUt ut, int id, ImsReasonInfo error)
+ throws RemoteException {
+ }
+
+ /**
+ * Notifies the result of the supplementary service configuration query.
+ */
+ @Override
+ public void utConfigurationQueried(IImsUt ut, int id, Bundle ssInfo) throws RemoteException {
+ }
+
+ @Override
+ public void utConfigurationQueryFailed(IImsUt ut, int id, ImsReasonInfo error)
+ throws RemoteException {
+ }
+
+ /**
+ * Notifies the status of the call barring supplementary service.
+ */
+ @Override
+ public void utConfigurationCallBarringQueried(IImsUt ut, int id, ImsSsInfo[] cbInfo)
+ throws RemoteException {
+ }
+
+ /**
+ * Notifies the status of the call forwarding supplementary service.
+ */
+ @Override
+ public void utConfigurationCallForwardQueried(IImsUt ut, int id, ImsCallForwardInfo[] cfInfo)
+ throws RemoteException {
+ }
+
+ /**
+ * Notifies the status of the call waiting supplementary service.
+ */
+ @Override
+ public void utConfigurationCallWaitingQueried(IImsUt ut, int id, ImsSsInfo[] cwInfo)
+ throws RemoteException {
+ }
+}
diff --git a/telephony/java/com/android/ims/ImsConfig.java b/telephony/java/com/android/ims/ImsConfig.java
new file mode 100644
index 0000000..cd076b1
--- /dev/null
+++ b/telephony/java/com/android/ims/ImsConfig.java
@@ -0,0 +1,694 @@
+/*
+ * 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.ims;
+
+import android.content.Context;
+import android.os.RemoteException;
+import android.telephony.Rlog;
+
+import com.android.ims.internal.IImsConfig;
+
+/**
+ * Provides APIs to get/set the IMS service feature/capability/parameters.
+ * The config items include:
+ * 1) Items provisioned by the operator.
+ * 2) Items configured by user. Mainly service feature class.
+ *
+ * @hide
+ */
+public class ImsConfig {
+ private static final String TAG = "ImsConfig";
+ private boolean DBG = true;
+ private final IImsConfig miConfig;
+ private Context mContext;
+
+ /**
+ * Broadcast action: the feature enable status was changed
+ *
+ * @hide
+ */
+ public static final String ACTION_IMS_FEATURE_CHANGED =
+ "com.android.intent.action.IMS_FEATURE_CHANGED";
+
+ /**
+ * Broadcast action: the configuration was changed
+ *
+ * @hide
+ */
+ public static final String ACTION_IMS_CONFIG_CHANGED =
+ "com.android.intent.action.IMS_CONFIG_CHANGED";
+
+ /**
+ * Extra parameter "item" of intent ACTION_IMS_FEATURE_CHANGED and ACTION_IMS_CONFIG_CHANGED.
+ * It is the value of FeatureConstants or ConfigConstants.
+ *
+ * @hide
+ */
+ public static final String EXTRA_CHANGED_ITEM = "item";
+
+ /**
+ * Extra parameter "value" of intent ACTION_IMS_FEATURE_CHANGED and ACTION_IMS_CONFIG_CHANGED.
+ * It is the new value of "item".
+ *
+ * @hide
+ */
+ public static final String EXTRA_NEW_VALUE = "value";
+
+ /**
+ * Defines IMS service/capability feature constants.
+ */
+ public static class FeatureConstants {
+ public static final int FEATURE_TYPE_UNKNOWN = -1;
+
+ /**
+ * FEATURE_TYPE_VOLTE supports features defined in 3GPP and
+ * GSMA IR.92 over LTE.
+ */
+ public static final int FEATURE_TYPE_VOICE_OVER_LTE = 0;
+
+ /**
+ * FEATURE_TYPE_LVC supports features defined in 3GPP and
+ * GSMA IR.94 over LTE.
+ */
+ public static final int FEATURE_TYPE_VIDEO_OVER_LTE = 1;
+
+ /**
+ * FEATURE_TYPE_VOICE_OVER_WIFI supports features defined in 3GPP and
+ * GSMA IR.92 over WiFi.
+ */
+ public static final int FEATURE_TYPE_VOICE_OVER_WIFI = 2;
+
+ /**
+ * FEATURE_TYPE_VIDEO_OVER_WIFI supports features defined in 3GPP and
+ * GSMA IR.94 over WiFi.
+ */
+ public static final int FEATURE_TYPE_VIDEO_OVER_WIFI = 3;
+
+ /**
+ * FEATURE_TYPE_UT supports features defined in 3GPP and
+ * GSMA IR.92 over LTE.
+ */
+ public static final int FEATURE_TYPE_UT_OVER_LTE = 4;
+
+ /**
+ * FEATURE_TYPE_UT_OVER_WIFI supports features defined in 3GPP and
+ * GSMA IR.92 over WiFi.
+ */
+ public static final int FEATURE_TYPE_UT_OVER_WIFI = 5;
+ }
+
+ /**
+ * Defines IMS service/capability parameters.
+ */
+ public static class ConfigConstants {
+
+ // Define IMS config items
+ public static final int CONFIG_START = 0;
+
+ // Define operator provisioned config items
+ public static final int PROVISIONED_CONFIG_START = CONFIG_START;
+
+ /**
+ * AMR CODEC Mode Value set, 0-7 in comma separated sequence.
+ * Value is in String format.
+ */
+ public static final int VOCODER_AMRMODESET = CONFIG_START;
+
+ /**
+ * Wide Band AMR CODEC Mode Value set,0-7 in comma separated sequence.
+ * Value is in String format.
+ */
+ public static final int VOCODER_AMRWBMODESET = 1;
+
+ /**
+ * SIP Session Timer value (seconds).
+ * Value is in Integer format.
+ */
+ public static final int SIP_SESSION_TIMER = 2;
+
+ /**
+ * Minimum SIP Session Expiration Timer in (seconds).
+ * Value is in Integer format.
+ */
+ public static final int MIN_SE = 3;
+
+ /**
+ * SIP_INVITE cancellation time out value (in milliseconds). Integer format.
+ * Value is in Integer format.
+ */
+ public static final int CANCELLATION_TIMER = 4;
+
+ /**
+ * Delay time when an iRAT transition from eHRPD/HRPD/1xRTT to LTE.
+ * Value is in Integer format.
+ */
+ public static final int TDELAY = 5;
+
+ /**
+ * Silent redial status of Enabled (True), or Disabled (False).
+ * Value is in Integer format.
+ */
+ public static final int SILENT_REDIAL_ENABLE = 6;
+
+ /**
+ * SIP T1 timer value in milliseconds. See RFC 3261 for define.
+ * Value is in Integer format.
+ */
+ public static final int SIP_T1_TIMER = 7;
+
+ /**
+ * SIP T2 timer value in milliseconds. See RFC 3261 for define.
+ * Value is in Integer format.
+ */
+ public static final int SIP_T2_TIMER = 8;
+
+ /**
+ * SIP TF timer value in milliseconds. See RFC 3261 for define.
+ * Value is in Integer format.
+ */
+ public static final int SIP_TF_TIMER = 9;
+
+ /**
+ * VoLTE status for VLT/s status of Enabled (1), or Disabled (0).
+ * Value is in Integer format.
+ */
+ public static final int VLT_SETTING_ENABLED = 10;
+
+ /**
+ * VoLTE status for LVC/s status of Enabled (1), or Disabled (0).
+ * Value is in Integer format.
+ */
+ public static final int LVC_SETTING_ENABLED = 11;
+ /**
+ * Domain Name for the device to populate the request URI for REGISTRATION.
+ * Value is in String format.
+ */
+ public static final int DOMAIN_NAME = 12;
+ /**
+ * Device Outgoing SMS based on either 3GPP or 3GPP2 standards.
+ * Value is in Integer format. 3GPP2(0), 3GPP(1)
+ */
+ public static final int SMS_FORMAT = 13;
+ /**
+ * Turns IMS ON/OFF on the device.
+ * Value is in Integer format. ON (1), OFF(0).
+ */
+ public static final int SMS_OVER_IP = 14;
+ /**
+ * Requested expiration for Published Online availability.
+ * Value is in Integer format.
+ */
+ public static final int PUBLISH_TIMER = 15;
+ /**
+ * Requested expiration for Published Offline availability.
+ * Value is in Integer format.
+ */
+ public static final int PUBLISH_TIMER_EXTENDED = 16;
+ /**
+ *
+ * Value is in Integer format.
+ */
+ public static final int CAPABILITY_DISCOVERY_ENABLED = 17;
+ /**
+ * Period of time the capability information of the contact is cached on handset.
+ * Value is in Integer format.
+ */
+ public static final int CAPABILITIES_CACHE_EXPIRATION = 18;
+ /**
+ * Peiod of time the availability information of a contact is cached on device.
+ * Value is in Integer format.
+ */
+ public static final int AVAILABILITY_CACHE_EXPIRATION = 19;
+ /**
+ * Interval between successive capabilities polling.
+ * Value is in Integer format.
+ */
+ public static final int CAPABILITIES_POLL_INTERVAL = 20;
+ /**
+ * Minimum time between two published messages from the device.
+ * Value is in Integer format.
+ */
+ public static final int SOURCE_THROTTLE_PUBLISH = 21;
+ /**
+ * The Maximum number of MDNs contained in one Request Contained List.
+ * Value is in Integer format.
+ */
+ public static final int MAX_NUMENTRIES_IN_RCL = 22;
+ /**
+ * Expiration timer for subscription of a Request Contained List, used in capability
+ * polling.
+ * Value is in Integer format.
+ */
+ public static final int CAPAB_POLL_LIST_SUB_EXP = 23;
+ /**
+ * Applies compression to LIST Subscription.
+ * Value is in Integer format. Enable (1), Disable(0).
+ */
+ public static final int GZIP_FLAG = 24;
+ /**
+ * VOLTE Status for EAB/s status of Enabled (1), or Disabled (0).
+ * Value is in Integer format.
+ */
+ public static final int EAB_SETTING_ENABLED = 25;
+ /**
+ * Wi-Fi calling roaming status.
+ * Value is in Integer format. ON (1), OFF(0).
+ */
+ public static final int VOICE_OVER_WIFI_ROAMING = 26;
+ /**
+ * Wi-Fi calling modem - WfcModeFeatureValueConstants.
+ * Value is in Integer format.
+ */
+ public static final int VOICE_OVER_WIFI_MODE = 27;
+ /**
+ * VOLTE Status for voice over wifi status of Enabled (1), or Disabled (0).
+ * Value is in Integer format.
+ */
+ public static final int VOICE_OVER_WIFI_SETTING_ENABLED = 28;
+ /**
+ * Mobile data enabled.
+ * Value is in Integer format. On (1), OFF(0).
+ */
+ public static final int MOBILE_DATA_ENABLED = 29;
+ /**
+ * VoLTE user opted in status.
+ * Value is in Integer format. Opted-in (1) Opted-out (0).
+ */
+ public static final int VOLTE_USER_OPT_IN_STATUS = 30;
+ /**
+ * Proxy for Call Session Control Function(P-CSCF) address for Local-BreakOut(LBO).
+ * Value is in String format.
+ */
+ public static final int LBO_PCSCF_ADDRESS = 31;
+ /**
+ * Keep Alive Enabled for SIP.
+ * Value is in Integer format. On(1), OFF(0).
+ */
+ public static final int KEEP_ALIVE_ENABLED = 32;
+ /**
+ * Registration retry Base Time value in seconds.
+ * Value is in Integer format.
+ */
+ public static final int REGISTRATION_RETRY_BASE_TIME_SEC = 33;
+ /**
+ * Registration retry Max Time value in seconds.
+ * Value is in Integer format.
+ */
+ public static final int REGISTRATION_RETRY_MAX_TIME_SEC = 34;
+ /**
+ * Smallest RTP port for speech codec.
+ * Value is in integer format.
+ */
+ public static final int SPEECH_START_PORT = 35;
+ /**
+ * Largest RTP port for speech code.
+ * Value is in Integer format.
+ */
+ public static final int SPEECH_END_PORT = 36;
+ /**
+ * SIP Timer A's value in milliseconds. Timer A is the INVITE request
+ * retransmit interval, for UDP only.
+ * Value is in Integer format.
+ */
+ public static final int SIP_INVITE_REQ_RETX_INTERVAL_MSEC = 37;
+ /**
+ * SIP Timer B's value in milliseconds. Timer B is the wait time for
+ * INVITE message to be acknowledged.
+ * Value is in Integer format.
+ */
+ public static final int SIP_INVITE_RSP_WAIT_TIME_MSEC = 38;
+ /**
+ * SIP Timer D's value in milliseconds. Timer D is the wait time for
+ * response retransmits of the invite client transactions.
+ * Value is in Integer format.
+ */
+ public static final int SIP_INVITE_RSP_RETX_WAIT_TIME_MSEC = 39;
+ /**
+ * SIP Timer E's value in milliseconds. Timer E is the value Non-INVITE
+ * request retransmit interval, for UDP only.
+ * Value is in Integer format.
+ */
+ public static final int SIP_NON_INVITE_REQ_RETX_INTERVAL_MSEC = 40;
+ /**
+ * SIP Timer F's value in milliseconds. Timer F is the Non-INVITE transaction
+ * timeout timer.
+ * Value is in Integer format.
+ */
+ public static final int SIP_NON_INVITE_TXN_TIMEOUT_TIMER_MSEC = 41;
+ /**
+ * SIP Timer G's value in milliseconds. Timer G is the value of INVITE response
+ * retransmit interval.
+ * Value is in Integer format.
+ */
+ public static final int SIP_INVITE_RSP_RETX_INTERVAL_MSEC = 42;
+ /**
+ * SIP Timer H's value in milliseconds. Timer H is the value of wait time for
+ * ACK receipt.
+ * Value is in Integer format.
+ */
+ public static final int SIP_ACK_RECEIPT_WAIT_TIME_MSEC = 43;
+ /**
+ * SIP Timer I's value in milliseconds. Timer I is the value of wait time for
+ * ACK retransmits.
+ * Value is in Integer format.
+ */
+ public static final int SIP_ACK_RETX_WAIT_TIME_MSEC = 44;
+ /**
+ * SIP Timer J's value in milliseconds. Timer J is the value of wait time for
+ * non-invite request retransmission.
+ * Value is in Integer format.
+ */
+ public static final int SIP_NON_INVITE_REQ_RETX_WAIT_TIME_MSEC = 45;
+ /**
+ * SIP Timer K's value in milliseconds. Timer K is the value of wait time for
+ * non-invite response retransmits.
+ * Value is in Integer format.
+ */
+ public static final int SIP_NON_INVITE_RSP_RETX_WAIT_TIME_MSEC = 46;
+ /**
+ * AMR WB octet aligned dynamic payload type.
+ * Value is in Integer format.
+ */
+ public static final int AMR_WB_OCTET_ALIGNED_PT = 47;
+ /**
+ * AMR WB bandwidth efficient payload type.
+ * Value is in Integer format.
+ */
+ public static final int AMR_WB_BANDWIDTH_EFFICIENT_PT = 48;
+ /**
+ * AMR octet aligned dynamic payload type.
+ * Value is in Integer format.
+ */
+ public static final int AMR_OCTET_ALIGNED_PT = 49;
+ /**
+ * AMR bandwidth efficient payload type.
+ * Value is in Integer format.
+ */
+ public static final int AMR_BANDWIDTH_EFFICIENT_PT = 50;
+ /**
+ * DTMF WB payload type.
+ * Value is in Integer format.
+ */
+ public static final int DTMF_WB_PT = 51;
+ /**
+ * DTMF NB payload type.
+ * Value is in Integer format.
+ */
+ public static final int DTMF_NB_PT = 52;
+ /**
+ * AMR Default encoding mode.
+ * Value is in Integer format.
+ */
+ public static final int AMR_DEFAULT_MODE = 53;
+ /**
+ * SMS Public Service Identity.
+ * Value is in String format.
+ */
+ public static final int SMS_PSI = 54;
+ /**
+ * Video Quality - VideoQualityFeatureValuesConstants.
+ * Value is in Integer format.
+ */
+ public static final int VIDEO_QUALITY = 55;
+ /**
+ * LTE threshold.
+ * Handover from LTE to WiFi if LTE < THLTE1 and WiFi >= VOWT_A.
+ */
+ public static final int TH_LTE1 = 56;
+ /**
+ * LTE threshold.
+ * Handover from WiFi to LTE if LTE >= THLTE3 or (WiFi < VOWT_B and LTE >= THLTE2).
+ */
+ public static final int TH_LTE2 = 57;
+ /**
+ * LTE threshold.
+ * Handover from WiFi to LTE if LTE >= THLTE3 or (WiFi < VOWT_B and LTE >= THLTE2).
+ */
+ public static final int TH_LTE3 = 58;
+ /**
+ * 1x threshold.
+ * Handover from 1x to WiFi if 1x < TH1x
+ */
+ public static final int TH_1x = 59;
+ /**
+ * WiFi threshold.
+ * Handover from LTE to WiFi if LTE < THLTE1 and WiFi >= VOWT_A.
+ */
+ public static final int VOWT_A = 60;
+ /**
+ * WiFi threshold.
+ * Handover from WiFi to LTE if LTE >= THLTE3 or (WiFi < VOWT_B and LTE >= THLTE2).
+ */
+ public static final int VOWT_B = 61;
+ /**
+ * LTE ePDG timer.
+ * Device shall not handover back to LTE until the T_ePDG_LTE timer expires.
+ */
+ public static final int T_EPDG_LTE = 62;
+ /**
+ * WiFi ePDG timer.
+ * Device shall not handover back to WiFi until the T_ePDG_WiFi timer expires.
+ */
+ public static final int T_EPDG_WIFI = 63;
+ /**
+ * 1x ePDG timer.
+ * Device shall not re-register on 1x until the T_ePDG_1x timer expires.
+ */
+ public static final int T_EPDG_1X = 64;
+ /**
+ * MultiEndpoint status: Enabled (1), or Disabled (0).
+ * Value is in Integer format.
+ */
+ public static final int VICE_SETTING_ENABLED = 65;
+
+ // Expand the operator config items as needed here, need to change
+ // PROVISIONED_CONFIG_END after that.
+ public static final int PROVISIONED_CONFIG_END = VICE_SETTING_ENABLED;
+
+ // Expand the operator config items as needed here.
+ }
+
+ /**
+ * Defines IMS set operation status.
+ */
+ public static class OperationStatusConstants {
+ public static final int UNKNOWN = -1;
+ public static final int SUCCESS = 0;
+ public static final int FAILED = 1;
+ public static final int UNSUPPORTED_CAUSE_NONE = 2;
+ public static final int UNSUPPORTED_CAUSE_RAT = 3;
+ public static final int UNSUPPORTED_CAUSE_DISABLED = 4;
+ }
+
+ /**
+ * Defines IMS get operation values.
+ */
+ public static class OperationValuesConstants {
+ /**
+ * Values related to Video Quality
+ */
+ public static final int VIDEO_QUALITY_UNKNOWN = -1;
+ public static final int VIDEO_QUALITY_LOW = 0;
+ public static final int VIDEO_QUALITY_HIGH = 1;
+ }
+
+ /**
+ * Defines IMS video quality feature value.
+ */
+ public static class VideoQualityFeatureValuesConstants {
+ public static final int LOW = 0;
+ public static final int HIGH = 1;
+ }
+
+ /**
+ * Defines IMS feature value.
+ */
+ public static class FeatureValueConstants {
+ public static final int OFF = 0;
+ public static final int ON = 1;
+ }
+
+ /**
+ * Defines IMS feature value.
+ */
+ public static class WfcModeFeatureValueConstants {
+ public static final int WIFI_ONLY = 0;
+ public static final int CELLULAR_PREFERRED = 1;
+ public static final int WIFI_PREFERRED = 2;
+ }
+
+ public ImsConfig(IImsConfig iconfig, Context context) {
+ if (DBG) Rlog.d(TAG, "ImsConfig creates");
+ miConfig = iconfig;
+ mContext = context;
+ }
+
+ /**
+ * Gets the provisioned value for IMS service/capabilities parameters used by IMS stack.
+ * This function should not be called from the mainthread as it could block the
+ * mainthread.
+ *
+ * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
+ * @return the value in Integer format.
+ *
+ * @throws ImsException if calling the IMS service results in an error.
+ */
+ public int getProvisionedValue(int item) throws ImsException {
+ int ret = 0;
+ try {
+ ret = miConfig.getProvisionedValue(item);
+ } catch (RemoteException e) {
+ throw new ImsException("getValue()", e,
+ ImsReasonInfo.CODE_LOCAL_SERVICE_UNAVAILABLE);
+ }
+ if (DBG) Rlog.d(TAG, "getProvisionedValue(): item = " + item + ", ret =" + ret);
+
+ return ret;
+ }
+
+ /**
+ * Gets the provisioned value for IMS service/capabilities parameters used by IMS stack.
+ * This function should not be called from the mainthread as it could block the
+ * mainthread.
+ *
+ * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
+ * @return value in String format.
+ *
+ * @throws ImsException if calling the IMS service results in an error.
+ */
+ public String getProvisionedStringValue(int item) throws ImsException {
+ String ret = "Unknown";
+ try {
+ ret = miConfig.getProvisionedStringValue(item);
+ } catch (RemoteException e) {
+ throw new ImsException("getProvisionedStringValue()", e,
+ ImsReasonInfo.CODE_LOCAL_SERVICE_UNAVAILABLE);
+ }
+ if (DBG) Rlog.d(TAG, "getProvisionedStringValue(): item = " + item + ", ret =" + ret);
+
+ return ret;
+ }
+
+ /**
+ * Sets the value for IMS service/capabilities parameters by
+ * the operator device management entity.
+ * This function should not be called from main thread as it could block
+ * mainthread.
+ *
+ * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
+ * @param value in Integer format.
+ * @return as defined in com.android.ims.ImsConfig#OperationStatusConstants
+ *
+ * @throws ImsException if calling the IMS service results in an error.
+ */
+ public int setProvisionedValue(int item, int value)
+ throws ImsException {
+ int ret = OperationStatusConstants.UNKNOWN;
+ if (DBG) {
+ Rlog.d(TAG, "setProvisionedValue(): item = " + item +
+ "value = " + value);
+ }
+ try {
+ ret = miConfig.setProvisionedValue(item, value);
+ } catch (RemoteException e) {
+ throw new ImsException("setProvisionedValue()", e,
+ ImsReasonInfo.CODE_LOCAL_SERVICE_UNAVAILABLE);
+ }
+ if (DBG) {
+ Rlog.d(TAG, "setProvisionedValue(): item = " + item +
+ " value = " + value + " ret = " + ret);
+ }
+ return ret;
+ }
+
+ /**
+ * Sets the value for IMS service/capabilities parameters by
+ * the operator device management entity.
+ * This function should not be called from main thread as it could block
+ * mainthread.
+ *
+ * @param item, as defined in com.android.ims.ImsConfig#ConfigConstants.
+ * @param value in String format.
+ * @return as defined in com.android.ims.ImsConfig#OperationStatusConstants
+ *
+ * @throws ImsException if calling the IMS service results in an error.
+ */
+ public int setProvisionedStringValue(int item, String value)
+ throws ImsException {
+ int ret = OperationStatusConstants.UNKNOWN;
+ try {
+ ret = miConfig.setProvisionedStringValue(item, value);
+ } catch (RemoteException e) {
+ throw new ImsException("setProvisionedStringValue()", e,
+ ImsReasonInfo.CODE_LOCAL_SERVICE_UNAVAILABLE);
+ }
+ if (DBG) {
+ Rlog.d(TAG, "setProvisionedStringValue(): item = " + item +
+ ", value =" + value);
+ }
+ return ret;
+ }
+
+ /**
+ * Gets the value for IMS feature item for specified network type.
+ *
+ * @param feature, defined as in FeatureConstants.
+ * @param network, defined as in android.telephony.TelephonyManager#NETWORK_TYPE_XXX.
+ * @param listener, provided to be notified for the feature on/off status.
+ * @return void
+ *
+ * @throws ImsException if calling the IMS service results in an error.
+ */
+ public void getFeatureValue(int feature, int network,
+ ImsConfigListener listener) throws ImsException {
+ if (DBG) {
+ Rlog.d(TAG, "getFeatureValue: feature = " + feature + ", network =" + network +
+ ", listener =" + listener);
+ }
+ try {
+ miConfig.getFeatureValue(feature, network, listener);
+ } catch (RemoteException e) {
+ throw new ImsException("getFeatureValue()", e,
+ ImsReasonInfo.CODE_LOCAL_SERVICE_UNAVAILABLE);
+ }
+ }
+
+ /**
+ * Sets the value for IMS feature item for specified network type.
+ *
+ * @param feature, as defined in FeatureConstants.
+ * @param network, as defined in android.telephony.TelephonyManager#NETWORK_TYPE_XXX.
+ * @param value, as defined in FeatureValueConstants.
+ * @param listener, provided if caller needs to be notified for set result.
+ * @return void
+ *
+ * @throws ImsException if calling the IMS service results in an error.
+ */
+ public void setFeatureValue(int feature, int network, int value,
+ ImsConfigListener listener) throws ImsException {
+ if (DBG) {
+ Rlog.d(TAG, "setFeatureValue: feature = " + feature + ", network =" + network +
+ ", value =" + value + ", listener =" + listener);
+ }
+ try {
+ miConfig.setFeatureValue(feature, network, value, listener);
+ } catch (RemoteException e) {
+ throw new ImsException("setFeatureValue()", e,
+ ImsReasonInfo.CODE_LOCAL_SERVICE_UNAVAILABLE);
+ }
+ }
+}
diff --git a/telephony/java/com/android/ims/ImsException.java b/telephony/java/com/android/ims/ImsException.java
new file mode 100644
index 0000000..74b20f4
--- /dev/null
+++ b/telephony/java/com/android/ims/ImsException.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ims;
+
+/**
+ * This class defines a general IMS-related exception.
+ *
+ * @hide
+ */
+public class ImsException extends Exception {
+
+ /**
+ * Refer to CODE_LOCAL_* in {@link ImsReasonInfo}
+ */
+ private int mCode;
+
+ public ImsException() {
+ }
+
+ public ImsException(String message, int code) {
+ super(message + ", code = " + code);
+ mCode = code;
+ }
+
+ public ImsException(String message, Throwable cause, int code) {
+ super(message, cause);
+ mCode = code;
+ }
+
+ /**
+ * Gets the detailed exception code when ImsException is throwed
+ *
+ * @return the exception code in {@link ImsReasonInfo}
+ */
+ public int getCode() {
+ return mCode;
+ }
+}
diff --git a/telephony/java/com/android/ims/ImsReasonInfo.java b/telephony/java/com/android/ims/ImsReasonInfo.java
index c71808c..e4f380f 100644
--- a/telephony/java/com/android/ims/ImsReasonInfo.java
+++ b/telephony/java/com/android/ims/ImsReasonInfo.java
@@ -313,6 +313,12 @@
public static final int CODE_WIFI_LOST = 1407;
/**
+ * Indicates the registration attempt on IWLAN failed due to IKEv2 authetication failure
+ * during tunnel establishment.
+ */
+ public static final int CODE_IKEV2_AUTH_FAILURE = 1408;
+
+ /**
* Network string error messages.
* mExtraMessage may have these values.
*/
diff --git a/telephony/java/com/android/ims/ImsUtInterface.java b/telephony/java/com/android/ims/ImsUtInterface.java
new file mode 100644
index 0000000..5984e78
--- /dev/null
+++ b/telephony/java/com/android/ims/ImsUtInterface.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ims;
+
+import android.os.Message;
+
+/**
+ * Provides APIs for the supplementary service settings using IMS (Ut interface).
+ * It is created from 3GPP TS 24.623 (XCAP(XML Configuration Access Protocol)
+ * over the Ut interface for manipulating supplementary services).
+ *
+ * @hide
+ */
+public interface ImsUtInterface {
+ /**
+ * Actions
+ * @hide
+ */
+ public static final int ACTION_DEACTIVATION = 0;
+ public static final int ACTION_ACTIVATION = 1;
+ public static final int ACTION_REGISTRATION = 3;
+ public static final int ACTION_ERASURE = 4;
+ public static final int ACTION_INTERROGATION = 5;
+
+ /**
+ * OIR (Originating Identification Restriction, 3GPP TS 24.607)
+ * OIP (Originating Identification Presentation, 3GPP TS 24.607)
+ * TIR (Terminating Identification Restriction, 3GPP TS 24.608)
+ * TIP (Terminating Identification Presentation, 3GPP TS 24.608)
+ */
+ public static final int OIR_DEFAULT = 0; // "user subscription default value"
+ public static final int OIR_PRESENTATION_RESTRICTED = 1;
+ public static final int OIR_PRESENTATION_NOT_RESTRICTED = 2;
+
+ /**
+ * CW (Communication Waiting, 3GPP TS 24.615)
+ */
+
+ /**
+ * CDIV (Communication Diversion, 3GPP TS 24.604)
+ * actions: target, no reply timer
+ */
+ public static final int CDIV_CF_UNCONDITIONAL = 0;
+ public static final int CDIV_CF_BUSY = 1;
+ public static final int CDIV_CF_NO_REPLY = 2;
+ public static final int CDIV_CF_NOT_REACHABLE = 3;
+ // For CS service code: 002
+ public static final int CDIV_CF_ALL = 4;
+ // For CS service code: 004
+ public static final int CDIV_CF_ALL_CONDITIONAL = 5;
+ // It's only supported in the IMS service (CS does not define it).
+ // IR.92 recommends that an UE activates both the CFNRc and the CFNL
+ // (CDIV using condition not-registered) to the same target.
+ public static final int CDIV_CF_NOT_LOGGED_IN = 6;
+
+ /**
+ * CB (Communication Barring, 3GPP TS 24.611)
+ */
+ // Barring of All Incoming Calls
+ public static final int CB_BAIC = 1;
+ // Barring of All Outgoing Calls
+ public static final int CB_BAOC = 2;
+ // Barring of Outgoing International Calls
+ public static final int CB_BOIC = 3;
+ // Barring of Outgoing International Calls - excluding Home Country
+ public static final int CB_BOIC_EXHC = 4;
+ // Barring of Incoming Calls - when roaming
+ public static final int CB_BIC_WR = 5;
+ // Barring of Anonymous Communication Rejection (ACR) - a particular case of ICB service
+ public static final int CB_BIC_ACR = 6;
+ // Barring of All Calls
+ public static final int CB_BA_ALL = 7;
+ // Barring of Outgoing Services (Service Code 333 - 3GPP TS 22.030 Table B-1)
+ public static final int CB_BA_MO = 8;
+ // Barring of Incoming Services (Service Code 353 - 3GPP TS 22.030 Table B-1)
+ public static final int CB_BA_MT = 9;
+ // Barring of Specific Incoming calls
+ public static final int CB_BS_MT = 10;
+
+ /**
+ * Invalid result value.
+ */
+ public static final int INVALID = (-1);
+
+
+
+ /**
+ * Operations for the supplementary service configuration
+ */
+
+ /**
+ * Retrieves the configuration of the call barring.
+ * The return value of ((AsyncResult)result.obj) is an array of {@link ImsSsInfo}.
+ */
+ public void queryCallBarring(int cbType, Message result);
+
+ /**
+ * Retrieves the configuration of the call forward.
+ * The return value of ((AsyncResult)result.obj) is an array of {@link ImsCallForwardInfo}.
+ */
+ public void queryCallForward(int condition, String number, Message result);
+
+ /**
+ * Retrieves the configuration of the call waiting.
+ * The return value of ((AsyncResult)result.obj) is an array of {@link ImsSsInfo}.
+ */
+ public void queryCallWaiting(Message result);
+
+ /**
+ * Retrieves the default CLIR setting.
+ */
+ public void queryCLIR(Message result);
+
+ /**
+ * Retrieves the CLIP call setting.
+ */
+ public void queryCLIP(Message result);
+
+ /**
+ * Retrieves the COLR call setting.
+ */
+ public void queryCOLR(Message result);
+
+ /**
+ * Retrieves the COLP call setting.
+ */
+ public void queryCOLP(Message result);
+
+ /**
+ * Modifies the configuration of the call barring.
+ */
+ public void updateCallBarring(int cbType, int action,
+ Message result, String[] barrList);
+
+ /**
+ * Modifies the configuration of the call forward.
+ */
+ public void updateCallForward(int action, int condition, String number,
+ int serviceClass, int timeSeconds, Message result);
+
+ /**
+ * Modifies the configuration of the call waiting.
+ */
+ public void updateCallWaiting(boolean enable, int serviceClass, Message result);
+
+ /**
+ * Updates the configuration of the CLIR supplementary service.
+ */
+ public void updateCLIR(int clirMode, Message result);
+
+ /**
+ * Updates the configuration of the CLIP supplementary service.
+ */
+ public void updateCLIP(boolean enable, Message result);
+
+ /**
+ * Updates the configuration of the COLR supplementary service.
+ */
+ public void updateCOLR(int presentation, Message result);
+
+ /**
+ * Updates the configuration of the COLP supplementary service.
+ */
+ public void updateCOLP(boolean enable, Message result);
+}
diff --git a/telephony/java/com/android/ims/internal/IImsFeatureStatusCallback.aidl b/telephony/java/com/android/ims/internal/IImsFeatureStatusCallback.aidl
new file mode 100644
index 0000000..41b1042
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/IImsFeatureStatusCallback.aidl
@@ -0,0 +1,25 @@
+/*
+ * 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.ims.internal;
+
+/**
+* Interface from ImsFeature in the ImsService to ImsServiceController.
+ * {@hide}
+ */
+oneway interface IImsFeatureStatusCallback {
+ void notifyImsFeatureStatus(int featureStatus);
+}
\ No newline at end of file
diff --git a/telephony/java/com/android/ims/internal/IImsServiceController.aidl b/telephony/java/com/android/ims/internal/IImsServiceController.aidl
index fa86a43..712816f 100644
--- a/telephony/java/com/android/ims/internal/IImsServiceController.aidl
+++ b/telephony/java/com/android/ims/internal/IImsServiceController.aidl
@@ -16,10 +16,49 @@
package com.android.ims.internal;
+import android.app.PendingIntent;
+
+import com.android.ims.ImsCallProfile;
+import com.android.ims.internal.IImsCallSession;
+import com.android.ims.internal.IImsCallSessionListener;
+import com.android.ims.internal.IImsConfig;
+import com.android.ims.internal.IImsEcbm;
+import com.android.ims.internal.IImsFeatureStatusCallback;
+import com.android.ims.internal.IImsMultiEndpoint;
+import com.android.ims.internal.IImsRegistrationListener;
+import com.android.ims.internal.IImsUt;
+
+import android.os.Message;
+
/**
+ * See ImsService and IMMTelFeature for more information.
* {@hide}
*/
interface IImsServiceController {
- void createImsFeature(int slotId, int feature);
+ // ImsService Control
+ void createImsFeature(int slotId, int feature, IImsFeatureStatusCallback c);
void removeImsFeature(int slotId, int feature);
+ // MMTel Feature
+ int startSession(int slotId, int featureType, in PendingIntent incomingCallIntent,
+ in IImsRegistrationListener listener);
+ void endSession(int slotId, int featureType, int sessionId);
+ boolean isConnected(int slotId, int featureType, int callSessionType, int callType);
+ boolean isOpened(int slotId, int featureType);
+ int getFeatureStatus(int slotId, int featureType);
+ void addRegistrationListener(int slotId, int featureType, in IImsRegistrationListener listener);
+ void removeRegistrationListener(int slotId, int featureType,
+ in IImsRegistrationListener listener);
+ ImsCallProfile createCallProfile(int slotId, int featureType, int sessionId,
+ int callSessionType, int callType);
+ IImsCallSession createCallSession(int slotId, int featureType, int sessionId,
+ in ImsCallProfile profile, IImsCallSessionListener listener);
+ IImsCallSession getPendingCallSession(int slotId, int featureType, int sessionId,
+ String callId);
+ IImsUt getUtInterface(int slotId, int featureType);
+ IImsConfig getConfigInterface(int slotId, int featureType);
+ void turnOnIms(int slotId, int featureType);
+ void turnOffIms(int slotId, int featureType);
+ IImsEcbm getEcbmInterface(int slotId, int featureType);
+ void setUiTTYMode(int slotId, int featureType, int uiTtyMode, in Message onComplete);
+ IImsMultiEndpoint getMultiEndpointInterface(int slotId, int featureType);
}
diff --git a/telephony/java/com/android/ims/internal/IImsServiceFeatureListener.aidl b/telephony/java/com/android/ims/internal/IImsServiceFeatureListener.aidl
index 0a36b6b..df10700 100644
--- a/telephony/java/com/android/ims/internal/IImsServiceFeatureListener.aidl
+++ b/telephony/java/com/android/ims/internal/IImsServiceFeatureListener.aidl
@@ -17,9 +17,12 @@
package com.android.ims.internal;
/**
+ * Interface from ImsResolver to ImsServiceProxy in ImsManager.
+ * Callback to ImsManager when a feature changes in the ImsServiceController.
* {@hide}
*/
oneway interface IImsServiceFeatureListener {
void imsFeatureCreated(int slotId, int feature);
void imsFeatureRemoved(int slotId, int feature);
+ void imsStatusChanged(int slotId, int feature, int status);
}
\ No newline at end of file
diff --git a/telephony/java/com/android/ims/internal/ImsCallSession.java b/telephony/java/com/android/ims/internal/ImsCallSession.java
new file mode 100644
index 0000000..8196b23
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/ImsCallSession.java
@@ -0,0 +1,1290 @@
+/*
+ * Copyright (c) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ims.internal;
+
+import android.os.Message;
+import android.os.RemoteException;
+
+import java.util.Objects;
+
+import android.telephony.ims.stub.ImsCallSessionListenerImplBase;
+import android.util.Log;
+import com.android.ims.ImsCallProfile;
+import com.android.ims.ImsConferenceState;
+import com.android.ims.ImsReasonInfo;
+import com.android.ims.ImsStreamMediaProfile;
+import com.android.ims.ImsSuppServiceNotification;
+
+/**
+ * Provides the call initiation/termination, and media exchange between two IMS endpoints.
+ * It directly communicates with IMS service which implements the IMS protocol behavior.
+ *
+ * @hide
+ */
+public class ImsCallSession {
+ private static final String TAG = "ImsCallSession";
+
+ /**
+ * Defines IMS call session state.
+ */
+ public static class State {
+ public static final int IDLE = 0;
+ public static final int INITIATED = 1;
+ public static final int NEGOTIATING = 2;
+ public static final int ESTABLISHING = 3;
+ public static final int ESTABLISHED = 4;
+
+ public static final int RENEGOTIATING = 5;
+ public static final int REESTABLISHING = 6;
+
+ public static final int TERMINATING = 7;
+ public static final int TERMINATED = 8;
+
+ public static final int INVALID = (-1);
+
+ /**
+ * Converts the state to string.
+ */
+ public static String toString(int state) {
+ switch (state) {
+ case IDLE:
+ return "IDLE";
+ case INITIATED:
+ return "INITIATED";
+ case NEGOTIATING:
+ return "NEGOTIATING";
+ case ESTABLISHING:
+ return "ESTABLISHING";
+ case ESTABLISHED:
+ return "ESTABLISHED";
+ case RENEGOTIATING:
+ return "RENEGOTIATING";
+ case REESTABLISHING:
+ return "REESTABLISHING";
+ case TERMINATING:
+ return "TERMINATING";
+ case TERMINATED:
+ return "TERMINATED";
+ default:
+ return "UNKNOWN";
+ }
+ }
+
+ private State() {
+ }
+ }
+
+ /**
+ * Listener for events relating to an IMS session, such as when a session is being
+ * recieved ("on ringing") or a call is outgoing ("on calling").
+ * <p>Many of these events are also received by {@link ImsCall.Listener}.</p>
+ */
+ public static class Listener {
+ /**
+ * Called when a request is sent out to initiate a new session
+ * and 1xx response is received from the network.
+ *
+ * @param session the session object that carries out the IMS session
+ */
+ public void callSessionProgressing(ImsCallSession session,
+ ImsStreamMediaProfile profile) {
+ // no-op
+ }
+
+ /**
+ * Called when the session is established.
+ *
+ * @param session the session object that carries out the IMS session
+ */
+ public void callSessionStarted(ImsCallSession session,
+ ImsCallProfile profile) {
+ // no-op
+ }
+
+ /**
+ * Called when the session establishment is failed.
+ *
+ * @param session the session object that carries out the IMS session
+ * @param reasonInfo detailed reason of the session establishment failure
+ */
+ public void callSessionStartFailed(ImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ }
+
+ /**
+ * Called when the session is terminated.
+ *
+ * @param session the session object that carries out the IMS session
+ * @param reasonInfo detailed reason of the session termination
+ */
+ public void callSessionTerminated(ImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ }
+
+ /**
+ * Called when the session is in hold.
+ *
+ * @param session the session object that carries out the IMS session
+ */
+ public void callSessionHeld(ImsCallSession session,
+ ImsCallProfile profile) {
+ }
+
+ /**
+ * Called when the session hold is failed.
+ *
+ * @param session the session object that carries out the IMS session
+ * @param reasonInfo detailed reason of the session hold failure
+ */
+ public void callSessionHoldFailed(ImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ }
+
+ /**
+ * Called when the session hold is received from the remote user.
+ *
+ * @param session the session object that carries out the IMS session
+ */
+ public void callSessionHoldReceived(ImsCallSession session,
+ ImsCallProfile profile) {
+ }
+
+ /**
+ * Called when the session resume is done.
+ *
+ * @param session the session object that carries out the IMS session
+ */
+ public void callSessionResumed(ImsCallSession session,
+ ImsCallProfile profile) {
+ }
+
+ /**
+ * Called when the session resume is failed.
+ *
+ * @param session the session object that carries out the IMS session
+ * @param reasonInfo detailed reason of the session resume failure
+ */
+ public void callSessionResumeFailed(ImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ }
+
+ /**
+ * Called when the session resume is received from the remote user.
+ *
+ * @param session the session object that carries out the IMS session
+ */
+ public void callSessionResumeReceived(ImsCallSession session,
+ ImsCallProfile profile) {
+ }
+
+ /**
+ * Called when the session merge has been started. At this point, the {@code newSession}
+ * represents the session which has been initiated to the IMS conference server for the
+ * new merged conference.
+ *
+ * @param session the session object that carries out the IMS session
+ * @param newSession the session object that is merged with an active & hold session
+ */
+ public void callSessionMergeStarted(ImsCallSession session,
+ ImsCallSession newSession, ImsCallProfile profile) {
+ }
+
+ /**
+ * Called when the session merge is successful and the merged session is active.
+ *
+ * @param session the session object that carries out the IMS session
+ */
+ public void callSessionMergeComplete(ImsCallSession session) {
+ }
+
+ /**
+ * Called when the session merge has failed.
+ *
+ * @param session the session object that carries out the IMS session
+ * @param reasonInfo detailed reason of the call merge failure
+ */
+ public void callSessionMergeFailed(ImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ }
+
+ /**
+ * Called when the session is updated (except for hold/unhold).
+ *
+ * @param session the session object that carries out the IMS session
+ */
+ public void callSessionUpdated(ImsCallSession session,
+ ImsCallProfile profile) {
+ }
+
+ /**
+ * Called when the session update is failed.
+ *
+ * @param session the session object that carries out the IMS session
+ * @param reasonInfo detailed reason of the session update failure
+ */
+ public void callSessionUpdateFailed(ImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ }
+
+ /**
+ * Called when the session update is received from the remote user.
+ *
+ * @param session the session object that carries out the IMS session
+ */
+ public void callSessionUpdateReceived(ImsCallSession session,
+ ImsCallProfile profile) {
+ // no-op
+ }
+
+ /**
+ * Called when the session is extended to the conference session.
+ *
+ * @param session the session object that carries out the IMS session
+ * @param newSession the session object that is extended to the conference
+ * from the active session
+ */
+ public void callSessionConferenceExtended(ImsCallSession session,
+ ImsCallSession newSession, ImsCallProfile profile) {
+ }
+
+ /**
+ * Called when the conference extension is failed.
+ *
+ * @param session the session object that carries out the IMS session
+ * @param reasonInfo detailed reason of the conference extension failure
+ */
+ public void callSessionConferenceExtendFailed(ImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ }
+
+ /**
+ * Called when the conference extension is received from the remote user.
+ *
+ * @param session the session object that carries out the IMS session
+ */
+ public void callSessionConferenceExtendReceived(ImsCallSession session,
+ ImsCallSession newSession, ImsCallProfile profile) {
+ // no-op
+ }
+
+ /**
+ * Called when the invitation request of the participants is delivered to the conference
+ * server.
+ *
+ * @param session the session object that carries out the IMS session
+ */
+ public void callSessionInviteParticipantsRequestDelivered(ImsCallSession session) {
+ // no-op
+ }
+
+ /**
+ * Called when the invitation request of the participants is failed.
+ *
+ * @param session the session object that carries out the IMS session
+ * @param reasonInfo detailed reason of the conference invitation failure
+ */
+ public void callSessionInviteParticipantsRequestFailed(ImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ // no-op
+ }
+
+ /**
+ * Called when the removal request of the participants is delivered to the conference
+ * server.
+ *
+ * @param session the session object that carries out the IMS session
+ */
+ public void callSessionRemoveParticipantsRequestDelivered(ImsCallSession session) {
+ // no-op
+ }
+
+ /**
+ * Called when the removal request of the participants is failed.
+ *
+ * @param session the session object that carries out the IMS session
+ * @param reasonInfo detailed reason of the conference removal failure
+ */
+ public void callSessionRemoveParticipantsRequestFailed(ImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ // no-op
+ }
+
+ /**
+ * Called when the conference state is updated.
+ *
+ * @param session the session object that carries out the IMS session
+ */
+ public void callSessionConferenceStateUpdated(ImsCallSession session,
+ ImsConferenceState state) {
+ // no-op
+ }
+
+ /**
+ * Called when the USSD message is received from the network.
+ *
+ * @param mode mode of the USSD message (REQUEST / NOTIFY)
+ * @param ussdMessage USSD message
+ */
+ public void callSessionUssdMessageReceived(ImsCallSession session,
+ int mode, String ussdMessage) {
+ // no-op
+ }
+
+ /**
+ * Called when session access technology changes
+ *
+ * @param session IMS session object
+ * @param srcAccessTech original access technology
+ * @param targetAccessTech new access technology
+ * @param reasonInfo
+ */
+ public void callSessionHandover(ImsCallSession session,
+ int srcAccessTech, int targetAccessTech,
+ ImsReasonInfo reasonInfo) {
+ // no-op
+ }
+
+ /**
+ * Called when session access technology change fails
+ *
+ * @param session IMS session object
+ * @param srcAccessTech original access technology
+ * @param targetAccessTech new access technology
+ * @param reasonInfo handover failure reason
+ */
+ public void callSessionHandoverFailed(ImsCallSession session,
+ int srcAccessTech, int targetAccessTech,
+ ImsReasonInfo reasonInfo) {
+ // no-op
+ }
+
+ /**
+ * Called when TTY mode of remote party changed
+ *
+ * @param session IMS session object
+ * @param mode TTY mode of remote party
+ */
+ public void callSessionTtyModeReceived(ImsCallSession session,
+ int mode) {
+ // no-op
+ }
+
+ /**
+ * Notifies of a change to the multiparty state for this {@code ImsCallSession}.
+ *
+ * @param session The call session.
+ * @param isMultiParty {@code true} if the session became multiparty, {@code false}
+ * otherwise.
+ */
+ public void callSessionMultipartyStateChanged(ImsCallSession session,
+ boolean isMultiParty) {
+ // no-op
+ }
+
+ /**
+ * Called when the session supplementary service is received
+ *
+ * @param session the session object that carries out the IMS session
+ */
+ public void callSessionSuppServiceReceived(ImsCallSession session,
+ ImsSuppServiceNotification suppServiceInfo) {
+ }
+ }
+
+ private final IImsCallSession miSession;
+ private boolean mClosed = false;
+ private Listener mListener;
+
+ public ImsCallSession(IImsCallSession iSession) {
+ miSession = iSession;
+
+ if (iSession != null) {
+ try {
+ iSession.setListener(new IImsCallSessionListenerProxy());
+ } catch (RemoteException e) {
+ }
+ } else {
+ mClosed = true;
+ }
+ }
+
+ public ImsCallSession(IImsCallSession iSession, Listener listener) {
+ this(iSession);
+ setListener(listener);
+ }
+
+ /**
+ * Closes this object. This object is not usable after being closed.
+ */
+ public synchronized void close() {
+ if (mClosed) {
+ return;
+ }
+
+ try {
+ miSession.close();
+ mClosed = true;
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Gets the call ID of the session.
+ *
+ * @return the call ID
+ */
+ public String getCallId() {
+ if (mClosed) {
+ return null;
+ }
+
+ try {
+ return miSession.getCallId();
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the call profile that this session is associated with
+ *
+ * @return the call profile that this session is associated with
+ */
+ public ImsCallProfile getCallProfile() {
+ if (mClosed) {
+ return null;
+ }
+
+ try {
+ return miSession.getCallProfile();
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the local call profile that this session is associated with
+ *
+ * @return the local call profile that this session is associated with
+ */
+ public ImsCallProfile getLocalCallProfile() {
+ if (mClosed) {
+ return null;
+ }
+
+ try {
+ return miSession.getLocalCallProfile();
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the remote call profile that this session is associated with
+ *
+ * @return the remote call profile that this session is associated with
+ */
+ public ImsCallProfile getRemoteCallProfile() {
+ if (mClosed) {
+ return null;
+ }
+
+ try {
+ return miSession.getRemoteCallProfile();
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the video call provider for the session.
+ *
+ * @return The video call provider.
+ */
+ public IImsVideoCallProvider getVideoCallProvider() {
+ if (mClosed) {
+ return null;
+ }
+
+ try {
+ return miSession.getVideoCallProvider();
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the value associated with the specified property of this session.
+ *
+ * @return the string value associated with the specified property
+ */
+ public String getProperty(String name) {
+ if (mClosed) {
+ return null;
+ }
+
+ try {
+ return miSession.getProperty(name);
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the session state.
+ * The value returned must be one of the states in {@link State}.
+ *
+ * @return the session state
+ */
+ public int getState() {
+ if (mClosed) {
+ return State.INVALID;
+ }
+
+ try {
+ return miSession.getState();
+ } catch (RemoteException e) {
+ return State.INVALID;
+ }
+ }
+
+ /**
+ * Determines if the {@link ImsCallSession} is currently alive (e.g. not in a terminated or
+ * closed state).
+ *
+ * @return {@code True} if the session is alive.
+ */
+ public boolean isAlive() {
+ if (mClosed) {
+ return false;
+ }
+
+ int state = getState();
+ switch (state) {
+ case State.IDLE:
+ case State.INITIATED:
+ case State.NEGOTIATING:
+ case State.ESTABLISHING:
+ case State.ESTABLISHED:
+ case State.RENEGOTIATING:
+ case State.REESTABLISHING:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ /**
+ * Gets the native IMS call session.
+ * @hide
+ */
+ public IImsCallSession getSession() {
+ return miSession;
+ }
+
+ /**
+ * Checks if the session is in call.
+ *
+ * @return true if the session is in call
+ */
+ public boolean isInCall() {
+ if (mClosed) {
+ return false;
+ }
+
+ try {
+ return miSession.isInCall();
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Sets the listener to listen to the session events. A {@link ImsCallSession}
+ * can only hold one listener at a time. Subsequent calls to this method
+ * override the previous listener.
+ *
+ * @param listener to listen to the session events of this object
+ */
+ public void setListener(Listener listener) {
+ mListener = listener;
+ }
+
+ /**
+ * Mutes or unmutes the mic for the active call.
+ *
+ * @param muted true if the call is muted, false otherwise
+ */
+ public void setMute(boolean muted) {
+ if (mClosed) {
+ return;
+ }
+
+ try {
+ miSession.setMute(muted);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Initiates an IMS call with the specified target and call profile.
+ * The session listener is called back upon defined session events.
+ * The method is only valid to call when the session state is in
+ * {@link ImsCallSession.State#IDLE}.
+ *
+ * @param callee dialed string to make the call to
+ * @param profile call profile to make the call with the specified service type,
+ * call type and media information
+ * @see Listener#callSessionStarted, Listener#callSessionStartFailed
+ */
+ public void start(String callee, ImsCallProfile profile) {
+ if (mClosed) {
+ return;
+ }
+
+ try {
+ miSession.start(callee, profile);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Initiates an IMS conference call with the specified target and call profile.
+ * The session listener is called back upon defined session events.
+ * The method is only valid to call when the session state is in
+ * {@link ImsCallSession.State#IDLE}.
+ *
+ * @param participants participant list to initiate an IMS conference call
+ * @param profile call profile to make the call with the specified service type,
+ * call type and media information
+ * @see Listener#callSessionStarted, Listener#callSessionStartFailed
+ */
+ public void start(String[] participants, ImsCallProfile profile) {
+ if (mClosed) {
+ return;
+ }
+
+ try {
+ miSession.startConference(participants, profile);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Accepts an incoming call or session update.
+ *
+ * @param callType call type specified in {@link ImsCallProfile} to be answered
+ * @param profile stream media profile {@link ImsStreamMediaProfile} to be answered
+ * @see Listener#callSessionStarted
+ */
+ public void accept(int callType, ImsStreamMediaProfile profile) {
+ if (mClosed) {
+ return;
+ }
+
+ try {
+ miSession.accept(callType, profile);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Rejects an incoming call or session update.
+ *
+ * @param reason reason code to reject an incoming call
+ * @see Listener#callSessionStartFailed
+ */
+ public void reject(int reason) {
+ if (mClosed) {
+ return;
+ }
+
+ try {
+ miSession.reject(reason);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Terminates a call.
+ *
+ * @see Listener#callSessionTerminated
+ */
+ public void terminate(int reason) {
+ if (mClosed) {
+ return;
+ }
+
+ try {
+ miSession.terminate(reason);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Puts a call on hold. When it succeeds, {@link Listener#callSessionHeld} is called.
+ *
+ * @param profile stream media profile {@link ImsStreamMediaProfile} to hold the call
+ * @see Listener#callSessionHeld, Listener#callSessionHoldFailed
+ */
+ public void hold(ImsStreamMediaProfile profile) {
+ if (mClosed) {
+ return;
+ }
+
+ try {
+ miSession.hold(profile);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Continues a call that's on hold. When it succeeds,
+ * {@link Listener#callSessionResumed} is called.
+ *
+ * @param profile stream media profile {@link ImsStreamMediaProfile} to resume the call
+ * @see Listener#callSessionResumed, Listener#callSessionResumeFailed
+ */
+ public void resume(ImsStreamMediaProfile profile) {
+ if (mClosed) {
+ return;
+ }
+
+ try {
+ miSession.resume(profile);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Merges the active & hold call. When it succeeds,
+ * {@link Listener#callSessionMergeStarted} is called.
+ *
+ * @see Listener#callSessionMergeStarted , Listener#callSessionMergeFailed
+ */
+ public void merge() {
+ if (mClosed) {
+ return;
+ }
+
+ try {
+ miSession.merge();
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Updates the current call's properties (ex. call mode change: video upgrade / downgrade).
+ *
+ * @param callType call type specified in {@link ImsCallProfile} to be updated
+ * @param profile stream media profile {@link ImsStreamMediaProfile} to be updated
+ * @see Listener#callSessionUpdated, Listener#callSessionUpdateFailed
+ */
+ public void update(int callType, ImsStreamMediaProfile profile) {
+ if (mClosed) {
+ return;
+ }
+
+ try {
+ miSession.update(callType, profile);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Extends this call to the conference call with the specified recipients.
+ *
+ * @param participants list to be invited to the conference call after extending the call
+ * @see Listener#callSessionConferenceExtended
+ * @see Listener#callSessionConferenceExtendFailed
+ */
+ public void extendToConference(String[] participants) {
+ if (mClosed) {
+ return;
+ }
+
+ try {
+ miSession.extendToConference(participants);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Requests the conference server to invite an additional participants to the conference.
+ *
+ * @param participants list to be invited to the conference call
+ * @see Listener#callSessionInviteParticipantsRequestDelivered
+ * @see Listener#callSessionInviteParticipantsRequestFailed
+ */
+ public void inviteParticipants(String[] participants) {
+ if (mClosed) {
+ return;
+ }
+
+ try {
+ miSession.inviteParticipants(participants);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Requests the conference server to remove the specified participants from the conference.
+ *
+ * @param participants participant list to be removed from the conference call
+ * @see Listener#callSessionRemoveParticipantsRequestDelivered
+ * @see Listener#callSessionRemoveParticipantsRequestFailed
+ */
+ public void removeParticipants(String[] participants) {
+ if (mClosed) {
+ return;
+ }
+
+ try {
+ miSession.removeParticipants(participants);
+ } catch (RemoteException e) {
+ }
+ }
+
+
+ /**
+ * Sends a DTMF code. According to <a href="http://tools.ietf.org/html/rfc2833">RFC 2833</a>,
+ * event 0 ~ 9 maps to decimal value 0 ~ 9, '*' to 10, '#' to 11, event 'A' ~ 'D' to 12 ~ 15,
+ * and event flash to 16. Currently, event flash is not supported.
+ *
+ * @param c the DTMF to send. '0' ~ '9', 'A' ~ 'D', '*', '#' are valid inputs.
+ */
+ public void sendDtmf(char c, Message result) {
+ if (mClosed) {
+ return;
+ }
+
+ try {
+ miSession.sendDtmf(c, result);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Starts a DTMF code. According to <a href="http://tools.ietf.org/html/rfc2833">RFC 2833</a>,
+ * event 0 ~ 9 maps to decimal value 0 ~ 9, '*' to 10, '#' to 11, event 'A' ~ 'D' to 12 ~ 15,
+ * and event flash to 16. Currently, event flash is not supported.
+ *
+ * @param c the DTMF to send. '0' ~ '9', 'A' ~ 'D', '*', '#' are valid inputs.
+ */
+ public void startDtmf(char c) {
+ if (mClosed) {
+ return;
+ }
+
+ try {
+ miSession.startDtmf(c);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Stops a DTMF code.
+ */
+ public void stopDtmf() {
+ if (mClosed) {
+ return;
+ }
+
+ try {
+ miSession.stopDtmf();
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Sends an USSD message.
+ *
+ * @param ussdMessage USSD message to send
+ */
+ public void sendUssd(String ussdMessage) {
+ if (mClosed) {
+ return;
+ }
+
+ try {
+ miSession.sendUssd(ussdMessage);
+ } catch (RemoteException e) {
+ }
+ }
+
+ /**
+ * Determines if the session is multiparty.
+ *
+ * @return {@code True} if the session is multiparty.
+ */
+ public boolean isMultiparty() {
+ if (mClosed) {
+ return false;
+ }
+
+ try {
+ return miSession.isMultiparty();
+ } catch (RemoteException e) {
+ return false;
+ }
+ }
+
+ /**
+ * A listener type for receiving notification on IMS call session events.
+ * When an event is generated for an {@link IImsCallSession},
+ * the application is notified by having one of the methods called on
+ * the {@link IImsCallSessionListener}.
+ */
+ private class IImsCallSessionListenerProxy extends ImsCallSessionListenerImplBase {
+ /**
+ * Notifies the result of the basic session operation (setup / terminate).
+ */
+ @Override
+ public void callSessionProgressing(IImsCallSession session,
+ ImsStreamMediaProfile profile) {
+ if (mListener != null) {
+ mListener.callSessionProgressing(ImsCallSession.this, profile);
+ }
+ }
+
+ @Override
+ public void callSessionStarted(IImsCallSession session,
+ ImsCallProfile profile) {
+ if (mListener != null) {
+ mListener.callSessionStarted(ImsCallSession.this, profile);
+ }
+ }
+
+ @Override
+ public void callSessionStartFailed(IImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ if (mListener != null) {
+ mListener.callSessionStartFailed(ImsCallSession.this, reasonInfo);
+ }
+ }
+
+ @Override
+ public void callSessionTerminated(IImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ if (mListener != null) {
+ mListener.callSessionTerminated(ImsCallSession.this, reasonInfo);
+ }
+ }
+
+ /**
+ * Notifies the result of the call hold/resume operation.
+ */
+ @Override
+ public void callSessionHeld(IImsCallSession session,
+ ImsCallProfile profile) {
+ if (mListener != null) {
+ mListener.callSessionHeld(ImsCallSession.this, profile);
+ }
+ }
+
+ @Override
+ public void callSessionHoldFailed(IImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ if (mListener != null) {
+ mListener.callSessionHoldFailed(ImsCallSession.this, reasonInfo);
+ }
+ }
+
+ @Override
+ public void callSessionHoldReceived(IImsCallSession session,
+ ImsCallProfile profile) {
+ if (mListener != null) {
+ mListener.callSessionHoldReceived(ImsCallSession.this, profile);
+ }
+ }
+
+ @Override
+ public void callSessionResumed(IImsCallSession session,
+ ImsCallProfile profile) {
+ if (mListener != null) {
+ mListener.callSessionResumed(ImsCallSession.this, profile);
+ }
+ }
+
+ @Override
+ public void callSessionResumeFailed(IImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ if (mListener != null) {
+ mListener.callSessionResumeFailed(ImsCallSession.this, reasonInfo);
+ }
+ }
+
+ @Override
+ public void callSessionResumeReceived(IImsCallSession session,
+ ImsCallProfile profile) {
+ if (mListener != null) {
+ mListener.callSessionResumeReceived(ImsCallSession.this, profile);
+ }
+ }
+
+ /**
+ * Notifies the start of a call merge operation.
+ *
+ * @param session The call session.
+ * @param newSession The merged call session.
+ * @param profile The call profile.
+ */
+ @Override
+ public void callSessionMergeStarted(IImsCallSession session,
+ IImsCallSession newSession, ImsCallProfile profile) {
+ // This callback can be used for future use to add additional
+ // functionality that may be needed between conference start and complete
+ Log.d(TAG, "callSessionMergeStarted");
+ }
+
+ /**
+ * Notifies the successful completion of a call merge operation.
+ *
+ * @param newSession The call session.
+ */
+ @Override
+ public void callSessionMergeComplete(IImsCallSession newSession) {
+ if (mListener != null) {
+ if (newSession != null) {
+ // Check if the active session is the same session that was
+ // active before the merge request was sent.
+ ImsCallSession validActiveSession = ImsCallSession.this;
+ try {
+ if (!Objects.equals(miSession.getCallId(), newSession.getCallId())) {
+ // New session created after conference
+ validActiveSession = new ImsCallSession(newSession);
+ }
+ } catch (RemoteException rex) {
+ Log.e(TAG, "callSessionMergeComplete: exception for getCallId!");
+ }
+ mListener.callSessionMergeComplete(validActiveSession);
+ } else {
+ // Session already exists. Hence no need to pass
+ mListener.callSessionMergeComplete(null);
+ }
+ }
+ }
+
+ /**
+ * Notifies of a failure to perform a call merge operation.
+ *
+ * @param session The call session.
+ * @param reasonInfo The merge failure reason.
+ */
+ @Override
+ public void callSessionMergeFailed(IImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ if (mListener != null) {
+ mListener.callSessionMergeFailed(ImsCallSession.this, reasonInfo);
+ }
+ }
+
+ /**
+ * Notifies the result of call upgrade / downgrade or any other call updates.
+ */
+ @Override
+ public void callSessionUpdated(IImsCallSession session,
+ ImsCallProfile profile) {
+ if (mListener != null) {
+ mListener.callSessionUpdated(ImsCallSession.this, profile);
+ }
+ }
+
+ @Override
+ public void callSessionUpdateFailed(IImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ if (mListener != null) {
+ mListener.callSessionUpdateFailed(ImsCallSession.this, reasonInfo);
+ }
+ }
+
+ @Override
+ public void callSessionUpdateReceived(IImsCallSession session,
+ ImsCallProfile profile) {
+ if (mListener != null) {
+ mListener.callSessionUpdateReceived(ImsCallSession.this, profile);
+ }
+ }
+
+ /**
+ * Notifies the result of conference extension.
+ */
+ @Override
+ public void callSessionConferenceExtended(IImsCallSession session,
+ IImsCallSession newSession, ImsCallProfile profile) {
+ if (mListener != null) {
+ mListener.callSessionConferenceExtended(ImsCallSession.this,
+ new ImsCallSession(newSession), profile);
+ }
+ }
+
+ @Override
+ public void callSessionConferenceExtendFailed(IImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ if (mListener != null) {
+ mListener.callSessionConferenceExtendFailed(ImsCallSession.this, reasonInfo);
+ }
+ }
+
+ @Override
+ public void callSessionConferenceExtendReceived(IImsCallSession session,
+ IImsCallSession newSession, ImsCallProfile profile) {
+ if (mListener != null) {
+ mListener.callSessionConferenceExtendReceived(ImsCallSession.this,
+ new ImsCallSession(newSession), profile);
+ }
+ }
+
+ /**
+ * Notifies the result of the participant invitation / removal to/from
+ * the conference session.
+ */
+ @Override
+ public void callSessionInviteParticipantsRequestDelivered(IImsCallSession session) {
+ if (mListener != null) {
+ mListener.callSessionInviteParticipantsRequestDelivered(ImsCallSession.this);
+ }
+ }
+
+ @Override
+ public void callSessionInviteParticipantsRequestFailed(IImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ if (mListener != null) {
+ mListener.callSessionInviteParticipantsRequestFailed(ImsCallSession.this,
+ reasonInfo);
+ }
+ }
+
+ @Override
+ public void callSessionRemoveParticipantsRequestDelivered(IImsCallSession session) {
+ if (mListener != null) {
+ mListener.callSessionRemoveParticipantsRequestDelivered(ImsCallSession.this);
+ }
+ }
+
+ @Override
+ public void callSessionRemoveParticipantsRequestFailed(IImsCallSession session,
+ ImsReasonInfo reasonInfo) {
+ if (mListener != null) {
+ mListener.callSessionRemoveParticipantsRequestFailed(ImsCallSession.this,
+ reasonInfo);
+ }
+ }
+
+ /**
+ * Notifies the changes of the conference info. in the conference session.
+ */
+ @Override
+ public void callSessionConferenceStateUpdated(IImsCallSession session,
+ ImsConferenceState state) {
+ if (mListener != null) {
+ mListener.callSessionConferenceStateUpdated(ImsCallSession.this, state);
+ }
+ }
+
+ /**
+ * Notifies the incoming USSD message.
+ */
+ @Override
+ public void callSessionUssdMessageReceived(IImsCallSession session,
+ int mode, String ussdMessage) {
+ if (mListener != null) {
+ mListener.callSessionUssdMessageReceived(ImsCallSession.this, mode, ussdMessage);
+ }
+ }
+
+ /**
+ * Notifies of handover information for this call
+ */
+ @Override
+ public void callSessionHandover(IImsCallSession session,
+ int srcAccessTech, int targetAccessTech,
+ ImsReasonInfo reasonInfo) {
+ if (mListener != null) {
+ mListener.callSessionHandover(ImsCallSession.this, srcAccessTech,
+ targetAccessTech, reasonInfo);
+ }
+ }
+
+ /**
+ * Notifies of handover failure info for this call
+ */
+ @Override
+ public void callSessionHandoverFailed(IImsCallSession session,
+ int srcAccessTech, int targetAccessTech,
+ ImsReasonInfo reasonInfo) {
+ if (mListener != null) {
+ mListener.callSessionHandoverFailed(ImsCallSession.this, srcAccessTech,
+ targetAccessTech, reasonInfo);
+ }
+ }
+
+ /**
+ * Notifies the TTY mode received from remote party.
+ */
+ @Override
+ public void callSessionTtyModeReceived(IImsCallSession session,
+ int mode) {
+ if (mListener != null) {
+ mListener.callSessionTtyModeReceived(ImsCallSession.this, mode);
+ }
+ }
+
+ /**
+ * Notifies of a change to the multiparty state for this {@code ImsCallSession}.
+ *
+ * @param session The call session.
+ * @param isMultiParty {@code true} if the session became multiparty, {@code false}
+ * otherwise.
+ */
+ public void callSessionMultipartyStateChanged(IImsCallSession session,
+ boolean isMultiParty) {
+
+ if (mListener != null) {
+ mListener.callSessionMultipartyStateChanged(ImsCallSession.this, isMultiParty);
+ }
+ }
+
+ @Override
+ public void callSessionSuppServiceReceived(IImsCallSession session,
+ ImsSuppServiceNotification suppServiceInfo ) {
+ if (mListener != null) {
+ mListener.callSessionSuppServiceReceived(ImsCallSession.this, suppServiceInfo);
+ }
+ }
+
+ }
+
+ /**
+ * Provides a string representation of the {@link ImsCallSession}. Primarily intended for
+ * use in log statements.
+ *
+ * @return String representation of session.
+ */
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("[ImsCallSession objId:");
+ sb.append(System.identityHashCode(this));
+ sb.append(" state:");
+ sb.append(State.toString(getState()));
+ sb.append(" callId:");
+ sb.append(getCallId());
+ sb.append("]");
+ return sb.toString();
+ }
+}
diff --git a/telephony/java/com/android/ims/internal/ImsVideoCallProvider.java b/telephony/java/com/android/ims/internal/ImsVideoCallProvider.java
new file mode 100644
index 0000000..432dc39
--- /dev/null
+++ b/telephony/java/com/android/ims/internal/ImsVideoCallProvider.java
@@ -0,0 +1,294 @@
+/*
+ * 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.ims.internal;
+
+import android.net.Uri;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.telecom.Connection;
+import android.telecom.VideoProfile;
+import android.telecom.VideoProfile.CameraCapabilities;
+import android.view.Surface;
+
+import com.android.internal.os.SomeArgs;
+
+/**
+ * @hide
+ */
+public abstract class ImsVideoCallProvider {
+ private static final int MSG_SET_CALLBACK = 1;
+ private static final int MSG_SET_CAMERA = 2;
+ private static final int MSG_SET_PREVIEW_SURFACE = 3;
+ private static final int MSG_SET_DISPLAY_SURFACE = 4;
+ private static final int MSG_SET_DEVICE_ORIENTATION = 5;
+ private static final int MSG_SET_ZOOM = 6;
+ private static final int MSG_SEND_SESSION_MODIFY_REQUEST = 7;
+ private static final int MSG_SEND_SESSION_MODIFY_RESPONSE = 8;
+ private static final int MSG_REQUEST_CAMERA_CAPABILITIES = 9;
+ private static final int MSG_REQUEST_CALL_DATA_USAGE = 10;
+ private static final int MSG_SET_PAUSE_IMAGE = 11;
+
+ private final ImsVideoCallProviderBinder mBinder;
+
+ private IImsVideoCallCallback mCallback;
+
+ /**
+ * Default handler used to consolidate binder method calls onto a single thread.
+ */
+ private final Handler mProviderHandler = new Handler(Looper.getMainLooper()) {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_SET_CALLBACK:
+ mCallback = (IImsVideoCallCallback) msg.obj;
+ break;
+ case MSG_SET_CAMERA:
+ {
+ SomeArgs args = (SomeArgs) msg.obj;
+ try {
+ onSetCamera((String) args.arg1);
+ onSetCamera((String) args.arg1, args.argi1);
+ } finally {
+ args.recycle();
+ }
+ break;
+ }
+ case MSG_SET_PREVIEW_SURFACE:
+ onSetPreviewSurface((Surface) msg.obj);
+ break;
+ case MSG_SET_DISPLAY_SURFACE:
+ onSetDisplaySurface((Surface) msg.obj);
+ break;
+ case MSG_SET_DEVICE_ORIENTATION:
+ onSetDeviceOrientation(msg.arg1);
+ break;
+ case MSG_SET_ZOOM:
+ onSetZoom((Float) msg.obj);
+ break;
+ case MSG_SEND_SESSION_MODIFY_REQUEST: {
+ SomeArgs args = (SomeArgs) msg.obj;
+ try {
+ VideoProfile fromProfile = (VideoProfile) args.arg1;
+ VideoProfile toProfile = (VideoProfile) args.arg2;
+
+ onSendSessionModifyRequest(fromProfile, toProfile);
+ } finally {
+ args.recycle();
+ }
+ break;
+ }
+ case MSG_SEND_SESSION_MODIFY_RESPONSE:
+ onSendSessionModifyResponse((VideoProfile) msg.obj);
+ break;
+ case MSG_REQUEST_CAMERA_CAPABILITIES:
+ onRequestCameraCapabilities();
+ break;
+ case MSG_REQUEST_CALL_DATA_USAGE:
+ onRequestCallDataUsage();
+ break;
+ case MSG_SET_PAUSE_IMAGE:
+ onSetPauseImage((Uri) msg.obj);
+ break;
+ default:
+ break;
+ }
+ }
+ };
+
+ /**
+ * IImsVideoCallProvider stub implementation.
+ */
+ private final class ImsVideoCallProviderBinder extends IImsVideoCallProvider.Stub {
+ public void setCallback(IImsVideoCallCallback callback) {
+ mProviderHandler.obtainMessage(MSG_SET_CALLBACK, callback).sendToTarget();
+ }
+
+ public void setCamera(String cameraId, int uid) {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = cameraId;
+ args.argi1 = uid;
+ mProviderHandler.obtainMessage(MSG_SET_CAMERA, args).sendToTarget();
+ }
+
+ public void setPreviewSurface(Surface surface) {
+ mProviderHandler.obtainMessage(MSG_SET_PREVIEW_SURFACE, surface).sendToTarget();
+ }
+
+ public void setDisplaySurface(Surface surface) {
+ mProviderHandler.obtainMessage(MSG_SET_DISPLAY_SURFACE, surface).sendToTarget();
+ }
+
+ public void setDeviceOrientation(int rotation) {
+ mProviderHandler.obtainMessage(MSG_SET_DEVICE_ORIENTATION, rotation, 0).sendToTarget();
+ }
+
+ public void setZoom(float value) {
+ mProviderHandler.obtainMessage(MSG_SET_ZOOM, value).sendToTarget();
+ }
+
+ public void sendSessionModifyRequest(VideoProfile fromProfile, VideoProfile toProfile) {
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = fromProfile;
+ args.arg2 = toProfile;
+ mProviderHandler.obtainMessage(MSG_SEND_SESSION_MODIFY_REQUEST, args).sendToTarget();
+ }
+
+ public void sendSessionModifyResponse(VideoProfile responseProfile) {
+ mProviderHandler.obtainMessage(
+ MSG_SEND_SESSION_MODIFY_RESPONSE, responseProfile).sendToTarget();
+ }
+
+ public void requestCameraCapabilities() {
+ mProviderHandler.obtainMessage(MSG_REQUEST_CAMERA_CAPABILITIES).sendToTarget();
+ }
+
+ public void requestCallDataUsage() {
+ mProviderHandler.obtainMessage(MSG_REQUEST_CALL_DATA_USAGE).sendToTarget();
+ }
+
+ public void setPauseImage(Uri uri) {
+ mProviderHandler.obtainMessage(MSG_SET_PAUSE_IMAGE, uri).sendToTarget();
+ }
+ }
+
+ public ImsVideoCallProvider() {
+ mBinder = new ImsVideoCallProviderBinder();
+ }
+
+ /**
+ * Returns binder object which can be used across IPC methods.
+ */
+ public final IImsVideoCallProvider getInterface() {
+ return mBinder;
+ }
+
+ /** @see Connection.VideoProvider#onSetCamera */
+ public abstract void onSetCamera(String cameraId);
+
+ /**
+ * Similar to {@link #onSetCamera(String)}, except includes the UID of the calling process which
+ * the IMS service uses when opening the camera. This ensures camera permissions are verified
+ * by the camera service.
+ *
+ * @param cameraId The id of the camera to be opened.
+ * @param uid The uid of the caller, used when opening the camera for permission verification.
+ * @see Connection.VideoProvider#onSetCamera
+ */
+ public void onSetCamera(String cameraId, int uid) {
+ }
+
+ /** @see Connection.VideoProvider#onSetPreviewSurface */
+ public abstract void onSetPreviewSurface(Surface surface);
+
+ /** @see Connection.VideoProvider#onSetDisplaySurface */
+ public abstract void onSetDisplaySurface(Surface surface);
+
+ /** @see Connection.VideoProvider#onSetDeviceOrientation */
+ public abstract void onSetDeviceOrientation(int rotation);
+
+ /** @see Connection.VideoProvider#onSetZoom */
+ public abstract void onSetZoom(float value);
+
+ /** @see Connection.VideoProvider#onSendSessionModifyRequest */
+ public abstract void onSendSessionModifyRequest(VideoProfile fromProfile,
+ VideoProfile toProfile);
+
+ /** @see Connection.VideoProvider#onSendSessionModifyResponse */
+ public abstract void onSendSessionModifyResponse(VideoProfile responseProfile);
+
+ /** @see Connection.VideoProvider#onRequestCameraCapabilities */
+ public abstract void onRequestCameraCapabilities();
+
+ /** @see Connection.VideoProvider#onRequestCallDataUsage */
+ public abstract void onRequestCallDataUsage();
+
+ /** @see Connection.VideoProvider#onSetPauseImage */
+ public abstract void onSetPauseImage(Uri uri);
+
+ /** @see Connection.VideoProvider#receiveSessionModifyRequest */
+ public void receiveSessionModifyRequest(VideoProfile VideoProfile) {
+ if (mCallback != null) {
+ try {
+ mCallback.receiveSessionModifyRequest(VideoProfile);
+ } catch (RemoteException ignored) {
+ }
+ }
+ }
+
+ /** @see Connection.VideoProvider#receiveSessionModifyResponse */
+ public void receiveSessionModifyResponse(
+ int status, VideoProfile requestedProfile, VideoProfile responseProfile) {
+ if (mCallback != null) {
+ try {
+ mCallback.receiveSessionModifyResponse(status, requestedProfile, responseProfile);
+ } catch (RemoteException ignored) {
+ }
+ }
+ }
+
+ /** @see Connection.VideoProvider#handleCallSessionEvent */
+ public void handleCallSessionEvent(int event) {
+ if (mCallback != null) {
+ try {
+ mCallback.handleCallSessionEvent(event);
+ } catch (RemoteException ignored) {
+ }
+ }
+ }
+
+ /** @see Connection.VideoProvider#changePeerDimensions */
+ public void changePeerDimensions(int width, int height) {
+ if (mCallback != null) {
+ try {
+ mCallback.changePeerDimensions(width, height);
+ } catch (RemoteException ignored) {
+ }
+ }
+ }
+
+ /** @see Connection.VideoProvider#changeCallDataUsage */
+ public void changeCallDataUsage(long dataUsage) {
+ if (mCallback != null) {
+ try {
+ mCallback.changeCallDataUsage(dataUsage);
+ } catch (RemoteException ignored) {
+ }
+ }
+ }
+
+ /** @see Connection.VideoProvider#changeCameraCapabilities */
+ public void changeCameraCapabilities(CameraCapabilities CameraCapabilities) {
+ if (mCallback != null) {
+ try {
+ mCallback.changeCameraCapabilities(CameraCapabilities);
+ } catch (RemoteException ignored) {
+ }
+ }
+ }
+
+ /** @see Connection.VideoProvider#changeVideoQuality */
+ public void changeVideoQuality(int videoQuality) {
+ if (mCallback != null) {
+ try {
+ mCallback.changeVideoQuality(videoQuality);
+ } catch (RemoteException ignored) {
+ }
+ }
+ }
+}
diff --git a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
index cbedb95..e9c5461 100644
--- a/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
+++ b/telephony/java/com/android/internal/telephony/IPhoneStateListener.aidl
@@ -43,6 +43,8 @@
void onPreciseDataConnectionStateChanged(in PreciseDataConnectionState dataConnectionState);
void onDataConnectionRealTimeInfoChanged(in DataConnectionRealTimeInfo dcRtInfo);
void onVoLteServiceStateChanged(in VoLteServiceState lteState);
+ void onVoiceActivationStateChanged(int activationState);
+ void onDataActivationStateChanged(int activationState);
void onOemHookRawEvent(in byte[] rawData);
void onCarrierNetworkChange(in boolean active);
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 1988596..d21efc6 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -445,6 +445,30 @@
*/
boolean setVoiceMailNumber(int subId, String alphaTag, String number);
+ /**
+ * Sets the voice activation state for a particular subscriber.
+ */
+ void setVoiceActivationState(int subId, int activationState);
+
+ /**
+ * Sets the data activation state for a particular subscriber.
+ */
+ void setDataActivationState(int subId, int activationState);
+
+ /**
+ * Returns the voice activation state for a particular subscriber.
+ * @param subId user preferred sub
+ * @param callingPackage package queries voice activation state
+ */
+ int getVoiceActivationState(int subId, String callingPackage);
+
+ /**
+ * Returns the data activation state for a particular subscriber.
+ * @param subId user preferred sub
+ * @param callingPackage package queris data activation state
+ */
+ int getDataActivationState(int subId, String callingPackage);
+
/**
* Returns the unread count of voicemails
*/
@@ -1194,7 +1218,6 @@
*/
void setPolicyDataEnabled(boolean enabled, int subId);
-
/**
* Get Client request stats which will contain statistical information
* on each request made by client.
@@ -1203,4 +1226,24 @@
* @hide
*/
List<ClientRequestStats> getClientRequestStats(String callingPackage, int subid);
+
+ /**
+ * Set SIM card power state. Request is equivalent to inserting or removing the card.
+ * @param slotId SIM slot id
+ * @param powerUp True if powering up the SIM, otherwise powering down
+ * @hide
+ * */
+ void setSimPowerStateForSlot(int slotId, boolean powerUp);
+
+ /**
+ * Returns a list of Forbidden PLMNs from the specified SIM App
+ * Returns null if the query fails.
+ *
+ *
+ * <p>Requires that the calling app has READ_PRIVILEGED_PHONE_STATE
+ *
+ * @param subId subscription ID used for authentication
+ * @param appType the icc application type, like {@link #APPTYPE_USIM}
+ */
+ String[] getForbiddenPlmns(int subId, int appType);
}
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
index 2c6be62..2c2206c 100644
--- a/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl
@@ -65,6 +65,8 @@
String failCause);
void notifyCellInfoForSubscriber(in int subId, in List<CellInfo> cellInfo);
void notifyVoLteServiceStateChanged(in VoLteServiceState lteState);
+ void notifySimActivationStateChangedForPhoneId(in int phoneId, in int subId,
+ int activationState, int activationType);
void notifyOemHookRawEventForSubscriber(in int subId, in byte[] rawData);
void notifySubscriptionInfoChanged();
void notifyCarrierNetworkChange(in boolean active);
diff --git a/telephony/java/com/android/internal/telephony/PhoneConstants.java b/telephony/java/com/android/internal/telephony/PhoneConstants.java
index fdc68b9..f9de776 100644
--- a/telephony/java/com/android/internal/telephony/PhoneConstants.java
+++ b/telephony/java/com/android/internal/telephony/PhoneConstants.java
@@ -74,6 +74,9 @@
public static final int PRESENTATION_UNKNOWN = 3; // no specified or unknown by network
public static final int PRESENTATION_PAYPHONE = 4; // show pay phone info
+ // Sim activation type
+ public static final int SIM_ACTIVATION_TYPE_VOICE = 0;
+ public static final int SIM_ACTIVATION_TYPE_DATA = 1;
public static final String PHONE_NAME_KEY = "phoneName";
public static final String FAILURE_REASON_KEY = "reason";
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index b770b19..81ecdc9 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -411,6 +411,7 @@
int RIL_REQUEST_GET_ACTIVITY_INFO = 135;
int RIL_REQUEST_SET_ALLOWED_CARRIERS = 136;
int RIL_REQUEST_GET_ALLOWED_CARRIERS = 137;
+ int RIL_REQUEST_SET_SIM_CARD_POWER = 140;
int RIL_RESPONSE_ACKNOWLEDGEMENT = 800;
diff --git a/telephony/java/com/android/internal/telephony/TelephonyIntents.java b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
index 0168874..682b672 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyIntents.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyIntents.java
@@ -264,15 +264,6 @@
= "android.intent.action.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS";
/**
- * Activity Action: Start this activity to invoke the carrier setup app.
- * The carrier app must be signed using a certificate that matches the UICC access rules.
- *
- * <p class="note">Callers of this should hold the android.permission.INVOKE_CARRIER_SETUP
- * permission.</p>
- */
- public static final String ACTION_CARRIER_SETUP = "android.intent.action.ACTION_CARRIER_SETUP";
-
- /**
* <p>Broadcast Action: Indicates that the action is forbidden by network.
* <p class="note">
* This is for the OEM applications to understand about possible provisioning issues.
@@ -411,7 +402,7 @@
* <p class="note">This is a protected intent that can only be sent by the system.</p>
*/
public static final String ACTION_CARRIER_SIGNAL_REDIRECTED =
- "android.intent.action.CARRIER_SIGNAL_REDIRECTED";
+ "com.android.internal.telephony.CARRIER_SIGNAL_REDIRECTED";
/**
* <p>Broadcast Action: when data connections setup fails.
* intended for sim/account status checks and only sent to the specified carrier app
@@ -424,7 +415,7 @@
* <p class="note">This is a protected intent that can only be sent by the system. </p>
*/
public static final String ACTION_CARRIER_SIGNAL_REQUEST_NETWORK_FAILED =
- "android.intent.action.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED";
+ "com.android.internal.telephony.CARRIER_SIGNAL_REQUEST_NETWORK_FAILED";
/**
* <p>Broadcast Action: when pco value is available.
@@ -441,7 +432,7 @@
* <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 =
- "android.intent.action.CARRIER_SIGNAL_PCO_VALUE";
+ "com.android.internal.telephony.CARRIER_SIGNAL_PCO_VALUE";
// CARRIER_SIGNAL_ACTION extra keys
public static final String EXTRA_REDIRECTION_URL_KEY = "redirectionUrl";
diff --git a/test-runner/src/android/test/suitebuilder/TestMethod.java b/test-runner/src/android/test/suitebuilder/TestMethod.java
index 08568d5..ae1db5e 100644
--- a/test-runner/src/android/test/suitebuilder/TestMethod.java
+++ b/test-runner/src/android/test/suitebuilder/TestMethod.java
@@ -26,7 +26,11 @@
/**
* Represents a test to be run. Can be constructed without instantiating the TestCase or even
* loading the class.
+ *
+ * @deprecated New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
*/
+@Deprecated
public class TestMethod {
private final String enclosingClassname;
diff --git a/test-runner/src/android/test/suitebuilder/TestSuiteBuilder.java b/test-runner/src/android/test/suitebuilder/TestSuiteBuilder.java
index 8c89489..3b920cf 100644
--- a/test-runner/src/android/test/suitebuilder/TestSuiteBuilder.java
+++ b/test-runner/src/android/test/suitebuilder/TestSuiteBuilder.java
@@ -38,7 +38,11 @@
/**
* Build suites based on a combination of included packages, excluded packages,
* and predicates that must be satisfied.
+ *
+ * @deprecated New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
*/
+@Deprecated
public class TestSuiteBuilder {
private Context context;
@@ -223,7 +227,11 @@
/**
* A special {@link junit.framework.TestCase} used to indicate a failure during the build()
* step.
+ *
+ * @deprecated New tests should be written using the
+ * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
*/
+ @Deprecated
public static class FailedToCreateTests extends TestCase {
private final Exception exception;
diff --git a/test-runner/src/junit/runner/package-info.java b/test-runner/src/junit/runner/package-info.java
index b746185..364e362 100644
--- a/test-runner/src/junit/runner/package-info.java
+++ b/test-runner/src/junit/runner/package-info.java
@@ -1,4 +1,4 @@
/**
- * Provides JUnit v3.x test runners.
+ * Utility classes supporting the junit test framework.
*/
package junit.runner;
\ No newline at end of file
diff --git a/test-runner/src/junit/runner/package.html b/test-runner/src/junit/runner/package.html
deleted file mode 100644
index f08fa70..0000000
--- a/test-runner/src/junit/runner/package.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<HTML>
-<BODY>
-Utility classes supporting the junit test framework.
-</BODY>
-</HTML>
diff --git a/test-runner/src/junit/textui/package-info.java b/test-runner/src/junit/textui/package-info.java
index 2dcc10c..28b2ef4 100644
--- a/test-runner/src/junit/textui/package-info.java
+++ b/test-runner/src/junit/textui/package-info.java
@@ -1,5 +1,5 @@
/**
- * Provides JUnit v3.x command line based tool to run tests.
+ * Utility classes supporting the junit test framework.
* {@hide}
*/
package junit.textui;
\ No newline at end of file
diff --git a/test-runner/src/junit/textui/package.html b/test-runner/src/junit/textui/package.html
deleted file mode 100644
index 723f2ae..0000000
--- a/test-runner/src/junit/textui/package.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<HTML>
-<BODY>
-Utility classes supporting the junit test framework.
-{@hide} - Not needed for 1.0 SDK
-</BODY>
-</HTML>
diff --git a/tests/net/java/android/net/ConnectivityMetricsLoggerTest.java b/tests/net/java/android/net/ConnectivityMetricsLoggerTest.java
deleted file mode 100644
index f896030..0000000
--- a/tests/net/java/android/net/ConnectivityMetricsLoggerTest.java
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * 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.net;
-
-import android.os.Bundle;
-import android.os.Parcel;
-import android.test.suitebuilder.annotation.SmallTest;
-import java.util.List;
-import junit.framework.TestCase;
-import org.mockito.ArgumentCaptor;
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import static org.mockito.Mockito.any;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
-
-public class ConnectivityMetricsLoggerTest extends TestCase {
-
- // use same Parcel object everywhere for pointer equality
- static final Bundle FAKE_EV = new Bundle();
- static final int FAKE_COMPONENT = 1;
- static final int FAKE_EVENT = 2;
-
- @Mock IConnectivityMetricsLogger mService;
- ArgumentCaptor<ConnectivityMetricsEvent> evCaptor;
- ArgumentCaptor<ConnectivityMetricsEvent[]> evArrayCaptor;
-
- ConnectivityMetricsLogger mLog;
-
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- evCaptor = ArgumentCaptor.forClass(ConnectivityMetricsEvent.class);
- evArrayCaptor = ArgumentCaptor.forClass(ConnectivityMetricsEvent[].class);
- mLog = new ConnectivityMetricsLogger(mService);
- }
-
- @SmallTest
- public void testLogEvents() throws Exception {
- mLog.logEvent(1, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
- mLog.logEvent(2, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
- mLog.logEvent(3, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
-
- List<ConnectivityMetricsEvent> gotEvents = verifyEvents(3);
- assertEventsEqual(expectedEvent(1), gotEvents.get(0));
- assertEventsEqual(expectedEvent(2), gotEvents.get(1));
- assertEventsEqual(expectedEvent(3), gotEvents.get(2));
- }
-
- @SmallTest
- public void testLogEventTriggerThrottling() throws Exception {
- when(mService.logEvent(any())).thenReturn(1234L);
-
- mLog.logEvent(1, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
- mLog.logEvent(2, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
-
- List<ConnectivityMetricsEvent> gotEvents = verifyEvents(1);
- assertEventsEqual(expectedEvent(1), gotEvents.get(0));
- }
-
- @SmallTest
- public void testLogEventFails() throws Exception {
- when(mService.logEvent(any())).thenReturn(-1L); // Error.
-
- mLog.logEvent(1, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
- mLog.logEvent(2, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
-
- List<ConnectivityMetricsEvent> gotEvents = verifyEvents(1);
- assertEventsEqual(expectedEvent(1), gotEvents.get(0));
- }
-
- @SmallTest
- public void testLogEventWhenThrottling() throws Exception {
- when(mService.logEvent(any())).thenReturn(Long.MAX_VALUE); // Throttled
-
- // No events are logged. The service is only called once
- // After that, throttling state is maintained locally.
- mLog.logEvent(1, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
- mLog.logEvent(2, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
-
- List<ConnectivityMetricsEvent> gotEvents = verifyEvents(1);
- assertEventsEqual(expectedEvent(1), gotEvents.get(0));
- }
-
- @SmallTest
- public void testLogEventRecoverFromThrottling() throws Exception {
- final long throttleTimeout = System.currentTimeMillis() + 10;
- when(mService.logEvent(any())).thenReturn(throttleTimeout, 0L);
-
- mLog.logEvent(1, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
- mLog.logEvent(2, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
- mLog.logEvent(3, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
- Thread.sleep(100);
- mLog.logEvent(53, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
-
- List<ConnectivityMetricsEvent> gotEvents = verifyEvents(1);
- assertEventsEqual(expectedEvent(1), gotEvents.get(0));
-
- verify(mService, times(1)).logEvents(evArrayCaptor.capture());
- ConnectivityMetricsEvent[] gotOtherEvents = evArrayCaptor.getAllValues().get(0);
- assertEquals(ConnectivityMetricsLogger.TAG_SKIPPED_EVENTS, gotOtherEvents[0].eventTag);
- assertEventsEqual(expectedEvent(53), gotOtherEvents[1]);
- }
-
- List<ConnectivityMetricsEvent> verifyEvents(int n) throws Exception {
- verify(mService, times(n)).logEvent(evCaptor.capture());
- return evCaptor.getAllValues();
- }
-
- static ConnectivityMetricsEvent expectedEvent(int timestamp) {
- return new ConnectivityMetricsEvent((long)timestamp, FAKE_COMPONENT, FAKE_EVENT, FAKE_EV);
- }
-
- /** Outer equality for ConnectivityMetricsEvent to avoid overriding equals() and hashCode(). */
- static void assertEventsEqual(ConnectivityMetricsEvent expected, ConnectivityMetricsEvent got) {
- assertEquals(expected.timestamp, got.timestamp);
- assertEquals(expected.componentTag, got.componentTag);
- assertEquals(expected.eventTag, got.eventTag);
- assertEquals(expected.data, got.data);
- }
-}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 39406a11..52d2b63 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -369,6 +369,11 @@
connect(false);
}
+ public void suspend() {
+ mNetworkInfo.setDetailedState(DetailedState.SUSPENDED, null, null);
+ mNetworkAgent.sendNetworkInfo(mNetworkInfo);
+ }
+
public void disconnect() {
mNetworkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null);
mNetworkAgent.sendNetworkInfo(mNetworkInfo);
@@ -1048,6 +1053,7 @@
AVAILABLE,
NETWORK_CAPABILITIES,
LINK_PROPERTIES,
+ SUSPENDED,
LOSING,
LOST,
UNAVAILABLE
@@ -1061,7 +1067,7 @@
state = s; network = n; arg = o;
}
public String toString() {
- return String.format("%s (%s)", state, network);
+ return String.format("%s (%s) (%s)", state, network, arg);
}
@Override
public boolean equals(Object o) {
@@ -1099,11 +1105,26 @@
}
@Override
+ public void onCapabilitiesChanged(Network network, NetworkCapabilities netCap) {
+ setLastCallback(CallbackState.NETWORK_CAPABILITIES, network, netCap);
+ }
+
+ @Override
+ public void onLinkPropertiesChanged(Network network, LinkProperties linkProp) {
+ setLastCallback(CallbackState.LINK_PROPERTIES, network, linkProp);
+ }
+
+ @Override
public void onUnavailable() {
setLastCallback(CallbackState.UNAVAILABLE, null, null);
}
@Override
+ public void onNetworkSuspended(Network network) {
+ setLastCallback(CallbackState.SUSPENDED, network, null);
+ }
+
+ @Override
public void onLosing(Network network, int maxMsToLive) {
setLastCallback(CallbackState.LOSING, network, maxMsToLive /* autoboxed int */);
}
@@ -1126,11 +1147,12 @@
return cb;
}
- void expectCallback(CallbackState state, MockNetworkAgent mockAgent, int timeoutMs) {
- CallbackInfo expected = new CallbackInfo(
- state, (mockAgent != null) ? mockAgent.getNetwork() : null, 0);
+ CallbackInfo expectCallback(CallbackState state, MockNetworkAgent agent, int timeoutMs) {
+ final Network expectedNetwork = (agent != null) ? agent.getNetwork() : null;
+ CallbackInfo expected = new CallbackInfo(state, expectedNetwork, 0);
CallbackInfo actual = nextCallback(timeoutMs);
assertEquals("Unexpected callback:", expected, actual);
+
if (state == CallbackState.LOSING) {
String msg = String.format(
"Invalid linger time value %d, must be between %d and %d",
@@ -1138,10 +1160,50 @@
int maxMsToLive = (Integer) actual.arg;
assertTrue(msg, 0 <= maxMsToLive && maxMsToLive <= TEST_LINGER_DELAY_MS);
}
+
+ return actual;
}
- void expectCallback(CallbackState state, MockNetworkAgent mockAgent) {
- expectCallback(state, mockAgent, TIMEOUT_MS);
+ CallbackInfo expectCallback(CallbackState state, MockNetworkAgent agent) {
+ return expectCallback(state, agent, TIMEOUT_MS);
+ }
+
+ void expectAvailableCallbacks(MockNetworkAgent agent, boolean expectSuspended, int timeoutMs) {
+ expectCallback(CallbackState.AVAILABLE, agent, timeoutMs);
+
+ final boolean HAS_DATASYNC_ON_AVAILABLE = false;
+ if (HAS_DATASYNC_ON_AVAILABLE) {
+ if (expectSuspended) {
+ expectCallback(CallbackState.SUSPENDED, agent, timeoutMs);
+ }
+ expectCallback(CallbackState.NETWORK_CAPABILITIES, agent, timeoutMs);
+ expectCallback(CallbackState.LINK_PROPERTIES, agent, timeoutMs);
+ }
+ }
+
+ void expectAvailableCallbacks(MockNetworkAgent agent) {
+ expectAvailableCallbacks(agent, false, TIMEOUT_MS);
+ }
+
+ void expectAvailableAndSuspendedCallbacks(MockNetworkAgent agent) {
+ expectAvailableCallbacks(agent, true, TIMEOUT_MS);
+ }
+
+ void expectAvailableAndValidatedCallbacks(MockNetworkAgent agent) {
+ expectAvailableCallbacks(agent, true, TIMEOUT_MS);
+ expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, agent);
+ }
+
+ void expectCapabilitiesWith(int capability, MockNetworkAgent agent) {
+ CallbackInfo cbi = expectCallback(CallbackState.NETWORK_CAPABILITIES, agent);
+ NetworkCapabilities nc = (NetworkCapabilities) cbi.arg;
+ assertTrue(nc.hasCapability(capability));
+ }
+
+ void expectCapabilitiesWithout(int capability, MockNetworkAgent agent) {
+ CallbackInfo cbi = expectCallback(CallbackState.NETWORK_CAPABILITIES, agent);
+ NetworkCapabilities nc = (NetworkCapabilities) cbi.arg;
+ assertFalse(nc.hasCapability(capability));
}
void assertNoCallback() {
@@ -1178,8 +1240,8 @@
ConditionVariable cv = waitForConnectivityBroadcasts(1);
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(false);
- genericNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
- cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ genericNetworkCallback.expectAvailableCallbacks(mCellNetworkAgent);
+ cellNetworkCallback.expectAvailableCallbacks(mCellNetworkAgent);
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
waitFor(cv);
assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
@@ -1193,8 +1255,8 @@
cv = waitForConnectivityBroadcasts(2);
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(false);
- genericNetworkCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
- wifiNetworkCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ genericNetworkCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
+ wifiNetworkCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
waitFor(cv);
assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
@@ -1217,8 +1279,8 @@
// Test validated networks
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(true);
- genericNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
- cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ genericNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
+ cellNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
@@ -1230,9 +1292,10 @@
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(true);
- genericNetworkCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ genericNetworkCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
genericNetworkCallback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
- wifiNetworkCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ genericNetworkCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
+ wifiNetworkCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
cellNetworkCallback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
assertNoCallbacks(genericNetworkCallback, wifiNetworkCallback, cellNetworkCallback);
@@ -1268,28 +1331,32 @@
mEthernetNetworkAgent.addCapability(NET_CAPABILITY_NOT_METERED);
mCellNetworkAgent.connect(true);
- callback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ callback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
+ defaultCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
mWiFiNetworkAgent.connect(true);
// We get AVAILABLE on wifi when wifi connects and satisfies our unmetered request.
// We then get LOSING when wifi validates and cell is outscored.
- callback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ callback.expectAvailableCallbacks(mWiFiNetworkAgent);
+ // TODO: Investigate sending validated before losing.
callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
+ defaultCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
mEthernetNetworkAgent.connect(true);
- callback.expectCallback(CallbackState.AVAILABLE, mEthernetNetworkAgent);
+ callback.expectAvailableCallbacks(mEthernetNetworkAgent);
+ // TODO: Investigate sending validated before losing.
callback.expectCallback(CallbackState.LOSING, mWiFiNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mEthernetNetworkAgent);
+ callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mEthernetNetworkAgent);
+ defaultCallback.expectAvailableAndValidatedCallbacks(mEthernetNetworkAgent);
assertEquals(mEthernetNetworkAgent.getNetwork(), mCm.getActiveNetwork());
mEthernetNetworkAgent.disconnect();
callback.expectCallback(CallbackState.LOST, mEthernetNetworkAgent);
defaultCallback.expectCallback(CallbackState.LOST, mEthernetNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
for (int i = 0; i < 4; i++) {
MockNetworkAgent oldNetwork, newNetwork;
@@ -1306,7 +1373,7 @@
callback.expectCallback(CallbackState.LOSING, oldNetwork);
// TODO: should we send an AVAILABLE callback to newNetwork, to indicate that it is no
// longer lingering?
- defaultCallback.expectCallback(CallbackState.AVAILABLE, newNetwork);
+ defaultCallback.expectAvailableCallbacks(newNetwork);
assertEquals(newNetwork.getNetwork(), mCm.getActiveNetwork());
}
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
@@ -1314,17 +1381,19 @@
// Verify that if a network no longer satisfies a request, we send LOST and not LOSING, even
// if the network is still up.
mWiFiNetworkAgent.removeCapability(NET_CAPABILITY_NOT_METERED);
+ // We expect a notification about the capabilities change, and nothing else.
+ defaultCallback.expectCapabilitiesWithout(NET_CAPABILITY_NOT_METERED, mWiFiNetworkAgent);
+ defaultCallback.assertNoCallback();
callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
// Wifi no longer satisfies our listen, which is for an unmetered network.
// But because its score is 55, it's still up (and the default network).
- defaultCallback.assertNoCallback();
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
// Disconnect our test networks.
mWiFiNetworkAgent.disconnect();
defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
mCellNetworkAgent.disconnect();
defaultCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
@@ -1340,22 +1409,22 @@
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(false); // Score: 10
- callback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ callback.expectAvailableCallbacks(mCellNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
// Bring up wifi with a score of 20.
// Cell stays up because it would satisfy the default request if it validated.
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(false); // Score: 20
- callback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ callback.expectAvailableCallbacks(mWiFiNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
mWiFiNetworkAgent.disconnect();
callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
// Bring up wifi with a score of 70.
@@ -1363,31 +1432,33 @@
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.adjustScore(50);
mWiFiNetworkAgent.connect(false); // Score: 70
- callback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ callback.expectAvailableCallbacks(mWiFiNetworkAgent);
callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
// Tear down wifi.
mWiFiNetworkAgent.disconnect();
callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
// Bring up wifi, then validate it. Previous versions would immediately tear down cell, but
// it's arguably correct to linger it, since it was the default network before it validated.
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(true);
- callback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ callback.expectAvailableCallbacks(mWiFiNetworkAgent);
+ // TODO: Investigate sending validated before losing.
callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
+ defaultCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
mWiFiNetworkAgent.disconnect();
callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
mCellNetworkAgent.disconnect();
callback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
defaultCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
@@ -1395,13 +1466,15 @@
// If a network is lingering, and we add and remove a request from it, resume lingering.
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(true);
- callback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ callback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
+ defaultCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(true);
- callback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ defaultCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
+ callback.expectAvailableCallbacks(mWiFiNetworkAgent);
+ // TODO: Investigate sending validated before losing.
callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
NetworkRequest cellRequest = new NetworkRequest.Builder()
.addTransportType(TRANSPORT_CELLULAR).build();
@@ -1417,7 +1490,7 @@
mWiFiNetworkAgent.disconnect();
callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
defaultCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
// Cell is now the default network. Pin it with a cell-specific request.
noopCallback = new NetworkCallback(); // Can't reuse NetworkCallbacks. http://b/20701525
@@ -1426,8 +1499,8 @@
// Now connect wifi, and expect it to become the default network.
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(true);
- callback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ callback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
+ defaultCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
// The default request is lingering on cell, but nothing happens to cell, and we send no
// callbacks for it, because it's kept up by cellRequest.
callback.assertNoCallback();
@@ -1613,7 +1686,7 @@
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
mCellNetworkAgent.addCapability(NET_CAPABILITY_MMS);
mCellNetworkAgent.connectWithoutInternet();
- networkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ networkCallback.expectAvailableCallbacks(mCellNetworkAgent);
verifyActiveNetwork(TRANSPORT_WIFI);
// Test releasing NetworkRequest disconnects cellular with MMS
cv = mCellNetworkAgent.getDisconnectedCV();
@@ -1639,7 +1712,7 @@
MockNetworkAgent mmsNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
mmsNetworkAgent.addCapability(NET_CAPABILITY_MMS);
mmsNetworkAgent.connectWithoutInternet();
- networkCallback.expectCallback(CallbackState.AVAILABLE, mmsNetworkAgent);
+ networkCallback.expectAvailableCallbacks(mmsNetworkAgent);
verifyActiveNetwork(TRANSPORT_CELLULAR);
// Test releasing MMS NetworkRequest does not disconnect main cellular NetworkAgent
cv = mmsNetworkAgent.getDisconnectedCV();
@@ -1665,7 +1738,7 @@
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
String firstRedirectUrl = "http://example.com/firstPath";
mWiFiNetworkAgent.connectWithCaptivePortal(firstRedirectUrl);
- captivePortalCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ captivePortalCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
assertEquals(mWiFiNetworkAgent.waitForRedirectUrl(), firstRedirectUrl);
// Take down network.
@@ -1678,7 +1751,7 @@
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
String secondRedirectUrl = "http://example.com/secondPath";
mWiFiNetworkAgent.connectWithCaptivePortal(secondRedirectUrl);
- captivePortalCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ captivePortalCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
assertEquals(mWiFiNetworkAgent.waitForRedirectUrl(), secondRedirectUrl);
// Make captive portal disappear then revalidate.
@@ -1688,7 +1761,9 @@
captivePortalCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
// Expect NET_CAPABILITY_VALIDATED onAvailable callback.
- validatedCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ validatedCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
+ // TODO: Investigate only sending available callbacks.
+ validatedCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
// Break network connectivity.
// Expect NET_CAPABILITY_VALIDATED onLost callback.
@@ -1733,7 +1808,7 @@
mWiFiNetworkAgent.connectWithCaptivePortal(secondRedirectUrl);
// Expect NET_CAPABILITY_VALIDATED onAvailable callback.
- validatedCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ validatedCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
// But there should be no CaptivePortal callback.
captivePortalCallback.assertNoCallback();
}
@@ -1786,14 +1861,14 @@
// Bring up cell and expect CALLBACK_AVAILABLE.
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(true);
- cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
- defaultNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ cellNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
+ defaultNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
// Bring up wifi and expect CALLBACK_AVAILABLE.
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(true);
cellNetworkCallback.assertNoCallback();
- defaultNetworkCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ defaultNetworkCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
// Bring down cell. Expect no default network callback, since it wasn't the default.
mCellNetworkAgent.disconnect();
@@ -1803,7 +1878,7 @@
// Bring up cell. Expect no default network callback, since it won't be the default.
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(true);
- cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ cellNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
defaultNetworkCallback.assertNoCallback();
// Bring down wifi. Expect the default network callback to notified of LOST wifi
@@ -1811,28 +1886,16 @@
mWiFiNetworkAgent.disconnect();
cellNetworkCallback.assertNoCallback();
defaultNetworkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- defaultNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ defaultNetworkCallback.expectAvailableCallbacks(mCellNetworkAgent);
mCellNetworkAgent.disconnect();
cellNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
defaultNetworkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
}
- private class TestRequestUpdateCallback extends TestNetworkCallback {
- @Override
- public void onCapabilitiesChanged(Network network, NetworkCapabilities netCap) {
- setLastCallback(CallbackState.NETWORK_CAPABILITIES, network, netCap);
- }
-
- @Override
- public void onLinkPropertiesChanged(Network network, LinkProperties linkProp) {
- setLastCallback(CallbackState.LINK_PROPERTIES, network, linkProp);
- }
- }
-
@SmallTest
- public void testRequestCallbackUpdates() throws Exception {
+ public void testAdditionalStateCallbacks() throws Exception {
// File a network request for mobile.
- final TestNetworkCallback cellNetworkCallback = new TestRequestUpdateCallback();
+ final TestNetworkCallback cellNetworkCallback = new TestNetworkCallback();
final NetworkRequest cellRequest = new NetworkRequest.Builder()
.addTransportType(TRANSPORT_CELLULAR).build();
mCm.requestNetwork(cellRequest, cellNetworkCallback);
@@ -1841,10 +1904,10 @@
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(true);
- // We should get onAvailable().
- cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
- // We should get onCapabilitiesChanged(), when the mobile network successfully validates.
- cellNetworkCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES, mCellNetworkAgent);
+ // We should get onAvailable(), onCapabilitiesChanged(), and
+ // onLinkPropertiesChanged() in rapid succession. Additionally, we
+ // should get onCapabilitiesChanged() when the mobile network validates.
+ cellNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
cellNetworkCallback.assertNoCallback();
// Update LinkProperties.
@@ -1855,20 +1918,28 @@
cellNetworkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
cellNetworkCallback.assertNoCallback();
+ // Suspend the network.
+ mCellNetworkAgent.suspend();
+ cellNetworkCallback.expectCallback(CallbackState.SUSPENDED, mCellNetworkAgent);
+ cellNetworkCallback.assertNoCallback();
+
// Register a garden variety default network request.
- final TestNetworkCallback dfltNetworkCallback = new TestRequestUpdateCallback();
+ final TestNetworkCallback dfltNetworkCallback = new TestNetworkCallback();
mCm.registerDefaultNetworkCallback(dfltNetworkCallback);
- // Only onAvailable() is called; no other information is delivered.
- dfltNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ // We should get onAvailable(), onCapabilitiesChanged(), onLinkPropertiesChanged(),
+ // as well as onNetworkSuspended() in rapid succession.
+ dfltNetworkCallback.expectAvailableAndSuspendedCallbacks(mCellNetworkAgent);
dfltNetworkCallback.assertNoCallback();
// Request a NetworkCapabilities update; only the requesting callback is notified.
+ // TODO: Delete this together with Connectivity{Manager,Service} code.
mCm.requestNetworkCapabilities(dfltNetworkCallback);
dfltNetworkCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES, mCellNetworkAgent);
cellNetworkCallback.assertNoCallback();
dfltNetworkCallback.assertNoCallback();
// Request a LinkProperties update; only the requesting callback is notified.
+ // TODO: Delete this together with Connectivity{Manager,Service} code.
mCm.requestLinkProperties(dfltNetworkCallback);
dfltNetworkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
cellNetworkCallback.assertNoCallback();
@@ -1911,18 +1982,20 @@
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(true);
- callback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
- fgCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ callback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
+ fgCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
assertTrue(isForegroundNetwork(mCellNetworkAgent));
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(true);
// When wifi connects, cell lingers.
- callback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
- fgCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ callback.expectAvailableCallbacks(mWiFiNetworkAgent);
callback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ callback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
+ fgCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
fgCallback.expectCallback(CallbackState.LOSING, mCellNetworkAgent);
+ fgCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
assertTrue(isForegroundNetwork(mCellNetworkAgent));
assertTrue(isForegroundNetwork(mWiFiNetworkAgent));
@@ -1930,7 +2003,8 @@
mService.waitForIdle();
int timeoutMs = TEST_LINGER_DELAY_MS + TEST_LINGER_DELAY_MS / 4;
fgCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent, timeoutMs);
- callback.assertNoCallback();
+ // Expect a network capabilities update sans FOREGROUND.
+ callback.expectCapabilitiesWithout(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent);
assertFalse(isForegroundNetwork(mCellNetworkAgent));
assertTrue(isForegroundNetwork(mWiFiNetworkAgent));
@@ -1939,9 +2013,15 @@
.addTransportType(TRANSPORT_CELLULAR).build();
final TestNetworkCallback cellCallback = new TestNetworkCallback();
mCm.requestNetwork(cellRequest, cellCallback);
- cellCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
- fgCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
- callback.assertNoCallback(); // Because the network is already up.
+ // NOTE: This request causes the network's capabilities to change. This
+ // is currently delivered before the onAvailable() callbacks.
+ // TODO: Fix this.
+ cellCallback.expectCapabilitiesWith(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent);
+ cellCallback.expectAvailableCallbacks(mCellNetworkAgent);
+ fgCallback.expectAvailableCallbacks(mCellNetworkAgent);
+ // Expect a network capabilities update with FOREGROUND, because the most recent
+ // request causes its state to change.
+ callback.expectCapabilitiesWith(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent);
assertTrue(isForegroundNetwork(mCellNetworkAgent));
assertTrue(isForegroundNetwork(mWiFiNetworkAgent));
@@ -1949,7 +2029,8 @@
// lingering.
mCm.unregisterNetworkCallback(cellCallback);
fgCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
- callback.assertNoCallback();
+ // Expect a network capabilities update sans FOREGROUND.
+ callback.expectCapabilitiesWithout(NET_CAPABILITY_FOREGROUND, mCellNetworkAgent);
assertFalse(isForegroundNetwork(mCellNetworkAgent));
assertTrue(isForegroundNetwork(mWiFiNetworkAgent));
@@ -1957,7 +2038,7 @@
mWiFiNetworkAgent.disconnect();
callback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
fgCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
- fgCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ fgCallback.expectAvailableCallbacks(mCellNetworkAgent);
assertTrue(isForegroundNetwork(mCellNetworkAgent));
mCm.unregisterNetworkCallback(callback);
@@ -2098,7 +2179,7 @@
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
testFactory.expectAddRequests(2); // Because the cell request changes score twice.
mCellNetworkAgent.connect(true);
- cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ cellNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
testFactory.waitForNetworkRequests(2);
assertFalse(testFactory.getMyStartRequested()); // Because the cell network outscores us.
@@ -2189,20 +2270,22 @@
// Bring up validated cell.
mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
mCellNetworkAgent.connect(true);
- cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ cellNetworkCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
+ defaultCallback.expectAvailableAndValidatedCallbacks(mCellNetworkAgent);
Network cellNetwork = mCellNetworkAgent.getNetwork();
// Bring up validated wifi.
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(true);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
- validatedWifiCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ defaultCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
+ validatedWifiCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
+ validatedWifiCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
Network wifiNetwork = mWiFiNetworkAgent.getNetwork();
// Fail validation on wifi.
mWiFiNetworkAgent.getWrappedNetworkMonitor().gen204ProbeResult = 599;
mCm.reportNetworkConnectivity(wifiNetwork, false);
+ defaultCallback.expectCapabilitiesWithout(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
validatedWifiCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
// Because avoid bad wifi is off, we don't switch to cellular.
@@ -2217,18 +2300,18 @@
// that we switch back to cell.
tracker.configRestrictsAvoidBadWifi = false;
tracker.reevaluate();
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
assertEquals(mCm.getActiveNetwork(), cellNetwork);
// Switch back to a restrictive carrier.
tracker.configRestrictsAvoidBadWifi = true;
tracker.reevaluate();
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
assertEquals(mCm.getActiveNetwork(), wifiNetwork);
// Simulate the user selecting "switch" on the dialog, and check that we switch to cell.
mCm.setAvoidUnvalidated(wifiNetwork);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
assertFalse(mCm.getNetworkCapabilities(wifiNetwork).hasCapability(
NET_CAPABILITY_VALIDATED));
assertTrue(mCm.getNetworkCapabilities(cellNetwork).hasCapability(
@@ -2239,13 +2322,15 @@
mWiFiNetworkAgent.disconnect();
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(true);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
- validatedWifiCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ defaultCallback.expectAvailableAndValidatedCallbacks(mWiFiNetworkAgent);
+ validatedWifiCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
+ validatedWifiCallback.expectCapabilitiesWith(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
wifiNetwork = mWiFiNetworkAgent.getNetwork();
// Fail validation on wifi and expect the dialog to appear.
mWiFiNetworkAgent.getWrappedNetworkMonitor().gen204ProbeResult = 599;
mCm.reportNetworkConnectivity(wifiNetwork, false);
+ defaultCallback.expectCapabilitiesWithout(NET_CAPABILITY_VALIDATED, mWiFiNetworkAgent);
validatedWifiCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
// Simulate the user selecting "switch" and checking the don't ask again checkbox.
@@ -2253,7 +2338,7 @@
tracker.reevaluate();
// We now switch to cell.
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
assertFalse(mCm.getNetworkCapabilities(wifiNetwork).hasCapability(
NET_CAPABILITY_VALIDATED));
assertTrue(mCm.getNetworkCapabilities(cellNetwork).hasCapability(
@@ -2264,17 +2349,17 @@
// We switch to wifi and then to cell.
Settings.Global.putString(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, null);
tracker.reevaluate();
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
assertEquals(mCm.getActiveNetwork(), wifiNetwork);
Settings.Global.putInt(cr, Settings.Global.NETWORK_AVOID_BAD_WIFI, 1);
tracker.reevaluate();
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mCellNetworkAgent);
assertEquals(mCm.getActiveNetwork(), cellNetwork);
// If cell goes down, we switch to wifi.
mCellNetworkAgent.disconnect();
defaultCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
- defaultCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent);
+ defaultCallback.expectAvailableCallbacks(mWiFiNetworkAgent);
validatedWifiCallback.assertNoCallback();
mCm.unregisterNetworkCallback(cellNetworkCallback);
@@ -2296,7 +2381,7 @@
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(false);
- networkCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent, timeoutMs);
+ networkCallback.expectAvailableCallbacks(mWiFiNetworkAgent, false, timeoutMs);
// pass timeout and validate that UNAVAILABLE is not called
networkCallback.assertNoCallback();
@@ -2317,7 +2402,7 @@
mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
mWiFiNetworkAgent.connect(false);
final int assertTimeoutMs = 150;
- networkCallback.expectCallback(CallbackState.AVAILABLE, mWiFiNetworkAgent, assertTimeoutMs);
+ networkCallback.expectAvailableCallbacks(mWiFiNetworkAgent, false, assertTimeoutMs);
sleepFor(20);
mWiFiNetworkAgent.disconnect();
networkCallback.expectCallback(CallbackState.LOST, mWiFiNetworkAgent);
diff --git a/tests/net/java/com/android/server/connectivity/MetricsLoggerServiceTest.java b/tests/net/java/com/android/server/connectivity/MetricsLoggerServiceTest.java
deleted file mode 100644
index 5981f48..0000000
--- a/tests/net/java/com/android/server/connectivity/MetricsLoggerServiceTest.java
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * 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 com.android.server.connectivity;
-
-import android.content.Context;
-import android.net.ConnectivityMetricsEvent;
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.test.suitebuilder.annotation.SmallTest;
-import static android.net.ConnectivityMetricsEvent.Reference;
-
-import junit.framework.TestCase;
-import org.junit.Before;
-import org.junit.Test;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertArrayEquals;
-
-import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
-
-import java.io.FileDescriptor;
-import java.io.FileOutputStream;
-import java.util.Arrays;
-import java.util.Comparator;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-/*
- * TODO:
- * - allow overriding MetricsLoggerService constants in tests.
- * - test intents are correctly sent after the notification threshold.
- * - test oldest events are correctly pushed out when internal deque is full.
- * - test throttling triggers correctly.
- */
-public class MetricsLoggerServiceTest extends TestCase {
-
- static final int COMPONENT_TAG = 1;
- static final long N_EVENTS = 10L;
- static final ConnectivityMetricsEvent EVENTS[] = new ConnectivityMetricsEvent[(int)N_EVENTS];
- static {
- for (int i = 0; i < N_EVENTS; i++) {
- EVENTS[i] = new ConnectivityMetricsEvent(i, COMPONENT_TAG, i, new Bundle());
- }
- }
-
- static final ConnectivityMetricsEvent NO_EVENTS[] = new ConnectivityMetricsEvent[0];
-
- @Mock Context mContext;
- MetricsLoggerService mService;
-
- public void setUp() {
- MockitoAnnotations.initMocks(this);
- mService = new MetricsLoggerService(mContext);
- mService.onStart();
- }
-
- @SmallTest
- public void testGetNoEvents() throws Exception {
- Reference r = new Reference(0);
- assertArrayEquals(NO_EVENTS, mService.mBinder.getEvents(r));
- assertEquals(0, r.getValue());
- }
-
- @SmallTest
- public void testLogAndGetEvents() throws Exception {
- mService.mBinder.logEvents(EVENTS);
-
- Reference r = new Reference(0);
-
- assertArrayEquals(EVENTS, mService.mBinder.getEvents(r));
- assertEquals(N_EVENTS, r.getValue());
-
- assertArrayEquals(NO_EVENTS, mService.mBinder.getEvents(r));
- assertEquals(N_EVENTS, r.getValue());
- }
-
- @SmallTest
- public void testLogOneByOne() throws Exception {
- for (ConnectivityMetricsEvent ev : EVENTS) {
- mService.mBinder.logEvent(ev);
- }
-
- Reference r = new Reference(0);
-
- assertArrayEquals(EVENTS, mService.mBinder.getEvents(r));
- assertEquals(N_EVENTS, r.getValue());
-
- assertArrayEquals(NO_EVENTS, mService.mBinder.getEvents(r));
- assertEquals(N_EVENTS, r.getValue());
- }
-
- @SmallTest
- public void testInterleavedLogAndGet() throws Exception {
- mService.mBinder.logEvents(Arrays.copyOfRange(EVENTS, 0, 3));
-
- Reference r = new Reference(0);
-
- assertArrayEquals(Arrays.copyOfRange(EVENTS, 0, 3), mService.mBinder.getEvents(r));
- assertEquals(3, r.getValue());
-
- mService.mBinder.logEvents(Arrays.copyOfRange(EVENTS, 3, 8));
- mService.mBinder.logEvents(Arrays.copyOfRange(EVENTS, 8, 10));
-
- assertArrayEquals(Arrays.copyOfRange(EVENTS, 3, 10), mService.mBinder.getEvents(r));
- assertEquals(N_EVENTS, r.getValue());
-
- assertArrayEquals(NO_EVENTS, mService.mBinder.getEvents(r));
- assertEquals(N_EVENTS, r.getValue());
- }
-
- @SmallTest
- public void testMultipleGetAll() throws Exception {
- mService.mBinder.logEvents(Arrays.copyOf(EVENTS, 3));
-
- Reference r1 = new Reference(0);
- assertArrayEquals(Arrays.copyOf(EVENTS, 3), mService.mBinder.getEvents(r1));
- assertEquals(3, r1.getValue());
-
- mService.mBinder.logEvents(Arrays.copyOfRange(EVENTS, 3, 10));
-
- Reference r2 = new Reference(0);
- assertArrayEquals(EVENTS, mService.mBinder.getEvents(r2));
- assertEquals(N_EVENTS, r2.getValue());
- }
-
- @SmallTest
- public void testLogAndDumpConcurrently() throws Exception {
- for (int i = 0; i < 50; i++) {
- mContext = null;
- mService = null;
- setUp();
- logAndDumpConcurrently();
- }
- }
-
- public void logAndDumpConcurrently() throws Exception {
- final CountDownLatch latch = new CountDownLatch((int)N_EVENTS);
- final FileDescriptor fd = new FileOutputStream("/dev/null").getFD();
-
- for (ConnectivityMetricsEvent ev : EVENTS) {
- new Thread() {
- public void run() {
- mService.mBinder.logEvent(ev);
- latch.countDown();
- }
- }.start();
- }
-
- new Thread() {
- public void run() {
- while (latch.getCount() > 0) {
- mService.mBinder.dump(fd, new String[]{"--all"});
- }
- }
- }.start();
-
- latch.await(100, TimeUnit.MILLISECONDS);
-
- Reference r = new Reference(0);
- ConnectivityMetricsEvent[] got = mService.mBinder.getEvents(r);
- Arrays.sort(got, new EventComparator());
- assertArrayEquals(EVENTS, got);
- assertEquals(N_EVENTS, r.getValue());
- }
-
- static class EventComparator implements Comparator<ConnectivityMetricsEvent> {
- public int compare(ConnectivityMetricsEvent ev1, ConnectivityMetricsEvent ev2) {
- return Long.compare(ev1.timestamp, ev2.timestamp);
- }
- public boolean equal(Object o) {
- return o instanceof EventComparator;
- }
- };
-}
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 9f7261d..32e1b96 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachineTest.java
@@ -28,6 +28,9 @@
import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR;
import static android.net.ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR;
import static android.net.ConnectivityManager.TETHER_ERROR_UNTETHER_IFACE_ERROR;
+import static android.net.ConnectivityManager.TETHERING_BLUETOOTH;
+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_TETHERED;
import static com.android.server.connectivity.tethering.IControlsTethering.STATE_UNAVAILABLE;
@@ -92,7 +95,7 @@
@Test
public void startsOutAvailable() {
mTestedSm = new TetherInterfaceStateMachine(IFACE_NAME, mLooper.getLooper(),
- ConnectivityManager.TETHERING_BLUETOOTH, mNMService, mStatsService, mTetherHelper,
+ TETHERING_BLUETOOTH, mNMService, mStatsService, mTetherHelper,
mIPv6TetheringInterfaceServices);
mTestedSm.start();
mLooper.dispatchAll();
@@ -103,7 +106,7 @@
@Test
public void shouldDoNothingUntilRequested() throws Exception {
- initStateMachine(ConnectivityManager.TETHERING_BLUETOOTH);
+ initStateMachine(TETHERING_BLUETOOTH);
final int [] NOOP_COMMANDS = {
TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED,
TetherInterfaceStateMachine.CMD_IP_FORWARDING_ENABLE_ERROR,
@@ -123,7 +126,7 @@
@Test
public void handlesImmediateInterfaceDown() throws Exception {
- initStateMachine(ConnectivityManager.TETHERING_BLUETOOTH);
+ initStateMachine(TETHERING_BLUETOOTH);
dispatchCommand(TetherInterfaceStateMachine.CMD_INTERFACE_DOWN);
verify(mTetherHelper).notifyInterfaceStateChange(
@@ -133,7 +136,7 @@
@Test
public void canBeTethered() throws Exception {
- initStateMachine(ConnectivityManager.TETHERING_BLUETOOTH);
+ initStateMachine(TETHERING_BLUETOOTH);
dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_REQUESTED);
InOrder inOrder = inOrder(mTetherHelper, mNMService);
@@ -145,7 +148,7 @@
@Test
public void canUnrequestTethering() throws Exception {
- initTetheredStateMachine(ConnectivityManager.TETHERING_BLUETOOTH, null);
+ initTetheredStateMachine(TETHERING_BLUETOOTH, null);
dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED);
InOrder inOrder = inOrder(mNMService, mStatsService, mTetherHelper);
@@ -157,7 +160,7 @@
@Test
public void canBeTetheredAsUsb() throws Exception {
- initStateMachine(ConnectivityManager.TETHERING_USB);
+ initStateMachine(TETHERING_USB);
dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_REQUESTED);
InOrder inOrder = inOrder(mTetherHelper, mNMService);
@@ -171,7 +174,7 @@
@Test
public void handlesFirstUpstreamChange() throws Exception {
- initTetheredStateMachine(ConnectivityManager.TETHERING_BLUETOOTH, null);
+ initTetheredStateMachine(TETHERING_BLUETOOTH, null);
// Telling the state machine about its upstream interface triggers a little more configuration.
dispatchTetherConnectionChanged(UPSTREAM_IFACE);
@@ -183,7 +186,7 @@
@Test
public void handlesChangingUpstream() throws Exception {
- initTetheredStateMachine(ConnectivityManager.TETHERING_BLUETOOTH, UPSTREAM_IFACE);
+ initTetheredStateMachine(TETHERING_BLUETOOTH, UPSTREAM_IFACE);
dispatchTetherConnectionChanged(UPSTREAM_IFACE2);
InOrder inOrder = inOrder(mNMService, mStatsService);
@@ -196,8 +199,44 @@
}
@Test
+ public void handlesChangingUpstreamNatFailure() throws Exception {
+ initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE);
+
+ doThrow(RemoteException.class).when(mNMService).enableNat(IFACE_NAME, UPSTREAM_IFACE2);
+
+ dispatchTetherConnectionChanged(UPSTREAM_IFACE2);
+ InOrder inOrder = inOrder(mNMService, mStatsService);
+ inOrder.verify(mStatsService).forceUpdate();
+ inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE);
+ inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE);
+ inOrder.verify(mNMService).enableNat(IFACE_NAME, UPSTREAM_IFACE2);
+ inOrder.verify(mStatsService).forceUpdate();
+ inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE2);
+ inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE2);
+ }
+
+ @Test
+ public void handlesChangingUpstreamInterfaceForwardingFailure() throws Exception {
+ initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE);
+
+ doThrow(RemoteException.class).when(mNMService).startInterfaceForwarding(
+ IFACE_NAME, UPSTREAM_IFACE2);
+
+ dispatchTetherConnectionChanged(UPSTREAM_IFACE2);
+ InOrder inOrder = inOrder(mNMService, mStatsService);
+ inOrder.verify(mStatsService).forceUpdate();
+ inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE);
+ inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE);
+ inOrder.verify(mNMService).enableNat(IFACE_NAME, UPSTREAM_IFACE2);
+ inOrder.verify(mNMService).startInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE2);
+ inOrder.verify(mStatsService).forceUpdate();
+ inOrder.verify(mNMService).stopInterfaceForwarding(IFACE_NAME, UPSTREAM_IFACE2);
+ inOrder.verify(mNMService).disableNat(IFACE_NAME, UPSTREAM_IFACE2);
+ }
+
+ @Test
public void canUnrequestTetheringWithUpstream() throws Exception {
- initTetheredStateMachine(ConnectivityManager.TETHERING_BLUETOOTH, UPSTREAM_IFACE);
+ initTetheredStateMachine(TETHERING_BLUETOOTH, UPSTREAM_IFACE);
dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_UNREQUESTED);
InOrder inOrder = inOrder(mNMService, mStatsService, mTetherHelper);
@@ -213,7 +252,7 @@
@Test
public void interfaceDownLeadsToUnavailable() throws Exception {
for (boolean shouldThrow : new boolean[]{true, false}) {
- initTetheredStateMachine(ConnectivityManager.TETHERING_USB, null);
+ initTetheredStateMachine(TETHERING_USB, null);
if (shouldThrow) {
doThrow(RemoteException.class).when(mNMService).untetherInterface(IFACE_NAME);
@@ -230,7 +269,7 @@
@Test
public void usbShouldBeTornDownOnTetherError() throws Exception {
- initStateMachine(ConnectivityManager.TETHERING_USB);
+ initStateMachine(TETHERING_USB);
doThrow(RemoteException.class).when(mNMService).tetherInterface(IFACE_NAME);
dispatchCommand(TetherInterfaceStateMachine.CMD_TETHER_REQUESTED);
@@ -244,7 +283,7 @@
@Test
public void shouldTearDownUsbOnUpstreamError() throws Exception {
- initTetheredStateMachine(ConnectivityManager.TETHERING_USB, null);
+ initTetheredStateMachine(TETHERING_USB, null);
doThrow(RemoteException.class).when(mNMService).enableNat(anyString(), anyString());
dispatchTetherConnectionChanged(UPSTREAM_IFACE);
@@ -255,6 +294,18 @@
IFACE_NAME, mTestedSm, STATE_AVAILABLE, TETHER_ERROR_ENABLE_NAT_ERROR);
}
+ @Test
+ public void ignoresDuplicateUpstreamNotifications() throws Exception {
+ initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE);
+
+ verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
+
+ for (int i = 0; i < 5; i++) {
+ dispatchTetherConnectionChanged(UPSTREAM_IFACE);
+ verifyNoMoreInteractions(mNMService, mStatsService, mTetherHelper);
+ }
+ }
+
/**
* Send a command to the state machine under test, and run the event loop to idle.
*
diff --git a/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java b/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
index 3ed56df..c72efb0 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
@@ -32,6 +32,8 @@
import static org.mockito.Mockito.verifyNoMoreInteractions;
import android.content.Context;
+import android.os.Handler;
+import android.os.Message;
import android.net.ConnectivityManager;
import android.net.ConnectivityManager.NetworkCallback;
import android.net.IConnectivityManager;
@@ -42,6 +44,10 @@
import android.support.test.filters.SmallTest;
import android.support.test.runner.AndroidJUnit4;
+import com.android.internal.util.State;
+import com.android.internal.util.StateMachine;
+
+import org.junit.After;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.junit.Test;
@@ -49,6 +55,7 @@
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
@@ -63,6 +70,7 @@
@Mock private Context mContext;
@Mock private IConnectivityManager mCS;
+ private TestStateMachine mSM;
private TestConnectivityManager mCM;
private UpstreamNetworkMonitor mUNM;
@@ -72,7 +80,15 @@
reset(mCS);
mCM = spy(new TestConnectivityManager(mContext, mCS));
- mUNM = new UpstreamNetworkMonitor(null, EVENT_UNM_UPDATE, (ConnectivityManager) mCM);
+ mSM = new TestStateMachine();
+ mUNM = new UpstreamNetworkMonitor(mSM, EVENT_UNM_UPDATE, (ConnectivityManager) mCM);
+ }
+
+ @After public void tearDown() throws Exception {
+ if (mSM != null) {
+ mSM.quit();
+ mSM = null;
+ }
}
@Test
@@ -139,15 +155,17 @@
mUNM.start();
verify(mCM, Mockito.times(1)).registerNetworkCallback(
- any(NetworkRequest.class), any(NetworkCallback.class));
- verify(mCM, Mockito.times(1)).registerDefaultNetworkCallback(any(NetworkCallback.class));
+ any(NetworkRequest.class), any(NetworkCallback.class), any(Handler.class));
+ verify(mCM, Mockito.times(1)).registerDefaultNetworkCallback(
+ any(NetworkCallback.class), any(Handler.class));
assertFalse(mUNM.mobileNetworkRequested());
assertEquals(0, mCM.requested.size());
mUNM.updateMobileRequiresDun(true);
mUNM.registerMobileNetworkRequest();
verify(mCM, Mockito.times(1)).requestNetwork(
- any(NetworkRequest.class), any(NetworkCallback.class), anyInt(), anyInt());
+ any(NetworkRequest.class), any(NetworkCallback.class), anyInt(), anyInt(),
+ any(Handler.class));
assertTrue(mUNM.mobileNetworkRequested());
assertUpstreamTypeRequested(TYPE_MOBILE_DUN);
@@ -224,6 +242,7 @@
}
public static class TestConnectivityManager extends ConnectivityManager {
+ public Map<NetworkCallback, Handler> allCallbacks = new HashMap<>();
public Set<NetworkCallback> trackingDefault = new HashSet<>();
public Map<NetworkCallback, NetworkRequest> listening = new HashMap<>();
public Map<NetworkCallback, NetworkRequest> requested = new HashMap<>();
@@ -234,7 +253,8 @@
}
boolean hasNoCallbacks() {
- return trackingDefault.isEmpty() &&
+ return allCallbacks.isEmpty() &&
+ trackingDefault.isEmpty() &&
listening.isEmpty() &&
requested.isEmpty() &&
legacyTypeMap.isEmpty();
@@ -262,14 +282,23 @@
}
@Override
- public void requestNetwork(NetworkRequest req, NetworkCallback cb) {
+ public void requestNetwork(NetworkRequest req, NetworkCallback cb, Handler h) {
+ assertFalse(allCallbacks.containsKey(cb));
+ allCallbacks.put(cb, h);
assertFalse(requested.containsKey(cb));
requested.put(cb, req);
}
@Override
+ public void requestNetwork(NetworkRequest req, NetworkCallback cb) {
+ fail("Should never be called.");
+ }
+
+ @Override
public void requestNetwork(NetworkRequest req, NetworkCallback cb,
- int timeoutMs, int legacyType) {
+ int timeoutMs, int legacyType, Handler h) {
+ assertFalse(allCallbacks.containsKey(cb));
+ allCallbacks.put(cb, h);
assertFalse(requested.containsKey(cb));
requested.put(cb, req);
assertFalse(legacyTypeMap.containsKey(cb));
@@ -279,18 +308,32 @@
}
@Override
- public void registerNetworkCallback(NetworkRequest req, NetworkCallback cb) {
+ public void registerNetworkCallback(NetworkRequest req, NetworkCallback cb, Handler h) {
+ assertFalse(allCallbacks.containsKey(cb));
+ allCallbacks.put(cb, h);
assertFalse(listening.containsKey(cb));
listening.put(cb, req);
}
@Override
- public void registerDefaultNetworkCallback(NetworkCallback cb) {
+ public void registerNetworkCallback(NetworkRequest req, NetworkCallback cb) {
+ fail("Should never be called.");
+ }
+
+ @Override
+ public void registerDefaultNetworkCallback(NetworkCallback cb, Handler h) {
+ assertFalse(allCallbacks.containsKey(cb));
+ allCallbacks.put(cb, h);
assertFalse(trackingDefault.contains(cb));
trackingDefault.add(cb);
}
@Override
+ public void registerDefaultNetworkCallback(NetworkCallback cb) {
+ fail("Should never be called.");
+ }
+
+ @Override
public void unregisterNetworkCallback(NetworkCallback cb) {
if (trackingDefault.contains(cb)) {
trackingDefault.remove(cb);
@@ -302,10 +345,35 @@
} else {
fail("Unexpected callback removed");
}
+ allCallbacks.remove(cb);
+ assertFalse(allCallbacks.containsKey(cb));
assertFalse(trackingDefault.contains(cb));
assertFalse(listening.containsKey(cb));
assertFalse(requested.containsKey(cb));
}
}
+
+ public static class TestStateMachine extends StateMachine {
+ public final ArrayList<Message> messages = new ArrayList<>();
+ private final State mLoggingState = new LoggingState();
+
+ class LoggingState extends State {
+ @Override public void enter() { messages.clear(); }
+
+ @Override public void exit() { messages.clear(); }
+
+ @Override public boolean processMessage(Message msg) {
+ messages.add(msg);
+ return true;
+ }
+ }
+
+ public TestStateMachine() {
+ super("UpstreamNetworkMonitor.TestStateMachine");
+ addState(mLoggingState);
+ setInitialState(mLoggingState);
+ super.start();
+ }
+ }
}
diff --git a/tools/fonts/fontchain_lint.py b/tools/fonts/fontchain_lint.py
index 7ec46a3e..c5598f0 100755
--- a/tools/fonts/fontchain_lint.py
+++ b/tools/fonts/fontchain_lint.py
@@ -14,7 +14,9 @@
LANG_TO_SCRIPT = {
'as': 'Beng',
+ 'bg': 'Cyrl',
'bn': 'Beng',
+ 'cu': 'Cyrl',
'cy': 'Latn',
'da': 'Latn',
'de': 'Latn',
diff --git a/tools/layoutlib/create/Android.mk b/tools/layoutlib/create/Android.mk
index c7f2c41..7611cde 100644
--- a/tools/layoutlib/create/Android.mk
+++ b/tools/layoutlib/create/Android.mk
@@ -20,7 +20,7 @@
LOCAL_JAR_MANIFEST := manifest.txt
LOCAL_STATIC_JAVA_LIBRARIES := \
- asm-5.0
+ asm-5.2
LOCAL_MODULE := layoutlib_create
diff --git a/tools/layoutlib/create/tests/Android.mk b/tools/layoutlib/create/tests/Android.mk
index 61e381d..488d7d6 100644
--- a/tools/layoutlib/create/tests/Android.mk
+++ b/tools/layoutlib/create/tests/Android.mk
@@ -24,7 +24,7 @@
LOCAL_MODULE_TAGS := optional
LOCAL_JAVA_LIBRARIES := layoutlib_create junit-host
-LOCAL_STATIC_JAVA_LIBRARIES := asm-5.0
+LOCAL_STATIC_JAVA_LIBRARIES := asm-5.2
include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 306f6f5..2ba573c 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -845,6 +845,7 @@
* This network is disabled because EAP-TLS failure
*/
public static final int DISABLED_TLS_VERSION_MISMATCH = 7;
+ // Values above are for temporary disablement; values below are for permanent disablement.
/**
* This network is disabled due to absence of user credentials
*/
@@ -969,6 +970,28 @@
private boolean mHasEverConnected;
/**
+ * Boolean indicating whether {@link com.android.server.wifi.RecommendedNetworkEvaluator}
+ * chose not to connect to this network in the last qualified network selection process.
+ */
+ private boolean mNotRecommended;
+
+ /**
+ * Set whether {@link com.android.server.wifi.RecommendedNetworkEvaluator} does not
+ * recommend connecting to this network.
+ */
+ public void setNotRecommended(boolean notRecommended) {
+ mNotRecommended = notRecommended;
+ }
+
+ /**
+ * Returns whether {@link com.android.server.wifi.RecommendedNetworkEvaluator} does not
+ * recommend connecting to this network.
+ */
+ public boolean isNotRecommended() {
+ return mNotRecommended;
+ }
+
+ /**
* set whether this network is visible in latest Qualified Network Selection
* @param seen value set to candidate
*/
@@ -1272,6 +1295,7 @@
setConnectChoice(source.getConnectChoice());
setConnectChoiceTimestamp(source.getConnectChoiceTimestamp());
setHasEverConnected(source.getHasEverConnected());
+ setNotRecommended(source.isNotRecommended());
}
public void writeToParcel(Parcel dest) {
@@ -1291,6 +1315,7 @@
dest.writeInt(CONNECT_CHOICE_NOT_EXISTS);
}
dest.writeInt(getHasEverConnected() ? 1 : 0);
+ dest.writeInt(isNotRecommended() ? 1 : 0);
}
public void readFromParcel(Parcel in) {
@@ -1310,6 +1335,7 @@
setConnectChoiceTimestamp(INVALID_NETWORK_SELECTION_DISABLE_TIMESTAMP);
}
setHasEverConnected(in.readInt() != 0);
+ setNotRecommended(in.readInt() != 0);
}
}
diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
index 0bfb955..f790332 100644
--- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
+++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
@@ -263,11 +263,17 @@
public static final int MSCHAPV2 = 3;
/** Generic Token Card */
public static final int GTC = 4;
+ /** EAP-Subscriber Identity Module */
+ public static final int SIM = 5;
+ /** EAP-Authentication and Key Agreement */
+ public static final int AKA = 6;
+ /** EAP-Authentication and Key Agreement Prime */
+ public static final int AKA_PRIME = 7;
private static final String AUTH_PREFIX = "auth=";
private static final String AUTHEAP_PREFIX = "autheap=";
/** @hide */
public static final String[] strings = {EMPTY_VALUE, "PAP", "MSCHAP",
- "MSCHAPV2", "GTC" };
+ "MSCHAPV2", "GTC", "SIM", "AKA", "AKA'" };
/** Prevent initialization */
private Phase2() {}
@@ -426,6 +432,9 @@
case Phase2.MSCHAP:
case Phase2.MSCHAPV2:
case Phase2.GTC:
+ case Phase2.SIM:
+ case Phase2.AKA:
+ case Phase2.AKA_PRIME:
mPhase2Method = phase2Method;
break;
default:
diff --git a/wifi/java/android/net/wifi/WifiSsid.java b/wifi/java/android/net/wifi/WifiSsid.java
index c53cd3c..7a3cddf 100644
--- a/wifi/java/android/net/wifi/WifiSsid.java
+++ b/wifi/java/android/net/wifi/WifiSsid.java
@@ -49,6 +49,14 @@
private WifiSsid() {
}
+ public static WifiSsid createFromByteArray(byte ssid[]) {
+ WifiSsid wifiSsid = new WifiSsid();
+ if (ssid != null) {
+ wifiSsid.octets.write(ssid, 0/* the start offset */, ssid.length);;
+ }
+ return wifiSsid;
+ }
+
public static WifiSsid createFromAsciiEncoded(String asciiEncoded) {
WifiSsid a = new WifiSsid();
a.convertToBytes(asciiEncoded);
diff --git a/wifi/java/android/net/wifi/aware/ConfigRequest.java b/wifi/java/android/net/wifi/aware/ConfigRequest.java
index 6a5957b..cc14ab2 100644
--- a/wifi/java/android/net/wifi/aware/ConfigRequest.java
+++ b/wifi/java/android/net/wifi/aware/ConfigRequest.java
@@ -19,6 +19,8 @@
import android.os.Parcel;
import android.os.Parcelable;
+import java.util.Arrays;
+
/**
* Defines a request object to configure a Wi-Fi Aware network. Built using
* {@link ConfigRequest.Builder}. Configuration is requested using
@@ -41,6 +43,18 @@
public static final int CLUSTER_ID_MAX = 0xFFFF;
/**
+ * Indices for configuration variables which are specified per band.
+ */
+ public static final int NAN_BAND_24GHZ = 0;
+ public static final int NAN_BAND_5GHZ = 1;
+
+ /**
+ * Magic values for Discovery Window (DW) interval configuration
+ */
+ public static final int DW_INTERVAL_NOT_INIT = -1;
+ public static final int DW_DISABLE = 0; // only valid for 5GHz
+
+ /**
* Indicates whether 5G band support is requested.
*/
public final boolean mSupport5gBand;
@@ -62,19 +76,26 @@
*/
public final int mClusterHigh;
+ /**
+ * Specifies the discovery window interval for the device on NAN_BAND_*.
+ */
+ public final int mDiscoveryWindowInterval[];
+
private ConfigRequest(boolean support5gBand, int masterPreference, int clusterLow,
- int clusterHigh) {
+ int clusterHigh, int discoveryWindowInterval[]) {
mSupport5gBand = support5gBand;
mMasterPreference = masterPreference;
mClusterLow = clusterLow;
mClusterHigh = clusterHigh;
+ mDiscoveryWindowInterval = discoveryWindowInterval;
}
@Override
public String toString() {
return "ConfigRequest [mSupport5gBand=" + mSupport5gBand + ", mMasterPreference="
+ mMasterPreference + ", mClusterLow=" + mClusterLow + ", mClusterHigh="
- + mClusterHigh + "]";
+ + mClusterHigh + ", mDiscoveryWindowInterval="
+ + Arrays.toString(mDiscoveryWindowInterval) + "]";
}
@Override
@@ -88,6 +109,7 @@
dest.writeInt(mMasterPreference);
dest.writeInt(mClusterLow);
dest.writeInt(mClusterHigh);
+ dest.writeIntArray(mDiscoveryWindowInterval);
}
public static final Creator<ConfigRequest> CREATOR = new Creator<ConfigRequest>() {
@@ -102,7 +124,10 @@
int masterPreference = in.readInt();
int clusterLow = in.readInt();
int clusterHigh = in.readInt();
- return new ConfigRequest(support5gBand, masterPreference, clusterLow, clusterHigh);
+ int discoveryWindowInterval[] = in.createIntArray();
+
+ return new ConfigRequest(support5gBand, masterPreference, clusterLow, clusterHigh,
+ discoveryWindowInterval);
}
};
@@ -119,17 +144,8 @@
ConfigRequest lhs = (ConfigRequest) o;
return mSupport5gBand == lhs.mSupport5gBand && mMasterPreference == lhs.mMasterPreference
- && mClusterLow == lhs.mClusterLow && mClusterHigh == lhs.mClusterHigh;
- }
-
- /**
- * Checks whether the configuration's settings are non-default.
- *
- * @return true if any of the settings are non-default.
- */
- public boolean isNonDefault() {
- return mSupport5gBand || mMasterPreference != 0 || mClusterLow != CLUSTER_ID_MIN
- || mClusterHigh != CLUSTER_ID_MAX;
+ && mClusterLow == lhs.mClusterLow && mClusterHigh == lhs.mClusterHigh
+ && Arrays.equals(mDiscoveryWindowInterval, lhs.mDiscoveryWindowInterval);
}
@Override
@@ -140,6 +156,7 @@
result = 31 * result + mMasterPreference;
result = 31 * result + mClusterLow;
result = 31 * result + mClusterHigh;
+ result = 31 * result + Arrays.hashCode(mDiscoveryWindowInterval);
return result;
}
@@ -173,6 +190,23 @@
throw new IllegalArgumentException(
"Invalid argument combination - must have Cluster Low <= Cluster High");
}
+ if (mDiscoveryWindowInterval.length != 2) {
+ throw new IllegalArgumentException(
+ "Invalid discovery window interval: must have 2 elements (2.4 & 5");
+ }
+ if (mDiscoveryWindowInterval[NAN_BAND_24GHZ] != DW_INTERVAL_NOT_INIT &&
+ (mDiscoveryWindowInterval[NAN_BAND_24GHZ] < 1 // valid for 2.4GHz: [1-5]
+ || mDiscoveryWindowInterval[NAN_BAND_24GHZ] > 5)) {
+ throw new IllegalArgumentException(
+ "Invalid discovery window interval for 2.4GHz: valid is UNSET or [1,5]");
+ }
+ if (mDiscoveryWindowInterval[NAN_BAND_5GHZ] != DW_INTERVAL_NOT_INIT &&
+ (mDiscoveryWindowInterval[NAN_BAND_5GHZ] < 0 // valid for 5GHz: [0-5]
+ || mDiscoveryWindowInterval[NAN_BAND_5GHZ] > 5)) {
+ throw new IllegalArgumentException(
+ "Invalid discovery window interval for 5GHz: valid is UNSET or [0,5]");
+ }
+
}
/**
@@ -183,6 +217,7 @@
private int mMasterPreference = 0;
private int mClusterLow = CLUSTER_ID_MIN;
private int mClusterHigh = CLUSTER_ID_MAX;
+ private int mDiscoveryWindowInterval[] = {DW_INTERVAL_NOT_INIT, DW_INTERVAL_NOT_INIT};
/**
* Specify whether 5G band support is required in this request. Disabled by default.
@@ -271,6 +306,33 @@
}
/**
+ * The discovery window interval specifies the discovery windows in which the device will be
+ * awake. The configuration enables trading off latency vs. power (higher interval means
+ * higher discovery latency but lower power).
+ *
+ * @param band Either {@link #NAN_BAND_24GHZ} or {@link #NAN_BAND_5GHZ}.
+ * @param interval A value of 1, 2, 3, 4, or 5 indicating an interval of 2^(interval-1). For
+ * the 5GHz band a value of 0 indicates that the device will not be awake
+ * for any discovery windows.
+ *
+ * @return The builder itself to facilitate chaining operations
+ * {@code builder.setDiscoveryWindowInterval(...).setMasterPreference(...)}.
+ */
+ public Builder setDiscoveryWindowInterval(int band, int interval) {
+ if (band != NAN_BAND_24GHZ && band != NAN_BAND_5GHZ) {
+ throw new IllegalArgumentException("Invalid band value");
+ }
+ if ((band == NAN_BAND_24GHZ && (interval < 1 || interval > 5))
+ || (band == NAN_BAND_5GHZ && (interval < 0 || interval > 5))) {
+ throw new IllegalArgumentException(
+ "Invalid interval value: 2.4 GHz [1,5] or 5GHz [0,5]");
+ }
+
+ mDiscoveryWindowInterval[band] = interval;
+ return this;
+ }
+
+ /**
* Build {@link ConfigRequest} given the current requests made on the
* builder.
*/
@@ -280,7 +342,8 @@
"Invalid argument combination - must have Cluster Low <= Cluster High");
}
- return new ConfigRequest(mSupport5gBand, mMasterPreference, mClusterLow, mClusterHigh);
+ return new ConfigRequest(mSupport5gBand, mMasterPreference, mClusterLow, mClusterHigh,
+ mDiscoveryWindowInterval);
}
}
}
diff --git a/wifi/java/android/net/wifi/aware/DiscoverySession.java b/wifi/java/android/net/wifi/aware/DiscoverySession.java
index adf189b..59fe1ee 100644
--- a/wifi/java/android/net/wifi/aware/DiscoverySession.java
+++ b/wifi/java/android/net/wifi/aware/DiscoverySession.java
@@ -31,8 +31,7 @@
* {@link PublishDiscoverySession} and {@link SubscribeDiscoverySession}. This
* class provides functionality common to both publish and subscribe discovery sessions:
* <ul>
- * <li>Sending messages: {@link #sendMessage(PeerHandle, int, byte[])} or
- * {@link #sendMessage(PeerHandle, int, byte[], int)} methods.
+ * <li>Sending messages: {@link #sendMessage(PeerHandle, int, byte[])} method.
* <li>Creating a network-specifier when requesting a Aware connection:
* {@link #createNetworkSpecifier(PeerHandle, byte[])}.
* </ul>
@@ -62,6 +61,8 @@
* {@link #sendMessage(PeerHandle, int, byte[], int)}.
*
* @return Maximum retry count when sending messages.
+ *
+ * @hide
*/
public static int getMaxSendRetryCount() {
return MAX_SEND_RETRY_COUNT;
@@ -163,6 +164,8 @@
* or MAC level) retries should be attempted if there is no ACK from the receiver
* (note: no retransmissions are attempted in other failure cases). A value of 0
* indicates no retries. Max permitted value is {@link #getMaxSendRetryCount()}.
+ *
+ * @hide
*/
public void sendMessage(@NonNull PeerHandle peerHandle, int messageId,
@Nullable byte[] message, int retryCount) {
@@ -195,8 +198,6 @@
* The peer will get a callback indicating a message was received using
* {@link DiscoverySessionCallback#onMessageReceived(PeerHandle,
* byte[])}.
- * Equivalent to {@link #sendMessage(PeerHandle, int, byte[], int)}
- * with a {@code retryCount} of 0.
*
* @param peerHandle The peer's handle for the message. Must be a result of an
* {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle,
@@ -246,8 +247,8 @@
}
/**
- * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} for a
- * WiFi Aware connection to the specified peer. The
+ * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} for an
+ * unencrypted WiFi Aware connection (link) to the specified peer. The
* {@link android.net.NetworkRequest.Builder#addTransportType(int)} should be set to
* {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}.
* <p>
@@ -255,7 +256,58 @@
* discovery or communication (in such scenarios the MAC address of the peer is shielded by
* an opaque peer ID handle). If a Aware connection is needed to a peer discovered using other
* OOB (out-of-band) mechanism then use the alternative
- * {@link WifiAwareSession#createNetworkSpecifier(int, byte[], byte[])} method - which uses the
+ * {@link WifiAwareSession#createNetworkSpecifierOpen(int, byte[])} method - which uses the
+ * peer's MAC address.
+ * <p>
+ * Note: per the Wi-Fi Aware specification the roles are fixed - a Subscriber is an INITIATOR
+ * and a Publisher is a RESPONDER.
+ *
+ * @param peerHandle The peer's handle obtained through
+ * {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle, byte[], java.util.List)}
+ * or
+ * {@link DiscoverySessionCallback#onMessageReceived(PeerHandle, byte[])}.
+ * On a RESPONDER this value is used to gate the acceptance of a connection
+ * request from only that peer. A RESPONDER may specify a null - indicating
+ * that it will accept connection requests from any device.
+ *
+ * @return A string to be used to construct
+ * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} to pass to
+ * {@link android.net.ConnectivityManager#requestNetwork(android.net.NetworkRequest,
+ * android.net.ConnectivityManager.NetworkCallback)}
+ * [or other varieties of that API].
+ *
+ * @hide
+ */
+ public String createNetworkSpecifierOpen(@Nullable PeerHandle peerHandle) {
+ if (mTerminated) {
+ Log.w(TAG, "createNetworkSpecifierOpen: called on terminated session");
+ return null;
+ } else {
+ WifiAwareManager mgr = mMgr.get();
+ if (mgr == null) {
+ Log.w(TAG, "createNetworkSpecifierOpen: called post GC on WifiAwareManager");
+ return null;
+ }
+
+ int role = this instanceof SubscribeDiscoverySession
+ ? WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR
+ : WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER;
+
+ return mgr.createNetworkSpecifier(mClientId, role, mSessionId, peerHandle, null);
+ }
+ }
+
+ /**
+ * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} for an
+ * encrypted WiFi Aware connection (link) to the specified peer. The
+ * {@link android.net.NetworkRequest.Builder#addTransportType(int)} should be set to
+ * {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}.
+ * <p>
+ * This method should be used when setting up a connection with a peer discovered through Aware
+ * discovery or communication (in such scenarios the MAC address of the peer is shielded by
+ * an opaque peer ID handle). If a Aware connection is needed to a peer discovered using other
+ * OOB (out-of-band) mechanism then use the alternative
+ * {@link WifiAwareSession#createNetworkSpecifierPmk(int, byte[], byte[])} method - which uses the
* peer's MAC address.
* <p>
* Note: per the Wi-Fi Aware specification the roles are fixed - a Subscriber is an INITIATOR
@@ -266,29 +318,34 @@
* byte[], java.util.List)} or
* {@link DiscoverySessionCallback#onMessageReceived(PeerHandle,
* byte[])}. On a RESPONDER this value is used to gate the acceptance of a connection request
- * from only that peer. A RESPONDER may specified a null - indicating that
+ * from only that peer. A RESPONDER may specify a null - indicating that
* it will accept connection requests from any device.
- * @param token An arbitrary token (message) to be used to match connection initiation request
- * to a responder setup. A RESPONDER is set up with a {@code token} which must
- * be matched by the token provided by the INITIATOR. A null token is permitted
- * on the RESPONDER and matches any peer token. An empty ({@code ""}) token is
- * not the same as a null token and requires the peer token to be empty as well.
+ * @param pmk A PMK (pairwise master key, see IEEE 802.11i) specifying the key to use for
+ * encrypting the data-path. Use the
+ * {@link #createNetworkSpecifierOpen(PeerHandle)} to specify an open (unencrypted)
+ * link.
*
* @return A string to be used to construct
* {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} to pass to
* {@link android.net.ConnectivityManager#requestNetwork(android.net.NetworkRequest,
* android.net.ConnectivityManager.NetworkCallback)}
* [or other varieties of that API].
+ *
+ * @hide
*/
- public String createNetworkSpecifier(@Nullable PeerHandle peerHandle,
- @Nullable byte[] token) {
+ public String createNetworkSpecifierPmk(@Nullable PeerHandle peerHandle,
+ @NonNull byte[] pmk) {
+ if (pmk == null || pmk.length == 0) {
+ throw new IllegalArgumentException("PMK must not be null or empty");
+ }
+
if (mTerminated) {
- Log.w(TAG, "createNetworkSpecifier: called on terminated session");
+ Log.w(TAG, "createNetworkSpecifierPmk: called on terminated session");
return null;
} else {
WifiAwareManager mgr = mMgr.get();
if (mgr == null) {
- Log.w(TAG, "createNetworkSpecifier: called post GC on WifiAwareManager");
+ Log.w(TAG, "createNetworkSpecifierPmk: called post GC on WifiAwareManager");
return null;
}
@@ -296,7 +353,30 @@
? WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR
: WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER;
- return mgr.createNetworkSpecifier(mClientId, role, mSessionId, peerHandle, token);
+ return mgr.createNetworkSpecifier(mClientId, role, mSessionId, peerHandle, pmk);
}
}
+
+ /**
+ * Place-holder for {@code createNetworkSpecifierOpen(PeerHandle)}. Present to enable
+ * development of replacements CL without causing an API change. Will be removed when new
+ * APIs are exposed.
+ *
+ * @param peerHandle The peer's handle obtained through
+ * {@link DiscoverySessionCallback#onServiceDiscovered(PeerHandle,
+ * byte[], java.util.List)} or
+ * {@link DiscoverySessionCallback#onMessageReceived(PeerHandle,
+ * byte[])}. On a RESPONDER this value is used to gate the acceptance of a connection request
+ * from only that peer. A RESPONDER may specify a null - indicating that
+ * it will accept connection requests from any device.
+ * @param token Deprecated and ignored.
+ * @return A string to be used to construct
+ * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} to pass to
+ * {@link android.net.ConnectivityManager#requestNetwork(android.net.NetworkRequest,
+ * android.net.ConnectivityManager.NetworkCallback)}
+ * [or other varieties of that API].
+ */
+ public String createNetworkSpecifier(@Nullable PeerHandle peerHandle, @Nullable byte[] token) {
+ return createNetworkSpecifierOpen(peerHandle);
+ }
}
diff --git a/wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java b/wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java
index 33da182..9645b1d 100644
--- a/wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java
+++ b/wifi/java/android/net/wifi/aware/DiscoverySessionCallback.java
@@ -124,10 +124,9 @@
}
/**
- * Called when message transmission fails - when no ACK is received from the peer.
- * Retries when ACKs are not received are done by hardware, MAC, and in the Aware stack (using
- * the {@link DiscoverySession#sendMessage(PeerHandle, int,
- * byte[], int)} method) - this event is received after all retries are exhausted.
+ * Called when message transmission initiated with
+ * {@link DiscoverySession#sendMessage(PeerHandle, int, byte[])} fails. E.g. when no ACK is
+ * received from the peer.
* <p>
* Note that either this callback or
* {@link DiscoverySessionCallback#onMessageSendSucceeded(int)} will be received
@@ -141,9 +140,7 @@
/**
* Called when a message is received from a discovery session peer - in response to the
- * peer's {@link DiscoverySession#sendMessage(PeerHandle, int,
- * byte[])} or {@link DiscoverySession#sendMessage(PeerHandle,
- * int, byte[], int)}.
+ * peer's {@link DiscoverySession#sendMessage(PeerHandle, int, byte[])}.
*
* @param peerHandle An opaque handle to the peer matching our discovery operation.
* @param message A byte array containing the message.
diff --git a/wifi/java/android/net/wifi/aware/IWifiAwareManager.aidl b/wifi/java/android/net/wifi/aware/IWifiAwareManager.aidl
index 794c142..0f4910f 100644
--- a/wifi/java/android/net/wifi/aware/IWifiAwareManager.aidl
+++ b/wifi/java/android/net/wifi/aware/IWifiAwareManager.aidl
@@ -34,8 +34,6 @@
interface IWifiAwareManager
{
// Aware API
- void enableUsage();
- void disableUsage();
boolean isUsageEnabled();
Characteristics getCharacteristics();
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareManager.java b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
index a9e38ce..3d784ba 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareManager.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareManager.java
@@ -130,55 +130,34 @@
*/
/**
- * TYPE_1A: role, client_id, session_id, peer_id, token
+ * TYPE: in band, specific peer: role, client_id, session_id, peer_id, pmk optional
* @hide
*/
- public static final int NETWORK_SPECIFIER_TYPE_1A = 0;
+ public static final int NETWORK_SPECIFIER_TYPE_IB = 0;
/**
- * TYPE_1B: role, client_id, session_id, peer_id [only permitted for RESPONDER]
+ * TYPE: in band, any peer: role, client_id, session_id, pmk optional
+ * [only permitted for RESPONDER]
* @hide
*/
- public static final int NETWORK_SPECIFIER_TYPE_1B = 1;
+ public static final int NETWORK_SPECIFIER_TYPE_IB_ANY_PEER = 1;
/**
- * TYPE_1C: role, client_id, session_id, token [only permitted for RESPONDER]
+ * TYPE: out-of-band: role, client_id, peer_mac, pmk optional
* @hide
*/
- public static final int NETWORK_SPECIFIER_TYPE_1C = 2;
+ public static final int NETWORK_SPECIFIER_TYPE_OOB = 2;
/**
- * TYPE_1C: role, client_id, session_id [only permitted for RESPONDER]
+ * TYPE: out-of-band, any peer: role, client_id, pmk optional
+ * [only permitted for RESPONDER]
* @hide
*/
- public static final int NETWORK_SPECIFIER_TYPE_1D = 3;
+ public static final int NETWORK_SPECIFIER_TYPE_OOB_ANY_PEER = 3;
- /**
- * TYPE_2A: role, client_id, peer_mac, token
- * @hide
- */
- public static final int NETWORK_SPECIFIER_TYPE_2A = 4;
-
- /**
- * TYPE_2B: role, client_id, peer_mac [only permitted for RESPONDER]
- * @hide
- */
- public static final int NETWORK_SPECIFIER_TYPE_2B = 5;
-
- /**
- * TYPE_2C: role, client_id, token [only permitted for RESPONDER]
- * @hide
- */
- public static final int NETWORK_SPECIFIER_TYPE_2C = 6;
-
- /**
- * TYPE_2D: role, client_id [only permitted for RESPONDER]
- * @hide
- */
- public static final int NETWORK_SPECIFIER_TYPE_2D = 7;
/** @hide */
- public static final int NETWORK_SPECIFIER_TYPE_MAX_VALID = NETWORK_SPECIFIER_TYPE_2D;
+ public static final int NETWORK_SPECIFIER_TYPE_MAX_VALID = NETWORK_SPECIFIER_TYPE_OOB_ANY_PEER;
/** @hide */
public static final String NETWORK_SPECIFIER_KEY_TYPE = "type";
@@ -199,7 +178,7 @@
public static final String NETWORK_SPECIFIER_KEY_PEER_MAC = "peer_mac";
/** @hide */
- public static final String NETWORK_SPECIFIER_KEY_TOKEN = "token";
+ public static final String NETWORK_SPECIFIER_KEY_PMK = "pmk";
/**
* Broadcast intent action to indicate that the state of Wi-Fi Aware availability has changed.
@@ -253,36 +232,6 @@
}
/**
- * Enable the usage of the Aware API. Doesn't actually turn on Aware cluster formation - that
- * only happens when an attach is attempted. {@link #ACTION_WIFI_AWARE_STATE_CHANGED} broadcast
- * will be triggered.
- *
- * @hide
- */
- public void enableUsage() {
- try {
- mService.enableUsage();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
- * Disable the usage of the Aware API. All attempts to attach() will be rejected. All open
- * connections and sessions will be terminated. {@link #ACTION_WIFI_AWARE_STATE_CHANGED}
- * broadcast will be triggered.
- *
- * @hide
- */
- public void disableUsage() {
- try {
- mService.disableUsage();
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
* Returns the current status of Aware API: whether or not Aware is available. To track
* changes in the state of Aware API register for the
* {@link #ACTION_WIFI_AWARE_STATE_CHANGED} broadcast.
@@ -524,23 +473,15 @@
/** @hide */
public String createNetworkSpecifier(int clientId, int role, int sessionId,
- PeerHandle peerHandle, byte[] token) {
+ PeerHandle peerHandle, @Nullable byte[] pmk) {
if (VDBG) {
Log.v(TAG, "createNetworkSpecifier: role=" + role + ", sessionId=" + sessionId
+ ", peerHandle=" + ((peerHandle == null) ? peerHandle : peerHandle.peerId)
- + ", token=" + token);
+ + ", pmk=" + ((pmk == null) ? "null" : "non-null"));
}
- int type;
- if (token != null && peerHandle != null) {
- type = NETWORK_SPECIFIER_TYPE_1A;
- } else if (token == null && peerHandle != null) {
- type = NETWORK_SPECIFIER_TYPE_1B;
- } else if (token != null && peerHandle == null) {
- type = NETWORK_SPECIFIER_TYPE_1C;
- } else {
- type = NETWORK_SPECIFIER_TYPE_1D;
- }
+ int type = (peerHandle == null) ? NETWORK_SPECIFIER_TYPE_IB_ANY_PEER
+ : NETWORK_SPECIFIER_TYPE_IB;
if (role != WIFI_AWARE_DATA_PATH_ROLE_INITIATOR
&& role != WIFI_AWARE_DATA_PATH_ROLE_RESPONDER) {
@@ -549,10 +490,6 @@
+ "specifier");
}
if (role == WIFI_AWARE_DATA_PATH_ROLE_INITIATOR) {
- if (token == null) {
- throw new IllegalArgumentException(
- "createNetworkSpecifier: Invalid null token - not permitted on INITIATOR");
- }
if (peerHandle == null) {
throw new IllegalArgumentException(
"createNetworkSpecifier: Invalid peer handle (value of null) - not "
@@ -570,10 +507,11 @@
if (peerHandle != null) {
json.put(NETWORK_SPECIFIER_KEY_PEER_ID, peerHandle.peerId);
}
- if (token != null) {
- json.put(NETWORK_SPECIFIER_KEY_TOKEN,
- Base64.encodeToString(token, 0, token.length, Base64.DEFAULT));
+ if (pmk == null) {
+ pmk = new byte[0];
}
+ json.put(NETWORK_SPECIFIER_KEY_PMK,
+ Base64.encodeToString(pmk, 0, pmk.length, Base64.DEFAULT));
} catch (JSONException e) {
return "";
}
@@ -583,21 +521,14 @@
/** @hide */
public String createNetworkSpecifier(int clientId, @DataPathRole int role,
- @Nullable byte[] peer, @Nullable byte[] token) {
+ @Nullable byte[] peer, @Nullable byte[] pmk) {
if (VDBG) {
- Log.v(TAG, "createNetworkSpecifier: role=" + role + ", token=" + token);
+ Log.v(TAG, "createNetworkSpecifier: role=" + role
+ + ", pmk=" + ((pmk == null) ? "null" : "non-null"));
}
- int type;
- if (token != null && peer != null) {
- type = NETWORK_SPECIFIER_TYPE_2A;
- } else if (token == null && peer != null) {
- type = NETWORK_SPECIFIER_TYPE_2B;
- } else if (token != null && peer == null) {
- type = NETWORK_SPECIFIER_TYPE_2C;
- } else { // both are null
- type = NETWORK_SPECIFIER_TYPE_2D;
- }
+ int type = (peer == null) ?
+ NETWORK_SPECIFIER_TYPE_OOB_ANY_PEER : NETWORK_SPECIFIER_TYPE_OOB;
if (role != WIFI_AWARE_DATA_PATH_ROLE_INITIATOR
&& role != WIFI_AWARE_DATA_PATH_ROLE_RESPONDER) {
@@ -606,19 +537,13 @@
+ "specifier");
}
if (role == WIFI_AWARE_DATA_PATH_ROLE_INITIATOR) {
- if (peer == null || peer.length != 6) {
- throw new IllegalArgumentException(
- "createNetworkSpecifier: Invalid peer MAC address");
+ if (peer == null) {
+ throw new IllegalArgumentException("createNetworkSpecifier: Invalid peer MAC "
+ + "address - null not permitted on INITIATOR");
}
- if (token == null) {
- throw new IllegalArgumentException(
- "createNetworkSpecifier: Invalid null token - not permitted on INITIATOR");
- }
- } else {
- if (peer != null && peer.length != 6) {
- throw new IllegalArgumentException(
- "createNetworkSpecifier: Invalid peer MAC address");
- }
+ }
+ if (peer != null && peer.length != 6) {
+ throw new IllegalArgumentException("createNetworkSpecifier: Invalid peer MAC address");
}
JSONObject json;
@@ -630,10 +555,11 @@
if (peer != null) {
json.put(NETWORK_SPECIFIER_KEY_PEER_MAC, new String(HexEncoding.encode(peer)));
}
- if (token != null) {
- json.put(NETWORK_SPECIFIER_KEY_TOKEN,
- Base64.encodeToString(token, 0, token.length, Base64.DEFAULT));
+ if (pmk == null) {
+ pmk = new byte[0];
}
+ json.put(NETWORK_SPECIFIER_KEY_PMK,
+ Base64.encodeToString(pmk, 0, pmk.length, Base64.DEFAULT));
} catch (JSONException e) {
return "";
}
diff --git a/wifi/java/android/net/wifi/aware/WifiAwareSession.java b/wifi/java/android/net/wifi/aware/WifiAwareSession.java
index 8696920..856066e 100644
--- a/wifi/java/android/net/wifi/aware/WifiAwareSession.java
+++ b/wifi/java/android/net/wifi/aware/WifiAwareSession.java
@@ -183,47 +183,114 @@
}
/**
- * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} for a
- * WiFi Aware connection to the specified peer. The
+ * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} for an
+ * unencrypted WiFi Aware connection (link) to the specified peer. The
* {@link android.net.NetworkRequest.Builder#addTransportType(int)} should be set to
* {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}.
* <p>
* This API is targeted for applications which can obtain the peer MAC address using OOB
* (out-of-band) discovery. Aware discovery does not provide the MAC address of the peer -
* when using Aware discovery use the alternative network specifier method -
- * {@link DiscoverySession#createNetworkSpecifier(PeerHandle,
- * byte[])}.
+ * {@link DiscoverySession#createNetworkSpecifierOpen(PeerHandle)}.
*
* @param role The role of this device:
* {@link WifiAwareManager#WIFI_AWARE_DATA_PATH_ROLE_INITIATOR} or
* {@link WifiAwareManager#WIFI_AWARE_DATA_PATH_ROLE_RESPONDER}
* @param peer The MAC address of the peer's Aware discovery interface. On a RESPONDER this
* value is used to gate the acceptance of a connection request from only that
- * peer. A RESPONDER may specified a null - indicating that it will accept
+ * peer. A RESPONDER may specify a null - indicating that it will accept
* connection requests from any device.
- * @param token An arbitrary token (message) to be used to match connection initiation request
- * to a responder setup. A RESPONDER is set up with a {@code token} which must
- * be matched by the token provided by the INITIATOR. A null token is permitted
- * on the RESPONDER and matches any peer token. An empty ({@code ""}) token is
- * not the same as a null token and requires the peer token to be empty as well.
*
* @return A string to be used to construct
* {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} to pass to
* {@link android.net.ConnectivityManager#requestNetwork(android.net.NetworkRequest,
* android.net.ConnectivityManager.NetworkCallback)}
* [or other varieties of that API].
+ *
+ * @hide
+ */
+ public String createNetworkSpecifierOpen(@WifiAwareManager.DataPathRole int role,
+ @Nullable byte[] peer) {
+ WifiAwareManager mgr = mMgr.get();
+ if (mgr == null) {
+ Log.e(TAG, "createNetworkSpecifierOpen: called post GC on WifiAwareManager");
+ return "";
+ }
+ if (mTerminated) {
+ Log.e(TAG, "createNetworkSpecifierOpen: called after termination");
+ return "";
+ }
+ return mgr.createNetworkSpecifier(mClientId, role, peer, null);
+ }
+
+ /**
+ * Create a {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} for an
+ * encrypted WiFi Aware connection (link) to the specified peer. The
+ * {@link android.net.NetworkRequest.Builder#addTransportType(int)} should be set to
+ * {@link android.net.NetworkCapabilities#TRANSPORT_WIFI_AWARE}.
+ * <p>
+ * This API is targeted for applications which can obtain the peer MAC address using OOB
+ * (out-of-band) discovery. Aware discovery does not provide the MAC address of the peer -
+ * when using Aware discovery use the alternative network specifier method -
+ * {@link DiscoverySession#createNetworkSpecifierPmk(PeerHandle, byte[])}}.
+ *
+ * @param role The role of this device:
+ * {@link WifiAwareManager#WIFI_AWARE_DATA_PATH_ROLE_INITIATOR} or
+ * {@link WifiAwareManager#WIFI_AWARE_DATA_PATH_ROLE_RESPONDER}
+ * @param peer The MAC address of the peer's Aware discovery interface. On a RESPONDER this
+ * value is used to gate the acceptance of a connection request from only that
+ * peer. A RESPONDER may specify a null - indicating that it will accept
+ * connection requests from any device.
+ * @param pmk A PMK (pairwise master key, see IEEE 802.11i) specifying the key to use for
+ * encrypting the data-path. Use the {@link #createNetworkSpecifierOpen(int, byte[])}
+ * to specify an open (unencrypted) link.
+ *
+ * @return A string to be used to construct
+ * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} to pass to
+ * {@link android.net.ConnectivityManager#requestNetwork(android.net.NetworkRequest,
+ * android.net.ConnectivityManager.NetworkCallback)}
+ * [or other varieties of that API].
+ *
+ * @hide
+ */
+ public String createNetworkSpecifierPmk(@WifiAwareManager.DataPathRole int role,
+ @Nullable byte[] peer, @NonNull byte[] pmk) {
+ WifiAwareManager mgr = mMgr.get();
+ if (mgr == null) {
+ Log.e(TAG, "createNetworkSpecifierPmk: called post GC on WifiAwareManager");
+ return "";
+ }
+ if (mTerminated) {
+ Log.e(TAG, "createNetworkSpecifierPmk: called after termination");
+ return "";
+ }
+ if (pmk == null || pmk.length == 0) {
+ throw new IllegalArgumentException("PMK must not be null or empty");
+ }
+ return mgr.createNetworkSpecifier(mClientId, role, peer, pmk);
+ }
+
+ /**
+ * Place-holder for {@code #createNetworkSpecifierOpen(int, byte[])}. Present to enable
+ * development of replacements CL without causing an API change. Will be removed when new
+ * APIs are exposed.
+ *
+ * @param role The role of this device:
+ * {@link WifiAwareManager#WIFI_AWARE_DATA_PATH_ROLE_INITIATOR} or
+ * {@link WifiAwareManager#WIFI_AWARE_DATA_PATH_ROLE_RESPONDER}
+ * @param peer The MAC address of the peer's Aware discovery interface. On a RESPONDER this
+ * value is used to gate the acceptance of a connection request from only that
+ * peer. A RESPONDER may specify a null - indicating that it will accept
+ * connection requests from any device.
+ * @param token Deprecated and ignored.
+ * @return A string to be used to construct
+ * {@link android.net.NetworkRequest.Builder#setNetworkSpecifier(String)} to pass to
+ * {@link android.net.ConnectivityManager#requestNetwork(android.net.NetworkRequest,
+ * android.net.ConnectivityManager.NetworkCallback)}
+ * [or other varieties of that API].
*/
public String createNetworkSpecifier(@WifiAwareManager.DataPathRole int role,
@Nullable byte[] peer, @Nullable byte[] token) {
- WifiAwareManager mgr = mMgr.get();
- if (mgr == null) {
- Log.e(TAG, "createNetworkSpecifier: called post GC on WifiAwareManager");
- return "";
- }
- if (mTerminated) {
- Log.e(TAG, "createNetworkSpecifier: called after termination");
- return "";
- }
- return mgr.createNetworkSpecifier(mClientId, role, peer, token);
+ return createNetworkSpecifierOpen(role, peer);
}
}
diff --git a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
index 7b73b4b..1f661c4 100644
--- a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
+++ b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
@@ -120,7 +120,7 @@
public void setUpdateIdentifier(int updateIdentifier) {
mUpdateIdentifier = updateIdentifier;
}
- public int getUpdateIdentififer() {
+ public int getUpdateIdentifier() {
return mUpdateIdentifier;
}
diff --git a/wifi/java/android/net/wifi/hotspot2/pps/Credential.java b/wifi/java/android/net/wifi/hotspot2/pps/Credential.java
index 025d4d3..620759d 100644
--- a/wifi/java/android/net/wifi/hotspot2/pps/Credential.java
+++ b/wifi/java/android/net/wifi/hotspot2/pps/Credential.java
@@ -100,7 +100,7 @@
public void setCheckAaaServerCertStatus(boolean checkAaaServerCertStatus) {
mCheckAaaServerCertStatus = checkAaaServerCertStatus;
}
- public boolean getCheckAaaServerStatus() {
+ public boolean getCheckAaaServerCertStatus() {
return mCheckAaaServerCertStatus;
}
diff --git a/wifi/java/android/net/wifi/hotspot2/pps/HomeSp.java b/wifi/java/android/net/wifi/hotspot2/pps/HomeSp.java
index 7a46129..8ec40c0 100644
--- a/wifi/java/android/net/wifi/hotspot2/pps/HomeSp.java
+++ b/wifi/java/android/net/wifi/hotspot2/pps/HomeSp.java
@@ -131,7 +131,7 @@
public void setMatchAnyOis(long[] matchAnyOis) {
mMatchAnyOis = matchAnyOis;
}
- public long[] getMatchAnysOis() {
+ public long[] getMatchAnyOis() {
return mMatchAnyOis;
}
diff --git a/wifi/java/android/net/wifi/hotspot2/pps/Policy.java b/wifi/java/android/net/wifi/hotspot2/pps/Policy.java
index caca0e4..63238e8 100644
--- a/wifi/java/android/net/wifi/hotspot2/pps/Policy.java
+++ b/wifi/java/android/net/wifi/hotspot2/pps/Policy.java
@@ -77,7 +77,7 @@
public void setMinHomeDownlinkBandwidth(long minHomeDownlinkBandwidth) {
mMinHomeDownlinkBandwidth = minHomeDownlinkBandwidth;
}
- public long getMinHomeDownlinkBandWidht() {
+ public long getMinHomeDownlinkBandwidth() {
return mMinHomeDownlinkBandwidth;
}
private long mMinHomeUplinkBandwidth = Long.MIN_VALUE;
diff --git a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
index 5f949747..632cfaf 100644
--- a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java
@@ -20,6 +20,7 @@
import static org.junit.Assert.assertEquals;
import android.os.Parcel;
+import android.net.wifi.WifiConfiguration.NetworkSelectionStatus;
import org.junit.Before;
import org.junit.Test;
@@ -66,4 +67,35 @@
assertArrayEquals(bytes, rebytes);
}
+
+ @Test
+ public void testNetworkSelectionStatusCopy() {
+ NetworkSelectionStatus networkSelectionStatus = new NetworkSelectionStatus();
+ networkSelectionStatus.setNotRecommended(true);
+
+ NetworkSelectionStatus copy = new NetworkSelectionStatus();
+ copy.copy(networkSelectionStatus);
+
+ assertEquals(networkSelectionStatus.isNotRecommended(), copy.isNotRecommended());
+ }
+
+ @Test
+ public void testNetworkSelectionStatusParcel() {
+ NetworkSelectionStatus networkSelectionStatus = new NetworkSelectionStatus();
+ networkSelectionStatus.setNotRecommended(true);
+
+ Parcel parcelW = Parcel.obtain();
+ networkSelectionStatus.writeToParcel(parcelW);
+ byte[] bytes = parcelW.marshall();
+ parcelW.recycle();
+
+ Parcel parcelR = Parcel.obtain();
+ parcelR.unmarshall(bytes, 0, bytes.length);
+ parcelR.setDataPosition(0);
+
+ NetworkSelectionStatus copy = new NetworkSelectionStatus();
+ copy.readFromParcel(parcelR);
+
+ assertEquals(networkSelectionStatus.isNotRecommended(), copy.isNotRecommended());
+ }
}
diff --git a/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java b/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java
index fa546a5..c4d2d32 100644
--- a/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiEnterpriseConfigTest.java
@@ -283,6 +283,21 @@
assertEquals("\"auth=GTC\"", getSupplicantPhase2Method());
}
+ /** Verfies PEAP/SIM, PEAP/AKA, PEAP/AKA'. */
+ @Test
+ public void peapSimAkaAkaPrime() {
+ mEnterpriseConfig.setEapMethod(Eap.PEAP);
+ mEnterpriseConfig.setPhase2Method(Phase2.SIM);
+ assertEquals("PEAP", getSupplicantEapMethod());
+ assertEquals("\"auth=SIM\"", getSupplicantPhase2Method());
+
+ mEnterpriseConfig.setPhase2Method(Phase2.AKA);
+ assertEquals("\"auth=AKA\"", getSupplicantPhase2Method());
+
+ mEnterpriseConfig.setPhase2Method(Phase2.AKA_PRIME);
+ assertEquals("\"auth=AKA'\"", getSupplicantPhase2Method());
+ }
+
/** Verfies that the copy constructor preseves the inner method information. */
@Test
public void copyConstructor() {
diff --git a/wifi/tests/src/android/net/wifi/WifiSsidTest.java b/wifi/tests/src/android/net/wifi/WifiSsidTest.java
new file mode 100644
index 0000000..c7bdb7b
--- /dev/null
+++ b/wifi/tests/src/android/net/wifi/WifiSsidTest.java
@@ -0,0 +1,40 @@
+/*
+ * 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.wifi;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+/**
+ * Unit tests for {@link android.net.wifi.WifiSsid}.
+ */
+public class WifiSsidTest {
+
+ private static final byte[] TEST_SSID =
+ new byte[] {'G', 'o', 'o', 'g', 'l', 'e', 'G', 'u', 'e', 's', 't'};
+ /**
+ * Check that createFromByteArray() works.
+ */
+ @Test
+ public void testCreateFromByteArray() {
+ WifiSsid wifiSsid = WifiSsid.createFromByteArray(TEST_SSID);
+ assertTrue(wifiSsid != null);
+ assertEquals(new String(TEST_SSID), wifiSsid.toString());
+ }
+}
diff --git a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
index a396d87..992958b 100644
--- a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
@@ -100,26 +100,6 @@
*/
/**
- * Validate pass-through of enableUsage() API.
- */
- @Test
- public void testEnableUsage() throws Exception {
- mDut.enableUsage();
-
- verify(mockAwareService).enableUsage();
- }
-
- /**
- * Validate pass-through of disableUsage() API.
- */
- @Test
- public void testDisableUsage() throws Exception {
- mDut.disableUsage();
-
- verify(mockAwareService).disableUsage();
- }
-
- /**
* Validate pass-through of isUsageEnabled() API.
*/
@Test
@@ -566,6 +546,12 @@
collector.checkThat("mMasterPreference", 0,
equalTo(configRequest.mMasterPreference));
collector.checkThat("mSupport5gBand", false, equalTo(configRequest.mSupport5gBand));
+ collector.checkThat("mDiscoveryWindowInterval.length", 2,
+ equalTo(configRequest.mDiscoveryWindowInterval.length));
+ collector.checkThat("mDiscoveryWindowInterval[2.4GHz]", ConfigRequest.DW_INTERVAL_NOT_INIT,
+ equalTo(configRequest.mDiscoveryWindowInterval[ConfigRequest.NAN_BAND_24GHZ]));
+ collector.checkThat("mDiscoveryWindowInterval[5Hz]", ConfigRequest.DW_INTERVAL_NOT_INIT,
+ equalTo(configRequest.mDiscoveryWindowInterval[ConfigRequest.NAN_BAND_5GHZ]));
}
@Test
@@ -574,10 +560,12 @@
final int clusterLow = 5;
final int masterPreference = 55;
final boolean supportBand5g = true;
+ final int dwWindow5GHz = 3;
ConfigRequest configRequest = new ConfigRequest.Builder().setClusterHigh(clusterHigh)
.setClusterLow(clusterLow).setMasterPreference(masterPreference)
.setSupport5gBand(supportBand5g)
+ .setDiscoveryWindowInterval(ConfigRequest.NAN_BAND_5GHZ, dwWindow5GHz)
.build();
collector.checkThat("mClusterHigh", clusterHigh, equalTo(configRequest.mClusterHigh));
@@ -585,6 +573,12 @@
collector.checkThat("mMasterPreference", masterPreference,
equalTo(configRequest.mMasterPreference));
collector.checkThat("mSupport5gBand", supportBand5g, equalTo(configRequest.mSupport5gBand));
+ collector.checkThat("mDiscoveryWindowInterval.length", 2,
+ equalTo(configRequest.mDiscoveryWindowInterval.length));
+ collector.checkThat("mDiscoveryWindowInterval[2.4GHz]", ConfigRequest.DW_INTERVAL_NOT_INIT,
+ equalTo(configRequest.mDiscoveryWindowInterval[ConfigRequest.NAN_BAND_24GHZ]));
+ collector.checkThat("mDiscoveryWindowInterval[5GHz]", dwWindow5GHz,
+ equalTo(configRequest.mDiscoveryWindowInterval[ConfigRequest.NAN_BAND_5GHZ]));
}
@Test(expected = IllegalArgumentException.class)
@@ -633,16 +627,44 @@
new ConfigRequest.Builder().setClusterLow(100).setClusterHigh(5).build();
}
+ @Test(expected = IllegalArgumentException.class)
+ public void testConfigRequestBuilderDwIntervalInvalidBand() {
+ new ConfigRequest.Builder().setDiscoveryWindowInterval(5, 1).build();
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testConfigRequestBuilderDwIntervalInvalidValueZero() {
+ new ConfigRequest.Builder().setDiscoveryWindowInterval(ConfigRequest.NAN_BAND_24GHZ,
+ 0).build();
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testConfigRequestBuilderDwIntervalInvalidValueLarge() {
+ new ConfigRequest.Builder().setDiscoveryWindowInterval(ConfigRequest.NAN_BAND_5GHZ,
+ 6).build();
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testConfigRequestBuilderDwIntervalInvalidValueLargeValidate() {
+ ConfigRequest cr = new ConfigRequest.Builder().build();
+ cr.mDiscoveryWindowInterval[ConfigRequest.NAN_BAND_5GHZ] = 6;
+ cr.validate();
+ }
+
@Test
public void testConfigRequestParcel() {
final int clusterHigh = 189;
final int clusterLow = 25;
final int masterPreference = 177;
final boolean supportBand5g = true;
+ final int dwWindow24GHz = 1;
+ final int dwWindow5GHz = 5;
ConfigRequest configRequest = new ConfigRequest.Builder().setClusterHigh(clusterHigh)
.setClusterLow(clusterLow).setMasterPreference(masterPreference)
.setSupport5gBand(supportBand5g)
+ .setDiscoveryWindowInterval(ConfigRequest.NAN_BAND_24GHZ, dwWindow24GHz)
+ .setDiscoveryWindowInterval(ConfigRequest.NAN_BAND_5GHZ, dwWindow5GHz)
.build();
Parcel parcelW = Parcel.obtain();
@@ -951,11 +973,11 @@
final int sessionId = 123;
final PeerHandle peerHandle = new PeerHandle(123412);
final int role = WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_RESPONDER;
- final String token = "Some arbitrary token string - can really be anything";
+ final byte[] pmk = "Some arbitrary byte array".getBytes();
final ConfigRequest configRequest = new ConfigRequest.Builder().build();
final PublishConfig publishConfig = new PublishConfig.Builder().build();
- String tokenB64 = Base64.encodeToString(token.getBytes(), Base64.DEFAULT);
+ String pmkB64 = Base64.encodeToString(pmk, Base64.DEFAULT);
ArgumentCaptor<WifiAwareSession> sessionCaptor = ArgumentCaptor.forClass(
WifiAwareSession.class);
@@ -986,9 +1008,8 @@
mMockLooper.dispatchAll();
inOrder.verify(mockSessionCallback).onPublishStarted(publishSession.capture());
- // (3) request a network specifier from the session
- String networkSpecifier = publishSession.getValue().createNetworkSpecifier(peerHandle,
- token.getBytes());
+ // (3) request an open (unencrypted) network specifier from the session
+ String networkSpecifier = publishSession.getValue().createNetworkSpecifierOpen(peerHandle);
// validate format
JSONObject jsonObject = new JSONObject(networkSpecifier);
@@ -1000,8 +1021,22 @@
equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_SESSION_ID)));
collector.checkThat("peer_id", peerHandle.peerId,
equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_PEER_ID)));
- collector.checkThat("token", tokenB64,
- equalTo(jsonObject.getString(WifiAwareManager.NETWORK_SPECIFIER_KEY_TOKEN)));
+
+ // (4) request an encrypted (PMK) network specifier from the session
+ networkSpecifier = publishSession.getValue().createNetworkSpecifierPmk(peerHandle, pmk);
+
+ // validate format
+ jsonObject = new JSONObject(networkSpecifier);
+ collector.checkThat("role", role,
+ equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_ROLE)));
+ collector.checkThat("client_id", clientId,
+ equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_CLIENT_ID)));
+ collector.checkThat("session_id", sessionId,
+ equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_SESSION_ID)));
+ collector.checkThat("peer_id", peerHandle.peerId,
+ equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_PEER_ID)));
+ collector.checkThat("pmk", pmkB64 ,
+ equalTo(jsonObject.getString(WifiAwareManager.NETWORK_SPECIFIER_KEY_PMK)));
verifyNoMoreInteractions(mockCallback, mockSessionCallback, mockAwareService,
mockPublishSession, mockRttListener);
@@ -1017,9 +1052,9 @@
final ConfigRequest configRequest = new ConfigRequest.Builder().build();
final byte[] someMac = HexEncoding.decode("000102030405".toCharArray(), false);
final int role = WifiAwareManager.WIFI_AWARE_DATA_PATH_ROLE_INITIATOR;
- final String token = "Some arbitrary token string - can really be anything";
+ final byte[] pmk = "Some arbitrary pmk data".getBytes();
- String tokenB64 = Base64.encodeToString(token.getBytes(), Base64.DEFAULT);
+ String pmkB64 = Base64.encodeToString(pmk, Base64.DEFAULT);
ArgumentCaptor<WifiAwareSession> sessionCaptor = ArgumentCaptor.forClass(
WifiAwareSession.class);
@@ -1038,10 +1073,10 @@
inOrder.verify(mockCallback).onAttached(sessionCaptor.capture());
WifiAwareSession session = sessionCaptor.getValue();
- /* (2) request a direct network specifier*/
- String networkSpecifier = session.createNetworkSpecifier(role, someMac, token.getBytes());
+ // (2) request an open (unencrypted) direct network specifier
+ String networkSpecifier = session.createNetworkSpecifierOpen(role, someMac);
- /* validate format*/
+ // validate format
JSONObject jsonObject = new JSONObject(networkSpecifier);
collector.checkThat("role", role,
equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_ROLE)));
@@ -1050,8 +1085,21 @@
collector.checkThat("peer_mac", someMac, equalTo(HexEncoding.decode(
jsonObject.getString(WifiAwareManager.NETWORK_SPECIFIER_KEY_PEER_MAC).toCharArray(),
false)));
- collector.checkThat("token", tokenB64,
- equalTo(jsonObject.getString(WifiAwareManager.NETWORK_SPECIFIER_KEY_TOKEN)));
+
+ // (3) request an encrypted (PMK) direct network specifier
+ networkSpecifier = session.createNetworkSpecifierPmk(role, someMac, pmk);
+
+ // validate format
+ jsonObject = new JSONObject(networkSpecifier);
+ collector.checkThat("role", role,
+ equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_ROLE)));
+ collector.checkThat("client_id", clientId,
+ equalTo(jsonObject.getInt(WifiAwareManager.NETWORK_SPECIFIER_KEY_CLIENT_ID)));
+ collector.checkThat("peer_mac", someMac, equalTo(HexEncoding.decode(
+ jsonObject.getString(WifiAwareManager.NETWORK_SPECIFIER_KEY_PEER_MAC).toCharArray(),
+ false)));
+ collector.checkThat("pmk", pmkB64,
+ equalTo(jsonObject.getString(WifiAwareManager.NETWORK_SPECIFIER_KEY_PMK)));
verifyNoMoreInteractions(mockCallback, mockSessionCallback, mockAwareService,
mockPublishSession, mockRttListener);