From 119076ae6e875a7efaf525cf901c1c51bb9708e5 Mon Sep 17 00:00:00 2001 From: Brad Ebinger Date: Wed, 23 Sep 2020 17:00:10 -0700 Subject: [PATCH] Add isSupported implementation for SipTransport Add implementation for SipDelegateManager#isSupported as well as CTS tests. Bug: 154763999 Test: atest CtsTelephonyTestCases Change-Id: I7fbd39a8ff17c4e947fdbcca148857684faa3252 --- api/current.txt | 1 + api/system-current.txt | 15 +++ non-updatable-api/current.txt | 1 + non-updatable-api/system-current.txt | 15 +++ telephony/api/system-current.txt | 15 +++ .../telephony/CarrierConfigManager.java | 15 +++ .../java/android/telephony/ImsManager.java | 21 +++++ .../android/telephony/ims/ImsService.java | 12 ++- .../telephony/ims/SipDelegateManager.java | 93 +++++++++++++++++++ .../telephony/ims/aidl/IImsRcsController.aidl | 3 + .../ims/stub/SipTransportImplBase.java | 5 +- 11 files changed, 191 insertions(+), 5 deletions(-) create mode 100644 telephony/java/android/telephony/ims/SipDelegateManager.java diff --git a/api/current.txt b/api/current.txt index 498d4704928f9..e96d3cac279de 100644 --- a/api/current.txt +++ b/api/current.txt @@ -47083,6 +47083,7 @@ package android.telephony { } public static final class CarrierConfigManager.Ims { + field public static final String KEY_IMS_SINGLE_REGISTRATION_REQUIRED_BOOL = "ims.ims_single_registration_required_bool"; field public static final String KEY_PREFIX = "ims."; field public static final String KEY_WIFI_OFF_DEFERRING_TIME_MILLIS_INT = "ims.wifi_off_deferring_time_millis_int"; } diff --git a/api/system-current.txt b/api/system-current.txt index 1da8c29996f92..aaf5ec02ecb17 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -12473,6 +12473,10 @@ package android.telephony.ims { field @NonNull public static final android.os.Parcelable.Creator CREATOR; } + public class ImsManager { + method @NonNull public android.telephony.ims.SipDelegateManager getSipDelegateManager(int); + } + public class ImsMmTelManager implements android.telephony.ims.RegistrationManager { method @Deprecated @NonNull @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public static android.telephony.ims.ImsMmTelManager createForSubscriptionId(int); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getFeatureState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer) throws android.telephony.ims.ImsException; @@ -12508,10 +12512,13 @@ package android.telephony.ims { method public void disableIms(int); method public void enableIms(int); method public android.telephony.ims.stub.ImsConfigImplBase getConfig(int); + method public long getImsServiceCapabilities(); method public android.telephony.ims.stub.ImsRegistrationImplBase getRegistration(int); + method @Nullable public android.telephony.ims.stub.SipTransportImplBase getSipTransport(int); method public final void onUpdateSupportedImsFeatures(android.telephony.ims.stub.ImsFeatureConfiguration) throws android.os.RemoteException; method public android.telephony.ims.stub.ImsFeatureConfiguration querySupportedImsFeatures(); method public void readyForFeatureCreation(); + field public static final long CAPABILITY_SIP_DELEGATE_CREATION = 2L; // 0x2L } public final class ImsSsData implements android.os.Parcelable { @@ -12757,6 +12764,10 @@ package android.telephony.ims { method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setUceSettingEnabled(boolean) throws android.telephony.ims.ImsException; } + public class SipDelegateManager { + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isSupported() throws android.telephony.ims.ImsException; + } + } package android.telephony.ims.feature { @@ -13006,6 +13017,10 @@ package android.telephony.ims.stub { method public int updateColr(int); } + public class SipTransportImplBase { + ctor public SipTransportImplBase(@NonNull java.util.concurrent.Executor); + } + } package android.telephony.mbms { diff --git a/non-updatable-api/current.txt b/non-updatable-api/current.txt index babd54d723b8f..2298ddb03aae0 100644 --- a/non-updatable-api/current.txt +++ b/non-updatable-api/current.txt @@ -45213,6 +45213,7 @@ package android.telephony { } public static final class CarrierConfigManager.Ims { + field public static final String KEY_IMS_SINGLE_REGISTRATION_REQUIRED_BOOL = "ims.ims_single_registration_required_bool"; field public static final String KEY_PREFIX = "ims."; field public static final String KEY_WIFI_OFF_DEFERRING_TIME_MILLIS_INT = "ims.wifi_off_deferring_time_millis_int"; } diff --git a/non-updatable-api/system-current.txt b/non-updatable-api/system-current.txt index 3b6673509f36c..3ae3c391541f4 100644 --- a/non-updatable-api/system-current.txt +++ b/non-updatable-api/system-current.txt @@ -11328,6 +11328,10 @@ package android.telephony.ims { field @NonNull public static final android.os.Parcelable.Creator CREATOR; } + public class ImsManager { + method @NonNull public android.telephony.ims.SipDelegateManager getSipDelegateManager(int); + } + public class ImsMmTelManager implements android.telephony.ims.RegistrationManager { method @Deprecated @NonNull @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public static android.telephony.ims.ImsMmTelManager createForSubscriptionId(int); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getFeatureState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer) throws android.telephony.ims.ImsException; @@ -11363,10 +11367,13 @@ package android.telephony.ims { method public void disableIms(int); method public void enableIms(int); method public android.telephony.ims.stub.ImsConfigImplBase getConfig(int); + method public long getImsServiceCapabilities(); method public android.telephony.ims.stub.ImsRegistrationImplBase getRegistration(int); + method @Nullable public android.telephony.ims.stub.SipTransportImplBase getSipTransport(int); method public final void onUpdateSupportedImsFeatures(android.telephony.ims.stub.ImsFeatureConfiguration) throws android.os.RemoteException; method public android.telephony.ims.stub.ImsFeatureConfiguration querySupportedImsFeatures(); method public void readyForFeatureCreation(); + field public static final long CAPABILITY_SIP_DELEGATE_CREATION = 2L; // 0x2L } public final class ImsSsData implements android.os.Parcelable { @@ -11612,6 +11619,10 @@ package android.telephony.ims { method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setUceSettingEnabled(boolean) throws android.telephony.ims.ImsException; } + public class SipDelegateManager { + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isSupported() throws android.telephony.ims.ImsException; + } + } package android.telephony.ims.feature { @@ -11861,6 +11872,10 @@ package android.telephony.ims.stub { method public int updateColr(int); } + public class SipTransportImplBase { + ctor public SipTransportImplBase(@NonNull java.util.concurrent.Executor); + } + } package android.telephony.mbms { diff --git a/telephony/api/system-current.txt b/telephony/api/system-current.txt index 228f98e489e48..484b79acb13e8 100644 --- a/telephony/api/system-current.txt +++ b/telephony/api/system-current.txt @@ -1435,6 +1435,10 @@ package android.telephony.ims { field @NonNull public static final android.os.Parcelable.Creator CREATOR; } + public class ImsManager { + method @NonNull public android.telephony.ims.SipDelegateManager getSipDelegateManager(int); + } + public class ImsMmTelManager implements android.telephony.ims.RegistrationManager { method @Deprecated @NonNull @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public static android.telephony.ims.ImsMmTelManager createForSubscriptionId(int); method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public void getFeatureState(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer) throws android.telephony.ims.ImsException; @@ -1470,10 +1474,13 @@ package android.telephony.ims { method public void disableIms(int); method public void enableIms(int); method public android.telephony.ims.stub.ImsConfigImplBase getConfig(int); + method public long getImsServiceCapabilities(); method public android.telephony.ims.stub.ImsRegistrationImplBase getRegistration(int); + method @Nullable public android.telephony.ims.stub.SipTransportImplBase getSipTransport(int); method public final void onUpdateSupportedImsFeatures(android.telephony.ims.stub.ImsFeatureConfiguration) throws android.os.RemoteException; method public android.telephony.ims.stub.ImsFeatureConfiguration querySupportedImsFeatures(); method public void readyForFeatureCreation(); + field public static final long CAPABILITY_SIP_DELEGATE_CREATION = 2L; // 0x2L } public final class ImsSsData implements android.os.Parcelable { @@ -1719,6 +1726,10 @@ package android.telephony.ims { method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setUceSettingEnabled(boolean) throws android.telephony.ims.ImsException; } + public class SipDelegateManager { + method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isSupported() throws android.telephony.ims.ImsException; + } + } package android.telephony.ims.feature { @@ -1968,6 +1979,10 @@ package android.telephony.ims.stub { method public int updateColr(int); } + public class SipTransportImplBase { + ctor public SipTransportImplBase(@NonNull java.util.concurrent.Executor); + } + } package android.telephony.mbms { diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 3d33b95d34d23..157609130c1bb 100644 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -3832,11 +3832,26 @@ public class CarrierConfigManager { public static final String KEY_WIFI_OFF_DEFERRING_TIME_MILLIS_INT = KEY_PREFIX + "wifi_off_deferring_time_millis_int"; + /** + * A boolean flag specifying whether or not this carrier requires one IMS registration for + * all IMS services (MMTEL and RCS). + *

