1 /* 2 * Copyright (c) 2019 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 com.android.ims; 18 19 import android.content.Context; 20 import android.os.IInterface; 21 import android.os.RemoteCallbackList; 22 import android.telephony.SubscriptionManager; 23 import android.util.Log; 24 25 26 public abstract class ImsCallbackAdapterManager<T extends IInterface> { 27 private static final String TAG = "ImsCallbackAM"; 28 29 private final Context mContext; 30 private final Object mLock; 31 private final int mSlotId; 32 private final int mSubId; 33 34 // List of all active callbacks to ImsService 35 private final RemoteCallbackList<T> mRemoteCallbacks = new RemoteCallbackList<>(); 36 ImsCallbackAdapterManager(Context context, Object lock, int slotId, int subId)37 public ImsCallbackAdapterManager(Context context, Object lock, int slotId, int subId) { 38 mContext = context; 39 mLock = lock; 40 mSlotId = slotId; 41 mSubId = subId; 42 } 43 44 // Add a callback to the ImsFeature associated with this manager (independent of the 45 // current subscription). addCallback(T localCallback)46 public final void addCallback(T localCallback) { 47 synchronized (mLock) { 48 // Skip registering to callback subscription map here, because we are registering 49 // for the slot, independent of subscription (deprecated behavior). 50 // Throws a IllegalStateException if this registration fails. 51 registerCallback(localCallback); 52 Log.i(TAG + " [" + mSlotId + "]", "Local callback added: " + localCallback); 53 54 mRemoteCallbacks.register(localCallback); 55 } 56 } 57 58 // Add a callback to be associated with a subscription. addCallbackForSubscription(T localCallback, int subId)59 public void addCallbackForSubscription(T localCallback, int subId) { 60 if (!SubscriptionManager.isValidSubscriptionId(subId)) { 61 Log.w(TAG + " [" + mSlotId + ", " + mSubId + "]", "add callback: invalid subId."); 62 return; 63 } 64 if (mSubId != subId) { 65 // In some cases, telephony has changed sub id and IMS is still catching up to the 66 // state change. Ensure that the device does not try to register a callback on an 67 // inactive subscription, because this can cause a condition where we remove the 68 // callback invisibly when the new subscription loads. Instead, simulate the existing 69 // IllegalStateException that happens when the ImsService is not ready/active for 70 // backwards compatibility. 71 Log.w(TAG + " [" + mSlotId + ", " + mSubId + "]", "add callback: inactive" 72 + " subID detected: " + subId); 73 throw new IllegalStateException("ImsService is not available for the subscription " 74 + "specified."); 75 } 76 synchronized (mLock) { 77 addCallback(localCallback); 78 } 79 } 80 81 // Removes a callback associated with the ImsFeature. removeCallback(T localCallback)82 public final void removeCallback(T localCallback) { 83 Log.i(TAG + " [" + mSlotId + "]", "Local callback removed: " + localCallback); 84 synchronized (mLock) { 85 if (mRemoteCallbacks.unregister(localCallback)) { 86 // Will only occur if we have record of this callback in mRemoteCallbacks. 87 unregisterCallback(localCallback); 88 } 89 } 90 } 91 92 // The ImsService these callbacks are registered to has become unavailable or crashed, or 93 // the ImsResolver has switched to a new ImsService. In these cases, clean up all existing 94 // callbacks. close()95 public final void close() { 96 synchronized (mLock) { 97 final int lastCallbackIndex = mRemoteCallbacks.getRegisteredCallbackCount() - 1; 98 for(int ii = lastCallbackIndex; ii >= 0; ii --) { 99 T callbackItem = mRemoteCallbacks.getRegisteredCallbackItem(ii); 100 unregisterCallback(callbackItem); 101 mRemoteCallbacks.unregister(callbackItem); 102 } 103 Log.i(TAG + " [" + mSlotId + "]", "Closing connection and clearing callbacks"); 104 } 105 } 106 107 // A callback has been registered. Register that callback with the ImsFeature. registerCallback(T localCallback)108 public abstract void registerCallback(T localCallback); 109 110 // A callback has been removed, unregister that callback with the RcsFeature. unregisterCallback(T localCallback)111 public abstract void unregisterCallback(T localCallback); 112 } 113