Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4b733da9 authored by James.cf Lin's avatar James.cf Lin
Browse files

When the capability type is SIP OPTIONS, the PUBLISH STATE should be OK

Bug: 188447963
Test: atest -c CtsTelephonyTestCases:android.telephony.ims.cts.ImsServiceTest
Change-Id: I2c7bb5fe471578e3442c4857b0678fd798a3191e
parent 3808616e
Loading
Loading
Loading
Loading
+103 −11
Original line number Diff line number Diff line
@@ -89,6 +89,8 @@ public class PublishControllerImpl implements PublishController {
    private volatile RcsFeatureManager mRcsFeatureManager;
    private final UceControllerCallback mUceCtrlCallback;

    // The capability type that the device is using.
    private @RcsImsCapabilityFlag int mCapabilityType;
    // The device publish state
    private @PublishState int mPublishState;
    // The timestamp of updating the publish state
@@ -154,7 +156,8 @@ public class PublishControllerImpl implements PublishController {
    }

    private void initPublishController(Looper looper) {
        mPublishState = RcsUceAdapter.PUBLISH_STATE_NOT_PUBLISHED;
        mCapabilityType = PublishUtils.getCapabilityType(mContext, mSubId);
        mPublishState = getInitialPublishState(mCapabilityType);
        mPublishStateCallbacks = new RemoteCallbackList<>();
        mPublishHandler = new PublishHandler(this, looper);

@@ -166,6 +169,26 @@ public class PublishControllerImpl implements PublishController {

        // Turn on the listener to listen to the device changes.
        mDeviceCapListener.initialize();

        logd("initPublishController completed: capabilityType=" + mCapabilityType +
                ", publishState=" + mPublishState);
    }

    /**
     * Get the initial publish state according to the given capability type.
     * <p>
     * The default publish state is NOT_PUBLISH when the capability type is PRESENCE.
     * The default publish state is OK when the capability type is SIP OPTIONS.
     * Otherwise, the default initial value is ERROR.
     */
    private int getInitialPublishState(@RcsImsCapabilityFlag int capabilityType) {
        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;
        } else {
            return RcsUceAdapter.PUBLISH_STATE_OTHER_ERROR;
        }
    }

    private void initPublishProcessor() {
@@ -573,14 +596,7 @@ public class PublishControllerImpl implements PublishController {
        }

        public void sendPublishMessage(@PublishTriggerType int type) {
            PublishControllerImpl publishCtrl = mPublishControllerRef.get();
            if (publishCtrl == null) return;
            if (publishCtrl.mIsDestroyedFlag) return;

            Message message = obtainMessage();
            message.what = MSG_REQUEST_PUBLISH;
            message.arg1 = type;
            sendMessage(message);
            sendPublishMessage(type, 0L);
        }

        public void sendPublishMessage(@PublishTriggerType int type, long delay) {
@@ -588,6 +604,13 @@ public class PublishControllerImpl implements PublishController {
            if (publishCtrl == null) return;
            if (publishCtrl.mIsDestroyedFlag) return;

            // Disallow publish if the PRESENCE PUBLISH is not enabled and this request is not
            // triggered by the ImsService.
            if (!publishCtrl.isPresencePublishEnabled() && type != PUBLISH_TRIGGER_SERVICE) {
                publishCtrl.logd("sendPublishMessage: disallowed type=" + type);
                return;
            }

            Message message = obtainMessage();
            message.what = MSG_REQUEST_PUBLISH;
            message.arg1 = type;
@@ -692,7 +715,8 @@ public class PublishControllerImpl implements PublishController {

        // The first PUBLISH request is required to be triggered from the service.
        if (!mReceivePublishFromService) {
            logd("isPublishRequestAllowed: Have not received the first PUBLISH from the service.");
            logd("isPublishRequestAllowed: "
                    + "The first PUBLISH request from the server has not been received.");
            return false;
        }

@@ -713,6 +737,19 @@ public class PublishControllerImpl implements PublishController {
        return true;
    }

    /**
     * Check whether the PRESENCE PUBLISH should be enabled or not. It should be enabled only when
     * the PRESENCE mechanism is supported.
     */
    private boolean isPresencePublishEnabled() {
        synchronized (mPublishStateLock) {
            return mCapabilityType == RcsImsCapabilities.CAPABILITY_TYPE_PRESENCE_UCE;
        }
    }

    /**
     * Handle the RCS connected message. This method is called in the handler thread.
     */
    private void handleRcsConnectedMessage(RcsFeatureManager manager) {
        if (mIsDestroyedFlag) return;
        mRcsFeatureManager = manager;
@@ -721,15 +758,27 @@ public class PublishControllerImpl implements PublishController {
        registerRcsAvailabilityChanged(manager);
    }

    /**
     * Handle the RCS disconnected message. This method is called in the handler thread.
     */
    private void handleRcsDisconnectedMessage() {
        if (mIsDestroyedFlag) return;
        mRcsFeatureManager = null;
        onUnpublish();
        mDeviceCapabilityInfo.updatePresenceCapable(false);
        mDeviceCapListener.onRcsDisconnected();
        mPublishProcessor.onRcsDisconnected();

        // When the RCS is disconnected, update the publish state to NOT_PUBLISH if the PRESENCE
        // PUBLISH is enabled.
        if (isPresencePublishEnabled()) {
            handlePublishStateChangedMessage(RcsUceAdapter.PUBLISH_STATE_NOT_PUBLISHED,
                    Instant.now(), null /*pidfXml*/);
        }
    }

    /**
     * Handle the Destroyed message. This method is called in the handler thread.
     */
    private void handleDestroyedMessage() {
        mIsDestroyedFlag = true;
        mDeviceCapabilityInfo.updatePresenceCapable(false);
@@ -768,8 +817,14 @@ public class PublishControllerImpl implements PublishController {
        }
    }

    /**
     * Handle the carrier config changed message. This method is called in the handler thread.
     */
    private void handleCarrierConfigChangedMessage() {
        if (mIsDestroyedFlag) return;

        updateCapabilityTypeAndPublishStateIfNeeded();

        String[] newMap = getCarrierServiceDescriptionFeatureTagMap();
        if (mDeviceCapabilityInfo.updateCapabilityRegistrationTrackerMap(newMap)) {
            mPublishHandler.sendPublishMessage(
@@ -777,6 +832,37 @@ public class PublishControllerImpl implements PublishController {
        }
    }

    /**
     * Check whether the capability type has changed or not because of the carrier config changed.
     * If the capability type has changed, the publish state also needs to be reinitialized.
     * <p>
     * This method is called in the handler thread.
     */
    private void updateCapabilityTypeAndPublishStateIfNeeded() {
        synchronized (mPublishStateLock) {
            int originalMechanism = mCapabilityType;
            mCapabilityType = PublishUtils.getCapabilityType(mContext, mSubId);

            // Return when the capability type has not changed.
            if (originalMechanism == mCapabilityType) {
                logd("updateCapTypeAndPublishStateIfNeeded: " +
                        "The capability type is not changed=" + mCapabilityType);
                return;
            }

            // Reinitialize the publish state because the capability type has changed.
            int updatedPublishState = getInitialPublishState(mCapabilityType);

            logd("updateCapTypeAndPublishStateIfNeeded from " + originalMechanism +
                    " to " + mCapabilityType + ", new publish state=" + updatedPublishState);

            // 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*/);
        }
    }

    private String[] getCarrierServiceDescriptionFeatureTagMap() {
        CarrierConfigManager manager = mContext.getSystemService(CarrierConfigManager.class);
        PersistableBundle bundle = manager != null ? manager.getConfigForSubId(mSubId) :
@@ -898,6 +984,12 @@ public class PublishControllerImpl implements PublishController {
        mUceCtrlCallback.resetDeviceState();
    }

    @VisibleForTesting
    public void setCapabilityType(int type) {
        mCapabilityType = type;
        mPublishState = getInitialPublishState(mCapabilityType);
    }

    @VisibleForTesting
    public void setPublishStateCallback(RemoteCallbackList<IRcsUcePublishStateCallback> list) {
        mPublishStateCallbacks = list;
+15 −0
Original line number Diff line number Diff line
@@ -20,6 +20,8 @@ import android.content.Context;
import android.net.Uri;
import android.telephony.PhoneNumberUtils;
import android.telephony.TelephonyManager;
import android.telephony.ims.feature.RcsFeature.RcsImsCapabilities;
import android.telephony.ims.feature.RcsFeature.RcsImsCapabilities.RcsImsCapabilityFlag;
import android.text.TextUtils;
import android.util.Log;

@@ -133,4 +135,17 @@ public class PublishUtils {
            return telephonyManager.createForSubscriptionId(subId);
        }
    }

    static @RcsImsCapabilityFlag int getCapabilityType(Context context, int subId) {
        boolean isPresenceSupported = UceUtils.isPresenceSupported(context, subId);
        boolean isSipOptionsSupported = UceUtils.isSipOptionsSupported(context, subId);
        if (isPresenceSupported) {
            return RcsImsCapabilities.CAPABILITY_TYPE_PRESENCE_UCE;
        } else if (isSipOptionsSupported) {
            return RcsImsCapabilities.CAPABILITY_TYPE_OPTIONS_UCE;
        } else {
            // Return NONE when neither OPTIONS nor PRESENCE is supported.
            return RcsImsCapabilities.CAPABILITY_TYPE_NONE;
        }
    }
}
+32 −0
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ import android.os.RemoteCallbackList;
import android.telephony.ims.RcsUceAdapter;
import android.telephony.ims.aidl.IImsCapabilityCallback;
import android.telephony.ims.aidl.IRcsUcePublishStateCallback;
import android.telephony.ims.feature.RcsFeature.RcsImsCapabilities;

import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
@@ -315,11 +316,42 @@ public class PublishControllerImplTest extends ImsTestBase {
        assertFalse("still contained 555-555-1212: " + testString, result.contains("555-555-1212"));
    }

    @Test
    @SmallTest
    public void testNotPublishWhitSipOptions() throws Exception {
        PublishControllerImpl publishController = createPublishController();
        publishController.setCapabilityType(RcsImsCapabilities.CAPABILITY_TYPE_OPTIONS_UCE);
        doReturn(Optional.of(0L)).when(mPublishProcessor).getPublishingDelayTime();

        // Trigger a publish request (VT changes)
        PublishControllerCallback callback = publishController.getPublishControllerCallback();
        callback.requestPublishFromInternal(PUBLISH_TRIGGER_VT_SETTING_CHANGE);
        Handler handler = publishController.getPublishHandler();
        waitForHandlerAction(handler, 1000);

        // Verify it cannot be processed because the capability type is SIP OPTIONS and the publish
        // request is triggered from device changed
        verify(mPublishProcessor, never()).doPublish(PUBLISH_TRIGGER_VT_SETTING_CHANGE);

        // Set the PRESENCE is capable
        IImsCapabilityCallback RcsCapCallback = publishController.getRcsCapabilitiesCallback();
        RcsCapCallback.onCapabilitiesStatusChanged(RcsImsCapabilities.CAPABILITY_TYPE_PRESENCE_UCE);

        // Trigger the PUBLISH request from the service.
        publishController.requestPublishCapabilitiesFromService(
                RcsUceAdapter.CAPABILITY_UPDATE_TRIGGER_MOVE_TO_IWLAN);
        waitForHandlerAction(handler, 1000);

        // Verify the request which is from the service can be processed
        verify(mPublishProcessor).doPublish(PublishController.PUBLISH_TRIGGER_SERVICE);
    }

    private PublishControllerImpl createPublishController() {
        PublishControllerImpl publishController = new PublishControllerImpl(mContext, mSubId,
                mUceCtrlCallback, Looper.getMainLooper(), mDeviceCapListenerFactory,
                mPublishProcessorFactory);
        publishController.setPublishStateCallback(mPublishStateCallbacks);
        publishController.setCapabilityType(RcsImsCapabilities.CAPABILITY_TYPE_PRESENCE_UCE);
        return publishController;
    }
}