diff options
14 files changed, 901 insertions, 90 deletions
diff --git a/rcs/rcsmanager/src/java/com/android/ims/RcsManager.java b/rcs/rcsmanager/src/java/com/android/ims/RcsManager.java index 644d567..c198bb3 100644 --- a/rcs/rcsmanager/src/java/com/android/ims/RcsManager.java +++ b/rcs/rcsmanager/src/java/com/android/ims/RcsManager.java @@ -239,6 +239,7 @@ public class RcsManager { private int mSubId; private IRcsService mRcsService = null; private RcsServiceDeathRecipient mDeathRecipient = new RcsServiceDeathRecipient(); + private boolean mPresenceEnabledByFramework = true; // Interface for presence // TODO: Could add other RCS service such RcsChat, RcsFt later. @@ -290,8 +291,9 @@ public class RcsManager { Rlog.e(TAG, "isRcsServiceAvailable RcsException", e); } - if (DBG) Rlog.d(TAG, "isRcsServiceAvailable ret =" + ret); - return ret; + if (DBG) Rlog.d(TAG, "isRcsServiceAvailable ret =" + ret + " mPresenceEnabledByFramework =" + + mPresenceEnabledByFramework); + return ret && mPresenceEnabledByFramework; } /** @@ -381,4 +383,8 @@ public class RcsManager { } } } + + public void setPresenceEnabledByFramework(boolean presenceEnabledByFramework) { + mPresenceEnabledByFramework = presenceEnabledByFramework; + } } diff --git a/rcs/rcsservice/Android.bp b/rcs/rcsservice/Android.bp index 24153a5..547ae5e 100644 --- a/rcs/rcsservice/Android.bp +++ b/rcs/rcsservice/Android.bp @@ -38,6 +38,9 @@ java_library { "src/com/android/service/ims/RcsUtils.java", "src/com/android/service/ims/Task.java", "src/com/android/service/ims/TaskManager.java", + "src/com/android/service/ims/RcsFeatureImpl.java", + "src/com/android/service/ims/RcsPresenceExchangeImpl.java", + "src/com/android/service/ims/ImsServiceImpl.java", // Move the following to the app once the dependencies have been decoupled. "src/com/android/service/ims/RcsStackAdaptor.java" ], diff --git a/rcs/rcsservice/AndroidManifest.xml b/rcs/rcsservice/AndroidManifest.xml index 9b9de40..0f31c7b 100644 --- a/rcs/rcsservice/AndroidManifest.xml +++ b/rcs/rcsservice/AndroidManifest.xml @@ -56,12 +56,22 @@ <uses-permission android:name="com.android.rcs.eab.permission.READ_WRITE_EAB"/> <application android:name="RcsServiceApp" android:persistent="true" - android:process="com.android.ims.rcsservice"> + android:process="com.android.ims.rcsservice" android:directBootAware="true"> <service android:name="com.android.service.ims.RcsService" android:exported="true" android:enabled="true" android:permission="com.android.ims.permission.PRESENCE_ACCESS"> </service> + <service + android:name="com.android.service.ims.ImsServiceImpl" + android:persistent="true" + android:permission="android.permission.BIND_IMS_SERVICE" > + <meta-data android:name="android.telephony.ims.RCS_FEATURE" android:value="true" /> + <intent-filter> + <action android:name="android.telephony.ims.ImsService" /> + </intent-filter> + </service> + <receiver android:name="com.android.service.ims.DeviceShutdown" androidprv:systemUserOnly="true"> diff --git a/rcs/rcsservice/src/com/android/service/ims/ImsServiceImpl.java b/rcs/rcsservice/src/com/android/service/ims/ImsServiceImpl.java new file mode 100644 index 0000000..8f4948c --- /dev/null +++ b/rcs/rcsservice/src/com/android/service/ims/ImsServiceImpl.java @@ -0,0 +1,105 @@ +/*- + * Copyright (C) 2019 The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package com.android.service.ims; + +import android.content.Context; +import android.content.Intent; +import android.os.IBinder; +import android.telephony.TelephonyManager; +import android.telephony.ims.ImsService; +import android.telephony.ims.feature.RcsFeature; +import android.util.Log; + +public class ImsServiceImpl extends ImsService { + public static final String TAG = "ImsServiceImpl"; + private static final int INVALID_SLOT_ID = -1; + private static final int UNINITIALIZED_VALUE = -1; + private int mNumPhonesCache = UNINITIALIZED_VALUE; + private RcsFeature mRcsFeature[]; + protected final Object mLock = new Object(); + + private int getNumSlots() { + if (mNumPhonesCache == UNINITIALIZED_VALUE) { + mNumPhonesCache = ((TelephonyManager) getSystemService( + Context.TELEPHONY_SERVICE)).getPhoneCount(); + } + return mNumPhonesCache; + } + + private void setup() { + final int numSlots = getNumSlots(); + mRcsFeature = new RcsFeatureImpl[numSlots]; + for (int i = 0; i < numSlots; i++) { + mRcsFeature[i] = new RcsFeatureImpl(this, i); + } + } + + @Override + public void onCreate() { + super.onCreate(); + Log.i(TAG, "ImsService created!"); + setup(); + } + + @Override + public IBinder onBind(Intent intent) { + if (android.telephony.ims.ImsService.SERVICE_INTERFACE.equals(intent.getAction())) { + Log.d(TAG, "Returning mImsServiceController for ImsService binding"); + return mImsServiceController; + } + Log.e(TAG, "Invalid Intent action in onBind: " + intent.getAction()); + return null; + } + + @Override + public void onDestroy() { + super.onDestroy(); + Log.i(TAG, "ImsService destroyed!"); + } + + /** + * When called, the framework is requesting that a new {@link RcsFeature} is created for the + * specified slot. + * + * @param slotId The slot ID that the RCS Feature is being created for. + * @return The newly created {@link RcsFeature} associated with the slot or null if the feature + * is not supported. + */ + @Override + public RcsFeature createRcsFeature(int slotId) { + Log.d(TAG, "createRcsFeature :: slotId=" + slotId + " numSlots=" + mNumPhonesCache); + if (slotId > INVALID_SLOT_ID && slotId < getNumSlots()) { + return mRcsFeature[slotId]; + } + Log.e(TAG, "createRcsFeature :: Invalid slotId " + slotId); + return null; + } +} diff --git a/rcs/rcsservice/src/com/android/service/ims/RcsFeatureImpl.java b/rcs/rcsservice/src/com/android/service/ims/RcsFeatureImpl.java new file mode 100644 index 0000000..53c44ad --- /dev/null +++ b/rcs/rcsservice/src/com/android/service/ims/RcsFeatureImpl.java @@ -0,0 +1,373 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +package com.android.service.ims; + +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.ComponentName; +import android.content.Intent; +import android.content.IntentFilter; +import android.os.Handler; +import android.os.HandlerThread; +import android.telephony.SubscriptionManager; +import android.telephony.ims.feature.CapabilityChangeRequest; +import android.telephony.ims.feature.CapabilityChangeRequest.CapabilityPair; +import android.telephony.ims.feature.ImsFeature; +import android.telephony.ims.feature.RcsFeature; +import android.telephony.ims.stub.ImsRegistrationImplBase; +import android.telephony.ims.stub.RcsPresenceExchangeImplBase; +import android.telephony.ims.stub.RcsSipOptionsImplBase; +import android.util.Log; + +import com.android.ims.RcsManager; +import com.android.internal.telephony.TelephonyIntents; + +import java.util.List; + +public class RcsFeatureImpl extends RcsFeature { + + private static final String TAG = "RcsFeatureImpl"; + + private static final String RCS_PACKAGE = "com.android.service.ims"; + private static final String RCS_CLASS = "com.android.service.ims.RcsService"; + private Context mContext; + private Handler mFeatureCallbackHandler; + private HandlerThread mFeatureHandlerThread; + private RcsImsCapabilities mRcsImsCapabilities; + private int mPhoneId; + private int mSubId; + private int mDefaultVoiceSubId; + private SubscriptionManager mSubscriptionManager; + private SubscriptionChangedListener mSubscriptionListener; + private RcsPresenceExchangeImplBase mRcsPresenceExchangeBase; + private RcsStackAdaptor mRcsStackAdaptor; + + // Used to synchronize mSubId and mDefaultVoiceSubId + private Object mToken = new Object(); + + + public RcsFeatureImpl(Context context, int phoneId) { + mContext = context; + mPhoneId = phoneId; + mFeatureHandlerThread = new HandlerThread(this + "FeatureHandlerThread"); + mFeatureHandlerThread.start(); + mFeatureCallbackHandler = new Handler(mFeatureHandlerThread.getLooper()); + mDefaultVoiceSubId = SubscriptionManager.getDefaultSubscriptionId(); + mRcsPresenceExchangeBase = new RcsPresenceExchangeImpl(mContext); + mRcsStackAdaptor = RcsStackAdaptor.getInstance(mContext); + mRcsImsCapabilities = new RcsImsCapabilities(RcsImsCapabilities.CAPABILITY_TYPE_NONE); + mSubscriptionManager = (SubscriptionManager) mContext.getSystemService( + Context.TELEPHONY_SUBSCRIPTION_SERVICE); + mSubId = getSubId(); + mSubscriptionListener = new SubscriptionChangedListener(); + mSubscriptionManager.addOnSubscriptionsChangedListener(mSubscriptionListener); + + registerVoiceSubscriptionChange(); + registerRcsStateReceiver(); + initFeatureState(); + logd("RcsFeatureImpl constructor mSubId:" + mSubId + ", " + + "mDefaultVoiceSubId:" + mDefaultVoiceSubId); + + } + + private int getSubId() { + int subId[] = mSubscriptionManager.getSubscriptionIds(mPhoneId); + return subId != null ? subId[0] : SubscriptionManager.INVALID_SUBSCRIPTION_ID; + } + + private void registerVoiceSubscriptionChange() { + IntentFilter intentFilter = new IntentFilter + (TelephonyIntents.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED); + mContext.registerReceiver(mVoiceSubscriptionReceiver, intentFilter); + } + + private void initFeatureState() { + // In DSDS environment, RcsFeatureImpl is only available for default voice subId. + if (isDefaultVoiceSubId()) { + logd("set STATE_READY"); + setFeatureState(ImsFeature.STATE_READY); + } else { + logd("set STATE_UNAVAILABLE"); + setFeatureState(ImsFeature.STATE_UNAVAILABLE); + } + } + + private boolean isDefaultVoiceSubId() { + synchronized (mToken) { + return SubscriptionManager.isValidSubscriptionId(mSubId) && + SubscriptionManager.isValidSubscriptionId(mDefaultVoiceSubId) && + mSubscriptionManager.isActiveSubscriptionId(mSubId) && + mSubscriptionManager.isActiveSubscriptionId(mDefaultVoiceSubId) && + mSubId == mDefaultVoiceSubId; + } + } + + private void startRcsService() { + ComponentName comp = new ComponentName(RCS_PACKAGE, RCS_CLASS); + ComponentName service = mContext.startService(new Intent().setComponent(comp)); + if (service == null) { + Log.e(TAG, "Could Not Start Service " + comp.toString()); + } else { + Log.d(TAG, comp.toString() + " started Successfully"); + } + } + + @Override + public void onFeatureReady() { + logd("onFeatureReady"); + mRcsPresenceExchangeBase.initialize(this); + mRcsStackAdaptor.setRcsPresenceExchangeImplBase(mRcsPresenceExchangeBase); + mRcsStackAdaptor.init(); + startRcsService(); + } + + @Override + public void onFeatureRemoved() { + logd("onFeatureRemoved"); + mContext.unregisterReceiver(mRcsStateReceiver); + mContext.unregisterReceiver(mVoiceSubscriptionReceiver); + mRcsStackAdaptor.setRcsPresenceExchangeImplBase(null); + } + + private void registerRcsStateReceiver() { + IntentFilter intentFilter = new IntentFilter(); + intentFilter.addAction(RcsManager.ACTION_RCS_SERVICE_AVAILABLE); + intentFilter.addAction(RcsManager.ACTION_RCS_SERVICE_UNAVAILABLE); + intentFilter.addAction(RcsManager.ACTION_RCS_SERVICE_DIED); + mContext.registerReceiver(mRcsStateReceiver, intentFilter); + } + + /** + * Retrieve the implementation of UCE presence for this {@link RcsFeature}. + * Will only be requested by the framework if presence exchang is configured as capable during + * a {@link #changeEnabledCapabilities(CapabilityChangeRequest, CapabilityCallbackProxy)} + * operation and the RcsFeature sets the status of the capability to true using + * {@link #notifyCapabilitiesStatusChanged(RcsImsCapabilities)}. + * + * @return An instance of {@link RcsPresenceExchangeImplBase} that implements presence + * exchange if it is supported by the device. + * @hide + */ + @Override + public RcsPresenceExchangeImplBase getPresenceExchangeImpl() { + return mRcsPresenceExchangeBase; + } + + /** + * Retrieve the implementation of SIP OPTIONS for this {@link RcsFeature}. + * <p> + * Will only be requested by the framework if capability exchange via SIP OPTIONS is + * configured as capable during a + * {@link #changeEnabledCapabilities(CapabilityChangeRequest, CapabilityCallbackProxy)} + * operation and the RcsFeature sets the status of the capability to true using + * {@link #notifyCapabilitiesStatusChanged(RcsImsCapabilities)}. + * + * @return An instance of {@link RcsSipOptionsImplBase} that implements SIP options exchange if + * it is supported by the device. + * @hide + */ + @Override + public RcsSipOptionsImplBase getOptionsExchangeImpl() { + return null; + } + + @Override + public void changeEnabledCapabilities(CapabilityChangeRequest request, + CapabilityCallbackProxy c) { + logd("changeEnabledCapabilities"); + if (request == null || c == null) { + loge("changeEnabledCapabilities :: Invalid argument(s)."); + return; + } + + List<CapabilityPair> capsToEnable = request.getCapabilitiesToEnable(); + List<CapabilityPair> capsToDisable = request.getCapabilitiesToDisable(); + if (capsToEnable.isEmpty() && capsToDisable.isEmpty()) { + loge("changeEnabledCapabilities :: No CapabilityPair objects to process!"); + return; + } + + for (CapabilityPair cp : capsToEnable) { + if (cp.getCapability() == RcsImsCapabilities.CAPABILITY_TYPE_OPTIONS_UCE) { + // SIP OPTION is not supported + callBackError(cp, c); + } else if (cp.getCapability() == RcsImsCapabilities.CAPABILITY_TYPE_PRESENCE_UCE) { + mRcsImsCapabilities.addCapabilities( + RcsImsCapabilities.CAPABILITY_TYPE_PRESENCE_UCE); + enableRcsPresence(); + } + } + for (CapabilityPair cp : capsToDisable) { + if (cp.getCapability() == RcsImsCapabilities.CAPABILITY_TYPE_OPTIONS_UCE) { + // SIP OPTION is not supported + callBackError(cp, c); + } else if (cp.getCapability() == RcsImsCapabilities.CAPABILITY_TYPE_PRESENCE_UCE) { + mRcsImsCapabilities.removeCapabilities(RcsImsCapabilities + .CAPABILITY_TYPE_PRESENCE_UCE); + disableRcsPresence(); + } + } + } + + private void callBackError(CapabilityPair cp, CapabilityCallbackProxy c) { + final Runnable r = new Runnable() { + @Override + public void run() { + c.onChangeCapabilityConfigurationError(cp.getCapability(), cp.getRadioTech(), + ImsFeature.CAPABILITY_ERROR_GENERIC); + } + }; + if (mFeatureCallbackHandler != null) { + mFeatureCallbackHandler.post(r); + } + } + + private void enableRcsPresence() { + RcsManager rcsManager = getRcsManager(); + if (rcsManager != null) { + rcsManager.setPresenceEnabledByFramework(true); + } + if (rcsManager != null && rcsManager.isRcsServiceAvailable()) { + Intent intent = new Intent(RcsManager.ACTION_RCS_SERVICE_AVAILABLE); + mContext.sendBroadcast(intent, + "com.android.ims.rcs.permission.STATUS_CHANGED"); + } + } + + private void disableRcsPresence() { + RcsManager rcsManager = getRcsManager(); + if (rcsManager != null) { + rcsManager.setPresenceEnabledByFramework(false); + } + Intent intent = new Intent(RcsManager.ACTION_RCS_SERVICE_UNAVAILABLE); + mContext.sendBroadcast(intent, + "com.android.ims.rcs.permission.STATUS_CHANGED"); + } + + private RcsManager getRcsManager() { + if (isDefaultVoiceSubId()) { + return RcsManager.getInstance(mContext, mSubId); + } else { + return null; + } + } + + @Override + public boolean queryCapabilityConfiguration( + @RcsImsCapabilities.RcsImsCapabilityFlag int capability, + @ImsRegistrationImplBase.ImsRegistrationTech int radioTech) { + logi("queryCapabilityConfiguration :: capability=" + capability + + " radioTech=" + radioTech); + return mRcsImsCapabilities != null && mRcsImsCapabilities.isCapable(capability); + } + + private final BroadcastReceiver mRcsStateReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + RcsFeatureImpl.this.logi("onReceive(), intent: " + intent + ", context: " + context); + String action = intent.getAction(); + RcsManager rcsManager = getRcsManager(); + if (RcsManager.ACTION_RCS_SERVICE_AVAILABLE.equals(action)) { + // Check if both enableRcsPresence() and StackListener's serviceAvailable() are + // executed. + if (rcsManager != null && rcsManager.isRcsServiceAvailable()) { + notifyCapabilitiesStatusChanged(new RcsImsCapabilities(RcsImsCapabilities + .CAPABILITY_TYPE_PRESENCE_UCE)); + } + } else if (RcsManager.ACTION_RCS_SERVICE_UNAVAILABLE.equals(action) || + RcsManager.ACTION_RCS_SERVICE_DIED.equals(action)) { + // Triggered from disabledRcsPresence() or StackListener's serviceUnAvailable(). + if (rcsManager != null) { + notifyCapabilitiesStatusChanged(new RcsImsCapabilities(RcsImsCapabilities + .CAPABILITY_TYPE_NONE)); + } + } + } + }; + + private final BroadcastReceiver mVoiceSubscriptionReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + String action = intent.getAction(); + if (TelephonyIntents.ACTION_DEFAULT_VOICE_SUBSCRIPTION_CHANGED.equals(action)) { + int newVoiceSubId = SubscriptionManager.getDefaultSubscriptionId(); + synchronized (mToken) { + if (newVoiceSubId != mDefaultVoiceSubId) { + mDefaultVoiceSubId = newVoiceSubId; + mSubId = getSubId(); + logd("mVoiceSubscriptionReceiver mSubId:" + mSubId + " " + + "mDefaultVoiceSubId:" + mDefaultVoiceSubId); + processFeatureChange(); + } + } + } + } + }; + + class SubscriptionChangedListener extends SubscriptionManager.OnSubscriptionsChangedListener { + @Override + public void onSubscriptionsChanged() { + int newSubId = getSubId(); + synchronized (mToken) { + if (newSubId != mSubId) { + mSubId = newSubId; + mDefaultVoiceSubId = SubscriptionManager.getDefaultSubscriptionId(); + logd("onSubscriptionsChanged mSubId:" + mSubId + " mDefaultVoiceSubId:" + + mDefaultVoiceSubId); + processFeatureChange(); + } + } + } + } + + private void processFeatureChange() { + if (isDefaultVoiceSubId()) { + logd("set STATE_READY"); + setFeatureState(ImsFeature.STATE_READY); + } else { + logd("set STATE_UNAVAILABLE"); + setFeatureState(ImsFeature.STATE_UNAVAILABLE); + } + } + + private void logd(String s) { + Log.d(TAG, "[" + mPhoneId + "][" + mSubId + "] " + s); + } + + private void logi(String s) { + Log.i(TAG, "[" + mPhoneId + "][" + mSubId + "] " + s); + } + + private void loge(String s) { + Log.e(TAG, "[" + mPhoneId + "][" + mSubId + "] " + s); + } +} diff --git a/rcs/rcsservice/src/com/android/service/ims/RcsPresenceExchangeImpl.java b/rcs/rcsservice/src/com/android/service/ims/RcsPresenceExchangeImpl.java new file mode 100644 index 0000000..3a995f4 --- /dev/null +++ b/rcs/rcsservice/src/com/android/service/ims/RcsPresenceExchangeImpl.java @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of the copyright holder nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +package com.android.service.ims; + +import android.annotation.NonNull; +import android.content.Context; +import android.net.Uri; +import android.telephony.ims.RcsContactUceCapability; +import android.telephony.ims.stub.RcsPresenceExchangeImplBase; +import android.util.Log; + +import com.android.ims.RcsManager; +import com.android.ims.RcsPresenceInfo; +import com.android.service.ims.RcsStackAdaptor; +import com.android.service.ims.TaskManager; + +import java.util.List; + +public class RcsPresenceExchangeImpl extends RcsPresenceExchangeImplBase { + + private Context mContext; + private static final String TAG = "RcsPresenceExchangeImpl"; + + public RcsPresenceExchangeImpl(Context context) { + mContext = context; + } + + + /** + * The user capabilities of one or multiple contacts have been requested by the framework. + * <p> + * The implementer must follow up this call with an {@link #onCommandUpdate(int, int)} call to + * indicate whether or not this operation succeeded. If this operation succeeds, network + * response updates should be sent to the framework using + * {@link #onNetworkResponse(int, String, int)}. When the operation is completed, + * {@link #onCapabilityRequestResponse(List, int)} should be called with the presence + * information for the contacts specified. + * + * @param uris A {@link List} of the {@link Uri}s that the framework is requesting + * the UCE + * capabilities for. + * @param operationToken The token associated with this operation. Updates to this request using + * {@link #onCommandUpdate(int, int)}, + * {@link #onNetworkResponse(int, String, int)}, and + * {@link #onCapabilityRequestResponse(List, int)} must use the same + * operation token + * in response. + */ + public void requestCapabilities(@NonNull List<Uri> uris, int operationToken) { + Log.d(TAG, "requestCapabilities operationToken:" + operationToken); + String[] contacts = new String[uris.size()]; + for (int i = 0; i < uris.size(); i++) { + contacts[i] = uris.get(i).toString(); + } + RcsStackAdaptor.getInstance(null).requestCapability(contacts, operationToken); + } + + /** + * The capabilities of this device have been updated and should be published to the network. + * <p> + * The implementer must follow up this call with an {@link #onCommandUpdate(int, int)} call to + * indicate whether or not this operation succeeded. If this operation succeeds, network + * response updates should be sent to the framework using + * {@link #onNetworkResponse(int, String, int)}. + * + * @param capabilities The capabilities for this device. + * @param operationToken The token associated with this operation. Any subsequent + * {@link #onCommandUpdate(int, int)} or + * {@link #onNetworkResponse(int, String, int)} + * calls regarding this update must use the same token. + */ + public void updateCapabilities(@NonNull RcsContactUceCapability capabilities, + int operationToken) { + Log.d(TAG, "updateCapabilities operationToken:" + operationToken); + boolean isVolte = capabilities.isCapable(RcsContactUceCapability + .CAPABILITY_IP_VOICE_CALL); + boolean isVt = capabilities.isCapable( + RcsContactUceCapability.CAPABILITY_IP_VIDEO_CALL); + int volteState = isVolte ? RcsPresenceInfo.ServiceState.ONLINE + : RcsPresenceInfo.ServiceState.OFFLINE; + int vtState = isVt ? RcsPresenceInfo.ServiceState.ONLINE + : RcsPresenceInfo.ServiceState.OFFLINE; + RcsPresenceInfo presenceInfo = new RcsPresenceInfo(capabilities.getContactUri().toString(), + RcsPresenceInfo.VolteStatus.VOLTE_UNKNOWN, + volteState, + null, + System.currentTimeMillis(), + vtState, + null, + System.currentTimeMillis() + ); + RcsStackAdaptor.getInstance(null).requestPublication(presenceInfo, null, operationToken); + } + +} diff --git a/rcs/rcsservice/src/com/android/service/ims/RcsService.java b/rcs/rcsservice/src/com/android/service/ims/RcsService.java index 953db2f..5e83d51 100644 --- a/rcs/rcsservice/src/com/android/service/ims/RcsService.java +++ b/rcs/rcsservice/src/com/android/service/ims/RcsService.java @@ -80,7 +80,7 @@ public class RcsService extends Service{ logger.debug("RcsService onCreate"); - mRcsStackAdaptor = RcsStackAdaptor.getInstance(this); + mRcsStackAdaptor = RcsStackAdaptor.getInstance(null); mPublication = new PresencePublication(mRcsStackAdaptor, this, getResources().getStringArray( diff --git a/rcs/rcsservice/src/com/android/service/ims/RcsServiceApp.java b/rcs/rcsservice/src/com/android/service/ims/RcsServiceApp.java index c1f683d..c48f1dc 100644 --- a/rcs/rcsservice/src/com/android/service/ims/RcsServiceApp.java +++ b/rcs/rcsservice/src/com/android/service/ims/RcsServiceApp.java @@ -39,8 +39,6 @@ public class RcsServiceApp extends Application { public void onCreate() { super.onCreate(); logger.debug("in onCreate() of RcsServiceApp"); - - LauncherUtils.launchRcsService(this); } } diff --git a/rcs/rcsservice/src/com/android/service/ims/RcsStackAdaptor.java b/rcs/rcsservice/src/com/android/service/ims/RcsStackAdaptor.java index 902f6c7..2f2c2d3 100644 --- a/rcs/rcsservice/src/com/android/service/ims/RcsStackAdaptor.java +++ b/rcs/rcsservice/src/com/android/service/ims/RcsStackAdaptor.java @@ -56,6 +56,7 @@ import com.android.ims.ImsConfig; import com.android.ims.ImsManager; import com.android.ims.ImsException; import android.telephony.SubscriptionManager; +import android.telephony.ims.stub.RcsPresenceExchangeImplBase; import com.android.ims.IRcsPresenceListener; import com.android.ims.RcsPresence; @@ -160,11 +161,11 @@ public class RcsStackAdaptor{ // The singleton. private static RcsStackAdaptor sInstance = null; + private RcsPresenceExchangeImplBase mRcsPresenceExchangeImplBase; + // Constructor private RcsStackAdaptor(Context context) { mContext = context; - - init(); } public static synchronized RcsStackAdaptor getInstance(Context context) { @@ -342,7 +343,8 @@ public class RcsStackAdaptor{ return ret; } - public int requestPublication(RcsPresenceInfo presenceInfo, IRcsPresenceListener listener) { + public int requestPublication(RcsPresenceInfo presenceInfo, IRcsPresenceListener listener, + int taskId) { logger.debug("requestPublication ..."); // Don't use checkStackAndPublish() @@ -395,7 +397,6 @@ public class RcsStackAdaptor{ return PresencePublication.PUBLISH_GENIRIC_FAILURE; } - int taskId = TaskManager.getDefault().addPublishTask(myNumber, listener); try{ PresCapInfo pMyCapInfo = new PresCapInfo(); // Fill cap info @@ -614,7 +615,7 @@ public class RcsStackAdaptor{ thread.start(); } - private void init() { + public void init() { createListeningThread(); logger.debug("after createListeningThread"); @@ -729,6 +730,15 @@ public class RcsStackAdaptor{ clearImsUceService(); } + public RcsPresenceExchangeImplBase getRcsPresenceExchangeImplBase() { + return mRcsPresenceExchangeImplBase; + } + + public void setRcsPresenceExchangeImplBase( + RcsPresenceExchangeImplBase rcsPresenceExchangeImplBase) { + mRcsPresenceExchangeImplBase = rcsPresenceExchangeImplBase; + } + protected void finalize() throws Throwable { super.finalize(); finish(); diff --git a/rcs/rcsservice/src/com/android/service/ims/RcsUtils.java b/rcs/rcsservice/src/com/android/service/ims/RcsUtils.java index bbfacd2..623fa74 100644 --- a/rcs/rcsservice/src/com/android/service/ims/RcsUtils.java +++ b/rcs/rcsservice/src/com/android/service/ims/RcsUtils.java @@ -28,10 +28,19 @@ package com.android.service.ims; +import static com.android.ims.RcsPresenceInfo.ServiceType.VOLTE_CALL; +import static com.android.ims.RcsPresenceInfo.ServiceType.VT_CALL; + import java.lang.String; +import java.util.ArrayList; + +import android.net.Uri; import android.telephony.TelephonyManager; import android.content.Context; +import android.telephony.ims.RcsContactUceCapability; +import android.telephony.ims.stub.RcsCapabilityExchange; +import com.android.ims.RcsPresenceInfo; import com.android.ims.internal.uce.common.StatusCode; import com.android.ims.RcsManager.ResultCode; @@ -90,6 +99,75 @@ public class RcsUtils{ return ResultCode.SUBSCRIBE_GENERIC; } + static public int statusCodeToCommandCode(int sipStatusCode) { + if (sipStatusCode == StatusCode.UCE_SUCCESS || + sipStatusCode == StatusCode.UCE_SUCCESS_ASYC_UPDATE) { + return RcsCapabilityExchange.COMMAND_CODE_SUCCESS; + } + + if (sipStatusCode == StatusCode.UCE_INVALID_PARAM) { + return RcsCapabilityExchange.COMMAND_CODE_INVALID_PARAM; + } + + if (sipStatusCode == StatusCode.UCE_FETCH_ERROR) { + return RcsCapabilityExchange.COMMAND_CODE_FETCH_ERROR; + } + + if (sipStatusCode == StatusCode.UCE_REQUEST_TIMEOUT) { + return RcsCapabilityExchange.COMMAND_CODE_REQUEST_TIMEOUT; + } + + if (sipStatusCode == StatusCode.UCE_INSUFFICIENT_MEMORY) { + return RcsCapabilityExchange.COMMAND_CODE_INSUFFICIENT_MEMORY; + } + + if (sipStatusCode == StatusCode.UCE_LOST_NET) { + return RcsCapabilityExchange.COMMAND_CODE_LOST_NETWORK_CONNECTION; + } + + if (sipStatusCode == StatusCode.UCE_NOT_SUPPORTED) { + return RcsCapabilityExchange.COMMAND_CODE_NOT_SUPPORTED; + } + + if (sipStatusCode == StatusCode.UCE_NOT_FOUND) { + return RcsCapabilityExchange.COMMAND_CODE_NOT_FOUND; + } + + if (sipStatusCode == StatusCode.UCE_FAILURE || + sipStatusCode == StatusCode.UCE_INVALID_SERVICE_HANDLE || + sipStatusCode == StatusCode.UCE_INVALID_LISTENER_HANDLE) { + return RcsCapabilityExchange.COMMAND_CODE_GENERIC_FAILURE; + } + + return RcsCapabilityExchange.COMMAND_CODE_GENERIC_FAILURE; + } + + static public ArrayList<RcsContactUceCapability> transformToRcsContactUceCapability + (ArrayList<RcsPresenceInfo> presenceInfoList) { + ArrayList<RcsContactUceCapability> uceCapabilityArrayList = new ArrayList<>( + presenceInfoList.size()); + for (RcsPresenceInfo info : presenceInfoList) { + RcsContactUceCapability.Builder builder = new RcsContactUceCapability.Builder(Uri + .parse(info.getContactNumber())); + if (info.getServiceState(VOLTE_CALL) == RcsPresenceInfo.ServiceState.ONLINE) { + builder.add(RcsContactUceCapability.CAPABILITY_IP_VOICE_CALL); + } + if (info.getServiceState(VT_CALL) == RcsPresenceInfo.ServiceState.ONLINE) { + builder.add(RcsContactUceCapability.CAPABILITY_IP_VIDEO_CALL); + } + uceCapabilityArrayList.add(builder.build()); + } + return uceCapabilityArrayList; + } + + static public ArrayList<Uri> transformToUri(String[] contacts) { + ArrayList<Uri> list = new ArrayList<>(); + for(String contact : contacts) { + list.add(Uri.parse(contact)); + } + return list; + } + static public String toContactString(String[] contacts) { if(contacts == null) { return null; diff --git a/rcs/rcsservice/src/com/android/service/ims/TaskManager.java b/rcs/rcsservice/src/com/android/service/ims/TaskManager.java index 74e11a6..7d11ea3 100644 --- a/rcs/rcsservice/src/com/android/service/ims/TaskManager.java +++ b/rcs/rcsservice/src/com/android/service/ims/TaskManager.java @@ -66,6 +66,7 @@ public class TaskManager{ private int mTaskId = 0; + public final static int INVALID_ID = -1; public final static int TASK_TYPE_GET_CAPABILITY = 1; public final static int TASK_TYPE_GET_AVAILABILITY = 2; public final static int TASK_TYPE_PUBLISH = 3; @@ -190,16 +191,16 @@ public class TaskManager{ return null; } - public void onTerminated(String contact){ // for single number capability polling + public int onTerminated(String contact){ // for single number capability polling if(contact == null){ - return; + return INVALID_ID; } synchronized (mSyncObj){ Set<String> keys= mTaskMap.keySet(); if(keys == null){ logger.debug("onTerminated keys is null"); - return; + return INVALID_ID; } for(String key:keys){ @@ -225,19 +226,21 @@ public class TaskManager{ TASK_MANAGER_ON_TERMINATED, messageData); sMsgHandler.sendMessage(notifyMessage); + return task.mTaskId; } } } } + return INVALID_ID; } - public void onTerminated(int requestId, String reason){ + public int onTerminated(int requestId, String reason){ logger.debug("onTerminated requestId=" + requestId + " reason=" + reason); Task task = getTaskByRequestId(requestId); if(task == null){ logger.debug("onTerminated Can't find request " + requestId); - return; + return INVALID_ID; } synchronized (mSyncObj){ @@ -249,8 +252,10 @@ public class TaskManager{ Message notifyMessage = sMsgHandler.obtainMessage(TASK_MANAGER_ON_TERMINATED, messageData); sMsgHandler.sendMessage(notifyMessage); + return task.mTaskId; } } + return INVALID_ID; } public void onTimeout(int taskId){ diff --git a/rcs/rcsservice/src/com/android/service/ims/presence/PresencePublication.java b/rcs/rcsservice/src/com/android/service/ims/presence/PresencePublication.java index e7607ee..4e7edb6 100644 --- a/rcs/rcsservice/src/com/android/service/ims/presence/PresencePublication.java +++ b/rcs/rcsservice/src/com/android/service/ims/presence/PresencePublication.java @@ -28,53 +28,45 @@ package com.android.service.ims.presence; -import java.util.List; -import java.util.Arrays; - +import android.app.AlarmManager; +import android.app.PendingIntent; +import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; -import com.android.internal.telephony.Phone; -import android.provider.Settings; -import android.os.SystemProperties; -import android.content.BroadcastReceiver; -import android.content.ComponentName; -import android.telephony.TelephonyManager; -import com.android.internal.telephony.IccCardConstants; -import com.android.internal.telephony.TelephonyIntents; -import android.telecom.TelecomManager; import android.content.IntentFilter; -import android.app.PendingIntent; -import android.app.AlarmManager; -import android.os.SystemClock; -import android.os.Message; +import android.net.Uri; import android.os.Handler; +import android.os.Message; +import android.os.SystemClock; +import android.os.SystemProperties; +import android.provider.Settings; +import android.telecom.TelecomManager; +import android.telephony.SubscriptionManager; +import android.telephony.TelephonyManager; +import android.telephony.ims.RcsContactUceCapability; +import android.telephony.ims.stub.RcsPresenceExchangeImplBase; - +import com.android.ims.ImsConfig; import com.android.ims.ImsManager; -import com.android.ims.ImsConnectionStateListener; import com.android.ims.ImsServiceClass; -import com.android.ims.ImsException; -import android.telephony.SubscriptionManager; -import com.android.ims.ImsConfig; -import com.android.ims.ImsConfig.FeatureConstants; -import com.android.ims.ImsConfig.FeatureValueConstants; - -import com.android.service.ims.RcsSettingUtils; -import com.android.ims.RcsPresenceInfo; -import com.android.ims.IRcsPresenceListener; import com.android.ims.RcsManager.ResultCode; import com.android.ims.RcsPresence.PublishState; - +import com.android.ims.RcsPresenceInfo; import com.android.ims.internal.Logger; -import com.android.service.ims.TaskManager; -import com.android.service.ims.Task; - +import com.android.ims.internal.uce.presence.PresCmdStatus; import com.android.ims.internal.uce.presence.PresPublishTriggerType; import com.android.ims.internal.uce.presence.PresSipResponse; -import com.android.ims.internal.uce.common.StatusCode; -import com.android.ims.internal.uce.presence.PresCmdStatus; - +import com.android.internal.telephony.IccCardConstants; +import com.android.internal.telephony.Phone; +import com.android.internal.telephony.TelephonyIntents; +import com.android.service.ims.RcsPresenceExchangeImpl; +import com.android.service.ims.RcsSettingUtils; import com.android.service.ims.RcsStackAdaptor; +import com.android.service.ims.RcsUtils; +import com.android.service.ims.Task; +import com.android.service.ims.TaskManager; + +import java.util.Arrays; public class PresencePublication extends PresenceBase { private Logger logger = Logger.getLogger(this.getClass().getName()); @@ -932,7 +924,24 @@ public class PresencePublication extends PresenceBase { mPublishingRequest.setTimestamp(System.currentTimeMillis()); } - int ret = mRcsStackAdaptor.requestPublication(presenceInfo, null); + RcsPresenceExchangeImplBase rcsPresenceExchange = RcsStackAdaptor.getInstance( + null).getRcsPresenceExchangeImplBase(); + int ret = ResultCode.ERROR_SERVICE_NOT_AVAILABLE; + if (rcsPresenceExchange != null) { + RcsContactUceCapability.Builder builder = new RcsContactUceCapability.Builder(Uri + .parse("tel:" + teleMgr.getLine1Number())); + int taskId = TaskManager.getDefault().addPublishTask(teleMgr.getLine1Number(), null); + if (publishRequest.getVolteCapable()) { + builder.add(RcsContactUceCapability.CAPABILITY_IP_VOICE_CALL); + } + if (publishRequest.getVtCapable()) { + builder.add(RcsContactUceCapability.CAPABILITY_IP_VIDEO_CALL); + } + rcsPresenceExchange.updateCapabilities(builder.build(), taskId); + } else { + logger.debug("rcsPresenceExchange = null for publish request"); + } + if(ret == ResultCode.ERROR_SERVICE_NOT_AVAILABLE){ mHasCachedTrigger = true; }else{ @@ -943,6 +952,19 @@ public class PresencePublication extends PresenceBase { public void handleCmdStatus(PresCmdStatus cmdStatus) { super.handleCmdStatus(cmdStatus); + int commandCode = RcsUtils.statusCodeToCommandCode(cmdStatus.getStatus().getStatusCode()); + RcsPresenceExchangeImplBase rcsPresenceExchange = RcsStackAdaptor.getInstance(null) + .getRcsPresenceExchangeImplBase(); + logger.debug("publish cmd:" + cmdStatus); + if (rcsPresenceExchange != null) { + try { + rcsPresenceExchange.onCommandUpdate(commandCode, cmdStatus.getUserData()); + } catch (Exception e) { + logger.error(e.getMessage()); + } + } else { + logger.debug("rcsPresenceExchange = null for sip response"); + } } private PendingIntent mRetryAlarmIntent = null; @@ -1077,6 +1099,24 @@ public class PresencePublication extends PresenceBase { } handleCallback(task, getPublishState(), false); + notifyFrameworkForPublishResponse(task); + } + + private void notifyFrameworkForPublishResponse(Task task) { + RcsPresenceExchangeImpl rcsPresenceExchange = + (RcsPresenceExchangeImpl) RcsStackAdaptor.getInstance(null) + .getRcsPresenceExchangeImplBase(); + if (rcsPresenceExchange != null) { + try { + logger.debug("onNetworkResponse task:"+task); + rcsPresenceExchange.onNetworkResponse(task.mSipResponseCode, task.mSipReasonPhrase, + task.mTaskId); + } catch (Exception e) { + logger.error(e.getMessage()); + } + } else { + logger.debug("rcsPresenceExchange = null for sip response"); + } } private static boolean isTtyEnabled(int mode) { diff --git a/rcs/rcsservice/src/com/android/service/ims/presence/PresenceSubscriber.java b/rcs/rcsservice/src/com/android/service/ims/presence/PresenceSubscriber.java index daa2636..fd2a701 100644 --- a/rcs/rcsservice/src/com/android/service/ims/presence/PresenceSubscriber.java +++ b/rcs/rcsservice/src/com/android/service/ims/presence/PresenceSubscriber.java @@ -30,30 +30,19 @@ package com.android.service.ims.presence; import java.util.List; import java.util.ArrayList; -import java.util.Timer; -import java.util.TimerTask; -import java.util.concurrent.Semaphore; -import android.content.ContentValues; +import android.telephony.ims.RcsContactUceCapability; +import android.telephony.ims.stub.RcsCapabilityExchange; +import android.telephony.ims.stub.RcsPresenceExchangeImplBase; import android.text.TextUtils; -import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; -import android.content.IntentFilter; -import com.android.internal.telephony.TelephonyIntents; -import android.os.HandlerThread; -import android.os.RemoteException; import android.telephony.TelephonyManager; -import android.database.Cursor; import java.lang.String; -import android.content.Context; -import android.util.Log; import com.android.ims.internal.uce.presence.PresSipResponse; -import com.android.ims.internal.uce.common.StatusCode; -import com.android.ims.internal.uce.common.StatusCode; import com.android.ims.internal.uce.presence.PresSubscriptionState; import com.android.ims.internal.uce.presence.PresCmdStatus; import com.android.ims.internal.uce.presence.PresResInfo; @@ -68,6 +57,7 @@ import com.android.ims.RcsPresence.PublishState; import com.android.ims.internal.Logger; import com.android.ims.internal.ContactNumberUtils; +import com.android.service.ims.RcsPresenceExchangeImpl; import com.android.service.ims.TaskManager; import com.android.service.ims.Task; import com.android.service.ims.RcsStackAdaptor; @@ -160,6 +150,15 @@ public class PresenceSubscriber extends PresenceBase{ for(int i=0; i<formatedContacts.length; i++){ formatedContacts[i] = numberToTelString(formatedNumbers[i]); } + + RcsPresenceExchangeImplBase rcsPresenceExchange = RcsStackAdaptor.getInstance( + null).getRcsPresenceExchangeImplBase(); + if (rcsPresenceExchange == null) { + ret = ResultCode.SUBSCRIBE_GENIRIC_FAILURE; + logger.error("rcsPresenceExchange = null"); + return ret; + } + // In ms long timeout = RcsSettingUtils.getCapabPollListSubExp(mContext) * 1000; timeout += RcsSettingUtils.getSIPT1Timer(mContext); @@ -176,12 +175,8 @@ public class PresenceSubscriber extends PresenceBase{ listener, timeout); logger.print("taskId=" + taskId); - ret = mRcsStackAdaptor.requestCapability(formatedContacts, taskId); - if(ret < ResultCode.SUCCESS){ - logger.error("requestCapability ret=" + ret + " remove taskId=" + taskId); - TaskManager.getDefault().removeTask(taskId); - } - + rcsPresenceExchange.requestCapabilities(RcsUtils.transformToUri(formatedContacts), + taskId); ret = taskId; return ret; @@ -444,6 +439,24 @@ public class PresenceSubscriber extends PresenceBase{ } handleCallback(task, errorCode, false); + notifyFrameworkForSubscribeResponse(task); + } + + private void notifyFrameworkForSubscribeResponse(Task task) { + RcsPresenceExchangeImpl rcsPresenceExchange = + (RcsPresenceExchangeImpl) RcsStackAdaptor.getInstance(null) + .getRcsPresenceExchangeImplBase(); + if (rcsPresenceExchange != null) { + try { + logger.debug("onNetworkResponse taskid=" + task.mTaskId); + rcsPresenceExchange.onNetworkResponse(task.mSipResponseCode, task.mSipReasonPhrase, + task.mTaskId); + } catch (Exception e) { + logger.error(e.getMessage()); + } + } else { + logger.debug("rcsPresenceExchange = null for sip response"); + } } private void launchPersistService(Intent intent) { @@ -481,7 +494,7 @@ public class PresenceSubscriber extends PresenceBase{ rcsPresenceInfoList.add(rcsPresenceInfo); // For single contact number we got 1 NOTIFY only. So regard it as terminated. - TaskManager.getDefault().onTerminated(rcsPresenceInfo.getContactNumber()); + int taskId = TaskManager.getDefault().onTerminated(rcsPresenceInfo.getContactNumber()); PresenceAvailabilityTask availabilityTask = TaskManager.getDefault(). getAvailabilityTaskByContact(rcsPresenceInfo.getContactNumber()); @@ -495,6 +508,7 @@ public class PresenceSubscriber extends PresenceBase{ rcsPresenceInfoList); intent.putExtra("updateLastTimestamp", true); launchPersistService(intent); + notifyPresence(rcsPresenceInfoList, taskId); } public void updatePresences(PresRlmiInfo pRlmiInfo, PresResInfo[] pRcsPresenceInfo) { @@ -529,8 +543,9 @@ public class PresenceSubscriber extends PresenceBase{ } } + int taskId = TaskManager.INVALID_ID; if(isTerminated){ - TaskManager.getDefault().onTerminated(pRlmiInfo.getRequestId(), + taskId = TaskManager.getDefault().onTerminated(pRlmiInfo.getRequestId(), pRlmiInfo.getSubscriptionTerminatedReason()); } @@ -543,6 +558,24 @@ public class PresenceSubscriber extends PresenceBase{ rcsPresenceInfoList); intent.putExtra("updateLastTimestamp", true); launchPersistService(intent); + notifyPresence(rcsPresenceInfoList, taskId); + } + } + + private void notifyPresence(ArrayList rcsPresenceInfoList, int taskId) { + RcsPresenceExchangeImplBase rcsPresenceExchange = RcsStackAdaptor.getInstance(null) + .getRcsPresenceExchangeImplBase(); + if (rcsPresenceExchange != null) { + try { + ArrayList<RcsContactUceCapability> list = RcsUtils + .transformToRcsContactUceCapability(rcsPresenceInfoList); + logger.debug("onCapabilityRequestResponse taskid="+taskId); + rcsPresenceExchange.onCapabilityRequestResponse(list, taskId); + } catch (Exception e) { + logger.error(e.getMessage()); + } + } else { + logger.debug("rcsPresenceExchange = null for sip response"); } } @@ -552,7 +585,6 @@ public class PresenceSubscriber extends PresenceBase{ return; } - Task taskTmp = TaskManager.getDefault().getTask(pCmdStatus.getUserData()); int resultCode = RcsUtils.statusCodeToResultCode(pCmdStatus.getStatus().getStatusCode()); logger.print("handleCmdStatus resultCode=" + resultCode); @@ -565,12 +597,27 @@ public class PresenceSubscriber extends PresenceBase{ // handle error as the same as temporary network error // set availability to false, keep old capability - if(resultCode != ResultCode.SUCCESS && task.mContacts != null){ + if(resultCode != RcsCapabilityExchange.COMMAND_CODE_SUCCESS && task.mContacts != + null){ updateAvailabilityToUnknown(task); } } handleCallback(task, resultCode, true); + + RcsPresenceExchangeImplBase rcsPresenceExchange = RcsStackAdaptor.getInstance(null) + .getRcsPresenceExchangeImplBase(); + if (rcsPresenceExchange != null) { + try { + logger.print("onCommandUpdate id:"+pCmdStatus.getUserData()); + int commandCode = RcsUtils.statusCodeToCommandCode(pCmdStatus.getStatus().getStatusCode()); + rcsPresenceExchange.onCommandUpdate(commandCode, pCmdStatus.getUserData()); + } catch (Exception e) { + logger.error(e.getMessage()); + } + } else { + logger.debug("rcsPresenceExchange = null for sip response"); + } } private void updateAvailabilityToUnknown(Task inTask){ diff --git a/rcs/rcsservice/src/com/android/service/ims/presence/StackListener.java b/rcs/rcsservice/src/com/android/service/ims/presence/StackListener.java index 9ca82fc..9f15e23 100644 --- a/rcs/rcsservice/src/com/android/service/ims/presence/StackListener.java +++ b/rcs/rcsservice/src/com/android/service/ims/presence/StackListener.java @@ -28,19 +28,13 @@ package com.android.service.ims.presence; -import java.util.ArrayList; -import java.util.List; - -import android.content.ServiceConnection; -import android.annotation.SuppressLint; import android.content.Intent; import android.content.Context; -import android.content.SharedPreferences; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.RemoteException; -import android.text.TextUtils; +import android.telephony.ims.stub.RcsPresenceExchangeImplBase; import android.util.Log; import android.os.Parcel; @@ -53,17 +47,11 @@ import com.android.ims.internal.uce.presence.PresRlmiInfo; import com.android.ims.internal.uce.presence.PresSipResponse; import com.android.ims.internal.uce.presence.PresTupleInfo; import com.android.ims.internal.uce.common.StatusCode; -import com.android.ims.internal.uce.common.StatusCode; import com.android.ims.RcsManager; -import com.android.ims.RcsManager.ResultCode; -import com.android.ims.RcsPresence; -import com.android.ims.RcsPresenceInfo; -import com.android.ims.IRcsPresenceListener; import com.android.ims.internal.Logger; -import com.android.service.ims.TaskManager; -import com.android.service.ims.Task; +import com.android.service.ims.RcsPresenceExchangeImpl; import com.android.service.ims.RcsStackAdaptor; public class StackListener extends Handler{ @@ -391,7 +379,18 @@ public class StackListener extends Handler{ publishTrigger.getPublishTrigeerType()); } logger.debug("ListenerHandler : PublishTriggering"); - + RcsPresenceExchangeImplBase rcsPresenceExchange = RcsStackAdaptor.getInstance(null) + .getRcsPresenceExchangeImplBase(); + if (rcsPresenceExchange != null) { + try { + logger.debug("onNotifyUpdateCapabilites"); + rcsPresenceExchange.onNotifyUpdateCapabilites(); + } catch (Exception e) { + logger.error(e.getMessage()); + } + } else { + logger.debug("rcsPresenceExchange = null for publishTriggering"); + } Message publishTrigerMsg = StackListener.this.obtainMessage( PRESENCE_IMS_UNSOL_PUBLISH_TRIGGER, publishTrigger); StackListener.this.sendMessage(publishTrigerMsg); @@ -532,6 +531,19 @@ public class StackListener extends Handler{ public void unpublishMessageSent() { logger.debug("unpublishMessageSent()"); + RcsPresenceExchangeImpl rcsPresenceExchange = + (RcsPresenceExchangeImpl) RcsStackAdaptor.getInstance(null) + .getRcsPresenceExchangeImplBase(); + if (rcsPresenceExchange != null) { + try { + logger.debug("onUnpublish"); + rcsPresenceExchange.onUnpublish(); + } catch (Exception e) { + logger.error(e.getMessage()); + } + } else { + logger.debug("rcsPresenceExchange = null for unpublish sent"); + } } }; } |