1 /* 2 * Copyright (C) 2018 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.compat.feature; 18 19 import android.annotation.IntDef; 20 import android.compat.annotation.UnsupportedAppUsage; 21 import android.content.Context; 22 import android.os.Build; 23 import android.os.IInterface; 24 import android.os.RemoteException; 25 import android.telephony.SubscriptionManager; 26 import android.util.Log; 27 28 import com.android.ims.internal.IImsFeatureStatusCallback; 29 30 import java.lang.annotation.Retention; 31 import java.lang.annotation.RetentionPolicy; 32 import java.util.Collections; 33 import java.util.Iterator; 34 import java.util.Set; 35 import java.util.WeakHashMap; 36 37 /** 38 * Base class for all IMS features that are supported by the framework. 39 * @hide 40 */ 41 public abstract class ImsFeature { 42 43 private static final String LOG_TAG = "ImsFeature"; 44 45 // Invalid feature value 46 public static final int INVALID = -1; 47 // ImsFeatures that are defined in the Manifests. Ensure that these values match the previously 48 // defined values in ImsServiceClass for compatibility purposes. 49 public static final int EMERGENCY_MMTEL = 0; 50 public static final int MMTEL = 1; 51 public static final int RCS = 2; 52 // Total number of features defined 53 public static final int MAX = 3; 54 55 // Integer values defining the state of the ImsFeature at any time. 56 @IntDef(flag = true, 57 value = { 58 STATE_NOT_AVAILABLE, 59 STATE_INITIALIZING, 60 STATE_READY, 61 }) 62 @Retention(RetentionPolicy.SOURCE) 63 public @interface ImsState {} 64 public static final int STATE_NOT_AVAILABLE = 0; 65 public static final int STATE_INITIALIZING = 1; 66 public static final int STATE_READY = 2; 67 68 private final Set<IImsFeatureStatusCallback> mStatusCallbacks = Collections.newSetFromMap( 69 new WeakHashMap<IImsFeatureStatusCallback, Boolean>()); 70 private @ImsState int mState = STATE_NOT_AVAILABLE; 71 private int mSlotId = SubscriptionManager.INVALID_SIM_SLOT_INDEX; 72 protected Context mContext; 73 setContext(Context context)74 public void setContext(Context context) { 75 mContext = context; 76 } 77 setSlotId(int slotId)78 public void setSlotId(int slotId) { 79 mSlotId = slotId; 80 } 81 82 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) getFeatureState()83 public int getFeatureState() { 84 return mState; 85 } 86 87 @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553) setFeatureState(@msState int state)88 protected final void setFeatureState(@ImsState int state) { 89 if (mState != state) { 90 mState = state; 91 notifyFeatureState(state); 92 } 93 } 94 addImsFeatureStatusCallback(IImsFeatureStatusCallback c)95 public void addImsFeatureStatusCallback(IImsFeatureStatusCallback c) { 96 if (c == null) { 97 return; 98 } 99 try { 100 // If we have just connected, send queued status. 101 c.notifyImsFeatureStatus(mState); 102 // Add the callback if the callback completes successfully without a RemoteException. 103 synchronized (mStatusCallbacks) { 104 mStatusCallbacks.add(c); 105 } 106 } catch (RemoteException e) { 107 Log.w(LOG_TAG, "Couldn't notify feature state: " + e.getMessage()); 108 } 109 } 110 removeImsFeatureStatusCallback(IImsFeatureStatusCallback c)111 public void removeImsFeatureStatusCallback(IImsFeatureStatusCallback c) { 112 if (c == null) { 113 return; 114 } 115 synchronized (mStatusCallbacks) { 116 mStatusCallbacks.remove(c); 117 } 118 } 119 120 /** 121 * Internal method called by ImsFeature when setFeatureState has changed. 122 * @param state 123 */ notifyFeatureState(@msState int state)124 private void notifyFeatureState(@ImsState int state) { 125 synchronized (mStatusCallbacks) { 126 for (Iterator<IImsFeatureStatusCallback> iter = mStatusCallbacks.iterator(); 127 iter.hasNext(); ) { 128 IImsFeatureStatusCallback callback = iter.next(); 129 try { 130 Log.i(LOG_TAG, "notifying ImsFeatureState=" + state); 131 callback.notifyImsFeatureStatus(state); 132 } catch (RemoteException e) { 133 // remove if the callback is no longer alive. 134 iter.remove(); 135 Log.w(LOG_TAG, "Couldn't notify feature state: " + e.getMessage()); 136 } 137 } 138 } 139 } 140 141 /** 142 * Called when the feature is ready to use. 143 */ onFeatureReady()144 public abstract void onFeatureReady(); 145 146 /** 147 * Called when the feature is being removed and must be cleaned up. 148 */ onFeatureRemoved()149 public abstract void onFeatureRemoved(); 150 151 /** 152 * @return Binder instance 153 */ getBinder()154 public abstract IInterface getBinder(); 155 } 156