From b4211ece2d91f10d8c5b3a0ebf9edc710b171cb9 Mon Sep 17 00:00:00 2001 From: Spandan Das Date: Thu, 16 Sep 2021 19:07:31 +0000 Subject: Enforce min_sdk_version=29 This test is run as part of the MTS suite, setting min_sdk_version ensures backwards compatibility with devices Q and above. Formatting changes are from bpmodify Test: atest [...] Bug: 156476221 Change-Id: I6db4edf0cd3c19f0c1e3649e30489da1967ed412 --- tests/Android.bp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/Android.bp b/tests/Android.bp index 82c303d5..7ae66b56 100644 --- a/tests/Android.bp +++ b/tests/Android.bp @@ -40,6 +40,7 @@ android_test { ], test_suites: [ - "device-tests" - ] + "device-tests", + ], + min_sdk_version: "29", } -- cgit v1.2.3 From d29ea0d65feba938b5823cd65411e248e1d0fef5 Mon Sep 17 00:00:00 2001 From: Brad Ebinger Date: Wed, 16 Feb 2022 13:17:55 -0800 Subject: Add the ability to get subId for RcsFeatureManager Bug: 218893458 Test: ImsCommonTests Change-Id: Iec3b48cce04e6e579775df76a8320cfedc8946c8 --- src/java/com/android/ims/RcsFeatureManager.java | 30 +++---------------------- 1 file changed, 3 insertions(+), 27 deletions(-) diff --git a/src/java/com/android/ims/RcsFeatureManager.java b/src/java/com/android/ims/RcsFeatureManager.java index e034a68d..ce5422b3 100644 --- a/src/java/com/android/ims/RcsFeatureManager.java +++ b/src/java/com/android/ims/RcsFeatureManager.java @@ -44,7 +44,6 @@ import android.telephony.ims.aidl.ISipTransport; import android.telephony.ims.aidl.ISubscribeResponseCallback; import android.telephony.ims.feature.CapabilityChangeRequest; import android.telephony.ims.feature.ImsFeature; -import android.telephony.ims.feature.RcsFeature; import android.telephony.ims.feature.RcsFeature.RcsImsCapabilities; import android.telephony.ims.stub.ImsRegistrationImplBase; import android.util.Log; @@ -604,38 +603,15 @@ public class RcsFeatureManager implements FeatureUpdates { mRcsFeatureConnection.updateFeatureCapabilities(capabilities); } - /** - * Testing interface used to mock SubscriptionManager in testing - * @hide - */ - @VisibleForTesting - public interface SubscriptionManagerProxy { - /** - * Mock-able interface for {@link SubscriptionManager#getSubId(int)} used for testing. - */ - int getSubId(int slotId); - } - public IImsConfig getConfig() { return mRcsFeatureConnection.getConfig(); } - private static SubscriptionManagerProxy sSubscriptionManagerProxy - = slotId -> { - int[] subIds = SubscriptionManager.getSubId(slotId); - if (subIds != null) { - return subIds[0]; - } - return SubscriptionManager.INVALID_SUBSCRIPTION_ID; - }; - /** - * Testing function used to mock SubscriptionManager in testing - * @hide + * @return the subscription ID associated with this ImsService connection. */ - @VisibleForTesting - public static void setSubscriptionManager(SubscriptionManagerProxy proxy) { - sSubscriptionManagerProxy = proxy; + public int getSubId() { + return mRcsFeatureConnection.getSubId(); } private void log(String s) { -- cgit v1.2.3 From 0407bd9e1876d2290526fbd1c2cc762a646f20ad Mon Sep 17 00:00:00 2001 From: Hyunho Date: Fri, 18 Feb 2022 05:22:00 +0000 Subject: Set mPendingPublicCapabilities to the currently registered service description If getDeviceCapabilities() is called when mechanism is PRESENCE, set mPendingPublicCapabilities to the currently registered service description. Test: atest DeviceCapabilityInfoTest Bug: b/220236505 Change-Id: Icaf0b7430879f295e9981821180d311c2e14a535 --- .../android/ims/rcs/uce/presence/publish/DeviceCapabilityInfo.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityInfo.java b/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityInfo.java index 8de8b01f..b7bdd9d6 100644 --- a/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityInfo.java +++ b/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityInfo.java @@ -520,7 +520,12 @@ public class DeviceCapabilityInfo { @CapabilityMechanism int mechanism, Context context) { switch (mechanism) { case RcsContactUceCapability.CAPABILITY_MECHANISM_PRESENCE: - return getPresenceCapabilities(context); + RcsContactUceCapability rcsContactUceCapability = getPresenceCapabilities(context); + if (rcsContactUceCapability != null) { + mPendingPublishCapabilities = + mServiceCapRegTracker.copyRegistrationCapabilities(); + } + return rcsContactUceCapability; case RcsContactUceCapability.CAPABILITY_MECHANISM_OPTIONS: return getOptionsCapabilities(context); default: -- cgit v1.2.3 From 521c0ea7d0d4ca44685854fcfb7fddf378e87c6a Mon Sep 17 00:00:00 2001 From: Hyunho Date: Thu, 3 Mar 2022 06:32:26 +0000 Subject: Add a new api that does not send PUBLISH request with duplicated presence capabilities Add API that get RcsContactUsCapability when there are changed presence capabilities. If there is no changed presence capabilities, do not send PUBLISH request. Test: atest DeviceCapabilityInfoTest, PublishProcessor Bug: b/215749573 Change-Id: Ia08d39bfc70b8d5785750033a048755dd3c15395 --- .../uce/presence/publish/DeviceCapabilityInfo.java | 69 ++++++++++- .../rcs/uce/presence/publish/PublishProcessor.java | 21 +++- .../presence/publish/DeviceCapabilityInfoTest.java | 128 +++++++++++++++++++++ .../uce/presence/publish/PublishProcessorTest.java | 9 +- 4 files changed, 222 insertions(+), 5 deletions(-) create mode 100644 tests/src/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityInfoTest.java diff --git a/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityInfo.java b/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityInfo.java index 7fcb1ff7..31f86fc2 100644 --- a/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityInfo.java +++ b/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityInfo.java @@ -38,10 +38,12 @@ import android.util.Log; import com.android.ims.rcs.uce.util.FeatureTags; import com.android.ims.rcs.uce.util.UceUtils; +import com.android.internal.annotations.VisibleForTesting; import java.io.PrintWriter; import java.util.Arrays; import java.util.Collections; +import java.util.Iterator; import java.util.List; import java.util.Objects; import java.util.Set; @@ -104,6 +106,11 @@ public class DeviceCapabilityInfo { private boolean mMobileData; private boolean mVtSetting; + // The service description associated with the last publication update. + private final Set mLastSuccessfulCapabilities = new ArraySet<>(); + // The service description to temporarily store the presence capability being sent. + private Set mPendingPublishCapabilities; + public DeviceCapabilityInfo(int subId, String[] capToRegistrationMap) { mSubId = subId; mServiceCapRegTracker = PublishServiceDescTracker.fromCarrierConfig(capToRegistrationMap); @@ -126,6 +133,8 @@ public class DeviceCapabilityInfo { mMmTelCapabilities = new MmTelCapabilities(); mMmtelAssociatedUris = Collections.EMPTY_LIST; mRcsAssociatedUris = Collections.EMPTY_LIST; + mLastSuccessfulCapabilities.clear(); + mPendingPublishCapabilities = null; } /** @@ -174,6 +183,8 @@ public class DeviceCapabilityInfo { mMmtelRegistered = false; } mMmtelNetworkRegType = AccessNetworkConstants.TRANSPORT_TYPE_INVALID; + mLastSuccessfulCapabilities.clear(); + mPendingPublishCapabilities = null; } /** @@ -242,6 +253,8 @@ public class DeviceCapabilityInfo { changed = true; } mRcsNetworkRegType = AccessNetworkConstants.TRANSPORT_TYPE_INVALID; + mLastSuccessfulCapabilities.clear(); + mPendingPublishCapabilities = null; return changed; } @@ -430,6 +443,55 @@ public class DeviceCapabilityInfo { return mPresenceCapable; } + // Get the device's capabilities with the PRESENCE mechanism. + public RcsContactUceCapability getChangedPresenceCapability(Context context) { + if (context == null) { + return null; + } + Set capableFromReg = + mServiceCapRegTracker.copyRegistrationCapabilities(); + if (isPresenceCapabilityChanged(capableFromReg)) { + RcsContactUceCapability rcsContactUceCapability = getPresenceCapabilities(context); + if (rcsContactUceCapability != null) { + mPendingPublishCapabilities = mServiceCapRegTracker.copyRegistrationCapabilities(); + } + return rcsContactUceCapability; + } + return null; + } + + public void setPresencePublishResult(boolean isSuccess) { + if (isSuccess) { + mLastSuccessfulCapabilities.clear(); + if (mPendingPublishCapabilities != null) { + mLastSuccessfulCapabilities.addAll(mPendingPublishCapabilities); + } + } + mPendingPublishCapabilities = null; + } + + public void resetPresenceCapability() { + mLastSuccessfulCapabilities.clear(); + mPendingPublishCapabilities = null; + } + + @VisibleForTesting + public void addLastSuccessfulServiceDescription(ServiceDescription capability) { + mLastSuccessfulCapabilities.add(capability); + } + + @VisibleForTesting + public boolean isPresenceCapabilityChanged(Set capableFromReg) { + if (mLastSuccessfulCapabilities.isEmpty()) { + return true; + } + + if (capableFromReg.equals(mLastSuccessfulCapabilities)) { + return false; + } + return true; + } + private boolean isVolteAvailable(int networkRegType, MmTelCapabilities capabilities) { return (networkRegType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) && capabilities.isCapable(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE); @@ -462,7 +524,12 @@ public class DeviceCapabilityInfo { @CapabilityMechanism int mechanism, Context context) { switch (mechanism) { case RcsContactUceCapability.CAPABILITY_MECHANISM_PRESENCE: - return getPresenceCapabilities(context); + RcsContactUceCapability rcsContactUceCapability = getPresenceCapabilities(context); + if (rcsContactUceCapability != null) { + mPendingPublishCapabilities = + mServiceCapRegTracker.copyRegistrationCapabilities(); + } + return rcsContactUceCapability; case RcsContactUceCapability.CAPABILITY_MECHANISM_OPTIONS: return getOptionsCapabilities(context); default: diff --git a/src/java/com/android/ims/rcs/uce/presence/publish/PublishProcessor.java b/src/java/com/android/ims/rcs/uce/presence/publish/PublishProcessor.java index d8531a70..0df3b17e 100644 --- a/src/java/com/android/ims/rcs/uce/presence/publish/PublishProcessor.java +++ b/src/java/com/android/ims/rcs/uce/presence/publish/PublishProcessor.java @@ -112,6 +112,8 @@ public class PublishProcessor { logi("onRcsDisconnected"); mRcsFeatureManager = null; mProcessorState.onRcsDisconnected(); + // reset the publish capabilities. + mDeviceCapabilities.resetPresenceCapability(); } /** @@ -152,10 +154,15 @@ public class PublishProcessor { } // Get the latest device's capabilities. - RcsContactUceCapability deviceCapability = - mDeviceCapabilities.getDeviceCapabilities(CAPABILITY_MECHANISM_PRESENCE, mContext); + RcsContactUceCapability deviceCapability; + if (triggerType == PublishController.PUBLISH_TRIGGER_SERVICE) { + deviceCapability = mDeviceCapabilities.getDeviceCapabilities( + CAPABILITY_MECHANISM_PRESENCE, mContext); + } else { + deviceCapability = mDeviceCapabilities.getChangedPresenceCapability(mContext); + } if (deviceCapability == null) { - logw("doPublishInternal: device capability is null"); + logi("doPublishInternal: device capability hasn't changed or is null"); return false; } @@ -349,6 +356,8 @@ public class PublishProcessor { // Increase the retry count mProcessorState.increaseRetryCount(); + // reset the last capabilities because of the request is failed + mDeviceCapabilities.setPresencePublishResult(false); // Reset the pending flag because it is going to resend a request. clearPendingRequest(); @@ -373,10 +382,14 @@ public class PublishProcessor { Instant responseTime = response.getResponseTimestamp(); // Record the time when the request is successful and reset the retry count. + boolean publishSuccess = false; if (response.isRequestSuccess()) { mProcessorState.setLastPublishedTime(responseTime); mProcessorState.resetRetryCount(); + publishSuccess = true; } + // set the last capabilities according to the result of request. + mDeviceCapabilities.setPresencePublishResult(publishSuccess); // Update the publish state after the request has finished. int publishState = response.getPublishState(); @@ -492,6 +505,8 @@ public class PublishProcessor { */ public void resetState() { mProcessorState.resetState(); + // reset the publish capabilities. + mDeviceCapabilities.resetPresenceCapability(); } /** diff --git a/tests/src/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityInfoTest.java b/tests/src/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityInfoTest.java new file mode 100644 index 00000000..eb2140e6 --- /dev/null +++ b/tests/src/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityInfoTest.java @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2022 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.rcs.uce.presence.publish; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import android.telephony.ims.RcsContactPresenceTuple; +import android.util.ArraySet; + +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.filters.SmallTest; + +import com.android.ims.ImsTestBase; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; + +import java.util.Collections; +import java.util.Set; + +@RunWith(AndroidJUnit4.class) +public class DeviceCapabilityInfoTest extends ImsTestBase { + + int mSubId = 1; + @Mock PublishServiceDescTracker mPublishServiceDescTracker; + + @Before + public void setUp() throws Exception { + super.setUp(); + } + + @After + public void tearDown() throws Exception { + super.tearDown(); + } + + @Test + @SmallTest + public void testGetPresenceCapabilityForSameDescription() throws Exception { + DeviceCapabilityInfo deviceCapInfo = createDeviceCapabilityInfo(); + + Set mTestCapability = new ArraySet<>(); + mTestCapability.add(getChatDescription()); + mTestCapability.add(getMmtelDescription()); + mTestCapability.add(getUndefinedDescription()); + + deviceCapInfo.addLastSuccessfulServiceDescription(getMmtelDescription()); + deviceCapInfo.addLastSuccessfulServiceDescription(getChatDescription()); + deviceCapInfo.addLastSuccessfulServiceDescription(getUndefinedDescription()); + assertFalse(deviceCapInfo.isPresenceCapabilityChanged(mTestCapability)); + } + + @Test + @SmallTest + public void testGetPresenceCapabilityForSameSizeOfDescription() throws Exception { + DeviceCapabilityInfo deviceCapInfo = createDeviceCapabilityInfo(); + + Set mTestCapability = new ArraySet<>(); + mTestCapability.add(getChatDescription()); + mTestCapability.add(getMmtelDescription()); + mTestCapability.add(getUndefinedDescription()); + + deviceCapInfo.addLastSuccessfulServiceDescription(getMmtelDescription()); + deviceCapInfo.addLastSuccessfulServiceDescription(getChatDescription()); + deviceCapInfo.addLastSuccessfulServiceDescription(getUndefined2Description()); + + assertTrue(deviceCapInfo.isPresenceCapabilityChanged(mTestCapability)); + } + private DeviceCapabilityInfo createDeviceCapabilityInfo() { + DeviceCapabilityInfo deviceCapInfo = new DeviceCapabilityInfo(mSubId, null); + return deviceCapInfo; + } + + private ServiceDescription getChatDescription() { + ServiceDescription SERVICE_DESCRIPTION_CHAT_SESSION = + new ServiceDescription( + RcsContactPresenceTuple.SERVICE_ID_CHAT_V2, + "2.0" /*version*/, + null /*description*/ + ); + return SERVICE_DESCRIPTION_CHAT_SESSION; + } + + private ServiceDescription getMmtelDescription() { + ServiceDescription SERVICE_DESCRIPTION_MMTEL_VOICE = new ServiceDescription( + RcsContactPresenceTuple.SERVICE_ID_MMTEL, + "1.0" /*version*/, + "Voice Service" /*description*/ + ); + return SERVICE_DESCRIPTION_MMTEL_VOICE; + } + + private ServiceDescription getUndefinedDescription() { + ServiceDescription SERVICE_DESCRIPTION_TEST = new ServiceDescription( + "test", + "1.0" /*version*/, + "Test_Service" /*description*/ + ); + return SERVICE_DESCRIPTION_TEST; + } + + private ServiceDescription getUndefined2Description() { + ServiceDescription SERVICE_DESCRIPTION_TEST2 = new ServiceDescription( + "test1", + "1.0" /*version*/, + "Test_Service" /*description*/ + ); + return SERVICE_DESCRIPTION_TEST2; + } +} \ No newline at end of file diff --git a/tests/src/com/android/ims/rcs/uce/presence/publish/PublishProcessorTest.java b/tests/src/com/android/ims/rcs/uce/presence/publish/PublishProcessorTest.java index f632ca5b..c466ac48 100644 --- a/tests/src/com/android/ims/rcs/uce/presence/publish/PublishProcessorTest.java +++ b/tests/src/com/android/ims/rcs/uce/presence/publish/PublishProcessorTest.java @@ -66,6 +66,7 @@ public class PublishProcessorTest extends ImsTestBase { doReturn(true).when(mDeviceCapabilities).isImsRegistered(); RcsContactUceCapability capability = getRcsContactUceCapability(); + doReturn(capability).when(mDeviceCapabilities).getChangedPresenceCapability(any()); doReturn(capability).when(mDeviceCapabilities).getDeviceCapabilities(anyInt(), any()); doReturn(mTaskId).when(mResponseCallback).getTaskId(); @@ -96,7 +97,7 @@ public class PublishProcessorTest extends ImsTestBase { PublishProcessor publishProcessor = getPublishProcessor(); publishProcessor.doPublish(PublishController.PUBLISH_TRIGGER_RETRY); - + verify(mDeviceCapabilities).getChangedPresenceCapability(any()); verify(mProcessorState, never()).resetRetryCount(); } @@ -155,6 +156,7 @@ public class PublishProcessorTest extends ImsTestBase { publishProcessor.onCommandError(mResponseCallback); + verify(mDeviceCapabilities).setPresencePublishResult(false); verify(mProcessorState).increaseRetryCount(); verify(mPublishCtrlCallback).requestPublishFromInternal( eq(PublishController.PUBLISH_TRIGGER_RETRY)); @@ -172,10 +174,12 @@ public class PublishProcessorTest extends ImsTestBase { doReturn(mTaskId).when(mProcessorState).getCurrentTaskId(); doReturn(mTaskId).when(mResponseCallback).getTaskId(); doReturn(false).when(mResponseCallback).needRetry(); + doReturn(true).when(mResponseCallback).isRequestSuccess(); PublishProcessor publishProcessor = getPublishProcessor(); publishProcessor.onCommandError(mResponseCallback); + verify(mDeviceCapabilities).setPresencePublishResult(true); verify(mPublishCtrlCallback).updatePublishRequestResult(anyInt(), any(), any()); verify(mResponseCallback).onDestroy(); verify(mProcessorState).setPublishingFlag(false); @@ -193,6 +197,7 @@ public class PublishProcessorTest extends ImsTestBase { publishProcessor.onNetworkResponse(mResponseCallback); + verify(mDeviceCapabilities).setPresencePublishResult(false); verify(mProcessorState).increaseRetryCount(); verify(mPublishCtrlCallback).requestPublishFromInternal( eq(PublishController.PUBLISH_TRIGGER_RETRY)); @@ -214,6 +219,7 @@ public class PublishProcessorTest extends ImsTestBase { publishProcessor.onNetworkResponse(mResponseCallback); + verify(mDeviceCapabilities).setPresencePublishResult(true); verify(mPublishCtrlCallback).updatePublishRequestResult(anyInt(), any(), any()); verify(mResponseCallback).onDestroy(); verify(mProcessorState).setPublishingFlag(false); @@ -248,6 +254,7 @@ public class PublishProcessorTest extends ImsTestBase { publishProcessor.publishUpdated(mResponseCallback); + verify(mDeviceCapabilities).setPresencePublishResult(true); verify(mProcessorState).setLastPublishedTime(any()); verify(mProcessorState).resetRetryCount(); verify(mPublishCtrlCallback).updatePublishRequestResult(anyInt(), any(), any()); -- cgit v1.2.3 From 1a8b55d771fc630be410757f2b3ae5665b545202 Mon Sep 17 00:00:00 2001 From: Hyunho Date: Mon, 28 Mar 2022 04:32:11 +0000 Subject: Add the processing code that the device received the 504 response to the PUBLISH request As per AT&T requirements, if a device receives a 504 response to a PUBLISH request, it is treated like a received 403 response. However, the current AOSP framework is missing for this. Bug: b/225094509 Test: atest CtsTelephonyTestCases:ImsServiceTest Change-Id: I43665589e735023de9c8d3d3138e23d094910c19 --- src/java/com/android/ims/rcs/uce/UceDeviceState.java | 1 + .../com/android/ims/rcs/uce/presence/publish/PublishRequestResponse.java | 1 + src/java/com/android/ims/rcs/uce/util/NetworkSipCode.java | 1 + 3 files changed, 3 insertions(+) diff --git a/src/java/com/android/ims/rcs/uce/UceDeviceState.java b/src/java/com/android/ims/rcs/uce/UceDeviceState.java index 857e25c8..8d4de9f2 100644 --- a/src/java/com/android/ims/rcs/uce/UceDeviceState.java +++ b/src/java/com/android/ims/rcs/uce/UceDeviceState.java @@ -255,6 +255,7 @@ public class UceDeviceState { // Update the device state based on the given sip code. switch (sipCode) { case NetworkSipCode.SIP_CODE_FORBIDDEN: // sip 403 + case NetworkSipCode.SIP_CODE_SERVER_TIMEOUT: // sip 504 if (requestType == UceController.REQUEST_TYPE_PUBLISH) { // Provisioning error for publish request. setDeviceState(DEVICE_STATE_PROVISION_ERROR); diff --git a/src/java/com/android/ims/rcs/uce/presence/publish/PublishRequestResponse.java b/src/java/com/android/ims/rcs/uce/presence/publish/PublishRequestResponse.java index b651cfb5..47aa37c3 100644 --- a/src/java/com/android/ims/rcs/uce/presence/publish/PublishRequestResponse.java +++ b/src/java/com/android/ims/rcs/uce/presence/publish/PublishRequestResponse.java @@ -352,6 +352,7 @@ public class PublishRequestResponse { return RcsUceAdapter.PUBLISH_STATE_OK; case NetworkSipCode.SIP_CODE_FORBIDDEN: case NetworkSipCode.SIP_CODE_NOT_FOUND: + case NetworkSipCode.SIP_CODE_SERVER_TIMEOUT: return RcsUceAdapter.PUBLISH_STATE_RCS_PROVISION_ERROR; case NetworkSipCode.SIP_CODE_REQUEST_TIMEOUT: return RcsUceAdapter.PUBLISH_STATE_REQUEST_TIMEOUT; diff --git a/src/java/com/android/ims/rcs/uce/util/NetworkSipCode.java b/src/java/com/android/ims/rcs/uce/util/NetworkSipCode.java index e5505803..30099f3b 100644 --- a/src/java/com/android/ims/rcs/uce/util/NetworkSipCode.java +++ b/src/java/com/android/ims/rcs/uce/util/NetworkSipCode.java @@ -64,6 +64,7 @@ public class NetworkSipCode { int uceError; switch (sipCode) { case NetworkSipCode.SIP_CODE_FORBIDDEN: // 403 + case NetworkSipCode.SIP_CODE_SERVER_TIMEOUT: // 504 if(requestType == UceController.REQUEST_TYPE_PUBLISH) { // Not provisioned for PUBLISH request. uceError = RcsUceAdapter.ERROR_NOT_AUTHORIZED; -- cgit v1.2.3 From f2ff2fc485876cae2cc8000800e120f0c9d2ab6d Mon Sep 17 00:00:00 2001 From: Hyunho Date: Tue, 29 Mar 2022 03:36:33 +0000 Subject: Do not delete the DB if the received document is malformed/corrupt According to RCC.59 v5, if a device receives malformed/corrupted xml it should keep the old functionality. However, if the presence element is malformed, that contact is set to the non-rcs user. And if one of the tuple in xml is malformed, another valid tuple should be parsed and stored in DB. Don't save anything if all tuples in xml are malformed. Bug: b/225998718 Test: atest PresenceTest TupleTest Test: cts CtsTelephonyTestCases:RcsUceAdapterTest Change-Id: I4839a45f933092a9bd42d74564797bacfeac49c1 --- .../rcs/uce/presence/pidfparser/PidfParser.java | 44 +++++--- .../uce/presence/pidfparser/PidfParserUtils.java | 10 ++ .../pidfparser/RcsContactUceCapabilityWrapper.java | 119 +++++++++++++++++++++ .../rcs/uce/presence/pidfparser/pidf/Presence.java | 24 ++++- .../rcs/uce/presence/pidfparser/pidf/Tuple.java | 11 ++ .../ims/rcs/uce/request/SubscribeRequest.java | 44 ++++++-- .../uce/presence/pidfparser/PidfParserTest.java | 20 +++- .../RcsContactUceCapabilityWrapperTest.java | 74 +++++++++++++ .../uce/presence/pidfparser/pidf/PresenceTest.java | 90 +++++++++++++++- .../uce/presence/pidfparser/pidf/TupleTest.java | 5 +- 10 files changed, 412 insertions(+), 29 deletions(-) create mode 100644 src/java/com/android/ims/rcs/uce/presence/pidfparser/RcsContactUceCapabilityWrapper.java create mode 100644 tests/src/com/android/ims/rcs/uce/presence/pidfparser/RcsContactUceCapabilityWrapperTest.java diff --git a/src/java/com/android/ims/rcs/uce/presence/pidfparser/PidfParser.java b/src/java/com/android/ims/rcs/uce/presence/pidfparser/PidfParser.java index 1b0bdaed..10b43a56 100644 --- a/src/java/com/android/ims/rcs/uce/presence/pidfparser/PidfParser.java +++ b/src/java/com/android/ims/rcs/uce/presence/pidfparser/PidfParser.java @@ -21,10 +21,10 @@ import android.net.Uri; import android.telephony.ims.RcsContactPresenceTuple; import android.telephony.ims.RcsContactPresenceTuple.ServiceCapabilities; import android.telephony.ims.RcsContactUceCapability; -import android.telephony.ims.RcsContactUceCapability.PresenceBuilder; import android.text.TextUtils; import android.util.Log; + import com.android.ims.rcs.uce.presence.pidfparser.capabilities.Audio; import com.android.ims.rcs.uce.presence.pidfparser.capabilities.CapsConstant; import com.android.ims.rcs.uce.presence.pidfparser.capabilities.Duplex; @@ -35,6 +35,7 @@ import com.android.ims.rcs.uce.presence.pidfparser.pidf.Basic; import com.android.ims.rcs.uce.presence.pidfparser.pidf.PidfConstant; import com.android.ims.rcs.uce.presence.pidfparser.pidf.Presence; import com.android.ims.rcs.uce.presence.pidfparser.pidf.Tuple; +import com.android.ims.rcs.uce.presence.pidfparser.RcsContactUceCapabilityWrapper; import com.android.ims.rcs.uce.util.UceUtils; import com.android.internal.annotations.VisibleForTesting; @@ -120,11 +121,12 @@ public class PidfParser { } /** - * Get the RcsContactUceCapability from the given PIDF xml format. + * Get the RcsContactUceCapabilityWrapper from the given PIDF xml format. */ - public static @Nullable RcsContactUceCapability getRcsContactUceCapability(String pidf) { + public static @Nullable RcsContactUceCapabilityWrapper getRcsContactUceCapabilityWrapper( + String pidf) { if (TextUtils.isEmpty(pidf)) { - Log.w(LOG_TAG, "getRcsContactUceCapability: The given pidf is empty"); + Log.w(LOG_TAG, "getRcsContactUceCapabilityWrapper: The given pidf is empty"); return null; } @@ -132,7 +134,7 @@ public class PidfParser { Matcher matcher = PIDF_PATTERN.matcher(pidf); String formattedPidf = matcher.replaceAll(""); if (TextUtils.isEmpty(formattedPidf)) { - Log.w(LOG_TAG, "getRcsContactUceCapability: The formatted pidf is empty"); + Log.w(LOG_TAG, "getRcsContactUceCapabilityWrapper: The formatted pidf is empty"); return null; } @@ -147,7 +149,7 @@ public class PidfParser { // Start parsing Presence presence = parsePidf(parser); - // Convert from the Presence to the RcsContactUceCapability + // Convert from the Presence to the RcsContactUceCapabilityWrapper return convertToRcsContactUceCapability(presence); } catch (XmlPullParserException | IOException e) { @@ -168,10 +170,12 @@ public class PidfParser { XmlPullParserException { Presence presence = null; int nextType = parser.next(); + boolean findPresenceTag = false; do { // Find the Presence start tag if (nextType == XmlPullParser.START_TAG && Presence.ELEMENT_NAME.equals(parser.getName())) { + findPresenceTag = true; presence = new Presence(); presence.parse(parser); break; @@ -179,13 +183,18 @@ public class PidfParser { nextType = parser.next(); } while(nextType != XmlPullParser.END_DOCUMENT); + if (!findPresenceTag) { + Log.w(LOG_TAG, "parsePidf: The presence start tag not found."); + } + return presence; } /* - * Convert the given Presence to the RcsContactUceCapability + * Convert the given Presence to the RcsContactUceCapabilityWrapper */ - private static RcsContactUceCapability convertToRcsContactUceCapability(Presence presence) { + private static RcsContactUceCapabilityWrapper convertToRcsContactUceCapability( + Presence presence) { if (presence == null) { Log.w(LOG_TAG, "convertToRcsContactUceCapability: The presence is null"); return null; @@ -195,19 +204,24 @@ public class PidfParser { return null; } - PresenceBuilder presenceBuilder = new PresenceBuilder(Uri.parse(presence.getEntity()), - RcsContactUceCapability.SOURCE_TYPE_NETWORK, + RcsContactUceCapabilityWrapper uceCapabilityWrapper = new RcsContactUceCapabilityWrapper( + Uri.parse(presence.getEntity()), RcsContactUceCapability.SOURCE_TYPE_NETWORK, RcsContactUceCapability.REQUEST_RESULT_FOUND); // Add all the capability tuples of this contact presence.getTupleList().forEach(tuple -> { - RcsContactPresenceTuple capabilityTuple = getRcsContactPresenceTuple(tuple); - if (capabilityTuple != null) { - presenceBuilder.addCapabilityTuple(capabilityTuple); + // The tuple that fails parsing is invalid data, so discard it. + if (!tuple.getMalformed()) { + RcsContactPresenceTuple capabilityTuple = getRcsContactPresenceTuple(tuple); + if (capabilityTuple != null) { + uceCapabilityWrapper.addCapabilityTuple(capabilityTuple); + } + } else { + uceCapabilityWrapper.setMalformedContents(); } }); - presenceBuilder.setEntityUri(Uri.parse(presence.getEntity())); - return presenceBuilder.build(); + uceCapabilityWrapper.setEntityUri(Uri.parse(presence.getEntity())); + return uceCapabilityWrapper; } /* diff --git a/src/java/com/android/ims/rcs/uce/presence/pidfparser/PidfParserUtils.java b/src/java/com/android/ims/rcs/uce/presence/pidfparser/PidfParserUtils.java index f2b21bd0..d43819ec 100644 --- a/src/java/com/android/ims/rcs/uce/presence/pidfparser/PidfParserUtils.java +++ b/src/java/com/android/ims/rcs/uce/presence/pidfparser/PidfParserUtils.java @@ -283,6 +283,16 @@ public class PidfParserUtils { return null; } + /** + * Get the malformed status from the given tuple. + */ + public static boolean getTupleMalformedStatus(Tuple tuple) { + if (tuple == null) { + return false; + } + return tuple.getMalformed(); + } + /** * Get the terminated capability which disable all the capabilities. */ diff --git a/src/java/com/android/ims/rcs/uce/presence/pidfparser/RcsContactUceCapabilityWrapper.java b/src/java/com/android/ims/rcs/uce/presence/pidfparser/RcsContactUceCapabilityWrapper.java new file mode 100644 index 00000000..3b2f163f --- /dev/null +++ b/src/java/com/android/ims/rcs/uce/presence/pidfparser/RcsContactUceCapabilityWrapper.java @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2022 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.rcs.uce.presence.pidfparser; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.net.Uri; + +import android.telephony.ims.RcsContactPresenceTuple; +import android.telephony.ims.RcsContactUceCapability; +import android.telephony.ims.RcsContactUceCapability.PresenceBuilder; + +import java.util.ArrayList; +import java.util.List; + +/** + * A wrapper class that uses the parsed information to construct {@link RcsContactUceCapability} + * instances. + */ + +public class RcsContactUceCapabilityWrapper { + private final Uri mContactUri; + private final int mSourceType; + private final int mRequestResult; + private boolean mIsMalformed; + private final List mPresenceTuples = new ArrayList<>(); + private Uri mEntityUri; + + /** + * Create the wrapper, which can be used to set UCE capabilities as well as custom + * capability extensions. + * @param contact The contact URI that the capabilities are attached to. + * @param sourceType The type where the capabilities of this contact were retrieved from. + * @param requestResult the request result + */ + public RcsContactUceCapabilityWrapper(@NonNull Uri contact, int sourceType, int requestResult) { + mContactUri = contact; + mSourceType = sourceType; + mRequestResult = requestResult; + mIsMalformed = false; + } + + /** + * Add the {@link RcsContactPresenceTuple} into the presence tuple list. + * @param tuple The {@link RcsContactPresenceTuple} to be added into. + */ + public void addCapabilityTuple(@NonNull RcsContactPresenceTuple tuple) { + mPresenceTuples.add(tuple); + } + + /** + * This flag is set if at least one tuple could not be parsed due to malformed contents. + */ + public void setMalformedContents() { + mIsMalformed = true; + } + + /** + * Set the entity URI related to the contact whose capabilities were requested. + * @param entityUri the 'pres' URL of the PRESENTITY publishing presence document. + */ + public void setEntityUri(@NonNull Uri entityUri) { + mEntityUri = entityUri; + } + + /** + * Whether the XML is malformed. + * @return {@code true} if all of the presence tuple information associated with + * the entity URI ({@link #getEntityUri}) is malformed and there is no tuple info + * available. If one or more of the tuples are still well-formed after parsing the + * XML, this method will return {@code false}. + */ + public boolean isMalformed() { + if (mIsMalformed == false) { + return false; + } + if (mPresenceTuples.isEmpty()) { + return true; + } + return false; + } + + /** + * Retrieve the entity URI of the contact whose presence information is being requested for. + * @return the URI representing the 'pres' URL of the PRESENTITY publishing presence document + * or {@code null} if the entity uri does not exist in the presence document. + */ + public @Nullable Uri getEntityUri() { + return mEntityUri; + } + + /** + * @return a new RcsContactUceCapability instance from the contents of this wrapper. + */ + public @NonNull RcsContactUceCapability toRcsContactUceCapability() { + + PresenceBuilder presenceBuilder = new PresenceBuilder(mContactUri, + mSourceType, mRequestResult); + + // Add all the capability tuples of this contact + presenceBuilder.addCapabilityTuples(mPresenceTuples); + presenceBuilder.setEntityUri(mEntityUri); + return presenceBuilder.build(); + } +} diff --git a/src/java/com/android/ims/rcs/uce/presence/pidfparser/pidf/Presence.java b/src/java/com/android/ims/rcs/uce/presence/pidfparser/pidf/Presence.java index e9a40a84..b2173145 100644 --- a/src/java/com/android/ims/rcs/uce/presence/pidfparser/pidf/Presence.java +++ b/src/java/com/android/ims/rcs/uce/presence/pidfparser/pidf/Presence.java @@ -18,8 +18,11 @@ package com.android.ims.rcs.uce.presence.pidfparser.pidf; import android.annotation.NonNull; import android.net.Uri; +import android.text.TextUtils; +import android.util.Log; import com.android.ims.rcs.uce.presence.pidfparser.ElementBase; +import com.android.ims.rcs.uce.util.UceUtils; import com.android.internal.annotations.VisibleForTesting; import org.xmlpull.v1.XmlPullParser; @@ -41,6 +44,7 @@ public class Presence extends ElementBase { * 2: Any number (including 0) of elements * 3: Any number of OPTIONAL extension elements from other namespaces. */ + private static final String LOG_TAG = UceUtils.getLogPrefix() + "Presence"; /** The name of this element */ public static final String ELEMENT_NAME = "presence"; @@ -133,6 +137,9 @@ public class Presence extends ElementBase { } mEntity = parser.getAttributeValue(XmlPullParser.NO_NAMESPACE, ATTRIBUTE_NAME_ENTITY); + if (TextUtils.isEmpty(mEntity)) { + throw new XmlPullParserException("Entity uri of presence is empty"); + } // Move to the next event. int eventType = parser.next(); @@ -146,11 +153,24 @@ public class Presence extends ElementBase { if (isTupleElement(eventType, tagName)) { Tuple tuple = new Tuple(); - tuple.parse(parser); + try { + // If one tuple encounters an xml exception, we must parse the other tuple + // and store valid information. + tuple.parse(parser); + } catch (XmlPullParserException e) { + e.printStackTrace(); + Log.w(LOG_TAG, "parse: Exception occurred during Tuple parsing."); + tuple.setMalformed(true); + } mTupleList.add(tuple); } else if (isNoteElement(eventType, tagName)) { Note note = new Note(); - note.parse(parser); + try { + note.parse(parser); + } catch (XmlPullParserException e) { + e.printStackTrace(); + Log.w(LOG_TAG, "parse: Exception occurred during Note parsing."); + } mNoteList.add(note); } } diff --git a/src/java/com/android/ims/rcs/uce/presence/pidfparser/pidf/Tuple.java b/src/java/com/android/ims/rcs/uce/presence/pidfparser/pidf/Tuple.java index 014dbed0..e2744660 100644 --- a/src/java/com/android/ims/rcs/uce/presence/pidfparser/pidf/Tuple.java +++ b/src/java/com/android/ims/rcs/uce/presence/pidfparser/pidf/Tuple.java @@ -59,8 +59,11 @@ public class Tuple extends ElementBase { private List mNoteList = new ArrayList<>(); private Timestamp mTimestamp; + private boolean mMalformed; + public Tuple() { mId = getTupleId(); + mMalformed = false; } @Override @@ -121,6 +124,14 @@ public class Tuple extends ElementBase { return mTimestamp; } + public void setMalformed(boolean malformed) { + mMalformed = malformed; + } + + public boolean getMalformed() { + return mMalformed; + } + @Override public void serialize(XmlSerializer serializer) throws IOException { String namespace = getNamespace(); diff --git a/src/java/com/android/ims/rcs/uce/request/SubscribeRequest.java b/src/java/com/android/ims/rcs/uce/request/SubscribeRequest.java index 2b5e91a9..bee71771 100644 --- a/src/java/com/android/ims/rcs/uce/request/SubscribeRequest.java +++ b/src/java/com/android/ims/rcs/uce/request/SubscribeRequest.java @@ -25,12 +25,15 @@ import android.telephony.ims.RcsUceAdapter; import android.telephony.ims.aidl.ISubscribeResponseCallback; import android.telephony.ims.stub.RcsCapabilityExchangeImplBase.CommandCode; +import com.android.ims.rcs.uce.eab.EabCapabilityResult; import com.android.ims.rcs.uce.presence.pidfparser.PidfParser; import com.android.ims.rcs.uce.presence.pidfparser.PidfParserUtils; +import com.android.ims.rcs.uce.presence.pidfparser.RcsContactUceCapabilityWrapper; import com.android.ims.rcs.uce.presence.subscribe.SubscribeController; import com.android.ims.rcs.uce.request.UceRequestManager.RequestManagerCallback; import com.android.internal.annotations.VisibleForTesting; +import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Objects; @@ -189,30 +192,59 @@ public class SubscribeRequest extends CapabilityRequest { pidfXml = Collections.EMPTY_LIST; } - // Convert from the pidf xml to the list of RcsContactUceCapability - List capabilityList = pidfXml.stream() - .map(pidf -> PidfParser.getRcsContactUceCapability(pidf)) + // Convert from the pidf xml to the list of RcsContactUceCapabilityWrapper + List capabilityList = pidfXml.stream() + .map(pidf -> PidfParser.getRcsContactUceCapabilityWrapper(pidf)) .filter(Objects::nonNull) .collect(Collectors.toList()); // When the given PIDF xml is empty, set the contacts who have not received the // capabilities updated as non-RCS user. + List notReceivedCapabilityList = new ArrayList<>(); if (capabilityList.isEmpty()) { logd("onCapabilitiesUpdate: The capabilities list is empty, Set to non-RCS user."); List notReceiveCapUpdatedContactList = mRequestResponse.getNotReceiveCapabilityUpdatedContact(); - capabilityList = notReceiveCapUpdatedContactList.stream() + notReceivedCapabilityList = notReceiveCapUpdatedContactList.stream() .map(PidfParserUtils::getNotFoundContactCapabilities) .filter(Objects::nonNull) .collect(Collectors.toList()); } + List updateCapabilityList = new ArrayList<>(); + List malformedListWithEntityURI = new ArrayList<>(); + for (RcsContactUceCapabilityWrapper capability : capabilityList) { + if (!capability.isMalformed()) { + updateCapabilityList.add(capability.toRcsContactUceCapability()); + } else { + logw("onCapabilitiesUpdate: malformed capability was found and not saved."); + malformedListWithEntityURI.add(capability.getEntityUri()); + } + } logd("onCapabilitiesUpdate: PIDF size=" + pidfXml.size() - + ", contact capability size=" + capabilityList.size()); + + ", not received capability size=" + notReceivedCapabilityList.size() + + ", normal capability size=" + updateCapabilityList.size() + + ", malformed but entity uri is valid capability size=" + + malformedListWithEntityURI.size()); + + for (RcsContactUceCapability emptyCapability : notReceivedCapabilityList) { + updateCapabilityList.add(emptyCapability); + } + // All tuples in received xml are malformed but entity uri is valid. + // The capability should be get from the DB and report it to callback. + List cachedCapabilityList = + mRequestManagerCallback.getCapabilitiesFromCache(malformedListWithEntityURI); + for (EabCapabilityResult cacheEabCapability : cachedCapabilityList) { + RcsContactUceCapability cachedCapability = cacheEabCapability.getContactCapabilities(); + if (cachedCapability != null) { + updateCapabilityList.add(cachedCapability); + } + } // Add these updated RcsContactUceCapability into the RequestResponse and notify // the RequestManager to process the RcsContactUceCapabilities updated. - mRequestResponse.addUpdatedCapabilities(capabilityList); + logd("onCapabilitiesUpdate: updatedCapability size=" + updateCapabilityList.size()); + mRequestResponse.addUpdatedCapabilities(updateCapabilityList); mRequestManagerCallback.notifyCapabilitiesUpdated(mCoordinatorId, mTaskId); } diff --git a/tests/src/com/android/ims/rcs/uce/presence/pidfparser/PidfParserTest.java b/tests/src/com/android/ims/rcs/uce/presence/pidfparser/PidfParserTest.java index fc21f75e..fd29d5b3 100644 --- a/tests/src/com/android/ims/rcs/uce/presence/pidfparser/PidfParserTest.java +++ b/tests/src/com/android/ims/rcs/uce/presence/pidfparser/PidfParserTest.java @@ -93,7 +93,10 @@ public class PidfParserTest extends ImsTestBase { isVideoSupported); // Convert to the class RcsContactUceCapability - RcsContactUceCapability capabilities = PidfParser.getRcsContactUceCapability(pidfData); + RcsContactUceCapabilityWrapper capabilitiesWrapper = + PidfParser.getRcsContactUceCapabilityWrapper(pidfData); + assertNotNull(capabilitiesWrapper); + RcsContactUceCapability capabilities = capabilitiesWrapper.toRcsContactUceCapability(); assertNotNull(capabilities); assertEquals(Uri.parse(contact), capabilities.getContactUri()); assertEquals(Uri.parse(contact), capabilities.getEntityUri()); @@ -168,7 +171,10 @@ public class PidfParserTest extends ImsTestBase { String pidfData = getPidfDataWithNewlineAndWhitespaceCharacters(); // Convert to the class RcsContactUceCapability - RcsContactUceCapability capabilities = PidfParser.getRcsContactUceCapability(pidfData); + RcsContactUceCapabilityWrapper capabilitiesWrapper = + PidfParser.getRcsContactUceCapabilityWrapper(pidfData); + assertNotNull(capabilitiesWrapper); + RcsContactUceCapability capabilities = capabilitiesWrapper.toRcsContactUceCapability(); assertNotNull(capabilities); assertEquals(Uri.parse(contact), capabilities.getContactUri()); @@ -235,7 +241,10 @@ public class PidfParserTest extends ImsTestBase { serviceId2, serviceDescription2, isAudioSupported, isVideoSupported); // Convert to the class RcsContactUceCapability - RcsContactUceCapability capabilities = PidfParser.getRcsContactUceCapability(pidfData); + RcsContactUceCapabilityWrapper capabilitiesWrapper = + PidfParser.getRcsContactUceCapabilityWrapper(pidfData); + assertNotNull(capabilitiesWrapper); + RcsContactUceCapability capabilities = capabilitiesWrapper.toRcsContactUceCapability(); assertNotNull(capabilities); assertEquals(Uri.parse(contact), capabilities.getContactUri()); @@ -277,8 +286,11 @@ public class PidfParserTest extends ImsTestBase { final String pidf = PidfParser.convertToPidf(capability); // Restore to the RcsContactUceCapability from the pidf + RcsContactUceCapabilityWrapper capabilitiesWrapper = + PidfParser.getRcsContactUceCapabilityWrapper(pidf); + assertNotNull(capabilitiesWrapper); final RcsContactUceCapability restoredCapability = - PidfParser.getRcsContactUceCapability(pidf); + capabilitiesWrapper.toRcsContactUceCapability(); assertEquals(capability.getContactUri(), restoredCapability.getContactUri()); assertEquals(capability.getCapabilityMechanism(), diff --git a/tests/src/com/android/ims/rcs/uce/presence/pidfparser/RcsContactUceCapabilityWrapperTest.java b/tests/src/com/android/ims/rcs/uce/presence/pidfparser/RcsContactUceCapabilityWrapperTest.java new file mode 100644 index 00000000..9497e198 --- /dev/null +++ b/tests/src/com/android/ims/rcs/uce/presence/pidfparser/RcsContactUceCapabilityWrapperTest.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2022 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.rcs.uce.presence.pidfparser; + + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import android.net.Uri; +import android.telephony.ims.RcsContactPresenceTuple; +import android.telephony.ims.RcsContactUceCapability; + +import androidx.test.ext.junit.runners.AndroidJUnit4; +import androidx.test.filters.SmallTest; + +import com.android.ims.ImsTestBase; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(AndroidJUnit4.class) +public class RcsContactUceCapabilityWrapperTest extends ImsTestBase { + + + @Before + public void setUp() throws Exception { + super.setUp(); + } + + @After + public void tearDown() throws Exception { + super.tearDown(); + } + + @Test + @SmallTest + public void testMalformedStatus() throws Exception { + RcsContactUceCapabilityWrapper capabilityWrapper = getRcsContactUceCapabilityWrapper(); + capabilityWrapper.setMalformedContents(); + + assertTrue(capabilityWrapper.isMalformed()); + + RcsContactPresenceTuple.Builder tupleBuilder = new RcsContactPresenceTuple.Builder( + "open", "test", "1.0"); + + capabilityWrapper.addCapabilityTuple(tupleBuilder.build()); + assertFalse(capabilityWrapper.isMalformed()); + } + + private RcsContactUceCapabilityWrapper getRcsContactUceCapabilityWrapper() { + final Uri contact = Uri.fromParts("sip", "test", null); + RcsContactUceCapabilityWrapper wrapper = new RcsContactUceCapabilityWrapper(contact, + RcsContactUceCapability.SOURCE_TYPE_NETWORK, + RcsContactUceCapability.REQUEST_RESULT_FOUND); + + return wrapper; + } +} diff --git a/tests/src/com/android/ims/rcs/uce/presence/pidfparser/pidf/PresenceTest.java b/tests/src/com/android/ims/rcs/uce/presence/pidfparser/pidf/PresenceTest.java index 99606f90..3a4c9f93 100644 --- a/tests/src/com/android/ims/rcs/uce/presence/pidfparser/pidf/PresenceTest.java +++ b/tests/src/com/android/ims/rcs/uce/presence/pidfparser/pidf/PresenceTest.java @@ -49,7 +49,6 @@ import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlPullParserFactory; import org.xmlpull.v1.XmlSerializer; - @RunWith(AndroidJUnit4.class) public class PresenceTest extends ImsTestBase { @@ -171,6 +170,95 @@ public class PresenceTest extends ImsTestBase { assertEquals(contact, PidfParserUtils.getTupleContact(tuple)); } + @Test + @SmallTest + public void testMalformedParsing() throws Exception { + final String contact = Uri.fromParts("sip", "test", null).toString(); + final String serviceId = "service_id_01"; + final String version = "1.0"; + final String description = "description_test"; + final String serviceId2 = "service_id_02"; + final String version2 = "2.0"; + final String description2 = "description_test2"; + final String serviceId3 = "service_id_03"; + final String version3 = "3.0"; + final String description3 = "description_test3"; + + StringBuilder presenceExample = new StringBuilder(); + presenceExample.append("") + .append("") + .append("open") + .append("") + .append("").append(serviceId).append("") + .append("").append(version).append("") + .append("").append(description).append("") + .append("") + .append("sip:test") + .append("open") + .append("") + .append("").append(serviceId2).append("") + .append("").append(version2).append("") + .append("").append(description2).append("") + .append("") + .append("sip:test") + .append("open") + .append("") + .append("").append(serviceId3).append("") + .append("").append(version3).append("") + .append("").append(description3).append("") + .append("") + .append("sip:test"); + + XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser(); + parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true); + Reader reader = new StringReader(presenceExample.toString()); + parser.setInput(reader); + + Presence presence = null; + int nextType = parser.next(); + + // Find the start tag + do { + if (nextType == XmlPullParser.START_TAG + && Presence.ELEMENT_NAME.equals(parser.getName())) { + presence = new Presence(); + presence.parse(parser); + break; + } + nextType = parser.next(); + } while(nextType != XmlPullParser.END_DOCUMENT); + + reader.close(); + + assertNotNull(presence); + assertEquals(contact, presence.getEntity()); + + List tupleList = presence.getTupleList(); + assertNotNull(tupleList); + assertEquals(3, tupleList.size()); + assertNotNull(tupleList.get(0)); // tuple of tid0 + assertNotNull(tupleList.get(1)); // tuple of tid1. tid1 is a tuple that failed to parse. + assertNotNull(tupleList.get(2)); // tuple of tid2. + + Tuple tuple = tupleList.get(0); + assertEquals(contact, PidfParserUtils.getTupleContact(tuple)); + + assertEquals(serviceId, PidfParserUtils.getTupleServiceId(tuple)); + assertEquals(version, PidfParserUtils.getTupleServiceVersion(tuple)); + assertEquals(description, PidfParserUtils.getTupleServiceDescription(tuple)); + + Tuple tuple1 = tupleList.get(1); + assertTrue(PidfParserUtils.getTupleMalformedStatus(tuple1)); + + Tuple tuple3 = tupleList.get(2); + assertEquals(serviceId3, PidfParserUtils.getTupleServiceId(tuple3)); + assertEquals(version3, PidfParserUtils.getTupleServiceVersion(tuple3)); + assertEquals(description3, PidfParserUtils.getTupleServiceDescription(tuple3)); + } + private Tuple getTuple(String statusValue, String serviceIdValue, String descValue, String contactValue) { Basic basic = new Basic(statusValue); diff --git a/tests/src/com/android/ims/rcs/uce/presence/pidfparser/pidf/TupleTest.java b/tests/src/com/android/ims/rcs/uce/presence/pidfparser/pidf/TupleTest.java index 3c44bd2b..dc5edaa8 100644 --- a/tests/src/com/android/ims/rcs/uce/presence/pidfparser/pidf/TupleTest.java +++ b/tests/src/com/android/ims/rcs/uce/presence/pidfparser/pidf/TupleTest.java @@ -218,7 +218,10 @@ public class TupleTest extends ImsTestBase { String resultNote = null; List noteList = tuple.getNoteList(); if (noteList != null && !noteList.isEmpty()) { - resultNote = noteList.get(0).getNote(); + Note eachNote = noteList.get(0); + if (eachNote != null) { + resultNote = eachNote.getNote(); + } } assertTrue(note.equals(resultNote)); -- cgit v1.2.3 From 6dd12f9e2dc9e9ff0d6f7b0284d08c64393d4ef4 Mon Sep 17 00:00:00 2001 From: Hyunho Date: Wed, 6 Apr 2022 13:13:29 +0000 Subject: After saving the capability information in the EAB DB, the invalid data is immediately deleted from the EAB DB. However, if you request the information just saved in DB, EabControllerImpl can generate information based on invalid data. Bug: b/227862302 Test: atest CtsTelephonyTestCases:EabControllerTest, RcsContactUceCapabilityTest, RcsUceAdapterTest, ImsServiceTest Test: atest EabControllerTest, EabProviderTest, UceControllerTest, UceControllerManagerTest, Change-Id: I357cbc22821bf8847ba3ac5fb8a98da15fd4d53a --- .../android/ims/rcs/uce/eab/EabControllerImpl.java | 49 ++++++++++++---------- .../android/ims/rcs/uce/eab/EabControllerTest.java | 31 ++++++++++++++ 2 files changed, 58 insertions(+), 22 deletions(-) diff --git a/src/java/com/android/ims/rcs/uce/eab/EabControllerImpl.java b/src/java/com/android/ims/rcs/uce/eab/EabControllerImpl.java index 1750385b..aaab0a9f 100644 --- a/src/java/com/android/ims/rcs/uce/eab/EabControllerImpl.java +++ b/src/java/com/android/ims/rcs/uce/eab/EabControllerImpl.java @@ -128,6 +128,7 @@ public class EabControllerImpl implements EabController { // Pick up changes to CarrierConfig and run any applicable cleanup tasks associated with // that configuration. mCapabilityCleanupRunnable.run(); + cleanupOrphanedRows(); if (!mIsSetDestroyedFlag) { mEabBulkCapabilityUpdater.onCarrierConfigChanged(); } @@ -270,7 +271,7 @@ public class EabControllerImpl implements EabController { c.close(); } } - + cleanupOrphanedRows(); mEabBulkCapabilityUpdater.updateExpiredTimeAlert(); if (mHandler.hasCallbacks(mCapabilityCleanupRunnable)) { @@ -280,6 +281,25 @@ public class EabControllerImpl implements EabController { CLEAN_UP_LEGACY_CAPABILITY_DELAY_MILLI_SEC); } + /** + * Cleanup the entry of common table that can't map to presence or option table + */ + @VisibleForTesting + public void cleanupOrphanedRows() { + String presenceSelection = + " (SELECT " + EabProvider.PresenceTupleColumns.EAB_COMMON_ID + + " FROM " + EAB_PRESENCE_TUPLE_TABLE_NAME + ") "; + String optionSelection = + " (SELECT " + EabProvider.OptionsColumns.EAB_COMMON_ID + + " FROM " + EAB_OPTIONS_TABLE_NAME + ") "; + + mContext.getContentResolver().delete( + EabProvider.COMMON_URI, + EabProvider.EabCommonColumns._ID + " NOT IN " + presenceSelection + + " AND " + EabProvider.EabCommonColumns._ID+ " NOT IN " + optionSelection, + null); + } + private List generateDestroyedResult(List contactUri) { List destroyedResult = new ArrayList<>(); for (Uri uri : contactUri) { @@ -392,8 +412,12 @@ public class EabControllerImpl implements EabController { RcsUceCapabilityBuilderWrapper builderWrapper) { if (builderWrapper.getMechanism() == CAPABILITY_MECHANISM_PRESENCE) { PresenceBuilder builder = builderWrapper.getPresenceBuilder(); - if (builder != null) { - builder.addCapabilityTuple(createPresenceTuple(contactUri, cursor)); + if (builder == null) { + return; + } + RcsContactPresenceTuple presenceTuple = createPresenceTuple(contactUri, cursor); + if (presenceTuple != null) { + builder.addCapabilityTuple(presenceTuple); } } else { OptionsBuilder builder = builderWrapper.getOptionsBuilder(); @@ -799,7 +823,6 @@ public class EabControllerImpl implements EabController { cleanupCapabilities(rcsCapabilitiesExpiredTime, getRcsCommonIdList()); cleanupCapabilities(nonRcsCapabilitiesExpiredTime, getNonRcsCommonIdList()); - cleanupOrphanedRows(); } private void cleanupCapabilities(long rcsCapabilitiesExpiredTime, List commonIdList) { @@ -867,24 +890,6 @@ public class EabControllerImpl implements EabController { return list; } - /** - * Cleanup the entry of common table that can't map to presence or option table - */ - private void cleanupOrphanedRows() { - String presenceSelection = - " (SELECT " + EabProvider.PresenceTupleColumns.EAB_COMMON_ID + - " FROM " + EAB_PRESENCE_TUPLE_TABLE_NAME + ") "; - String optionSelection = - " (SELECT " + EabProvider.OptionsColumns.EAB_COMMON_ID + - " FROM " + EAB_OPTIONS_TABLE_NAME + ") "; - - mContext.getContentResolver().delete( - EabProvider.COMMON_URI, - EabProvider.EabCommonColumns._ID + " NOT IN " + presenceSelection + - " AND " + EabProvider.EabCommonColumns._ID+ " NOT IN " + optionSelection, - null); - } - private String getStringValue(Cursor cursor, String column) { return cursor.getString(cursor.getColumnIndex(column)); } diff --git a/tests/src/com/android/ims/rcs/uce/eab/EabControllerTest.java b/tests/src/com/android/ims/rcs/uce/eab/EabControllerTest.java index f855d061..0040dc9e 100644 --- a/tests/src/com/android/ims/rcs/uce/eab/EabControllerTest.java +++ b/tests/src/com/android/ims/rcs/uce/eab/EabControllerTest.java @@ -208,6 +208,34 @@ public class EabControllerTest extends ImsTestBase { mEabControllerSub1.getCapabilities(contactUriList).get(0).getStatus()); } + @Test + @SmallTest + public void testSaveCapabilityAndCleanupInvalidDataInCommonTable() throws InterruptedException { + // Insert invalid data in common table + ContentValues data = new ContentValues(); + data.put(EabProvider.EabCommonColumns.EAB_CONTACT_ID, -1); + data.put(EabProvider.EabCommonColumns.MECHANISM, CAPABILITY_MECHANISM_PRESENCE); + data.put(EabProvider.EabCommonColumns.REQUEST_RESULT, REQUEST_RESULT_FOUND); + data.put(EabProvider.EabCommonColumns.SUBSCRIPTION_ID, -1); + mContext.getContentResolver().insert(COMMON_URI, data); + + List contactList = new ArrayList<>(); + contactList.add(createPresenceCapability()); + mEabControllerSub1.saveCapabilities(contactList); + + mExecutor.awaitTermination(TIME_OUT_IN_SEC, TimeUnit.SECONDS); + + // Verify the entry that cannot map to presence/option table has been removed + Cursor cursor = mContext.getContentResolver().query(COMMON_URI, null, null, null, null); + while(cursor.moveToNext()) { + int contactId = cursor.getInt( + cursor.getColumnIndex(EabProvider.EabCommonColumns.EAB_CONTACT_ID)); + if (contactId == -1) { + fail("Invalid data didn't been cleared"); + } + } + } + @Test @SmallTest public void testCleanupInvalidDataInCommonTable() throws InterruptedException { @@ -219,6 +247,7 @@ public class EabControllerTest extends ImsTestBase { data.put(EabProvider.EabCommonColumns.SUBSCRIPTION_ID, -1); mContext.getContentResolver().insert(COMMON_URI, data); + mEabControllerSub1.cleanupOrphanedRows(); mExecutor.execute(mEabControllerSub1.mCapabilityCleanupRunnable); mExecutor.awaitTermination(TIME_OUT_IN_SEC, TimeUnit.SECONDS); @@ -252,6 +281,7 @@ public class EabControllerTest extends ImsTestBase { expiredDate.getTime().getTime() / 1000); mContext.getContentResolver().insert(PRESENCE_URI, data); + mEabControllerSub1.cleanupOrphanedRows(); mExecutor.execute(mEabControllerSub1.mCapabilityCleanupRunnable); mExecutor.awaitTermination(TIME_OUT_IN_SEC, TimeUnit.SECONDS); @@ -285,6 +315,7 @@ public class EabControllerTest extends ImsTestBase { expiredDate.getTime().getTime() / 1000); mContext.getContentResolver().insert(OPTIONS_URI, data); + mEabControllerSub1.cleanupOrphanedRows(); mExecutor.execute(mEabControllerSub1.mCapabilityCleanupRunnable); mExecutor.awaitTermination(TIME_OUT_IN_SEC, TimeUnit.SECONDS); -- cgit v1.2.3 From 4bacd9b15a36491fd5727c836258de19905c6ae7 Mon Sep 17 00:00:00 2001 From: virkumar Date: Thu, 21 Apr 2022 09:31:35 +0000 Subject: (Increasing logging) Adding a new case for IllegalStateException Handle IllegalStateException for increasing logging incase such excpetion occures. Test: atest CtsTelephonyTestCases:ImsCallingTest Bug: 229756822 Change-Id: Iea42ae7c41eb424978bf4390aa8cea63fbd81fce --- src/java/com/android/ims/MmTelFeatureConnection.java | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/java/com/android/ims/MmTelFeatureConnection.java b/src/java/com/android/ims/MmTelFeatureConnection.java index cd8c3f15..3170d413 100644 --- a/src/java/com/android/ims/MmTelFeatureConnection.java +++ b/src/java/com/android/ims/MmTelFeatureConnection.java @@ -87,9 +87,10 @@ public class MmTelFeatureConnection extends FeatureConnection { if (imsRegistration != null) { try { imsRegistration.removeRegistrationCallback(localCallback); - } catch (RemoteException e) { + } catch (RemoteException | IllegalStateException e) { Log.w(TAG + " [" + mSlotId + "]", "ImsRegistrationCallbackAdapter -" - + " unregisterCallback: couldn't remove registration callback"); + + " unregisterCallback: couldn't remove registration callback" + + " Exception: " + e.getMessage()); } } else { Log.e(TAG + " [" + mSlotId + "]", "ImsRegistrationCallbackAdapter: ImsRegistration" @@ -145,9 +146,9 @@ public class MmTelFeatureConnection extends FeatureConnection { if (binder != null) { try { binder.removeCapabilityCallback(localCallback); - } catch (RemoteException e) { + } catch (RemoteException | IllegalStateException e) { Log.w(TAG + " [" + mSlotId + "]", "CapabilityCallbackManager, unregister:" - + " Binder is dead."); + + " Binder is dead. Exception: " + e.getMessage()); } } else { Log.w(TAG + " [" + mSlotId + "]", "CapabilityCallbackManager, unregister:" @@ -187,9 +188,9 @@ public class MmTelFeatureConnection extends FeatureConnection { } try { binder.removeImsConfigCallback(localCallback); - } catch (RemoteException e) { + } catch (RemoteException | IllegalStateException e) { Log.w(TAG + " [" + mSlotId + "]", "ProvisioningCallbackManager - couldn't" - + " unregister, binder is dead."); + + " unregister, binder is dead. Exception: " + e.getMessage()); } } } @@ -322,8 +323,9 @@ public class MmTelFeatureConnection extends FeatureConnection { mMultiEndpoint.getInterface().setExternalCallStateListener(null); mMultiEndpoint = new BinderAccessState<>(BinderAccessState.STATE_NOT_SET); } - } catch (RemoteException e) { - Log.w(TAG + " [" + mSlotId + "]", "closeConnection: couldn't remove listeners!"); + } catch (RemoteException | IllegalStateException e) { + Log.w(TAG + " [" + mSlotId + "]", "closeConnection: couldn't remove listeners!" + + " Exception: " + e.getMessage()); } } } -- cgit v1.2.3 From fe88fb788d696fe0d6e55d574e35b28c4edcedff Mon Sep 17 00:00:00 2001 From: Hyunho Date: Thu, 21 Apr 2022 02:36:07 +0000 Subject: Add the break statement between vt_provisioning_status and rcs_publish_source_throttle_ms This is to prevent an accident in which an incorrect value is set. Bug: b/229396800 Test: Build pass Change-Id: I283bcadb6bf1e91635d4052a1e67cc0bcb8db56d Merged-In: I283bcadb6bf1e91635d4052a1e67cc0bcb8db56d --- .../android/ims/rcs/uce/presence/publish/DeviceCapabilityListener.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListener.java b/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListener.java index d2177eaa..442cf7da 100644 --- a/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListener.java +++ b/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListener.java @@ -554,6 +554,7 @@ public class DeviceCapabilityListener { case ProvisioningManager.KEY_VOLTE_PROVISIONING_STATUS: case ProvisioningManager.KEY_VT_PROVISIONING_STATUS: handleProvisioningChanged(); + break; case ProvisioningManager.KEY_RCS_PUBLISH_SOURCE_THROTTLE_MS: handlePublishThrottleChanged(value); break; -- cgit v1.2.3 From 41ac9d60fd0892e63d737538906c24fca7a43f49 Mon Sep 17 00:00:00 2001 From: Hyunho Date: Thu, 21 Apr 2022 12:36:41 +0000 Subject: Add state for 480,486,500,503,603 responses of PUBLISH Upon receiving 480,486,500,503,603 responses to PUBLISH, the device state set to re_try. If the device state is retry, the PUBLISH requests should be blocked until the vendor called CapabilityExchangeEventListener#onPublishUpdated or CapabilityExchangeEventListener#onRequestPublishCapabilities. Test: atest PublishControllerImplTest CapabilityRequestTest UceControllerTest Bug: b/228781651 Change-Id: I0a4d41a885ff3d212f1d003602b83ccf5ed0a430 Merged-In: I0a4d41a885ff3d212f1d003602b83ccf5ed0a430 --- src/java/com/android/ims/rcs/uce/UceDeviceState.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/java/com/android/ims/rcs/uce/UceDeviceState.java b/src/java/com/android/ims/rcs/uce/UceDeviceState.java index 8d4de9f2..93445dbf 100644 --- a/src/java/com/android/ims/rcs/uce/UceDeviceState.java +++ b/src/java/com/android/ims/rcs/uce/UceDeviceState.java @@ -297,7 +297,12 @@ public class UceDeviceState { break; case NetworkSipCode.SIP_CODE_REQUEST_ENTITY_TOO_LARGE: // sip 413 + case NetworkSipCode.SIP_CODE_TEMPORARILY_UNAVAILABLE: // sip 480 + case NetworkSipCode.SIP_CODE_BUSY: // sip 486 + case NetworkSipCode.SIP_CODE_SERVER_INTERNAL_ERROR: // sip 500 + case NetworkSipCode.SIP_CODE_SERVICE_UNAVAILABLE: // sip 503 case NetworkSipCode.SIP_CODE_BUSY_EVERYWHERE: // sip 600 + case NetworkSipCode.SIP_CODE_DECLINE: // sip 603 if (requestType == UceController.REQUEST_TYPE_PUBLISH) { setDeviceState(DEVICE_STATE_NO_RETRY); // There is no request retry time for SIP code 413 -- cgit v1.2.3 From c222f29e504dd9a676a2d02cd25b2ab2fd38651d Mon Sep 17 00:00:00 2001 From: Hyunho Date: Wed, 4 May 2022 22:43:32 +0000 Subject: add use_tel_uri_for_pidf_xml field for ATT-UCE 430 Add use_tel_uri_for_pidf_xml field for ATT-UCE 430 Set the added filed to false by defaut and true for ATT If the field is true, get the first TEL URI from associated uris. Bug: b/229669620 Test: PUBLSIH-200 OK in live network Test: Forcibly set tel and sip uri to assocoated uri and change the field value to see if the desired URI is obtained. Test: atest DeviceCapabilityInfoTest Change-Id: I64537994418beb37c7a05c206cebe5bbc9fcb8f5 --- .../uce/presence/publish/DeviceCapabilityInfo.java | 33 ++++++-- .../ims/rcs/uce/presence/publish/PublishUtils.java | 55 ++++++++++++- .../com/android/ims/rcs/uce/util/UceUtils.java | 16 ++++ .../presence/publish/DeviceCapabilityInfoTest.java | 95 ++++++++++++++++++++++ 4 files changed, 188 insertions(+), 11 deletions(-) diff --git a/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityInfo.java b/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityInfo.java index 31f86fc2..7c574ce5 100644 --- a/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityInfo.java +++ b/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityInfo.java @@ -20,6 +20,7 @@ import static android.telephony.ims.RcsContactUceCapability.SOURCE_TYPE_CACHED; import android.content.Context; import android.net.Uri; +import android.telecom.PhoneAccount; import android.telecom.TelecomManager; import android.telephony.AccessNetworkConstants; import android.telephony.ims.ImsRegistrationAttributes; @@ -289,12 +290,30 @@ public class DeviceCapabilityInfo { * Get the IMS associated URI. It will first get the uri of MMTEL if it is not empty, otherwise * it will try to get the uri of RCS. The null will be returned if both MMTEL and RCS are empty. */ - public synchronized Uri getImsAssociatedUri() { - if (!mRcsAssociatedUris.isEmpty()) { - return mRcsAssociatedUris.get(0); - } else if (!mMmtelAssociatedUris.isEmpty()) { - return mMmtelAssociatedUris.get(0); + public synchronized Uri getImsAssociatedUri(boolean perferTelUri) { + if (perferTelUri == false) { + if (!mRcsAssociatedUris.isEmpty()) { + return mRcsAssociatedUris.get(0); + } else if (!mMmtelAssociatedUris.isEmpty()) { + return mMmtelAssociatedUris.get(0); + } else { + return null; + } } else { + if (!mRcsAssociatedUris.isEmpty()) { + for (Uri rcsAssociatedUri : mRcsAssociatedUris) { + if (PhoneAccount.SCHEME_TEL.equalsIgnoreCase(rcsAssociatedUri.getScheme())) { + return rcsAssociatedUri; + } + } + } + if (!mMmtelAssociatedUris.isEmpty()) { + for (Uri mmtelAssociatedUri : mMmtelAssociatedUris) { + if (PhoneAccount.SCHEME_TEL.equalsIgnoreCase(mmtelAssociatedUri.getScheme())) { + return mmtelAssociatedUri; + } + } + } return null; } } @@ -540,7 +559,7 @@ public class DeviceCapabilityInfo { // Get the device's capabilities with the PRESENCE mechanism. private RcsContactUceCapability getPresenceCapabilities(Context context) { - Uri uri = PublishUtils.getDeviceContactUri(context, mSubId, this); + Uri uri = PublishUtils.getDeviceContactUri(context, mSubId, this, true); if (uri == null) { logw("getPresenceCapabilities: uri is empty"); return null; @@ -601,7 +620,7 @@ public class DeviceCapabilityInfo { // Get the device's capabilities with the OPTIONS mechanism. private RcsContactUceCapability getOptionsCapabilities(Context context) { - Uri uri = PublishUtils.getDeviceContactUri(context, mSubId, this); + Uri uri = PublishUtils.getDeviceContactUri(context, mSubId, this, false); if (uri == null) { logw("getOptionsCapabilities: uri is empty"); return null; diff --git a/src/java/com/android/ims/rcs/uce/presence/publish/PublishUtils.java b/src/java/com/android/ims/rcs/uce/presence/publish/PublishUtils.java index ea1d11b9..7df6bde5 100644 --- a/src/java/com/android/ims/rcs/uce/presence/publish/PublishUtils.java +++ b/src/java/com/android/ims/rcs/uce/presence/publish/PublishUtils.java @@ -18,6 +18,7 @@ package com.android.ims.rcs.uce.presence.publish; import android.content.Context; import android.net.Uri; +import android.telecom.PhoneAccount; import android.telephony.PhoneNumberUtils; import android.telephony.TelephonyManager; import android.telephony.ims.feature.RcsFeature.RcsImsCapabilities; @@ -25,6 +26,9 @@ import android.telephony.ims.feature.RcsFeature.RcsImsCapabilities.RcsImsCapabil import android.text.TextUtils; import android.util.Log; +import com.android.i18n.phonenumbers.NumberParseException; +import com.android.i18n.phonenumbers.PhoneNumberUtil; +import com.android.i18n.phonenumbers.Phonenumber; import com.android.ims.rcs.uce.util.UceUtils; import java.util.Arrays; @@ -40,9 +44,13 @@ public class PublishUtils { private static final String DOMAIN_SEPARATOR = "@"; public static Uri getDeviceContactUri(Context context, int subId, - DeviceCapabilityInfo deviceCap) { + DeviceCapabilityInfo deviceCap, boolean isForPresence) { + boolean preferTelUri = false; + if (isForPresence) { + preferTelUri = UceUtils.isTelUriForPidfXmlEnabled(context, subId); + } // Get the uri from the IMS associated URI which is provided by the IMS service. - Uri contactUri = deviceCap.getImsAssociatedUri(); + Uri contactUri = deviceCap.getImsAssociatedUri(preferTelUri); if (contactUri != null) { Log.d(LOG_TAG, "getDeviceContactUri: ims associated uri"); return contactUri; @@ -58,10 +66,18 @@ public class PublishUtils { contactUri = getContactUriFromIsim(telephonyManager); if (contactUri != null) { Log.d(LOG_TAG, "getDeviceContactUri: impu"); - return contactUri; + if (preferTelUri) { + return getConvertedTelUri(context, contactUri); + } else { + return contactUri; + } } else { Log.d(LOG_TAG, "getDeviceContactUri: line number"); - return getContactUriFromLine1Number(telephonyManager); + if (preferTelUri) { + return getConvertedTelUri(context, getContactUriFromLine1Number(telephonyManager)); + } else { + return getContactUriFromLine1Number(telephonyManager); + } } } @@ -136,6 +152,37 @@ public class PublishUtils { } } + private static Uri getConvertedTelUri(Context context, Uri contactUri) { + if (contactUri == null) { + return null; + } + if (contactUri.getScheme().equalsIgnoreCase(SCHEME_SIP)) { + TelephonyManager manager = context.getSystemService(TelephonyManager.class); + if (manager.getIsimDomain() == null) { + return contactUri; + } + + String numbers = contactUri.getSchemeSpecificPart(); + String[] numberParts = numbers.split("[@;:]"); + String number = numberParts[0]; + + String simCountryIso = manager.getSimCountryIso(); + if (!TextUtils.isEmpty(simCountryIso)) { + simCountryIso = simCountryIso.toUpperCase(); + PhoneNumberUtil util = PhoneNumberUtil.getInstance(); + try { + Phonenumber.PhoneNumber phoneNumber = util.parse(number, simCountryIso); + number = util.format(phoneNumber, PhoneNumberUtil.PhoneNumberFormat.E164); + String telUri = SCHEME_TEL + ":" + number; + contactUri = Uri.parse(telUri); + } catch (NumberParseException e) { + Log.w(LOG_TAG, "formatNumber: could not format " + number + ", error: " + e); + } + } + } + return contactUri; + } + static @RcsImsCapabilityFlag int getCapabilityType(Context context, int subId) { boolean isPresenceSupported = UceUtils.isPresenceSupported(context, subId); boolean isSipOptionsSupported = UceUtils.isSipOptionsSupported(context, subId); diff --git a/src/java/com/android/ims/rcs/uce/util/UceUtils.java b/src/java/com/android/ims/rcs/uce/util/UceUtils.java index ae98393a..e6d81b1d 100644 --- a/src/java/com/android/ims/rcs/uce/util/UceUtils.java +++ b/src/java/com/android/ims/rcs/uce/util/UceUtils.java @@ -207,6 +207,22 @@ public class UceUtils { CarrierConfigManager.Ims.KEY_USE_SIP_URI_FOR_PRESENCE_SUBSCRIBE_BOOL); } + /** + * Check whether tel uri should be used for pidf xml + */ + public static boolean isTelUriForPidfXmlEnabled(Context context, int subId) { + CarrierConfigManager configManager = context.getSystemService(CarrierConfigManager.class); + if (configManager == null) { + return false; + } + PersistableBundle config = configManager.getConfigForSubId(subId); + if (config == null) { + return false; + } + return config.getBoolean( + CarrierConfigManager.Ims.KEY_USE_TEL_URI_FOR_PIDF_XML_BOOL); + } + /** * Get the minimum time that allow two PUBLISH requests can be executed continuously. * diff --git a/tests/src/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityInfoTest.java b/tests/src/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityInfoTest.java index eb2140e6..7a304796 100644 --- a/tests/src/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityInfoTest.java +++ b/tests/src/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityInfoTest.java @@ -22,6 +22,12 @@ import static org.junit.Assert.assertTrue; import android.telephony.ims.RcsContactPresenceTuple; import android.util.ArraySet; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +import android.net.Uri; +import android.telecom.PhoneAccount; + import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; @@ -40,8 +46,12 @@ import java.util.Set; public class DeviceCapabilityInfoTest extends ImsTestBase { int mSubId = 1; + @Mock PublishServiceDescTracker mPublishServiceDescTracker; + String sipNumber = "123456789"; + String telNumber = "987654321"; + @Before public void setUp() throws Exception { super.setUp(); @@ -68,6 +78,43 @@ public class DeviceCapabilityInfoTest extends ImsTestBase { assertFalse(deviceCapInfo.isPresenceCapabilityChanged(mTestCapability)); } + @Test + @SmallTest + public void testGetImsAssociatedUriWithoutPreferTelUri() throws Exception { + DeviceCapabilityInfo deviceCapInfo = createDeviceCapabilityInfo(); + + Uri[] uris = new Uri[2]; + uris[0] = Uri.fromParts(PhoneAccount.SCHEME_SIP, sipNumber, null); + uris[1] = Uri.fromParts(PhoneAccount.SCHEME_TEL, telNumber, null); + + // When stored in the order of SIP, TEL URI, check whether the SIP URI saved at + // the beginning is retrieved. + deviceCapInfo.updateRcsAssociatedUri(uris); + Uri outUri = deviceCapInfo.getImsAssociatedUri(false); + + String numbers = outUri.getSchemeSpecificPart(); + String[] numberParts = numbers.split("[@;:]"); + String number = numberParts[0]; + + assertEquals(number, sipNumber); + + // When stored in the order of TEL, SIP URI, check whether the TEL URI saved at + // the beginning is retrieved. + deviceCapInfo = createDeviceCapabilityInfo(); + + uris[0] = Uri.fromParts(PhoneAccount.SCHEME_TEL, telNumber, null); + uris[1] = Uri.fromParts(PhoneAccount.SCHEME_SIP, sipNumber, null); + + deviceCapInfo.updateRcsAssociatedUri(uris); + outUri = deviceCapInfo.getImsAssociatedUri(false); + + numbers = outUri.getSchemeSpecificPart(); + numberParts = numbers.split("[@;:]"); + number = numberParts[0]; + + assertEquals(number, telNumber); + } + @Test @SmallTest public void testGetPresenceCapabilityForSameSizeOfDescription() throws Exception { @@ -84,6 +131,54 @@ public class DeviceCapabilityInfoTest extends ImsTestBase { assertTrue(deviceCapInfo.isPresenceCapabilityChanged(mTestCapability)); } + + @Test + @SmallTest + public void testGetImsAssociatedUriWithPreferTelUri() throws Exception { + DeviceCapabilityInfo deviceCapInfo = createDeviceCapabilityInfo(); + + Uri[] uris = new Uri[2]; + uris[0] = Uri.fromParts(PhoneAccount.SCHEME_SIP, sipNumber, null); + uris[1] = Uri.fromParts(PhoneAccount.SCHEME_TEL, telNumber, null); + + // Check whether TEL URI is returned when preferTelUri is true even if SIP and TEL URI + // are in the order. + deviceCapInfo.updateRcsAssociatedUri(uris); + Uri outUri = deviceCapInfo.getImsAssociatedUri(true); + + String numbers = outUri.getSchemeSpecificPart(); + String[] numberParts = numbers.split("[@;:]"); + String number = numberParts[0]; + + assertEquals(number, telNumber); + + // If preferTelUri is true, check if a TEL URI is returned. + deviceCapInfo = createDeviceCapabilityInfo(); + + uris[0] = Uri.fromParts(PhoneAccount.SCHEME_TEL, telNumber, null); + uris[1] = Uri.fromParts(PhoneAccount.SCHEME_SIP, sipNumber, null); + + deviceCapInfo.updateRcsAssociatedUri(uris); + outUri = deviceCapInfo.getImsAssociatedUri(true); + + numbers = outUri.getSchemeSpecificPart(); + numberParts = numbers.split("[@;:]"); + number = numberParts[0]; + + assertEquals(number, telNumber); + + //If there is only SIP URI, check the return uri is null if preferTelUir is true. + deviceCapInfo = createDeviceCapabilityInfo(); + + uris[0] = Uri.fromParts(PhoneAccount.SCHEME_SIP, telNumber, null); + uris[1] = Uri.fromParts(PhoneAccount.SCHEME_SIP, sipNumber, null); + + deviceCapInfo.updateRcsAssociatedUri(uris); + outUri = deviceCapInfo.getImsAssociatedUri(true); + + assertNull(outUri); + } + private DeviceCapabilityInfo createDeviceCapabilityInfo() { DeviceCapabilityInfo deviceCapInfo = new DeviceCapabilityInfo(mSubId, null); return deviceCapInfo; -- cgit v1.2.3 From bd80e173471fe720e076fc47f021bd2199eb81ae Mon Sep 17 00:00:00 2001 From: Chinmay Dhodapkar Date: Wed, 11 May 2022 02:11:44 +0000 Subject: updating OWNERS file Change-Id: Id0a072ae8bf6f71d3d2523bef84edecaaed30b48 --- OWNERS | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/OWNERS b/OWNERS index 8a0d4eda..95e48fc9 100644 --- a/OWNERS +++ b/OWNERS @@ -1,4 +1,5 @@ breadley@google.com -hallliu@google.com tgunn@google.com -dbright@google.com +chinmayd@google.com +xiaotonj@google.com +tjstuart@google.com -- cgit v1.2.3 From 7b6fb80d5ec80d4ef996453f16403727d17ff279 Mon Sep 17 00:00:00 2001 From: Chinmay Dhodapkar Date: Wed, 8 Jun 2022 11:56:11 -0700 Subject: Fix shouldProcessCall in ImsManager There can be call attempts made before the ims service is initialized. In this case, shouldProcessCall should throw an exception, else it might result in subsequent call failure in IMS. Bug: 232514463 Test: atest ImsManagerTest Change-Id: I81a25250a65bf6af0910c57f093ebbc71bad1dba --- src/java/com/android/ims/ImsManager.java | 3 ++- tests/src/com/android/ims/ImsManagerTest.java | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/java/com/android/ims/ImsManager.java b/src/java/com/android/ims/ImsManager.java index cf95a20b..c41426d0 100644 --- a/src/java/com/android/ims/ImsManager.java +++ b/src/java/com/android/ims/ImsManager.java @@ -3035,7 +3035,8 @@ public class ImsManager implements FeatureUpdates { public @MmTelFeature.ProcessCallResult int shouldProcessCall(boolean isEmergency, String[] numbers) throws ImsException { try { - return mMmTelConnectionRef.get().shouldProcessCall(isEmergency, numbers); + MmTelFeatureConnection c = getOrThrowExceptionIfServiceUnavailable(); + return c.shouldProcessCall(isEmergency, numbers); } catch (RemoteException e) { throw new ImsException("shouldProcessCall()", e, ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); diff --git a/tests/src/com/android/ims/ImsManagerTest.java b/tests/src/com/android/ims/ImsManagerTest.java index 42f110dc..0653908d 100644 --- a/tests/src/com/android/ims/ImsManagerTest.java +++ b/tests/src/com/android/ims/ImsManagerTest.java @@ -22,6 +22,7 @@ import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TE import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_LTE; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThrows; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.anyInt; @@ -968,6 +969,21 @@ public class ImsManagerTest extends ImsTestBase { anyInt()); } + @Test @SmallTest + public void testShouldProcessCall_ThrowsExceptionIfServiceIsStillInitializing() { + ImsManager imsManager = getImsManagerAndInitProvisionedValues(); + doReturn(-1).when(mMmTelFeatureConnection).getSubId(); + assertThrows(ImsException.class, () -> imsManager.shouldProcessCall(true, new String[1])); + } + + @Test @SmallTest + public void testShouldProcessCall_DoesNotThrowExceptionWhenServiceInitialized() + throws Exception { + ImsManager imsManager = getImsManagerAndInitProvisionedValues(); + int ret = imsManager.shouldProcessCall(true, new String[1]); + assertEquals(MmTelFeature.PROCESS_CALL_IMS, ret); + } + /** * Tests the operation of setWfcRoamingSetting and ensures that the user setting for WFC roaming * and the ImsConfig setting are both called properly. -- cgit v1.2.3 From 6780d3a616d0bb788f9b66d130f8a23356f54fa9 Mon Sep 17 00:00:00 2001 From: Hunsuk Choi Date: Thu, 2 Dec 2021 09:45:37 +0000 Subject: Add setTerminalBasedCallWaitingStatus to ImsManager setCallWaiting notifies IMS service the change of the user setting for the terminal-based call waiting. Bug: 202463005 Test: atest FrameworksTelephonyTests:CallWaitingControllerTest Change-Id: Idcd3765670a30db9c83bb45fe1e7bef1faed8efc (cherry picked from commit 1a27027d26e23b9db5a1e293f322518408fa0b66) Merged-In: Idcd3765670a30db9c83bb45fe1e7bef1faed8efc --- src/java/com/android/ims/ImsManager.java | 38 ++++++++++++++++++++++ .../com/android/ims/MmTelFeatureConnection.java | 13 ++++++++ 2 files changed, 51 insertions(+) diff --git a/src/java/com/android/ims/ImsManager.java b/src/java/com/android/ims/ImsManager.java index c41426d0..18bbd3e1 100644 --- a/src/java/com/android/ims/ImsManager.java +++ b/src/java/com/android/ims/ImsManager.java @@ -2689,6 +2689,44 @@ public class ImsManager implements FeatureUpdates { } } + /** + * Notifies the change of user setting. + * + * @param enabled indicates whether the user setting for call waiting is enabled or not. + */ + public void setTerminalBasedCallWaitingStatus(boolean enabled) throws ImsException { + MmTelFeatureConnection c = getOrThrowExceptionIfServiceUnavailable(); + try { + c.setTerminalBasedCallWaitingStatus(enabled); + } catch (ServiceSpecificException se) { + if (se.errorCode + == android.telephony.ims.ImsException.CODE_ERROR_UNSUPPORTED_OPERATION) { + throw new ImsException("setTerminalBasedCallWaitingStatus()", se, + ImsReasonInfo.CODE_LOCAL_IMS_NOT_SUPPORTED_ON_DEVICE); + } else { + throw new ImsException("setTerminalBasedCallWaitingStatus()", se, + ImsReasonInfo.CODE_LOCAL_INTERNAL_ERROR); + } + } catch (RemoteException e) { + throw new ImsException("setTerminalBasedCallWaitingStatus()", e, + ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); + } + } + + /** + * Returns whether all of the capabilities specified are capable or not. + */ + public boolean isCapable(@ImsService.ImsServiceCapability long capabilities) + throws ImsException { + MmTelFeatureConnection c = getOrThrowExceptionIfServiceUnavailable(); + try { + return c.isCapable(capabilities); + } catch (RemoteException e) { + throw new ImsException("isCapable()", e, + ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); + } + } + public int getImsServiceState() throws ImsException { MmTelFeatureConnection c = getOrThrowExceptionIfServiceUnavailable(); return c.getFeatureState(); diff --git a/src/java/com/android/ims/MmTelFeatureConnection.java b/src/java/com/android/ims/MmTelFeatureConnection.java index 3170d413..5ea5e420 100644 --- a/src/java/com/android/ims/MmTelFeatureConnection.java +++ b/src/java/com/android/ims/MmTelFeatureConnection.java @@ -576,6 +576,19 @@ public class MmTelFeatureConnection extends FeatureConnection { } } + /** + * Notifies the MmTelFeature of the enablement status of terminal based call waiting + * + * @param enabled indicates whether the user setting for call waiting is enabled or not. + */ + public void setTerminalBasedCallWaitingStatus(boolean enabled) + throws RemoteException { + synchronized (mLock) { + checkServiceIsReady(); + getServiceInterface(mBinder).setTerminalBasedCallWaitingStatus(enabled); + } + } + private IImsMmTelFeature getServiceInterface(IBinder b) { return IImsMmTelFeature.Stub.asInterface(b); } -- cgit v1.2.3 From 6ff421d8fc86013c64d449971c930afa0928907a Mon Sep 17 00:00:00 2001 From: Chinmay Dhodapkar Date: Fri, 17 Jun 2022 14:29:47 -0700 Subject: Add MODIFY_PHONE_STATE when registering receiver Without this additional check we can end up handling ACTION_TTY_PREFERRED_MODE_CHANGE from an unpriviledged app Currently this intent is sent by dialer on 1P devices, so it cannot be converted to a protected-broadcast Bug: 236264289 Tests: atest DeviceCapabilityListenerTest Change-Id: I221b28dd3e1f7ed51f915dc79a62f8818f8a65a2 --- .../ims/rcs/uce/presence/publish/DeviceCapabilityListener.java | 3 ++- tests/src/com/android/ims/ContextFixture.java | 7 +++++++ .../ims/rcs/uce/presence/publish/DeviceCapabilityListenerTest.java | 3 ++- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListener.java b/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListener.java index 442cf7da..cc5cadb2 100644 --- a/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListener.java +++ b/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListener.java @@ -274,7 +274,8 @@ public class DeviceCapabilityListener { IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED); filter.addAction(TelecomManager.ACTION_TTY_PREFERRED_MODE_CHANGED); - mContext.registerReceiver(mReceiver, filter); + mContext.registerReceiver(mReceiver, filter, android.Manifest.permission.MODIFY_PHONE_STATE, + null); ContentResolver resolver = mContext.getContentResolver(); if (resolver != null) { diff --git a/tests/src/com/android/ims/ContextFixture.java b/tests/src/com/android/ims/ContextFixture.java index e987b387..48cb9ab1 100644 --- a/tests/src/com/android/ims/ContextFixture.java +++ b/tests/src/com/android/ims/ContextFixture.java @@ -33,6 +33,7 @@ import android.content.IntentFilter; import android.content.pm.PackageManager; import android.content.res.Resources; import android.net.ConnectivityManager; +import android.os.Handler; import android.os.PersistableBundle; import android.telecom.TelecomManager; import android.telephony.CarrierConfigManager; @@ -130,6 +131,12 @@ public class ContextFixture { return null; } + @Override + public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter, + String broadcastPermission, Handler scheduler) { + return null; + } + @Override public void unregisterReceiver(BroadcastReceiver receiver) { } diff --git a/tests/src/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListenerTest.java b/tests/src/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListenerTest.java index 2d170ab6..f6221720 100644 --- a/tests/src/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListenerTest.java +++ b/tests/src/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListenerTest.java @@ -107,7 +107,8 @@ public class DeviceCapabilityListenerTest extends ImsTestBase { deviceCapListener.initialize(); - verify(mContext).registerReceiver(any(), any()); + verify(mContext).registerReceiver(any(), any(), + eq(android.Manifest.permission.MODIFY_PHONE_STATE), any()); verify(mProvisioningManager).registerProvisioningChangedCallback(any(), any()); } -- cgit v1.2.3 From ed6a388e3f5a65065c11acd80f175b7e7169e9b2 Mon Sep 17 00:00:00 2001 From: Chinmay Dhodapkar Date: Fri, 17 Jun 2022 14:29:47 -0700 Subject: Add MODIFY_PHONE_STATE when registering receiver Without this additional check we can end up handling ACTION_TTY_PREFERRED_MODE_CHANGE from an unpriviledged app Currently this intent is sent by dialer on 1P devices, so it cannot be converted to a protected-broadcast Bug: 236264289 Tests: atest DeviceCapabilityListenerTest Change-Id: I221b28dd3e1f7ed51f915dc79a62f8818f8a65a2 --- .../ims/rcs/uce/presence/publish/DeviceCapabilityListener.java | 3 ++- tests/src/com/android/ims/ContextFixture.java | 7 +++++++ .../ims/rcs/uce/presence/publish/DeviceCapabilityListenerTest.java | 3 ++- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListener.java b/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListener.java index 442cf7da..cc5cadb2 100644 --- a/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListener.java +++ b/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListener.java @@ -274,7 +274,8 @@ public class DeviceCapabilityListener { IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED); filter.addAction(TelecomManager.ACTION_TTY_PREFERRED_MODE_CHANGED); - mContext.registerReceiver(mReceiver, filter); + mContext.registerReceiver(mReceiver, filter, android.Manifest.permission.MODIFY_PHONE_STATE, + null); ContentResolver resolver = mContext.getContentResolver(); if (resolver != null) { diff --git a/tests/src/com/android/ims/ContextFixture.java b/tests/src/com/android/ims/ContextFixture.java index e987b387..48cb9ab1 100644 --- a/tests/src/com/android/ims/ContextFixture.java +++ b/tests/src/com/android/ims/ContextFixture.java @@ -33,6 +33,7 @@ import android.content.IntentFilter; import android.content.pm.PackageManager; import android.content.res.Resources; import android.net.ConnectivityManager; +import android.os.Handler; import android.os.PersistableBundle; import android.telecom.TelecomManager; import android.telephony.CarrierConfigManager; @@ -130,6 +131,12 @@ public class ContextFixture { return null; } + @Override + public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter, + String broadcastPermission, Handler scheduler) { + return null; + } + @Override public void unregisterReceiver(BroadcastReceiver receiver) { } diff --git a/tests/src/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListenerTest.java b/tests/src/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListenerTest.java index 2d170ab6..f6221720 100644 --- a/tests/src/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListenerTest.java +++ b/tests/src/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListenerTest.java @@ -107,7 +107,8 @@ public class DeviceCapabilityListenerTest extends ImsTestBase { deviceCapListener.initialize(); - verify(mContext).registerReceiver(any(), any()); + verify(mContext).registerReceiver(any(), any(), + eq(android.Manifest.permission.MODIFY_PHONE_STATE), any()); verify(mProvisioningManager).registerProvisioningChangedCallback(any(), any()); } -- cgit v1.2.3 From b4a75a44ff977b0e9bfb215cdde502901ca36d6c Mon Sep 17 00:00:00 2001 From: Hyunho Date: Tue, 30 Aug 2022 11:56:49 +0000 Subject: Remove airplane mode handling code. In VZW TC 3.18, the device did not need to send a PUBLISH when a 412 response was received for a UN PUBLISH request. Turn on airplane mode for testing. As a result, the device sends a UN PUBLISH request. However, since airplane mode has changed, the Framework sends a PUBLISH request to the ImsService. So this case failed. Bug: b/243137045 Test: Turn on airplane mode > deice sends a UN PUBLISH request > Not handle airplane mode change event in the publish controller. Test: atest DeviceCapabilityListenerTest Change-Id: Id96bd4a233e9208865afaa9c3fe0cccb239bad93 --- .../uce/presence/publish/DeviceCapabilityInfo.java | 15 ----------- .../presence/publish/DeviceCapabilityListener.java | 15 ----------- .../uce/presence/publish/PublishController.java | 30 ++++++++++------------ .../publish/DeviceCapabilityListenerTest.java | 18 ------------- 4 files changed, 13 insertions(+), 65 deletions(-) diff --git a/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityInfo.java b/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityInfo.java index 9d65672b..96e952b9 100644 --- a/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityInfo.java +++ b/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityInfo.java @@ -103,7 +103,6 @@ public class DeviceCapabilityInfo { // Whether the settings are changed or not private int mTtyPreferredMode; - private boolean mAirplaneMode; private boolean mMobileData; private boolean mVtSetting; @@ -128,7 +127,6 @@ public class DeviceCapabilityInfo { mRcsRegistered = false; mRcsNetworkRegType = AccessNetworkConstants.TRANSPORT_TYPE_INVALID; mTtyPreferredMode = TelecomManager.TTY_MODE_OFF; - mAirplaneMode = false; mMobileData = true; mVtSetting = true; mMmTelCapabilities = new MmTelCapabilities(); @@ -385,19 +383,6 @@ public class DeviceCapabilityInfo { return false; } - /** - * Update airplane mode state. - * @return {@code true} if the airplane mode is changed, {@code false} otherwise. - */ - public synchronized boolean updateAirplaneMode(boolean state) { - if (mAirplaneMode != state) { - logd("Airplane mode changes from " + mAirplaneMode + " to " + state); - mAirplaneMode = state; - return true; - } - return false; - } - /** * Update mobile data setting. * @return {@code true} if the mobile data setting is changed, {@code false} otherwise. diff --git a/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListener.java b/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListener.java index cc5cadb2..9070c6f2 100644 --- a/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListener.java +++ b/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListener.java @@ -272,7 +272,6 @@ public class DeviceCapabilityListener { private void registerReceivers() { logd("registerReceivers"); IntentFilter filter = new IntentFilter(); - filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED); filter.addAction(TelecomManager.ACTION_TTY_PREFERRED_MODE_CHANGED); mContext.registerReceiver(mReceiver, filter, android.Manifest.permission.MODIFY_PHONE_STATE, null); @@ -390,11 +389,6 @@ public class DeviceCapabilityListener { TelecomManager.TTY_MODE_OFF); handleTtyPreferredModeChanged(preferredMode); break; - - case Intent.ACTION_AIRPLANE_MODE_CHANGED: - boolean airplaneMode = intent.getBooleanExtra("state", false); - handleAirplaneModeChanged(airplaneMode); - break; } } }; @@ -572,15 +566,6 @@ public class DeviceCapabilityListener { } } - private void handleAirplaneModeChanged(boolean state) { - boolean isChanged = mCapabilityInfo.updateAirplaneMode(state); - logi("Airplane mode changed: " + state + ", isChanged="+ isChanged); - if (isChanged) { - mHandler.sendTriggeringPublishMessage( - PublishController.PUBLISH_TRIGGER_AIRPLANE_MODE_CHANGE); - } - } - private void handleMobileDataChanged(boolean isEnabled) { boolean isChanged = mCapabilityInfo.updateMobileData(isEnabled); logi("Mobile data changed: " + isEnabled + ", isChanged=" + isChanged); diff --git a/src/java/com/android/ims/rcs/uce/presence/publish/PublishController.java b/src/java/com/android/ims/rcs/uce/presence/publish/PublishController.java index b20f5ceb..a3d31b9e 100644 --- a/src/java/com/android/ims/rcs/uce/presence/publish/PublishController.java +++ b/src/java/com/android/ims/rcs/uce/presence/publish/PublishController.java @@ -45,53 +45,49 @@ public interface PublishController extends ControllerBase { /** Publish trigger type: TTY preferred changes */ int PUBLISH_TRIGGER_TTY_PREFERRED_CHANGE = 3; - /** Publish trigger type: Airplane mode changes */ - int PUBLISH_TRIGGER_AIRPLANE_MODE_CHANGE = 4; - /** Publish trigger type: Mobile data changes */ - int PUBLISH_TRIGGER_MOBILE_DATA_CHANGE = 5; + int PUBLISH_TRIGGER_MOBILE_DATA_CHANGE = 4; /** Publish trigger type: VT setting changes */ - int PUBLISH_TRIGGER_VT_SETTING_CHANGE = 6; + int PUBLISH_TRIGGER_VT_SETTING_CHANGE = 5; /** Publish trigger type: MMTEL registered */ - int PUBLISH_TRIGGER_MMTEL_REGISTERED = 7; + int PUBLISH_TRIGGER_MMTEL_REGISTERED = 6; /** Publish trigger type: MMTEL unregistered */ - int PUBLISH_TRIGGER_MMTEL_UNREGISTERED = 8; + int PUBLISH_TRIGGER_MMTEL_UNREGISTERED = 7; /** Publish trigger type: MMTEL capability changes */ - int PUBLISH_TRIGGER_MMTEL_CAPABILITY_CHANGE = 9; + int PUBLISH_TRIGGER_MMTEL_CAPABILITY_CHANGE = 8; /** Publish trigger type: MMTEL associated uri changes */ - int PUBLISH_TRIGGER_MMTEL_URI_CHANGE = 10; + int PUBLISH_TRIGGER_MMTEL_URI_CHANGE = 9; /** Publish trigger type: RCS registered */ - int PUBLISH_TRIGGER_RCS_REGISTERED = 11; + int PUBLISH_TRIGGER_RCS_REGISTERED = 10; /** Publish trigger type: RCS unregistered */ - int PUBLISH_TRIGGER_RCS_UNREGISTERED = 12; + int PUBLISH_TRIGGER_RCS_UNREGISTERED = 11; /** Publish trigger type: RCS associated uri changes */ - int PUBLISH_TRIGGER_RCS_URI_CHANGE = 13; + int PUBLISH_TRIGGER_RCS_URI_CHANGE = 12; /** Publish trigger type: provisioning changes */ - int PUBLISH_TRIGGER_PROVISIONING_CHANGE = 14; + int PUBLISH_TRIGGER_PROVISIONING_CHANGE = 13; /**The caps have been overridden for a test*/ - int PUBLISH_TRIGGER_OVERRIDE_CAPS = 15; + int PUBLISH_TRIGGER_OVERRIDE_CAPS = 14; /** The Carrier Config for the subscription has Changed **/ - int PUBLISH_TRIGGER_CARRIER_CONFIG_CHANGED = 16; + int PUBLISH_TRIGGER_CARRIER_CONFIG_CHANGED = 15; /** MMTEL and RCS are unregistered. **/ - int PUBLISH_TRIGGER_MMTEL_RCS_UNREGISTERED = 17; + int PUBLISH_TRIGGER_MMTEL_RCS_UNREGISTERED = 16; @IntDef(value = { PUBLISH_TRIGGER_SERVICE, PUBLISH_TRIGGER_RETRY, PUBLISH_TRIGGER_TTY_PREFERRED_CHANGE, - PUBLISH_TRIGGER_AIRPLANE_MODE_CHANGE, PUBLISH_TRIGGER_MOBILE_DATA_CHANGE, PUBLISH_TRIGGER_VT_SETTING_CHANGE, PUBLISH_TRIGGER_MMTEL_REGISTERED, diff --git a/tests/src/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListenerTest.java b/tests/src/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListenerTest.java index f6221720..f3801101 100644 --- a/tests/src/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListenerTest.java +++ b/tests/src/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListenerTest.java @@ -84,7 +84,6 @@ public class DeviceCapabilityListenerTest extends ImsTestBase { getProvisioningManager(anyInt()); doReturn(true).when(mDeviceCapability).updateTtyPreferredMode(anyInt()); - doReturn(true).when(mDeviceCapability).updateAirplaneMode(anyBoolean()); doReturn(true).when(mDeviceCapability).updateMobileData(anyBoolean()); doReturn(true).when(mDeviceCapability).updateVtSetting(anyBoolean()); doReturn(true).when(mDeviceCapability).updateVtSetting(anyBoolean()); @@ -142,23 +141,6 @@ public class DeviceCapabilityListenerTest extends ImsTestBase { PublishController.PUBLISH_TRIGGER_TTY_PREFERRED_CHANGE); } - @Test - @SmallTest - public void testAirplaneModeChange() throws Exception { - DeviceCapabilityListener deviceCapListener = createDeviceCapabilityListener(); - final BroadcastReceiver receiver = deviceCapListener.mReceiver; - - Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED); - receiver.onReceive(mContext, intent); - - Handler handler = deviceCapListener.getHandler(); - waitForHandlerActionDelayed(handler, HANDLER_WAIT_TIMEOUT_MS, HANDLER_SENT_DELAY_MS); - - verify(mDeviceCapability).updateAirplaneMode(anyBoolean()); - verify(mCallback).requestPublishFromInternal( - PublishController.PUBLISH_TRIGGER_AIRPLANE_MODE_CHANGE); - } - @Test @SmallTest public void testMmtelRegistration() throws Exception { -- cgit v1.2.3 From ba955a0c0e3c006a17655825b95e436b7dcb6376 Mon Sep 17 00:00:00 2001 From: Hyunho Date: Fri, 2 Sep 2022 04:10:45 +0000 Subject: If only RCS or MMTEL is unregistered, send a modify PUBLISH request When RCS or MMTEL is unregistered, send a modify PUBLISH request message with delay. And after that, other service will be unregistered. In this case, it sends a unregistered message and removes the existing unprocessed message. Bug: b/235973951 Test: atest DeviceCapabilityListenerTest Change-Id: Ie61f2488a0bad23807f84cb55fcdcb2aae407191 --- .../presence/publish/DeviceCapabilityListener.java | 26 +++++++++--------- .../publish/DeviceCapabilityListenerTest.java | 31 ++++++++++++++++++++++ 2 files changed, 45 insertions(+), 12 deletions(-) diff --git a/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListener.java b/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListener.java index cc5cadb2..0ec30403 100644 --- a/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListener.java +++ b/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListener.java @@ -162,6 +162,8 @@ public class DeviceCapabilityListener { public void sendImsUnregisteredMessage() { logd("sendImsUnregisteredMessage"); + // The IMS has been unregistered. Remove the existing message not processed. + removeMessages(EVENT_REQUEST_PUBLISH); // Remove the existing message and resend a new message. removeMessages(EVENT_IMS_UNREGISTERED); Message msg = obtainMessage(EVENT_IMS_UNREGISTERED); @@ -493,7 +495,7 @@ public class DeviceCapabilityListener { public void onSubscriberAssociatedUriChanged(Uri[] uris) { synchronized (mLock) { logi("onRcsSubscriberAssociatedUriChanged"); - handleRcsSubscriberAssociatedUriChanged(uris, true); + handleRcsSubscriberAssociatedUriChanged(uris); } } }; @@ -524,7 +526,7 @@ public class DeviceCapabilityListener { public void onSubscriberAssociatedUriChanged(Uri[] uris) { synchronized (mLock) { logi("onMmTelSubscriberAssociatedUriChanged"); - handleMmTelSubscriberAssociatedUriChanged(uris, true); + handleMmTelSubscriberAssociatedUriChanged(uris); } } }; @@ -614,7 +616,7 @@ public class DeviceCapabilityListener { private void handleImsMmtelUnregistered() { mCapabilityInfo.updateImsMmtelUnregistered(); // When the MMTEL is unregistered, the mmtel associated uri should be cleared. - handleMmTelSubscriberAssociatedUriChanged(null, false); + handleMmTelSubscriberAssociatedUriChanged(null); // If the RCS is already unregistered, it informs that the IMS is unregistered. if (mCapabilityInfo.isImsRegistered() == false) { @@ -625,16 +627,16 @@ public class DeviceCapabilityListener { /* * This method is called when the MMTEL associated uri has changed. */ - private void handleMmTelSubscriberAssociatedUriChanged(Uri[] uris, boolean triggerPublish) { + private void handleMmTelSubscriberAssociatedUriChanged(Uri[] uris) { Uri originalUri = mCapabilityInfo.getMmtelAssociatedUri(); mCapabilityInfo.updateMmTelAssociatedUri(uris); Uri currentUri = mCapabilityInfo.getMmtelAssociatedUri(); boolean hasChanged = !(Objects.equals(originalUri, currentUri)); - logi("handleMmTelSubscriberAssociatedUriChanged: triggerPublish=" + triggerPublish + - ", hasChanged=" + hasChanged); + logi("handleMmTelSubscriberAssociatedUriChanged: hasChanged=" + hasChanged); - if (triggerPublish && hasChanged) { + // Send internal request to send a modification PUBLISH if the MMTEL or RCS is registered. + if (mCapabilityInfo.isImsRegistered() && hasChanged) { mHandler.sendTriggeringPublishMessage( PublishController.PUBLISH_TRIGGER_MMTEL_URI_CHANGE); } @@ -664,7 +666,7 @@ public class DeviceCapabilityListener { private void handleImsRcsUnregistered() { boolean hasChanged = mCapabilityInfo.updateImsRcsUnregistered(); // When the RCS is unregistered, the rcs associated uri should be cleared. - handleRcsSubscriberAssociatedUriChanged(null, false); + handleRcsSubscriberAssociatedUriChanged(null); // If the MMTEL is already unregistered, it informs that the IMS is unregistered. if (mCapabilityInfo.isImsRegistered() == false) { mHandler.sendImsUnregisteredMessage(); @@ -674,16 +676,16 @@ public class DeviceCapabilityListener { /* * This method is called when the RCS associated uri has changed. */ - private void handleRcsSubscriberAssociatedUriChanged(Uri[] uris, boolean triggerPublish) { + private void handleRcsSubscriberAssociatedUriChanged(Uri[] uris) { Uri originalUri = mCapabilityInfo.getRcsAssociatedUri(); mCapabilityInfo.updateRcsAssociatedUri(uris); Uri currentUri = mCapabilityInfo.getRcsAssociatedUri(); boolean hasChanged = !(Objects.equals(originalUri, currentUri)); - logi("handleRcsSubscriberAssociatedUriChanged: triggerPublish=" + triggerPublish + - ", hasChanged=" + hasChanged); + logi("handleRcsSubscriberAssociatedUriChanged: hasChanged=" + hasChanged); - if (triggerPublish && hasChanged) { + // Send internal request to send a modification PUBLISH if the MMTEL or RCS is registered. + if (mCapabilityInfo.isImsRegistered() && hasChanged) { mHandler.sendTriggeringPublishMessage(PublishController.PUBLISH_TRIGGER_RCS_URI_CHANGE); } } diff --git a/tests/src/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListenerTest.java b/tests/src/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListenerTest.java index f6221720..7bdeb11d 100644 --- a/tests/src/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListenerTest.java +++ b/tests/src/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListenerTest.java @@ -267,6 +267,37 @@ public class DeviceCapabilityListenerTest extends ImsTestBase { verify(mCallback).updateImsUnregistered(); } + @Test + @SmallTest + public void testRcsAndMmtelUnregistration() throws Exception { + DeviceCapabilityListener deviceCapListener = createDeviceCapabilityListener(); + deviceCapListener.setImsCallbackRegistered(true); + + Handler handler = deviceCapListener.getHandler(); + ImsReasonInfo info = new ImsReasonInfo(ImsReasonInfo.CODE_LOCAL_NOT_REGISTERED, -1, ""); + // RCS unregistered + RegistrationCallback rcsRegiCallback = deviceCapListener.mRcsRegistrationCallback; + + doReturn(true).when(mDeviceCapability).updateImsRcsUnregistered(); + // RCS is unregistered but MMTEL is registered. + doReturn(true).when(mDeviceCapability).isImsRegistered(); + rcsRegiCallback.onUnregistered(info); + + // MMTEL unregistered + RegistrationCallback mmtelRegiCallback = deviceCapListener.mMmtelRegistrationCallback; + // set the Ims is unregistered + doReturn(false).when(mDeviceCapability).isImsRegistered(); + mmtelRegiCallback.onUnregistered(info); + + waitForHandlerActionDelayed(handler, HANDLER_WAIT_TIMEOUT_MS, HANDLER_SENT_DELAY_MS); + + // Do not send internal publish trigger + verify(mCallback, never()).requestPublishFromInternal(anyInt()); + // IMS is unregistered. Verify send ImsUnregistered. + verify(mCallback).updateImsUnregistered(); + } + + private DeviceCapabilityListener createDeviceCapabilityListener() { DeviceCapabilityListener deviceCapListener = new DeviceCapabilityListener(mContext, mSubId, mDeviceCapability, mCallback, mUceStatsWriter); -- cgit v1.2.3 From d71f8d1b5f9ae386b0011097ba5e45923462d5d2 Mon Sep 17 00:00:00 2001 From: Orion Hodson Date: Tue, 13 Sep 2022 09:01:56 +0100 Subject: Avoid a few uses of `new Boolean()` Prefer Boolean.{TRUE,FALSE} constants or using Boolean.valueOf(). Bug: N/A Test: Treehugger Change-Id: I29d16c23aca76bb7560a835b7efd0d27ef93798c --- .../android/ims/rcs/uce/presence/publish/PublishControllerImpl.java | 2 +- .../ims/rcs/uce/presence/publish/PublishControllerImplTest.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/java/com/android/ims/rcs/uce/presence/publish/PublishControllerImpl.java b/src/java/com/android/ims/rcs/uce/presence/publish/PublishControllerImpl.java index 034d9ac2..35a5d557 100644 --- a/src/java/com/android/ims/rcs/uce/presence/publish/PublishControllerImpl.java +++ b/src/java/com/android/ims/rcs/uce/presence/publish/PublishControllerImpl.java @@ -303,7 +303,7 @@ public class PublishControllerImpl implements PublishController { boolean supportPublishingState) { synchronized (mPublishStateLock) { if (mIsDestroyedFlag) return; - mPublishStateCallbacks.register(c, new Boolean(supportPublishingState)); + mPublishStateCallbacks.register(c, Boolean.valueOf(supportPublishingState)); logd("registerPublishStateCallback: size=" + mPublishStateCallbacks.getRegisteredCallbackCount()); } diff --git a/tests/src/com/android/ims/rcs/uce/presence/publish/PublishControllerImplTest.java b/tests/src/com/android/ims/rcs/uce/presence/publish/PublishControllerImplTest.java index a7e0bbbe..a6e3d0b8 100644 --- a/tests/src/com/android/ims/rcs/uce/presence/publish/PublishControllerImplTest.java +++ b/tests/src/com/android/ims/rcs/uce/presence/publish/PublishControllerImplTest.java @@ -242,7 +242,7 @@ public class PublishControllerImplTest extends ImsTestBase { @SmallTest public void testPublishingStateTargetingEnable() throws Exception { doReturn(1).when(mPublishStateCallbacks).getRegisteredCallbackCount(); - Boolean boolObj = new Boolean(true); + Boolean boolObj = Boolean.TRUE; Object uid1 = (Object)boolObj; doReturn(uid1).when(mPublishStateCallbacks).getRegisteredCallbackCookie(anyInt()); @@ -282,7 +282,7 @@ public class PublishControllerImplTest extends ImsTestBase { @SmallTest public void testPublishingStateTargetingDisable() throws Exception { doReturn(1).when(mPublishStateCallbacks).getRegisteredCallbackCount(); - Boolean boolObj = new Boolean(false); + Boolean boolObj = Boolean.FALSE; Object uid1 = (Object)boolObj; doReturn(uid1).when(mPublishStateCallbacks).getRegisteredCallbackCookie(anyInt()); -- cgit v1.2.3 From e60edd7244b4c193ecbabaad1c222b603ed19e0a Mon Sep 17 00:00:00 2001 From: Hyunho Date: Fri, 2 Sep 2022 04:10:45 +0000 Subject: If only RCS or MMTEL is unregistered, send a modify PUBLISH request When RCS or MMTEL is unregistered, send a modify PUBLISH request message with delay. And after that, other service will be unregistered. In this case, it sends a unregistered message and removes the existing unprocessed message. Bug: b/235973951 Test: atest DeviceCapabilityListenerTest Change-Id: Ie61f2488a0bad23807f84cb55fcdcb2aae407191 Merged-In: Ie61f2488a0bad23807f84cb55fcdcb2aae407191 --- .../presence/publish/DeviceCapabilityListener.java | 26 +++++++++--------- .../publish/DeviceCapabilityListenerTest.java | 31 ++++++++++++++++++++++ 2 files changed, 45 insertions(+), 12 deletions(-) diff --git a/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListener.java b/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListener.java index 442cf7da..54e227d4 100644 --- a/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListener.java +++ b/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListener.java @@ -162,6 +162,8 @@ public class DeviceCapabilityListener { public void sendImsUnregisteredMessage() { logd("sendImsUnregisteredMessage"); + // The IMS has been unregistered. Remove the existing message not processed. + removeMessages(EVENT_REQUEST_PUBLISH); // Remove the existing message and resend a new message. removeMessages(EVENT_IMS_UNREGISTERED); Message msg = obtainMessage(EVENT_IMS_UNREGISTERED); @@ -492,7 +494,7 @@ public class DeviceCapabilityListener { public void onSubscriberAssociatedUriChanged(Uri[] uris) { synchronized (mLock) { logi("onRcsSubscriberAssociatedUriChanged"); - handleRcsSubscriberAssociatedUriChanged(uris, true); + handleRcsSubscriberAssociatedUriChanged(uris); } } }; @@ -523,7 +525,7 @@ public class DeviceCapabilityListener { public void onSubscriberAssociatedUriChanged(Uri[] uris) { synchronized (mLock) { logi("onMmTelSubscriberAssociatedUriChanged"); - handleMmTelSubscriberAssociatedUriChanged(uris, true); + handleMmTelSubscriberAssociatedUriChanged(uris); } } }; @@ -613,7 +615,7 @@ public class DeviceCapabilityListener { private void handleImsMmtelUnregistered() { mCapabilityInfo.updateImsMmtelUnregistered(); // When the MMTEL is unregistered, the mmtel associated uri should be cleared. - handleMmTelSubscriberAssociatedUriChanged(null, false); + handleMmTelSubscriberAssociatedUriChanged(null); // If the RCS is already unregistered, it informs that the IMS is unregistered. if (mCapabilityInfo.isImsRegistered() == false) { @@ -624,16 +626,16 @@ public class DeviceCapabilityListener { /* * This method is called when the MMTEL associated uri has changed. */ - private void handleMmTelSubscriberAssociatedUriChanged(Uri[] uris, boolean triggerPublish) { + private void handleMmTelSubscriberAssociatedUriChanged(Uri[] uris) { Uri originalUri = mCapabilityInfo.getMmtelAssociatedUri(); mCapabilityInfo.updateMmTelAssociatedUri(uris); Uri currentUri = mCapabilityInfo.getMmtelAssociatedUri(); boolean hasChanged = !(Objects.equals(originalUri, currentUri)); - logi("handleMmTelSubscriberAssociatedUriChanged: triggerPublish=" + triggerPublish + - ", hasChanged=" + hasChanged); + logi("handleMmTelSubscriberAssociatedUriChanged: hasChanged=" + hasChanged); - if (triggerPublish && hasChanged) { + // Send internal request to send a modification PUBLISH if the MMTEL or RCS is registered. + if (mCapabilityInfo.isImsRegistered() && hasChanged) { mHandler.sendTriggeringPublishMessage( PublishController.PUBLISH_TRIGGER_MMTEL_URI_CHANGE); } @@ -663,7 +665,7 @@ public class DeviceCapabilityListener { private void handleImsRcsUnregistered() { boolean hasChanged = mCapabilityInfo.updateImsRcsUnregistered(); // When the RCS is unregistered, the rcs associated uri should be cleared. - handleRcsSubscriberAssociatedUriChanged(null, false); + handleRcsSubscriberAssociatedUriChanged(null); // If the MMTEL is already unregistered, it informs that the IMS is unregistered. if (mCapabilityInfo.isImsRegistered() == false) { mHandler.sendImsUnregisteredMessage(); @@ -673,16 +675,16 @@ public class DeviceCapabilityListener { /* * This method is called when the RCS associated uri has changed. */ - private void handleRcsSubscriberAssociatedUriChanged(Uri[] uris, boolean triggerPublish) { + private void handleRcsSubscriberAssociatedUriChanged(Uri[] uris) { Uri originalUri = mCapabilityInfo.getRcsAssociatedUri(); mCapabilityInfo.updateRcsAssociatedUri(uris); Uri currentUri = mCapabilityInfo.getRcsAssociatedUri(); boolean hasChanged = !(Objects.equals(originalUri, currentUri)); - logi("handleRcsSubscriberAssociatedUriChanged: triggerPublish=" + triggerPublish + - ", hasChanged=" + hasChanged); + logi("handleRcsSubscriberAssociatedUriChanged: hasChanged=" + hasChanged); - if (triggerPublish && hasChanged) { + // Send internal request to send a modification PUBLISH if the MMTEL or RCS is registered. + if (mCapabilityInfo.isImsRegistered() && hasChanged) { mHandler.sendTriggeringPublishMessage(PublishController.PUBLISH_TRIGGER_RCS_URI_CHANGE); } } diff --git a/tests/src/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListenerTest.java b/tests/src/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListenerTest.java index 2d170ab6..3f716888 100644 --- a/tests/src/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListenerTest.java +++ b/tests/src/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListenerTest.java @@ -266,6 +266,37 @@ public class DeviceCapabilityListenerTest extends ImsTestBase { verify(mCallback).updateImsUnregistered(); } + @Test + @SmallTest + public void testRcsAndMmtelUnregistration() throws Exception { + DeviceCapabilityListener deviceCapListener = createDeviceCapabilityListener(); + deviceCapListener.setImsCallbackRegistered(true); + + Handler handler = deviceCapListener.getHandler(); + ImsReasonInfo info = new ImsReasonInfo(ImsReasonInfo.CODE_LOCAL_NOT_REGISTERED, -1, ""); + // RCS unregistered + RegistrationCallback rcsRegiCallback = deviceCapListener.mRcsRegistrationCallback; + + doReturn(true).when(mDeviceCapability).updateImsRcsUnregistered(); + // RCS is unregistered but MMTEL is registered. + doReturn(true).when(mDeviceCapability).isImsRegistered(); + rcsRegiCallback.onUnregistered(info); + + // MMTEL unregistered + RegistrationCallback mmtelRegiCallback = deviceCapListener.mMmtelRegistrationCallback; + // set the Ims is unregistered + doReturn(false).when(mDeviceCapability).isImsRegistered(); + mmtelRegiCallback.onUnregistered(info); + + waitForHandlerActionDelayed(handler, HANDLER_WAIT_TIMEOUT_MS, HANDLER_SENT_DELAY_MS); + + // Do not send internal publish trigger + verify(mCallback, never()).requestPublishFromInternal(anyInt()); + // IMS is unregistered. Verify send ImsUnregistered. + verify(mCallback).updateImsUnregistered(); + } + + private DeviceCapabilityListener createDeviceCapabilityListener() { DeviceCapabilityListener deviceCapListener = new DeviceCapabilityListener(mContext, mSubId, mDeviceCapability, mCallback, mUceStatsWriter); -- cgit v1.2.3 From ba9e9d137831bb336064cfcf203c55e5aa8eba45 Mon Sep 17 00:00:00 2001 From: Hyunho Date: Thu, 29 Sep 2022 03:01:22 +0000 Subject: If the device receive a failure response except 404 for SUBSCRIBE, do not stored the capability as a NON-RCS to the DB. Bug: b/243772320 Test: atest SubscribeCoordinatorTest Test: TMO network. When a 404 response to SUBSCRIBE is received, NON RCS capability is stored in DB. And when capability discovery is requested for the same number, information cached in DB is notified to the caller. Test: TMO netowrk. If a response other than 404 for SUBSCRIBE is received, it informs the caller of NON RCS capability and is not stored in DB. And for the same number, the SUBSCRIBE method is sent to the server during capability discovery. Change-Id: If694e61606820558bceaf3a9a0ec4b6426c43314 --- .../ims/rcs/uce/request/SubscribeRequestCoordinator.java | 4 +++- .../ims/rcs/uce/request/SubscribeCoordinatorTest.java | 13 ++++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/java/com/android/ims/rcs/uce/request/SubscribeRequestCoordinator.java b/src/java/com/android/ims/rcs/uce/request/SubscribeRequestCoordinator.java index f44686ac..2d1736c6 100644 --- a/src/java/com/android/ims/rcs/uce/request/SubscribeRequestCoordinator.java +++ b/src/java/com/android/ims/rcs/uce/request/SubscribeRequestCoordinator.java @@ -297,7 +297,9 @@ public class SubscribeRequestCoordinator extends UceRequestCoordinator { // Trigger capabilities updated callback if there is any. List updatedCapList = response.getUpdatedContactCapability(); if (!updatedCapList.isEmpty()) { - mRequestManagerCallback.saveCapabilities(updatedCapList); + if (response.isNotFound()) { + mRequestManagerCallback.saveCapabilities(updatedCapList); + } triggerCapabilitiesReceivedCallback(updatedCapList); response.removeUpdatedCapabilities(updatedCapList); } diff --git a/tests/src/com/android/ims/rcs/uce/request/SubscribeCoordinatorTest.java b/tests/src/com/android/ims/rcs/uce/request/SubscribeCoordinatorTest.java index bcd3c98d..94ee3edb 100644 --- a/tests/src/com/android/ims/rcs/uce/request/SubscribeCoordinatorTest.java +++ b/tests/src/com/android/ims/rcs/uce/request/SubscribeCoordinatorTest.java @@ -49,6 +49,7 @@ import androidx.test.filters.SmallTest; import com.android.ims.ImsTestBase; import com.android.ims.rcs.uce.UceDeviceState.DeviceStateResult; import com.android.ims.rcs.uce.UceStatsWriter; +import com.android.ims.rcs.uce.eab.EabCapabilityResult; import com.android.ims.rcs.uce.request.UceRequestCoordinator.RequestResult; import com.android.ims.rcs.uce.request.UceRequestManager.RequestManagerCallback; @@ -150,10 +151,20 @@ public class SubscribeCoordinatorTest extends ImsTestBase { SubscribeRequestCoordinator coordinator = getSubscribeCoordinator(); + List eabResultList = new ArrayList<>(); + + Uri contactUri = Uri.fromParts("tel", "123456789", null); + EabCapabilityResult result = new EabCapabilityResult(contactUri, + EabCapabilityResult.EAB_CONTACT_NOT_FOUND_FAILURE, null); + eabResultList.add(result); + + doReturn(eabResultList).when(mRequestMgrCallback). + getCapabilitiesFromCacheIncludingExpired(any()); + coordinator.onRequestUpdated(mTaskId, REQUEST_UPDATE_NETWORK_RESPONSE); verify(mUceStatsWriter).setSubscribeResponse(eq(mSubId), eq(mTaskId), eq(400)); - + verify(mRequestMgrCallback, never()).saveCapabilities(any()); verify(mRequest).onFinish(); } -- cgit v1.2.3 From 718ebc1819a21275a36a7d8e703e6911167cd7a2 Mon Sep 17 00:00:00 2001 From: Cole Faust Date: Sat, 15 Oct 2022 21:33:31 -0700 Subject: Fix errorprone warnings that should be errors This commit is part of a large scale change to fix errorprone errors that have been downgraded to warnings in the android source tree, so that they can be promoted to errors again. The full list of changes include the following, but not all will be present in any one individual commit: BadAnnotationImplementation BadShiftAmount BanJNDI BoxedPrimitiveEquality ComparableType ComplexBooleanConstant CollectionToArraySafeParameter ConditionalExpressionNumericPromotion DangerousLiteralNull DoubleBraceInitialization DurationFrom DurationTemporalUnit EmptyTopLevelDeclaration EqualsNull EqualsReference FormatString FromTemporalAccessor GetClassOnAnnotation GetClassOnClass HashtableContains IdentityBinaryExpression IdentityHashMapBoxing InstantTemporalUnit InvalidTimeZoneID InvalidZoneId IsInstanceIncompatibleType JUnitParameterMethodNotFound LockOnBoxedPrimitive MathRoundIntLong MislabeledAndroidString MisusedDayOfYear MissingSuperCall MisusedWeekYear ModifyingCollectionWithItself NoCanIgnoreReturnValueOnClasses NonRuntimeAnnotation NullableOnContainingClass NullTernary OverridesJavaxInjectableMethod ParcelableCreator PeriodFrom PreconditionsInvalidPlaceholder ProtoBuilderReturnValueIgnored ProtoFieldNullComparison RandomModInteger RectIntersectReturnValueIgnored ReturnValueIgnored SelfAssignment SelfComparison SelfEquals SizeGreaterThanOrEqualsZero StringBuilderInitWithChar TreeToString TryFailThrowable UnnecessaryCheckNotNull UnusedCollectionModifiedInPlace XorPower See https://errorprone.info/bugpatterns for more information on the checks. Bug: 253827323 Test: m RUN_ERROR_PRONE=true javac-check Change-Id: If4a2eda08cc384881dda4b7d7bace425f3b3c807 --- src/java/com/android/ims/ImsUt.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/java/com/android/ims/ImsUt.java b/src/java/com/android/ims/ImsUt.java index d02ffaa5..17e34154 100644 --- a/src/java/com/android/ims/ImsUt.java +++ b/src/java/com/android/ims/ImsUt.java @@ -382,9 +382,9 @@ public class ImsUt implements ImsUtInterface { String[] barrList, int serviceClass, String password) { if (DBG) { if (barrList != null) { - String bList = new String(); + String bList = ""; for (int i = 0; i < barrList.length; i++) { - bList.concat(barrList[i] + " "); + bList += barrList[i] + " "; } log("updateCallBarring :: Ut=" + miUt + ", cbType=" + cbType + ", action=" + action + ", serviceClass=" + serviceClass -- cgit v1.2.3 From de8e8c98463a5c1892970f20d4612a0bb7754ba0 Mon Sep 17 00:00:00 2001 From: Hyunho Date: Tue, 30 Aug 2022 11:56:49 +0000 Subject: Remove airplane mode handling code. In VZW TC 3.18, the device did not need to send a PUBLISH when a 412 response was received for a UN PUBLISH request. Turn on airplane mode for testing. As a result, the device sends a UN PUBLISH request. However, since airplane mode has changed, the Framework sends a PUBLISH request to the ImsService. So this case failed. Bug: b/243137045 Test: Turn on airplane mode > deice sends a UN PUBLISH request > Not handle airplane mode change event in the publish controller. Test: atest DeviceCapabilityListenerTest Change-Id: Id96bd4a233e9208865afaa9c3fe0cccb239bad93 Merged-In: Id96bd4a233e9208865afaa9c3fe0cccb239bad93 (cherry picked from commit b4a75a44ff977b0e9bfb215cdde502901ca36d6c) --- .../uce/presence/publish/DeviceCapabilityInfo.java | 15 ----------- .../presence/publish/DeviceCapabilityListener.java | 15 ----------- .../uce/presence/publish/PublishController.java | 30 ++++++++++------------ .../publish/DeviceCapabilityListenerTest.java | 18 ------------- 4 files changed, 13 insertions(+), 65 deletions(-) diff --git a/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityInfo.java b/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityInfo.java index dc794331..bc3b07ec 100644 --- a/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityInfo.java +++ b/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityInfo.java @@ -101,7 +101,6 @@ public class DeviceCapabilityInfo { // Whether the settings are changed or not private int mTtyPreferredMode; - private boolean mAirplaneMode; private boolean mMobileData; private boolean mVtSetting; @@ -121,7 +120,6 @@ public class DeviceCapabilityInfo { mRcsRegistered = false; mRcsNetworkRegType = AccessNetworkConstants.TRANSPORT_TYPE_INVALID; mTtyPreferredMode = TelecomManager.TTY_MODE_OFF; - mAirplaneMode = false; mMobileData = true; mVtSetting = true; mMmTelCapabilities = new MmTelCapabilities(); @@ -372,19 +370,6 @@ public class DeviceCapabilityInfo { return false; } - /** - * Update airplane mode state. - * @return {@code true} if the airplane mode is changed, {@code false} otherwise. - */ - public synchronized boolean updateAirplaneMode(boolean state) { - if (mAirplaneMode != state) { - logd("Airplane mode changes from " + mAirplaneMode + " to " + state); - mAirplaneMode = state; - return true; - } - return false; - } - /** * Update mobile data setting. * @return {@code true} if the mobile data setting is changed, {@code false} otherwise. diff --git a/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListener.java b/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListener.java index cc5cadb2..9070c6f2 100644 --- a/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListener.java +++ b/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListener.java @@ -272,7 +272,6 @@ public class DeviceCapabilityListener { private void registerReceivers() { logd("registerReceivers"); IntentFilter filter = new IntentFilter(); - filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED); filter.addAction(TelecomManager.ACTION_TTY_PREFERRED_MODE_CHANGED); mContext.registerReceiver(mReceiver, filter, android.Manifest.permission.MODIFY_PHONE_STATE, null); @@ -390,11 +389,6 @@ public class DeviceCapabilityListener { TelecomManager.TTY_MODE_OFF); handleTtyPreferredModeChanged(preferredMode); break; - - case Intent.ACTION_AIRPLANE_MODE_CHANGED: - boolean airplaneMode = intent.getBooleanExtra("state", false); - handleAirplaneModeChanged(airplaneMode); - break; } } }; @@ -572,15 +566,6 @@ public class DeviceCapabilityListener { } } - private void handleAirplaneModeChanged(boolean state) { - boolean isChanged = mCapabilityInfo.updateAirplaneMode(state); - logi("Airplane mode changed: " + state + ", isChanged="+ isChanged); - if (isChanged) { - mHandler.sendTriggeringPublishMessage( - PublishController.PUBLISH_TRIGGER_AIRPLANE_MODE_CHANGE); - } - } - private void handleMobileDataChanged(boolean isEnabled) { boolean isChanged = mCapabilityInfo.updateMobileData(isEnabled); logi("Mobile data changed: " + isEnabled + ", isChanged=" + isChanged); diff --git a/src/java/com/android/ims/rcs/uce/presence/publish/PublishController.java b/src/java/com/android/ims/rcs/uce/presence/publish/PublishController.java index b20f5ceb..a3d31b9e 100644 --- a/src/java/com/android/ims/rcs/uce/presence/publish/PublishController.java +++ b/src/java/com/android/ims/rcs/uce/presence/publish/PublishController.java @@ -45,53 +45,49 @@ public interface PublishController extends ControllerBase { /** Publish trigger type: TTY preferred changes */ int PUBLISH_TRIGGER_TTY_PREFERRED_CHANGE = 3; - /** Publish trigger type: Airplane mode changes */ - int PUBLISH_TRIGGER_AIRPLANE_MODE_CHANGE = 4; - /** Publish trigger type: Mobile data changes */ - int PUBLISH_TRIGGER_MOBILE_DATA_CHANGE = 5; + int PUBLISH_TRIGGER_MOBILE_DATA_CHANGE = 4; /** Publish trigger type: VT setting changes */ - int PUBLISH_TRIGGER_VT_SETTING_CHANGE = 6; + int PUBLISH_TRIGGER_VT_SETTING_CHANGE = 5; /** Publish trigger type: MMTEL registered */ - int PUBLISH_TRIGGER_MMTEL_REGISTERED = 7; + int PUBLISH_TRIGGER_MMTEL_REGISTERED = 6; /** Publish trigger type: MMTEL unregistered */ - int PUBLISH_TRIGGER_MMTEL_UNREGISTERED = 8; + int PUBLISH_TRIGGER_MMTEL_UNREGISTERED = 7; /** Publish trigger type: MMTEL capability changes */ - int PUBLISH_TRIGGER_MMTEL_CAPABILITY_CHANGE = 9; + int PUBLISH_TRIGGER_MMTEL_CAPABILITY_CHANGE = 8; /** Publish trigger type: MMTEL associated uri changes */ - int PUBLISH_TRIGGER_MMTEL_URI_CHANGE = 10; + int PUBLISH_TRIGGER_MMTEL_URI_CHANGE = 9; /** Publish trigger type: RCS registered */ - int PUBLISH_TRIGGER_RCS_REGISTERED = 11; + int PUBLISH_TRIGGER_RCS_REGISTERED = 10; /** Publish trigger type: RCS unregistered */ - int PUBLISH_TRIGGER_RCS_UNREGISTERED = 12; + int PUBLISH_TRIGGER_RCS_UNREGISTERED = 11; /** Publish trigger type: RCS associated uri changes */ - int PUBLISH_TRIGGER_RCS_URI_CHANGE = 13; + int PUBLISH_TRIGGER_RCS_URI_CHANGE = 12; /** Publish trigger type: provisioning changes */ - int PUBLISH_TRIGGER_PROVISIONING_CHANGE = 14; + int PUBLISH_TRIGGER_PROVISIONING_CHANGE = 13; /**The caps have been overridden for a test*/ - int PUBLISH_TRIGGER_OVERRIDE_CAPS = 15; + int PUBLISH_TRIGGER_OVERRIDE_CAPS = 14; /** The Carrier Config for the subscription has Changed **/ - int PUBLISH_TRIGGER_CARRIER_CONFIG_CHANGED = 16; + int PUBLISH_TRIGGER_CARRIER_CONFIG_CHANGED = 15; /** MMTEL and RCS are unregistered. **/ - int PUBLISH_TRIGGER_MMTEL_RCS_UNREGISTERED = 17; + int PUBLISH_TRIGGER_MMTEL_RCS_UNREGISTERED = 16; @IntDef(value = { PUBLISH_TRIGGER_SERVICE, PUBLISH_TRIGGER_RETRY, PUBLISH_TRIGGER_TTY_PREFERRED_CHANGE, - PUBLISH_TRIGGER_AIRPLANE_MODE_CHANGE, PUBLISH_TRIGGER_MOBILE_DATA_CHANGE, PUBLISH_TRIGGER_VT_SETTING_CHANGE, PUBLISH_TRIGGER_MMTEL_REGISTERED, diff --git a/tests/src/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListenerTest.java b/tests/src/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListenerTest.java index f6221720..f3801101 100644 --- a/tests/src/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListenerTest.java +++ b/tests/src/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListenerTest.java @@ -84,7 +84,6 @@ public class DeviceCapabilityListenerTest extends ImsTestBase { getProvisioningManager(anyInt()); doReturn(true).when(mDeviceCapability).updateTtyPreferredMode(anyInt()); - doReturn(true).when(mDeviceCapability).updateAirplaneMode(anyBoolean()); doReturn(true).when(mDeviceCapability).updateMobileData(anyBoolean()); doReturn(true).when(mDeviceCapability).updateVtSetting(anyBoolean()); doReturn(true).when(mDeviceCapability).updateVtSetting(anyBoolean()); @@ -142,23 +141,6 @@ public class DeviceCapabilityListenerTest extends ImsTestBase { PublishController.PUBLISH_TRIGGER_TTY_PREFERRED_CHANGE); } - @Test - @SmallTest - public void testAirplaneModeChange() throws Exception { - DeviceCapabilityListener deviceCapListener = createDeviceCapabilityListener(); - final BroadcastReceiver receiver = deviceCapListener.mReceiver; - - Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED); - receiver.onReceive(mContext, intent); - - Handler handler = deviceCapListener.getHandler(); - waitForHandlerActionDelayed(handler, HANDLER_WAIT_TIMEOUT_MS, HANDLER_SENT_DELAY_MS); - - verify(mDeviceCapability).updateAirplaneMode(anyBoolean()); - verify(mCallback).requestPublishFromInternal( - PublishController.PUBLISH_TRIGGER_AIRPLANE_MODE_CHANGE); - } - @Test @SmallTest public void testMmtelRegistration() throws Exception { -- cgit v1.2.3 From 31437bdf4224bb14d9cbafadfe0df5c06b669360 Mon Sep 17 00:00:00 2001 From: Hunsuk Choi Date: Tue, 8 Feb 2022 06:11:13 +0000 Subject: Implement apis to support SRVCC Bug: 217654931 Test: atest Change-Id: I078f7ceee35a31d198f6b881d3fe2e090b33fdea (cherry picked from commit 0cc9bbcbe1ef7bf42fb3e749a3c4ab9c1558a879) --- src/java/com/android/ims/ImsManager.java | 56 ++++++++++++++++++++++ .../com/android/ims/MmTelFeatureConnection.java | 30 ++++++++++++ 2 files changed, 86 insertions(+) diff --git a/src/java/com/android/ims/ImsManager.java b/src/java/com/android/ims/ImsManager.java index 18bbd3e1..f016ff63 100644 --- a/src/java/com/android/ims/ImsManager.java +++ b/src/java/com/android/ims/ImsManager.java @@ -52,6 +52,7 @@ import android.telephony.ims.ImsService; import android.telephony.ims.ProvisioningManager; import android.telephony.ims.RegistrationManager; import android.telephony.ims.RtpHeaderExtensionType; +import android.telephony.ims.SrvccCall; import android.telephony.ims.aidl.IImsCapabilityCallback; import android.telephony.ims.aidl.IImsConfig; import android.telephony.ims.aidl.IImsConfigCallback; @@ -60,6 +61,7 @@ import android.telephony.ims.aidl.IImsRegistration; import android.telephony.ims.aidl.IImsRegistrationCallback; import android.telephony.ims.aidl.IImsSmsListener; import android.telephony.ims.aidl.ISipTransport; +import android.telephony.ims.aidl.ISrvccStartedCallback; import android.telephony.ims.feature.CapabilityChangeRequest; import android.telephony.ims.feature.ImsFeature; import android.telephony.ims.feature.MmTelFeature; @@ -2727,6 +2729,60 @@ public class ImsManager implements FeatureUpdates { } } + /** + * Notifies SRVCC started. + * @param cb The callback to receive the list of {@link SrvccCall}. + */ + public void notifySrvccStarted(ISrvccStartedCallback cb) + throws ImsException { + MmTelFeatureConnection c = getOrThrowExceptionIfServiceUnavailable(); + try { + c.notifySrvccStarted(cb); + } catch (RemoteException e) { + throw new ImsException("notifySrvccStarted", e, + ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); + } + } + + /** + * Notifies SRVCC is completed, IMS service will hang up all calls. + */ + public void notifySrvccCompleted() throws ImsException { + MmTelFeatureConnection c = getOrThrowExceptionIfServiceUnavailable(); + try { + c.notifySrvccCompleted(); + } catch (RemoteException e) { + throw new ImsException("notifySrvccCompleted", e, + ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); + } + } + + /** + * Notifies SRVCC failed. IMS service will recover and continue calls over IMS. + */ + public void notifySrvccFailed() throws ImsException { + MmTelFeatureConnection c = getOrThrowExceptionIfServiceUnavailable(); + try { + c.notifySrvccFailed(); + } catch (RemoteException e) { + throw new ImsException("notifySrvccFailed", e, + ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); + } + } + + /** + * Notifies SRVCC is canceled. IMS service will recover and continue calls over IMS. + */ + public void notifySrvccCanceled() throws ImsException { + MmTelFeatureConnection c = getOrThrowExceptionIfServiceUnavailable(); + try { + c.notifySrvccCanceled(); + } catch (RemoteException e) { + throw new ImsException("notifySrvccCanceled", e, + ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); + } + } + public int getImsServiceState() throws ImsException { MmTelFeatureConnection c = getOrThrowExceptionIfServiceUnavailable(); return c.getFeatureState(); diff --git a/src/java/com/android/ims/MmTelFeatureConnection.java b/src/java/com/android/ims/MmTelFeatureConnection.java index 5ea5e420..8bafc9db 100644 --- a/src/java/com/android/ims/MmTelFeatureConnection.java +++ b/src/java/com/android/ims/MmTelFeatureConnection.java @@ -33,6 +33,7 @@ import android.telephony.ims.aidl.IImsRegistration; import android.telephony.ims.aidl.IImsRegistrationCallback; import android.telephony.ims.aidl.IImsSmsListener; import android.telephony.ims.aidl.ISipTransport; +import android.telephony.ims.aidl.ISrvccStartedCallback; import android.telephony.ims.feature.CapabilityChangeRequest; import android.telephony.ims.feature.MmTelFeature; import android.telephony.ims.stub.ImsEcbmImplBase; @@ -541,6 +542,35 @@ public class MmTelFeatureConnection extends FeatureConnection { } } + public void notifySrvccStarted(ISrvccStartedCallback cb) + throws RemoteException { + synchronized (mLock) { + checkServiceIsReady(); + getServiceInterface(mBinder).notifySrvccStarted(cb); + } + } + + public void notifySrvccCompleted() throws RemoteException { + synchronized (mLock) { + checkServiceIsReady(); + getServiceInterface(mBinder).notifySrvccCompleted(); + } + } + + public void notifySrvccFailed() throws RemoteException { + synchronized (mLock) { + checkServiceIsReady(); + getServiceInterface(mBinder).notifySrvccFailed(); + } + } + + public void notifySrvccCanceled() throws RemoteException { + synchronized (mLock) { + checkServiceIsReady(); + getServiceInterface(mBinder).notifySrvccCanceled(); + } + } + public @MmTelFeature.ProcessCallResult int shouldProcessCall(boolean isEmergency, String[] numbers) throws RemoteException { if (isEmergency && !isEmergencyMmTelAvailable()) { -- cgit v1.2.3 From e991e710acf71cc9b115b7269321b4745383ff06 Mon Sep 17 00:00:00 2001 From: Hunsuk Choi Date: Wed, 15 Dec 2021 09:19:52 +0000 Subject: Implement the API to notify that radio triggered IMS deregistration Bug: 219242993 Test: atest Change-Id: I536fe9fb94124d4f82b818557992aab6c4b60cba --- src/java/com/android/ims/ImsManager.java | 15 +++++++++++++++ src/java/com/android/ims/MmTelFeatureConnection.java | 11 +++++++++++ 2 files changed, 26 insertions(+) diff --git a/src/java/com/android/ims/ImsManager.java b/src/java/com/android/ims/ImsManager.java index f016ff63..a2829e0c 100644 --- a/src/java/com/android/ims/ImsManager.java +++ b/src/java/com/android/ims/ImsManager.java @@ -2783,6 +2783,21 @@ public class ImsManager implements FeatureUpdates { } } + /** + * Notifies that radio triggered IMS deregistration. + * @param reason the reason why the deregistration is triggered. + */ + public void triggerDeregistration(@ImsRegistrationImplBase.ImsDeregistrationReason int reason) + throws ImsException { + MmTelFeatureConnection c = getOrThrowExceptionIfServiceUnavailable(); + try { + c.triggerDeregistration(reason); + } catch (RemoteException e) { + throw new ImsException("triggerDeregistration", e, + ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); + } + } + public int getImsServiceState() throws ImsException { MmTelFeatureConnection c = getOrThrowExceptionIfServiceUnavailable(); return c.getFeatureState(); diff --git a/src/java/com/android/ims/MmTelFeatureConnection.java b/src/java/com/android/ims/MmTelFeatureConnection.java index 8bafc9db..fefffa7d 100644 --- a/src/java/com/android/ims/MmTelFeatureConnection.java +++ b/src/java/com/android/ims/MmTelFeatureConnection.java @@ -37,6 +37,7 @@ import android.telephony.ims.aidl.ISrvccStartedCallback; import android.telephony.ims.feature.CapabilityChangeRequest; import android.telephony.ims.feature.MmTelFeature; import android.telephony.ims.stub.ImsEcbmImplBase; +import android.telephony.ims.stub.ImsRegistrationImplBase; import android.telephony.ims.stub.ImsSmsImplBase; import android.util.Log; @@ -571,6 +572,16 @@ public class MmTelFeatureConnection extends FeatureConnection { } } + public void triggerDeregistration(@ImsRegistrationImplBase.ImsDeregistrationReason int reason) + throws RemoteException { + IImsRegistration registration = getRegistration(); + if (registration != null) { + registration.triggerDeregistration(reason); + } else { + Log.e(TAG + " [" + mSlotId + "]", "triggerDeregistration IImsRegistration is null"); + } + } + public @MmTelFeature.ProcessCallResult int shouldProcessCall(boolean isEmergency, String[] numbers) throws RemoteException { if (isEmergency && !isEmergencyMmTelAvailable()) { -- cgit v1.2.3 From fa045d3ccd4034b9cfb415295e3b8bfbc5a89498 Mon Sep 17 00:00:00 2001 From: Saifuddin Date: Fri, 21 Oct 2022 09:27:33 +0000 Subject: Acknowledge IMS with TPDU with the received Data Coding Scheme, Protocol Identifier and response bytes. Test: manual(receive class2 SMS) Change-Id: I38f08948196b9305222ff4cbf4d2b6c3f93ee231 --- src/java/com/android/ims/ImsManager.java | 9 +++++++++ src/java/com/android/ims/MmTelFeatureConnection.java | 8 ++++++++ 2 files changed, 17 insertions(+) diff --git a/src/java/com/android/ims/ImsManager.java b/src/java/com/android/ims/ImsManager.java index 18bbd3e1..65cd08e3 100644 --- a/src/java/com/android/ims/ImsManager.java +++ b/src/java/com/android/ims/ImsManager.java @@ -3022,6 +3022,15 @@ public class ImsManager implements FeatureUpdates { } } + public void acknowledgeSms(int token, int messageRef, int result, byte[] pdu) throws ImsException { + try { + mMmTelConnectionRef.get().acknowledgeSms(token, messageRef, result, pdu); + } catch (RemoteException e) { + throw new ImsException("acknowledgeSms()", e, + ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); + } + } + public void acknowledgeSmsReport(int token, int messageRef, int result) throws ImsException{ try { mMmTelConnectionRef.get().acknowledgeSmsReport(token, messageRef, result); diff --git a/src/java/com/android/ims/MmTelFeatureConnection.java b/src/java/com/android/ims/MmTelFeatureConnection.java index 5ea5e420..1bbd191b 100644 --- a/src/java/com/android/ims/MmTelFeatureConnection.java +++ b/src/java/com/android/ims/MmTelFeatureConnection.java @@ -512,6 +512,14 @@ public class MmTelFeatureConnection extends FeatureConnection { } } + public void acknowledgeSms(int token, int messageRef, + @ImsSmsImplBase.SendStatusResult int result, byte[] pdu) throws RemoteException { + synchronized (mLock) { + checkServiceIsReady(); + getServiceInterface(mBinder).acknowledgeSmsWithPdu(token, messageRef, result, pdu); + } + } + public void acknowledgeSmsReport(int token, int messageRef, @ImsSmsImplBase.StatusReportResult int result) throws RemoteException { synchronized (mLock) { -- cgit v1.2.3 From 701c7fb74fd922f1c59322bbd87c041118faa3ea Mon Sep 17 00:00:00 2001 From: Megha Patil Date: Mon, 17 Oct 2022 11:17:01 +0000 Subject: Unit Testing For RP-SMMA Implementation in ImsManager - Added testcase for onMemoryAvailable api in ImsManager - Bug: b/240883268 Test: atest ImsMangerTest Change-Id: Ifca76a46f098828f4ee7c33c4ce76b4f8661e77f --- tests/src/com/android/ims/ImsManagerTest.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/src/com/android/ims/ImsManagerTest.java b/tests/src/com/android/ims/ImsManagerTest.java index 0653908d..2c0fd870 100644 --- a/tests/src/com/android/ims/ImsManagerTest.java +++ b/tests/src/com/android/ims/ImsManagerTest.java @@ -1012,6 +1012,14 @@ public class ImsManagerTest extends ImsTestBase { } + @Test @SmallTest + public void onMemoryAvailableTest() throws Exception{ + ImsManager imsManager = getImsManagerAndInitProvisionedValues(); + int token = 1; + imsManager.onMemoryAvailable(token); + verify(mMmTelFeatureConnection).onMemoryAvailable(eq(token)); + } + private ImsManager getImsManagerAndInitProvisionedValues() { when(mImsConfigImplBaseMock.getConfigInt(anyInt())) .thenAnswer(invocation -> { -- cgit v1.2.3 From adc4b9d39cba9c3e87a5f015f4d36d1e894e4e3d Mon Sep 17 00:00:00 2001 From: Megha Patil Date: Fri, 30 Sep 2022 08:20:42 +0000 Subject: Send Sms Memory Availability notification to ImsService - Send Memory Availability notification to Ims SMS Service - Add onMemoryAvailable Api in ImsManager - Bug: b/240883268 Test: Tested Memory full and available conditions in Pixel6 Change-Id: I580ead22037b1cbb7f3bb4e570fd1b891bb97016 --- src/java/com/android/ims/ImsManager.java | 9 +++++++++ src/java/com/android/ims/MmTelFeatureConnection.java | 7 +++++++ 2 files changed, 16 insertions(+) diff --git a/src/java/com/android/ims/ImsManager.java b/src/java/com/android/ims/ImsManager.java index 15f34d8e..dccb9b3b 100644 --- a/src/java/com/android/ims/ImsManager.java +++ b/src/java/com/android/ims/ImsManager.java @@ -3069,6 +3069,15 @@ public class ImsManager implements FeatureUpdates { } } + public void onMemoryAvailable(int token) throws ImsException { + try { + mMmTelConnectionRef.get().onMemoryAvailable(token); + } catch (RemoteException e) { + throw new ImsException("onMemoryAvailable()", e, + ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN); + } + } + public void acknowledgeSms(int token, int messageRef, int result) throws ImsException { try { mMmTelConnectionRef.get().acknowledgeSms(token, messageRef, result); diff --git a/src/java/com/android/ims/MmTelFeatureConnection.java b/src/java/com/android/ims/MmTelFeatureConnection.java index 3fc3e4f6..3eeb8aa9 100644 --- a/src/java/com/android/ims/MmTelFeatureConnection.java +++ b/src/java/com/android/ims/MmTelFeatureConnection.java @@ -505,6 +505,13 @@ public class MmTelFeatureConnection extends FeatureConnection { } } + public void onMemoryAvailable(int token) throws RemoteException { + synchronized (mLock) { + checkServiceIsReady(); + getServiceInterface(mBinder).onMemoryAvailable(token); + } + } + public void acknowledgeSms(int token, int messageRef, @ImsSmsImplBase.SendStatusResult int result) throws RemoteException { synchronized (mLock) { -- cgit v1.2.3 From 70d82344eb703f146c14e99346b915a7cddfb3e2 Mon Sep 17 00:00:00 2001 From: Sewook Seo Date: Tue, 8 Nov 2022 04:59:31 +0000 Subject: Media quality CB: Telephony FWK implementation ImsManager & MmTelFeatureConnection modification to pass IImsMediaQaulityStatusCallback & MediaThreshold to register callback to ImsService with regarding Threshold values. Bug: 242934908 Test: system build, device test b/259482963 Change-Id: I7ccfec15a878223238fa33f8add8b1103236e91a --- src/java/com/android/ims/ImsManager.java | 23 ++++++++++++++++++++++ .../com/android/ims/MmTelFeatureConnection.java | 23 ++++++++++++++++++++-- 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/src/java/com/android/ims/ImsManager.java b/src/java/com/android/ims/ImsManager.java index 15f34d8e..637e1ac1 100644 --- a/src/java/com/android/ims/ImsManager.java +++ b/src/java/com/android/ims/ImsManager.java @@ -49,6 +49,8 @@ import android.telephony.ims.ImsCallSession; import android.telephony.ims.ImsMmTelManager; import android.telephony.ims.ImsReasonInfo; import android.telephony.ims.ImsService; +import android.telephony.ims.MediaQualityStatus; +import android.telephony.ims.MediaThreshold; import android.telephony.ims.ProvisioningManager; import android.telephony.ims.RegistrationManager; import android.telephony.ims.RtpHeaderExtensionType; @@ -2788,6 +2790,27 @@ public class ImsManager implements FeatureUpdates { return c.getFeatureState(); } + public void setMediaThreshold(@MediaQualityStatus.MediaSessionType int sessionType, + MediaThreshold threshold) throws ImsException { + MmTelFeatureConnection c = getOrThrowExceptionIfServiceUnavailable(); + try { + c.setMediaThreshold(sessionType, threshold); + } catch (RemoteException e) { + loge("setMediaThreshold Failed."); + } + } + + public MediaQualityStatus queryMediaQualityStatus ( + @MediaQualityStatus.MediaSessionType int sessionType) throws ImsException { + MmTelFeatureConnection c = getOrThrowExceptionIfServiceUnavailable(); + try { + return c.queryMediaQualityStatus(sessionType); + } catch (RemoteException e) { + loge("queryMediaQualityStatus Failed."); + return null; + } + } + @Override public void updateFeatureState(int state) { mMmTelConnectionRef.get().updateFeatureState(state); diff --git a/src/java/com/android/ims/MmTelFeatureConnection.java b/src/java/com/android/ims/MmTelFeatureConnection.java index 3fc3e4f6..7fc3d76c 100644 --- a/src/java/com/android/ims/MmTelFeatureConnection.java +++ b/src/java/com/android/ims/MmTelFeatureConnection.java @@ -22,8 +22,11 @@ import android.os.IBinder; import android.os.IInterface; import android.os.Message; import android.os.RemoteException; +import android.telephony.SubscriptionManager; import android.telephony.ims.ImsCallProfile; import android.telephony.ims.ImsService; +import android.telephony.ims.MediaQualityStatus; +import android.telephony.ims.MediaThreshold; import android.telephony.ims.RtpHeaderExtensionType; import android.telephony.ims.aidl.IImsCapabilityCallback; import android.telephony.ims.aidl.IImsConfig; @@ -39,6 +42,7 @@ import android.telephony.ims.feature.MmTelFeature; import android.telephony.ims.stub.ImsEcbmImplBase; import android.telephony.ims.stub.ImsSmsImplBase; import android.util.Log; +import android.util.SparseArray; import com.android.ims.internal.IImsCallSession; import com.android.ims.internal.IImsEcbm; @@ -46,7 +50,7 @@ import com.android.ims.internal.IImsMultiEndpoint; import com.android.ims.internal.IImsUt; import java.util.ArrayList; -import java.util.Optional; +import java.util.HashMap; import java.util.Set; /** @@ -101,7 +105,6 @@ public class MmTelFeatureConnection extends FeatureConnection { } private class CapabilityCallbackManager extends ImsCallbackAdapterManager { - public CapabilityCallbackManager(Context context, Object lock) { super(context, lock, mSlotId, mSubId); } @@ -377,6 +380,22 @@ public class MmTelFeatureConnection extends FeatureConnection { mProvisioningCallbackManager.removeCallback(callback); } + public void setMediaThreshold(@MediaQualityStatus.MediaSessionType int sessionType, + MediaThreshold threshold) throws RemoteException { + synchronized (mLock) { + checkServiceIsReady(); + getServiceInterface(mBinder).setMediaQualityThreshold(sessionType, threshold); + } + } + + public MediaQualityStatus queryMediaQualityStatus( + @MediaQualityStatus.MediaSessionType int sessionType) throws RemoteException { + synchronized (mLock) { + checkServiceIsReady(); + return getServiceInterface(mBinder).queryMediaQualityStatus(sessionType); + } + } + public void changeEnabledCapabilities(CapabilityChangeRequest request, IImsCapabilityCallback callback) throws RemoteException { synchronized (mLock) { -- cgit v1.2.3 From 31f3630abbcb1118e616906523d6adcd5c76773b Mon Sep 17 00:00:00 2001 From: Hyunho Date: Tue, 25 Oct 2022 06:40:14 +0000 Subject: Create a PublishAttributes class that tells the result of a publish request, including sip debug information. In order to more debug issues during the publication, the caller should have access to specfic SIP signaling information. To access SIP information, using the created SipDetails class and set it as a variable in PublishAttributes class. And the existing interface change to set the SipDetails class as a parameter. Bug: b/238192081 Test: cts CtsTelephonyTestCases:ImsServiceTest Test: atest DeviceCapabilityInfoTest PublishControllerImplTest PublishProcessorTest Change-Id: Ic338f44b7180cc678c5f12b51938edd0af083f0e --- src/java/com/android/ims/RcsFeatureManager.java | 13 ++-- .../com/android/ims/rcs/uce/UceController.java | 43 ++++------- .../uce/presence/publish/DeviceCapabilityInfo.java | 13 ++++ .../uce/presence/publish/PublishController.java | 9 ++- .../presence/publish/PublishControllerImpl.java | 87 +++++++++++++--------- .../rcs/uce/presence/publish/PublishProcessor.java | 5 +- .../presence/publish/PublishRequestResponse.java | 80 ++++++++------------ .../presence/publish/DeviceCapabilityInfoTest.java | 50 ++++++++++++- .../publish/PublishControllerImplTest.java | 61 ++++++++++++++- .../uce/presence/publish/PublishProcessorTest.java | 24 +++++- 10 files changed, 252 insertions(+), 133 deletions(-) diff --git a/src/java/com/android/ims/RcsFeatureManager.java b/src/java/com/android/ims/RcsFeatureManager.java index ce5422b3..e3f50c34 100644 --- a/src/java/com/android/ims/RcsFeatureManager.java +++ b/src/java/com/android/ims/RcsFeatureManager.java @@ -16,6 +16,8 @@ package com.android.ims; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.content.Context; import android.net.Uri; import android.os.IBinder; @@ -30,6 +32,7 @@ import android.telephony.ims.ImsException; import android.telephony.ims.ImsService; import android.telephony.ims.RcsUceAdapter.StackPublishTriggerType; import android.telephony.ims.RegistrationManager; +import android.telephony.ims.SipDetails; import android.telephony.ims.aidl.ICapabilityExchangeEventListener; import android.telephony.ims.aidl.IImsCapabilityCallback; import android.telephony.ims.aidl.IImsConfig; @@ -95,8 +98,7 @@ public class RcsFeatureManager implements FeatureUpdates { * This method must be called to notify the framework of SUCCESS (200 OK) and FAILURE (300+) * codes in order to keep the AOSP stack up to date. */ - void onPublishUpdated(int reasonCode, String reasonPhrase, - int reasonHeaderCause, String reasonHeaderText); + void onPublishUpdated(SipDetails details); /** * Receive a capabilities request from the remote client. @@ -122,10 +124,9 @@ public class RcsFeatureManager implements FeatureUpdates { } @Override - public void onPublishUpdated(int reasonCode, String reasonPhrase, - int reasonHeaderCause, String reasonHeaderText) { - mCapabilityEventCallback.forEach(callback -> callback.onPublishUpdated( - reasonCode, reasonPhrase, reasonHeaderCause, reasonHeaderText)); + public void onPublishUpdated(@NonNull SipDetails details) { + mCapabilityEventCallback.forEach( + callback ->callback.onPublishUpdated(details)); } @Override diff --git a/src/java/com/android/ims/rcs/uce/UceController.java b/src/java/com/android/ims/rcs/uce/UceController.java index 6fb27b06..429b5518 100644 --- a/src/java/com/android/ims/rcs/uce/UceController.java +++ b/src/java/com/android/ims/rcs/uce/UceController.java @@ -18,6 +18,7 @@ package com.android.ims.rcs.uce; import android.annotation.IntDef; import android.annotation.NonNull; +import android.annotation.Nullable; import android.content.Context; import android.net.Uri; import android.os.HandlerThread; @@ -28,6 +29,7 @@ import android.telephony.ims.RcsContactUceCapability.CapabilityMechanism; import android.telephony.ims.RcsUceAdapter; import android.telephony.ims.RcsUceAdapter.PublishState; import android.telephony.ims.RcsUceAdapter.StackPublishTriggerType; +import android.telephony.ims.SipDetails; import android.telephony.ims.aidl.IOptionsRequestCallback; import android.telephony.ims.aidl.IRcsUceControllerCallback; import android.telephony.ims.aidl.IRcsUcePublishStateCallback; @@ -212,7 +214,7 @@ public class UceController { private static class CachedCapabilityEvent { private Optional mRequestPublishCapabilitiesEvent; private Optional mUnpublishEvent; - private Optional mPublishUpdatedEvent; + private Optional mPublishUpdatedEvent; private Optional mRemoteCapabilityRequestEvent; public CachedCapabilityEvent() { @@ -239,14 +241,8 @@ public class UceController { /** * Cache the publish update event triggered by the ImsService. */ - public synchronized void setOnPublishUpdatedEvent(int reasonCode, String reasonPhrase, - int reasonHeaderCause, String reasonHeaderText) { - SomeArgs args = SomeArgs.obtain(); - args.arg1 = reasonCode; - args.arg2 = reasonPhrase; - args.arg3 = reasonHeaderCause; - args.arg4 = reasonHeaderText; - mPublishUpdatedEvent = Optional.of(args); + public synchronized void setOnPublishUpdatedEvent(SipDetails details) { + mPublishUpdatedEvent = Optional.of(details); } /** @@ -272,7 +268,7 @@ public class UceController { } /** @Return the cached pubilsh update event */ - public synchronized Optional getPublishUpdatedEvent() { + public synchronized Optional getPublishUpdatedEvent() { return mPublishUpdatedEvent; } @@ -285,7 +281,6 @@ public class UceController { public synchronized void clear() { mRequestPublishCapabilitiesEvent = Optional.empty(); mUnpublishEvent = Optional.empty(); - mPublishUpdatedEvent.ifPresent(args -> args.recycle()); mPublishUpdatedEvent = Optional.empty(); mRemoteCapabilityRequestEvent.ifPresent(args -> args.recycle()); mRemoteCapabilityRequestEvent = Optional.empty(); @@ -489,14 +484,9 @@ public class UceController { Optional unpublishEvent = mCachedCapabilityEvent.getUnpublishEvent(); unpublishEvent.ifPresent(unpublish -> onUnpublish()); - Optional publishUpdatedEvent = mCachedCapabilityEvent.getPublishUpdatedEvent(); - publishUpdatedEvent.ifPresent(args -> { - int reasonCode = (Integer) args.arg1; - String reasonPhrase = (String) args.arg2; - int reasonHeaderCause = (Integer) args.arg3; - String reasonHeaderText = (String) args.arg4; - onPublishUpdated(reasonCode, reasonPhrase, reasonHeaderCause, reasonHeaderText); - }); + Optional publishUpdatedEvent = mCachedCapabilityEvent.getPublishUpdatedEvent(); + publishUpdatedEvent.ifPresent(details -> + onPublishUpdated(details)); Optional remoteRequest = mCachedCapabilityEvent.getRemoteCapabilityRequestEvent(); remoteRequest.ifPresent(args -> { @@ -606,15 +596,12 @@ public class UceController { } @Override - public void onPublishUpdated(int reasonCode, String reasonPhrase, - int reasonHeaderCause, String reasonHeaderText) { + public void onPublishUpdated(@NonNull SipDetails details) { if (isRcsConnecting()) { - mCachedCapabilityEvent.setOnPublishUpdatedEvent(reasonCode, reasonPhrase, - reasonHeaderCause, reasonHeaderText); + mCachedCapabilityEvent.setOnPublishUpdatedEvent(details); return; } - UceController.this.onPublishUpdated(reasonCode, reasonPhrase, - reasonHeaderCause, reasonHeaderText); + UceController.this.onPublishUpdated(details); } @Override @@ -740,11 +727,9 @@ public class UceController { * This method is triggered by the ImsService to notify framework that the device's * publish status has been changed. */ - public void onPublishUpdated(int reasonCode, String reasonPhrase, - int reasonHeaderCause, String reasonHeaderText) { + public void onPublishUpdated(@NonNull SipDetails details) { logi("onPublishUpdated"); - mPublishController.onPublishUpdated(reasonCode, reasonPhrase, - reasonHeaderCause, reasonHeaderText); + mPublishController.onPublishUpdated(details); } /** diff --git a/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityInfo.java b/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityInfo.java index 96e952b9..4dd76be6 100644 --- a/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityInfo.java +++ b/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityInfo.java @@ -42,6 +42,7 @@ import com.android.ims.rcs.uce.util.UceUtils; import com.android.internal.annotations.VisibleForTesting; import java.io.PrintWriter; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Iterator; @@ -484,6 +485,18 @@ public class DeviceCapabilityInfo { mPendingPublishCapabilities = null; } + public List getLastSuccessfulPresenceTuplesWithoutContactUri() { + List presenceTuples = new ArrayList<>(); + if (mLastSuccessfulCapabilities.isEmpty()) { + return presenceTuples; + } + + for (ServiceDescription capability : mLastSuccessfulCapabilities) { + presenceTuples.add(capability.getTupleBuilder().build()); + } + return presenceTuples; + } + @VisibleForTesting public void addLastSuccessfulServiceDescription(ServiceDescription capability) { mLastSuccessfulCapabilities.add(capability); diff --git a/src/java/com/android/ims/rcs/uce/presence/publish/PublishController.java b/src/java/com/android/ims/rcs/uce/presence/publish/PublishController.java index a3d31b9e..732a558b 100644 --- a/src/java/com/android/ims/rcs/uce/presence/publish/PublishController.java +++ b/src/java/com/android/ims/rcs/uce/presence/publish/PublishController.java @@ -18,9 +18,11 @@ package com.android.ims.rcs.uce.presence.publish; import android.annotation.IntDef; import android.annotation.NonNull; +import android.annotation.Nullable; import android.telephony.ims.RcsContactUceCapability; import android.telephony.ims.RcsContactUceCapability.CapabilityMechanism; import android.telephony.ims.RcsUceAdapter.PublishState; +import android.telephony.ims.SipDetails; import android.telephony.ims.aidl.IRcsUcePublishStateCallback; import com.android.ims.rcs.uce.ControllerBase; @@ -138,7 +140,8 @@ public interface PublishController extends ControllerBase { /** * Update the publish request result. */ - void updatePublishRequestResult(int publishState, Instant updatedTimestamp, String pidfXml); + void updatePublishRequestResult(int publishState, Instant updatedTimestamp, String pidfXml, + SipDetails details); /** * Update the value of the publish throttle. @@ -208,9 +211,7 @@ public interface PublishController extends ControllerBase { /** * Notify that the device's publish status have been changed. */ - void onPublishUpdated(int reasonCode, String reasonPhrase, - int reasonHeaderCause, String reasonHeaderText); - + void onPublishUpdated(@NonNull SipDetails details); /** * Retrieve the device's capabilities. */ diff --git a/src/java/com/android/ims/rcs/uce/presence/publish/PublishControllerImpl.java b/src/java/com/android/ims/rcs/uce/presence/publish/PublishControllerImpl.java index 35a5d557..101aa810 100644 --- a/src/java/com/android/ims/rcs/uce/presence/publish/PublishControllerImpl.java +++ b/src/java/com/android/ims/rcs/uce/presence/publish/PublishControllerImpl.java @@ -16,7 +16,10 @@ package com.android.ims.rcs.uce.presence.publish; +import static android.telephony.ims.RcsUceAdapter.PUBLISH_STATE_OK; + import android.annotation.NonNull; +import android.annotation.Nullable; import android.content.Context; import android.os.Build; import android.os.Handler; @@ -27,10 +30,13 @@ import android.os.RemoteCallbackList; import android.os.RemoteException; import android.telephony.CarrierConfigManager; import android.telephony.ims.ImsException; +import android.telephony.ims.PublishAttributes; +import android.telephony.ims.RcsContactPresenceTuple; import android.telephony.ims.RcsContactUceCapability; import android.telephony.ims.RcsContactUceCapability.CapabilityMechanism; import android.telephony.ims.RcsUceAdapter; import android.telephony.ims.RcsUceAdapter.PublishState; +import android.telephony.ims.SipDetails; import android.telephony.ims.aidl.IImsCapabilityCallback; import android.telephony.ims.aidl.IRcsUcePublishStateCallback; import android.telephony.ims.feature.RcsFeature.RcsImsCapabilities; @@ -53,6 +59,7 @@ import java.io.PrintWriter; import java.lang.ref.WeakReference; import java.time.Instant; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; @@ -198,7 +205,7 @@ public class PublishControllerImpl implements PublishController { if (capabilityType == RcsImsCapabilities.CAPABILITY_TYPE_PRESENCE_UCE) { return RcsUceAdapter.PUBLISH_STATE_NOT_PUBLISHED; } else if (capabilityType == RcsImsCapabilities.CAPABILITY_TYPE_OPTIONS_UCE) { - return RcsUceAdapter.PUBLISH_STATE_OK; + return PUBLISH_STATE_OK; } else { return RcsUceAdapter.PUBLISH_STATE_OTHER_ERROR; } @@ -363,11 +370,9 @@ public class PublishControllerImpl implements PublishController { * Notify that the device's publish status have been changed. */ @Override - public void onPublishUpdated(int reasonCode, String reasonPhrase, - int reasonHeaderCause, String reasonHeaderText) { + public void onPublishUpdated(@NonNull SipDetails details) { if (mIsDestroyedFlag) return; - mPublishHandler.sendPublishUpdatedMessage(reasonCode, reasonPhrase, reasonHeaderCause, - reasonHeaderText); + mPublishHandler.sendPublishUpdatedMessage(details); } @Override @@ -412,9 +417,10 @@ public class PublishControllerImpl implements PublishController { @Override public void updatePublishRequestResult(@PublishState int state, - Instant updatedTime, String pidfXml) { + Instant updatedTime, String pidfXml, SipDetails details) { logd("updatePublishRequestResult: " + state + ", time=" + updatedTime); - mPublishHandler.sendPublishStateChangedMessage(state, updatedTime, pidfXml); + mPublishHandler.sendPublishStateChangedMessage(state, updatedTime, pidfXml, + details); } @Override @@ -514,9 +520,10 @@ public class PublishControllerImpl implements PublishController { int newPublishState = (Integer) args.arg1; Instant updatedTimestamp = (Instant) args.arg2; String pidfXml = (String) args.arg3; + SipDetails details = (SipDetails) args.arg4; args.recycle(); publishCtrl.handlePublishStateChangedMessage(newPublishState, updatedTimestamp, - pidfXml); + pidfXml, details); break; } case MSG_NOTIFY_CURRENT_PUBLISH_STATE: @@ -566,14 +573,8 @@ public class PublishControllerImpl implements PublishController { break; case MSG_PUBLISH_UPDATED: { - SomeArgs args = (SomeArgs) message.obj; - int reasonCode = (Integer) args.arg1; - String reasonPhrase = (String) args.arg2; - int reasonHeaderCause = (Integer) args.arg3; - String reasonHeaderText = (String) args.arg4; - args.recycle(); - publishCtrl.handlePublishUpdatedMessage(reasonCode, reasonPhrase, - reasonHeaderCause, reasonHeaderText); + SipDetails details = (SipDetails) message.obj; + publishCtrl.handlePublishUpdatedMessage(details); break; } @@ -654,7 +655,7 @@ public class PublishControllerImpl implements PublishController { * Send the message to notify the publish state is changed. */ public void sendPublishStateChangedMessage(@PublishState int publishState, - @NonNull Instant updatedTimestamp, String pidfXml) { + @NonNull Instant updatedTimestamp, String pidfXml, SipDetails details) { PublishControllerImpl publishCtrl = mPublishControllerRef.get(); if (publishCtrl == null) return; if (publishCtrl.mIsDestroyedFlag) return; @@ -663,6 +664,7 @@ public class PublishControllerImpl implements PublishController { args.arg1 = publishState; args.arg2 = updatedTimestamp; args.arg3 = pidfXml; + args.arg4 = details; Message message = obtainMessage(); message.what = MSG_PUBLISH_STATE_CHANGED; message.obj = args; @@ -689,20 +691,14 @@ public class PublishControllerImpl implements PublishController { /** * Send the message to notify the publish state is changed. */ - public void sendPublishUpdatedMessage(int reasonCode, String reasonPhrase, - int reasonHeaderCause, String reasonHeaderText) { + public void sendPublishUpdatedMessage(@NonNull SipDetails details) { PublishControllerImpl publishCtrl = mPublishControllerRef.get(); if (publishCtrl == null) return; if (publishCtrl.mIsDestroyedFlag) return; - SomeArgs args = SomeArgs.obtain(); - args.arg1 = reasonCode; - args.arg2 = reasonPhrase; - args.arg3 = reasonHeaderCause; - args.arg4 = reasonHeaderText; Message message = obtainMessage(); message.what = MSG_PUBLISH_UPDATED; - message.obj = args; + message.obj = details; sendMessage(message); } @@ -924,7 +920,7 @@ public class PublishControllerImpl implements PublishController { // PUBLISH is enabled. if (isPresencePublishEnabled()) { handlePublishStateChangedMessage(RcsUceAdapter.PUBLISH_STATE_NOT_PUBLISHED, - Instant.now(), null /*pidfXml*/); + Instant.now(), null /*pidfXml*/, null /*SipDetails*/); } } @@ -1011,7 +1007,8 @@ public class PublishControllerImpl implements PublishController { // Update the publish state directly. Because this method is called in the // handler thread already, the process of updating publish state does not need to be // sent to the looper again. - handlePublishStateChangedMessage(updatedPublishState, Instant.now(), null /*pidfxml*/); + handlePublishStateChangedMessage(updatedPublishState, Instant.now(), null /*pidfxml*/, + null /*SipDetails*/); } } @@ -1040,7 +1037,7 @@ public class PublishControllerImpl implements PublishController { * from original state. */ private void handlePublishStateChangedMessage(@PublishState int newPublishState, - Instant updatedTimestamp, String pidfXml) { + Instant updatedTimestamp, String pidfXml, SipDetails details) { synchronized (mPublishStateLock) { if (mIsDestroyedFlag) return; // Check if the time of the given publish state is not earlier than existing time. @@ -1067,7 +1064,7 @@ public class PublishControllerImpl implements PublishController { logd("Notify publish state changed: " + mCurrentPublishState); mPublishStateCallbacks.broadcast(c -> { try { - c.onPublishStateChanged(mCurrentPublishState); + c.onPublishUpdated(getPublishAttributes(mCurrentPublishState, details)); } catch (RemoteException e) { logw("Notify publish state changed error: " + e); } @@ -1075,11 +1072,25 @@ public class PublishControllerImpl implements PublishController { logd("Notify publish state changed: completed"); } + private PublishAttributes getPublishAttributes(@PublishState int mCurrentPublishState, + SipDetails details) { + List tuples = null; + if (mCurrentPublishState == PUBLISH_STATE_OK) { + tuples = mDeviceCapabilityInfo.getLastSuccessfulPresenceTuplesWithoutContactUri(); + } + if (tuples != null && !tuples.isEmpty()) { + return new PublishAttributes.Builder(mCurrentPublishState).setSipDetails(details) + .setPresenceTuples(tuples).build(); + } + return new PublishAttributes.Builder(mCurrentPublishState).setSipDetails(details).build(); + } + private void handleNotifyCurrentPublishStateMessage(IRcsUcePublishStateCallback callback, boolean supportPublishingState) { if (mIsDestroyedFlag || callback == null) return; try { - callback.onPublishStateChanged(getUcePublishState(supportPublishingState)); + int publishState = getUcePublishState(supportPublishingState); + callback.onPublishUpdated(getPublishAttributes(publishState, null /*SipDetails*/)); } catch (RemoteException e) { logw("handleCurrentPublishStateUpdateMessage exception: " + e); } @@ -1146,7 +1157,8 @@ public class PublishControllerImpl implements PublishController { Instant updatedTimestamp) { if (mIsDestroyedFlag) return; mPublishProcessor.resetState(); - handlePublishStateChangedMessage(newPublishState, updatedTimestamp, null); + handlePublishStateChangedMessage(newPublishState, updatedTimestamp, + null /*pidfXml*/, null /*SipDetails*/); } private void handlePublishSentMessage() { @@ -1170,20 +1182,22 @@ public class PublishControllerImpl implements PublishController { mCurrentPublishState = RcsUceAdapter.PUBLISH_STATE_PUBLISHING; if (isSupportPublishingState) { if (callback != null) { - callback.onPublishStateChanged(mCurrentPublishState); + callback.onPublishUpdated(getPublishAttributes(mCurrentPublishState, + null /*SipDetails*/)); } } else { // If it is currently PUBLISH_STATE_OK, the state must not be changed to // PUBLISH_STATE_NOT_PUBLISHED. // And in the case of the current PUBLISH_STATE_NOT_PUBLISHED, it is // necessary to avoid reporting the duplicate state. - if (tempPublishState != RcsUceAdapter.PUBLISH_STATE_OK + if (tempPublishState != PUBLISH_STATE_OK && tempPublishState != RcsUceAdapter.PUBLISH_STATE_NOT_PUBLISHED) { // set the state to PUBLISH_STATE_NOT_PUBLISHED so that // getUcePublishState is consistent with the callback mLastPublishState = RcsUceAdapter.PUBLISH_STATE_NOT_PUBLISHED; if (callback != null) { - callback.onPublishStateChanged(mLastPublishState); + callback.onPublishUpdated(getPublishAttributes(mLastPublishState, + null /*SipDetails*/)); } } } @@ -1194,11 +1208,10 @@ public class PublishControllerImpl implements PublishController { } } - private void handlePublishUpdatedMessage(int reasonCode, String reasonPhrase, - int reasonHeaderCause, String reasonHeaderText) { + private void handlePublishUpdatedMessage(@NonNull SipDetails details) { if (mIsDestroyedFlag) return; PublishRequestResponse updatedPublish = new PublishRequestResponse(getLastPidfXml(), - reasonCode, reasonPhrase, reasonHeaderCause, reasonHeaderText); + details); mPublishProcessor.publishUpdated(updatedPublish); } diff --git a/src/java/com/android/ims/rcs/uce/presence/publish/PublishProcessor.java b/src/java/com/android/ims/rcs/uce/presence/publish/PublishProcessor.java index 8a6802a4..c239dd5a 100644 --- a/src/java/com/android/ims/rcs/uce/presence/publish/PublishProcessor.java +++ b/src/java/com/android/ims/rcs/uce/presence/publish/PublishProcessor.java @@ -22,6 +22,7 @@ import android.annotation.NonNull; import android.content.Context; import android.os.RemoteException; import android.telephony.ims.RcsContactUceCapability; +import android.telephony.ims.SipDetails; import android.telephony.ims.stub.ImsRegistrationImplBase; import android.telephony.ims.stub.RcsCapabilityExchangeImplBase; import android.text.TextUtils; @@ -394,7 +395,9 @@ public class PublishProcessor { // Update the publish state after the request has finished. int publishState = response.getPublishState(); String pidfXml = response.getPidfXml(); - mPublishCtrlCallback.updatePublishRequestResult(publishState, responseTime, pidfXml); + SipDetails details = response.getSipDetails().orElse(null); + mPublishCtrlCallback.updatePublishRequestResult(publishState, responseTime, pidfXml, + details); // Refresh the device state with the publish request result. response.getResponseSipCode().ifPresent(sipCode -> { diff --git a/src/java/com/android/ims/rcs/uce/presence/publish/PublishRequestResponse.java b/src/java/com/android/ims/rcs/uce/presence/publish/PublishRequestResponse.java index 47aa37c3..aa1b27c1 100644 --- a/src/java/com/android/ims/rcs/uce/presence/publish/PublishRequestResponse.java +++ b/src/java/com/android/ims/rcs/uce/presence/publish/PublishRequestResponse.java @@ -16,8 +16,10 @@ package com.android.ims.rcs.uce.presence.publish; +import android.annotation.NonNull; import android.annotation.Nullable; import android.telephony.ims.RcsUceAdapter; +import android.telephony.ims.SipDetails; import android.telephony.ims.aidl.IPublishResponseCallback; import android.telephony.ims.stub.RcsCapabilityExchangeImplBase; import android.text.TextUtils; @@ -47,7 +49,7 @@ public class PublishRequestResponse { private Optional mReasonPhrase; private Optional mReasonHeaderCause; private Optional mReasonHeaderText; - + private Optional mSipDetails; // The timestamp when receive the response from the network. private Instant mResponseTimestamp; @@ -61,29 +63,29 @@ public class PublishRequestResponse { mReasonPhrase = Optional.empty(); mReasonHeaderCause = Optional.empty(); mReasonHeaderText = Optional.empty(); + mSipDetails = Optional.empty(); } - public PublishRequestResponse(String pidfXml, int sipCode, String reasonPhrase, - int reasonHeaderCause, String reasonHeaderText) { + public PublishRequestResponse(String pidfXml, @Nullable SipDetails details) { mTaskId = 0L; mPublishCtrlCallback = null; mCmdErrorCode = Optional.empty(); mPidfXml = pidfXml; mResponseTimestamp = Instant.now(); - mNetworkRespSipCode = Optional.of(sipCode); - mReasonPhrase = Optional.ofNullable(reasonPhrase); - if (reasonHeaderCause != 0) { - mReasonHeaderCause = Optional.of(reasonHeaderCause); + mNetworkRespSipCode = Optional.of(details.getResponseCode()); + mReasonPhrase = Optional.ofNullable(details.getResponsePhrase()); + if (details.getReasonHeaderCause() != 0) { + mReasonHeaderCause = Optional.of(details.getReasonHeaderCause()); } else { mReasonHeaderCause = Optional.empty(); } - if (TextUtils.isEmpty(reasonHeaderText)) { + if (TextUtils.isEmpty(details.getReasonHeaderText())) { mReasonHeaderText = Optional.empty(); } else { - mReasonHeaderText = Optional.ofNullable(reasonHeaderText); + mReasonHeaderText = Optional.ofNullable(details.getReasonHeaderText()); } - + mSipDetails = Optional.ofNullable(details); } // The result callback of the publish capability request. @@ -94,15 +96,8 @@ public class PublishRequestResponse { } @Override - public void onNetworkResponse(int code, String reason) { - PublishRequestResponse.this.onNetworkResponse(code, reason); - } - - @Override - public void onNetworkRespHeader(int code, String reasonPhrase, int reasonHeaderCause, - String reasonHeaderText) { - PublishRequestResponse.this.onNetworkResponse(code, reasonPhrase, reasonHeaderCause, - reasonHeaderText); + public void onNetworkResponse(@NonNull SipDetails details) { + PublishRequestResponse.this.onNetworkResponse(details); } }; @@ -149,6 +144,12 @@ public class PublishRequestResponse { return mReasonHeaderText; } + /** + * Retrieve the sip information which received from the network. + */ + public Optional getSipDetails() { + return mSipDetails; + } /** * Retrieve the SIP code from the network response. It will get the value from the Reason * Header first. If the ReasonHeader is not present, it will get the value from the Network @@ -198,49 +199,34 @@ public class PublishRequestResponse { } } - private void onNetworkResponse(int sipCode, String reason) { + private void onNetworkResponse(@NonNull SipDetails details) { // When we send a request to PUBLISH and there is no change to the UCE capabilities, we // expected onCommandError() with COMMAND_CODE_NO_CHANGE. // But some of the vendor will instead send SIP code 999. - if (sipCode == 999) { + if (details.getResponseCode() == 999) { onCommandError(RcsCapabilityExchangeImplBase.COMMAND_CODE_NO_CHANGE); return; } mResponseTimestamp = Instant.now(); - mNetworkRespSipCode = Optional.of(sipCode); - mReasonPhrase = Optional.ofNullable(reason); - updateRetryFlagByNetworkResponse(); - - PublishControllerCallback ctrlCallback = mPublishCtrlCallback; - if (ctrlCallback != null) { - ctrlCallback.onRequestNetworkResp(this); - } else { - Log.d(LOG_TAG, "onNetworkResponse: already destroyed. sip code=" + sipCode); + mNetworkRespSipCode = Optional.of(details.getResponseCode()); + mReasonPhrase = Optional.ofNullable(details.getResponsePhrase()); + if (details.getReasonHeaderCause() != 0) { + mReasonHeaderCause = Optional.of(details.getReasonHeaderCause()); } - } - - private void onNetworkResponse(int sipCode, String reasonPhrase, int reasonHeaderCause, - String reasonHeaderText) { - // When we send a request to PUBLISH and there is no change to the UCE capabilities, we - // expected onCommandError() with COMMAND_CODE_NO_CHANGE. - // But some of the vendor will instead send SIP code 999. - if (sipCode == 999) { - onCommandError(RcsCapabilityExchangeImplBase.COMMAND_CODE_NO_CHANGE); - return; + if (TextUtils.isEmpty(details.getReasonHeaderText())) { + mReasonHeaderText = Optional.empty(); + } else { + mReasonHeaderText = Optional.ofNullable(details.getReasonHeaderText()); } - mResponseTimestamp = Instant.now(); - mNetworkRespSipCode = Optional.of(sipCode); - mReasonPhrase = Optional.ofNullable(reasonPhrase); - mReasonHeaderCause = Optional.of(reasonHeaderCause); - mReasonHeaderText = Optional.ofNullable(reasonHeaderText); + mSipDetails = Optional.ofNullable(details); updateRetryFlagByNetworkResponse(); PublishControllerCallback ctrlCallback = mPublishCtrlCallback; if (ctrlCallback != null) { ctrlCallback.onRequestNetworkResp(this); } else { - Log.d(LOG_TAG, "onNetworkResponse: already destroyed. sipCode=" + sipCode + - ", reasonHeader=" + reasonHeaderCause); + Log.d(LOG_TAG, "onNetworkResponse: already destroyed. sip code=" + + details.getResponseCode()); } } diff --git a/tests/src/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityInfoTest.java b/tests/src/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityInfoTest.java index 65e5540a..de045de4 100644 --- a/tests/src/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityInfoTest.java +++ b/tests/src/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityInfoTest.java @@ -18,7 +18,14 @@ package com.android.ims.rcs.uce.presence.publish; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; - +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.anyBoolean; +import static org.mockito.Mockito.anyInt; +import static org.mockito.Mockito.doReturn; + +import android.content.Context; +import android.telephony.CarrierConfigManager; +import android.telephony.TelephonyManager; import android.telephony.ims.RcsContactPresenceTuple; import android.util.ArraySet; @@ -32,6 +39,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import com.android.ims.ImsTestBase; +import com.android.ims.rcs.uce.util.UceUtils; import org.junit.After; import org.junit.Before; @@ -39,15 +47,17 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; +import java.util.ArrayList; import java.util.Collections; +import java.util.List; import java.util.Set; @RunWith(AndroidJUnit4.class) public class DeviceCapabilityInfoTest extends ImsTestBase { - int mSubId = 1; @Mock PublishServiceDescTracker mPublishServiceDescTracker; + @Mock Context mMockContext; String sipNumber = "123456789"; String telNumber = "987654321"; @@ -182,7 +192,43 @@ public class DeviceCapabilityInfoTest extends ImsTestBase { number = numberParts[0]; assertEquals(number, telNumber); + } + @Test + @SmallTest + public void testGetLastSuccessfulPresenceTuples() throws Exception { + DeviceCapabilityInfo deviceCapInfo = createDeviceCapabilityInfo(); + + List tuples = + deviceCapInfo.getLastSuccessfulPresenceTuplesWithoutContactUri(); + // Verify that the presence tuples are empty when the last capabilities are empty. + assertTrue(tuples.isEmpty()); + + doReturn(null).when(mMockContext).getSystemService(CarrierConfigManager.class); + doReturn(null).when(mMockContext).getSystemService(TelephonyManager.class); + ServiceDescription mmtelDescription = getMmtelDescription(); + deviceCapInfo.addLastSuccessfulServiceDescription(mmtelDescription); + ServiceDescription chatDescription = getChatDescription(); + deviceCapInfo.addLastSuccessfulServiceDescription(chatDescription); + tuples = deviceCapInfo.getLastSuccessfulPresenceTuplesWithoutContactUri(); + assertEquals(2, tuples.size()); + + Uri[] uris = new Uri[1]; + uris[0] = Uri.fromParts(PhoneAccount.SCHEME_SIP, sipNumber, null); + deviceCapInfo.updateRcsAssociatedUri(uris); + List expectedTuples = new ArrayList<>(); + expectedTuples.add(mmtelDescription.getTupleBuilder().setContactUri(uris[0]).build()); + expectedTuples.add(chatDescription.getTupleBuilder().setContactUri(uris[0]).build()); + + tuples = deviceCapInfo.getLastSuccessfulPresenceTuplesWithoutContactUri(); + assertTrue(!tuples.isEmpty()); + assertEquals(expectedTuples.size(), tuples.size()); + for (int i = 0; i < tuples.size(); i++) { + assertEquals(expectedTuples.get(i).getServiceId(), tuples.get(i).getServiceId()); + assertEquals(expectedTuples.get(i).getServiceVersion(), + tuples.get(i).getServiceVersion()); + assertNull(tuples.get(i).getContactUri()); + } } private DeviceCapabilityInfo createDeviceCapabilityInfo() { diff --git a/tests/src/com/android/ims/rcs/uce/presence/publish/PublishControllerImplTest.java b/tests/src/com/android/ims/rcs/uce/presence/publish/PublishControllerImplTest.java index a6e3d0b8..aa145c7c 100644 --- a/tests/src/com/android/ims/rcs/uce/presence/publish/PublishControllerImplTest.java +++ b/tests/src/com/android/ims/rcs/uce/presence/publish/PublishControllerImplTest.java @@ -22,6 +22,8 @@ import static com.android.ims.rcs.uce.presence.publish.PublishController.PUBLISH import static junit.framework.Assert.assertFalse; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; @@ -34,6 +36,7 @@ import android.os.Handler; import android.os.Looper; import android.os.RemoteCallbackList; import android.telephony.ims.RcsUceAdapter; +import android.telephony.ims.SipDetails; import android.telephony.ims.aidl.IImsCapabilityCallback; import android.telephony.ims.aidl.IRcsUcePublishStateCallback; import android.telephony.ims.feature.RcsFeature.RcsImsCapabilities; @@ -137,7 +140,7 @@ public class PublishControllerImplTest extends ImsTestBase { assertEquals(RcsUceAdapter.PUBLISH_STATE_NOT_PUBLISHED, initState); publishController.getPublishControllerCallback().updatePublishRequestResult( - RcsUceAdapter.PUBLISH_STATE_OK, Instant.now(), null); + RcsUceAdapter.PUBLISH_STATE_OK, Instant.now(), null, null); Handler handler = publishController.getPublishHandler(); waitForHandlerAction(handler, 1000); @@ -154,7 +157,7 @@ public class PublishControllerImplTest extends ImsTestBase { assertEquals(RcsUceAdapter.PUBLISH_STATE_NOT_PUBLISHED, initState); publishController.getPublishControllerCallback().updatePublishRequestResult( - RcsUceAdapter.PUBLISH_STATE_PUBLISHING, Instant.now(), null); + RcsUceAdapter.PUBLISH_STATE_PUBLISHING, Instant.now(), null, null); Handler handler = publishController.getPublishHandler(); waitForHandlerAction(handler, 1000); @@ -223,8 +226,10 @@ public class PublishControllerImplTest extends ImsTestBase { public void testPublishUpdated() throws Exception { PublishControllerImpl publishController = createPublishController(); int responseCode = 200; + String responsePhrase = "OK"; - publishController.onPublishUpdated(responseCode, "", 0, ""); + publishController.onPublishUpdated(new SipDetails.Builder(SipDetails.METHOD_PUBLISH) + .setSipResponseCode(responseCode, responsePhrase).build()); Handler handler = publishController.getPublishHandler(); waitForHandlerAction(handler, 1000); @@ -235,7 +240,57 @@ public class PublishControllerImplTest extends ImsTestBase { verify(mPublishProcessor).publishUpdated(captor.capture()); PublishRequestResponse response = captor.getValue(); int expectedCode = response.getNetworkRespSipCode().orElse(-1); + String expectedPhrase = response.getReasonPhrase().orElse(""); assertEquals(responseCode, expectedCode); + assertEquals(responsePhrase, expectedPhrase); + SipDetails details = response.getSipDetails().orElse(null); + assertNotNull(details); + assertEquals(responseCode, details.getResponseCode()); + assertEquals(responsePhrase, details.getResponsePhrase()); + } + + @Test + @SmallTest + public void testPublishUpdatedWithSipDetails() throws Exception { + PublishControllerImpl publishController = createPublishController(); + int responseCode = 200; + String responsePhrase = "OK"; + int reasonHdrCause = 7; + String reasonHdrText = "reasonHeaderText"; + int cseq = 10; + String callId = "TestCallId"; + + publishController.onPublishUpdated(new SipDetails.Builder(SipDetails.METHOD_PUBLISH) + .setCSeq(cseq).setSipResponseCode(responseCode, responsePhrase).setCallId(callId) + .setSipResponseReasonHeader(reasonHdrCause, reasonHdrText).build()); + + Handler handler = publishController.getPublishHandler(); + waitForHandlerAction(handler, 1000); + + ArgumentCaptor captor = + ArgumentCaptor.forClass(PublishRequestResponse.class); + + verify(mPublishProcessor).publishUpdated(captor.capture()); + PublishRequestResponse response = captor.getValue(); + int expectedCode = response.getNetworkRespSipCode().orElse(-1); + String expectedPhrase = response.getReasonPhrase().orElse(""); + int expectedReasonCause = response.getReasonHeaderCause().orElse(-1); + String expectedReasonText = response.getReasonHeaderText().orElse(""); + + assertEquals(responseCode, expectedCode); + assertEquals(responsePhrase, expectedPhrase); + assertEquals(reasonHdrCause, expectedReasonCause); + assertEquals(reasonHdrText, expectedReasonText); + + SipDetails details = response.getSipDetails().orElse(null); + assertNotNull(details); + assertEquals(SipDetails.METHOD_PUBLISH, details.getMethod()); + assertEquals(cseq, details.getCSeq()); + assertEquals(responseCode, details.getResponseCode()); + assertEquals(responsePhrase, details.getResponsePhrase()); + assertEquals(reasonHdrCause, details.getReasonHeaderCause()); + assertEquals(reasonHdrText, details.getReasonHeaderText()); + assertEquals(callId, details.getCallId()); } @Test diff --git a/tests/src/com/android/ims/rcs/uce/presence/publish/PublishProcessorTest.java b/tests/src/com/android/ims/rcs/uce/presence/publish/PublishProcessorTest.java index d0b7c0af..2de47146 100644 --- a/tests/src/com/android/ims/rcs/uce/presence/publish/PublishProcessorTest.java +++ b/tests/src/com/android/ims/rcs/uce/presence/publish/PublishProcessorTest.java @@ -30,6 +30,7 @@ import android.content.Context; import android.net.Uri; import android.telephony.ims.RcsContactPresenceTuple; import android.telephony.ims.RcsContactUceCapability; +import android.telephony.ims.SipDetails; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; @@ -140,7 +141,7 @@ public class PublishProcessorTest extends ImsTestBase { publishProcessor.onNetworkResponse(mResponseCallback); - verify(mPublishCtrlCallback).updatePublishRequestResult(anyInt(), any(), any()); + verify(mPublishCtrlCallback).updatePublishRequestResult(anyInt(), any(), any(), eq(null)); verify(mResponseCallback).onDestroy(); verify(mProcessorState).setPublishingFlag(false); verify(mPublishCtrlCallback).clearRequestCanceledTimer(); @@ -196,7 +197,7 @@ public class PublishProcessorTest extends ImsTestBase { publishProcessor.onCommandError(mResponseCallback); verify(mDeviceCapabilities).setPresencePublishResult(true); - verify(mPublishCtrlCallback).updatePublishRequestResult(anyInt(), any(), any()); + verify(mPublishCtrlCallback).updatePublishRequestResult(anyInt(), any(), any(), eq(null)); verify(mResponseCallback).onDestroy(); verify(mProcessorState).setPublishingFlag(false); verify(mPublishCtrlCallback).clearRequestCanceledTimer(); @@ -231,12 +232,20 @@ public class PublishProcessorTest extends ImsTestBase { doReturn(false).when(mResponseCallback).needRetry(); doReturn(true).when(mResponseCallback).isRequestSuccess(); doReturn(Optional.of(200)).when(mResponseCallback).getNetworkRespSipCode(); + + SipDetails details = new SipDetails.Builder(SipDetails.METHOD_PUBLISH) + .setCSeq(10).setSipResponseCode(200, "OK").setCallId("CallId").build(); + Optional sipDetails = Optional.ofNullable(details); + doReturn(sipDetails).when(mResponseCallback).getSipDetails(); + PublishProcessor publishProcessor = getPublishProcessor(); publishProcessor.onNetworkResponse(mResponseCallback); + SipDetails actualInfo = sipDetails.orElse(null); verify(mDeviceCapabilities).setPresencePublishResult(true); - verify(mPublishCtrlCallback).updatePublishRequestResult(anyInt(), any(), any()); + verify(mPublishCtrlCallback).updatePublishRequestResult(anyInt(), any(), any(), + eq(actualInfo)); verify(mResponseCallback).onDestroy(); verify(mProcessorState).setPublishingFlag(false); verify(mPublishCtrlCallback).clearRequestCanceledTimer(); @@ -266,14 +275,21 @@ public class PublishProcessorTest extends ImsTestBase { doReturn(0).when(mResponseCallback).getPublishState(); doReturn("").when(mResponseCallback).getPidfXml(); + SipDetails details = new SipDetails.Builder(SipDetails.METHOD_PUBLISH) + .setCSeq(10).setSipResponseCode(200, "").setCallId("CallId").build(); + Optional sipDetails = Optional.ofNullable(details); + doReturn(sipDetails).when(mResponseCallback).getSipDetails(); + PublishProcessor publishProcessor = getPublishProcessor(); publishProcessor.publishUpdated(mResponseCallback); + SipDetails actualInfo = sipDetails.orElse(null); verify(mDeviceCapabilities).setPresencePublishResult(true); verify(mProcessorState).setLastPublishedTime(any()); verify(mProcessorState).resetRetryCount(); - verify(mPublishCtrlCallback).updatePublishRequestResult(anyInt(), any(), any()); + verify(mPublishCtrlCallback).updatePublishRequestResult(anyInt(), any(), any(), + eq(actualInfo)); } private PublishProcessor getPublishProcessor() { -- cgit v1.2.3 From 09c468419841562de2a67f25f82715b0b3e6e58d Mon Sep 17 00:00:00 2001 From: Hyunho Date: Wed, 2 Nov 2022 01:10:09 +0000 Subject: Changed the interface between the caller and the framework for subscriptions. In order to more debug issues during the subscription, the caller should have access to the sip information. To access the sip information, using the created SipDetails class. The existing interface change to set the SipDetails class as a parameter. Bug: b/238192079 Test: cts CtsTelephonyTestCases:RcsUceAdapterTest Test: atest UceControllerTest SubscribeCoordinatorTest SubscribeRequestTest UceRequestManagerTest Change-Id: Iadb98971b7b12911d079bc4a9c99f2cd7e7ee78e --- .../com/android/ims/rcs/uce/UceController.java | 12 ++--- .../ims/rcs/uce/eab/EabBulkCapabilityUpdater.java | 5 ++- .../rcs/uce/request/CapabilityRequestResponse.java | 34 ++++++++++++--- .../rcs/uce/request/OptionsRequestCoordinator.java | 4 +- .../ims/rcs/uce/request/SubscribeRequest.java | 32 +++----------- .../uce/request/SubscribeRequestCoordinator.java | 39 ++++++++++++----- .../ims/rcs/uce/request/UceRequestCoordinator.java | 51 ++++++++++++++++++++++ .../ims/rcs/uce/request/UceRequestManager.java | 8 ++-- .../com/android/ims/rcs/uce/UceControllerTest.java | 8 ++-- .../rcs/uce/request/SubscribeCoordinatorTest.java | 45 ++++++++++++++----- .../ims/rcs/uce/request/SubscribeRequestTest.java | 27 ++++++++---- .../ims/rcs/uce/request/UceRequestManagerTest.java | 9 ++-- 12 files changed, 191 insertions(+), 83 deletions(-) diff --git a/src/java/com/android/ims/rcs/uce/UceController.java b/src/java/com/android/ims/rcs/uce/UceController.java index 429b5518..aeab0611 100644 --- a/src/java/com/android/ims/rcs/uce/UceController.java +++ b/src/java/com/android/ims/rcs/uce/UceController.java @@ -635,14 +635,14 @@ public class UceController { if (uriList == null || uriList.isEmpty() || c == null) { logw("requestCapabilities: parameter is empty"); if (c != null) { - c.onError(RcsUceAdapter.ERROR_GENERIC_FAILURE, 0L); + c.onError(RcsUceAdapter.ERROR_GENERIC_FAILURE, 0L, null); } return; } if (isUnavailable()) { logw("requestCapabilities: controller is unavailable"); - c.onError(RcsUceAdapter.ERROR_GENERIC_FAILURE, 0L); + c.onError(RcsUceAdapter.ERROR_GENERIC_FAILURE, 0L, null); return; } @@ -655,7 +655,7 @@ public class UceController { long retryAfterMillis = deviceStateResult.getRequestRetryAfterMillis(); logw("requestCapabilities: The device is disallowed, deviceState= " + deviceState + ", errorCode=" + errorCode + ", retryAfterMillis=" + retryAfterMillis); - c.onError(errorCode, retryAfterMillis); + c.onError(errorCode, retryAfterMillis, null); return; } @@ -674,14 +674,14 @@ public class UceController { if (uri == null || c == null) { logw("requestAvailability: parameter is empty"); if (c != null) { - c.onError(RcsUceAdapter.ERROR_GENERIC_FAILURE, 0L); + c.onError(RcsUceAdapter.ERROR_GENERIC_FAILURE, 0L, null); } return; } if (isUnavailable()) { logw("requestAvailability: controller is unavailable"); - c.onError(RcsUceAdapter.ERROR_GENERIC_FAILURE, 0L); + c.onError(RcsUceAdapter.ERROR_GENERIC_FAILURE, 0L, null); return; } @@ -694,7 +694,7 @@ public class UceController { long retryAfterMillis = deviceStateResult.getRequestRetryAfterMillis(); logw("requestAvailability: The device is disallowed, deviceState= " + deviceState + ", errorCode=" + errorCode + ", retryAfterMillis=" + retryAfterMillis); - c.onError(errorCode, retryAfterMillis); + c.onError(errorCode, retryAfterMillis, null); return; } diff --git a/src/java/com/android/ims/rcs/uce/eab/EabBulkCapabilityUpdater.java b/src/java/com/android/ims/rcs/uce/eab/EabBulkCapabilityUpdater.java index b4406fdd..738a4fc8 100644 --- a/src/java/com/android/ims/rcs/uce/eab/EabBulkCapabilityUpdater.java +++ b/src/java/com/android/ims/rcs/uce/eab/EabBulkCapabilityUpdater.java @@ -37,6 +37,7 @@ import android.telephony.CarrierConfigManager; import android.telephony.ims.ImsManager; import android.telephony.ims.ImsRcsManager; import android.telephony.ims.RcsContactUceCapability; +import android.telephony.ims.SipDetails; import android.telephony.ims.aidl.IRcsUceControllerCallback; import android.util.Log; @@ -142,12 +143,12 @@ public final class EabBulkCapabilityUpdater { } @Override - public void onComplete() { + public void onComplete(SipDetails details) { Log.d(TAG, "onComplete"); } @Override - public void onError(int errorCode, long retryAfterMilliseconds) { + public void onError(int errorCode, long retryAfterMilliseconds, SipDetails details) { Log.d(TAG, "Refresh capabilities failed. Error code: " + errorCode + ", retryAfterMilliseconds: " + retryAfterMilliseconds); if (retryAfterMilliseconds != 0) { diff --git a/src/java/com/android/ims/rcs/uce/request/CapabilityRequestResponse.java b/src/java/com/android/ims/rcs/uce/request/CapabilityRequestResponse.java index 97371b8b..6da31301 100644 --- a/src/java/com/android/ims/rcs/uce/request/CapabilityRequestResponse.java +++ b/src/java/com/android/ims/rcs/uce/request/CapabilityRequestResponse.java @@ -16,11 +16,14 @@ package com.android.ims.rcs.uce.request; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.net.Uri; import android.telephony.ims.RcsContactTerminatedReason; import android.telephony.ims.RcsContactUceCapability; import android.telephony.ims.RcsUceAdapter; import android.telephony.ims.RcsUceAdapter.ErrorCode; +import android.telephony.ims.SipDetails; import android.telephony.ims.stub.RcsCapabilityExchangeImplBase; import android.telephony.ims.stub.RcsCapabilityExchangeImplBase.CommandCode; import android.text.TextUtils; @@ -85,6 +88,9 @@ public class CapabilityRequestResponse { // The collection to record whether the request contacts have received the capabilities updated. private Map mContactCapsReceived; + // The SIP detail information of the network response. + private Optional mSipDetails; + public CapabilityRequestResponse() { mRequestInternalError = Optional.empty(); mCommandError = Optional.empty(); @@ -99,6 +105,7 @@ public class CapabilityRequestResponse { mUpdatedCapabilityList = new ArrayList<>(); mRemoteCaps = new HashSet<>(); mContactCapsReceived = new HashMap<>(); + mSipDetails = Optional.empty(); } /** @@ -169,12 +176,20 @@ public class CapabilityRequestResponse { /** * Set the network response of this request which is sent by the network. */ - public synchronized void setNetworkResponseCode(int sipCode, String reasonPhrase, - int reasonHeaderCause, String reasonHeaderText) { - mNetworkRespSipCode = Optional.of(sipCode); - mReasonPhrase = Optional.ofNullable(reasonPhrase); - mReasonHeaderCause = Optional.of(reasonHeaderCause); - mReasonHeaderText = Optional.ofNullable(reasonHeaderText); + public synchronized void setSipDetails(@NonNull SipDetails details) { + setNetworkResponseCode(details.getResponseCode(), details.getResponsePhrase()); + if (details.getReasonHeaderCause() != 0) { + mReasonHeaderCause = Optional.of(details.getReasonHeaderCause()); + } else { + mReasonHeaderCause = Optional.empty(); + } + if (TextUtils.isEmpty(details.getReasonHeaderText())) { + mReasonHeaderText = Optional.empty(); + } else { + mReasonHeaderText = Optional.ofNullable(details.getReasonHeaderText()); + } + + mSipDetails = Optional.ofNullable(details); } // Get the sip code of the network response. @@ -238,6 +253,13 @@ public class CapabilityRequestResponse { return mRetryAfterMillis.orElse(0L); } + /** + * Retrieve the SIP information which received from the network. + */ + public Optional getSipDetails() { + return mSipDetails; + } + /** * Add the capabilities which are retrieved from the cache. */ diff --git a/src/java/com/android/ims/rcs/uce/request/OptionsRequestCoordinator.java b/src/java/com/android/ims/rcs/uce/request/OptionsRequestCoordinator.java index a2660931..b2db1788 100644 --- a/src/java/com/android/ims/rcs/uce/request/OptionsRequestCoordinator.java +++ b/src/java/com/android/ims/rcs/uce/request/OptionsRequestCoordinator.java @@ -315,7 +315,7 @@ public class OptionsRequestCoordinator extends UceRequestCoordinator { private void triggerCompletedCallback() { try { logd("triggerCompletedCallback"); - mCapabilitiesCallback.onComplete(); + mCapabilitiesCallback.onComplete(null); } catch (RemoteException e) { logw("triggerCompletedCallback exception: " + e); } finally { @@ -329,7 +329,7 @@ public class OptionsRequestCoordinator extends UceRequestCoordinator { private void triggerErrorCallback(int errorCode, long retryAfterMillis) { try { logd("triggerErrorCallback: errorCode=" + errorCode + ", retry=" + retryAfterMillis); - mCapabilitiesCallback.onError(errorCode, retryAfterMillis); + mCapabilitiesCallback.onError(errorCode, retryAfterMillis, null); } catch (RemoteException e) { logw("triggerErrorCallback exception: " + e); } finally { diff --git a/src/java/com/android/ims/rcs/uce/request/SubscribeRequest.java b/src/java/com/android/ims/rcs/uce/request/SubscribeRequest.java index bee71771..a306eb42 100644 --- a/src/java/com/android/ims/rcs/uce/request/SubscribeRequest.java +++ b/src/java/com/android/ims/rcs/uce/request/SubscribeRequest.java @@ -17,11 +17,13 @@ package com.android.ims.rcs.uce.request; import android.annotation.NonNull; +import android.annotation.Nullable; import android.net.Uri; import android.os.RemoteException; import android.telephony.ims.RcsContactTerminatedReason; import android.telephony.ims.RcsContactUceCapability; import android.telephony.ims.RcsUceAdapter; +import android.telephony.ims.SipDetails; import android.telephony.ims.aidl.ISubscribeResponseCallback; import android.telephony.ims.stub.RcsCapabilityExchangeImplBase.CommandCode; @@ -53,14 +55,8 @@ public class SubscribeRequest extends CapabilityRequest { SubscribeRequest.this.onCommandError(code); } @Override - public void onNetworkResponse(int code, String reason) { - SubscribeRequest.this.onNetworkResponse(code, reason); - } - @Override - public void onNetworkRespHeader(int code, String reasonPhrase, - int reasonHeaderCause, String reasonHeaderText) { - SubscribeRequest.this.onNetworkResponse(code, reasonPhrase, reasonHeaderCause, - reasonHeaderText); + public void onNetworkResponse(@NonNull SipDetails details) { + SubscribeRequest.this.onNetworkResponse(details); } @Override public void onNotifyCapabilitiesUpdate(List pidfXmls) { @@ -135,28 +131,14 @@ public class SubscribeRequest extends CapabilityRequest { } // Receive the network response callback which is triggered by ISubscribeResponseCallback. - private void onNetworkResponse(int sipCode, String reason) { - logd("onNetworkResponse: code=" + sipCode + ", reason=" + reason); - if (mIsFinished) { - logw("onNetworkResponse: request is already finished"); - return; - } - mRequestResponse.setNetworkResponseCode(sipCode, reason); - mRequestManagerCallback.notifyNetworkResponse(mCoordinatorId, mTaskId); - } + private void onNetworkResponse(@NonNull SipDetails details) { + logd("onNetworkResponse: sip details=" + details.toString()); - // Receive the network response callback which is triggered by ISubscribeResponseCallback. - private void onNetworkResponse(int sipCode, String reasonPhrase, - int reasonHeaderCause, String reasonHeaderText) { - logd("onNetworkResponse: code=" + sipCode + ", reasonPhrase=" + reasonPhrase + - ", reasonHeaderCause=" + reasonHeaderCause + - ", reasonHeaderText=" + reasonHeaderText); if (mIsFinished) { logw("onNetworkResponse: request is already finished"); return; } - mRequestResponse.setNetworkResponseCode(sipCode, reasonPhrase, reasonHeaderCause, - reasonHeaderText); + mRequestResponse.setSipDetails(details); mRequestManagerCallback.notifyNetworkResponse(mCoordinatorId, mTaskId); } diff --git a/src/java/com/android/ims/rcs/uce/request/SubscribeRequestCoordinator.java b/src/java/com/android/ims/rcs/uce/request/SubscribeRequestCoordinator.java index 2d1736c6..26143f94 100644 --- a/src/java/com/android/ims/rcs/uce/request/SubscribeRequestCoordinator.java +++ b/src/java/com/android/ims/rcs/uce/request/SubscribeRequestCoordinator.java @@ -18,10 +18,12 @@ package com.android.ims.rcs.uce.request; import static android.telephony.ims.stub.RcsCapabilityExchangeImplBase.COMMAND_CODE_GENERIC_FAILURE; +import android.annotation.Nullable; import android.net.Uri; import android.os.RemoteException; import android.telephony.ims.RcsContactUceCapability; import android.telephony.ims.RcsUceAdapter; +import android.telephony.ims.SipDetails; import android.telephony.ims.aidl.IRcsUceControllerCallback; import com.android.ims.rcs.uce.UceDeviceState.DeviceStateResult; @@ -111,21 +113,25 @@ public class SubscribeRequestCoordinator extends UceRequestCoordinator { private static final RequestResultCreator sNetworkRespErrorCreator = (taskId, response, requestMgrCallback) -> { DeviceStateResult deviceState = requestMgrCallback.getDeviceState(); + SipDetails details = response.getSipDetails().orElse(null); if (deviceState.isRequestForbidden()) { int errorCode = deviceState.getErrorCode().orElse(RcsUceAdapter.ERROR_FORBIDDEN); long retryAfter = deviceState.getRequestRetryAfterMillis(); - return RequestResult.createFailedResult(taskId, errorCode, retryAfter); + return RequestResult.createFailedResult(taskId, errorCode, retryAfter, details); } else { int errorCode = CapabilityRequestResponse.getCapabilityErrorFromSipCode(response); long retryAfter = response.getRetryAfterMillis(); - return RequestResult.createFailedResult(taskId, errorCode, retryAfter); + return RequestResult.createFailedResult(taskId, errorCode, retryAfter, details); } }; // The RequestResult creator of the network response is not 200 OK, however, we can to treat // it as a successful result and finish the request private static final RequestResultCreator sNetworkRespSuccessfulCreator = (taskId, response, - requestMgrCallback) -> RequestResult.createSuccessResult(taskId); + requestMgrCallback) -> { + SipDetails detail = response.getSipDetails().orElse(null); + return RequestResult.createSuccessResult(taskId, detail); + }; // The RequestResult creator of the request terminated. private static final RequestResultCreator sTerminatedCreator = (taskId, response, @@ -134,6 +140,7 @@ public class SubscribeRequestCoordinator extends UceRequestCoordinator { TerminatedResult terminatedResult = SubscriptionTerminatedHelper.getAnalysisResult( response.getTerminatedReason(), response.getRetryAfterMillis(), response.haveAllRequestCapsUpdatedBeenReceived()); + SipDetails details = response.getSipDetails().orElse(null); if (terminatedResult.getErrorCode().isPresent()) { // If the terminated error code is present, it means that the request is failed. int errorCode = terminatedResult.getErrorCode().get(); @@ -143,9 +150,9 @@ public class SubscribeRequestCoordinator extends UceRequestCoordinator { // If the network response is failed or the retryAfter is not 0, this request is failed. long retryAfterMillis = response.getRetryAfterMillis(); int errorCode = CapabilityRequestResponse.getCapabilityErrorFromSipCode(response); - return RequestResult.createFailedResult(taskId, errorCode, retryAfterMillis); + return RequestResult.createFailedResult(taskId, errorCode, retryAfterMillis, details); } else { - return RequestResult.createSuccessResult(taskId); + return RequestResult.createSuccessResult(taskId, details); } }; @@ -540,14 +547,23 @@ public class SubscribeRequestCoordinator extends UceRequestCoordinator { .max(Comparator.comparingLong(result -> result.getRetryMillis().orElse(-1L))); + Optional optDebugInfoResult = mFinishedRequests.values().stream() + .filter(result -> !result.getSipDetails().isEmpty()) + .findFirst(); + + SipDetails details = null; + if (optDebugInfoResult.isPresent()) { + RequestResult result = optDebugInfoResult.get(); + details = result.getSipDetails().orElse(null); + } // Trigger the callback if (optRequestResult.isPresent()) { RequestResult result = optRequestResult.get(); int errorCode = result.getErrorCode().orElse(DEFAULT_ERROR_CODE); long retryAfter = result.getRetryMillis().orElse(0L); - triggerErrorCallback(errorCode, retryAfter); + triggerErrorCallback(errorCode, retryAfter, details); } else { - triggerCompletedCallback(); + triggerCompletedCallback(details); } // Notify UceRequestManager to remove this instance from the collection. @@ -574,10 +590,10 @@ public class SubscribeRequestCoordinator extends UceRequestCoordinator { /** * Trigger the onComplete callback to notify the request is completed. */ - private void triggerCompletedCallback() { + private void triggerCompletedCallback(@Nullable SipDetails details) { try { logd("triggerCompletedCallback"); - mCapabilitiesCallback.onComplete(); + mCapabilitiesCallback.onComplete(details); } catch (RemoteException e) { logw("triggerCompletedCallback exception: " + e); } finally { @@ -588,10 +604,11 @@ public class SubscribeRequestCoordinator extends UceRequestCoordinator { /** * Trigger the onError callback to notify the request is failed. */ - private void triggerErrorCallback(int errorCode, long retryAfterMillis) { + private void triggerErrorCallback(int errorCode, long retryAfterMillis, + @Nullable SipDetails details) { try { logd("triggerErrorCallback: errorCode=" + errorCode + ", retry=" + retryAfterMillis); - mCapabilitiesCallback.onError(errorCode, retryAfterMillis); + mCapabilitiesCallback.onError(errorCode, retryAfterMillis, details); } catch (RemoteException e) { logw("triggerErrorCallback exception: " + e); } finally { diff --git a/src/java/com/android/ims/rcs/uce/request/UceRequestCoordinator.java b/src/java/com/android/ims/rcs/uce/request/UceRequestCoordinator.java index eea4fbe3..5d3a35da 100644 --- a/src/java/com/android/ims/rcs/uce/request/UceRequestCoordinator.java +++ b/src/java/com/android/ims/rcs/uce/request/UceRequestCoordinator.java @@ -20,6 +20,7 @@ import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.telephony.ims.RcsUceAdapter; +import android.telephony.ims.SipDetails; import android.util.Log; import com.android.ims.rcs.uce.request.UceRequestManager.RequestManagerCallback; @@ -134,6 +135,15 @@ public abstract class UceRequestCoordinator { return new RequestResult(taskId); } + /** + * Create a RequestResult that successfully completes the request. + * @param taskId the task id of the UceRequest + * @param details The SIP information related to this request. + */ + public static RequestResult createSuccessResult(long taskId, @Nullable SipDetails details) { + return new RequestResult(taskId, details); + } + /** * Create a RequestResult for the failed request. * @param taskId the task id of the UceRequest @@ -144,29 +154,66 @@ public abstract class UceRequestCoordinator { return new RequestResult(taskId, errorCode, retry); } + /** + * Create a RequestResult for the failed request. + * @param taskId the task id of the UceRequest + * @param errorCode the error code of the failed request + * @param retry When the request can be retried. + * @param details The SIP information related to this request. + */ + public static RequestResult createFailedResult(long taskId, int errorCode, long retry, + @Nullable SipDetails details) { + return new RequestResult(taskId, errorCode, retry, details); + } + private final Long mTaskId; private final Boolean mIsSuccess; private final Optional mErrorCode; private final Optional mRetryMillis; + private final Optional mSipDetails; /** * The private constructor for the successful request. */ private RequestResult(long taskId) { + this(taskId, null); + } + + /** + * The private constructor for the successful request. + */ + private RequestResult(long taskId, SipDetails details) { mTaskId = taskId; mIsSuccess = true; mErrorCode = Optional.empty(); mRetryMillis = Optional.empty(); + if (details == null) { + mSipDetails = Optional.empty(); + } else { + mSipDetails = Optional.ofNullable(details); + } } /** * The private constructor for the failed request. */ private RequestResult(long taskId, int errorCode, long retryMillis) { + this(taskId, errorCode, retryMillis, null); + } + + /** + * The private constructor for the failed request. + */ + private RequestResult(long taskId, int errorCode, long retryMillis, SipDetails details) { mTaskId = taskId; mIsSuccess = false; mErrorCode = Optional.of(errorCode); mRetryMillis = Optional.of(retryMillis); + if (details == null) { + mSipDetails = Optional.empty(); + } else { + mSipDetails = Optional.ofNullable(details); + } } public long getTaskId() { @@ -184,6 +231,10 @@ public abstract class UceRequestCoordinator { public Optional getRetryMillis() { return mRetryMillis; } + + public Optional getSipDetails() { + return mSipDetails; + } } // The default capability error code. diff --git a/src/java/com/android/ims/rcs/uce/request/UceRequestManager.java b/src/java/com/android/ims/rcs/uce/request/UceRequestManager.java index 85908f0c..8ff39c1b 100644 --- a/src/java/com/android/ims/rcs/uce/request/UceRequestManager.java +++ b/src/java/com/android/ims/rcs/uce/request/UceRequestManager.java @@ -478,7 +478,7 @@ public class UceRequestManager { public void sendCapabilityRequest(List uriList, boolean skipFromCache, IRcsUceControllerCallback callback) throws RemoteException { if (mIsDestroyed) { - callback.onError(RcsUceAdapter.ERROR_GENERIC_FAILURE, 0L); + callback.onError(RcsUceAdapter.ERROR_GENERIC_FAILURE, 0L, null); return; } sendRequestInternal(UceRequest.REQUEST_TYPE_CAPABILITY, uriList, skipFromCache, callback); @@ -490,7 +490,7 @@ public class UceRequestManager { public void sendAvailabilityRequest(Uri uri, IRcsUceControllerCallback callback) throws RemoteException { if (mIsDestroyed) { - callback.onError(RcsUceAdapter.ERROR_GENERIC_FAILURE, 0L); + callback.onError(RcsUceAdapter.ERROR_GENERIC_FAILURE, 0L, null); return; } sendRequestInternal(UceRequest.REQUEST_TYPE_AVAILABILITY, @@ -511,7 +511,7 @@ public class UceRequestManager { } if (nonCachedUris.isEmpty()) { logd("sendRequestInternal: shortcut complete, sending success result"); - callback.onComplete(); + callback.onComplete(null); return; } } @@ -525,7 +525,7 @@ public class UceRequestManager { if (requestCoordinator == null) { logw("sendRequestInternal: Neither Presence nor OPTIONS are supported"); - callback.onError(RcsUceAdapter.ERROR_NOT_ENABLED, 0L); + callback.onError(RcsUceAdapter.ERROR_NOT_ENABLED, 0L, null); return; } diff --git a/tests/src/com/android/ims/rcs/uce/UceControllerTest.java b/tests/src/com/android/ims/rcs/uce/UceControllerTest.java index 021a7c10..79702ed5 100644 --- a/tests/src/com/android/ims/rcs/uce/UceControllerTest.java +++ b/tests/src/com/android/ims/rcs/uce/UceControllerTest.java @@ -147,7 +147,7 @@ public class UceControllerTest extends ImsTestBase { List uriList = new ArrayList<>(); uceController.requestCapabilities(uriList, mCapabilitiesCallback); - verify(mCapabilitiesCallback).onError(RcsUceAdapter.ERROR_GENERIC_FAILURE, 0L); + verify(mCapabilitiesCallback).onError(RcsUceAdapter.ERROR_GENERIC_FAILURE, 0L, null); verify(mTaskManager, never()).sendCapabilityRequest(any(), eq(false), any()); } @@ -164,7 +164,7 @@ public class UceControllerTest extends ImsTestBase { uriList.add(Uri.fromParts("sip", "test", null)); uceController.requestCapabilities(uriList, mCapabilitiesCallback); - verify(mCapabilitiesCallback).onError(RcsUceAdapter.ERROR_FORBIDDEN, 0L); + verify(mCapabilitiesCallback).onError(RcsUceAdapter.ERROR_FORBIDDEN, 0L, null); verify(mTaskManager, never()).sendCapabilityRequest(any(), eq(false), any()); } @@ -194,7 +194,7 @@ public class UceControllerTest extends ImsTestBase { Uri contact = Uri.fromParts("sip", "test", null); uceController.requestAvailability(contact, mCapabilitiesCallback); - verify(mCapabilitiesCallback).onError(RcsUceAdapter.ERROR_GENERIC_FAILURE, 0L); + verify(mCapabilitiesCallback).onError(RcsUceAdapter.ERROR_GENERIC_FAILURE, 0L, null); verify(mTaskManager, never()).sendAvailabilityRequest(any(), any()); } @@ -210,7 +210,7 @@ public class UceControllerTest extends ImsTestBase { Uri contact = Uri.fromParts("sip", "test", null); uceController.requestAvailability(contact, mCapabilitiesCallback); - verify(mCapabilitiesCallback).onError(RcsUceAdapter.ERROR_FORBIDDEN, 0L); + verify(mCapabilitiesCallback).onError(RcsUceAdapter.ERROR_FORBIDDEN, 0L, null); verify(mTaskManager, never()).sendCapabilityRequest(any(), eq(false), any()); } diff --git a/tests/src/com/android/ims/rcs/uce/request/SubscribeCoordinatorTest.java b/tests/src/com/android/ims/rcs/uce/request/SubscribeCoordinatorTest.java index 94ee3edb..2c0042ea 100644 --- a/tests/src/com/android/ims/rcs/uce/request/SubscribeCoordinatorTest.java +++ b/tests/src/com/android/ims/rcs/uce/request/SubscribeCoordinatorTest.java @@ -25,14 +25,11 @@ import static com.android.ims.rcs.uce.request.UceRequestCoordinator.REQUEST_UPDA import static com.android.ims.rcs.uce.request.UceRequestCoordinator.REQUEST_UPDATE_RESOURCE_TERMINATED; import static com.android.ims.rcs.uce.request.UceRequestCoordinator.REQUEST_UPDATE_TERMINATED; -import static java.lang.Boolean.TRUE; - import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.never; @@ -41,6 +38,7 @@ import static org.mockito.Mockito.verify; import android.net.Uri; import android.telephony.ims.RcsContactPresenceTuple; import android.telephony.ims.RcsContactUceCapability; +import android.telephony.ims.SipDetails; import android.telephony.ims.aidl.IRcsUceControllerCallback; import androidx.test.ext.junit.runners.AndroidJUnit4; @@ -53,18 +51,19 @@ import com.android.ims.rcs.uce.eab.EabCapabilityResult; import com.android.ims.rcs.uce.request.UceRequestCoordinator.RequestResult; import com.android.ims.rcs.uce.request.UceRequestManager.RequestManagerCallback; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Optional; - import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Optional; + @RunWith(AndroidJUnit4.class) public class SubscribeCoordinatorTest extends ImsTestBase { @@ -128,6 +127,17 @@ public class SubscribeCoordinatorTest extends ImsTestBase { @Test @SmallTest public void testRequestNetworkRespSuccess() throws Exception { + int responseCode = 200; + String responsePhrase = "OK"; + int reasonHdrCause = 1; + String reasonHdrText = "reasonText"; + int cSeq = 10; + String callId = "TestCallId"; + SipDetails details = new SipDetails.Builder(SipDetails.METHOD_SUBSCRIBE).setCSeq(cSeq) + .setSipResponseCode(responseCode, responsePhrase).setCallId(callId) + .setSipResponseReasonHeader(reasonHdrCause, reasonHdrText).build(); + doReturn(Optional.ofNullable(details)).when(mResponse).getSipDetails(); + SubscribeRequestCoordinator coordinator = getSubscribeCoordinator(); doReturn(true).when(mResponse).isNetworkResponseOK(); doReturn(Optional.of(200)).when(mResponse).getNetworkRespSipCode(); @@ -139,8 +149,21 @@ public class SubscribeCoordinatorTest extends ImsTestBase { assertEquals(1, requestList.size()); assertTrue(resultList.isEmpty()); - verify(mUceStatsWriter).setSubscribeResponse(eq(mSubId), eq(mTaskId), eq(200)); + Iterator requestResults = resultList.iterator(); + while (requestResults.hasNext()) { + RequestResult req = requestResults.next(); + SipDetails receivedInfo = req.getSipDetails().orElse(null); + assertNotNull(receivedInfo); + assertEquals(SipDetails.METHOD_SUBSCRIBE, receivedInfo.getMethod()); + assertEquals(cSeq, receivedInfo.getCSeq()); + assertEquals(responseCode, receivedInfo.getResponseCode()); + assertEquals(responsePhrase, receivedInfo.getResponsePhrase()); + assertEquals(reasonHdrCause, receivedInfo.getReasonHeaderCause()); + assertEquals(reasonHdrText, receivedInfo.getReasonHeaderText()); + assertEquals(callId, receivedInfo.getCallId()); + } + verify(mUceStatsWriter).setSubscribeResponse(eq(mSubId), eq(mTaskId), eq(200)); verify(mRequest, never()).onFinish(); } diff --git a/tests/src/com/android/ims/rcs/uce/request/SubscribeRequestTest.java b/tests/src/com/android/ims/rcs/uce/request/SubscribeRequestTest.java index b4f9cca4..543ad6d2 100644 --- a/tests/src/com/android/ims/rcs/uce/request/SubscribeRequestTest.java +++ b/tests/src/com/android/ims/rcs/uce/request/SubscribeRequestTest.java @@ -19,7 +19,9 @@ package com.android.ims.rcs.uce.request; import static android.telephony.ims.stub.RcsCapabilityExchangeImplBase.COMMAND_CODE_NOT_SUPPORTED; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.never; @@ -28,6 +30,7 @@ import static org.mockito.Mockito.verify; import android.net.Uri; import android.telephony.ims.RcsContactTerminatedReason; import android.telephony.ims.RcsUceAdapter; +import android.telephony.ims.SipDetails; import android.telephony.ims.aidl.ISubscribeResponseCallback; import androidx.test.ext.junit.runners.AndroidJUnit4; @@ -36,10 +39,6 @@ import androidx.test.filters.SmallTest; import com.android.ims.ImsTestBase; import com.android.ims.rcs.uce.presence.subscribe.SubscribeController; import com.android.ims.rcs.uce.request.UceRequestManager.RequestManagerCallback; -import com.android.ims.rcs.uce.util.NetworkSipCode; - -import java.util.ArrayList; -import java.util.List; import org.junit.After; import org.junit.Before; @@ -47,6 +46,9 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; +import java.util.ArrayList; +import java.util.List; + @RunWith(AndroidJUnit4.class) public class SubscribeRequestTest extends ImsTestBase { @@ -88,6 +90,7 @@ public class SubscribeRequestTest extends ImsTestBase { subscribeRequest.requestCapabilities(uriList); verify(mRequestResponse).setRequestInternalError(RcsUceAdapter.ERROR_GENERIC_FAILURE); + verify(mRequestResponse, never()).setSipDetails(any()); verify(mRequestManagerCallback).notifyRequestError(eq(mCoordId), anyLong()); verify(mSubscribeController, never()).requestCapabilities(any(), any()); } @@ -101,6 +104,7 @@ public class SubscribeRequestTest extends ImsTestBase { callback.onCommandError(COMMAND_CODE_NOT_SUPPORTED); verify(mRequestResponse).setCommandError(COMMAND_CODE_NOT_SUPPORTED); + verify(mRequestResponse, never()).setSipDetails(any(SipDetails.class)); verify(mRequestManagerCallback).notifyCommandError(eq(mCoordId), anyLong()); } @@ -109,12 +113,16 @@ public class SubscribeRequestTest extends ImsTestBase { public void testNetworkResponse() throws Exception { SubscribeRequest subscribeRequest = getSubscribeRequest(); - int sipCode = NetworkSipCode.SIP_CODE_FORBIDDEN; - String reason = "forbidden"; + int sipCode = 200; + String reason = "OK"; + SipDetails details = new SipDetails.Builder(SipDetails.METHOD_SUBSCRIBE).setCSeq(1) + .setSipResponseCode(sipCode, reason).setCallId("callId").build(); + ISubscribeResponseCallback callback = subscribeRequest.getResponseCallback(); - callback.onNetworkResponse(sipCode, reason); + callback.onNetworkResponse(details); - verify(mRequestResponse).setNetworkResponseCode(sipCode, reason); + verify(mRequestResponse).setSipDetails(eq(details)); + verify(mRequestResponse, never()).setNetworkResponseCode(anyInt(), anyString()); verify(mRequestManagerCallback).notifyNetworkResponse(eq(mCoordId), anyLong()); } @@ -130,6 +138,7 @@ public class SubscribeRequestTest extends ImsTestBase { callback.onResourceTerminated(list); verify(mRequestResponse).addTerminatedResource(list); + verify(mRequestResponse, never()).setSipDetails(any()); verify(mRequestManagerCallback).notifyResourceTerminated(eq(mCoordId), anyLong()); } @@ -144,6 +153,7 @@ public class SubscribeRequestTest extends ImsTestBase { callback.onNotifyCapabilitiesUpdate(pidfXml); verify(mRequestResponse).addUpdatedCapabilities(any()); + verify(mRequestResponse, never()).setSipDetails(any()); verify(mRequestManagerCallback).notifyCapabilitiesUpdated(eq(mCoordId), anyLong()); } @@ -159,6 +169,7 @@ public class SubscribeRequestTest extends ImsTestBase { callback.onTerminated(reason, retryAfterMillis); verify(mRequestResponse).setTerminated(reason, retryAfterMillis); + verify(mRequestResponse, never()).setSipDetails(any()); verify(mRequestManagerCallback).notifyTerminated(eq(mCoordId), anyLong()); } diff --git a/tests/src/com/android/ims/rcs/uce/request/UceRequestManagerTest.java b/tests/src/com/android/ims/rcs/uce/request/UceRequestManagerTest.java index b380eac9..fa8214ed 100644 --- a/tests/src/com/android/ims/rcs/uce/request/UceRequestManagerTest.java +++ b/tests/src/com/android/ims/rcs/uce/request/UceRequestManagerTest.java @@ -31,6 +31,7 @@ import static com.android.ims.rcs.uce.request.UceRequestCoordinator.REQUEST_UPDA import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; @@ -133,7 +134,7 @@ public class UceRequestManagerTest extends ImsTestBase { waitForHandlerAction(handler, 500L); verify(mUceRequest, never()).executeRequest(); - verify(mCapabilitiesCallback).onError(RcsUceAdapter.ERROR_GENERIC_FAILURE, 0L); + verify(mCapabilitiesCallback).onError(RcsUceAdapter.ERROR_GENERIC_FAILURE, 0L, null); } /** @@ -164,7 +165,7 @@ public class UceRequestManagerTest extends ImsTestBase { verify(mCapabilitiesCallback).onCapabilitiesReceived( cachedNumbers.stream().map(EabCapabilityResult::getContactCapabilities).collect( Collectors.toList())); - verify(mCapabilitiesCallback).onComplete(); + verify(mCapabilitiesCallback).onComplete(eq(null)); // The cache should have been hit, so no network requests should have been generated. verify(mRequestRepository, never()).addRequestCoordinator(any()); } @@ -196,7 +197,7 @@ public class UceRequestManagerTest extends ImsTestBase { waitForHandlerAction(handler, 500L); // Extract caps from EabCapabilityResult and ensure the Lists match. verify(mCapabilitiesCallback, never()).onCapabilitiesReceived(any()); - verify(mCapabilitiesCallback, never()).onComplete(); + verify(mCapabilitiesCallback, never()).onComplete(any()); // A network request should have been generated for the expired contact. verify(mRequestRepository).addRequestCoordinator(any()); } @@ -240,7 +241,7 @@ public class UceRequestManagerTest extends ImsTestBase { // Extract caps from EabCapabilityResult and ensure the Lists match. verify(mCapabilitiesCallback).onCapabilitiesReceived( Collections.singletonList(cachedItem.getContactCapabilities())); - verify(mCapabilitiesCallback, never()).onComplete(); + verify(mCapabilitiesCallback, never()).onComplete(any()); // The cache should have been hit, but there was also entry that was not in the cache, so // ensure that is requested. verify(mRequestRepository).addRequestCoordinator(any()); -- cgit v1.2.3 From a63ff75dc8f120c95e235b1a851c96b6b39f3b73 Mon Sep 17 00:00:00 2001 From: Helen Date: Sat, 3 Dec 2022 19:31:15 +0000 Subject: Add a new system Api for ANBR - callSessionSendAnbrQuery - callSessionNotifyAnbr Bug: 259254356 Test: Build Change-Id: I98f6d2f88d128a82640148d4fc783b9f2eb60374 --- src/java/com/android/ims/ImsCall.java | 55 +++++++++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 3 deletions(-) diff --git a/src/java/com/android/ims/ImsCall.java b/src/java/com/android/ims/ImsCall.java index 06230a16..29f6acd4 100755 --- a/src/java/com/android/ims/ImsCall.java +++ b/src/java/com/android/ims/ImsCall.java @@ -537,6 +537,22 @@ public class ImsCall implements ICall { public void onCallSessionRtpHeaderExtensionsReceived(ImsCall imsCall, @NonNull Set rtpHeaderExtensionData) { } + + /** + * Access Network Bitrate Recommendation Query (ANBRQ), see 3GPP TS 26.114. + * This API triggers radio to send ANBRQ message to the access network to query the + * desired bitrate. + * + * @param imsCall The ImsCall the data was received on. + * @param mediaType MediaType is used to identify media stream such as audio or video. + * @param direction Direction of this packet stream (e.g. uplink or downlink). + * @param bitsPerSecond This value is the bitrate requested by the other party UE through + * RTP CMR, RTCPAPP or TMMBR, and ImsStack converts this value to the MAC bitrate + * (defined in TS36.321, range: 0 ~ 8000 kbit/s). + */ + public void onCallSessionSendAnbrQuery(ImsCall imsCall, int mediaType, int direction, + int bitsPerSecond) { + } } // List of update operation for IMS call control @@ -886,11 +902,25 @@ public class ImsCall implements ICall { } /** - * Gets the specified property of this call. + * Deliver the bitrate for the indicated media type, direction and bitrate to the upper layer. * - * @param name key to get the extra call information defined in {@link ImsCallProfile} - * @return the extra call information as string + * @param mediaType MediaType is used to identify media stream such as audio or video. + * @param direction Direction of this packet stream (e.g. uplink or downlink). + * @param bitsPerSecond This value is the bitrate received from the NW through the Recommended + * bitrate MAC Control Element message and ImsStack converts this value from MAC bitrate + * to audio/video codec bitrate (defined in TS26.114). + * @hide */ + public void callSessionNotifyAnbr(int mediaType, int direction, int bitsPerSecond) { + synchronized(mLockObj) { + if (mSession != null) { + mSession.callSessionNotifyAnbr(mediaType, direction, bitsPerSecond); + } else { + logi("callSessionNotifyAnbr : session - null"); + } + } + } + public String getCallExtra(String name) throws ImsException { // Lookup the cache @@ -3491,6 +3521,25 @@ public class ImsCall implements ICall { } } } + + @Override + public void callSessionSendAnbrQuery(int mediaType, int direction, int bitsPerSecond) { + ImsCall.Listener listener; + + logi("callSessionSendAnbrQuery in ImsCall"); + synchronized (ImsCall.this) { + listener = mListener; + } + + if (listener != null) { + try { + listener.onCallSessionSendAnbrQuery(ImsCall.this, mediaType, + direction, bitsPerSecond); + } catch (Throwable t) { + loge("callSessionSendAnbrQuery:: ", t); + } + } + } } /** -- cgit v1.2.3 From a0118dbc82791a5eadf410d86d4d9ea7492d7031 Mon Sep 17 00:00:00 2001 From: Hyunho Date: Tue, 6 Dec 2022 11:29:01 +0000 Subject: If only RCS or MMTEL is unregistered, send a modify PUBLISH request When RCS or MMTEL is unregistered, send a modify PUBLISH request message even if the associated URI has not changed. When RCS or MMTEL change from Unregistered to Unregistered, the registration status does not change. In this case, the modify PUBLISH request is sent depending on whether the associated URI has been changed. Bug: b/235973951 Test: atest DeviceCapabilityListenerTest Test: TMO Live network. The RCS and MMTEL are registered but the associated URI of RCS is not set. After that, RCS will be unregistered. Verified that the modify PUBLISH request has been sent to the netowrk. Change-Id: I96b565c15f11ee1083b56db29971ddee930d7e64 --- .../uce/presence/publish/DeviceCapabilityInfo.java | 5 +++- .../presence/publish/DeviceCapabilityListener.java | 20 +++++++++------- .../publish/DeviceCapabilityListenerTest.java | 28 ++++++++++++++++++++++ 3 files changed, 43 insertions(+), 10 deletions(-) diff --git a/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityInfo.java b/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityInfo.java index 4dd76be6..0c8515ba 100644 --- a/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityInfo.java +++ b/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityInfo.java @@ -177,14 +177,17 @@ public class DeviceCapabilityInfo { /** * Update the status that IMS MMTEL is unregistered. */ - public synchronized void updateImsMmtelUnregistered() { + public synchronized boolean updateImsMmtelUnregistered() { logi("IMS MMTEL unregistered: original state=" + mMmtelRegistered); + boolean changed = false; if (mMmtelRegistered) { mMmtelRegistered = false; + changed = true; } mMmtelNetworkRegType = AccessNetworkConstants.TRANSPORT_TYPE_INVALID; mLastSuccessfulCapabilities.clear(); mPendingPublishCapabilities = null; + return changed; } /** diff --git a/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListener.java b/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListener.java index 9874fdb3..b824aa08 100644 --- a/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListener.java +++ b/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListener.java @@ -489,7 +489,7 @@ public class DeviceCapabilityListener { public void onSubscriberAssociatedUriChanged(Uri[] uris) { synchronized (mLock) { logi("onRcsSubscriberAssociatedUriChanged"); - handleRcsSubscriberAssociatedUriChanged(uris); + handleRcsSubscriberAssociatedUriChanged(uris, false); } } }; @@ -520,7 +520,7 @@ public class DeviceCapabilityListener { public void onSubscriberAssociatedUriChanged(Uri[] uris) { synchronized (mLock) { logi("onMmTelSubscriberAssociatedUriChanged"); - handleMmTelSubscriberAssociatedUriChanged(uris); + handleMmTelSubscriberAssociatedUriChanged(uris, false); } } }; @@ -599,9 +599,9 @@ public class DeviceCapabilityListener { * This method is called when the MMTEL is unregistered. */ private void handleImsMmtelUnregistered() { - mCapabilityInfo.updateImsMmtelUnregistered(); + boolean hasChanged = mCapabilityInfo.updateImsMmtelUnregistered(); // When the MMTEL is unregistered, the mmtel associated uri should be cleared. - handleMmTelSubscriberAssociatedUriChanged(null); + handleMmTelSubscriberAssociatedUriChanged(null, hasChanged); // If the RCS is already unregistered, it informs that the IMS is unregistered. if (mCapabilityInfo.isImsRegistered() == false) { @@ -612,12 +612,13 @@ public class DeviceCapabilityListener { /* * This method is called when the MMTEL associated uri has changed. */ - private void handleMmTelSubscriberAssociatedUriChanged(Uri[] uris) { + private void handleMmTelSubscriberAssociatedUriChanged(Uri[] uris, boolean regiChanged) { Uri originalUri = mCapabilityInfo.getMmtelAssociatedUri(); mCapabilityInfo.updateMmTelAssociatedUri(uris); Uri currentUri = mCapabilityInfo.getMmtelAssociatedUri(); - boolean hasChanged = !(Objects.equals(originalUri, currentUri)); + boolean hasChanged = regiChanged || !(Objects.equals(originalUri, currentUri)); + logi("handleMmTelSubscriberAssociatedUriChanged: hasChanged=" + hasChanged); // Send internal request to send a modification PUBLISH if the MMTEL or RCS is registered. @@ -651,7 +652,7 @@ public class DeviceCapabilityListener { private void handleImsRcsUnregistered() { boolean hasChanged = mCapabilityInfo.updateImsRcsUnregistered(); // When the RCS is unregistered, the rcs associated uri should be cleared. - handleRcsSubscriberAssociatedUriChanged(null); + handleRcsSubscriberAssociatedUriChanged(null, hasChanged); // If the MMTEL is already unregistered, it informs that the IMS is unregistered. if (mCapabilityInfo.isImsRegistered() == false) { mHandler.sendImsUnregisteredMessage(); @@ -661,12 +662,13 @@ public class DeviceCapabilityListener { /* * This method is called when the RCS associated uri has changed. */ - private void handleRcsSubscriberAssociatedUriChanged(Uri[] uris) { + private void handleRcsSubscriberAssociatedUriChanged(Uri[] uris, boolean regiChanged) { Uri originalUri = mCapabilityInfo.getRcsAssociatedUri(); mCapabilityInfo.updateRcsAssociatedUri(uris); Uri currentUri = mCapabilityInfo.getRcsAssociatedUri(); - boolean hasChanged = !(Objects.equals(originalUri, currentUri)); + boolean hasChanged = regiChanged || !(Objects.equals(originalUri, currentUri)); + logi("handleRcsSubscriberAssociatedUriChanged: hasChanged=" + hasChanged); // Send internal request to send a modification PUBLISH if the MMTEL or RCS is registered. diff --git a/tests/src/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListenerTest.java b/tests/src/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListenerTest.java index 6b726740..4b3caeb4 100644 --- a/tests/src/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListenerTest.java +++ b/tests/src/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListenerTest.java @@ -279,6 +279,34 @@ public class DeviceCapabilityListenerTest extends ImsTestBase { verify(mCallback).updateImsUnregistered(); } + @Test + @SmallTest + public void testUnregisterRcsOnlyFromImsRegistration() throws Exception { + DeviceCapabilityListener deviceCapListener = createDeviceCapabilityListener(); + deviceCapListener.setImsCallbackRegistered(true); + Handler handler = deviceCapListener.getHandler(); + + // set the Ims is registered + doReturn(true).when(mDeviceCapability).isImsRegistered(); + ImsReasonInfo info = new ImsReasonInfo(ImsReasonInfo.CODE_LOCAL_NOT_REGISTERED, -1, ""); + // RCS unregistered + RegistrationCallback rcsRegiCallback = deviceCapListener.mRcsRegistrationCallback; + + doReturn(true).when(mDeviceCapability).updateImsRcsUnregistered(); + // RCS is unregistered but MMTEL is registered. + doReturn(true).when(mDeviceCapability).isImsRegistered(); + rcsRegiCallback.onUnregistered(info); + + waitForHandlerActionDelayed(handler, HANDLER_WAIT_TIMEOUT_MS, HANDLER_SENT_DELAY_MS); + + verify(mDeviceCapability).updateImsRcsUnregistered(); + // Only RCS unregistered. Verify the request of the modify publish is sent. + verify(mCallback).requestPublishFromInternal( + PublishController.PUBLISH_TRIGGER_RCS_URI_CHANGE); + + // Only RCS unregistered. Verify do not send ImsUnregistered. + verify(mCallback, never()).updateImsUnregistered(); + } private DeviceCapabilityListener createDeviceCapabilityListener() { DeviceCapabilityListener deviceCapListener = new DeviceCapabilityListener(mContext, -- cgit v1.2.3 From 56127f65b0df21518a6d2ba836a53e1c6c402271 Mon Sep 17 00:00:00 2001 From: Hyunho Date: Tue, 6 Dec 2022 11:29:01 +0000 Subject: If only RCS or MMTEL is unregistered, send a modify PUBLISH request When RCS or MMTEL is unregistered, send a modify PUBLISH request message even if the associated URI has not changed. When RCS or MMTEL change from Unregistered to Unregistered, the registration status does not change. In this case, the modify PUBLISH request is sent depending on whether the associated URI has been changed. Bug: b/235973951 Test: atest DeviceCapabilityListenerTest Test: TMO Live network. The RCS and MMTEL are registered but the associated URI of RCS is not set. After that, RCS will be unregistered. Verified that the modify PUBLISH request has been sent to the netowrk. Change-Id: I96b565c15f11ee1083b56db29971ddee930d7e64 Merged-In: I96b565c15f11ee1083b56db29971ddee930d7e64 --- .../uce/presence/publish/DeviceCapabilityInfo.java | 6 ++++- .../presence/publish/DeviceCapabilityListener.java | 20 +++++++++------- .../publish/DeviceCapabilityListenerTest.java | 28 ++++++++++++++++++++++ 3 files changed, 44 insertions(+), 10 deletions(-) diff --git a/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityInfo.java b/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityInfo.java index dc794331..f97ccf0a 100644 --- a/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityInfo.java +++ b/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityInfo.java @@ -168,13 +168,17 @@ public class DeviceCapabilityInfo { /** * Update the status that IMS MMTEL is unregistered. + * @return Mmtel registered status before change */ - public synchronized void updateImsMmtelUnregistered() { + public synchronized boolean updateImsMmtelUnregistered() { logi("IMS MMTEL unregistered: original state=" + mMmtelRegistered); + boolean changed = false; if (mMmtelRegistered) { mMmtelRegistered = false; + changed = true; } mMmtelNetworkRegType = AccessNetworkConstants.TRANSPORT_TYPE_INVALID; + return changed; } /** diff --git a/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListener.java b/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListener.java index 0ec30403..8e940073 100644 --- a/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListener.java +++ b/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListener.java @@ -495,7 +495,7 @@ public class DeviceCapabilityListener { public void onSubscriberAssociatedUriChanged(Uri[] uris) { synchronized (mLock) { logi("onRcsSubscriberAssociatedUriChanged"); - handleRcsSubscriberAssociatedUriChanged(uris); + handleRcsSubscriberAssociatedUriChanged(uris, false); } } }; @@ -526,7 +526,7 @@ public class DeviceCapabilityListener { public void onSubscriberAssociatedUriChanged(Uri[] uris) { synchronized (mLock) { logi("onMmTelSubscriberAssociatedUriChanged"); - handleMmTelSubscriberAssociatedUriChanged(uris); + handleMmTelSubscriberAssociatedUriChanged(uris, false); } } }; @@ -614,9 +614,9 @@ public class DeviceCapabilityListener { * This method is called when the MMTEL is unregistered. */ private void handleImsMmtelUnregistered() { - mCapabilityInfo.updateImsMmtelUnregistered(); + boolean hasChanged = mCapabilityInfo.updateImsMmtelUnregistered(); // When the MMTEL is unregistered, the mmtel associated uri should be cleared. - handleMmTelSubscriberAssociatedUriChanged(null); + handleMmTelSubscriberAssociatedUriChanged(null, hasChanged); // If the RCS is already unregistered, it informs that the IMS is unregistered. if (mCapabilityInfo.isImsRegistered() == false) { @@ -627,12 +627,13 @@ public class DeviceCapabilityListener { /* * This method is called when the MMTEL associated uri has changed. */ - private void handleMmTelSubscriberAssociatedUriChanged(Uri[] uris) { + private void handleMmTelSubscriberAssociatedUriChanged(Uri[] uris, boolean regiChanged) { Uri originalUri = mCapabilityInfo.getMmtelAssociatedUri(); mCapabilityInfo.updateMmTelAssociatedUri(uris); Uri currentUri = mCapabilityInfo.getMmtelAssociatedUri(); - boolean hasChanged = !(Objects.equals(originalUri, currentUri)); + boolean hasChanged = regiChanged || !(Objects.equals(originalUri, currentUri)); + logi("handleMmTelSubscriberAssociatedUriChanged: hasChanged=" + hasChanged); // Send internal request to send a modification PUBLISH if the MMTEL or RCS is registered. @@ -666,7 +667,7 @@ public class DeviceCapabilityListener { private void handleImsRcsUnregistered() { boolean hasChanged = mCapabilityInfo.updateImsRcsUnregistered(); // When the RCS is unregistered, the rcs associated uri should be cleared. - handleRcsSubscriberAssociatedUriChanged(null); + handleRcsSubscriberAssociatedUriChanged(null, hasChanged); // If the MMTEL is already unregistered, it informs that the IMS is unregistered. if (mCapabilityInfo.isImsRegistered() == false) { mHandler.sendImsUnregisteredMessage(); @@ -676,12 +677,13 @@ public class DeviceCapabilityListener { /* * This method is called when the RCS associated uri has changed. */ - private void handleRcsSubscriberAssociatedUriChanged(Uri[] uris) { + private void handleRcsSubscriberAssociatedUriChanged(Uri[] uris, boolean regiChanged) { Uri originalUri = mCapabilityInfo.getRcsAssociatedUri(); mCapabilityInfo.updateRcsAssociatedUri(uris); Uri currentUri = mCapabilityInfo.getRcsAssociatedUri(); - boolean hasChanged = !(Objects.equals(originalUri, currentUri)); + boolean hasChanged = regiChanged || !(Objects.equals(originalUri, currentUri)); + logi("handleRcsSubscriberAssociatedUriChanged: hasChanged=" + hasChanged); // Send internal request to send a modification PUBLISH if the MMTEL or RCS is registered. diff --git a/tests/src/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListenerTest.java b/tests/src/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListenerTest.java index 7bdeb11d..d96b87e6 100644 --- a/tests/src/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListenerTest.java +++ b/tests/src/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListenerTest.java @@ -297,6 +297,34 @@ public class DeviceCapabilityListenerTest extends ImsTestBase { verify(mCallback).updateImsUnregistered(); } + @Test + @SmallTest + public void testUnregisterRcsOnlyFromImsRegistration() throws Exception { + DeviceCapabilityListener deviceCapListener = createDeviceCapabilityListener(); + deviceCapListener.setImsCallbackRegistered(true); + Handler handler = deviceCapListener.getHandler(); + + // set the Ims is registered + doReturn(true).when(mDeviceCapability).isImsRegistered(); + ImsReasonInfo info = new ImsReasonInfo(ImsReasonInfo.CODE_LOCAL_NOT_REGISTERED, -1, ""); + // RCS unregistered + RegistrationCallback rcsRegiCallback = deviceCapListener.mRcsRegistrationCallback; + + doReturn(true).when(mDeviceCapability).updateImsRcsUnregistered(); + // RCS is unregistered but MMTEL is registered. + doReturn(true).when(mDeviceCapability).isImsRegistered(); + rcsRegiCallback.onUnregistered(info); + + waitForHandlerActionDelayed(handler, HANDLER_WAIT_TIMEOUT_MS, HANDLER_SENT_DELAY_MS); + + verify(mDeviceCapability).updateImsRcsUnregistered(); + // Only RCS unregistered. Verify the request of the modify publish is sent. + verify(mCallback).requestPublishFromInternal( + PublishController.PUBLISH_TRIGGER_RCS_URI_CHANGE); + + // Only RCS unregistered. Verify do not send ImsUnregistered. + verify(mCallback, never()).updateImsUnregistered(); + } private DeviceCapabilityListener createDeviceCapabilityListener() { DeviceCapabilityListener deviceCapListener = new DeviceCapabilityListener(mContext, -- cgit v1.2.3 From ddade4d45bd249822cbee54ee4a65db911855333 Mon Sep 17 00:00:00 2001 From: Hyunho Date: Wed, 11 Jan 2023 11:59:33 +0000 Subject: Add the feature tags for the pager mode, larege message mode, deffered messaging and large-pager mode. And the presence tuple of the standalone is added. Bug: b/262614903 Test: atest PublishServiceDescTrackerTest Test: In the live network, if there is the feature tag related to the standalone in the registered feature tags, the service id of standalone is included in the PIDF Change-Id: Ie35577303aab0f67bc261686d8e5e5ee3c624707 --- .../presence/publish/PublishServiceDescTracker.java | 10 +++++++++- .../rcs/uce/presence/publish/ServiceDescription.java | 14 ++++++++++++++ .../com/android/ims/rcs/uce/util/FeatureTags.java | 12 ++++++++++++ .../publish/PublishServiceDescTrackerTest.java | 20 +++++++++++++++++++- 4 files changed, 54 insertions(+), 2 deletions(-) diff --git a/src/java/com/android/ims/rcs/uce/presence/publish/PublishServiceDescTracker.java b/src/java/com/android/ims/rcs/uce/presence/publish/PublishServiceDescTracker.java index a107b1ad..7f7ea3e6 100644 --- a/src/java/com/android/ims/rcs/uce/presence/publish/PublishServiceDescTracker.java +++ b/src/java/com/android/ims/rcs/uce/presence/publish/PublishServiceDescTracker.java @@ -53,7 +53,7 @@ public class PublishServiceDescTracker { */ private static final Map> DEFAULT_SERVICE_DESCRIPTION_MAP; static { - ArrayMap> map = new ArrayMap<>(21); + ArrayMap> map = new ArrayMap<>(23); map.put(ServiceDescription.SERVICE_DESCRIPTION_CHAT_IM, Collections.singleton(FeatureTags.FEATURE_TAG_CHAT_IM)); map.put(ServiceDescription.SERVICE_DESCRIPTION_CHAT_SESSION, @@ -111,6 +111,14 @@ public class PublishServiceDescTracker { FeatureTags.FEATURE_TAG_CHATBOT_VERSION_V2_SUPPORTED))); map.put(ServiceDescription.SERVICE_DESCRIPTION_CHATBOT_ROLE, Collections.singleton(FeatureTags.FEATURE_TAG_CHATBOT_ROLE)); + map.put(ServiceDescription.SERVICE_DESCRIPTION_SLM, new ArraySet<>( + Arrays.asList(FeatureTags.FEATURE_TAG_PAGER_MODE, + FeatureTags.FEATURE_TAG_LARGE_MODE, + FeatureTags.FEATURE_TAG_DEFERRED_MESSAGING, + FeatureTags.FEATURE_TAG_LARGE_PAGER_MODE))); + map.put(ServiceDescription.SERVICE_DESCRIPTION_SLM_PAGER_LARGE, new ArraySet<>( + Arrays.asList(FeatureTags.FEATURE_TAG_PAGER_MODE, + FeatureTags.FEATURE_TAG_LARGE_MODE))); DEFAULT_SERVICE_DESCRIPTION_MAP = Collections.unmodifiableMap(map); } diff --git a/src/java/com/android/ims/rcs/uce/presence/publish/ServiceDescription.java b/src/java/com/android/ims/rcs/uce/presence/publish/ServiceDescription.java index 0f271e1c..e175f2a4 100644 --- a/src/java/com/android/ims/rcs/uce/presence/publish/ServiceDescription.java +++ b/src/java/com/android/ims/rcs/uce/presence/publish/ServiceDescription.java @@ -169,6 +169,20 @@ public class ServiceDescription { null /*description*/ ); + public static final ServiceDescription SERVICE_DESCRIPTION_SLM = + new ServiceDescription( + RcsContactPresenceTuple.SERVICE_ID_SLM, + "2.0" /*version*/, + null /*description*/ + ); + + public static final ServiceDescription SERVICE_DESCRIPTION_SLM_PAGER_LARGE = + new ServiceDescription( + RcsContactPresenceTuple.SERVICE_ID_SLM, + "2.0" /*version*/, + "Standalone Messaging" /*description*/ + ); + /** Mandatory "service-id" element */ public final @NonNull String serviceId; /** Mandatory "version" element */ diff --git a/src/java/com/android/ims/rcs/uce/util/FeatureTags.java b/src/java/com/android/ims/rcs/uce/util/FeatureTags.java index 8dbceda6..ed2eef4a 100644 --- a/src/java/com/android/ims/rcs/uce/util/FeatureTags.java +++ b/src/java/com/android/ims/rcs/uce/util/FeatureTags.java @@ -35,6 +35,18 @@ public class FeatureTags { + "service.ims.icsi.oma.cpm.largemsg,urn%3Aurn-7%3A3gpp-" + "service.ims.icsi.oma.cpm.deferred\";+g.gsma.rcs.cpm.pager-large"; + public static final String FEATURE_TAG_PAGER_MODE = + "+g.3gpp.icsi-ref=\"urn%3Aurn-7%3A3gpp-service.ims.icsi.oma.cpm.msg\""; + + public static final String FEATURE_TAG_LARGE_MODE = + "+g.3gpp.icsi-ref=\"urn%3Aurn-7%3A3gpp-service.ims.icsi.oma.cpm.largemsg\""; + + public static final String FEATURE_TAG_DEFERRED_MESSAGING = + "+g.3gpp.icsi-ref=\"urn%3Aurn-7%3A3gpp-service.ims.icsi.oma.cpm.deferred\""; + + public static final String FEATURE_TAG_LARGE_PAGER_MODE = + "+g.gsma.rcs.cpm.pager-large"; + public static final String FEATURE_TAG_CHAT_IM = "+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gpp-application.ims.iari.rcse.im\""; diff --git a/tests/src/com/android/ims/rcs/uce/presence/publish/PublishServiceDescTrackerTest.java b/tests/src/com/android/ims/rcs/uce/presence/publish/PublishServiceDescTrackerTest.java index 55006299..ddd8932f 100644 --- a/tests/src/com/android/ims/rcs/uce/presence/publish/PublishServiceDescTrackerTest.java +++ b/tests/src/com/android/ims/rcs/uce/presence/publish/PublishServiceDescTrackerTest.java @@ -107,7 +107,6 @@ public class PublishServiceDescTrackerTest { t1.updateImsRegistration(imsReg); assertEquals(expectedSet, t1.copyRegistrationCapabilities()); - expectedSet = Collections.singleton( ServiceDescription.SERVICE_DESCRIPTION_CHATBOT_SESSION); imsReg = createImsRegistration( @@ -139,6 +138,25 @@ public class PublishServiceDescTrackerTest { FeatureTags.FEATURE_TAG_VIDEO); t1.updateImsRegistration(imsReg); assertEquals(expectedSet, t1.copyRegistrationCapabilities()); + + expectedSet = Collections.singleton( + ServiceDescription.SERVICE_DESCRIPTION_SLM); + imsReg = createImsRegistration( + FeatureTags.FEATURE_TAG_PAGER_MODE, + FeatureTags.FEATURE_TAG_LARGE_MODE, + FeatureTags.FEATURE_TAG_DEFERRED_MESSAGING, + FeatureTags.FEATURE_TAG_LARGE_PAGER_MODE); + t1.updateImsRegistration(imsReg); + assertEquals(expectedSet, t1.copyRegistrationCapabilities()); + + + expectedSet = Collections.singleton( + ServiceDescription.SERVICE_DESCRIPTION_SLM_PAGER_LARGE); + imsReg = createImsRegistration( + FeatureTags.FEATURE_TAG_PAGER_MODE, + FeatureTags.FEATURE_TAG_LARGE_MODE); + t1.updateImsRegistration(imsReg); + assertEquals(expectedSet, t1.copyRegistrationCapabilities()); } @SmallTest -- cgit v1.2.3 From 6ca11dd4ebcb45ed4428a93bc7886addf142936d Mon Sep 17 00:00:00 2001 From: Hyunho Date: Wed, 11 Jan 2023 11:59:33 +0000 Subject: Add the feature tags for the pager mode, larege message mode, deffered messaging and large-pager mode. And the presence tuple of the standalone is added. Bug: b/262614903 Test: atest PublishServiceDescTrackerTest Test: In the live network, if there is the feature tag related to the standalone in the registered feature tags, the service id of standalone is included in the PIDF Change-Id: Ie35577303aab0f67bc261686d8e5e5ee3c624707 Merged-In: Ie35577303aab0f67bc261686d8e5e5ee3c624707 --- .../presence/publish/PublishServiceDescTracker.java | 10 +++++++++- .../rcs/uce/presence/publish/ServiceDescription.java | 14 ++++++++++++++ .../com/android/ims/rcs/uce/util/FeatureTags.java | 12 ++++++++++++ .../publish/PublishServiceDescTrackerTest.java | 20 +++++++++++++++++++- 4 files changed, 54 insertions(+), 2 deletions(-) diff --git a/src/java/com/android/ims/rcs/uce/presence/publish/PublishServiceDescTracker.java b/src/java/com/android/ims/rcs/uce/presence/publish/PublishServiceDescTracker.java index a107b1ad..7f7ea3e6 100644 --- a/src/java/com/android/ims/rcs/uce/presence/publish/PublishServiceDescTracker.java +++ b/src/java/com/android/ims/rcs/uce/presence/publish/PublishServiceDescTracker.java @@ -53,7 +53,7 @@ public class PublishServiceDescTracker { */ private static final Map> DEFAULT_SERVICE_DESCRIPTION_MAP; static { - ArrayMap> map = new ArrayMap<>(21); + ArrayMap> map = new ArrayMap<>(23); map.put(ServiceDescription.SERVICE_DESCRIPTION_CHAT_IM, Collections.singleton(FeatureTags.FEATURE_TAG_CHAT_IM)); map.put(ServiceDescription.SERVICE_DESCRIPTION_CHAT_SESSION, @@ -111,6 +111,14 @@ public class PublishServiceDescTracker { FeatureTags.FEATURE_TAG_CHATBOT_VERSION_V2_SUPPORTED))); map.put(ServiceDescription.SERVICE_DESCRIPTION_CHATBOT_ROLE, Collections.singleton(FeatureTags.FEATURE_TAG_CHATBOT_ROLE)); + map.put(ServiceDescription.SERVICE_DESCRIPTION_SLM, new ArraySet<>( + Arrays.asList(FeatureTags.FEATURE_TAG_PAGER_MODE, + FeatureTags.FEATURE_TAG_LARGE_MODE, + FeatureTags.FEATURE_TAG_DEFERRED_MESSAGING, + FeatureTags.FEATURE_TAG_LARGE_PAGER_MODE))); + map.put(ServiceDescription.SERVICE_DESCRIPTION_SLM_PAGER_LARGE, new ArraySet<>( + Arrays.asList(FeatureTags.FEATURE_TAG_PAGER_MODE, + FeatureTags.FEATURE_TAG_LARGE_MODE))); DEFAULT_SERVICE_DESCRIPTION_MAP = Collections.unmodifiableMap(map); } diff --git a/src/java/com/android/ims/rcs/uce/presence/publish/ServiceDescription.java b/src/java/com/android/ims/rcs/uce/presence/publish/ServiceDescription.java index 0f271e1c..e175f2a4 100644 --- a/src/java/com/android/ims/rcs/uce/presence/publish/ServiceDescription.java +++ b/src/java/com/android/ims/rcs/uce/presence/publish/ServiceDescription.java @@ -169,6 +169,20 @@ public class ServiceDescription { null /*description*/ ); + public static final ServiceDescription SERVICE_DESCRIPTION_SLM = + new ServiceDescription( + RcsContactPresenceTuple.SERVICE_ID_SLM, + "2.0" /*version*/, + null /*description*/ + ); + + public static final ServiceDescription SERVICE_DESCRIPTION_SLM_PAGER_LARGE = + new ServiceDescription( + RcsContactPresenceTuple.SERVICE_ID_SLM, + "2.0" /*version*/, + "Standalone Messaging" /*description*/ + ); + /** Mandatory "service-id" element */ public final @NonNull String serviceId; /** Mandatory "version" element */ diff --git a/src/java/com/android/ims/rcs/uce/util/FeatureTags.java b/src/java/com/android/ims/rcs/uce/util/FeatureTags.java index 8dbceda6..ed2eef4a 100644 --- a/src/java/com/android/ims/rcs/uce/util/FeatureTags.java +++ b/src/java/com/android/ims/rcs/uce/util/FeatureTags.java @@ -35,6 +35,18 @@ public class FeatureTags { + "service.ims.icsi.oma.cpm.largemsg,urn%3Aurn-7%3A3gpp-" + "service.ims.icsi.oma.cpm.deferred\";+g.gsma.rcs.cpm.pager-large"; + public static final String FEATURE_TAG_PAGER_MODE = + "+g.3gpp.icsi-ref=\"urn%3Aurn-7%3A3gpp-service.ims.icsi.oma.cpm.msg\""; + + public static final String FEATURE_TAG_LARGE_MODE = + "+g.3gpp.icsi-ref=\"urn%3Aurn-7%3A3gpp-service.ims.icsi.oma.cpm.largemsg\""; + + public static final String FEATURE_TAG_DEFERRED_MESSAGING = + "+g.3gpp.icsi-ref=\"urn%3Aurn-7%3A3gpp-service.ims.icsi.oma.cpm.deferred\""; + + public static final String FEATURE_TAG_LARGE_PAGER_MODE = + "+g.gsma.rcs.cpm.pager-large"; + public static final String FEATURE_TAG_CHAT_IM = "+g.3gpp.iari-ref=\"urn%3Aurn-7%3A3gpp-application.ims.iari.rcse.im\""; diff --git a/tests/src/com/android/ims/rcs/uce/presence/publish/PublishServiceDescTrackerTest.java b/tests/src/com/android/ims/rcs/uce/presence/publish/PublishServiceDescTrackerTest.java index 55006299..ddd8932f 100644 --- a/tests/src/com/android/ims/rcs/uce/presence/publish/PublishServiceDescTrackerTest.java +++ b/tests/src/com/android/ims/rcs/uce/presence/publish/PublishServiceDescTrackerTest.java @@ -107,7 +107,6 @@ public class PublishServiceDescTrackerTest { t1.updateImsRegistration(imsReg); assertEquals(expectedSet, t1.copyRegistrationCapabilities()); - expectedSet = Collections.singleton( ServiceDescription.SERVICE_DESCRIPTION_CHATBOT_SESSION); imsReg = createImsRegistration( @@ -139,6 +138,25 @@ public class PublishServiceDescTrackerTest { FeatureTags.FEATURE_TAG_VIDEO); t1.updateImsRegistration(imsReg); assertEquals(expectedSet, t1.copyRegistrationCapabilities()); + + expectedSet = Collections.singleton( + ServiceDescription.SERVICE_DESCRIPTION_SLM); + imsReg = createImsRegistration( + FeatureTags.FEATURE_TAG_PAGER_MODE, + FeatureTags.FEATURE_TAG_LARGE_MODE, + FeatureTags.FEATURE_TAG_DEFERRED_MESSAGING, + FeatureTags.FEATURE_TAG_LARGE_PAGER_MODE); + t1.updateImsRegistration(imsReg); + assertEquals(expectedSet, t1.copyRegistrationCapabilities()); + + + expectedSet = Collections.singleton( + ServiceDescription.SERVICE_DESCRIPTION_SLM_PAGER_LARGE); + imsReg = createImsRegistration( + FeatureTags.FEATURE_TAG_PAGER_MODE, + FeatureTags.FEATURE_TAG_LARGE_MODE); + t1.updateImsRegistration(imsReg); + assertEquals(expectedSet, t1.copyRegistrationCapabilities()); } @SmallTest -- cgit v1.2.3 From 6f2bf6fe778fea2ea0cbe60fca30c5d4965ea5bd Mon Sep 17 00:00:00 2001 From: Michael Groover Date: Thu, 26 Jan 2023 22:15:53 +0000 Subject: Add exported flag to exposed runtime receiver Android T allows apps to declare a runtime receiver as not exported by invoking registerReceiver with a new RECEIVER_NOT_EXPORTED flag; receivers registered with this flag will only receive broadcasts from the platform and the app itself. However to ensure developers can properly protect their receivers, all apps targeting U and registering a receiver for non-system broadcasts must specify either the exported or not exported flag when invoking registerReceiver; if one of these flags is not provided, the platform will throw a SecurityException. This commit updates the receiver in DeviceCapabilityListener with the RECEIVER_EXPORTED flag since it is registering for the TTY_PREFERRED_MODE_CHANGED action which can be sent from UIDs other than the system; the receiver is also protected by a signature permission which limits the apps that could send this broadcast to this receiver. Fixes: 266769311 Test: atest CellBroadcastUiTest#testAlertUiOnReceivedAlert Change-Id: I821e92fdd0a3027b189a6cdec5da7740ea8846e1 --- .../ims/rcs/uce/presence/publish/DeviceCapabilityListener.java | 2 +- tests/src/com/android/ims/ContextFixture.java | 6 ++++++ .../ims/rcs/uce/presence/publish/DeviceCapabilityListenerTest.java | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListener.java b/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListener.java index b824aa08..d3c82f2a 100644 --- a/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListener.java +++ b/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListener.java @@ -276,7 +276,7 @@ public class DeviceCapabilityListener { IntentFilter filter = new IntentFilter(); filter.addAction(TelecomManager.ACTION_TTY_PREFERRED_MODE_CHANGED); mContext.registerReceiver(mReceiver, filter, android.Manifest.permission.MODIFY_PHONE_STATE, - null); + null, Context.RECEIVER_EXPORTED); ContentResolver resolver = mContext.getContentResolver(); if (resolver != null) { diff --git a/tests/src/com/android/ims/ContextFixture.java b/tests/src/com/android/ims/ContextFixture.java index 48cb9ab1..21dd6348 100644 --- a/tests/src/com/android/ims/ContextFixture.java +++ b/tests/src/com/android/ims/ContextFixture.java @@ -137,6 +137,12 @@ public class ContextFixture { return null; } + @Override + public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter, + String broadcastPermission, Handler scheduler, int flags) { + return null; + } + @Override public void unregisterReceiver(BroadcastReceiver receiver) { } diff --git a/tests/src/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListenerTest.java b/tests/src/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListenerTest.java index 4b3caeb4..7c649891 100644 --- a/tests/src/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListenerTest.java +++ b/tests/src/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListenerTest.java @@ -107,7 +107,7 @@ public class DeviceCapabilityListenerTest extends ImsTestBase { deviceCapListener.initialize(); verify(mContext).registerReceiver(any(), any(), - eq(android.Manifest.permission.MODIFY_PHONE_STATE), any()); + eq(android.Manifest.permission.MODIFY_PHONE_STATE), any(), anyInt()); verify(mProvisioningManager).registerProvisioningChangedCallback(any(), any()); } -- cgit v1.2.3 From 6c7a6284938ba458653379f2a5daeec48ab51ca2 Mon Sep 17 00:00:00 2001 From: Jack Yu Date: Tue, 21 Feb 2023 15:03:01 -0800 Subject: Cleaned up the deprecated APIs Bug: 270094276 Test: Basic phone funcationality tests Change-Id: I077e92852f0a15df8bd7d12daf5edb4b7cbb722d --- src/java/com/android/ims/ImsManager.java | 13 ++++--------- tests/src/com/android/ims/ImsManagerTest.java | 2 +- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/src/java/com/android/ims/ImsManager.java b/src/java/com/android/ims/ImsManager.java index b1d2ebcc..b5a1168b 100644 --- a/src/java/com/android/ims/ImsManager.java +++ b/src/java/com/android/ims/ImsManager.java @@ -261,7 +261,7 @@ public class ImsManager implements FeatureUpdates { @VisibleForTesting public interface SubscriptionManagerProxy { boolean isValidSubscriptionId(int subId); - int[] getSubscriptionIds(int slotIndex); + int getSubscriptionId(int slotIndex); int getDefaultVoicePhoneId(); int getIntegerSubscriptionProperty(int subId, String propKey, int defValue); void setSubscriptionProperty(int subId, String propKey, String propValue); @@ -296,8 +296,8 @@ public class ImsManager implements FeatureUpdates { } @Override - public int[] getSubscriptionIds(int slotIndex) { - return getSubscriptionManager().getSubscriptionIds(slotIndex); + public int getSubscriptionId(int slotIndex) { + return SubscriptionManager.getSubscriptionId(slotIndex); } @Override @@ -1437,12 +1437,7 @@ public class ImsManager implements FeatureUpdates { } private int getSubId() { - int[] subIds = mSubscriptionManagerProxy.getSubscriptionIds(mPhoneId); - int subId = SubscriptionManager.INVALID_SUBSCRIPTION_ID; - if (subIds != null && subIds.length >= 1) { - subId = subIds[0]; - } - return subId; + return mSubscriptionManagerProxy.getSubscriptionId(mPhoneId); } private void setWfcModeInternal(int wfcMode) { diff --git a/tests/src/com/android/ims/ImsManagerTest.java b/tests/src/com/android/ims/ImsManagerTest.java index 2c0fd870..ad5051be 100644 --- a/tests/src/com/android/ims/ImsManagerTest.java +++ b/tests/src/com/android/ims/ImsManagerTest.java @@ -119,7 +119,7 @@ public class ImsManagerTest extends ImsTestBase { doReturn(true).when(mSubscriptionManagerProxy).isValidSubscriptionId(anyInt()); doReturn(mSubId).when(mSubscriptionManagerProxy).getActiveSubscriptionIdList(); - doReturn(mSubId).when(mSubscriptionManagerProxy).getSubscriptionIds(anyInt()); + doReturn(mSubId[0]).when(mSubscriptionManagerProxy).getSubscriptionId(anyInt()); doReturn(mPhoneId).when(mSubscriptionManagerProxy).getDefaultVoicePhoneId(); doReturn(-1).when(mSubscriptionManagerProxy).getIntegerSubscriptionProperty(anyInt(), anyString(), anyInt()); -- cgit v1.2.3 From 423c825bf3b7e65bea6ade38003ff1ec1fe53e61 Mon Sep 17 00:00:00 2001 From: Sungcheol Ahn Date: Wed, 15 Feb 2023 07:40:36 +0000 Subject: Fixed to update the Capability Info if any change in Rcs Feature Tags during Ims Mmtel alive. If RCS UnRegistration is executed due to the destruction of SipDelegate, RCS Feature Tags have been released from the PUBLISH tuple. Bug: b/235973951 Test: atest PublishServiceDescTrackerTest Test: TestRcsApp Change-Id: I1ff4824e351f156b983b0574debac1bdadd244c9 --- .../android/ims/rcs/uce/presence/publish/DeviceCapabilityInfo.java | 3 +++ .../ims/rcs/uce/presence/publish/PublishServiceDescTrackerTest.java | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityInfo.java b/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityInfo.java index 0c8515ba..49291484 100644 --- a/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityInfo.java +++ b/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityInfo.java @@ -255,6 +255,9 @@ public class DeviceCapabilityInfo { mRcsRegistered = false; changed = true; } + + mLastRegistrationFeatureTags = Collections.emptySet(); + updateRegistration(mLastRegistrationFeatureTags); mRcsNetworkRegType = AccessNetworkConstants.TRANSPORT_TYPE_INVALID; mLastSuccessfulCapabilities.clear(); mPendingPublishCapabilities = null; diff --git a/tests/src/com/android/ims/rcs/uce/presence/publish/PublishServiceDescTrackerTest.java b/tests/src/com/android/ims/rcs/uce/presence/publish/PublishServiceDescTrackerTest.java index ddd8932f..52017c7a 100644 --- a/tests/src/com/android/ims/rcs/uce/presence/publish/PublishServiceDescTrackerTest.java +++ b/tests/src/com/android/ims/rcs/uce/presence/publish/PublishServiceDescTrackerTest.java @@ -157,6 +157,11 @@ public class PublishServiceDescTrackerTest { FeatureTags.FEATURE_TAG_LARGE_MODE); t1.updateImsRegistration(imsReg); assertEquals(expectedSet, t1.copyRegistrationCapabilities()); + + // delete the feature tags for Unregistered + expectedSet = new ArraySet<>(); + t1.updateImsRegistration(Collections.emptySet()); + assertEquals(expectedSet, t1.copyRegistrationCapabilities()); } @SmallTest -- cgit v1.2.3 From ac281856a68bcf5d5bee5e44a8dc015042308585 Mon Sep 17 00:00:00 2001 From: Sungcheol Ahn Date: Thu, 16 Feb 2023 05:26:04 +0000 Subject: Fixed to update the Capability Info if any change in Rcs Feature Tags during Ims Mmtel alive. If RCS UnRegistration is executed due to the destruction of SipDelegate, RCS Feature Tags have been released from the PUBLISH tuple. Bug: b/235973951 Test: atest PublishServiceDescTrackerTest Test: TestRcsApp Merged-In: I1ff4824e351f156b983b0574debac1bdadd244c9 Change-Id: I42018de59b0f346941f60ed54f46dcd4b87fcad3 --- .../android/ims/rcs/uce/presence/publish/DeviceCapabilityInfo.java | 3 +++ .../ims/rcs/uce/presence/publish/PublishServiceDescTrackerTest.java | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityInfo.java b/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityInfo.java index f97ccf0a..de7c98c9 100644 --- a/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityInfo.java +++ b/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityInfo.java @@ -246,6 +246,9 @@ public class DeviceCapabilityInfo { mRcsRegistered = false; changed = true; } + + mLastRegistrationFeatureTags = Collections.emptySet(); + updateRegistration(mLastRegistrationFeatureTags); mRcsNetworkRegType = AccessNetworkConstants.TRANSPORT_TYPE_INVALID; return changed; } diff --git a/tests/src/com/android/ims/rcs/uce/presence/publish/PublishServiceDescTrackerTest.java b/tests/src/com/android/ims/rcs/uce/presence/publish/PublishServiceDescTrackerTest.java index ddd8932f..52017c7a 100644 --- a/tests/src/com/android/ims/rcs/uce/presence/publish/PublishServiceDescTrackerTest.java +++ b/tests/src/com/android/ims/rcs/uce/presence/publish/PublishServiceDescTrackerTest.java @@ -157,6 +157,11 @@ public class PublishServiceDescTrackerTest { FeatureTags.FEATURE_TAG_LARGE_MODE); t1.updateImsRegistration(imsReg); assertEquals(expectedSet, t1.copyRegistrationCapabilities()); + + // delete the feature tags for Unregistered + expectedSet = new ArraySet<>(); + t1.updateImsRegistration(Collections.emptySet()); + assertEquals(expectedSet, t1.copyRegistrationCapabilities()); } @SmallTest -- cgit v1.2.3 From ec0d7029274aa5e6a35110be78ae5f852de04dfe Mon Sep 17 00:00:00 2001 From: joonhunshin Date: Wed, 8 Mar 2023 00:28:11 +0000 Subject: Block PUBLISH execution when the MmTel registered to avoid multiple PUBLISH triggers. Block PUBLISH execution when the MmTel registered to avoid multiple PUBLISH tiggers. But PUBLISH will perform when Capability changed callback is called. Bug: 243163530 Test: atest DeviceCapabilityListenerTest Test: manually 1. MmTel registered 2. Airplan mode on - off 3. Check publish trigger Change-Id: I6c0cb370a0eb0c587c8dea63338f6cc6eb9a0e77 --- .../ims/rcs/uce/presence/publish/DeviceCapabilityListener.java | 4 ++-- .../ims/rcs/uce/presence/publish/DeviceCapabilityListenerTest.java | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListener.java b/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListener.java index d3c82f2a..b58f7ec6 100644 --- a/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListener.java +++ b/src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListener.java @@ -590,9 +590,9 @@ public class DeviceCapabilityListener { * This method is called when the MMTEL is registered. */ private void handleImsMmtelRegistered(int imsTransportType) { + // update capability, but not trigger PUBLISH message. + // PUBLISH message will be sent when the Capability status changed callback is called. mCapabilityInfo.updateImsMmtelRegistered(imsTransportType); - mHandler.sendTriggeringPublishMessage( - PublishController.PUBLISH_TRIGGER_MMTEL_REGISTERED); } /* diff --git a/tests/src/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListenerTest.java b/tests/src/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListenerTest.java index 7c649891..11350393 100644 --- a/tests/src/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListenerTest.java +++ b/tests/src/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListenerTest.java @@ -154,7 +154,8 @@ public class DeviceCapabilityListenerTest extends ImsTestBase { waitForHandlerActionDelayed(handler, HANDLER_WAIT_TIMEOUT_MS, HANDLER_SENT_DELAY_MS); verify(mDeviceCapability).updateImsMmtelRegistered(1); - verify(mCallback).requestPublishFromInternal( + // update capability, but not trigger PUBLISH message when MmTel registered. + verify(mCallback, never()).requestPublishFromInternal( PublishController.PUBLISH_TRIGGER_MMTEL_REGISTERED); } -- cgit v1.2.3 From ab8472c4793ffde2bda4fe69a7a124276a01fbe6 Mon Sep 17 00:00:00 2001 From: Tyler Gunn Date: Mon, 20 Mar 2023 17:39:17 +0000 Subject: Owners updates. Test: Owners only fix. Fixes: 274470555 Change-Id: Ia0e889e93c7f5ee8e05a002ada7c1d4fdb905751 --- OWNERS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/OWNERS b/OWNERS index 95e48fc9..fa4ba423 100644 --- a/OWNERS +++ b/OWNERS @@ -3,3 +3,5 @@ tgunn@google.com chinmayd@google.com xiaotonj@google.com tjstuart@google.com +grantmenke@google.com +pmadapurmath@google.com -- cgit v1.2.3