1 /* 2 * Copyright (C) 2021 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.telephony.ims; 18 19 import android.annotation.CallbackExecutor; 20 import android.annotation.IntDef; 21 import android.annotation.NonNull; 22 import android.os.Binder; 23 24 import com.android.internal.telephony.IImsStateCallback; 25 26 import java.lang.annotation.Retention; 27 import java.lang.annotation.RetentionPolicy; 28 import java.lang.ref.WeakReference; 29 import java.util.concurrent.Executor; 30 31 /** 32 * A callback class used for monitoring changes in IMS service connection states 33 * for a specific subscription. 34 * <p> 35 * @see ImsMmTelManager#registerImsStateCallback(Executor, ImsStateCallback) 36 * @see ImsRcsManager#registerImsStateCallback(Executor, ImsStateCallback) 37 */ 38 public abstract class ImsStateCallback { 39 40 /** @hide */ 41 @Retention(RetentionPolicy.SOURCE) 42 @IntDef(prefix = "REASON_", value = { 43 REASON_UNKNOWN_TEMPORARY_ERROR, 44 REASON_UNKNOWN_PERMANENT_ERROR, 45 REASON_IMS_SERVICE_DISCONNECTED, 46 REASON_NO_IMS_SERVICE_CONFIGURED, 47 REASON_SUBSCRIPTION_INACTIVE, 48 REASON_IMS_SERVICE_NOT_READY 49 }) 50 public @interface DisconnectedReason {} 51 52 /** 53 * The underlying IMS service is temporarily unavailable for the 54 * associated subscription. 55 * {@link #onAvailable} will be called when the IMS service becomes 56 * available again. 57 */ 58 public static final int REASON_UNKNOWN_TEMPORARY_ERROR = 1; 59 60 /** 61 * The underlying IMS service is permanently unavailable for the 62 * associated subscription and there will be no Manager available for 63 * this subscription. 64 */ 65 public static final int REASON_UNKNOWN_PERMANENT_ERROR = 2; 66 67 /** 68 * The underlying IMS service has died, is reconfiguring, or has never 69 * come up yet and as a result is currently unavailable. 70 * {@link #onAvailable} will be called when the IMS service becomes 71 * available. All callbacks should be unregistered now and registered again 72 * if the IMS service moves back to available. 73 */ 74 public static final int REASON_IMS_SERVICE_DISCONNECTED = 3; 75 76 /** 77 * There is no IMS service configured for the subscription ID specified. 78 * This is a permanent error and there will be no Manager available for 79 * this subscription. 80 */ 81 public static final int REASON_NO_IMS_SERVICE_CONFIGURED = 4; 82 83 /** 84 * The subscription associated with this Manager has moved to an inactive 85 * state (e.g. SIM removed) and the IMS service has torn down the resources 86 * related to this subscription. This has caused this callback 87 * to be deregistered. The callback must be re-registered when this subscription 88 * becomes active in order to continue listening to the IMS service state. 89 */ 90 public static final int REASON_SUBSCRIPTION_INACTIVE = 5; 91 92 /** 93 * The IMS service is connected, but in a NOT_READY state. Once the 94 * service moves to ready, {@link #onAvailable} will be called. 95 */ 96 public static final int REASON_IMS_SERVICE_NOT_READY = 6; 97 98 private IImsStateCallbackStub mCallback; 99 100 /** 101 * @hide 102 */ init(@onNull @allbackExecutor Executor executor)103 public void init(@NonNull @CallbackExecutor Executor executor) { 104 if (executor == null) { 105 throw new IllegalArgumentException("ImsStateCallback Executor must be non-null"); 106 } 107 mCallback = new IImsStateCallbackStub(this, executor); 108 } 109 110 /** 111 * Using a static class and weak reference here to avoid memory leak caused by the 112 * IImsStateCallback.Stub callback retaining references to the outside ImsStateCallback. 113 */ 114 private static class IImsStateCallbackStub extends IImsStateCallback.Stub { 115 private WeakReference<ImsStateCallback> mImsStateCallbackWeakRef; 116 private Executor mExecutor; 117 IImsStateCallbackStub(ImsStateCallback imsStateCallback, Executor executor)118 IImsStateCallbackStub(ImsStateCallback imsStateCallback, Executor executor) { 119 mImsStateCallbackWeakRef = new WeakReference<ImsStateCallback>(imsStateCallback); 120 mExecutor = executor; 121 } 122 getExecutor()123 Executor getExecutor() { 124 return mExecutor; 125 } 126 onAvailable()127 public void onAvailable() { 128 ImsStateCallback callback = mImsStateCallbackWeakRef.get(); 129 if (callback == null) return; 130 131 Binder.withCleanCallingIdentity( 132 () -> mExecutor.execute(() -> callback.onAvailable())); 133 } 134 onUnavailable(int reason)135 public void onUnavailable(int reason) { 136 ImsStateCallback callback = mImsStateCallbackWeakRef.get(); 137 if (callback == null) return; 138 139 Binder.withCleanCallingIdentity( 140 () -> mExecutor.execute(() -> callback.onUnavailable(reason))); 141 } 142 } 143 144 /** 145 * The IMS service has disconnected or is reporting NOT_READY and is no longer 146 * available to users. The user should clean up all related state and 147 * unregister callbacks. If it is a temporary error, {@link #onAvailable} will 148 * be called when the IMS service becomes available again. 149 * 150 * @param reason the specified reason 151 */ onUnavailable(@isconnectedReason int reason)152 public abstract void onUnavailable(@DisconnectedReason int reason); 153 154 /** 155 * The IMS service is connected and is ready for communication over the 156 * provided Manager. 157 */ onAvailable()158 public abstract void onAvailable(); 159 160 /** 161 * An unexpected error has occurred and the Telephony process has crashed. This 162 * has caused this callback to be deregistered. The callback must be 163 * re-registered in order to continue listening to the IMS service state. 164 */ onError()165 public abstract void onError(); 166 167 /** 168 * The callback to notify the death of telephony process 169 * @hide 170 */ binderDied()171 public final void binderDied() { 172 if (mCallback != null) { 173 mCallback.getExecutor().execute(() -> onError()); 174 } 175 } 176 177 /** 178 * Return the callback binder 179 * @hide 180 */ getCallbackBinder()181 public IImsStateCallbackStub getCallbackBinder() { 182 return mCallback; 183 } 184 } 185