Loading src/java/com/android/ims/rcs/uce/UceController.java +78 −122 Original line number Diff line number Diff line Loading @@ -18,7 +18,6 @@ package com.android.ims.rcs.uce; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.net.Uri; import android.os.HandlerThread; Loading @@ -36,6 +35,7 @@ import android.util.LocalLog; import android.util.Log; import com.android.ims.RcsFeatureManager; import com.android.ims.rcs.uce.UceDeviceState.DeviceStateResult; import com.android.ims.rcs.uce.eab.EabCapabilityResult; import com.android.ims.rcs.uce.eab.EabController; import com.android.ims.rcs.uce.eab.EabControllerImpl; Loading @@ -54,9 +54,6 @@ import com.android.internal.os.SomeArgs; import java.io.PrintWriter; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.time.Duration; import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.List; import java.util.Optional; import java.util.Set; Loading Loading @@ -96,25 +93,31 @@ public class UceController { RcsContactUceCapability getDeviceCapabilities(@CapabilityMechanism int mechanism); /** * The network reply that the request is forbidden. * @param isForbidden If UCE requests are forbidden by the network. * @param errorCode The {@link RcsUceAdapter#ErrorCode} of the forbidden reason. * @param retryAfterMillis The time to wait for the retry. * Refresh the device state. It is called when receive the UCE request response. * @param sipCode The SIP code of the request response. * @param reason The reason from the network response. */ void updateRequestForbidden(boolean isForbidden, @Nullable Integer errorCode, long retryAfterMillis); void refreshDeviceState(int sipCode, String reason); /** * Get the milliseconds need to wait for retry. * @return The milliseconds need to wait * Reset the device state when then device disallowed state is expired. */ long getRetryAfterMillis(); void resetDeviceState(); /** * Check if UCE request is forbidden by the network. * @return true when the UCE is forbidden by the network * Get the current device state to check if the device is allowed to send UCE requests. */ boolean isRequestForbiddenByNetwork(); DeviceStateResult getDeviceState(); /** * Setup timer to exit device disallowed state. */ void setupResetDeviceStateTimer(long resetAfterSec); /** * The device state is already reset, clear the timer. */ void clearResetDeviceStateTimer(); /** * The method is called when the given contacts' capabilities are expired and need to be Loading Loading @@ -283,17 +286,14 @@ public class UceController { private SubscribeController mSubscribeController; private OptionsController mOptionsController; private UceRequestManager mRequestManager; // The server state for UCE requests. private final ServerState mServerState; // The device state to execute UCE requests. private UceDeviceState mDeviceState; // The cache of the capability request event triggered by ImsService private final CachedCapabilityEvent mCachedCapabilityEvent; public UceController(Context context, int subId) { mSubId = subId; mContext = context; mServerState = new ServerState(); mCachedCapabilityEvent = new CachedCapabilityEvent(); mRcsConnectedState = RCS_STATE_DISCONNECTED; logi("create"); Loading @@ -301,14 +301,15 @@ public class UceController { initLooper(); initControllers(); initRequestManager(); initUceDeviceState(); } @VisibleForTesting public UceController(Context context, int subId, ServerState serverState, public UceController(Context context, int subId, UceDeviceState deviceState, ControllerFactory controllerFactory, RequestManagerFactory requestManagerFactory) { mSubId = subId; mContext = context; mServerState = serverState; mDeviceState = deviceState; mControllerFactory = controllerFactory; mRequestManagerFactory = requestManagerFactory; mCachedCapabilityEvent = new CachedCapabilityEvent(); Loading Loading @@ -341,6 +342,11 @@ public class UceController { mRequestManager.setOptionsController(mOptionsController); } private void initUceDeviceState() { mDeviceState = new UceDeviceState(mSubId, mContext, mCtrlCallback); mDeviceState.checkSendResetDeviceStateTimer(); } /** * The RcsFeature has been connected to the framework. This method runs on main thread. */ Loading Loading @@ -376,8 +382,6 @@ public class UceController { mRcsFeatureManager.removeCapabilityEventCallback(mCapabilityEventListener); mRcsFeatureManager = null; } // Reset Service specific state mServerState.updateRequestForbidden(false, null, 0L); // Notify each controllers that RCS is disconnected. mEabController.onRcsDisconnected(); mPublishController.onRcsDisconnected(); Loading Loading @@ -459,19 +463,28 @@ public class UceController { } @Override public void updateRequestForbidden(boolean isForbidden, @Nullable Integer errorCode, long retryAfterMillis) { mServerState.updateRequestForbidden(isForbidden, errorCode, retryAfterMillis); public void refreshDeviceState(int sipCode, String reason) { mDeviceState.refreshDeviceState(sipCode, reason); } @Override public void resetDeviceState() { mDeviceState.resetDeviceState(); } @Override public DeviceStateResult getDeviceState() { return mDeviceState.getCurrentState(); } @Override public long getRetryAfterMillis() { return mServerState.getRetryAfterMillis(); public void setupResetDeviceStateTimer(long resetAfterSec) { mPublishController.setupResetDeviceStateTimer(resetAfterSec); } @Override public boolean isRequestForbiddenByNetwork() { return (mServerState.getForbiddenErrorCode() != null) ? true : false; public void clearResetDeviceStateTimer() { mPublishController.clearResetDeviceStateTimer(); } @Override Loading Loading @@ -553,19 +566,21 @@ public class UceController { return; } // Check if UCE requests are forbidden by the network. if (mServerState.isRequestForbidden()) { Integer errorCode = mServerState.getForbiddenErrorCode(); long retryAfter = mServerState.getRetryAfterMillis(); logw("requestCapabilities: The request is forbidden, errorCode=" + errorCode + ", retryAfter=" + retryAfter); errorCode = (errorCode != null) ? errorCode : RcsUceAdapter.ERROR_FORBIDDEN; c.onError(errorCode, retryAfter); // Return if the device is not allowed to execute UCE requests. DeviceStateResult deviceStateResult = mDeviceState.getCurrentState(); if (deviceStateResult.isRequestForbidden()) { int deviceState = deviceStateResult.getDeviceState(); int errorCode = deviceStateResult.getErrorCode() .orElse(RcsUceAdapter.ERROR_GENERIC_FAILURE); long retryAfterMillis = deviceStateResult.getRequestRetryAfterMillis(); logw("requestCapabilities: The device is disallowed, deviceState= " + deviceState + ", errorCode=" + errorCode + ", retryAfterMillis=" + retryAfterMillis); c.onError(errorCode, retryAfterMillis); return; } // Trigger the capabilities request task logd("requestCapabilities: " + uriList.size()); logd("requestCapabilities: size=" + uriList.size()); mRequestManager.sendCapabilityRequest(uriList, skipFromCache, c); } Loading @@ -590,14 +605,16 @@ public class UceController { return; } // Check if UCE requests are forbidden by the network. if (mServerState.isRequestForbidden()) { Integer errorCode = mServerState.getForbiddenErrorCode(); long retryAfter = mServerState.getRetryAfterMillis(); logw("requestAvailability: The request is forbidden, errorCode=" + errorCode + ", retryAfter=" + retryAfter); errorCode = (errorCode != null) ? errorCode : RcsUceAdapter.ERROR_FORBIDDEN; c.onError(errorCode, retryAfter); // Return if the device is not allowed to execute UCE requests. DeviceStateResult deviceStateResult = mDeviceState.getCurrentState(); if (deviceStateResult.isRequestForbidden()) { int deviceState = deviceStateResult.getDeviceState(); int errorCode = deviceStateResult.getErrorCode() .orElse(RcsUceAdapter.ERROR_GENERIC_FAILURE); long retryAfterMillis = deviceStateResult.getRequestRetryAfterMillis(); logw("requestAvailability: The device is disallowed, deviceState= " + deviceState + ", errorCode=" + errorCode + ", retryAfterMillis=" + retryAfterMillis); c.onError(errorCode, retryAfterMillis); return; } Loading @@ -611,8 +628,8 @@ public class UceController { */ public void onRequestPublishCapabilitiesFromService(@StackPublishTriggerType int triggerType) { logd("onRequestPublishCapabilitiesFromService: " + triggerType); // Reset the forbidden status if the service requests to publish the device's capabilities mServerState.updateRequestForbidden(false, null, 0L); // Reset the device state when the service triggers to publish the device's capabilities mDeviceState.resetDeviceState(); // Send the publish request. mPublishController.requestPublishCapabilitiesFromService(triggerType); } Loading Loading @@ -702,6 +719,16 @@ public class UceController { return mPublishController.getLastPidfXml(); } /** * Remove the device disallowed state. * <p> * Used for testing ONLY. */ public void removeRequestDisallowedStatus() { logd("removeRequestDisallowedStatus"); mDeviceState.resetDeviceState(); } /** * Get the subscription ID. */ Loading @@ -728,77 +755,6 @@ public class UceController { return mRcsConnectedState == RCS_STATE_CONNECTED; } /** * The internal class to store the server state which sent from the network. It will help to * check if the network allows the UCE request. */ @VisibleForTesting public static class ServerState { private boolean mIsForbidden; private Integer mForbiddenErrorCode; // The timestamp when the network allows the UCE requests. This value may be null if the // network doesn't specified any retryAfter info. private Instant mAllowedTimestamp; private final Object mServerStateLock = new Object(); public ServerState() { mIsForbidden = false; mForbiddenErrorCode = null; mAllowedTimestamp = null; } public void updateRequestForbidden(boolean isForbidden, @Nullable Integer errorCode, long retryAfterMillis) { synchronized (mServerStateLock) { mIsForbidden = isForbidden; if (!mIsForbidden) { mForbiddenErrorCode = null; mAllowedTimestamp = null; } else { mForbiddenErrorCode = (errorCode == null) ? RcsUceAdapter.ERROR_FORBIDDEN : errorCode; mAllowedTimestamp = Instant.now().plus(retryAfterMillis, ChronoUnit.MILLIS); } Log.i(LOG_TAG, "updateRequestForbidden: isForbidden=" + mIsForbidden + ", errorCode=" + mForbiddenErrorCode + ", time=" + mAllowedTimestamp); } } public boolean isRequestForbidden() { synchronized (mServerStateLock) { if (mIsForbidden && mAllowedTimestamp != null) { return Instant.now().isBefore(mAllowedTimestamp); } return mIsForbidden; } } public @Nullable Integer getForbiddenErrorCode() { synchronized (mServerStateLock) { if (!mIsForbidden) { return null; } return mForbiddenErrorCode; } } public long getRetryAfterMillis() { synchronized (mServerStateLock) { if (!mIsForbidden || mAllowedTimestamp == null) { return 0L; } Duration duration = Duration.between(Instant.now(), mAllowedTimestamp); long retryAfterMillis = duration.toMillis(); if (retryAfterMillis < 0) { return 0L; } return retryAfterMillis; } } } public void dump(PrintWriter printWriter) { IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); pw.println("UceController" + "[subId: " + mSubId + "]:"); Loading src/java/com/android/ims/rcs/uce/UceDeviceState.java 0 → 100644 +371 −0 File added.Preview size limit exceeded, changes collapsed. Show changes src/java/com/android/ims/rcs/uce/presence/publish/PublishController.java +15 −0 Original line number Diff line number Diff line Loading @@ -136,6 +136,11 @@ public interface PublishController extends ControllerBase { * Update the value of the publish throttle. */ void updatePublishThrottle(int value); /** * Update the device state with the publish request result. */ void refreshDeviceState(int SipCode, String reason); } /** Loading Loading @@ -202,6 +207,16 @@ public interface PublishController extends ControllerBase { */ void unregisterPublishStateCallback(@NonNull IRcsUcePublishStateCallback c); /** * Setup the timer to reset the device state. */ void setupResetDeviceStateTimer(long resetAfterSec); /** * Clear the reset device state timer. */ void clearResetDeviceStateTimer(); /** * Dump the state of this PublishController to the printWriter. */ Loading src/java/com/android/ims/rcs/uce/presence/publish/PublishControllerImpl.java +75 −7 Original line number Diff line number Diff line Loading @@ -39,6 +39,7 @@ import android.util.Log; import com.android.ims.RcsFeatureManager; import com.android.ims.rcs.uce.UceController.UceControllerCallback; import com.android.ims.rcs.uce.UceDeviceState.DeviceStateResult; import com.android.ims.rcs.uce.util.UceUtils; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.os.SomeArgs; Loading @@ -51,6 +52,7 @@ import java.util.HashMap; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.concurrent.TimeUnit; /** * The implementation of PublishController. Loading Loading @@ -270,6 +272,18 @@ public class PublishControllerImpl implements PublishController { } } @Override public void setupResetDeviceStateTimer(long resetAfterSec) { logd("setupResetDeviceStateTimer: resetAfterSec=" + resetAfterSec); mPublishHandler.sendResetDeviceStateTimerMessage(resetAfterSec); } @Override public void clearResetDeviceStateTimer() { logd("clearResetDeviceStateTimer"); mPublishHandler.clearResetDeviceStateTimer(); } // Clear all the publish state callbacks since the publish controller instance is destroyed. private void clearPublishStateCallbacks() { synchronized (mPublishStateLock) { Loading Loading @@ -346,6 +360,11 @@ public class PublishControllerImpl implements PublishController { logd("updatePublishThrottle: value=" + value); mPublishProcessor.updatePublishThrottle(value); } @Override public void refreshDeviceState(int sipCode, String reason) { mUceCtrlCallback.refreshDeviceState(sipCode, reason); } }; /** Loading @@ -369,6 +388,7 @@ public class PublishControllerImpl implements PublishController { private static final int MSG_REQUEST_CMD_ERROR = 9; private static final int MSG_REQUEST_NETWORK_RESPONSE = 10; private static final int MSG_REQUEST_CANCELED = 11; private static final int MSG_RESET_DEVICE_STATE = 12; private final WeakReference<PublishControllerImpl> mPublishControllerRef; Loading Loading @@ -444,6 +464,10 @@ public class PublishControllerImpl implements PublishController { long taskId = (Long) message.obj; publishCtrl.handleRequestCanceledMessage(taskId); break; case MSG_RESET_DEVICE_STATE: publishCtrl.handleResetDeviceStateMessage(); break; } } Loading Loading @@ -611,6 +635,28 @@ public class PublishControllerImpl implements PublishController { removeMessages(MSG_REQUEST_CANCELED); } public void sendResetDeviceStateTimerMessage(long resetAfterSec) { PublishControllerImpl publishCtrl = mPublishControllerRef.get(); if (publishCtrl == null) { return; } if (publishCtrl.mIsDestroyedFlag) return; // Remove old timer and setup the new timer. removeMessages(MSG_RESET_DEVICE_STATE); Message message = obtainMessage(); message.what = MSG_RESET_DEVICE_STATE; sendMessageDelayed(message, TimeUnit.SECONDS.toMillis(resetAfterSec)); } public void clearResetDeviceStateTimer() { PublishControllerImpl publishCtrl = mPublishControllerRef.get(); if (publishCtrl == null) { return; } if (publishCtrl.mIsDestroyedFlag) return; removeMessages(MSG_RESET_DEVICE_STATE); } private static Map<Integer, String> EVENT_DESCRIPTION = new HashMap<>(); static { EVENT_DESCRIPTION.put(MSG_RCS_CONNECTED, "RCS_CONNECTED"); Loading @@ -624,6 +670,7 @@ public class PublishControllerImpl implements PublishController { EVENT_DESCRIPTION.put(MSG_REQUEST_CMD_ERROR, "REQUEST_CMD_ERROR"); EVENT_DESCRIPTION.put(MSG_REQUEST_NETWORK_RESPONSE, "REQUEST_NETWORK_RESPONSE"); EVENT_DESCRIPTION.put(MSG_REQUEST_CANCELED, "REQUEST_CANCELED"); EVENT_DESCRIPTION.put(MSG_RESET_DEVICE_STATE, "RESET_DEVICE_STATE"); } } Loading @@ -636,11 +683,21 @@ public class PublishControllerImpl implements PublishController { logd("isPublishRequestAllowed: capability presence uce is not enabled."); return false; } // The first PUBLISH request is required to be triggered from the service. if (!mReceivePublishFromService) { logd("isPublishRequestAllowed: Have not received the first PUBLISH from the service."); return false; } // Check whether the device state is not allowed to execute the PUBLISH request. DeviceStateResult deviceState = mUceCtrlCallback.getDeviceState(); if (deviceState.isRequestForbidden()) { logd("isPublishRequestAllowed: The device state is disallowed. " + deviceState.getDeviceState()); return false; } // Check whether there is already a publish request running or not. When the running // request is finished and there is a pending request, it will send a new request. if (mPublishProcessor.isPublishingNow()) { Loading Loading @@ -780,16 +837,22 @@ public class PublishControllerImpl implements PublishController { private void handleRequestPublishMessage(@PublishTriggerType int type) { if (mIsDestroyedFlag) return; if (mUceCtrlCallback.isRequestForbiddenByNetwork()) { logd("handleRequestPublishMessage: The network forbids UCE requests: type=" + type); return; } logd("handleRequestPublishMessage: type=" + type); // Set the flag if the publish is triggered by the ImsService. if (type == PublishController.PUBLISH_TRIGGER_SERVICE && !mReceivePublishFromService) { // Set the PUBLISH FROM SERVICE flag and reset the device state if the PUBLISH request is // triggered by the ImsService. if (type == PublishController.PUBLISH_TRIGGER_SERVICE) { // Set the flag if (!mReceivePublishFromService) { mReceivePublishFromService = true; } // Reset device state DeviceStateResult deviceState = mUceCtrlCallback.getDeviceState(); if (deviceState.isRequestForbidden()) { mUceCtrlCallback.resetDeviceState(); } } // Set the pending flag and return if the request is not allowed. if (!isPublishRequestAllowed()) { Loading Loading @@ -824,6 +887,11 @@ public class PublishControllerImpl implements PublishController { mPublishProcessor.cancelPublishRequest(taskId); } private void handleResetDeviceStateMessage() { if(mIsDestroyedFlag) return; mUceCtrlCallback.resetDeviceState(); } @VisibleForTesting public void setPublishStateCallback(RemoteCallbackList<IRcsUcePublishStateCallback> list) { mPublishStateCallbacks = list; Loading src/java/com/android/ims/rcs/uce/presence/publish/PublishProcessor.java +6 −0 Original line number Diff line number Diff line Loading @@ -337,6 +337,12 @@ public class PublishProcessor { String pidfXml = requestResponse.getPidfXml(); mPublishCtrlCallback.updatePublishRequestResult(publishState, responseTime, pidfXml); // Refresh the device state with the publish request result. requestResponse.getResponseSipCode().ifPresent(sipCode -> { String reason = requestResponse.getResponseReason().orElse(""); mPublishCtrlCallback.refreshDeviceState(sipCode, reason); }); // Finish the request and check if there is pending request. setRequestEnded(requestResponse); checkAndSendPendingRequest(); Loading Loading
src/java/com/android/ims/rcs/uce/UceController.java +78 −122 Original line number Diff line number Diff line Loading @@ -18,7 +18,6 @@ package com.android.ims.rcs.uce; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.net.Uri; import android.os.HandlerThread; Loading @@ -36,6 +35,7 @@ import android.util.LocalLog; import android.util.Log; import com.android.ims.RcsFeatureManager; import com.android.ims.rcs.uce.UceDeviceState.DeviceStateResult; import com.android.ims.rcs.uce.eab.EabCapabilityResult; import com.android.ims.rcs.uce.eab.EabController; import com.android.ims.rcs.uce.eab.EabControllerImpl; Loading @@ -54,9 +54,6 @@ import com.android.internal.os.SomeArgs; import java.io.PrintWriter; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.time.Duration; import java.time.Instant; import java.time.temporal.ChronoUnit; import java.util.List; import java.util.Optional; import java.util.Set; Loading Loading @@ -96,25 +93,31 @@ public class UceController { RcsContactUceCapability getDeviceCapabilities(@CapabilityMechanism int mechanism); /** * The network reply that the request is forbidden. * @param isForbidden If UCE requests are forbidden by the network. * @param errorCode The {@link RcsUceAdapter#ErrorCode} of the forbidden reason. * @param retryAfterMillis The time to wait for the retry. * Refresh the device state. It is called when receive the UCE request response. * @param sipCode The SIP code of the request response. * @param reason The reason from the network response. */ void updateRequestForbidden(boolean isForbidden, @Nullable Integer errorCode, long retryAfterMillis); void refreshDeviceState(int sipCode, String reason); /** * Get the milliseconds need to wait for retry. * @return The milliseconds need to wait * Reset the device state when then device disallowed state is expired. */ long getRetryAfterMillis(); void resetDeviceState(); /** * Check if UCE request is forbidden by the network. * @return true when the UCE is forbidden by the network * Get the current device state to check if the device is allowed to send UCE requests. */ boolean isRequestForbiddenByNetwork(); DeviceStateResult getDeviceState(); /** * Setup timer to exit device disallowed state. */ void setupResetDeviceStateTimer(long resetAfterSec); /** * The device state is already reset, clear the timer. */ void clearResetDeviceStateTimer(); /** * The method is called when the given contacts' capabilities are expired and need to be Loading Loading @@ -283,17 +286,14 @@ public class UceController { private SubscribeController mSubscribeController; private OptionsController mOptionsController; private UceRequestManager mRequestManager; // The server state for UCE requests. private final ServerState mServerState; // The device state to execute UCE requests. private UceDeviceState mDeviceState; // The cache of the capability request event triggered by ImsService private final CachedCapabilityEvent mCachedCapabilityEvent; public UceController(Context context, int subId) { mSubId = subId; mContext = context; mServerState = new ServerState(); mCachedCapabilityEvent = new CachedCapabilityEvent(); mRcsConnectedState = RCS_STATE_DISCONNECTED; logi("create"); Loading @@ -301,14 +301,15 @@ public class UceController { initLooper(); initControllers(); initRequestManager(); initUceDeviceState(); } @VisibleForTesting public UceController(Context context, int subId, ServerState serverState, public UceController(Context context, int subId, UceDeviceState deviceState, ControllerFactory controllerFactory, RequestManagerFactory requestManagerFactory) { mSubId = subId; mContext = context; mServerState = serverState; mDeviceState = deviceState; mControllerFactory = controllerFactory; mRequestManagerFactory = requestManagerFactory; mCachedCapabilityEvent = new CachedCapabilityEvent(); Loading Loading @@ -341,6 +342,11 @@ public class UceController { mRequestManager.setOptionsController(mOptionsController); } private void initUceDeviceState() { mDeviceState = new UceDeviceState(mSubId, mContext, mCtrlCallback); mDeviceState.checkSendResetDeviceStateTimer(); } /** * The RcsFeature has been connected to the framework. This method runs on main thread. */ Loading Loading @@ -376,8 +382,6 @@ public class UceController { mRcsFeatureManager.removeCapabilityEventCallback(mCapabilityEventListener); mRcsFeatureManager = null; } // Reset Service specific state mServerState.updateRequestForbidden(false, null, 0L); // Notify each controllers that RCS is disconnected. mEabController.onRcsDisconnected(); mPublishController.onRcsDisconnected(); Loading Loading @@ -459,19 +463,28 @@ public class UceController { } @Override public void updateRequestForbidden(boolean isForbidden, @Nullable Integer errorCode, long retryAfterMillis) { mServerState.updateRequestForbidden(isForbidden, errorCode, retryAfterMillis); public void refreshDeviceState(int sipCode, String reason) { mDeviceState.refreshDeviceState(sipCode, reason); } @Override public void resetDeviceState() { mDeviceState.resetDeviceState(); } @Override public DeviceStateResult getDeviceState() { return mDeviceState.getCurrentState(); } @Override public long getRetryAfterMillis() { return mServerState.getRetryAfterMillis(); public void setupResetDeviceStateTimer(long resetAfterSec) { mPublishController.setupResetDeviceStateTimer(resetAfterSec); } @Override public boolean isRequestForbiddenByNetwork() { return (mServerState.getForbiddenErrorCode() != null) ? true : false; public void clearResetDeviceStateTimer() { mPublishController.clearResetDeviceStateTimer(); } @Override Loading Loading @@ -553,19 +566,21 @@ public class UceController { return; } // Check if UCE requests are forbidden by the network. if (mServerState.isRequestForbidden()) { Integer errorCode = mServerState.getForbiddenErrorCode(); long retryAfter = mServerState.getRetryAfterMillis(); logw("requestCapabilities: The request is forbidden, errorCode=" + errorCode + ", retryAfter=" + retryAfter); errorCode = (errorCode != null) ? errorCode : RcsUceAdapter.ERROR_FORBIDDEN; c.onError(errorCode, retryAfter); // Return if the device is not allowed to execute UCE requests. DeviceStateResult deviceStateResult = mDeviceState.getCurrentState(); if (deviceStateResult.isRequestForbidden()) { int deviceState = deviceStateResult.getDeviceState(); int errorCode = deviceStateResult.getErrorCode() .orElse(RcsUceAdapter.ERROR_GENERIC_FAILURE); long retryAfterMillis = deviceStateResult.getRequestRetryAfterMillis(); logw("requestCapabilities: The device is disallowed, deviceState= " + deviceState + ", errorCode=" + errorCode + ", retryAfterMillis=" + retryAfterMillis); c.onError(errorCode, retryAfterMillis); return; } // Trigger the capabilities request task logd("requestCapabilities: " + uriList.size()); logd("requestCapabilities: size=" + uriList.size()); mRequestManager.sendCapabilityRequest(uriList, skipFromCache, c); } Loading @@ -590,14 +605,16 @@ public class UceController { return; } // Check if UCE requests are forbidden by the network. if (mServerState.isRequestForbidden()) { Integer errorCode = mServerState.getForbiddenErrorCode(); long retryAfter = mServerState.getRetryAfterMillis(); logw("requestAvailability: The request is forbidden, errorCode=" + errorCode + ", retryAfter=" + retryAfter); errorCode = (errorCode != null) ? errorCode : RcsUceAdapter.ERROR_FORBIDDEN; c.onError(errorCode, retryAfter); // Return if the device is not allowed to execute UCE requests. DeviceStateResult deviceStateResult = mDeviceState.getCurrentState(); if (deviceStateResult.isRequestForbidden()) { int deviceState = deviceStateResult.getDeviceState(); int errorCode = deviceStateResult.getErrorCode() .orElse(RcsUceAdapter.ERROR_GENERIC_FAILURE); long retryAfterMillis = deviceStateResult.getRequestRetryAfterMillis(); logw("requestAvailability: The device is disallowed, deviceState= " + deviceState + ", errorCode=" + errorCode + ", retryAfterMillis=" + retryAfterMillis); c.onError(errorCode, retryAfterMillis); return; } Loading @@ -611,8 +628,8 @@ public class UceController { */ public void onRequestPublishCapabilitiesFromService(@StackPublishTriggerType int triggerType) { logd("onRequestPublishCapabilitiesFromService: " + triggerType); // Reset the forbidden status if the service requests to publish the device's capabilities mServerState.updateRequestForbidden(false, null, 0L); // Reset the device state when the service triggers to publish the device's capabilities mDeviceState.resetDeviceState(); // Send the publish request. mPublishController.requestPublishCapabilitiesFromService(triggerType); } Loading Loading @@ -702,6 +719,16 @@ public class UceController { return mPublishController.getLastPidfXml(); } /** * Remove the device disallowed state. * <p> * Used for testing ONLY. */ public void removeRequestDisallowedStatus() { logd("removeRequestDisallowedStatus"); mDeviceState.resetDeviceState(); } /** * Get the subscription ID. */ Loading @@ -728,77 +755,6 @@ public class UceController { return mRcsConnectedState == RCS_STATE_CONNECTED; } /** * The internal class to store the server state which sent from the network. It will help to * check if the network allows the UCE request. */ @VisibleForTesting public static class ServerState { private boolean mIsForbidden; private Integer mForbiddenErrorCode; // The timestamp when the network allows the UCE requests. This value may be null if the // network doesn't specified any retryAfter info. private Instant mAllowedTimestamp; private final Object mServerStateLock = new Object(); public ServerState() { mIsForbidden = false; mForbiddenErrorCode = null; mAllowedTimestamp = null; } public void updateRequestForbidden(boolean isForbidden, @Nullable Integer errorCode, long retryAfterMillis) { synchronized (mServerStateLock) { mIsForbidden = isForbidden; if (!mIsForbidden) { mForbiddenErrorCode = null; mAllowedTimestamp = null; } else { mForbiddenErrorCode = (errorCode == null) ? RcsUceAdapter.ERROR_FORBIDDEN : errorCode; mAllowedTimestamp = Instant.now().plus(retryAfterMillis, ChronoUnit.MILLIS); } Log.i(LOG_TAG, "updateRequestForbidden: isForbidden=" + mIsForbidden + ", errorCode=" + mForbiddenErrorCode + ", time=" + mAllowedTimestamp); } } public boolean isRequestForbidden() { synchronized (mServerStateLock) { if (mIsForbidden && mAllowedTimestamp != null) { return Instant.now().isBefore(mAllowedTimestamp); } return mIsForbidden; } } public @Nullable Integer getForbiddenErrorCode() { synchronized (mServerStateLock) { if (!mIsForbidden) { return null; } return mForbiddenErrorCode; } } public long getRetryAfterMillis() { synchronized (mServerStateLock) { if (!mIsForbidden || mAllowedTimestamp == null) { return 0L; } Duration duration = Duration.between(Instant.now(), mAllowedTimestamp); long retryAfterMillis = duration.toMillis(); if (retryAfterMillis < 0) { return 0L; } return retryAfterMillis; } } } public void dump(PrintWriter printWriter) { IndentingPrintWriter pw = new IndentingPrintWriter(printWriter, " "); pw.println("UceController" + "[subId: " + mSubId + "]:"); Loading
src/java/com/android/ims/rcs/uce/UceDeviceState.java 0 → 100644 +371 −0 File added.Preview size limit exceeded, changes collapsed. Show changes
src/java/com/android/ims/rcs/uce/presence/publish/PublishController.java +15 −0 Original line number Diff line number Diff line Loading @@ -136,6 +136,11 @@ public interface PublishController extends ControllerBase { * Update the value of the publish throttle. */ void updatePublishThrottle(int value); /** * Update the device state with the publish request result. */ void refreshDeviceState(int SipCode, String reason); } /** Loading Loading @@ -202,6 +207,16 @@ public interface PublishController extends ControllerBase { */ void unregisterPublishStateCallback(@NonNull IRcsUcePublishStateCallback c); /** * Setup the timer to reset the device state. */ void setupResetDeviceStateTimer(long resetAfterSec); /** * Clear the reset device state timer. */ void clearResetDeviceStateTimer(); /** * Dump the state of this PublishController to the printWriter. */ Loading
src/java/com/android/ims/rcs/uce/presence/publish/PublishControllerImpl.java +75 −7 Original line number Diff line number Diff line Loading @@ -39,6 +39,7 @@ import android.util.Log; import com.android.ims.RcsFeatureManager; import com.android.ims.rcs.uce.UceController.UceControllerCallback; import com.android.ims.rcs.uce.UceDeviceState.DeviceStateResult; import com.android.ims.rcs.uce.util.UceUtils; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.os.SomeArgs; Loading @@ -51,6 +52,7 @@ import java.util.HashMap; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.concurrent.TimeUnit; /** * The implementation of PublishController. Loading Loading @@ -270,6 +272,18 @@ public class PublishControllerImpl implements PublishController { } } @Override public void setupResetDeviceStateTimer(long resetAfterSec) { logd("setupResetDeviceStateTimer: resetAfterSec=" + resetAfterSec); mPublishHandler.sendResetDeviceStateTimerMessage(resetAfterSec); } @Override public void clearResetDeviceStateTimer() { logd("clearResetDeviceStateTimer"); mPublishHandler.clearResetDeviceStateTimer(); } // Clear all the publish state callbacks since the publish controller instance is destroyed. private void clearPublishStateCallbacks() { synchronized (mPublishStateLock) { Loading Loading @@ -346,6 +360,11 @@ public class PublishControllerImpl implements PublishController { logd("updatePublishThrottle: value=" + value); mPublishProcessor.updatePublishThrottle(value); } @Override public void refreshDeviceState(int sipCode, String reason) { mUceCtrlCallback.refreshDeviceState(sipCode, reason); } }; /** Loading @@ -369,6 +388,7 @@ public class PublishControllerImpl implements PublishController { private static final int MSG_REQUEST_CMD_ERROR = 9; private static final int MSG_REQUEST_NETWORK_RESPONSE = 10; private static final int MSG_REQUEST_CANCELED = 11; private static final int MSG_RESET_DEVICE_STATE = 12; private final WeakReference<PublishControllerImpl> mPublishControllerRef; Loading Loading @@ -444,6 +464,10 @@ public class PublishControllerImpl implements PublishController { long taskId = (Long) message.obj; publishCtrl.handleRequestCanceledMessage(taskId); break; case MSG_RESET_DEVICE_STATE: publishCtrl.handleResetDeviceStateMessage(); break; } } Loading Loading @@ -611,6 +635,28 @@ public class PublishControllerImpl implements PublishController { removeMessages(MSG_REQUEST_CANCELED); } public void sendResetDeviceStateTimerMessage(long resetAfterSec) { PublishControllerImpl publishCtrl = mPublishControllerRef.get(); if (publishCtrl == null) { return; } if (publishCtrl.mIsDestroyedFlag) return; // Remove old timer and setup the new timer. removeMessages(MSG_RESET_DEVICE_STATE); Message message = obtainMessage(); message.what = MSG_RESET_DEVICE_STATE; sendMessageDelayed(message, TimeUnit.SECONDS.toMillis(resetAfterSec)); } public void clearResetDeviceStateTimer() { PublishControllerImpl publishCtrl = mPublishControllerRef.get(); if (publishCtrl == null) { return; } if (publishCtrl.mIsDestroyedFlag) return; removeMessages(MSG_RESET_DEVICE_STATE); } private static Map<Integer, String> EVENT_DESCRIPTION = new HashMap<>(); static { EVENT_DESCRIPTION.put(MSG_RCS_CONNECTED, "RCS_CONNECTED"); Loading @@ -624,6 +670,7 @@ public class PublishControllerImpl implements PublishController { EVENT_DESCRIPTION.put(MSG_REQUEST_CMD_ERROR, "REQUEST_CMD_ERROR"); EVENT_DESCRIPTION.put(MSG_REQUEST_NETWORK_RESPONSE, "REQUEST_NETWORK_RESPONSE"); EVENT_DESCRIPTION.put(MSG_REQUEST_CANCELED, "REQUEST_CANCELED"); EVENT_DESCRIPTION.put(MSG_RESET_DEVICE_STATE, "RESET_DEVICE_STATE"); } } Loading @@ -636,11 +683,21 @@ public class PublishControllerImpl implements PublishController { logd("isPublishRequestAllowed: capability presence uce is not enabled."); return false; } // The first PUBLISH request is required to be triggered from the service. if (!mReceivePublishFromService) { logd("isPublishRequestAllowed: Have not received the first PUBLISH from the service."); return false; } // Check whether the device state is not allowed to execute the PUBLISH request. DeviceStateResult deviceState = mUceCtrlCallback.getDeviceState(); if (deviceState.isRequestForbidden()) { logd("isPublishRequestAllowed: The device state is disallowed. " + deviceState.getDeviceState()); return false; } // Check whether there is already a publish request running or not. When the running // request is finished and there is a pending request, it will send a new request. if (mPublishProcessor.isPublishingNow()) { Loading Loading @@ -780,16 +837,22 @@ public class PublishControllerImpl implements PublishController { private void handleRequestPublishMessage(@PublishTriggerType int type) { if (mIsDestroyedFlag) return; if (mUceCtrlCallback.isRequestForbiddenByNetwork()) { logd("handleRequestPublishMessage: The network forbids UCE requests: type=" + type); return; } logd("handleRequestPublishMessage: type=" + type); // Set the flag if the publish is triggered by the ImsService. if (type == PublishController.PUBLISH_TRIGGER_SERVICE && !mReceivePublishFromService) { // Set the PUBLISH FROM SERVICE flag and reset the device state if the PUBLISH request is // triggered by the ImsService. if (type == PublishController.PUBLISH_TRIGGER_SERVICE) { // Set the flag if (!mReceivePublishFromService) { mReceivePublishFromService = true; } // Reset device state DeviceStateResult deviceState = mUceCtrlCallback.getDeviceState(); if (deviceState.isRequestForbidden()) { mUceCtrlCallback.resetDeviceState(); } } // Set the pending flag and return if the request is not allowed. if (!isPublishRequestAllowed()) { Loading Loading @@ -824,6 +887,11 @@ public class PublishControllerImpl implements PublishController { mPublishProcessor.cancelPublishRequest(taskId); } private void handleResetDeviceStateMessage() { if(mIsDestroyedFlag) return; mUceCtrlCallback.resetDeviceState(); } @VisibleForTesting public void setPublishStateCallback(RemoteCallbackList<IRcsUcePublishStateCallback> list) { mPublishStateCallbacks = list; Loading
src/java/com/android/ims/rcs/uce/presence/publish/PublishProcessor.java +6 −0 Original line number Diff line number Diff line Loading @@ -337,6 +337,12 @@ public class PublishProcessor { String pidfXml = requestResponse.getPidfXml(); mPublishCtrlCallback.updatePublishRequestResult(publishState, responseTime, pidfXml); // Refresh the device state with the publish request result. requestResponse.getResponseSipCode().ifPresent(sipCode -> { String reason = requestResponse.getResponseReason().orElse(""); mPublishCtrlCallback.refreshDeviceState(sipCode, reason); }); // Finish the request and check if there is pending request. setRequestEnded(requestResponse); checkAndSendPendingRequest(); Loading