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

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

[RCS UCE] The implementation of the PublishController

Create the PublishControllerImpl class which implments the method of PublishController.

Bug: 170476615
Test: atest UceControllerTest; atest PublishControllerImplTest; atest DeviceCapabilityListenerTest
Change-Id: Ib684d2fa8f7764115fdedc72362fb290d85abebc
parent be1b853b
Loading
Loading
Loading
Loading
+5 −7
Original line number Diff line number Diff line
@@ -123,8 +123,7 @@ public class UceController {
        /**
         * @return an {@link PublishController} associated with the subscription id specified.
         */
        PublishController createPublishController(Context context, int subId,
                UceControllerCallback c, Looper looper);
        PublishController createPublishController(Context context, int subId, Looper looper);

        /**
         * @return an {@link SubscribeController} associated with the subscription id specified.
@@ -183,8 +182,7 @@ public class UceController {
    private void initControllers() {
        mEabController = mControllerFactory.createEabController(mContext, mSubId, mCtrlCallback,
                mLooper);
        mPublishController = mControllerFactory.createPublishController(mContext, mSubId,
                mCtrlCallback, mLooper);
        mPublishController = mControllerFactory.createPublishController(mContext, mSubId, mLooper);
        mSubscribeController = mControllerFactory.createSubscribeController(mContext, mSubId,
                mCtrlCallback, mLooper);
        mOptionsController = mControllerFactory.createOptionsController(mContext, mSubId,
@@ -322,9 +320,9 @@ public class UceController {
    /**
     * Publish the device's capabilities. This request is triggered from the ImsService.
     */
    public void onRequestPublishCapabilitiesFromService(int triggerType) {
        logd("onRequestPublishCapabilitiesFromService: " + triggerType);
        mPublishController.publishCapabilities(triggerType);
    public void onRequestPublishCapabilitiesFromService() {
        logd("onRequestPublishCapabilitiesFromService");
        mPublishController.requestPublishCapabilitiesFromService();
    }

    /**
+320 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.ims.rcs.uce.presence.publish;

import android.content.Context;
import android.net.Uri;
import android.telecom.PhoneAccount;
import android.telecom.TelecomManager;
import android.telephony.AccessNetworkConstants;
import android.telephony.TelephonyManager;
import android.telephony.ims.RcsContactUceCapability;
import android.telephony.ims.feature.MmTelFeature;
import android.telephony.ims.feature.MmTelFeature.MmTelCapabilities;
import android.util.Log;

/**
 * Stores the device's capabilities information.
 */
public class DeviceCapabilityInfo {
    private static final String LOG_TAG = "DeviceCapabilityInfo";

    private final int mSubId;

    // The mmtel feature is registered or not
    private boolean mMmtelRegistered;

    // The network type which ims mmtel registers on.
    private int mMmtelNetworkRegType;

    // The rcs feature is registered or not
    private boolean mRcsRegistered;

    // The network type which ims rcs registers on.
    private int mRcsNetworkRegType;

    // The MMTel capabilities of this subscription Id
    private MmTelFeature.MmTelCapabilities mMmTelCapabilities;

    // Whether the settings are changed or not
    private int mTtyPreferredMode;
    private boolean mAirplaneMode;
    private boolean mMobileData;
    private boolean mVtSetting;

    public DeviceCapabilityInfo(int subId) {
        mSubId = subId;
        reset();
    }

    /**
     * Reset all the status.
     */
    public synchronized void reset() {
        logd("reset");
        mMmtelRegistered = false;
        mMmtelNetworkRegType = AccessNetworkConstants.TRANSPORT_TYPE_INVALID;
        mRcsRegistered = false;
        mRcsNetworkRegType = AccessNetworkConstants.TRANSPORT_TYPE_INVALID;
        mTtyPreferredMode = TelecomManager.TTY_MODE_OFF;
        mAirplaneMode = false;
        mMobileData = true;
        mVtSetting = true;
        mMmTelCapabilities = new MmTelCapabilities();
    }

    public synchronized boolean isImsRegistered() {
        return mMmtelRegistered;
    }

    /**
     * Update the status that IMS MMTEL is registered.
     */
    public synchronized void updateImsMmtelRegistered(int type) {
        StringBuilder builder = new StringBuilder();
        builder.append("IMS MMTEL registered: original state=").append(mMmtelRegistered)
                .append(", changes type from ").append(mMmtelNetworkRegType)
                .append(" to ").append(type);
        logi(builder.toString());

        if (!mMmtelRegistered) {
            mMmtelRegistered = true;
        }

        if (mMmtelNetworkRegType != type) {
            mMmtelNetworkRegType = type;
        }
    }

    /**
     * Update the status that IMS MMTEL is unregistered.
     */
    public synchronized void updateImsMmtelUnregistered() {
        logi("IMS MMTEL unregistered: original state=" + mMmtelRegistered);
        if (mMmtelRegistered) {
            mMmtelRegistered = false;
        }
        mMmtelNetworkRegType = AccessNetworkConstants.TRANSPORT_TYPE_INVALID;
    }

    /**
     * Update the status that IMS RCS is registered.
     */
    public synchronized void updateImsRcsRegistered(int type) {
        StringBuilder builder = new StringBuilder();
        builder.append("IMS RCS registered: original state=").append(mRcsRegistered)
                .append(", changes type from ").append(mRcsNetworkRegType)
                .append(" to ").append(type);
        logi(builder.toString());

        if (!mRcsRegistered) {
            mRcsRegistered = true;
        }

        if (mRcsNetworkRegType != type) {
            mRcsNetworkRegType = type;
        }
    }

    /**
     * Update the status that IMS RCS is unregistered.
     */
    public synchronized void updateImsRcsUnregistered() {
        logi("IMS RCS unregistered: original state=" + mRcsRegistered);
        if (mRcsRegistered) {
            mRcsRegistered = false;
        }
        mRcsNetworkRegType = AccessNetworkConstants.TRANSPORT_TYPE_INVALID;
    }

    /**
     * Update the TTY preferred mode.
     * @return {@code true} if tty preferred mode is changed, {@code false} otherwise.
     */
    public synchronized boolean updateTtyPreferredMode(int ttyMode) {
        if (mTtyPreferredMode != ttyMode) {
            logd("TTY preferred mode changes from " + mTtyPreferredMode + " to " + ttyMode);
            mTtyPreferredMode = ttyMode;
            return true;
        }
        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.
     */
    public synchronized boolean updateMobileData(boolean mobileData) {
        if (mMobileData != mobileData) {
            logd("Mobile data changes from " + mMobileData + " to " + mobileData);
            mMobileData = mobileData;
            return true;
        }
        return false;
    }

    /**
     * Update VT setting.
     * @return {@code true} if vt setting is changed, {@code false}.otherwise.
     */
    public synchronized boolean updateVtSetting(boolean vtSetting) {
        if (mVtSetting != vtSetting) {
            logd("VT setting changes from " + mVtSetting + " to " + vtSetting);
            mVtSetting = vtSetting;
            return true;
        }
        return false;
    }

    /**
     * Update the MMTEL capabilities if the capabilities is changed.
     * @return {@code true} if the mmtel capabilities are changed, {@code false} otherwise.
     */
    public synchronized boolean updateMmtelCapabilitiesChanged(MmTelCapabilities capabilities) {
        if (capabilities == null) {
            return false;
        }
        boolean oldVolteAvailable = isVolteAvailable(mMmtelNetworkRegType, mMmTelCapabilities);
        boolean oldVoWifiAvailable = isVoWifiAvailable(mMmtelNetworkRegType, mMmTelCapabilities);
        boolean oldVtAvailable = isVtAvailable(mMmtelNetworkRegType, mMmTelCapabilities);
        boolean oldViWifiAvailable = isViWifiAvailable(mMmtelNetworkRegType, mMmTelCapabilities);

        boolean volteAvailable = isVolteAvailable(mMmtelNetworkRegType, capabilities);
        boolean voWifiAvailable = isVoWifiAvailable(mMmtelNetworkRegType, capabilities);
        boolean vtAvailable = isVtAvailable(mMmtelNetworkRegType, capabilities);
        boolean viWifiAvailable = isViWifiAvailable(mMmtelNetworkRegType, capabilities);

        logd("updateMmtelCapabilitiesChanged: from " + mMmTelCapabilities + " to " + capabilities);

        // Update to the new mmtel capabilities
        mMmTelCapabilities = deepCopyCapabilities(capabilities);

        if (oldVolteAvailable != volteAvailable
                || oldVoWifiAvailable != voWifiAvailable
                || oldVtAvailable != vtAvailable
                || oldViWifiAvailable != viWifiAvailable) {
            return true;
        }
        return false;
    }

    private boolean isVolteAvailable(int networkRegType, MmTelCapabilities capabilities) {
        return (networkRegType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
                && capabilities.isCapable(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE);
    }

    private boolean isVoWifiAvailable(int networkRegType, MmTelCapabilities capabilities) {
        return (networkRegType == AccessNetworkConstants.TRANSPORT_TYPE_WLAN)
                && capabilities.isCapable(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE);
    }

    private boolean isVtAvailable(int networkRegType, MmTelCapabilities capabilities) {
        return (networkRegType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
                && capabilities.isCapable(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO);
    }

    private boolean isViWifiAvailable(int networkRegType, MmTelCapabilities capabilities) {
        return (networkRegType == AccessNetworkConstants.TRANSPORT_TYPE_WLAN)
                && capabilities.isCapable(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VIDEO);
    }

    /**
     * Get the device capabilities
     */
    public synchronized RcsContactUceCapability getDeviceCapabilities(Context context) {
        Uri uri = PublishUtils.getPublishingUri(context, mSubId);
        if (uri == null) {
            logw("getDeviceCapabilities: uri is empty");
            return null;
        }
        RcsContactUceCapability.Builder builder = new RcsContactUceCapability.Builder(uri);
        if (hasVolteCapability()) {
            builder.add(RcsContactUceCapability.CAPABILITY_IP_VOICE_CALL);
        }
        if (hasVtCapability()) {
            builder.add(RcsContactUceCapability.CAPABILITY_IP_VIDEO_CALL);
        }
        return builder.build();
    }

    // Check if the device has the VoLTE capability
    private synchronized boolean hasVolteCapability() {
        if (mMmTelCapabilities != null
                && mMmTelCapabilities.isCapable(MmTelCapabilities.CAPABILITY_TYPE_VOICE)) {
            return true;
        }
        return false;
    }

    // Check if the device has the VT capability
    private synchronized boolean hasVtCapability() {
        if (mMmTelCapabilities != null
                && mMmTelCapabilities.isCapable(MmTelCapabilities.CAPABILITY_TYPE_VIDEO)) {
            return true;
        }
        return false;
    }

    private synchronized MmTelCapabilities deepCopyCapabilities(MmTelCapabilities capabilities) {
        MmTelCapabilities mmTelCapabilities = new MmTelCapabilities();
        if (capabilities.isCapable(MmTelCapabilities.CAPABILITY_TYPE_VOICE)) {
            mmTelCapabilities.addCapabilities(MmTelCapabilities.CAPABILITY_TYPE_VOICE);
        }
        if (capabilities.isCapable(MmTelCapabilities.CAPABILITY_TYPE_VIDEO)) {
            mmTelCapabilities.addCapabilities(MmTelCapabilities.CAPABILITY_TYPE_VIDEO);
        }
        if (capabilities.isCapable(MmTelCapabilities.CAPABILITY_TYPE_UT)) {
            mmTelCapabilities.addCapabilities(MmTelCapabilities.CAPABILITY_TYPE_UT);
        }
        if (capabilities.isCapable(MmTelCapabilities.CAPABILITY_TYPE_SMS)) {
            mmTelCapabilities.addCapabilities(MmTelCapabilities.CAPABILITY_TYPE_SMS);
        }
        return mmTelCapabilities;
    }

    private void logd(String log) {
        Log.d(LOG_TAG, getLogPrefix().append(log).toString());
    }

    private void logi(String log) {
        Log.i(LOG_TAG, getLogPrefix().append(log).toString());
    }

    private void logw(String log) {
        Log.w(LOG_TAG, getLogPrefix().append(log).toString());
    }

    private StringBuilder getLogPrefix() {
        StringBuilder builder = new StringBuilder("[");
        builder.append(mSubId);
        builder.append("] ");
        return builder;
    }
}
+556 −0

File added.

Preview size limit exceeded, changes collapsed.

+74 −2
Original line number Diff line number Diff line
@@ -16,18 +16,90 @@

package com.android.ims.rcs.uce.presence.publish;

import android.annotation.IntDef;
import android.annotation.NonNull;
import android.telephony.ims.RcsContactUceCapability;
import android.telephony.ims.RcsUceAdapter.PublishState;
import android.telephony.ims.aidl.IRcsUcePublishStateCallback;

import com.android.ims.rcs.uce.ControllerBase;
import com.android.ims.rcs.uce.UceController.UceControllerCallback;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
 * The interface related to the PUBLISH request.
 */
public interface PublishController extends ControllerBase {

    /** Publish is triggered by the ImsService */
    int PUBLISH_TRIGGER_SERVICE = 1;

    /** Publish trigger type: retry */
    int PUBLISH_TRIGGER_RETRY = 2;

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

    /** Publish trigger type: VT setting changes */
    int PUBLISH_TRIGGER_VT_SETTING_CHANGE = 6;

    /** Publish trigger type: MMTEL registered */
    int PUBLISH_TRIGGER_MMTEL_REGISTERED = 7;

    /** Publish trigger type: MMTEL unregistered */
    int PUBLISH_TRIGGER_MMTEL_UNREGISTERED = 8;

    /** Publish trigger type: MMTEL capability changes */
    int PUBLISH_TRIGGER_MMTEL_CAPABILITY_CHANGE = 9;

    /** Publish trigger type: RCS registered */
    int PUBLISH_TRIGGER_RCS_REGISTERED = 10;

    /** Publish trigger type: RCS unregistered */
    int PUBLISH_TRIGGER_RCS_UNREGISTERED = 11;

    /** Publish trigger type: provisioning changes */
    int PUBLISH_TRIGGER_PROVISIONING_CHANGE = 12;

    @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,
            PUBLISH_TRIGGER_MMTEL_UNREGISTERED,
            PUBLISH_TRIGGER_MMTEL_CAPABILITY_CHANGE,
            PUBLISH_TRIGGER_RCS_REGISTERED,
            PUBLISH_TRIGGER_RCS_UNREGISTERED,
            PUBLISH_TRIGGER_PROVISIONING_CHANGE
    }, prefix="PUBLISH_TRIGGER_")
    @Retention(RetentionPolicy.SOURCE)
    @interface PublishTriggerType {}

    /**
     * Receive the callback from the sub-components which interact with PublishController.
     */
    interface PublishControllerCallback {
        /**
         * Request publish from local.
         */
        void requestPublishFromInternal(@PublishTriggerType int type, long delay);

        /**
         * Update the publish request result.
         */
        void updatePublishRequestResult(int publishState);
    }

    /**
     * Retrieve the RCS UCE Publish state.
     */
@@ -46,7 +118,7 @@ public interface PublishController extends ControllerBase {
    /**
     * Publish the device's capabilities to the Presence server.
     */
    void publishCapabilities(int triggerType);
    void requestPublishCapabilitiesFromService();

    /**
     * Register a {@link PublishStateCallback} to listen to the published state changed.
+360 −0

File added.

Preview size limit exceeded, changes collapsed.

Loading