Add ImsStateCallback

registerImsStateCallback and unregisterImsStateCallback are
added to ImsMmTelManager, ImsRcsManager, and SipDelegateManager.
Those are used to receive updates about the connection state
of the underlying ImsService.

Bug: 178016400
Test: atest ImsStateCallbackTest

Change-Id: If547ce637725d4f98942b0b554187a0ba91f60de
Merged-In: If547ce637725d4f98942b0b554187a0ba91f60de
Merged-In: I3ac14cc3bcb28f5f966a1b3c215727784527e475
This commit is contained in:
Hunsuk Choi
2021-11-15 23:43:57 +00:00
parent 6589fd106d
commit 9725d66837
9 changed files with 455 additions and 6 deletions

View File

@@ -43474,8 +43474,10 @@ package android.telephony.ims {
method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public boolean isVoWiFiSettingEnabled();
method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public boolean isVtSettingEnabled();
method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public void registerImsRegistrationCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.RegistrationManager.RegistrationCallback) throws android.telephony.ims.ImsException;
method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRECISE_PHONE_STATE, "android.permission.READ_PRIVILEGED_PHONE_STATE"}) public void registerImsStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ImsStateCallback) throws android.telephony.ims.ImsException;
method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public void registerMmTelCapabilityCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ImsMmTelManager.CapabilityCallback) throws android.telephony.ims.ImsException;
method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public void unregisterImsRegistrationCallback(@NonNull android.telephony.ims.RegistrationManager.RegistrationCallback);
method public void unregisterImsStateCallback(@NonNull android.telephony.ims.ImsStateCallback);
method @RequiresPermission(anyOf={"android.permission.READ_PRIVILEGED_PHONE_STATE", android.Manifest.permission.READ_PRECISE_PHONE_STATE}) public void unregisterMmTelCapabilityCallback(@NonNull android.telephony.ims.ImsMmTelManager.CapabilityCallback);
field public static final int WIFI_MODE_CELLULAR_PREFERRED = 1; // 0x1
field public static final int WIFI_MODE_WIFI_ONLY = 0; // 0x0
@@ -43492,7 +43494,9 @@ package android.telephony.ims {
method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void getRegistrationTransportType(@NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<java.lang.Integer>);
method @NonNull public android.telephony.ims.RcsUceAdapter getUceAdapter();
method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void registerImsRegistrationCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.RegistrationManager.RegistrationCallback) throws android.telephony.ims.ImsException;
method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRECISE_PHONE_STATE, "android.permission.READ_PRIVILEGED_PHONE_STATE", "android.permission.ACCESS_RCS_USER_CAPABILITY_EXCHANGE"}) public void registerImsStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ImsStateCallback) throws android.telephony.ims.ImsException;
method @RequiresPermission(android.Manifest.permission.READ_PRECISE_PHONE_STATE) public void unregisterImsRegistrationCallback(@NonNull android.telephony.ims.RegistrationManager.RegistrationCallback);
method public void unregisterImsStateCallback(@NonNull android.telephony.ims.ImsStateCallback);
field public static final String ACTION_SHOW_CAPABILITY_DISCOVERY_OPT_IN = "android.telephony.ims.action.SHOW_CAPABILITY_DISCOVERY_OPT_IN";
}
@@ -43691,6 +43695,19 @@ package android.telephony.ims {
field @NonNull public static final android.os.Parcelable.Creator<android.telephony.ims.ImsRegistrationAttributes> CREATOR;
}
public abstract class ImsStateCallback {
ctor public ImsStateCallback();
method public abstract void onAvailable();
method public abstract void onError();
method public abstract void onUnavailable(int);
field public static final int REASON_IMS_SERVICE_DISCONNECTED = 3; // 0x3
field public static final int REASON_IMS_SERVICE_NOT_READY = 6; // 0x6
field public static final int REASON_NO_IMS_SERVICE_CONFIGURED = 4; // 0x4
field public static final int REASON_SUBSCRIPTION_INACTIVE = 5; // 0x5
field public static final int REASON_UNKNOWN_PERMANENT_ERROR = 2; // 0x2
field public static final int REASON_UNKNOWN_TEMPORARY_ERROR = 1; // 0x1
}
public class RcsUceAdapter {
method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean isUceSettingEnabled() throws android.telephony.ims.ImsException;
}

