[RCS UCE] The creation of UceController by TelephonyRcsService.
TelephonyRcsService creates the UceController to replace the UserCapabilityExchangeImpl to handle the UCE capabilities request.
Bug: 161198092
Test: atest TelephonyRcsServiceTest; atest UceControllerManagerTest
Change-Id: I74a8aabe0c3953a18d65064a4593177a89fa4ff0
diff --git a/src/com/android/phone/ImsRcsController.java b/src/com/android/phone/ImsRcsController.java
index 461a097..e415122 100644
--- a/src/com/android/phone/ImsRcsController.java
+++ b/src/com/android/phone/ImsRcsController.java
@@ -23,6 +23,7 @@
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyFrameworkInitializer;
import android.telephony.ims.ImsException;
+import android.telephony.ims.RcsUceAdapter.PublishState;
import android.telephony.ims.RegistrationManager;
import android.telephony.ims.aidl.IImsCapabilityCallback;
import android.telephony.ims.aidl.IImsRcsController;
@@ -44,7 +45,7 @@
import com.android.services.telephony.rcs.RcsFeatureController;
import com.android.services.telephony.rcs.SipTransportController;
import com.android.services.telephony.rcs.TelephonyRcsService;
-import com.android.services.telephony.rcs.UserCapabilityExchangeImpl;
+import com.android.services.telephony.rcs.UceControllerManager;
import java.util.List;
@@ -203,40 +204,6 @@
}
}
- @Override
- public void registerUcePublishStateCallback(int subId, IRcsUcePublishStateCallback c) {
- enforceReadPrivilegedPermission("registerUcePublishStateCallback");
- final long token = Binder.clearCallingIdentity();
- try {
- UserCapabilityExchangeImpl uce = getRcsFeatureController(subId).getFeature(
- UserCapabilityExchangeImpl.class);
- if (uce == null) {
- throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
- "This subscription does not support UCE.");
- }
- uce.registerPublishStateCallback(c);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
- @Override
- public void unregisterUcePublishStateCallback(int subId, IRcsUcePublishStateCallback c) {
- enforceReadPrivilegedPermission("unregisterUcePublishStateCallback");
- final long token = Binder.clearCallingIdentity();
- try {
- UserCapabilityExchangeImpl uce = getRcsFeatureController(subId).getFeature(
- UserCapabilityExchangeImpl.class);
- if (uce == null) {
- throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
- "This subscription does not support UCE.");
- }
- uce.unregisterUcePublishStateCallback(c);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
/**
* Query for the capability of an IMS RCS service
*
@@ -296,13 +263,15 @@
}
final long token = Binder.clearCallingIdentity();
try {
- UserCapabilityExchangeImpl uce = getRcsFeatureController(subId).getFeature(
- UserCapabilityExchangeImpl.class);
- if (uce == null) {
+ UceControllerManager uceCtrlManager = getRcsFeatureController(subId).getFeature(
+ UceControllerManager.class);
+ if (uceCtrlManager == null) {
throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
"This subscription does not support UCE.");
}
- uce.requestCapabilities(contactNumbers, c);
+ uceCtrlManager.requestCapabilities(contactNumbers, c);
+ } catch (ImsException e) {
+ throw new ServiceSpecificException(e.getCode(), e.getMessage());
} finally {
Binder.restoreCallingIdentity(token);
}
@@ -316,21 +285,72 @@
throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
"The user has not enabled UCE for this subscription.");
}
- // TODO: Implement this method
- }
-
- @Override
- public int getUcePublishState(int subId) {
- enforceReadPrivilegedPermission("getUcePublishState");
final long token = Binder.clearCallingIdentity();
try {
- UserCapabilityExchangeImpl uce = getRcsFeatureController(subId).getFeature(
- UserCapabilityExchangeImpl.class);
- if (uce == null) {
+ UceControllerManager uceCtrlManager = getRcsFeatureController(subId).getFeature(
+ UceControllerManager.class);
+ if (uceCtrlManager == null) {
throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
"This subscription does not support UCE.");
}
- return uce.getUcePublishState();
+ uceCtrlManager.requestNetworkAvailability(contactNumber, c);
+ } catch (ImsException e) {
+ throw new ServiceSpecificException(e.getCode(), e.getMessage());
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public @PublishState int getUcePublishState(int subId) {
+ enforceReadPrivilegedPermission("getUcePublishState");
+ final long token = Binder.clearCallingIdentity();
+ try {
+ UceControllerManager uceCtrlManager = getRcsFeatureController(subId).getFeature(
+ UceControllerManager.class);
+ if (uceCtrlManager == null) {
+ throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
+ "This subscription does not support UCE.");
+ }
+ return uceCtrlManager.getUcePublishState();
+ } catch (ImsException e) {
+ throw new ServiceSpecificException(e.getCode(), e.getMessage());
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public void registerUcePublishStateCallback(int subId, IRcsUcePublishStateCallback c) {
+ enforceReadPrivilegedPermission("registerUcePublishStateCallback");
+ final long token = Binder.clearCallingIdentity();
+ try {
+ UceControllerManager uceCtrlManager = getRcsFeatureController(subId).getFeature(
+ UceControllerManager.class);
+ if (uceCtrlManager == null) {
+ throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
+ "This subscription does not support UCE.");
+ }
+ uceCtrlManager.registerPublishStateCallback(c);
+ } catch (ImsException e) {
+ throw new ServiceSpecificException(e.getCode(), e.getMessage());
+ } finally {
+ Binder.restoreCallingIdentity(token);
+ }
+ }
+
+ @Override
+ public void unregisterUcePublishStateCallback(int subId, IRcsUcePublishStateCallback c) {
+ enforceReadPrivilegedPermission("unregisterUcePublishStateCallback");
+ final long token = Binder.clearCallingIdentity();
+ try {
+ UceControllerManager uceCtrlManager = getRcsFeatureController(subId).getFeature(
+ UceControllerManager.class);
+ if (uceCtrlManager == null) {
+ throw new ServiceSpecificException(ImsException.CODE_ERROR_UNSUPPORTED_OPERATION,
+ "This subscription does not support UCE.");
+ }
+ uceCtrlManager.unregisterPublishStateCallback(c);
} finally {
Binder.restoreCallingIdentity(token);
}
diff --git a/src/com/android/services/telephony/rcs/TelephonyRcsService.java b/src/com/android/services/telephony/rcs/TelephonyRcsService.java
index 79170af..941a6a8 100644
--- a/src/com/android/services/telephony/rcs/TelephonyRcsService.java
+++ b/src/com/android/services/telephony/rcs/TelephonyRcsService.java
@@ -47,21 +47,19 @@
private static final String LOG_TAG = "TelephonyRcsService";
/**
- * Used to inject RcsFeatureController and UserCapabilityExchangeImpl instances for testing.
+ * Used to inject RcsFeatureController and UceController instances for testing.
*/
@VisibleForTesting
public interface FeatureFactory {
/**
- * @return an {@link RcsFeatureController} assoicated with the slot specified.
+ * @return an {@link RcsFeatureController} associated with the slot specified.
*/
RcsFeatureController createController(Context context, int slotId);
/**
- * @return an instance of {@link UserCapabilityExchangeImpl} associated with the slot
- * specified.
+ * @return an instance of {@link UceControllerManager} associated with the slot specified.
*/
- UserCapabilityExchangeImpl createUserCapabilityExchange(Context context, int slotId,
- int subId);
+ UceControllerManager createUceControllerManager(Context context, int slotId, int subId);
/**
* @return an instance of {@link SipTransportController} for the slot and subscription
@@ -77,9 +75,9 @@
}
@Override
- public UserCapabilityExchangeImpl createUserCapabilityExchange(Context context, int slotId,
+ public UceControllerManager createUceControllerManager(Context context, int slotId,
int subId) {
- return new UserCapabilityExchangeImpl(context, slotId, subId);
+ return new UceControllerManager(context, slotId, subId);
}
@Override
@@ -237,13 +235,13 @@
private void updateSupportedFeatures(RcsFeatureController c, int slotId, int subId) {
if (doesSubscriptionSupportPresence(subId)) {
- if (c.getFeature(UserCapabilityExchangeImpl.class) == null) {
- c.addFeature(mFeatureFactory.createUserCapabilityExchange(mContext, slotId, subId),
- UserCapabilityExchangeImpl.class);
+ if (c.getFeature(UceControllerManager.class) == null) {
+ c.addFeature(mFeatureFactory.createUceControllerManager(mContext, slotId, subId),
+ UceControllerManager.class);
}
} else {
- if (c.getFeature(UserCapabilityExchangeImpl.class) != null) {
- c.removeFeature(UserCapabilityExchangeImpl.class);
+ if (c.getFeature(UceControllerManager.class) != null) {
+ c.removeFeature(UceControllerManager.class);
}
}
diff --git a/src/com/android/services/telephony/rcs/UceControllerManager.java b/src/com/android/services/telephony/rcs/UceControllerManager.java
new file mode 100644
index 0000000..db8c933
--- /dev/null
+++ b/src/com/android/services/telephony/rcs/UceControllerManager.java
@@ -0,0 +1,234 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.services.telephony.rcs;
+
+import android.content.Context;
+import android.net.Uri;
+import android.telephony.ims.ImsException;
+import android.telephony.ims.RcsUceAdapter;
+import android.telephony.ims.RcsUceAdapter.PublishState;
+import android.telephony.ims.aidl.IRcsUceControllerCallback;
+import android.telephony.ims.aidl.IRcsUcePublishStateCallback;
+import android.util.Log;
+
+import com.android.ims.RcsFeatureManager;
+import com.android.ims.rcs.uce.UceController;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+/**
+ * Responsible for managing the creation and destruction of UceController. It also received the
+ * requests from {@link com.android.phone.ImsRcsController} and pass these requests to
+ * {@link UceController}
+ */
+public class UceControllerManager implements RcsFeatureController.Feature {
+
+ private static final String LOG_TAG = "UceControllerManager";
+
+ private final int mSlotId;
+ private final Context mContext;
+ private final ExecutorService mExecutorService;
+
+ private volatile UceController mUceController;
+
+ public UceControllerManager(Context context, int slotId, int subId) {
+ Log.d(LOG_TAG, "create: slotId=" + slotId + ", subId=" + subId);
+
+ mSlotId = slotId;
+ mContext = context;
+ mExecutorService = Executors.newSingleThreadExecutor();
+ mUceController = new UceController(mContext, subId);
+ }
+
+ /**
+ * Constructor to inject dependencies for testing.
+ */
+ @VisibleForTesting
+ public UceControllerManager(Context context, int slotId, int subId, ExecutorService executor) {
+ mSlotId = slotId;
+ mContext = context;
+ mExecutorService = executor;
+ mUceController = new UceController(mContext, subId);
+ }
+
+ @Override
+ public void onRcsConnected(RcsFeatureManager manager) {
+ mExecutorService.submit(() -> mUceController.onRcsConnected(manager));
+ }
+
+ @Override
+ public void onRcsDisconnected() {
+ mExecutorService.submit(() -> mUceController.onRcsDisconnected());
+ }
+
+ @Override
+ public void onDestroy() {
+ Log.d(LOG_TAG, "onDestroy");
+ mExecutorService.submit(() -> mUceController.onDestroy());
+ // When the shutdown is called, it will refuse any new tasks and let existing tasks finish.
+ mExecutorService.shutdown();
+ }
+
+ /**
+ * This method will be called when either the subscription ID associated with the slot has
+ * changed or the carrier configuration associated with the same subId has changed.
+ */
+ @Override
+ public void onAssociatedSubscriptionUpdated(int subId) {
+ mExecutorService.submit(() -> {
+ Log.i(LOG_TAG, "onAssociatedSubscriptionUpdated: slotId=" + mSlotId
+ + ", subId=" + subId);
+
+ // Destroy existing UceController and create a new one.
+ mUceController.onDestroy();
+ mUceController = new UceController(mContext, subId);
+ });
+ }
+
+ @VisibleForTesting
+ public void setUceController(UceController uceController) {
+ mUceController = uceController;
+ }
+
+ /**
+ * Request the capabilities for contacts.
+ *
+ * @param contactNumbers A list of numbers that the capabilities are being requested for.
+ * @param c A callback for when the request for capabilities completes.
+ * @throws ImsException if the ImsService connected to this controller is currently down.
+ */
+ public void requestCapabilities(List<Uri> contactNumbers, IRcsUceControllerCallback c)
+ throws ImsException {
+ Future future = mExecutorService.submit(() -> {
+ checkUceControllerState();
+ mUceController.requestCapabilities(contactNumbers, c);
+ return true;
+ });
+
+ try {
+ future.get();
+ } catch (ExecutionException | InterruptedException e) {
+ Log.w(LOG_TAG, "requestCapabilities: " + e);
+ Throwable cause = e.getCause();
+ if (cause instanceof ImsException) {
+ throw (ImsException) cause;
+ }
+ }
+ }
+
+ /**
+ * Request the capabilities for the given contact.
+ * @param contactNumber The contact of the capabilities are being requested for.
+ * @param c A callback for when the request for capabilities completes.
+ * @throws ImsException if the ImsService connected to this controller is currently down.
+ */
+ public void requestNetworkAvailability(Uri contactNumber, IRcsUceControllerCallback c)
+ throws ImsException {
+ Future future = mExecutorService.submit(() -> {
+ checkUceControllerState();
+ mUceController.requestAvailability(contactNumber, c);
+ return true;
+ });
+
+ try {
+ future.get();
+ } catch (ExecutionException | InterruptedException e) {
+ Log.w(LOG_TAG, "requestNetworkAvailability exception: " + e);
+ Throwable cause = e.getCause();
+ if (cause instanceof ImsException) {
+ throw (ImsException) cause;
+ }
+ }
+ }
+
+ /**
+ * Get the UCE publish state.
+ *
+ * @throws ImsException if the ImsService connected to this controller is currently down.
+ */
+ public @PublishState int getUcePublishState() throws ImsException {
+ Future future = mExecutorService.submit(() -> {
+ checkUceControllerState();
+ return mUceController.getUcePublishState();
+ });
+
+ try {
+ return (Integer) future.get();
+ } catch (ExecutionException | InterruptedException e) {
+ Log.w(LOG_TAG, "requestNetworkAvailability exception: " + e);
+ Throwable cause = e.getCause();
+ if (cause instanceof ImsException) {
+ throw (ImsException) cause;
+ }
+ return RcsUceAdapter.PUBLISH_STATE_OTHER_ERROR;
+ }
+ }
+
+ /**
+ * Register the Publish state changed callback.
+ *
+ * @throws ImsException if the ImsService connected to this controller is currently down.
+ */
+ public void registerPublishStateCallback(IRcsUcePublishStateCallback c) throws ImsException {
+ Future future = mExecutorService.submit(() -> {
+ checkUceControllerState();
+ mUceController.registerPublishStateCallback(c);
+ return true;
+ });
+
+ try {
+ future.get();
+ } catch (ExecutionException | InterruptedException e) {
+ Log.w(LOG_TAG, "registerPublishStateCallback exception: " + e);
+ Throwable cause = e.getCause();
+ if (cause instanceof ImsException) {
+ throw (ImsException) cause;
+ }
+ }
+ }
+
+ /**
+ * Unregister the existing publish state changed callback.
+ */
+ public void unregisterPublishStateCallback(IRcsUcePublishStateCallback c) {
+ Future future = mExecutorService.submit(() -> {
+ if (checkUceControllerState()) {
+ mUceController.unregisterPublishStateCallback(c);
+ }
+ return true;
+ });
+
+ try {
+ future.get();
+ } catch (ExecutionException | InterruptedException e) {
+ Log.w(LOG_TAG, "unregisterPublishStateCallback exception: " + e);
+ }
+ }
+
+ private boolean checkUceControllerState() throws ImsException {
+ if (mUceController == null || mUceController.isUnavailable()) {
+ throw new ImsException("UCE controller is unavailable",
+ ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
+ }
+ return true;
+ }
+}
diff --git a/src/com/android/services/telephony/rcs/UserCapabilityExchangeImpl.java b/src/com/android/services/telephony/rcs/UserCapabilityExchangeImpl.java
deleted file mode 100644
index 138d2d0..0000000
--- a/src/com/android/services/telephony/rcs/UserCapabilityExchangeImpl.java
+++ /dev/null
@@ -1,1063 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.services.telephony.rcs;
-
-import android.content.BroadcastReceiver;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.database.ContentObserver;
-import android.net.Uri;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.Looper;
-import android.os.Message;
-import android.os.PersistableBundle;
-import android.os.RemoteCallbackList;
-import android.os.RemoteException;
-import android.provider.Settings;
-import android.provider.Telephony;
-import android.telecom.TelecomManager;
-import android.telephony.AccessNetworkConstants;
-import android.telephony.CarrierConfigManager;
-import android.telephony.SubscriptionManager;
-import android.telephony.ims.ImsException;
-import android.telephony.ims.ImsManager;
-import android.telephony.ims.ImsMmTelManager;
-import android.telephony.ims.ImsReasonInfo;
-import android.telephony.ims.ProvisioningManager;
-import android.telephony.ims.RcsContactUceCapability;
-import android.telephony.ims.RcsUceAdapter;
-import android.telephony.ims.RegistrationManager;
-import android.telephony.ims.aidl.IRcsUceControllerCallback;
-import android.telephony.ims.aidl.IRcsUcePublishStateCallback;
-import android.telephony.ims.feature.MmTelFeature;
-import android.telephony.ims.stub.RcsCapabilityExchange;
-import android.telephony.ims.stub.RcsPresenceExchangeImplBase;
-import android.util.Log;
-
-import com.android.ims.RcsFeatureManager;
-import com.android.ims.RcsFeatureManager.RcsFeatureCallbacks;
-import com.android.ims.ResultCode;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.phone.R;
-import com.android.service.ims.presence.ContactCapabilityResponse;
-import com.android.service.ims.presence.PresenceBase;
-import com.android.service.ims.presence.PresencePublication;
-import com.android.service.ims.presence.PresencePublisher;
-import com.android.service.ims.presence.PresenceSubscriber;
-import com.android.service.ims.presence.SubscribePublisher;
-
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.stream.Collectors;
-
-/**
- * Implements User Capability Exchange using Presence.
- */
-public class UserCapabilityExchangeImpl implements RcsFeatureController.Feature, SubscribePublisher,
- PresencePublisher {
-
- private static final String LOG_TAG = "RcsUceImpl";
-
- private final int mSlotId;
- private volatile int mSubId;
- private volatile boolean mImsContentChangedCallbackRegistered = false;
- // The result of requesting publish
- private volatile int mPublishState = PresenceBase.PUBLISH_STATE_NOT_PUBLISHED;
- // The network type which IMS registers on
- private volatile int mNetworkRegistrationType = AccessNetworkConstants.TRANSPORT_TYPE_INVALID;
- // The MMTel capabilities of this subscription Id
- private MmTelFeature.MmTelCapabilities mMmTelCapabilities;
- private final Object mCapabilitiesLock = new Object();
-
- private final Context mContext;
- private final UceImplHandler mUceImplHandler;
- private RcsFeatureManager mRcsFeatureManager;
- private final PresencePublication mPresencePublication;
- private final PresenceSubscriber mPresenceSubscriber;
-
- // The task Ids of updating capabilities
- private final Set<Integer> mRequestingPublishTaskIds = new HashSet<>();
-
- // The callbacks to notify publish state changed.
- private final RemoteCallbackList<IRcsUcePublishStateCallback> mPublishStateCallbacks;
-
- // The task Ids of pending availability request.
- private final Set<Integer> mPendingAvailabilityRequests = new HashSet<>();
-
- private final ConcurrentHashMap<Integer, IRcsUceControllerCallback> mPendingCapabilityRequests =
- new ConcurrentHashMap<>();
-
- UserCapabilityExchangeImpl(Context context, int slotId, int subId) {
- mSlotId = slotId;
- mSubId = subId;
- logi("created");
-
- mContext = context;
- mPublishStateCallbacks = new RemoteCallbackList<>();
-
- HandlerThread handlerThread = new HandlerThread("UceImplHandlerThread");
- handlerThread.start();
- mUceImplHandler = new UceImplHandler(this, handlerThread.getLooper());
-
- String[] volteError = context.getResources().getStringArray(
- R.array.config_volte_provision_error_on_publish_response);
- String[] rcsError = context.getResources().getStringArray(
- R.array.config_rcs_provision_error_on_publish_response);
-
- // Initialize PresencePublication
- mPresencePublication = new PresencePublication(null /*PresencePublisher*/, context,
- volteError, rcsError);
- // Initialize PresenceSubscriber
- mPresenceSubscriber = new PresenceSubscriber(null /*SubscribePublisher*/, context,
- volteError, rcsError);
-
- onAssociatedSubscriptionUpdated(mSubId);
- registerReceivers();
- }
-
- @VisibleForTesting
- UserCapabilityExchangeImpl(Context context, int slotId, int subId, Looper looper,
- PresencePublication presencePublication, PresenceSubscriber presenceSubscriber,
- RemoteCallbackList<IRcsUcePublishStateCallback> publishStateCallbacks) {
- mSlotId = slotId;
- mSubId = subId;
- mContext = context;
- mPublishStateCallbacks = publishStateCallbacks;
- mUceImplHandler = new UceImplHandler(this, looper);
- mPresencePublication = presencePublication;
- mPresenceSubscriber = presenceSubscriber;
- onAssociatedSubscriptionUpdated(mSubId);
- registerReceivers();
- }
-
- // Runs on main thread.
- @Override
- public void onRcsConnected(RcsFeatureManager rcsFeatureManager) {
- logi("onRcsConnected");
- mRcsFeatureManager = rcsFeatureManager;
- mRcsFeatureManager.addFeatureListenerCallback(mRcsFeatureCallback);
-
- mPresencePublication.updatePresencePublisher(this);
- mPresenceSubscriber.updatePresenceSubscriber(this);
- }
-
- // Runs on main thread.
- @Override
- public void onRcsDisconnected() {
- logi("onRcsDisconnected");
- mPresencePublication.removePresencePublisher();
- mPresenceSubscriber.removePresenceSubscriber();
-
- if (mRcsFeatureManager != null) {
- mRcsFeatureManager.releaseConnection();
- mRcsFeatureManager = null;
- }
- }
-
- // Runs on main thread.
- @Override
- public void onAssociatedSubscriptionUpdated(int subId) {
- logi("onAssociatedSubscriptionUpdated: new subId=" + subId);
-
- // Listen to the IMS content changed with new subId.
- mUceImplHandler.registerImsContentChangedReceiver(subId);
-
- mSubId = subId;
- mPresencePublication.handleAssociatedSubscriptionChanged(subId);
- mPresenceSubscriber.handleAssociatedSubscriptionChanged(subId);
- }
-
- /**
- * Should be called before destroying this instance.
- * This instance is not usable after this method is called.
- */
- // Called on main thread.
- public void onDestroy() {
- logi("onDestroy");
- mUceImplHandler.getLooper().quit();
- unregisterReceivers();
- unregisterImsProvisionCallback(mSubId);
- onRcsDisconnected();
- }
-
- /**
- * @return the UCE Publish state.
- */
- // May happen on a Binder thread, PresencePublication locks to get result.
- public int getUcePublishState() {
- int publishState = mPresencePublication.getPublishState();
- return toUcePublishState(publishState);
- }
-
- @VisibleForTesting
- public UceImplHandler getHandler() {
- return mUceImplHandler;
- }
-
- /**
- * Register receiver to receive UCE publish state changed.
- */
- public void registerPublishStateCallback(IRcsUcePublishStateCallback c) {
- synchronized (mPublishStateCallbacks) {
- mPublishStateCallbacks.register(c);
- }
- }
-
- /**
- * Unregister UCE publish state callback.
- */
- public void unregisterUcePublishStateCallback(IRcsUcePublishStateCallback c) {
- synchronized (mPublishStateCallbacks) {
- mPublishStateCallbacks.unregister(c);
- }
- }
-
- private void clearPublishStateCallbacks() {
- synchronized (mPublishStateCallbacks) {
- logi("clearPublishStateCallbacks");
- final int lastIndex = mPublishStateCallbacks.getRegisteredCallbackCount() - 1;
- for (int index = lastIndex; index >= 0; index--) {
- IRcsUcePublishStateCallback callback =
- mPublishStateCallbacks.getRegisteredCallbackItem(index);
- mPublishStateCallbacks.unregister(callback);
- }
- }
- }
-
- private void notifyPublishStateChanged(@PresenceBase.PresencePublishState int state) {
- int result = toUcePublishState(state);
- synchronized (mPublishStateCallbacks) {
- mPublishStateCallbacks.broadcast(c -> {
- try {
- c.onPublishStateChanged(result);
- } catch (RemoteException e) {
- logw("notifyPublishStateChanged error: " + e);
- }
- });
- }
- }
-
- /**
- * Perform a capabilities request and call {@link IRcsUceControllerCallback} with the result.
- */
- // May happen on a Binder thread, PresenceSubscriber locks when requesting Capabilities.
- public void requestCapabilities(List<Uri> contactNumbers, IRcsUceControllerCallback c) {
- List<String> numbers = contactNumbers.stream()
- .map(UserCapabilityExchangeImpl::getNumberFromUri).collect(Collectors.toList());
- int taskId = mPresenceSubscriber.requestCapability(numbers,
- new ContactCapabilityResponse() {
- @Override
- public void onSuccess(int reqId) {
- logi("onSuccess called for reqId:" + reqId);
- }
-
- @Override
- public void onError(int reqId, int resultCode) {
- IRcsUceControllerCallback c = mPendingCapabilityRequests.remove(reqId);
- try {
- if (c != null) {
- c.onError(toUceError(resultCode));
- } else {
- logw("onError called for unknown reqId:" + reqId);
- }
- } catch (RemoteException e) {
- logi("Calling back to dead service");
- }
- }
-
- @Override
- public void onFinish(int reqId) {
- logi("onFinish called for reqId:" + reqId);
- }
-
- @Override
- public void onTimeout(int reqId) {
- IRcsUceControllerCallback c = mPendingCapabilityRequests.remove(reqId);
- try {
- if (c != null) {
- c.onError(RcsUceAdapter.ERROR_REQUEST_TIMEOUT);
- } else {
- logw("onTimeout called for unknown reqId:" + reqId);
- }
- } catch (RemoteException e) {
- logi("Calling back to dead service");
- }
- }
-
- @Override
- public void onCapabilitiesUpdated(int reqId,
- List<RcsContactUceCapability> contactCapabilities,
- boolean updateLastTimestamp) {
- IRcsUceControllerCallback c = mPendingCapabilityRequests.remove(reqId);
- try {
- if (c != null) {
- c.onCapabilitiesReceived(contactCapabilities);
- } else {
- logw("onCapabilitiesUpdated, unknown reqId:" + reqId);
- }
- } catch (RemoteException e) {
- logw("onCapabilitiesUpdated on dead service");
- }
- }
- });
- if (taskId < 0) {
- try {
- c.onError(toUceError(taskId));
- } catch (RemoteException e) {
- logi("Calling back to dead service");
- }
- return;
- }
- mPendingCapabilityRequests.put(taskId, c);
- }
-
- @Override
- public int requestCapability(String[] formattedContacts, int taskId) {
- if (formattedContacts == null || formattedContacts.length == 0) {
- logw("requestCapability error: contacts is null.");
- return ResultCode.SUBSCRIBE_INVALID_PARAM;
- }
- if (mRcsFeatureManager == null) {
- logw("requestCapability error: RcsFeatureManager is null.");
- return ResultCode.ERROR_SERVICE_NOT_AVAILABLE;
- }
-
- logi("requestCapability: taskId=" + taskId);
-
- try {
- List<Uri> contactList = Arrays.stream(formattedContacts)
- .map(Uri::parse).collect(Collectors.toList());
- mRcsFeatureManager.requestCapabilities(contactList, taskId);
- } catch (Exception e) {
- logw("requestCapability error: " + e.getMessage());
- return ResultCode.ERROR_SERVICE_NOT_AVAILABLE;
- }
- return ResultCode.SUCCESS;
- }
-
- @Override
- public int requestAvailability(String formattedContact, int taskId) {
- if (formattedContact == null || formattedContact.isEmpty()) {
- logw("requestAvailability error: contact is null.");
- return ResultCode.SUBSCRIBE_INVALID_PARAM;
- }
- if (mRcsFeatureManager == null) {
- logw("requestAvailability error: RcsFeatureManager is null.");
- return ResultCode.ERROR_SERVICE_NOT_AVAILABLE;
- }
-
- logi("requestAvailability: taskId=" + taskId);
- addRequestingAvailabilityTaskId(taskId);
-
- try {
- Uri contactUri = Uri.parse(formattedContact);
- List<Uri> contactUris = new ArrayList<>(Arrays.asList(contactUri));
- mRcsFeatureManager.requestCapabilities(contactUris, taskId);
- } catch (Exception e) {
- logw("requestAvailability error: " + e.getMessage());
- removeRequestingAvailabilityTaskId(taskId);
- return ResultCode.ERROR_SERVICE_NOT_AVAILABLE;
- }
- return ResultCode.SUCCESS;
- }
-
- @Override
- public int getStackStatusForCapabilityRequest() {
- if (mRcsFeatureManager == null) {
- logw("Check Stack status: Error! RcsFeatureManager is null.");
- return ResultCode.ERROR_SERVICE_NOT_AVAILABLE;
- }
-
- if (!isCapabilityDiscoveryEnabled(mSubId)) {
- logw("Check Stack status: Error! capability discovery not enabled");
- return ResultCode.ERROR_SERVICE_NOT_ENABLED;
- }
-
- if (!isEabProvisioned(mContext, mSubId)) {
- logw("Check Stack status: Error! EAB provisioning disabled.");
- return ResultCode.ERROR_SERVICE_NOT_ENABLED;
- }
-
- if (getPublisherState() != PresenceBase.PUBLISH_STATE_200_OK) {
- logw("Check Stack status: Error! publish state " + getPublisherState());
- return ResultCode.ERROR_SERVICE_NOT_PUBLISHED;
- }
- return ResultCode.SUCCESS;
- }
-
- /**
- * The feature callback is to receive the request and update from RcsPresExchangeImplBase
- */
- @VisibleForTesting
- public RcsFeatureCallbacks mRcsFeatureCallback = new RcsFeatureCallbacks() {
- public void onCommandUpdate(int commandCode, int operationToken) {
- logi("onCommandUpdate: code=" + commandCode + ", token=" + operationToken);
- if (isPublishRequestExisted(operationToken)) {
- onCommandUpdateForPublishRequest(commandCode, operationToken);
- } else if (isCapabilityRequestExisted(operationToken)) {
- onCommandUpdateForCapabilityRequest(commandCode, operationToken);
- } else if (isAvailabilityRequestExisted(operationToken)) {
- onCommandUpdateForAvailabilityRequest(commandCode, operationToken);
- } else {
- logw("onCommandUpdate: invalid token " + operationToken);
- }
- }
-
- /** See {@link RcsPresenceExchangeImplBase#onNetworkResponse(int, String, int)} */
- public void onNetworkResponse(int responseCode, String reason, int operationToken) {
- logi("onNetworkResponse: code=" + responseCode + ", reason=" + reason
- + ", operationToken=" + operationToken);
- if (isPublishRequestExisted(operationToken)) {
- onNetworkResponseForPublishRequest(responseCode, reason, operationToken);
- } else if (isCapabilityRequestExisted(operationToken)) {
- onNetworkResponseForCapabilityRequest(responseCode, reason, operationToken);
- } else if (isAvailabilityRequestExisted(operationToken)) {
- onNetworkResponseForAvailabilityRequest(responseCode, reason, operationToken);
- } else {
- logw("onNetworkResponse: invalid token " + operationToken);
- }
- }
-
- /** See {@link RcsPresenceExchangeImplBase#onCapabilityRequestResponse(List, int)} */
- public void onCapabilityRequestResponsePresence(List<RcsContactUceCapability> infos,
- int operationToken) {
- if (isAvailabilityRequestExisted(operationToken)) {
- handleAvailabilityReqResponse(infos, operationToken);
- } else if (isCapabilityRequestExisted(operationToken)) {
- handleCapabilityReqResponse(infos, operationToken);
- } else {
- logw("capability request response: invalid token " + operationToken);
- }
- }
-
- /** See {@link RcsPresenceExchangeImplBase#onNotifyUpdateCapabilites(int)} */
- public void onNotifyUpdateCapabilities(int publishTriggerType) {
- logi("onNotifyUpdateCapabilities: type=" + publishTriggerType);
- mUceImplHandler.notifyUpdateCapabilities(publishTriggerType);
- }
-
- /** See {@link RcsPresenceExchangeImplBase#onUnpublish()} */
- public void onUnpublish() {
- logi("onUnpublish");
- mUceImplHandler.unpublish();
- }
- };
-
- private static class UceImplHandler extends Handler {
- private static final int EVENT_REGISTER_IMS_CHANGED_RECEIVER = 1;
- private static final int EVENT_NOTIFY_UPDATE_CAPABILITIES = 2;
- private static final int EVENT_UNPUBLISH = 3;
-
- private static final int REGISTER_IMS_CHANGED_DELAY = 10000; //10 seconds
-
- private final WeakReference<UserCapabilityExchangeImpl> mUceImplRef;
-
- UceImplHandler(UserCapabilityExchangeImpl uceImpl, Looper looper) {
- super(looper);
- mUceImplRef = new WeakReference(uceImpl);
- }
-
- @Override
- public void handleMessage(Message msg) {
- UserCapabilityExchangeImpl uceImpl = mUceImplRef.get();
- if (uceImpl == null) {
- return;
- }
- switch (msg.what) {
- case EVENT_REGISTER_IMS_CHANGED_RECEIVER:
- int subId = msg.arg1;
- uceImpl.registerImsContentChangedReceiverInternal(subId);
- break;
- case EVENT_NOTIFY_UPDATE_CAPABILITIES:
- int publishTriggerType = msg.arg1;
- uceImpl.onNotifyUpdateCapabilities(publishTriggerType);
- break;
- case EVENT_UNPUBLISH:
- uceImpl.onUnPublish();
- break;
- default:
- Log.w(LOG_TAG, "handleMessage: error=" + msg.what);
- break;
- }
- }
-
- private void retryRegisteringImsContentChangedReceiver(int subId) {
- sendRegisteringImsContentChangedMessage(subId, REGISTER_IMS_CHANGED_DELAY);
- }
-
- private void registerImsContentChangedReceiver(int subId) {
- sendRegisteringImsContentChangedMessage(subId, 0);
- }
-
- private void sendRegisteringImsContentChangedMessage(int subId, int delay) {
- if (subId <= SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
- return;
- }
- removeRegisteringImsContentChangedReceiver();
- Message message = obtainMessage(EVENT_REGISTER_IMS_CHANGED_RECEIVER);
- message.arg1 = subId;
- sendMessageDelayed(message, delay);
- }
-
- private void removeRegisteringImsContentChangedReceiver() {
- removeMessages(EVENT_REGISTER_IMS_CHANGED_RECEIVER);
- }
-
- private void notifyUpdateCapabilities(int publishTriggerType) {
- Message message = obtainMessage(EVENT_NOTIFY_UPDATE_CAPABILITIES);
- message.arg1 = publishTriggerType;
- sendMessage(message);
- }
-
- private void unpublish() {
- sendEmptyMessage(EVENT_UNPUBLISH);
- }
- }
-
- private void onNotifyUpdateCapabilities(int publishTriggerType) {
- mPresencePublication.onStackPublishRequested(publishTriggerType);
- }
-
- private void onUnPublish() {
- mPresencePublication.setPublishState(PresenceBase.PUBLISH_STATE_NOT_PUBLISHED);
- }
-
- @Override
- public @PresenceBase.PresencePublishState int getPublisherState() {
- return mPublishState;
- }
-
- @Override
- public int requestPublication(RcsContactUceCapability capabilities, String contactUri,
- int taskId) {
- if (mRcsFeatureManager == null) {
- logw("requestPublication error: RcsFeatureManager is null.");
- return ResultCode.ERROR_SERVICE_NOT_AVAILABLE;
- }
-
- logi("requestPublication: taskId=" + taskId);
- addPublishRequestTaskId(taskId);
-
- try {
- mRcsFeatureManager.requestPublication(capabilities, taskId);
- } catch (Exception ex) {
- logw("requestPublication error: " + ex.getMessage());
- removePublishRequestTaskId(taskId);
- return ResultCode.PUBLISH_GENERIC_FAILURE;
- }
- return ResultCode.SUCCESS;
- }
-
- /*
- * Handle the callback method RcsFeatureCallbacks#onCommandUpdate(int, int)
- */
- private void onCommandUpdateForPublishRequest(int commandCode, int operationToken) {
- if (!isPublishRequestExisted(operationToken)) {
- return;
- }
- int resultCode = ResultCode.SUCCESS;
- if (commandCode != RcsCapabilityExchange.COMMAND_CODE_SUCCESS) {
- logw("onCommandUpdateForPublishRequest failed! taskId=" + operationToken
- + ", code=" + commandCode);
- removePublishRequestTaskId(operationToken);
- resultCode = ResultCode.PUBLISH_GENERIC_FAILURE;
- }
- mPresencePublication.onCommandStatusUpdated(operationToken, operationToken, resultCode);
- }
-
- private void onCommandUpdateForCapabilityRequest(int commandCode, int operationToken) {
- if (!isCapabilityRequestExisted(operationToken)) {
- return;
- }
- int resultCode = ResultCode.SUCCESS;
- if (commandCode != RcsCapabilityExchange.COMMAND_CODE_SUCCESS) {
- logw("onCommandUpdateForCapabilityRequest failed! taskId=" + operationToken
- + ", code=" + commandCode);
- mPendingCapabilityRequests.remove(operationToken);
- resultCode = ResultCode.PUBLISH_GENERIC_FAILURE;
- }
- mPresenceSubscriber.onCommandStatusUpdated(operationToken, operationToken, resultCode);
- }
-
- private void onCommandUpdateForAvailabilityRequest(int commandCode, int operationToken) {
- if (!isAvailabilityRequestExisted(operationToken)) {
- return;
- }
- int resultCode = ResultCode.SUCCESS;
- if (commandCode != RcsCapabilityExchange.COMMAND_CODE_SUCCESS) {
- logw("onCommandUpdateForAvailabilityRequest failed! taskId=" + operationToken
- + ", code=" + commandCode);
- removeRequestingAvailabilityTaskId(operationToken);
- resultCode = ResultCode.PUBLISH_GENERIC_FAILURE;
- }
- mPresenceSubscriber.onCommandStatusUpdated(operationToken, operationToken, resultCode);
- }
-
- /*
- * Handle the callback method RcsFeatureCallbacks#onNetworkResponse(int, String, int)
- */
- private void onNetworkResponseForPublishRequest(int responseCode, String reason,
- int operationToken) {
- if (!isPublishRequestExisted(operationToken)) {
- return;
- }
- removePublishRequestTaskId(operationToken);
- mPresencePublication.onSipResponse(operationToken, responseCode, reason);
- }
-
- private void onNetworkResponseForCapabilityRequest(int responseCode, String reason,
- int operationToken) {
- if (!isCapabilityRequestExisted(operationToken)) {
- return;
- }
- mPresenceSubscriber.onSipResponse(operationToken, responseCode, reason);
- }
-
- private void onNetworkResponseForAvailabilityRequest(int responseCode, String reason,
- int operationToken) {
- if (!isAvailabilityRequestExisted(operationToken)) {
- return;
- }
- removeRequestingAvailabilityTaskId(operationToken);
- mPresenceSubscriber.onSipResponse(operationToken, responseCode, reason);
- }
-
- private void handleAvailabilityReqResponse(List<RcsContactUceCapability> infos, int token) {
- try {
- if (infos == null || infos.isEmpty()) {
- logw("handle availability request response: infos is null " + token);
- return;
- }
- logi("handleAvailabilityReqResponse: token=" + token);
- mPresenceSubscriber.updatePresence(infos.get(0));
- } finally {
- removeRequestingAvailabilityTaskId(token);
- }
- }
-
- private void handleCapabilityReqResponse(List<RcsContactUceCapability> infos, int token) {
- if (infos == null) {
- logw("handleCapabilityReqResponse: infos is null " + token);
- mPendingCapabilityRequests.remove(token);
- return;
- }
- logi("handleCapabilityReqResponse: token=" + token);
- mPresenceSubscriber.updatePresences(token, infos, true, null);
- }
-
- @Override
- public void updatePublisherState(@PresenceBase.PresencePublishState int publishState) {
- logi("updatePublisherState: from " + mPublishState + " to " + publishState);
- mPublishState = publishState;
- notifyPublishStateChanged(publishState);
- }
-
- private void addPublishRequestTaskId(int taskId) {
- synchronized (mRequestingPublishTaskIds) {
- mRequestingPublishTaskIds.add(taskId);
- }
- }
-
- private void removePublishRequestTaskId(int taskId) {
- synchronized (mRequestingPublishTaskIds) {
- mRequestingPublishTaskIds.remove(taskId);
- }
- }
-
- private boolean isPublishRequestExisted(Integer taskId) {
- synchronized (mRequestingPublishTaskIds) {
- return mRequestingPublishTaskIds.contains(taskId);
- }
- }
-
- private void addRequestingAvailabilityTaskId(int taskId) {
- synchronized (mPendingAvailabilityRequests) {
- mPendingAvailabilityRequests.contains(taskId);
- }
- }
-
- private void removeRequestingAvailabilityTaskId(int taskId) {
- synchronized (mPendingAvailabilityRequests) {
- mPendingAvailabilityRequests.remove(taskId);
- }
- }
-
- private boolean isAvailabilityRequestExisted(Integer taskId) {
- synchronized (mPendingAvailabilityRequests) {
- return mPendingAvailabilityRequests.contains(taskId);
- }
- }
-
- private boolean isCapabilityRequestExisted(Integer taskId) {
- return mPendingCapabilityRequests.containsKey(taskId);
- }
-
- private static String getNumberFromUri(Uri uri) {
- String number = uri.getSchemeSpecificPart();
- String[] numberParts = number.split("[@;:]");
-
- if (numberParts.length == 0) {
- return null;
- }
- return numberParts[0];
- }
-
- private static int toUcePublishState(int publishState) {
- switch (publishState) {
- case PresenceBase.PUBLISH_STATE_200_OK:
- return RcsUceAdapter.PUBLISH_STATE_OK;
- case PresenceBase.PUBLISH_STATE_NOT_PUBLISHED:
- return RcsUceAdapter.PUBLISH_STATE_NOT_PUBLISHED;
- case PresenceBase.PUBLISH_STATE_VOLTE_PROVISION_ERROR:
- return RcsUceAdapter.PUBLISH_STATE_VOLTE_PROVISION_ERROR;
- case PresenceBase.PUBLISH_STATE_RCS_PROVISION_ERROR:
- return RcsUceAdapter.PUBLISH_STATE_RCS_PROVISION_ERROR;
- case PresenceBase.PUBLISH_STATE_REQUEST_TIMEOUT:
- return RcsUceAdapter.PUBLISH_STATE_REQUEST_TIMEOUT;
- case PresenceBase.PUBLISH_STATE_OTHER_ERROR:
- return RcsUceAdapter.PUBLISH_STATE_OTHER_ERROR;
- default:
- return RcsUceAdapter.PUBLISH_STATE_OTHER_ERROR;
- }
- }
-
- private static int toUceError(int resultCode) {
- switch (resultCode) {
- case ResultCode.SUBSCRIBE_NOT_REGISTERED:
- return RcsUceAdapter.ERROR_NOT_REGISTERED;
- case ResultCode.SUBSCRIBE_REQUEST_TIMEOUT:
- return RcsUceAdapter.ERROR_REQUEST_TIMEOUT;
- case ResultCode.SUBSCRIBE_FORBIDDEN:
- return RcsUceAdapter.ERROR_FORBIDDEN;
- case ResultCode.SUBSCRIBE_NOT_FOUND:
- return RcsUceAdapter.ERROR_NOT_FOUND;
- case ResultCode.SUBSCRIBE_TOO_LARGE:
- return RcsUceAdapter.ERROR_REQUEST_TOO_LARGE;
- case ResultCode.SUBSCRIBE_INSUFFICIENT_MEMORY:
- return RcsUceAdapter.ERROR_INSUFFICIENT_MEMORY;
- case ResultCode.SUBSCRIBE_LOST_NETWORK:
- return RcsUceAdapter.ERROR_LOST_NETWORK;
- default:
- return RcsUceAdapter.ERROR_GENERIC_FAILURE;
- }
- }
-
- /*
- * Register receivers for updating capabilities
- */
- private void registerReceivers() {
- IntentFilter filter = new IntentFilter(TelecomManager.ACTION_TTY_PREFERRED_MODE_CHANGED);
- filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
- mContext.registerReceiver(mReceiver, filter);
-
- ContentResolver resolver = mContext.getContentResolver();
- if (resolver != null) {
- // Register mobile data content changed.
- resolver.registerContentObserver(
- Settings.Global.getUriFor(Settings.Global.MOBILE_DATA), false,
- mMobileDataObserver);
-
- // Register SIM info content changed.
- resolver.registerContentObserver(Telephony.SimInfo.CONTENT_URI, false,
- mSimInfoContentObserver);
- }
- }
-
- private void unregisterReceivers() {
- mContext.unregisterReceiver(mReceiver);
- ContentResolver resolver = mContext.getContentResolver();
- if (resolver != null) {
- resolver.unregisterContentObserver(mMobileDataObserver);
- resolver.unregisterContentObserver(mSimInfoContentObserver);
- }
- }
-
- /**
- * Register IMS and provision content changed.
- *
- * Call the UceImplHandler#registerImsContentChangedReceiver instead of
- * calling this method directly.
- */
- private void registerImsContentChangedReceiverInternal(int subId) {
- mUceImplHandler.removeRegisteringImsContentChangedReceiver();
- try {
- final int originalSubId = mSubId;
- if ((originalSubId == subId) && (mImsContentChangedCallbackRegistered)) {
- logi("registerImsContentChangedReceiverInternal: already registered. skip");
- return;
- }
- // Unregister original IMS and Provision callback
- unregisterImsProvisionCallback(originalSubId);
- // Register new IMS and Provision callback
- registerImsProvisionCallback(subId);
- } catch (ImsException e) {
- logw("registerImsContentChangedReceiverInternal error: " + e);
- mUceImplHandler.retryRegisteringImsContentChangedReceiver(subId);
- }
- }
-
- private void unregisterImsProvisionCallback(int subId) {
- if (subId <= SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
- return;
- }
- // Unregister IMS callback
- ImsMmTelManager imsMmtelManager = getImsMmTelManager(subId);
- if (imsMmtelManager != null) {
- try {
- imsMmtelManager.unregisterImsRegistrationCallback(mImsRegistrationCallback);
- imsMmtelManager.unregisterMmTelCapabilityCallback(mCapabilityCallback);
- } catch (RuntimeException e) {
- logw("unregister IMS callback error: " + e.getMessage());
- }
- }
-
- // Unregister provision changed callback
- ProvisioningManager provisioningManager =
- ProvisioningManager.createForSubscriptionId(subId);
- try {
- provisioningManager.unregisterProvisioningChangedCallback(mProvisioningChangedCallback);
- } catch (RuntimeException e) {
- logw("unregister provisioning callback error: " + e.getMessage());
- }
-
- // Remove all publish state callbacks
- clearPublishStateCallbacks();
-
- mImsContentChangedCallbackRegistered = false;
- }
-
- private void registerImsProvisionCallback(int subId) throws ImsException {
- if (subId <= SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
- return;
- }
- // Register IMS callback
- ImsMmTelManager imsMmtelManager = getImsMmTelManager(subId);
- if (imsMmtelManager != null) {
- imsMmtelManager.registerImsRegistrationCallback(mContext.getMainExecutor(),
- mImsRegistrationCallback);
- imsMmtelManager.registerMmTelCapabilityCallback(mContext.getMainExecutor(),
- mCapabilityCallback);
- }
- // Register provision changed callback
- ProvisioningManager provisioningManager =
- ProvisioningManager.createForSubscriptionId(subId);
- provisioningManager.registerProvisioningChangedCallback(mContext.getMainExecutor(),
- mProvisioningChangedCallback);
-
- mImsContentChangedCallbackRegistered = true;
- logi("registerImsProvisionCallback");
- }
-
- private BroadcastReceiver mReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (intent == null) return;
- switch (intent.getAction()) {
- case TelecomManager.ACTION_TTY_PREFERRED_MODE_CHANGED:
- int preferredMode = intent.getIntExtra(
- TelecomManager.EXTRA_TTY_PREFERRED_MODE, TelecomManager.TTY_MODE_OFF);
- logi("TTY preferred mode changed: " + preferredMode);
- mPresencePublication.onTtyPreferredModeChanged(preferredMode);
- break;
-
- case Intent.ACTION_AIRPLANE_MODE_CHANGED:
- boolean airplaneMode = intent.getBooleanExtra("state", false);
- logi("Airplane mode changed: " + airplaneMode);
- mPresencePublication.onAirplaneModeChanged(airplaneMode);
- break;
- }
- }
- };
-
- private ContentObserver mMobileDataObserver = new ContentObserver(
- new Handler(Looper.getMainLooper())) {
- @Override
- public void onChange(boolean selfChange) {
- boolean isEnabled = Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.MOBILE_DATA, 1) == 1;
- logi("Mobile data changed: enabled=" + isEnabled);
- mPresencePublication.onMobileDataChanged(isEnabled);
- }
- };
-
- private ContentObserver mSimInfoContentObserver = new ContentObserver(
- new Handler(Looper.getMainLooper())) {
- @Override
- public void onChange(boolean selfChange) {
- if (mSubId <= SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
- return;
- }
-
- ImsMmTelManager ims = getImsMmTelManager(mSubId);
- if (ims == null) return;
-
- try {
- boolean isEnabled = ims.isVtSettingEnabled();
- logi("SimInfo changed: VT setting=" + isEnabled);
- mPresencePublication.onVtEnabled(isEnabled);
- } catch (RuntimeException e) {
- logw("SimInfo changed error: " + e);
- }
- }
- };
-
- private RegistrationManager.RegistrationCallback mImsRegistrationCallback =
- new RegistrationManager.RegistrationCallback() {
- @Override
- public void onRegistered(int imsTransportType) {
- logi("onRegistered: type=" + imsTransportType);
- mNetworkRegistrationType = imsTransportType;
- mPresencePublication.onImsConnected();
-
- // Also trigger PresencePublication#onFeatureCapabilityChanged method
- MmTelFeature.MmTelCapabilities capabilities = null;
- synchronized (mCapabilitiesLock) {
- capabilities = mMmTelCapabilities;
- }
-
- if (capabilities != null) {
- mPresencePublication.onFeatureCapabilityChanged(mNetworkRegistrationType,
- capabilities);
- }
- }
-
- @Override
- public void onUnregistered(ImsReasonInfo info) {
- logi("onUnregistered");
- mNetworkRegistrationType = AccessNetworkConstants.TRANSPORT_TYPE_INVALID;
-
- // Also trigger PresencePublication#onFeatureCapabilityChanged method
- MmTelFeature.MmTelCapabilities capabilities = null;
- synchronized (mCapabilitiesLock) {
- capabilities = mMmTelCapabilities;
- }
-
- if (capabilities != null) {
- mPresencePublication.onFeatureCapabilityChanged(mNetworkRegistrationType,
- capabilities);
- }
- mPresencePublication.onImsDisconnected();
- }
- };
-
- private ImsMmTelManager.CapabilityCallback mCapabilityCallback =
- new ImsMmTelManager.CapabilityCallback() {
- @Override
- public void onCapabilitiesStatusChanged(MmTelFeature.MmTelCapabilities capabilities) {
- if (capabilities == null) {
- logw("onCapabilitiesStatusChanged: parameter is null");
- return;
- }
- synchronized (mCapabilitiesLock) {
- mMmTelCapabilities = capabilities;
- }
- mPresencePublication.onFeatureCapabilityChanged(mNetworkRegistrationType, capabilities);
- }
- };
-
- private ProvisioningManager.Callback mProvisioningChangedCallback =
- new ProvisioningManager.Callback() {
- @Override
- public void onProvisioningIntChanged(int item, int value) {
- logi("onProvisioningIntChanged: item=" + item);
- switch (item) {
- case ProvisioningManager.KEY_EAB_PROVISIONING_STATUS:
- case ProvisioningManager.KEY_VOLTE_PROVISIONING_STATUS:
- case ProvisioningManager.KEY_VT_PROVISIONING_STATUS:
- mPresencePublication.handleProvisioningChanged();
- break;
- default:
- break;
- }
- }
- };
-
- private boolean isCapabilityDiscoveryEnabled(int subId) {
- try {
- ProvisioningManager manager = ProvisioningManager.createForSubscriptionId(subId);
- int discoveryEnabled = manager.getProvisioningIntValue(
- ProvisioningManager.KEY_RCS_CAPABILITY_DISCOVERY_ENABLED);
- return (discoveryEnabled == ProvisioningManager.PROVISIONING_VALUE_ENABLED);
- } catch (Exception e) {
- logw("isCapabilityDiscoveryEnabled error: " + e.getMessage());
- }
- return false;
- }
-
- private boolean isEabProvisioned(Context context, int subId) {
- if (subId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
- logw("isEabProvisioned error: invalid subscriptionId " + subId);
- return false;
- }
-
- CarrierConfigManager configManager = (CarrierConfigManager)
- context.getSystemService(Context.CARRIER_CONFIG_SERVICE);
- if (configManager != null) {
- PersistableBundle config = configManager.getConfigForSubId(subId);
- if (config != null && !config.getBoolean(
- CarrierConfigManager.KEY_CARRIER_VOLTE_PROVISIONED_BOOL)) {
- return true;
- }
- }
-
- try {
- ProvisioningManager manager = ProvisioningManager.createForSubscriptionId(subId);
- int provisioningStatus = manager.getProvisioningIntValue(
- ProvisioningManager.KEY_EAB_PROVISIONING_STATUS);
- return (provisioningStatus == ProvisioningManager.PROVISIONING_VALUE_ENABLED);
- } catch (Exception e) {
- logw("isEabProvisioned error: " + e.getMessage());
- }
- return false;
- }
-
- private ImsMmTelManager getImsMmTelManager(int subId) {
- try {
- ImsManager imsManager = (ImsManager) mContext.getSystemService(
- Context.TELEPHONY_IMS_SERVICE);
- return (imsManager == null) ? null : imsManager.getImsMmTelManager(subId);
- } catch (IllegalArgumentException e) {
- logw("getImsMmTelManager error: " + e.getMessage());
- return null;
- }
- }
-
- 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(mSlotId);
- builder.append("->");
- builder.append(mSubId);
- builder.append("] ");
- return builder;
- }
-}