+ * If set to {@code true}, the IMS Service must use one IMS registration for all IMS + * services. If set to {@code false}, IMS services may use separate IMS registrations for + * MMTEL and RCS. + *

+ * The default value for this configuration is {@code false}. + * @see android.telephony.ims.SipDelegateManager + */ + public static final String KEY_IMS_SINGLE_REGISTRATION_REQUIRED_BOOL = + KEY_PREFIX + "ims_single_registration_required_bool"; + private Ims() {} private static PersistableBundle getDefaults() { PersistableBundle defaults = new PersistableBundle(); defaults.putInt(KEY_WIFI_OFF_DEFERRING_TIME_MILLIS_INT, 4000); + defaults.putBoolean(KEY_IMS_SINGLE_REGISTRATION_REQUIRED_BOOL, false); return defaults; } } diff --git a/telephony/java/android/telephony/ImsManager.java b/telephony/java/android/telephony/ImsManager.java index 3984bd769edda..28feab27a794b 100644 --- a/telephony/java/android/telephony/ImsManager.java +++ b/telephony/java/android/telephony/ImsManager.java @@ -19,6 +19,7 @@ package android.telephony.ims; import android.annotation.NonNull; import android.annotation.SdkConstant; import android.annotation.SuppressLint; +import android.annotation.SystemApi; import android.annotation.SystemService; import android.content.Context; import android.telephony.SubscriptionManager; @@ -125,4 +126,24 @@ public class ImsManager { return new ImsMmTelManager(subscriptionId); } + + /** + * Create an instance of SipDelegateManager for the subscription id specified. + *

+ * Used for RCS single registration cases, where an IMS application needs to forward SIP + * traffic through the device's IMS service. + * @param subscriptionId The ID of the subscription that this SipDelegateManager will use. + * @throws IllegalArgumentException if the subscription is invalid. + * @return a SipDelegateManager instance for the specified subscription ID. + * @hide + */ + @SystemApi + @NonNull + public SipDelegateManager getSipDelegateManager(int subscriptionId) { + if (!SubscriptionManager.isValidSubscriptionId(subscriptionId)) { + throw new IllegalArgumentException("Invalid subscription ID: " + subscriptionId); + } + + return new SipDelegateManager(mContext, subscriptionId); + } } diff --git a/telephony/java/android/telephony/ims/ImsService.java b/telephony/java/android/telephony/ims/ImsService.java index c806d5c8ed3a0..9ab5aeb9c34c8 100644 --- a/telephony/java/android/telephony/ims/ImsService.java +++ b/telephony/java/android/telephony/ims/ImsService.java @@ -18,6 +18,7 @@ package android.telephony.ims; import android.annotation.LongDef; import android.annotation.Nullable; +import android.annotation.SuppressLint; import android.annotation.SystemApi; import android.app.Service; import android.content.Intent; @@ -125,7 +126,6 @@ public class ImsService extends Service { * {@link #getImsServiceCapabilities()}, {@link #getSipTransport(int)} must not return null, and * this ImsService MUST report the ability to create both {@link ImsFeature#FEATURE_MMTEL} and * {@link ImsFeature#FEATURE_RCS} features. - * @hide */ public static final long CAPABILITY_SIP_DELEGATE_CREATION = 1 << 1; @@ -423,9 +423,12 @@ public class ImsService extends Service { *

* This should be a static configuration and should not change at runtime. * @return The optional static capabilities of this ImsService implementation. - * @hide */ + // ImsService follows a different convention, since it is a stub class. The on* methods are + // final and call back into the framework with a state update. + @SuppressLint("OnNameExpected") public @ImsServiceCapability long getImsServiceCapabilities() { + // Stub implementation to be implemented by ImsService. return 0L; } @@ -513,9 +516,12 @@ public class ImsService extends Service { * supported for this ImsService. * @param slotId The slot that is associated with the SipTransport implementation. * @return the SipTransport implementation for the specified slot. - * @hide Keep this hidden until there is something to expose in SipTransport. */ + // ImsService follows a different convention, since it is a stub class. The on* methods are + // final and call back into the framework with a state update. + @SuppressLint("OnNameExpected") public @Nullable SipTransportImplBase getSipTransport(int slotId) { + // Stub implementation for ImsServices that do not support SipTransport. return null; } diff --git a/telephony/java/android/telephony/ims/SipDelegateManager.java b/telephony/java/android/telephony/ims/SipDelegateManager.java new file mode 100644 index 0000000000000..82c8a9cd58f4b --- /dev/null +++ b/telephony/java/android/telephony/ims/SipDelegateManager.java @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2020 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.Manifest; +import android.annotation.RequiresPermission; +import android.annotation.SystemApi; +import android.content.Context; +import android.os.IBinder; +import android.os.RemoteException; +import android.os.ServiceSpecificException; +import android.telephony.CarrierConfigManager; +import android.telephony.TelephonyFrameworkInitializer; +import android.telephony.ims.aidl.IImsRcsController; + +import com.android.internal.annotations.VisibleForTesting; + +/** + * Manages the creation and destruction of SipDelegates, which allow an IMS application to forward + * SIP messages for the purposes of providing a single IMS registration to the carrier's IMS network + * from multiple sources. + * @hide + */ +@SystemApi +public class SipDelegateManager { + + private final Context mContext; + private final int mSubId; + + /** + * Only visible for testing. To instantiate an instance of this class, please use + * {@link ImsManager#getSipDelegateManager(int)}. + * @hide + */ + @VisibleForTesting + public SipDelegateManager(Context context, int subId) { + mContext = context; + mSubId = subId; + } + + /** + * Determines if creating SIP delegates are supported for the subscription specified. + *

+ * If SIP delegates are not supported on this device or the carrier associated with this + * subscription, creating a SIP delegate will always fail, as this feature is not supported. + * @return true if this device supports creating a SIP delegate and the carrier associated with + * this subscription supports single registration, false if creating SIP delegates is not + * supported. + * @throws ImsException If the remote ImsService is not available for any reason or the + * subscription associated with this instance is no longer active. See + * {@link ImsException#getCode()} for more information. + * + * @see CarrierConfigManager.Ims#KEY_IMS_SINGLE_REGISTRATION_REQUIRED_BOOL + */ + @RequiresPermission(Manifest.permission.READ_PRIVILEGED_PHONE_STATE) + public boolean isSupported() throws ImsException { + try { + IImsRcsController controller = getIImsRcsController(); + if (controller == null) { + throw new ImsException("Telephony server is down", + ImsException.CODE_ERROR_SERVICE_UNAVAILABLE); + } + return controller.isSipDelegateSupported(mSubId); + } catch (ServiceSpecificException e) { + throw new ImsException(e.getMessage(), e.errorCode); + } catch (RemoteException e) { + throw new ImsException(e.getMessage(), + ImsException.CODE_ERROR_SERVICE_UNAVAILABLE); + } + } + + private IImsRcsController getIImsRcsController() { + IBinder binder = TelephonyFrameworkInitializer + .getTelephonyServiceManager() + .getTelephonyImsServiceRegisterer() + .get(); + return IImsRcsController.Stub.asInterface(binder); + } +} diff --git a/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl b/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl index e01ea9179452b..6d25a09e079f4 100644 --- a/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl +++ b/telephony/java/android/telephony/ims/aidl/IImsRcsController.aidl @@ -53,6 +53,9 @@ interface IImsRcsController { void registerUcePublishStateCallback(int subId, IRcsUcePublishStateCallback c); void unregisterUcePublishStateCallback(int subId, IRcsUcePublishStateCallback c); + // SipDelegateManager + boolean isSipDelegateSupported(int subId); + // Internal commands that should not be made public void registerRcsFeatureCallback(int slotId, in IImsServiceFeatureCallback callback); void unregisterImsFeatureCallback(in IImsServiceFeatureCallback callback); diff --git a/telephony/java/android/telephony/ims/stub/SipTransportImplBase.java b/telephony/java/android/telephony/ims/stub/SipTransportImplBase.java index 17bd4b14925f1..b2b2914b3739a 100644 --- a/telephony/java/android/telephony/ims/stub/SipTransportImplBase.java +++ b/telephony/java/android/telephony/ims/stub/SipTransportImplBase.java @@ -17,6 +17,7 @@ package android.telephony.ims.stub; import android.annotation.NonNull; +import android.annotation.SystemApi; import android.telephony.ims.aidl.ISipTransport; import java.util.concurrent.Executor; @@ -24,9 +25,9 @@ import java.util.concurrent.Executor; /** * Manages the creation and destruction of SipDelegates in order to proxy SIP traffic to other * IMS applications in order to support IMS single registration. - * - * @hide Until there is an implementation, keep this hidden + * @hide */ +@SystemApi public class SipTransportImplBase { private final Executor mBinderExecutor;