View File

@@ -13741,7 +13741,9 @@ package android.telephony.ims {
method @RequiresPermission(android.Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION) public void createSipDelegate(@NonNull android.telephony.ims.DelegateRequest, @NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.stub.DelegateConnectionStateCallback, @NonNull android.telephony.ims.stub.DelegateConnectionMessageCallback) throws android.telephony.ims.ImsException;
method @RequiresPermission(android.Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION) public void destroySipDelegate(@NonNull android.telephony.ims.SipDelegateConnection, int);
method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION}) public boolean isSupported() throws android.telephony.ims.ImsException;
method @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION}) public void registerImsStateCallback(@NonNull java.util.concurrent.Executor, @NonNull android.telephony.ims.ImsStateCallback) throws android.telephony.ims.ImsException;
method @RequiresPermission(android.Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION) public void triggerFullNetworkRegistration(@NonNull android.telephony.ims.SipDelegateConnection, @IntRange(from=100, to=699) int, @Nullable String);
method public void unregisterImsStateCallback(@NonNull android.telephony.ims.ImsStateCallback);
field public static final int DENIED_REASON_INVALID = 4; // 0x4
field public static final int DENIED_REASON_IN_USE_BY_ANOTHER_DELEGATE = 1; // 0x1
field public static final int DENIED_REASON_NOT_ALLOWED = 2; // 0x2

View File

