Loading src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityInfo.java +90 −24 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import android.content.Context; import android.net.Uri; import android.telecom.TelecomManager; import android.telephony.AccessNetworkConstants; import android.telephony.ims.ImsRegistrationAttributes; import android.telephony.ims.RcsContactPresenceTuple; import android.telephony.ims.RcsContactPresenceTuple.ServiceCapabilities; import android.telephony.ims.RcsContactUceCapability; Loading @@ -32,6 +33,10 @@ import android.util.Log; import com.android.ims.rcs.uce.util.FeatureTags; import com.android.ims.rcs.uce.util.UceUtils; import com.android.internal.util.IndentingPrintWriter; import java.io.PrintWriter; import java.util.Set; /** * Stores the device's capabilities information. Loading @@ -41,6 +46,9 @@ public class DeviceCapabilityInfo { private final int mSubId; // Tracks capability status based on the IMS registration. private final PublishServiceDescTracker mServiceCapRegTracker; // The mmtel feature is registered or not private boolean mMmtelRegistered; Loading @@ -50,6 +58,9 @@ public class DeviceCapabilityInfo { // The rcs feature is registered or not private boolean mRcsRegistered; // Whether or not presence is reported as capable private boolean mPresenceCapable; // The network type which ims rcs registers on. private int mRcsNetworkRegType; Loading @@ -62,8 +73,9 @@ public class DeviceCapabilityInfo { private boolean mMobileData; private boolean mVtSetting; public DeviceCapabilityInfo(int subId) { public DeviceCapabilityInfo(int subId, String[] capToRegistrationMap) { mSubId = subId; mServiceCapRegTracker = PublishServiceDescTracker.fromCarrierConfig(capToRegistrationMap); reset(); } Loading Loading @@ -117,23 +129,29 @@ public class DeviceCapabilityInfo { mMmtelNetworkRegType = AccessNetworkConstants.TRANSPORT_TYPE_INVALID; } public synchronized void updatePresenceCapable(boolean isCapable) { mPresenceCapable = isCapable; } /** * Update the status that IMS RCS is registered. */ public synchronized void updateImsRcsRegistered(int type) { public synchronized void updateImsRcsRegistered(ImsRegistrationAttributes attr) { StringBuilder builder = new StringBuilder(); builder.append("IMS RCS registered: original state=").append(mRcsRegistered) .append(", changes type from ").append(mRcsNetworkRegType) .append(" to ").append(type); .append(" to ").append(attr.getTransportType()); logi(builder.toString()); if (!mRcsRegistered) { mRcsRegistered = true; } if (mRcsNetworkRegType != type) { mRcsNetworkRegType = type; if (mRcsNetworkRegType != attr.getTransportType()) { mRcsNetworkRegType = attr.getTransportType(); } mServiceCapRegTracker.updateImsRegistration(attr.getFeatureTags()); } /** Loading Loading @@ -234,6 +252,10 @@ public class DeviceCapabilityInfo { return false; } public synchronized boolean isPresenceCapable() { return mPresenceCapable; } private boolean isVolteAvailable(int networkRegType, MmTelCapabilities capabilities) { return (networkRegType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) && capabilities.isCapable(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE); Loading Loading @@ -282,33 +304,59 @@ public class DeviceCapabilityInfo { logw("getPresenceCapabilities: uri is empty"); return null; } ServiceCapabilities.Builder servCapsBuilder = new ServiceCapabilities.Builder( hasVolteCapability(), hasVtCapability()); servCapsBuilder.addSupportedDuplexMode(ServiceCapabilities.DUPLEX_MODE_FULL); RcsContactPresenceTuple.Builder tupleBuilder = new RcsContactPresenceTuple.Builder( RcsContactPresenceTuple.TUPLE_BASIC_STATUS_OPEN, RcsContactPresenceTuple.SERVICE_ID_MMTEL, "1.0"); tupleBuilder.setContactUri(uri).setServiceCapabilities(servCapsBuilder.build()); RcsContactPresenceTuple.Builder callComposerTupleBuilder = new RcsContactPresenceTuple.Builder( RcsContactPresenceTuple.TUPLE_BASIC_STATUS_OPEN, RcsContactPresenceTuple.SERVICE_ID_CALL_COMPOSER, "2.0"); callComposerTupleBuilder.setContactUri(uri).setServiceCapabilities( servCapsBuilder.build()); Set<ServiceDescription> capableFromReg = mServiceCapRegTracker.copyRegistrationCapabilities(); PresenceBuilder presenceBuilder = new PresenceBuilder(uri, RcsContactUceCapability.SOURCE_TYPE_CACHED, RcsContactUceCapability.REQUEST_RESULT_FOUND); presenceBuilder.addCapabilityTuple(tupleBuilder.build()); // RCS presence tag (added to all presence documents) ServiceDescription presDescription = getCustomizedDescription( ServiceDescription.SERVICE_DESCRIPTION_PRESENCE, capableFromReg); addCapability(presenceBuilder, presDescription.getTupleBuilder(), uri); capableFromReg.remove(presDescription); // mmtel ServiceDescription voiceDescription = getCustomizedDescription( ServiceDescription.SERVICE_DESCRIPTION_MMTEL_VOICE, capableFromReg); ServiceDescription vtDescription = getCustomizedDescription( ServiceDescription.SERVICE_DESCRIPTION_MMTEL_VOICE_VIDEO, capableFromReg); ServiceDescription descToUse = hasVtCapability() ? vtDescription : voiceDescription; ServiceCapabilities servCaps = new ServiceCapabilities.Builder( hasVolteCapability(), hasVtCapability()) .addSupportedDuplexMode(ServiceCapabilities.DUPLEX_MODE_FULL).build(); addCapability(presenceBuilder, descToUse.getTupleBuilder() .setServiceCapabilities(servCaps), uri); capableFromReg.remove(voiceDescription); capableFromReg.remove(vtDescription); // call composer via mmtel ServiceDescription composerDescription = getCustomizedDescription( ServiceDescription.SERVICE_DESCRIPTION_CALL_COMPOSER_MMTEL, capableFromReg); if (hasCallComposerCapability()) { presenceBuilder.addCapabilityTuple(callComposerTupleBuilder.build()); addCapability(presenceBuilder, composerDescription.getTupleBuilder(), uri); } capableFromReg.remove(composerDescription); // External features can only be found using registration states from other components. // Count these features as capable and include in PIDF XML if they are registered. for (ServiceDescription capability : capableFromReg) { addCapability(presenceBuilder, capability.getTupleBuilder(), uri); } return presenceBuilder.build(); } /** * Search the refSet for the ServiceDescription that matches the service-id && version and * return that or return the reference if there is no match. */ private ServiceDescription getCustomizedDescription(ServiceDescription reference, Set<ServiceDescription> refSet) { return refSet.stream().filter(s -> s.serviceId.equals(reference.serviceId) && s.version.equals(reference.version)).findFirst().orElse(reference); } // Get the device's capabilities with the OPTIONS mechanism. private RcsContactUceCapability getOptionsCapabilities(Context context) { Uri uri = PublishUtils.getDeviceContactUri(context, mSubId); Loading @@ -317,13 +365,20 @@ public class DeviceCapabilityInfo { return null; } Set<String> capableFromReg = mServiceCapRegTracker.copyRegistrationFeatureTags(); OptionsBuilder optionsBuilder = new OptionsBuilder(uri); optionsBuilder.setRequestResult(RcsContactUceCapability.REQUEST_RESULT_FOUND); FeatureTags.addMmTelFeatureTags(optionsBuilder, hasVolteCapability(), hasVtCapability()); FeatureTags.addFeatureTags(optionsBuilder, hasVolteCapability(), hasVtCapability(), isPresenceCapable(), hasCallComposerCapability(), capableFromReg); return optionsBuilder.build(); } private void addCapability(RcsContactUceCapability.PresenceBuilder presenceBuilder, RcsContactPresenceTuple.Builder tupleBuilder, Uri contactUri) { presenceBuilder.addCapabilityTuple(tupleBuilder.setContactUri(contactUri).build()); } // Check if the device has the VoLTE capability private synchronized boolean hasVolteCapability() { if (mMmTelCapabilities != null Loading Loading @@ -389,4 +444,15 @@ public class DeviceCapabilityInfo { builder.append("] "); return builder; } public void dump(PrintWriter printWriter) { IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); pw.println("DeviceCapabilityInfo :"); pw.increaseIndent(); pw.println("ServiceDescriptionTracker:"); mServiceCapRegTracker.dump(pw); pw.decreaseIndent(); } } src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListener.java +30 −5 Original line number Diff line number Diff line Loading @@ -34,15 +34,20 @@ import android.telephony.ims.ImsMmTelManager; import android.telephony.ims.ImsMmTelManager.CapabilityCallback; import android.telephony.ims.ImsRcsManager; import android.telephony.ims.ImsReasonInfo; import android.telephony.ims.ImsRegistrationAttributes; import android.telephony.ims.ProvisioningManager; import android.telephony.ims.RegistrationManager; import android.telephony.ims.feature.MmTelFeature.MmTelCapabilities; import android.util.LocalLog; import android.util.Log; import com.android.ims.rcs.uce.presence.publish.PublishController.PublishControllerCallback; import com.android.ims.rcs.uce.util.UceUtils; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.util.HandlerExecutor; import com.android.internal.util.IndentingPrintWriter; import java.io.PrintWriter; /** * Listen to the device changes and notify the PublishController to publish the device's Loading Loading @@ -113,6 +118,7 @@ public class DeviceCapabilityListener { private final int mSubId; private final Context mContext; private final LocalLog mLocalLog = new LocalLog(UceUtils.LOG_SIZE); private volatile boolean mInitialized; // The listener is destroyed Loading Loading @@ -373,10 +379,10 @@ public class DeviceCapabilityListener { public final RegistrationManager.RegistrationCallback mRcsRegistrationCallback = new RegistrationManager.RegistrationCallback() { @Override public void onRegistered(int imsTransportType) { public void onRegistered(ImsRegistrationAttributes attributes) { synchronized (mLock) { logi("onRcsRegistered: " + imsTransportType); handleImsRcsRegistered(imsTransportType); logi("onRcsRegistered: " + attributes); handleImsRcsRegistered(attributes); } } Loading Loading @@ -507,8 +513,8 @@ public class DeviceCapabilityListener { /* * This method is called when the RCS is registered. */ private void handleImsRcsRegistered(int imsTransportType) { mCapabilityInfo.updateImsRcsRegistered(imsTransportType); private void handleImsRcsRegistered(ImsRegistrationAttributes attr) { mCapabilityInfo.updateImsRcsRegistered(attr); mCallback.requestPublishFromInternal( PublishController.PUBLISH_TRIGGER_RCS_REGISTERED, DELAY_SEND_IMS_REGISTERED_CHANGED_MSG); Loading Loading @@ -545,14 +551,17 @@ public class DeviceCapabilityListener { private void logd(String log) { Log.d(LOG_TAG, getLogPrefix().append(log).toString()); mLocalLog.log("[D] " + log); } private void logi(String log) { Log.i(LOG_TAG, getLogPrefix().append(log).toString()); mLocalLog.log("[I] " + log); } private void logw(String log) { Log.w(LOG_TAG, getLogPrefix().append(log).toString()); mLocalLog.log("[W] " + log); } private StringBuilder getLogPrefix() { Loading @@ -561,4 +570,20 @@ public class DeviceCapabilityListener { builder.append("] "); return builder; } public void dump(PrintWriter printWriter) { IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); pw.println("DeviceCapListener" + "[subId: " + mSubId + "]:"); pw.increaseIndent(); mCapabilityInfo.dump(pw); pw.println("Log:"); pw.increaseIndent(); mLocalLog.dump(pw); pw.decreaseIndent(); pw.println("---"); pw.decreaseIndent(); } } src/java/com/android/ims/rcs/uce/presence/publish/PublishController.java +1 −1 Original line number Diff line number Diff line Loading @@ -121,7 +121,7 @@ public interface PublishController extends ControllerBase { /** * Update the publish request result. */ void updatePublishRequestResult(int publishState, Instant updatedTimestamp); void updatePublishRequestResult(int publishState, Instant updatedTimestamp, String pidfXml); } /** Loading src/java/com/android/ims/rcs/uce/presence/publish/PublishControllerImpl.java +45 −21 Original line number Diff line number Diff line Loading @@ -21,8 +21,10 @@ import android.content.Context; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.PersistableBundle; import android.os.RemoteCallbackList; import android.os.RemoteException; import android.telephony.CarrierConfigManager; import android.telephony.ims.ImsException; import android.telephony.ims.RcsContactUceCapability; import android.telephony.ims.RcsContactUceCapability.CapabilityMechanism; Loading @@ -38,6 +40,7 @@ import com.android.ims.RcsFeatureManager; import com.android.ims.rcs.uce.UceController.UceControllerCallback; import com.android.ims.rcs.uce.util.UceUtils; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.os.SomeArgs; import com.android.internal.util.IndentingPrintWriter; import java.io.PrintWriter; Loading Loading @@ -76,7 +79,6 @@ public class PublishControllerImpl implements PublishController { private final LocalLog mLocalLog = new LocalLog(UceUtils.LOG_SIZE); private PublishHandler mPublishHandler; private volatile boolean mIsDestroyedFlag; private volatile boolean mCapabilityPresenceEnabled; private volatile boolean mReceivePublishFromService; private volatile RcsFeatureManager mRcsFeatureManager; private final UceControllerCallback mUceCtrlCallback; Loading @@ -85,6 +87,8 @@ public class PublishControllerImpl implements PublishController { private @PublishState int mPublishState; // The timestamp of updating the publish state private Instant mPublishStateUpdatedTime = Instant.now(); // The last PIDF XML used in the publish private String mPidfXml; // The callbacks to notify publish state changed. private RemoteCallbackList<IRcsUcePublishStateCallback> mPublishStateCallbacks; Loading Loading @@ -116,11 +120,11 @@ public class PublishControllerImpl implements PublishController { public void onCapabilitiesStatusChanged(int capabilities) { logd("onCapabilitiesStatusChanged: " + capabilities); RcsImsCapabilities RcsImsCapabilities = new RcsImsCapabilities(capabilities); mCapabilityPresenceEnabled = RcsImsCapabilities.isCapable(RcsUceAdapter.CAPABILITY_TYPE_PRESENCE_UCE); mDeviceCapabilityInfo.updatePresenceCapable( RcsImsCapabilities.isCapable(RcsUceAdapter.CAPABILITY_TYPE_PRESENCE_UCE)); // Trigger a publish request if the RCS capabilities presence is enabled. if (mCapabilityPresenceEnabled) { if (mDeviceCapabilityInfo.isPresenceCapable()) { mPublishProcessor.checkAndSendPendingRequest(); } } Loading Loading @@ -156,7 +160,14 @@ public class PublishControllerImpl implements PublishController { mPublishStateCallbacks = new RemoteCallbackList<>(); mPublishHandler = new PublishHandler(this, looper); mDeviceCapabilityInfo = new DeviceCapabilityInfo(mSubId); CarrierConfigManager manager = mContext.getSystemService(CarrierConfigManager.class); PersistableBundle bundle = manager != null ? manager.getConfigForSubId(mSubId) : CarrierConfigManager.getDefaultConfig(); String[] serviceDescFeatureTagMap = bundle.getStringArray( CarrierConfigManager.Ims. KEY_PUBLISH_SERVICE_DESC_FEATURE_TAG_MAP_OVERRIDE_STRING_ARRAY); mDeviceCapabilityInfo = new DeviceCapabilityInfo(mSubId, serviceDescFeatureTagMap); initPublishProcessor(); initDeviceCapabilitiesListener(); Loading Loading @@ -187,7 +198,7 @@ public class PublishControllerImpl implements PublishController { public void onRcsDisconnected() { logd("onRcsDisconnected"); mRcsFeatureManager = null; mCapabilityPresenceEnabled = false; mDeviceCapabilityInfo.updatePresenceCapable(false); mPublishProcessor.onRcsDisconnected(); } Loading @@ -195,7 +206,7 @@ public class PublishControllerImpl implements PublishController { public void onDestroy() { logi("onDestroy"); mIsDestroyedFlag = true; mCapabilityPresenceEnabled = false; mDeviceCapabilityInfo.updatePresenceCapable(false); unregisterRcsAvailabilityChanged(); mDeviceCapListener.onDestroy(); // It will turn off the listener automatically. mPublishHandler.onDestroy(); Loading Loading @@ -259,7 +270,7 @@ public class PublishControllerImpl implements PublishController { logd("onUnpublish"); if (mIsDestroyedFlag) return; mPublishHandler.onPublishStateChanged(RcsUceAdapter.PUBLISH_STATE_NOT_PUBLISHED, Instant.now()); Instant.now(), null /*pidfXml*/); } @Override Loading Loading @@ -330,9 +341,9 @@ public class PublishControllerImpl implements PublishController { @Override public void updatePublishRequestResult(@PublishState int publishState, Instant updatedTime) { Instant updatedTime, String pidfXml) { logd("updatePublishRequestResult: " + publishState + ", time=" + updatedTime); mPublishHandler.onPublishStateChanged(publishState, updatedTime); mPublishHandler.onPublishStateChanged(publishState, updatedTime, pidfXml); } }; Loading Loading @@ -371,9 +382,13 @@ public class PublishControllerImpl implements PublishController { publishCtrl.logd("handleMessage: " + EVENT_DESCRIPTION.get(message.what)); switch (message.what) { case MSG_PUBLISH_STATE_CHANGED: int newPublishState = message.arg1; Instant updatedTimestamp = (Instant) message.obj; publishCtrl.handlePublishStateChangedMessage(newPublishState, updatedTimestamp); SomeArgs args = (SomeArgs) message.obj; int newPublishState = (Integer) args.arg1; Instant updatedTimestamp = (Instant) args.arg2; String pidfXml = (String) args.arg3; args.recycle(); publishCtrl.handlePublishStateChangedMessage(newPublishState, updatedTimestamp, pidfXml); break; case MSG_NOTIFY_CURRENT_PUBLISH_STATE: Loading Loading @@ -414,11 +429,15 @@ public class PublishControllerImpl implements PublishController { * Send the message to notify the publish state is changed. */ public void onPublishStateChanged(@PublishState int publishState, @NonNull Instant updatedTimestamp) { @NonNull Instant updatedTimestamp, String pidfXml) { Message message = obtainMessage(); SomeArgs args = SomeArgs.obtain(); args.arg1 = publishState; args.arg2 = updatedTimestamp; args.arg3 = pidfXml; message.what = MSG_PUBLISH_STATE_CHANGED; message.arg1 = publishState; message.obj = updatedTimestamp; message.obj = args; sendMessage(message); } Loading Loading @@ -446,7 +465,7 @@ public class PublishControllerImpl implements PublishController { } if (publishCtrl.mIsDestroyedFlag) return; // Check if the PUBLISH request is allowed. // Return if the RCS capabilities presence uce is not enabled. if (!publishCtrl.isPublishRequestAllowed()) { publishCtrl.logd("requestPublish: SKIP. The publish request is not allowed."); publishCtrl.mPublishProcessor.setPendingRequest(true); Loading Loading @@ -543,7 +562,7 @@ public class PublishControllerImpl implements PublishController { */ private boolean isPublishRequestAllowed() { // The PUBLISH request requires that the RCS PRESENCE is capable. if (!mCapabilityPresenceEnabled) { if (!mDeviceCapabilityInfo.isPresenceCapable()) { logd("isPublishRequestAllowed: capability presence uce is not enabled."); return false; } Loading @@ -560,7 +579,7 @@ public class PublishControllerImpl implements PublishController { * from original state. */ private void handlePublishStateChangedMessage(@PublishState int newPublishState, Instant updatedTimestamp) { Instant updatedTimestamp, String pidfXml) { synchronized (mPublishStateLock) { if (mIsDestroyedFlag) return; // Check if the time of the given publish state is not earlier than existing time. Loading @@ -575,6 +594,7 @@ public class PublishControllerImpl implements PublishController { if (mPublishState == newPublishState) return; mPublishState = newPublishState; mPublishStateUpdatedTime = updatedTimestamp; mPidfXml = pidfXml; } // Trigger the publish state changed in handler thread since it may take time. Loading Loading @@ -660,12 +680,16 @@ public class PublishControllerImpl implements PublishController { pw.println("PublishControllerImpl" + "[subId: " + mSubId + "]:"); pw.increaseIndent(); pw.print("mCapabilityPresenceEnabled="); pw.println(mCapabilityPresenceEnabled); pw.print("isPresenceCapable="); pw.println(mDeviceCapabilityInfo.isPresenceCapable()); pw.print("mPublishState="); pw.print(mPublishState); pw.print(" at time "); pw.println(mPublishStateUpdatedTime); pw.println("Last PIDF XML:"); pw.increaseIndent(); pw.println(mPidfXml); pw.decreaseIndent(); if (mPublishProcessor != null) { mPublishProcessor.dump(pw); Loading src/java/com/android/ims/rcs/uce/presence/publish/PublishProcessor.java +7 −3 Original line number Diff line number Diff line Loading @@ -210,7 +210,7 @@ public class PublishProcessor { // Generate a unique taskId to track this request. long taskId = mProcessorState.generatePublishTaskId(); requestResponse = new PublishRequestResponse(mPublishCtrlCallback, taskId); requestResponse = new PublishRequestResponse(mPublishCtrlCallback, taskId, pidfXml); mLocalLog.log("publish capabilities: taskId=" + taskId); logi("publishCapabilities: taskId=" + taskId); Loading Loading @@ -261,7 +261,9 @@ public class PublishProcessor { // Update the publish state if the request is failed and doesn't need to retry. int publishState = requestResponse.getPublishStateByCmdErrorCode(); Instant responseTimestamp = requestResponse.getResponseTimestamp(); mPublishCtrlCallback.updatePublishRequestResult(publishState, responseTimestamp); String pidfXml = requestResponse.getPidfXml(); mPublishCtrlCallback.updatePublishRequestResult(publishState, responseTimestamp, pidfXml); // Check if there is a pending request checkAndSendPendingRequest(); Loading Loading @@ -306,7 +308,9 @@ public class PublishProcessor { // Update the publish state if the request doesn't need to retry. int publishResult = requestResponse.getPublishStateByNetworkResponse(); Instant responseTimestamp = requestResponse.getResponseTimestamp(); mPublishCtrlCallback.updatePublishRequestResult(publishResult, responseTimestamp); String pidfXml = requestResponse.getPidfXml(); mPublishCtrlCallback.updatePublishRequestResult(publishResult, responseTimestamp, pidfXml); // Check if there is a pending request checkAndSendPendingRequest(); Loading Loading
src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityInfo.java +90 −24 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import android.content.Context; import android.net.Uri; import android.telecom.TelecomManager; import android.telephony.AccessNetworkConstants; import android.telephony.ims.ImsRegistrationAttributes; import android.telephony.ims.RcsContactPresenceTuple; import android.telephony.ims.RcsContactPresenceTuple.ServiceCapabilities; import android.telephony.ims.RcsContactUceCapability; Loading @@ -32,6 +33,10 @@ import android.util.Log; import com.android.ims.rcs.uce.util.FeatureTags; import com.android.ims.rcs.uce.util.UceUtils; import com.android.internal.util.IndentingPrintWriter; import java.io.PrintWriter; import java.util.Set; /** * Stores the device's capabilities information. Loading @@ -41,6 +46,9 @@ public class DeviceCapabilityInfo { private final int mSubId; // Tracks capability status based on the IMS registration. private final PublishServiceDescTracker mServiceCapRegTracker; // The mmtel feature is registered or not private boolean mMmtelRegistered; Loading @@ -50,6 +58,9 @@ public class DeviceCapabilityInfo { // The rcs feature is registered or not private boolean mRcsRegistered; // Whether or not presence is reported as capable private boolean mPresenceCapable; // The network type which ims rcs registers on. private int mRcsNetworkRegType; Loading @@ -62,8 +73,9 @@ public class DeviceCapabilityInfo { private boolean mMobileData; private boolean mVtSetting; public DeviceCapabilityInfo(int subId) { public DeviceCapabilityInfo(int subId, String[] capToRegistrationMap) { mSubId = subId; mServiceCapRegTracker = PublishServiceDescTracker.fromCarrierConfig(capToRegistrationMap); reset(); } Loading Loading @@ -117,23 +129,29 @@ public class DeviceCapabilityInfo { mMmtelNetworkRegType = AccessNetworkConstants.TRANSPORT_TYPE_INVALID; } public synchronized void updatePresenceCapable(boolean isCapable) { mPresenceCapable = isCapable; } /** * Update the status that IMS RCS is registered. */ public synchronized void updateImsRcsRegistered(int type) { public synchronized void updateImsRcsRegistered(ImsRegistrationAttributes attr) { StringBuilder builder = new StringBuilder(); builder.append("IMS RCS registered: original state=").append(mRcsRegistered) .append(", changes type from ").append(mRcsNetworkRegType) .append(" to ").append(type); .append(" to ").append(attr.getTransportType()); logi(builder.toString()); if (!mRcsRegistered) { mRcsRegistered = true; } if (mRcsNetworkRegType != type) { mRcsNetworkRegType = type; if (mRcsNetworkRegType != attr.getTransportType()) { mRcsNetworkRegType = attr.getTransportType(); } mServiceCapRegTracker.updateImsRegistration(attr.getFeatureTags()); } /** Loading Loading @@ -234,6 +252,10 @@ public class DeviceCapabilityInfo { return false; } public synchronized boolean isPresenceCapable() { return mPresenceCapable; } private boolean isVolteAvailable(int networkRegType, MmTelCapabilities capabilities) { return (networkRegType == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) && capabilities.isCapable(MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE); Loading Loading @@ -282,33 +304,59 @@ public class DeviceCapabilityInfo { logw("getPresenceCapabilities: uri is empty"); return null; } ServiceCapabilities.Builder servCapsBuilder = new ServiceCapabilities.Builder( hasVolteCapability(), hasVtCapability()); servCapsBuilder.addSupportedDuplexMode(ServiceCapabilities.DUPLEX_MODE_FULL); RcsContactPresenceTuple.Builder tupleBuilder = new RcsContactPresenceTuple.Builder( RcsContactPresenceTuple.TUPLE_BASIC_STATUS_OPEN, RcsContactPresenceTuple.SERVICE_ID_MMTEL, "1.0"); tupleBuilder.setContactUri(uri).setServiceCapabilities(servCapsBuilder.build()); RcsContactPresenceTuple.Builder callComposerTupleBuilder = new RcsContactPresenceTuple.Builder( RcsContactPresenceTuple.TUPLE_BASIC_STATUS_OPEN, RcsContactPresenceTuple.SERVICE_ID_CALL_COMPOSER, "2.0"); callComposerTupleBuilder.setContactUri(uri).setServiceCapabilities( servCapsBuilder.build()); Set<ServiceDescription> capableFromReg = mServiceCapRegTracker.copyRegistrationCapabilities(); PresenceBuilder presenceBuilder = new PresenceBuilder(uri, RcsContactUceCapability.SOURCE_TYPE_CACHED, RcsContactUceCapability.REQUEST_RESULT_FOUND); presenceBuilder.addCapabilityTuple(tupleBuilder.build()); // RCS presence tag (added to all presence documents) ServiceDescription presDescription = getCustomizedDescription( ServiceDescription.SERVICE_DESCRIPTION_PRESENCE, capableFromReg); addCapability(presenceBuilder, presDescription.getTupleBuilder(), uri); capableFromReg.remove(presDescription); // mmtel ServiceDescription voiceDescription = getCustomizedDescription( ServiceDescription.SERVICE_DESCRIPTION_MMTEL_VOICE, capableFromReg); ServiceDescription vtDescription = getCustomizedDescription( ServiceDescription.SERVICE_DESCRIPTION_MMTEL_VOICE_VIDEO, capableFromReg); ServiceDescription descToUse = hasVtCapability() ? vtDescription : voiceDescription; ServiceCapabilities servCaps = new ServiceCapabilities.Builder( hasVolteCapability(), hasVtCapability()) .addSupportedDuplexMode(ServiceCapabilities.DUPLEX_MODE_FULL).build(); addCapability(presenceBuilder, descToUse.getTupleBuilder() .setServiceCapabilities(servCaps), uri); capableFromReg.remove(voiceDescription); capableFromReg.remove(vtDescription); // call composer via mmtel ServiceDescription composerDescription = getCustomizedDescription( ServiceDescription.SERVICE_DESCRIPTION_CALL_COMPOSER_MMTEL, capableFromReg); if (hasCallComposerCapability()) { presenceBuilder.addCapabilityTuple(callComposerTupleBuilder.build()); addCapability(presenceBuilder, composerDescription.getTupleBuilder(), uri); } capableFromReg.remove(composerDescription); // External features can only be found using registration states from other components. // Count these features as capable and include in PIDF XML if they are registered. for (ServiceDescription capability : capableFromReg) { addCapability(presenceBuilder, capability.getTupleBuilder(), uri); } return presenceBuilder.build(); } /** * Search the refSet for the ServiceDescription that matches the service-id && version and * return that or return the reference if there is no match. */ private ServiceDescription getCustomizedDescription(ServiceDescription reference, Set<ServiceDescription> refSet) { return refSet.stream().filter(s -> s.serviceId.equals(reference.serviceId) && s.version.equals(reference.version)).findFirst().orElse(reference); } // Get the device's capabilities with the OPTIONS mechanism. private RcsContactUceCapability getOptionsCapabilities(Context context) { Uri uri = PublishUtils.getDeviceContactUri(context, mSubId); Loading @@ -317,13 +365,20 @@ public class DeviceCapabilityInfo { return null; } Set<String> capableFromReg = mServiceCapRegTracker.copyRegistrationFeatureTags(); OptionsBuilder optionsBuilder = new OptionsBuilder(uri); optionsBuilder.setRequestResult(RcsContactUceCapability.REQUEST_RESULT_FOUND); FeatureTags.addMmTelFeatureTags(optionsBuilder, hasVolteCapability(), hasVtCapability()); FeatureTags.addFeatureTags(optionsBuilder, hasVolteCapability(), hasVtCapability(), isPresenceCapable(), hasCallComposerCapability(), capableFromReg); return optionsBuilder.build(); } private void addCapability(RcsContactUceCapability.PresenceBuilder presenceBuilder, RcsContactPresenceTuple.Builder tupleBuilder, Uri contactUri) { presenceBuilder.addCapabilityTuple(tupleBuilder.setContactUri(contactUri).build()); } // Check if the device has the VoLTE capability private synchronized boolean hasVolteCapability() { if (mMmTelCapabilities != null Loading Loading @@ -389,4 +444,15 @@ public class DeviceCapabilityInfo { builder.append("] "); return builder; } public void dump(PrintWriter printWriter) { IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); pw.println("DeviceCapabilityInfo :"); pw.increaseIndent(); pw.println("ServiceDescriptionTracker:"); mServiceCapRegTracker.dump(pw); pw.decreaseIndent(); } }
src/java/com/android/ims/rcs/uce/presence/publish/DeviceCapabilityListener.java +30 −5 Original line number Diff line number Diff line Loading @@ -34,15 +34,20 @@ import android.telephony.ims.ImsMmTelManager; import android.telephony.ims.ImsMmTelManager.CapabilityCallback; import android.telephony.ims.ImsRcsManager; import android.telephony.ims.ImsReasonInfo; import android.telephony.ims.ImsRegistrationAttributes; import android.telephony.ims.ProvisioningManager; import android.telephony.ims.RegistrationManager; import android.telephony.ims.feature.MmTelFeature.MmTelCapabilities; import android.util.LocalLog; import android.util.Log; import com.android.ims.rcs.uce.presence.publish.PublishController.PublishControllerCallback; import com.android.ims.rcs.uce.util.UceUtils; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.util.HandlerExecutor; import com.android.internal.util.IndentingPrintWriter; import java.io.PrintWriter; /** * Listen to the device changes and notify the PublishController to publish the device's Loading Loading @@ -113,6 +118,7 @@ public class DeviceCapabilityListener { private final int mSubId; private final Context mContext; private final LocalLog mLocalLog = new LocalLog(UceUtils.LOG_SIZE); private volatile boolean mInitialized; // The listener is destroyed Loading Loading @@ -373,10 +379,10 @@ public class DeviceCapabilityListener { public final RegistrationManager.RegistrationCallback mRcsRegistrationCallback = new RegistrationManager.RegistrationCallback() { @Override public void onRegistered(int imsTransportType) { public void onRegistered(ImsRegistrationAttributes attributes) { synchronized (mLock) { logi("onRcsRegistered: " + imsTransportType); handleImsRcsRegistered(imsTransportType); logi("onRcsRegistered: " + attributes); handleImsRcsRegistered(attributes); } } Loading Loading @@ -507,8 +513,8 @@ public class DeviceCapabilityListener { /* * This method is called when the RCS is registered. */ private void handleImsRcsRegistered(int imsTransportType) { mCapabilityInfo.updateImsRcsRegistered(imsTransportType); private void handleImsRcsRegistered(ImsRegistrationAttributes attr) { mCapabilityInfo.updateImsRcsRegistered(attr); mCallback.requestPublishFromInternal( PublishController.PUBLISH_TRIGGER_RCS_REGISTERED, DELAY_SEND_IMS_REGISTERED_CHANGED_MSG); Loading Loading @@ -545,14 +551,17 @@ public class DeviceCapabilityListener { private void logd(String log) { Log.d(LOG_TAG, getLogPrefix().append(log).toString()); mLocalLog.log("[D] " + log); } private void logi(String log) { Log.i(LOG_TAG, getLogPrefix().append(log).toString()); mLocalLog.log("[I] " + log); } private void logw(String log) { Log.w(LOG_TAG, getLogPrefix().append(log).toString()); mLocalLog.log("[W] " + log); } private StringBuilder getLogPrefix() { Loading @@ -561,4 +570,20 @@ public class DeviceCapabilityListener { builder.append("] "); return builder; } public void dump(PrintWriter printWriter) { IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); pw.println("DeviceCapListener" + "[subId: " + mSubId + "]:"); pw.increaseIndent(); mCapabilityInfo.dump(pw); pw.println("Log:"); pw.increaseIndent(); mLocalLog.dump(pw); pw.decreaseIndent(); pw.println("---"); pw.decreaseIndent(); } }
src/java/com/android/ims/rcs/uce/presence/publish/PublishController.java +1 −1 Original line number Diff line number Diff line Loading @@ -121,7 +121,7 @@ public interface PublishController extends ControllerBase { /** * Update the publish request result. */ void updatePublishRequestResult(int publishState, Instant updatedTimestamp); void updatePublishRequestResult(int publishState, Instant updatedTimestamp, String pidfXml); } /** Loading
src/java/com/android/ims/rcs/uce/presence/publish/PublishControllerImpl.java +45 −21 Original line number Diff line number Diff line Loading @@ -21,8 +21,10 @@ import android.content.Context; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.PersistableBundle; import android.os.RemoteCallbackList; import android.os.RemoteException; import android.telephony.CarrierConfigManager; import android.telephony.ims.ImsException; import android.telephony.ims.RcsContactUceCapability; import android.telephony.ims.RcsContactUceCapability.CapabilityMechanism; Loading @@ -38,6 +40,7 @@ import com.android.ims.RcsFeatureManager; import com.android.ims.rcs.uce.UceController.UceControllerCallback; import com.android.ims.rcs.uce.util.UceUtils; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.os.SomeArgs; import com.android.internal.util.IndentingPrintWriter; import java.io.PrintWriter; Loading Loading @@ -76,7 +79,6 @@ public class PublishControllerImpl implements PublishController { private final LocalLog mLocalLog = new LocalLog(UceUtils.LOG_SIZE); private PublishHandler mPublishHandler; private volatile boolean mIsDestroyedFlag; private volatile boolean mCapabilityPresenceEnabled; private volatile boolean mReceivePublishFromService; private volatile RcsFeatureManager mRcsFeatureManager; private final UceControllerCallback mUceCtrlCallback; Loading @@ -85,6 +87,8 @@ public class PublishControllerImpl implements PublishController { private @PublishState int mPublishState; // The timestamp of updating the publish state private Instant mPublishStateUpdatedTime = Instant.now(); // The last PIDF XML used in the publish private String mPidfXml; // The callbacks to notify publish state changed. private RemoteCallbackList<IRcsUcePublishStateCallback> mPublishStateCallbacks; Loading Loading @@ -116,11 +120,11 @@ public class PublishControllerImpl implements PublishController { public void onCapabilitiesStatusChanged(int capabilities) { logd("onCapabilitiesStatusChanged: " + capabilities); RcsImsCapabilities RcsImsCapabilities = new RcsImsCapabilities(capabilities); mCapabilityPresenceEnabled = RcsImsCapabilities.isCapable(RcsUceAdapter.CAPABILITY_TYPE_PRESENCE_UCE); mDeviceCapabilityInfo.updatePresenceCapable( RcsImsCapabilities.isCapable(RcsUceAdapter.CAPABILITY_TYPE_PRESENCE_UCE)); // Trigger a publish request if the RCS capabilities presence is enabled. if (mCapabilityPresenceEnabled) { if (mDeviceCapabilityInfo.isPresenceCapable()) { mPublishProcessor.checkAndSendPendingRequest(); } } Loading Loading @@ -156,7 +160,14 @@ public class PublishControllerImpl implements PublishController { mPublishStateCallbacks = new RemoteCallbackList<>(); mPublishHandler = new PublishHandler(this, looper); mDeviceCapabilityInfo = new DeviceCapabilityInfo(mSubId); CarrierConfigManager manager = mContext.getSystemService(CarrierConfigManager.class); PersistableBundle bundle = manager != null ? manager.getConfigForSubId(mSubId) : CarrierConfigManager.getDefaultConfig(); String[] serviceDescFeatureTagMap = bundle.getStringArray( CarrierConfigManager.Ims. KEY_PUBLISH_SERVICE_DESC_FEATURE_TAG_MAP_OVERRIDE_STRING_ARRAY); mDeviceCapabilityInfo = new DeviceCapabilityInfo(mSubId, serviceDescFeatureTagMap); initPublishProcessor(); initDeviceCapabilitiesListener(); Loading Loading @@ -187,7 +198,7 @@ public class PublishControllerImpl implements PublishController { public void onRcsDisconnected() { logd("onRcsDisconnected"); mRcsFeatureManager = null; mCapabilityPresenceEnabled = false; mDeviceCapabilityInfo.updatePresenceCapable(false); mPublishProcessor.onRcsDisconnected(); } Loading @@ -195,7 +206,7 @@ public class PublishControllerImpl implements PublishController { public void onDestroy() { logi("onDestroy"); mIsDestroyedFlag = true; mCapabilityPresenceEnabled = false; mDeviceCapabilityInfo.updatePresenceCapable(false); unregisterRcsAvailabilityChanged(); mDeviceCapListener.onDestroy(); // It will turn off the listener automatically. mPublishHandler.onDestroy(); Loading Loading @@ -259,7 +270,7 @@ public class PublishControllerImpl implements PublishController { logd("onUnpublish"); if (mIsDestroyedFlag) return; mPublishHandler.onPublishStateChanged(RcsUceAdapter.PUBLISH_STATE_NOT_PUBLISHED, Instant.now()); Instant.now(), null /*pidfXml*/); } @Override Loading Loading @@ -330,9 +341,9 @@ public class PublishControllerImpl implements PublishController { @Override public void updatePublishRequestResult(@PublishState int publishState, Instant updatedTime) { Instant updatedTime, String pidfXml) { logd("updatePublishRequestResult: " + publishState + ", time=" + updatedTime); mPublishHandler.onPublishStateChanged(publishState, updatedTime); mPublishHandler.onPublishStateChanged(publishState, updatedTime, pidfXml); } }; Loading Loading @@ -371,9 +382,13 @@ public class PublishControllerImpl implements PublishController { publishCtrl.logd("handleMessage: " + EVENT_DESCRIPTION.get(message.what)); switch (message.what) { case MSG_PUBLISH_STATE_CHANGED: int newPublishState = message.arg1; Instant updatedTimestamp = (Instant) message.obj; publishCtrl.handlePublishStateChangedMessage(newPublishState, updatedTimestamp); SomeArgs args = (SomeArgs) message.obj; int newPublishState = (Integer) args.arg1; Instant updatedTimestamp = (Instant) args.arg2; String pidfXml = (String) args.arg3; args.recycle(); publishCtrl.handlePublishStateChangedMessage(newPublishState, updatedTimestamp, pidfXml); break; case MSG_NOTIFY_CURRENT_PUBLISH_STATE: Loading Loading @@ -414,11 +429,15 @@ public class PublishControllerImpl implements PublishController { * Send the message to notify the publish state is changed. */ public void onPublishStateChanged(@PublishState int publishState, @NonNull Instant updatedTimestamp) { @NonNull Instant updatedTimestamp, String pidfXml) { Message message = obtainMessage(); SomeArgs args = SomeArgs.obtain(); args.arg1 = publishState; args.arg2 = updatedTimestamp; args.arg3 = pidfXml; message.what = MSG_PUBLISH_STATE_CHANGED; message.arg1 = publishState; message.obj = updatedTimestamp; message.obj = args; sendMessage(message); } Loading Loading @@ -446,7 +465,7 @@ public class PublishControllerImpl implements PublishController { } if (publishCtrl.mIsDestroyedFlag) return; // Check if the PUBLISH request is allowed. // Return if the RCS capabilities presence uce is not enabled. if (!publishCtrl.isPublishRequestAllowed()) { publishCtrl.logd("requestPublish: SKIP. The publish request is not allowed."); publishCtrl.mPublishProcessor.setPendingRequest(true); Loading Loading @@ -543,7 +562,7 @@ public class PublishControllerImpl implements PublishController { */ private boolean isPublishRequestAllowed() { // The PUBLISH request requires that the RCS PRESENCE is capable. if (!mCapabilityPresenceEnabled) { if (!mDeviceCapabilityInfo.isPresenceCapable()) { logd("isPublishRequestAllowed: capability presence uce is not enabled."); return false; } Loading @@ -560,7 +579,7 @@ public class PublishControllerImpl implements PublishController { * from original state. */ private void handlePublishStateChangedMessage(@PublishState int newPublishState, Instant updatedTimestamp) { Instant updatedTimestamp, String pidfXml) { synchronized (mPublishStateLock) { if (mIsDestroyedFlag) return; // Check if the time of the given publish state is not earlier than existing time. Loading @@ -575,6 +594,7 @@ public class PublishControllerImpl implements PublishController { if (mPublishState == newPublishState) return; mPublishState = newPublishState; mPublishStateUpdatedTime = updatedTimestamp; mPidfXml = pidfXml; } // Trigger the publish state changed in handler thread since it may take time. Loading Loading @@ -660,12 +680,16 @@ public class PublishControllerImpl implements PublishController { pw.println("PublishControllerImpl" + "[subId: " + mSubId + "]:"); pw.increaseIndent(); pw.print("mCapabilityPresenceEnabled="); pw.println(mCapabilityPresenceEnabled); pw.print("isPresenceCapable="); pw.println(mDeviceCapabilityInfo.isPresenceCapable()); pw.print("mPublishState="); pw.print(mPublishState); pw.print(" at time "); pw.println(mPublishStateUpdatedTime); pw.println("Last PIDF XML:"); pw.increaseIndent(); pw.println(mPidfXml); pw.decreaseIndent(); if (mPublishProcessor != null) { mPublishProcessor.dump(pw); Loading
src/java/com/android/ims/rcs/uce/presence/publish/PublishProcessor.java +7 −3 Original line number Diff line number Diff line Loading @@ -210,7 +210,7 @@ public class PublishProcessor { // Generate a unique taskId to track this request. long taskId = mProcessorState.generatePublishTaskId(); requestResponse = new PublishRequestResponse(mPublishCtrlCallback, taskId); requestResponse = new PublishRequestResponse(mPublishCtrlCallback, taskId, pidfXml); mLocalLog.log("publish capabilities: taskId=" + taskId); logi("publishCapabilities: taskId=" + taskId); Loading Loading @@ -261,7 +261,9 @@ public class PublishProcessor { // Update the publish state if the request is failed and doesn't need to retry. int publishState = requestResponse.getPublishStateByCmdErrorCode(); Instant responseTimestamp = requestResponse.getResponseTimestamp(); mPublishCtrlCallback.updatePublishRequestResult(publishState, responseTimestamp); String pidfXml = requestResponse.getPidfXml(); mPublishCtrlCallback.updatePublishRequestResult(publishState, responseTimestamp, pidfXml); // Check if there is a pending request checkAndSendPendingRequest(); Loading Loading @@ -306,7 +308,9 @@ public class PublishProcessor { // Update the publish state if the request doesn't need to retry. int publishResult = requestResponse.getPublishStateByNetworkResponse(); Instant responseTimestamp = requestResponse.getResponseTimestamp(); mPublishCtrlCallback.updatePublishRequestResult(publishResult, responseTimestamp); String pidfXml = requestResponse.getPidfXml(); mPublishCtrlCallback.updatePublishRequestResult(publishResult, responseTimestamp, pidfXml); // Check if there is a pending request checkAndSendPendingRequest(); Loading