Loading src/java/com/android/ims/RcsFeatureConnection.java +7 −0 Original line number Diff line number Diff line Loading @@ -33,8 +33,10 @@ import android.telephony.ims.aidl.ISipTransport; import android.telephony.ims.feature.CapabilityChangeRequest; import android.telephony.ims.feature.ImsFeature; import com.android.ims.rcs.uce.RcsCapabilityExchangeImplAdapter.PublishResponseCallback; import com.android.internal.annotations.VisibleForTesting; import com.android.telephony.Rlog; import java.util.List; /** Loading Loading @@ -223,6 +225,11 @@ public class RcsFeatureConnection extends FeatureConnection { } } public void requestPublication(String pidfXml, PublishResponseCallback responseCallback) throws RemoteException { // TODO: add the new API: requestPublication } public void requestCapabilities(List<Uri> uris, int taskId) throws RemoteException { synchronized (mLock) { checkServiceIsReady(); Loading src/java/com/android/ims/RcsFeatureManager.java +6 −0 Original line number Diff line number Diff line Loading @@ -47,6 +47,7 @@ import android.telephony.ims.stub.RcsSipOptionsImplBase; import android.util.Log; import com.android.ims.internal.IImsServiceFeatureCallback; import com.android.ims.rcs.uce.RcsCapabilityExchangeImplAdapter.PublishResponseCallback; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.ITelephony; import com.android.telephony.Rlog; Loading Loading @@ -449,6 +450,11 @@ public class RcsFeatureManager implements FeatureUpdates { mRcsFeatureConnection.requestPublication(capabilities, taskId); } public void requestPublication(String pidfXml, PublishResponseCallback responseCallback) throws RemoteException { mRcsFeatureConnection.requestPublication(pidfXml, responseCallback); } public void requestCapabilities(List<Uri> uris, int taskId) throws RemoteException { mRcsFeatureConnection.requestCapabilities(uris, taskId); } Loading src/java/com/android/ims/rcs/uce/presence/publish/PublishController.java +21 −0 Original line number Diff line number Diff line Loading @@ -94,6 +94,27 @@ public interface PublishController extends ControllerBase { */ void requestPublishFromInternal(@PublishTriggerType int type, long delay); /** * Receive the command error callback of the request from ImsService. */ void onRequestCommandError(PublishRequestResponse requestResponse); /** * Receive the network response callback fo the request from ImsService. */ void onRequestNetworkResp(PublishRequestResponse requestResponse); /** * Set the timer to cancel the request. This timer is to prevent taking too long for * waiting the response callback. */ void setupRequestCanceledTimer(long taskId, long delay); /** * Clear the request canceled timer. This api will be called if the request is finished. */ void clearRequestCanceledTimer(); /** * Update the publish request result. */ Loading src/java/com/android/ims/rcs/uce/presence/publish/PublishControllerImpl.java +80 −1 Original line number Diff line number Diff line Loading @@ -212,6 +212,30 @@ public class PublishControllerImpl implements PublishController { mPublishHandler.requestPublish(type, delay); } @Override public void onRequestCommandError(PublishRequestResponse requestResponse) { logd("onRequestCommandError: taskId=" + requestResponse.getTaskId()); mPublishHandler.onRequestCommandError(requestResponse); } @Override public void onRequestNetworkResp(PublishRequestResponse requestResponse) { logd("onRequestNetworkResp: taskId=" + requestResponse.getTaskId()); mPublishHandler.onRequestNetworkResponse(requestResponse); } @Override public void setupRequestCanceledTimer(long taskId, long delay) { logd("setupRequestCanceledTimer: taskId=" + taskId + ", delay=" + delay); mPublishHandler.setRequestCanceledTimer(taskId, delay); } @Override public void clearRequestCanceledTimer() { logd("clearRequestCanceledTimer"); mPublishHandler.clearRequestCanceledTimer(); } @Override public void updatePublishRequestResult(@PublishState int publishState) { logd("updatePublishRequestResult: " + publishState); Loading @@ -231,6 +255,9 @@ public class PublishControllerImpl implements PublishController { private class PublishHandler extends Handler { private static final int MSG_PUBLISH_STATE_CHANGED = 1; private static final int MSG_REQUEST_PUBLISH = 2; private static final int MSG_REQUEST_CMD_ERROR = 3; private static final int MSG_REQUEST_SIP_RESPONSE = 4; private static final int MSG_REQUEST_CANCELED = 5; public PublishHandler(Looper looper) { super(looper); Loading @@ -250,6 +277,21 @@ public class PublishControllerImpl implements PublishController { int type = (Integer) message.obj; handleRequestPublishMessage(type); break; case MSG_REQUEST_CMD_ERROR: PublishRequestResponse cmdErrorResponse = (PublishRequestResponse) message.obj; mPublishProcessor.onCommandError(cmdErrorResponse); break; case MSG_REQUEST_SIP_RESPONSE: PublishRequestResponse networkResponse = (PublishRequestResponse) message.obj; mPublishProcessor.onNetworkResponse(networkResponse); break; case MSG_REQUEST_CANCELED: long taskId = (Long) message.obj; handleRequestCanceledMessage(taskId); break; } } Loading Loading @@ -297,6 +339,39 @@ public class PublishControllerImpl implements PublishController { sendMessage(message); } } public void onRequestCommandError(PublishRequestResponse requestResponse) { if (mIsDestroyedFlag) return; Message message = obtainMessage(); message.what = MSG_REQUEST_CMD_ERROR; message.obj = requestResponse; sendMessage(message); } public void onRequestNetworkResponse(PublishRequestResponse requestResponse) { if (mIsDestroyedFlag) return; Message message = obtainMessage(); message.what = MSG_REQUEST_SIP_RESPONSE; message.obj = requestResponse; sendMessage(message); } public void setRequestCanceledTimer(long taskId, long delay) { if (mIsDestroyedFlag) return; removeMessages(MSG_REQUEST_CANCELED, (Long) taskId); Message message = obtainMessage(); message.what = MSG_REQUEST_CANCELED; message.obj = (Long) taskId; sendMessageDelayed(message, delay); } public void clearRequestCanceledTimer() { if (mIsDestroyedFlag) return; removeMessages(MSG_REQUEST_CANCELED); } } /** Loading Loading @@ -325,10 +400,14 @@ public class PublishControllerImpl implements PublishController { public void handleRequestPublishMessage(@PublishTriggerType int type) { if (mIsDestroyedFlag) return; logd("handleRequestPublishMessage"); mPublishProcessor.doPublish(type); } public void handleRequestCanceledMessage(long taskId) { if (mIsDestroyedFlag) return; mPublishProcessor.cancelPublishRequest(taskId); } @VisibleForTesting public void setPublishStateCallback(RemoteCallbackList<IRcsUcePublishStateCallback> list) { mPublishStateCallbacks = list; Loading src/java/com/android/ims/rcs/uce/presence/publish/PublishProcessor.java +369 −5 Original line number Diff line number Diff line Loading @@ -17,27 +17,81 @@ package com.android.ims.rcs.uce.presence.publish; import android.content.Context; import android.os.RemoteException; import android.telephony.ims.RcsContactUceCapability; import android.text.TextUtils; import android.util.LocalLog; import android.util.Log; import com.android.ims.RcsFeatureManager; import com.android.ims.rcs.uce.presence.pidfparser.PidfParser; import com.android.ims.rcs.uce.presence.publish.PublishController.PublishControllerCallback; import com.android.ims.rcs.uce.presence.publish.PublishController.PublishTriggerType; import com.android.ims.rcs.uce.util.UceUtils; import com.android.internal.annotations.VisibleForTesting; import java.io.PrintWriter; /** * Send the publish request and handle the response of the publish request result. */ public class PublishProcessor { private static final String LOG_TAG = "PublishProcessor"; // The length of time waiting for the response callback. private static final long RESPONSE_CALLBACK_WAITING_TIME = 60000L; private final int mSubId; private final Context mContext; private volatile boolean mIsDestroyed; private volatile RcsFeatureManager mRcsFeatureManager; // Manage the state of the publish processor. private PublishProcessorState mProcessorState; // The information of the device's capabilities. private DeviceCapabilityInfo mDeviceCapabilities; // The callback of the PublishController private PublishControllerCallback mPublishCtrlCallback; private final LocalLog mLocalLog = new LocalLog(20); public PublishProcessor(Context context, int subId, DeviceCapabilityInfo capabilityInfo, PublishControllerCallback callback) { PublishControllerCallback publishCtrlCallback) { mSubId = subId; mContext = context; mDeviceCapabilities = capabilityInfo; mPublishCtrlCallback = publishCtrlCallback; mProcessorState = new PublishProcessorState(); } /** * The RcsFeature has been connected to the framework. */ public void onRcsConnected(RcsFeatureManager featureManager) { // TODO: Implement this method mLocalLog.log("onRcsConnected"); logi("onRcsConnected"); mRcsFeatureManager = featureManager; } /** * The framework has lost the binding to the RcsFeature. */ public void onRcsDisconnected() { // TODO: Implement this method mLocalLog.log("onRcsDisconnected"); logi("onRcsDisconnected"); mRcsFeatureManager = null; } /** * Set the destroy flag */ public void onDestroy() { // TODO: Implement this method mLocalLog.log("onDestroy"); logi("onDestroy"); mIsDestroyed = true; } /** Loading @@ -45,6 +99,316 @@ public class PublishProcessor { * @param triggerType The type of triggering the publish request. */ public void doPublish(@PublishTriggerType int triggerType) { // TODO: Implement this method if (mIsDestroyed) return; mLocalLog.log("doPublish: trigger type=" + triggerType); logi("doPublish: trigger type=" + triggerType); // Check if it should reset the retry count. if (isResetRetryNeeded(triggerType)) { mProcessorState.resetRetryCount(); } // Return if this request is not allowed to execute. if (!isRequestAllowed()) { mLocalLog.log("doPublish: The request is not allowed"); return; } // Get the latest device's capabilities. RcsContactUceCapability deviceCapability = mDeviceCapabilities.getDeviceCapabilities(mContext); if (deviceCapability == null) { logw("doPublish: device capability is null"); return; } // Convert the device's capabilities to pidf format. String pidfXml = PidfParser.convertToPidf(deviceCapability); if (TextUtils.isEmpty(pidfXml)) { logw("doPublish: pidfXml is empty"); return; } // Publish to the Presence server. publishCapabilities(pidfXml); } // Check if the giving trigger type should reset the retry count. private boolean isResetRetryNeeded(@PublishTriggerType int triggerType) { // Do no reset the retry count if the request is triggered by the previous failed retry. if (triggerType == PublishController.PUBLISH_TRIGGER_RETRY) { return false; } return true; } // Check if the publish request is allowed to execute. private boolean isRequestAllowed() { // Check if the instance is destroyed. if (mIsDestroyed) { logd("isPublishAllowed: This instance is already destroyed"); return false; } // Check if it has provisioned. When the provisioning changes, a new publish request will // be triggered. if (!UceUtils.isEabProvisioned(mContext, mSubId)) { logd("isPublishAllowed: NOT provisioned"); return false; } // Do not request publish if the IMS is not registered. When the IMS is registered // afterward, a new publish request will be triggered. if (!mDeviceCapabilities.isImsRegistered()) { logd("isPublishAllowed: IMS is not registered"); return false; } // Set the pending flag if there's already a request running now. if (mProcessorState.isPublishingNow()) { logd("isPublishAllowed: There is already a request running now"); mProcessorState.setPendingRequest(true); return false; } // Check if the publishing request has reached the maximum number of retries. if (mProcessorState.isReachMaximumRetries()) { logd("isPublishAllowed: It has reached maximum number of retries"); return false; } // Skip this request and re-send the request with the delay time if the publish request // executes too frequently. if (!mProcessorState.isCurrentTimeAllowed()) { logd("isPublishAllowed: Current time is not allowed, resend this request"); long delayTime = mProcessorState.getDelayTimeToAllowPublish(); mPublishCtrlCallback.requestPublishFromInternal( PublishController.PUBLISH_TRIGGER_RETRY, delayTime); return false; } return true; } // Publish the device capabilities with the given pidf private void publishCapabilities(String pidfXml) { if (mIsDestroyed) { logw("publishCapabilities: This instance is already destroyed"); return; } // Check if the RCS is connected. RcsFeatureManager featureManager = mRcsFeatureManager; if (featureManager == null) { mLocalLog.log("publish capabilities: not connected"); logw("publishCapabilities: NOT connected"); return; } PublishRequestResponse requestResponse = null; try { // Set publishing flag mProcessorState.setPublishingFlag(true); // Clear the pending request flag since we're publishing the latest device's capability mProcessorState.setPendingRequest(false); // Generate a unique taskId to track this request. long taskId = mProcessorState.generatePublishTaskId(); requestResponse = new PublishRequestResponse(mPublishCtrlCallback, taskId); mLocalLog.log("publish capabilities: taskId=" + taskId); logi("publishCapabilities: taskId=" + taskId); // request publication featureManager.requestPublication(pidfXml, requestResponse); // Send a request canceled timer to avoid waiting too long for the response callback. mPublishCtrlCallback.setupRequestCanceledTimer(taskId, RESPONSE_CALLBACK_WAITING_TIME); } catch (RemoteException e) { mLocalLog.log("publish capability exception: " + e.getMessage()); logw("publishCapabilities: exception=" + e.getMessage()); // Exception occurred, end this request. setRequestEnded(requestResponse); checkAndSendPendingRequest(); } } /** * Handle the command error callback of the publish request. This method is called by the * handler of the PublishController. */ public void onCommandError(PublishRequestResponse requestResponse) { if (!checkRequestRespValid(requestResponse)) { mLocalLog.log("Command error callback is invalid"); logw("onCommandError: request response is invalid"); setRequestEnded(requestResponse); checkAndSendPendingRequest(); return; } mLocalLog.log("Receive command error code=" + requestResponse.getCmdErrorCode()); logd("onCommandError: " + requestResponse.toString()); if (requestResponse.needRetry()) { // Increase the retry count mProcessorState.increaseRetryCount(); // Reset the pending flag since it is going to resend a publish request. mProcessorState.setPendingRequest(false); // Resend a publish request long delayTime = mProcessorState.getDelayTimeToAllowPublish(); mPublishCtrlCallback.requestPublishFromInternal( PublishController.PUBLISH_TRIGGER_RETRY, delayTime); } else { // Update the publish state if the request is failed and doesn't need to retry. int publishState = requestResponse.getPublishStateByCmdErrorCode(); mPublishCtrlCallback.updatePublishRequestResult(publishState); // Check if there is a pending request checkAndSendPendingRequest(); } // End this request setRequestEnded(requestResponse); } /** * Handle the network response callback of the publish request. This method is called by the * handler of the PublishController. */ public void onNetworkResponse(PublishRequestResponse requestResponse) { if (!checkRequestRespValid(requestResponse)) { mLocalLog.log("Network response callback is invalid"); logw("onNetworkResponse: request response is invalid"); setRequestEnded(requestResponse); checkAndSendPendingRequest(); return; } mLocalLog.log("Receive network response code=" + requestResponse.getNetworkRespSipCode()); logd("onNetworkResponse: " + requestResponse.toString()); if (requestResponse.needRetry()) { // Increase the retry count mProcessorState.increaseRetryCount(); // Reset the pending flag since it is going to resend a publish request. mProcessorState.setPendingRequest(false); // Resend a publish request long delayTime = mProcessorState.getDelayTimeToAllowPublish(); mPublishCtrlCallback.requestPublishFromInternal( PublishController.PUBLISH_TRIGGER_RETRY, delayTime); } else { // Reset the retry count if the publish is success. if (requestResponse.isRequestSuccess()) { mProcessorState.resetRetryCount(); } // Update the publish state if the request doesn't need to retry. int publishResult = requestResponse.getPublishStateByNetworkResponse(); mPublishCtrlCallback.updatePublishRequestResult(publishResult); // Check if there is a pending request checkAndSendPendingRequest(); } // End this request setRequestEnded(requestResponse); } // Check if the request response callback is valid. private boolean checkRequestRespValid(PublishRequestResponse requestResponse) { if (requestResponse == null) { logd("checkRequestRespValid: request response is null"); return false; } if (!mProcessorState.isPublishingNow()) { logd("checkRequestRespValid: the request is finished"); return false; } // Abandon this response callback if the current taskId is different to the response // callback taskId. This response callback is obsoleted. long taskId = mProcessorState.getCurrentTaskId(); long responseTaskId = requestResponse.getTaskId(); if (taskId != responseTaskId) { logd("checkRequestRespValid: invalid taskId! current taskId=" + taskId + ", response callback taskId=" + responseTaskId); return false; } if (mIsDestroyed) { logd("checkRequestRespValid: is already destroyed! taskId=" + taskId); return false; } return true; } /** * Cancel the publishing request since it has token too long for waiting the response callback. * This method is called by the handler of the PublishController. */ public void cancelPublishRequest(long taskId) { mLocalLog.log("cancel publish request: taskId=" + taskId); logd("cancelPublishRequest: taskId=" + taskId); setRequestEnded(null); checkAndSendPendingRequest(); } private void setRequestEnded(PublishRequestResponse requestResponse) { long taskId = -1L; if (requestResponse != null) { requestResponse.onDestroy(); taskId = requestResponse.getTaskId(); } mProcessorState.setPublishingFlag(false); mPublishCtrlCallback.clearRequestCanceledTimer(); mLocalLog.log("Set request ended: taskId=" + taskId); logd("setRequestEnded: taskId=" + taskId); } private void checkAndSendPendingRequest() { if (mIsDestroyed) return; if (mProcessorState.hasPendingRequest()) { logd("checkAndSendPendingRequest: send pending request"); mProcessorState.setPublishingFlag(false); long delayTime = mProcessorState.getDelayTimeToAllowPublish(); mPublishCtrlCallback.requestPublishFromInternal( PublishController.PUBLISH_TRIGGER_RETRY, delayTime); } } @VisibleForTesting public void setProcessorState(PublishProcessorState processorState) { mProcessorState = processorState; } 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; } public void dump(PrintWriter printWriter) { mLocalLog.dump(printWriter); } } Loading
src/java/com/android/ims/RcsFeatureConnection.java +7 −0 Original line number Diff line number Diff line Loading @@ -33,8 +33,10 @@ import android.telephony.ims.aidl.ISipTransport; import android.telephony.ims.feature.CapabilityChangeRequest; import android.telephony.ims.feature.ImsFeature; import com.android.ims.rcs.uce.RcsCapabilityExchangeImplAdapter.PublishResponseCallback; import com.android.internal.annotations.VisibleForTesting; import com.android.telephony.Rlog; import java.util.List; /** Loading Loading @@ -223,6 +225,11 @@ public class RcsFeatureConnection extends FeatureConnection { } } public void requestPublication(String pidfXml, PublishResponseCallback responseCallback) throws RemoteException { // TODO: add the new API: requestPublication } public void requestCapabilities(List<Uri> uris, int taskId) throws RemoteException { synchronized (mLock) { checkServiceIsReady(); Loading
src/java/com/android/ims/RcsFeatureManager.java +6 −0 Original line number Diff line number Diff line Loading @@ -47,6 +47,7 @@ import android.telephony.ims.stub.RcsSipOptionsImplBase; import android.util.Log; import com.android.ims.internal.IImsServiceFeatureCallback; import com.android.ims.rcs.uce.RcsCapabilityExchangeImplAdapter.PublishResponseCallback; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.telephony.ITelephony; import com.android.telephony.Rlog; Loading Loading @@ -449,6 +450,11 @@ public class RcsFeatureManager implements FeatureUpdates { mRcsFeatureConnection.requestPublication(capabilities, taskId); } public void requestPublication(String pidfXml, PublishResponseCallback responseCallback) throws RemoteException { mRcsFeatureConnection.requestPublication(pidfXml, responseCallback); } public void requestCapabilities(List<Uri> uris, int taskId) throws RemoteException { mRcsFeatureConnection.requestCapabilities(uris, taskId); } Loading
src/java/com/android/ims/rcs/uce/presence/publish/PublishController.java +21 −0 Original line number Diff line number Diff line Loading @@ -94,6 +94,27 @@ public interface PublishController extends ControllerBase { */ void requestPublishFromInternal(@PublishTriggerType int type, long delay); /** * Receive the command error callback of the request from ImsService. */ void onRequestCommandError(PublishRequestResponse requestResponse); /** * Receive the network response callback fo the request from ImsService. */ void onRequestNetworkResp(PublishRequestResponse requestResponse); /** * Set the timer to cancel the request. This timer is to prevent taking too long for * waiting the response callback. */ void setupRequestCanceledTimer(long taskId, long delay); /** * Clear the request canceled timer. This api will be called if the request is finished. */ void clearRequestCanceledTimer(); /** * Update the publish request result. */ Loading
src/java/com/android/ims/rcs/uce/presence/publish/PublishControllerImpl.java +80 −1 Original line number Diff line number Diff line Loading @@ -212,6 +212,30 @@ public class PublishControllerImpl implements PublishController { mPublishHandler.requestPublish(type, delay); } @Override public void onRequestCommandError(PublishRequestResponse requestResponse) { logd("onRequestCommandError: taskId=" + requestResponse.getTaskId()); mPublishHandler.onRequestCommandError(requestResponse); } @Override public void onRequestNetworkResp(PublishRequestResponse requestResponse) { logd("onRequestNetworkResp: taskId=" + requestResponse.getTaskId()); mPublishHandler.onRequestNetworkResponse(requestResponse); } @Override public void setupRequestCanceledTimer(long taskId, long delay) { logd("setupRequestCanceledTimer: taskId=" + taskId + ", delay=" + delay); mPublishHandler.setRequestCanceledTimer(taskId, delay); } @Override public void clearRequestCanceledTimer() { logd("clearRequestCanceledTimer"); mPublishHandler.clearRequestCanceledTimer(); } @Override public void updatePublishRequestResult(@PublishState int publishState) { logd("updatePublishRequestResult: " + publishState); Loading @@ -231,6 +255,9 @@ public class PublishControllerImpl implements PublishController { private class PublishHandler extends Handler { private static final int MSG_PUBLISH_STATE_CHANGED = 1; private static final int MSG_REQUEST_PUBLISH = 2; private static final int MSG_REQUEST_CMD_ERROR = 3; private static final int MSG_REQUEST_SIP_RESPONSE = 4; private static final int MSG_REQUEST_CANCELED = 5; public PublishHandler(Looper looper) { super(looper); Loading @@ -250,6 +277,21 @@ public class PublishControllerImpl implements PublishController { int type = (Integer) message.obj; handleRequestPublishMessage(type); break; case MSG_REQUEST_CMD_ERROR: PublishRequestResponse cmdErrorResponse = (PublishRequestResponse) message.obj; mPublishProcessor.onCommandError(cmdErrorResponse); break; case MSG_REQUEST_SIP_RESPONSE: PublishRequestResponse networkResponse = (PublishRequestResponse) message.obj; mPublishProcessor.onNetworkResponse(networkResponse); break; case MSG_REQUEST_CANCELED: long taskId = (Long) message.obj; handleRequestCanceledMessage(taskId); break; } } Loading Loading @@ -297,6 +339,39 @@ public class PublishControllerImpl implements PublishController { sendMessage(message); } } public void onRequestCommandError(PublishRequestResponse requestResponse) { if (mIsDestroyedFlag) return; Message message = obtainMessage(); message.what = MSG_REQUEST_CMD_ERROR; message.obj = requestResponse; sendMessage(message); } public void onRequestNetworkResponse(PublishRequestResponse requestResponse) { if (mIsDestroyedFlag) return; Message message = obtainMessage(); message.what = MSG_REQUEST_SIP_RESPONSE; message.obj = requestResponse; sendMessage(message); } public void setRequestCanceledTimer(long taskId, long delay) { if (mIsDestroyedFlag) return; removeMessages(MSG_REQUEST_CANCELED, (Long) taskId); Message message = obtainMessage(); message.what = MSG_REQUEST_CANCELED; message.obj = (Long) taskId; sendMessageDelayed(message, delay); } public void clearRequestCanceledTimer() { if (mIsDestroyedFlag) return; removeMessages(MSG_REQUEST_CANCELED); } } /** Loading Loading @@ -325,10 +400,14 @@ public class PublishControllerImpl implements PublishController { public void handleRequestPublishMessage(@PublishTriggerType int type) { if (mIsDestroyedFlag) return; logd("handleRequestPublishMessage"); mPublishProcessor.doPublish(type); } public void handleRequestCanceledMessage(long taskId) { if (mIsDestroyedFlag) return; mPublishProcessor.cancelPublishRequest(taskId); } @VisibleForTesting public void setPublishStateCallback(RemoteCallbackList<IRcsUcePublishStateCallback> list) { mPublishStateCallbacks = list; Loading
src/java/com/android/ims/rcs/uce/presence/publish/PublishProcessor.java +369 −5 Original line number Diff line number Diff line Loading @@ -17,27 +17,81 @@ package com.android.ims.rcs.uce.presence.publish; import android.content.Context; import android.os.RemoteException; import android.telephony.ims.RcsContactUceCapability; import android.text.TextUtils; import android.util.LocalLog; import android.util.Log; import com.android.ims.RcsFeatureManager; import com.android.ims.rcs.uce.presence.pidfparser.PidfParser; import com.android.ims.rcs.uce.presence.publish.PublishController.PublishControllerCallback; import com.android.ims.rcs.uce.presence.publish.PublishController.PublishTriggerType; import com.android.ims.rcs.uce.util.UceUtils; import com.android.internal.annotations.VisibleForTesting; import java.io.PrintWriter; /** * Send the publish request and handle the response of the publish request result. */ public class PublishProcessor { private static final String LOG_TAG = "PublishProcessor"; // The length of time waiting for the response callback. private static final long RESPONSE_CALLBACK_WAITING_TIME = 60000L; private final int mSubId; private final Context mContext; private volatile boolean mIsDestroyed; private volatile RcsFeatureManager mRcsFeatureManager; // Manage the state of the publish processor. private PublishProcessorState mProcessorState; // The information of the device's capabilities. private DeviceCapabilityInfo mDeviceCapabilities; // The callback of the PublishController private PublishControllerCallback mPublishCtrlCallback; private final LocalLog mLocalLog = new LocalLog(20); public PublishProcessor(Context context, int subId, DeviceCapabilityInfo capabilityInfo, PublishControllerCallback callback) { PublishControllerCallback publishCtrlCallback) { mSubId = subId; mContext = context; mDeviceCapabilities = capabilityInfo; mPublishCtrlCallback = publishCtrlCallback; mProcessorState = new PublishProcessorState(); } /** * The RcsFeature has been connected to the framework. */ public void onRcsConnected(RcsFeatureManager featureManager) { // TODO: Implement this method mLocalLog.log("onRcsConnected"); logi("onRcsConnected"); mRcsFeatureManager = featureManager; } /** * The framework has lost the binding to the RcsFeature. */ public void onRcsDisconnected() { // TODO: Implement this method mLocalLog.log("onRcsDisconnected"); logi("onRcsDisconnected"); mRcsFeatureManager = null; } /** * Set the destroy flag */ public void onDestroy() { // TODO: Implement this method mLocalLog.log("onDestroy"); logi("onDestroy"); mIsDestroyed = true; } /** Loading @@ -45,6 +99,316 @@ public class PublishProcessor { * @param triggerType The type of triggering the publish request. */ public void doPublish(@PublishTriggerType int triggerType) { // TODO: Implement this method if (mIsDestroyed) return; mLocalLog.log("doPublish: trigger type=" + triggerType); logi("doPublish: trigger type=" + triggerType); // Check if it should reset the retry count. if (isResetRetryNeeded(triggerType)) { mProcessorState.resetRetryCount(); } // Return if this request is not allowed to execute. if (!isRequestAllowed()) { mLocalLog.log("doPublish: The request is not allowed"); return; } // Get the latest device's capabilities. RcsContactUceCapability deviceCapability = mDeviceCapabilities.getDeviceCapabilities(mContext); if (deviceCapability == null) { logw("doPublish: device capability is null"); return; } // Convert the device's capabilities to pidf format. String pidfXml = PidfParser.convertToPidf(deviceCapability); if (TextUtils.isEmpty(pidfXml)) { logw("doPublish: pidfXml is empty"); return; } // Publish to the Presence server. publishCapabilities(pidfXml); } // Check if the giving trigger type should reset the retry count. private boolean isResetRetryNeeded(@PublishTriggerType int triggerType) { // Do no reset the retry count if the request is triggered by the previous failed retry. if (triggerType == PublishController.PUBLISH_TRIGGER_RETRY) { return false; } return true; } // Check if the publish request is allowed to execute. private boolean isRequestAllowed() { // Check if the instance is destroyed. if (mIsDestroyed) { logd("isPublishAllowed: This instance is already destroyed"); return false; } // Check if it has provisioned. When the provisioning changes, a new publish request will // be triggered. if (!UceUtils.isEabProvisioned(mContext, mSubId)) { logd("isPublishAllowed: NOT provisioned"); return false; } // Do not request publish if the IMS is not registered. When the IMS is registered // afterward, a new publish request will be triggered. if (!mDeviceCapabilities.isImsRegistered()) { logd("isPublishAllowed: IMS is not registered"); return false; } // Set the pending flag if there's already a request running now. if (mProcessorState.isPublishingNow()) { logd("isPublishAllowed: There is already a request running now"); mProcessorState.setPendingRequest(true); return false; } // Check if the publishing request has reached the maximum number of retries. if (mProcessorState.isReachMaximumRetries()) { logd("isPublishAllowed: It has reached maximum number of retries"); return false; } // Skip this request and re-send the request with the delay time if the publish request // executes too frequently. if (!mProcessorState.isCurrentTimeAllowed()) { logd("isPublishAllowed: Current time is not allowed, resend this request"); long delayTime = mProcessorState.getDelayTimeToAllowPublish(); mPublishCtrlCallback.requestPublishFromInternal( PublishController.PUBLISH_TRIGGER_RETRY, delayTime); return false; } return true; } // Publish the device capabilities with the given pidf private void publishCapabilities(String pidfXml) { if (mIsDestroyed) { logw("publishCapabilities: This instance is already destroyed"); return; } // Check if the RCS is connected. RcsFeatureManager featureManager = mRcsFeatureManager; if (featureManager == null) { mLocalLog.log("publish capabilities: not connected"); logw("publishCapabilities: NOT connected"); return; } PublishRequestResponse requestResponse = null; try { // Set publishing flag mProcessorState.setPublishingFlag(true); // Clear the pending request flag since we're publishing the latest device's capability mProcessorState.setPendingRequest(false); // Generate a unique taskId to track this request. long taskId = mProcessorState.generatePublishTaskId(); requestResponse = new PublishRequestResponse(mPublishCtrlCallback, taskId); mLocalLog.log("publish capabilities: taskId=" + taskId); logi("publishCapabilities: taskId=" + taskId); // request publication featureManager.requestPublication(pidfXml, requestResponse); // Send a request canceled timer to avoid waiting too long for the response callback. mPublishCtrlCallback.setupRequestCanceledTimer(taskId, RESPONSE_CALLBACK_WAITING_TIME); } catch (RemoteException e) { mLocalLog.log("publish capability exception: " + e.getMessage()); logw("publishCapabilities: exception=" + e.getMessage()); // Exception occurred, end this request. setRequestEnded(requestResponse); checkAndSendPendingRequest(); } } /** * Handle the command error callback of the publish request. This method is called by the * handler of the PublishController. */ public void onCommandError(PublishRequestResponse requestResponse) { if (!checkRequestRespValid(requestResponse)) { mLocalLog.log("Command error callback is invalid"); logw("onCommandError: request response is invalid"); setRequestEnded(requestResponse); checkAndSendPendingRequest(); return; } mLocalLog.log("Receive command error code=" + requestResponse.getCmdErrorCode()); logd("onCommandError: " + requestResponse.toString()); if (requestResponse.needRetry()) { // Increase the retry count mProcessorState.increaseRetryCount(); // Reset the pending flag since it is going to resend a publish request. mProcessorState.setPendingRequest(false); // Resend a publish request long delayTime = mProcessorState.getDelayTimeToAllowPublish(); mPublishCtrlCallback.requestPublishFromInternal( PublishController.PUBLISH_TRIGGER_RETRY, delayTime); } else { // Update the publish state if the request is failed and doesn't need to retry. int publishState = requestResponse.getPublishStateByCmdErrorCode(); mPublishCtrlCallback.updatePublishRequestResult(publishState); // Check if there is a pending request checkAndSendPendingRequest(); } // End this request setRequestEnded(requestResponse); } /** * Handle the network response callback of the publish request. This method is called by the * handler of the PublishController. */ public void onNetworkResponse(PublishRequestResponse requestResponse) { if (!checkRequestRespValid(requestResponse)) { mLocalLog.log("Network response callback is invalid"); logw("onNetworkResponse: request response is invalid"); setRequestEnded(requestResponse); checkAndSendPendingRequest(); return; } mLocalLog.log("Receive network response code=" + requestResponse.getNetworkRespSipCode()); logd("onNetworkResponse: " + requestResponse.toString()); if (requestResponse.needRetry()) { // Increase the retry count mProcessorState.increaseRetryCount(); // Reset the pending flag since it is going to resend a publish request. mProcessorState.setPendingRequest(false); // Resend a publish request long delayTime = mProcessorState.getDelayTimeToAllowPublish(); mPublishCtrlCallback.requestPublishFromInternal( PublishController.PUBLISH_TRIGGER_RETRY, delayTime); } else { // Reset the retry count if the publish is success. if (requestResponse.isRequestSuccess()) { mProcessorState.resetRetryCount(); } // Update the publish state if the request doesn't need to retry. int publishResult = requestResponse.getPublishStateByNetworkResponse(); mPublishCtrlCallback.updatePublishRequestResult(publishResult); // Check if there is a pending request checkAndSendPendingRequest(); } // End this request setRequestEnded(requestResponse); } // Check if the request response callback is valid. private boolean checkRequestRespValid(PublishRequestResponse requestResponse) { if (requestResponse == null) { logd("checkRequestRespValid: request response is null"); return false; } if (!mProcessorState.isPublishingNow()) { logd("checkRequestRespValid: the request is finished"); return false; } // Abandon this response callback if the current taskId is different to the response // callback taskId. This response callback is obsoleted. long taskId = mProcessorState.getCurrentTaskId(); long responseTaskId = requestResponse.getTaskId(); if (taskId != responseTaskId) { logd("checkRequestRespValid: invalid taskId! current taskId=" + taskId + ", response callback taskId=" + responseTaskId); return false; } if (mIsDestroyed) { logd("checkRequestRespValid: is already destroyed! taskId=" + taskId); return false; } return true; } /** * Cancel the publishing request since it has token too long for waiting the response callback. * This method is called by the handler of the PublishController. */ public void cancelPublishRequest(long taskId) { mLocalLog.log("cancel publish request: taskId=" + taskId); logd("cancelPublishRequest: taskId=" + taskId); setRequestEnded(null); checkAndSendPendingRequest(); } private void setRequestEnded(PublishRequestResponse requestResponse) { long taskId = -1L; if (requestResponse != null) { requestResponse.onDestroy(); taskId = requestResponse.getTaskId(); } mProcessorState.setPublishingFlag(false); mPublishCtrlCallback.clearRequestCanceledTimer(); mLocalLog.log("Set request ended: taskId=" + taskId); logd("setRequestEnded: taskId=" + taskId); } private void checkAndSendPendingRequest() { if (mIsDestroyed) return; if (mProcessorState.hasPendingRequest()) { logd("checkAndSendPendingRequest: send pending request"); mProcessorState.setPublishingFlag(false); long delayTime = mProcessorState.getDelayTimeToAllowPublish(); mPublishCtrlCallback.requestPublishFromInternal( PublishController.PUBLISH_TRIGGER_RETRY, delayTime); } } @VisibleForTesting public void setProcessorState(PublishProcessorState processorState) { mProcessorState = processorState; } 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; } public void dump(PrintWriter printWriter) { mLocalLog.dump(printWriter); } }