@@ -119,7 +119,7 @@ public class ImsManager {
throw new IllegalArgumentException("Invalid subscription ID: " + subscriptionId);
}
return new ImsRcsManager(mContext, subscriptionId, sRcsCache);
return new ImsRcsManager(mContext, subscriptionId, sRcsCache, sTelephonyCache);
}
/**
@@ -135,7 +135,7 @@ public class ImsManager {
throw new IllegalArgumentException("Invalid subscription ID: " + subscriptionId);
}
return new ImsMmTelManager(subscriptionId, sTelephonyCache);
return new ImsMmTelManager(mContext, subscriptionId, sTelephonyCache);
}
/**
@@ -157,7 +157,7 @@ public class ImsManager {
throw new IllegalArgumentException("Invalid subscription ID: " + subscriptionId);
}
return new SipDelegateManager(mContext, subscriptionId, sRcsCache);
return new SipDelegateManager(mContext, subscriptionId, sRcsCache, sTelephonyCache);
}
private static IImsRcsController getIImsRcsControllerInterface() {

View File

@@ -25,6 +25,7 @@ import android.annotation.RequiresPermission;
import android.annotation.SuppressAutoDoc;
import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.content.Context;
import android.os.Binder;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
@@ -45,6 +46,7 @@ import com.android.internal.telephony.ITelephony;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
@@ -214,6 +216,7 @@ public class ImsMmTelManager implements RegistrationManager {
}
}
private final Context mContext;
private final int mSubId;
private final BinderCacheManager<ITelephony> mBinderCache;
@@ -255,6 +258,16 @@ public class ImsMmTelManager implements RegistrationManager {
*/
@VisibleForTesting
public ImsMmTelManager(int subId, BinderCacheManager<ITelephony> binderCache) {
this(null, subId, binderCache);
}
/**
* Only visible for testing, use {@link ImsManager#getImsMmTelManager(int)} instead.
* @hide
*/
@VisibleForTesting
public ImsMmTelManager(Context context, int subId, BinderCacheManager<ITelephony> binderCache) {
mContext = context;
mSubId = subId;
mBinderCache = binderCache;
}
@@ -1482,6 +1495,74 @@ public class ImsMmTelManager implements RegistrationManager {
}
}
/**
* Register a new callback, which is used to notify the registrant of changes to
* the state of the underlying IMS service that is attached to telephony to
* implement IMS functionality. If the manager is created for
* the {@link SubscriptionManager#DEFAULT_SUBSCRIPTION_ID},
* this throws an {@link ImsException}.
*
* <p>Requires Permission:
* {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE READ_PRECISE_PHONE_STATE}
* or that the calling app has carrier privileges
* (see {@link android.telephony.TelephonyManager#hasCarrierPrivileges}).
*
* @param executor the Executor that will be used to call the {@link ImsStateCallback}.
* @param callback The callback instance being registered.
* @throws ImsException in the case that the callback can not be registered.
* See {@link ImsException#getCode} for more information on when this is called.
*/
@RequiresPermission(anyOf = {Manifest.permission.READ_PRECISE_PHONE_STATE,
Manifest.permission.READ_PRIVILEGED_PHONE_STATE})
public void registerImsStateCallback(@NonNull Executor executor,
@NonNull ImsStateCallback callback) throws ImsException {
Objects.requireNonNull(callback, "Must include a non-null ImsStateCallback.");
Objects.requireNonNull(executor, "Must include a non-null Executor.");
callback.init(executor);
ITelephony telephony = mBinderCache.listenOnBinder(callback, callback::binderDied);
if (telephony == null) {
throw new ImsException("Telephony server is down",
ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
}
try {
telephony.registerImsStateCallback(
mSubId, ImsFeature.FEATURE_MMTEL,
callback.getCallbackBinder(), getOpPackageName());
} catch (ServiceSpecificException e) {
throw new ImsException(e.getMessage(), e.errorCode);
} catch (RemoteException | IllegalStateException e) {
throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
}
}
/**
* Unregisters a previously registered callback.
*
* @param callback The callback instance to be unregistered.
*/
public void unregisterImsStateCallback(@NonNull ImsStateCallback callback) {
Objects.requireNonNull(callback, "Must include a non-null ImsStateCallback.");
ITelephony telephony = mBinderCache.removeRunnable(callback);
try {
if (telephony != null) {
telephony.unregisterImsStateCallback(callback.getCallbackBinder());
}
} catch (RemoteException ignore) {
// ignore it
}
}
private String getOpPackageName() {
if (mContext != null) {
return mContext.getOpPackageName();
} else {
return null;
}
}
private ITelephony getITelephony() {
return mBinderCache.getBinder();
}

View File

@@ -39,9 +39,11 @@ import android.telephony.ims.stub.ImsRegistrationImplBase;
import android.util.Log;
import com.android.internal.telephony.IIntegerConsumer;
import com.android.internal.telephony.ITelephony;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
@@ -159,6 +161,7 @@ public class ImsRcsManager {
private final int mSubId;
private final Context mContext;
private final BinderCacheManager<IImsRcsController> mBinderCache;
private final BinderCacheManager<ITelephony> mTelephonyBinderCache;
private final Map<OnAvailabilityChangedListener, AvailabilityCallbackAdapter>
mAvailabilityChangedCallbacks;
@@ -167,11 +170,13 @@ public class ImsRcsManager {
* @hide
*/
public ImsRcsManager(Context context, int subId,
BinderCacheManager<IImsRcsController> binderCache) {
BinderCacheManager<IImsRcsController> binderCache,
BinderCacheManager<ITelephony> telephonyBinderCache) {
mSubId = subId;
mContext = context;
mBinderCache = binderCache;
mAvailabilityChangedCallbacks = new HashMap<>();
mTelephonyBinderCache = telephonyBinderCache;
}
/**
@@ -533,6 +538,67 @@ public class ImsRcsManager {
}
}
/**
* Register a new callback, which is used to notify the registrant of changes to
* the state of the underlying IMS service that is attached to telephony to
* implement IMS functionality. If the manager is created for
* the {@link android.telephony.SubscriptionManager#DEFAULT_SUBSCRIPTION_ID},
* this throws an {@link ImsException}.
*
* <p>Requires Permission:
* {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE READ_PRECISE_PHONE_STATE}
* or that the calling app has carrier privileges
* (see {@link android.telephony.TelephonyManager#hasCarrierPrivileges}).
*
* @param executor the Executor that will be used to call the {@link ImsStateCallback}.
* @param callback The callback instance being registered.
* @throws ImsException in the case that the callback can not be registered.
* See {@link ImsException#getCode} for more information on when this is called.
*/
@RequiresPermission(anyOf = {Manifest.permission.READ_PRECISE_PHONE_STATE,
Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
Manifest.permission.ACCESS_RCS_USER_CAPABILITY_EXCHANGE})
public void registerImsStateCallback(@NonNull Executor executor,
@NonNull ImsStateCallback callback) throws ImsException {
Objects.requireNonNull(callback, "Must include a non-null ImsStateCallback.");
Objects.requireNonNull(executor, "Must include a non-null Executor.");
callback.init(executor);
ITelephony telephony = mTelephonyBinderCache.listenOnBinder(callback, callback::binderDied);
if (telephony == null) {
throw new ImsException("Telephony server is down",
ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
}
try {
telephony.registerImsStateCallback(
mSubId, ImsFeature.FEATURE_RCS,
callback.getCallbackBinder(), mContext.getOpPackageName());
} catch (ServiceSpecificException e) {
throw new ImsException(e.getMessage(), e.errorCode);
} catch (RemoteException | IllegalStateException e) {
throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
}
}
/**
* Unregisters a previously registered callback.
*
* @param callback The callback instance to be unregistered.
*/
public void unregisterImsStateCallback(@NonNull ImsStateCallback callback) {
Objects.requireNonNull(callback, "Must include a non-null ImsStateCallback.");
ITelephony telephony = mTelephonyBinderCache.removeRunnable(callback);
try {
if (telephony != null) {
telephony.unregisterImsStateCallback(callback.getCallbackBinder());
}
} catch (RemoteException ignore) {
// ignore it
}
}
/**
* Add the {@link OnAvailabilityChangedListener} to collection for tracking.
* @param executor The executor that will be used when the publish state is changed and the

View File

@@ -0,0 +1,184 @@
/*
* Copyright (C) 2021 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 android.telephony.ims;
import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.os.Binder;
import com.android.internal.telephony.IImsStateCallback;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
import java.util.concurrent.Executor;
/**
* A callback class used for monitoring changes in IMS service connection states
* for a specific subscription.
* <p>
* @see ImsMmTelManager#registerImsStateCallback(Executor, ImsStateCallback)
* @see ImsRcsManager#registerImsStateCallback(Executor, ImsStateCallback)
*/
public abstract class ImsStateCallback {
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@IntDef(prefix = "REASON_", value = {
REASON_UNKNOWN_TEMPORARY_ERROR,
REASON_UNKNOWN_PERMANENT_ERROR,
REASON_IMS_SERVICE_DISCONNECTED,
REASON_NO_IMS_SERVICE_CONFIGURED,
REASON_SUBSCRIPTION_INACTIVE,
REASON_IMS_SERVICE_NOT_READY
})
public @interface DisconnectedReason {}
/**
* The underlying IMS service is temporarily unavailable for the
* associated subscription.
* {@link #onAvailable} will be called when the IMS service becomes
* available again.
*/
public static final int REASON_UNKNOWN_TEMPORARY_ERROR = 1;
/**
* The underlying IMS service is permanently unavailable for the
* associated subscription and there will be no Manager available for
* this subscription.
*/
public static final int REASON_UNKNOWN_PERMANENT_ERROR = 2;
/**
* The underlying IMS service has died, is reconfiguring, or has never
* come up yet and as a result is currently unavailable.
* {@link #onAvailable} will be called when the IMS service becomes
* available. All callbacks should be unregistered now and registered again
* if the IMS service moves back to available.
*/
public static final int REASON_IMS_SERVICE_DISCONNECTED = 3;
/**
* There is no IMS service configured for the subscription ID specified.
* This is a permanent error and there will be no Manager available for
* this subscription.
*/
public static final int REASON_NO_IMS_SERVICE_CONFIGURED = 4;
/**
* The subscription associated with this Manager has moved to an inactive
* state (e.g. SIM removed) and the IMS service has torn down the resources
* related to this subscription. This has caused this callback
* to be deregistered. The callback must be re-registered when this subscription
* becomes active in order to continue listening to the IMS service state.
*/
public static final int REASON_SUBSCRIPTION_INACTIVE = 5;
/**
* The IMS service is connected, but in a NOT_READY state. Once the
* service moves to ready, {@link #onAvailable} will be called.
*/
public static final int REASON_IMS_SERVICE_NOT_READY = 6;
private IImsStateCallbackStub mCallback;
/**
* @hide
*/
public void init(@NonNull @CallbackExecutor Executor executor) {
if (executor == null) {
throw new IllegalArgumentException("ImsStateCallback Executor must be non-null");
}
mCallback = new IImsStateCallbackStub(this, executor);
}
/**
* Using a static class and weak reference here to avoid memory leak caused by the
* IImsStateCallback.Stub callback retaining references to the outside ImsStateCallback.
*/
private static class IImsStateCallbackStub extends IImsStateCallback.Stub {
private WeakReference<ImsStateCallback> mImsStateCallbackWeakRef;
private Executor mExecutor;
IImsStateCallbackStub(ImsStateCallback imsStateCallback, Executor executor) {
mImsStateCallbackWeakRef = new WeakReference<ImsStateCallback>(imsStateCallback);
mExecutor = executor;
}
Executor getExecutor() {
return mExecutor;
}
public void onAvailable() {
ImsStateCallback callback = mImsStateCallbackWeakRef.get();
if (callback == null) return;
Binder.withCleanCallingIdentity(
() -> mExecutor.execute(() -> callback.onAvailable()));
}
public void onUnavailable(int reason) {
ImsStateCallback callback = mImsStateCallbackWeakRef.get();
if (callback == null) return;
Binder.withCleanCallingIdentity(
() -> mExecutor.execute(() -> callback.onUnavailable(reason)));
}
}
/**
* The IMS service has disconnected or is reporting NOT_READY and is no longer
* available to users. The user should clean up all related state and
* unregister callbacks. If it is a temporary error, {@link #onAvailable} will
* be called when the IMS service becomes available again.
*
* @param reason the specified reason
*/
public abstract void onUnavailable(@DisconnectedReason int reason);
/**
* The IMS service is connected and is ready for communication over the
* provided Manager.
*/
public abstract void onAvailable();
/**
* An unexpected error has occurred and the Telephony process has crashed. This
* has caused this callback to be deregistered. The callback must be
* re-registered in order to continue listening to the IMS service state.
*/
public abstract void onError();
/**
* The callback to notify the death of telephony process
* @hide
*/
public final void binderDied() {
if (mCallback != null) {
mCallback.getExecutor().execute(() -> onError());
}
}
/**
* Return the callback binder
* @hide
*/
public IImsStateCallbackStub getCallbackBinder() {
return mCallback;
}
}

View File

@@ -28,15 +28,16 @@ import android.content.pm.PackageManager;
import android.os.RemoteException;
import android.os.ServiceSpecificException;
import android.telephony.BinderCacheManager;
import android.telephony.CarrierConfigManager;
import android.telephony.ims.aidl.IImsRcsController;
import android.telephony.ims.aidl.SipDelegateConnectionAidlWrapper;
import android.telephony.ims.feature.ImsFeature;
import android.telephony.ims.stub.DelegateConnectionMessageCallback;
import android.telephony.ims.stub.DelegateConnectionStateCallback;
import android.telephony.ims.stub.SipDelegate;
import android.util.ArrayMap;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.ITelephony;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -282,6 +283,7 @@ public class SipDelegateManager {
private final Context mContext;
private final int mSubId;
private final BinderCacheManager<IImsRcsController> mBinderCache;
private final BinderCacheManager<ITelephony> mTelephonyBinderCache;
/**
* Only visible for testing. To instantiate an instance of this class, please use
@@ -290,10 +292,12 @@ public class SipDelegateManager {
*/
@VisibleForTesting
public SipDelegateManager(Context context, int subId,
BinderCacheManager<IImsRcsController> binderCache) {
BinderCacheManager<IImsRcsController> binderCache,
BinderCacheManager<ITelephony> telephonyBinderCache) {
mContext = context;
mSubId = subId;
mBinderCache = binderCache;
mTelephonyBinderCache = telephonyBinderCache;
}
/**
@@ -446,4 +450,65 @@ public class SipDelegateManager {
+ " into this method");
}
}
/**
* Register a new callback, which is used to notify the registrant of changes to
* the state of the underlying IMS service that is attached to telephony to
* implement IMS functionality. If the manager is created for
* the {@link android.telephony.SubscriptionManager#DEFAULT_SUBSCRIPTION_ID},
* this throws an {@link ImsException}.
*
* <p>Requires Permission:
* {@link android.Manifest.permission#READ_PRECISE_PHONE_STATE READ_PRECISE_PHONE_STATE}
* or that the calling app has carrier privileges
* (see {@link android.telephony.TelephonyManager#hasCarrierPrivileges}).
*
* @param executor the Executor that will be used to call the {@link ImsStateCallback}.
* @param callback The callback instance being registered.
* @throws ImsException in the case that the callback can not be registered.
* See {@link ImsException#getCode} for more information on when this is called.
*/
@RequiresPermission(anyOf = {Manifest.permission.READ_PRIVILEGED_PHONE_STATE,
Manifest.permission.PERFORM_IMS_SINGLE_REGISTRATION})
public void registerImsStateCallback(@NonNull Executor executor,
@NonNull ImsStateCallback callback) throws ImsException {
Objects.requireNonNull(callback, "Must include a non-null ImsStateCallback.");
Objects.requireNonNull(executor, "Must include a non-null Executor.");
callback.init(executor);
ITelephony telephony = mTelephonyBinderCache.listenOnBinder(callback, callback::binderDied);
if (telephony == null) {
throw new ImsException("Telephony server is down",
ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
}
try {
telephony.registerImsStateCallback(
mSubId, ImsFeature.FEATURE_RCS,
callback.getCallbackBinder(), mContext.getOpPackageName());
} catch (ServiceSpecificException e) {
throw new ImsException(e.getMessage(), e.errorCode);
} catch (RemoteException | IllegalStateException e) {
throw new ImsException(e.getMessage(), ImsException.CODE_ERROR_SERVICE_UNAVAILABLE);
}
}
/**
* Unregisters a previously registered callback.
*
* @param callback The callback instance to be unregistered.
*/
public void unregisterImsStateCallback(@NonNull ImsStateCallback callback) {
Objects.requireNonNull(callback, "Must include a non-null ImsStateCallback.");
ITelephony telephony = mTelephonyBinderCache.removeRunnable(callback);
try {
if (telephony != null) {
telephony.unregisterImsStateCallback(callback.getCallbackBinder());
}
} catch (RemoteException ignore) {
// ignore it
}
}
}

View File

@@ -0,0 +1,22 @@
/*
* Copyright (C) 2021 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.internal.telephony;
oneway interface IImsStateCallback {
void onUnavailable(int reason);
void onAvailable();
}

View File

@@ -67,6 +67,7 @@ import com.android.ims.internal.IImsServiceFeatureCallback;
import com.android.internal.telephony.CellNetworkScanResult;
import com.android.internal.telephony.IBooleanConsumer;
import com.android.internal.telephony.ICallForwardingInfoCallback;
import com.android.internal.telephony.IImsStateCallback;
import com.android.internal.telephony.IIntegerConsumer;
import com.android.internal.telephony.INumberVerificationCallback;
import com.android.internal.telephony.OperatorInfo;
@@ -2497,4 +2498,15 @@ interface ITelephony {
* NSSAIs (configured, allowed and rejected).
*/
void getSlicingConfig(in ResultReceiver callback);
/**
* Register an IMS connection state callback
*/
void registerImsStateCallback(int subId, int feature, in IImsStateCallback cb,
in String callingPackage);
/**
* Unregister an IMS connection state callback
*/
void unregisterImsStateCallback(in IImsStateCallback cb);
}