1 /* 2 * Copyright (C) 2017 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.stub; 18 19 import android.annotation.IntDef; 20 import android.annotation.SystemApi; 21 import android.net.Uri; 22 import android.os.RemoteCallbackList; 23 import android.os.RemoteException; 24 import android.telephony.ims.aidl.IImsRegistration; 25 import android.telephony.ims.aidl.IImsRegistrationCallback; 26 import android.util.Log; 27 28 import android.telephony.ims.ImsReasonInfo; 29 30 import com.android.internal.annotations.VisibleForTesting; 31 32 import java.lang.annotation.Retention; 33 import java.lang.annotation.RetentionPolicy; 34 35 /** 36 * Controls IMS registration for this ImsService and notifies the framework when the IMS 37 * registration for this ImsService has changed status. 38 * @hide 39 */ 40 @SystemApi 41 public class ImsRegistrationImplBase { 42 43 private static final String LOG_TAG = "ImsRegistrationImplBase"; 44 45 /** 46 * @hide 47 */ 48 // Defines the underlying radio technology type that we have registered for IMS over. 49 @IntDef(flag = true, 50 value = { 51 REGISTRATION_TECH_NONE, 52 REGISTRATION_TECH_LTE, 53 REGISTRATION_TECH_IWLAN 54 }) 55 @Retention(RetentionPolicy.SOURCE) 56 public @interface ImsRegistrationTech {} 57 /** 58 * No registration technology specified, used when we are not registered. 59 */ 60 public static final int REGISTRATION_TECH_NONE = -1; 61 /** 62 * IMS is registered to IMS via LTE. 63 */ 64 public static final int REGISTRATION_TECH_LTE = 0; 65 /** 66 * IMS is registered to IMS via IWLAN. 67 */ 68 public static final int REGISTRATION_TECH_IWLAN = 1; 69 70 // Registration states, used to notify new ImsRegistrationImplBase#Callbacks of the current 71 // state. 72 // The unknown state is set as the initialization state. This is so that we do not call back 73 // with NOT_REGISTERED in the case where the ImsService has not updated the registration state 74 // yet. 75 private static final int REGISTRATION_STATE_UNKNOWN = -1; 76 private static final int REGISTRATION_STATE_NOT_REGISTERED = 0; 77 private static final int REGISTRATION_STATE_REGISTERING = 1; 78 private static final int REGISTRATION_STATE_REGISTERED = 2; 79 80 /** 81 * Callback class for receiving Registration callback events. 82 * @hide 83 */ 84 public static class Callback { 85 /** 86 * Notifies the framework when the IMS Provider is connected to the IMS network. 87 * 88 * @param imsRadioTech the radio access technology. Valid values are defined in 89 * {@link ImsRegistrationTech}. 90 */ onRegistered(@msRegistrationTech int imsRadioTech)91 public void onRegistered(@ImsRegistrationTech int imsRadioTech) { 92 } 93 94 /** 95 * Notifies the framework when the IMS Provider is trying to connect the IMS network. 96 * 97 * @param imsRadioTech the radio access technology. Valid values are defined in 98 * {@link ImsRegistrationTech}. 99 */ onRegistering(@msRegistrationTech int imsRadioTech)100 public void onRegistering(@ImsRegistrationTech int imsRadioTech) { 101 } 102 103 /** 104 * Notifies the framework when the IMS Provider is disconnected from the IMS network. 105 * 106 * @param info the {@link ImsReasonInfo} associated with why registration was disconnected. 107 */ onDeregistered(ImsReasonInfo info)108 public void onDeregistered(ImsReasonInfo info) { 109 } 110 111 /** 112 * A failure has occurred when trying to handover registration to another technology type, 113 * defined in {@link ImsRegistrationTech} 114 * 115 * @param imsRadioTech The {@link ImsRegistrationTech} type that has failed 116 * @param info A {@link ImsReasonInfo} that identifies the reason for failure. 117 */ onTechnologyChangeFailed(@msRegistrationTech int imsRadioTech, ImsReasonInfo info)118 public void onTechnologyChangeFailed(@ImsRegistrationTech int imsRadioTech, 119 ImsReasonInfo info) { 120 } 121 122 /** 123 * Returns a list of subscriber {@link Uri}s associated with this IMS subscription when 124 * it changes. 125 * @param uris new array of subscriber {@link Uri}s that are associated with this IMS 126 * subscription. 127 */ onSubscriberAssociatedUriChanged(Uri[] uris)128 public void onSubscriberAssociatedUriChanged(Uri[] uris) { 129 130 } 131 } 132 133 private final IImsRegistration mBinder = new IImsRegistration.Stub() { 134 135 @Override 136 public @ImsRegistrationTech int getRegistrationTechnology() throws RemoteException { 137 return getConnectionType(); 138 } 139 140 @Override 141 public void addRegistrationCallback(IImsRegistrationCallback c) throws RemoteException { 142 ImsRegistrationImplBase.this.addRegistrationCallback(c); 143 } 144 145 @Override 146 public void removeRegistrationCallback(IImsRegistrationCallback c) throws RemoteException { 147 ImsRegistrationImplBase.this.removeRegistrationCallback(c); 148 } 149 }; 150 151 private final RemoteCallbackList<IImsRegistrationCallback> mCallbacks 152 = new RemoteCallbackList<>(); 153 private final Object mLock = new Object(); 154 // Locked on mLock 155 private @ImsRegistrationTech 156 int mConnectionType = REGISTRATION_TECH_NONE; 157 // Locked on mLock 158 private int mRegistrationState = REGISTRATION_STATE_UNKNOWN; 159 // Locked on mLock, create unspecified disconnect cause. 160 private ImsReasonInfo mLastDisconnectCause = new ImsReasonInfo(); 161 162 /** 163 * @hide 164 */ getBinder()165 public final IImsRegistration getBinder() { 166 return mBinder; 167 } 168 addRegistrationCallback(IImsRegistrationCallback c)169 private void addRegistrationCallback(IImsRegistrationCallback c) throws RemoteException { 170 mCallbacks.register(c); 171 updateNewCallbackWithState(c); 172 } 173 removeRegistrationCallback(IImsRegistrationCallback c)174 private void removeRegistrationCallback(IImsRegistrationCallback c) { 175 mCallbacks.unregister(c); 176 } 177 178 /** 179 * Notify the framework that the device is connected to the IMS network. 180 * 181 * @param imsRadioTech the radio access technology. Valid values are defined as 182 * {@link #REGISTRATION_TECH_LTE} and {@link #REGISTRATION_TECH_IWLAN}. 183 */ onRegistered(@msRegistrationTech int imsRadioTech)184 public final void onRegistered(@ImsRegistrationTech int imsRadioTech) { 185 updateToState(imsRadioTech, REGISTRATION_STATE_REGISTERED); 186 mCallbacks.broadcast((c) -> { 187 try { 188 c.onRegistered(imsRadioTech); 189 } catch (RemoteException e) { 190 Log.w(LOG_TAG, e + " " + "onRegistrationConnected() - Skipping " + 191 "callback."); 192 } 193 }); 194 } 195 196 /** 197 * Notify the framework that the device is trying to connect the IMS network. 198 * 199 * @param imsRadioTech the radio access technology. Valid values are defined as 200 * {@link #REGISTRATION_TECH_LTE} and {@link #REGISTRATION_TECH_IWLAN}. 201 */ onRegistering(@msRegistrationTech int imsRadioTech)202 public final void onRegistering(@ImsRegistrationTech int imsRadioTech) { 203 updateToState(imsRadioTech, REGISTRATION_STATE_REGISTERING); 204 mCallbacks.broadcast((c) -> { 205 try { 206 c.onRegistering(imsRadioTech); 207 } catch (RemoteException e) { 208 Log.w(LOG_TAG, e + " " + "onRegistrationProcessing() - Skipping " + 209 "callback."); 210 } 211 }); 212 } 213 214 /** 215 * Notify the framework that the device is disconnected from the IMS network. 216 * <p> 217 * Note: Prior to calling {@link #onDeregistered(ImsReasonInfo)}, you should ensure that any 218 * changes to {@link android.telephony.ims.feature.ImsFeature} capability availability is sent 219 * to the framework. For example, 220 * {@link android.telephony.ims.feature.MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VIDEO} 221 * and 222 * {@link android.telephony.ims.feature.MmTelFeature.MmTelCapabilities#CAPABILITY_TYPE_VOICE} 223 * may be set to unavailable to ensure the framework knows these services are no longer 224 * available due to de-registration. If you do not report capability changes impacted by 225 * de-registration, the framework will not know which features are no longer available as a 226 * result. 227 * 228 * @param info the {@link ImsReasonInfo} associated with why registration was disconnected. 229 */ onDeregistered(ImsReasonInfo info)230 public final void onDeregistered(ImsReasonInfo info) { 231 updateToDisconnectedState(info); 232 mCallbacks.broadcast((c) -> { 233 try { 234 c.onDeregistered(info); 235 } catch (RemoteException e) { 236 Log.w(LOG_TAG, e + " " + "onRegistrationDisconnected() - Skipping " + 237 "callback."); 238 } 239 }); 240 } 241 242 /** 243 * Notify the framework that the handover from the current radio technology to the technology 244 * defined in {@code imsRadioTech} has failed. 245 * @param imsRadioTech The technology that has failed to be changed. Valid values are 246 * {@link #REGISTRATION_TECH_LTE} and {@link #REGISTRATION_TECH_IWLAN}. 247 * @param info The {@link ImsReasonInfo} for the failure to change technology. 248 */ onTechnologyChangeFailed(@msRegistrationTech int imsRadioTech, ImsReasonInfo info)249 public final void onTechnologyChangeFailed(@ImsRegistrationTech int imsRadioTech, 250 ImsReasonInfo info) { 251 mCallbacks.broadcast((c) -> { 252 try { 253 c.onTechnologyChangeFailed(imsRadioTech, info); 254 } catch (RemoteException e) { 255 Log.w(LOG_TAG, e + " " + "onRegistrationChangeFailed() - Skipping " + 256 "callback."); 257 } 258 }); 259 } 260 261 /** 262 * The this device's subscriber associated {@link Uri}s have changed, which are used to filter 263 * out this device's {@link Uri}s during conference calling. 264 * @param uris 265 */ onSubscriberAssociatedUriChanged(Uri[] uris)266 public final void onSubscriberAssociatedUriChanged(Uri[] uris) { 267 mCallbacks.broadcast((c) -> { 268 try { 269 c.onSubscriberAssociatedUriChanged(uris); 270 } catch (RemoteException e) { 271 Log.w(LOG_TAG, e + " " + "onSubscriberAssociatedUriChanged() - Skipping " + 272 "callback."); 273 } 274 }); 275 } 276 updateToState(@msRegistrationTech int connType, int newState)277 private void updateToState(@ImsRegistrationTech int connType, int newState) { 278 synchronized (mLock) { 279 mConnectionType = connType; 280 mRegistrationState = newState; 281 mLastDisconnectCause = null; 282 } 283 } 284 updateToDisconnectedState(ImsReasonInfo info)285 private void updateToDisconnectedState(ImsReasonInfo info) { 286 synchronized (mLock) { 287 updateToState(REGISTRATION_TECH_NONE, REGISTRATION_STATE_NOT_REGISTERED); 288 if (info != null) { 289 mLastDisconnectCause = info; 290 } else { 291 Log.w(LOG_TAG, "updateToDisconnectedState: no ImsReasonInfo provided."); 292 mLastDisconnectCause = new ImsReasonInfo(); 293 } 294 } 295 } 296 297 /** 298 * @return the current registration connection type. Valid values are 299 * {@link #REGISTRATION_TECH_LTE} and {@link #REGISTRATION_TECH_IWLAN} 300 * @hide 301 */ 302 @VisibleForTesting getConnectionType()303 public final @ImsRegistrationTech int getConnectionType() { 304 synchronized (mLock) { 305 return mConnectionType; 306 } 307 } 308 309 /** 310 * @param c the newly registered callback that will be updated with the current registration 311 * state. 312 */ updateNewCallbackWithState(IImsRegistrationCallback c)313 private void updateNewCallbackWithState(IImsRegistrationCallback c) throws RemoteException { 314 int state; 315 ImsReasonInfo disconnectInfo; 316 synchronized (mLock) { 317 state = mRegistrationState; 318 disconnectInfo = mLastDisconnectCause; 319 } 320 switch (state) { 321 case REGISTRATION_STATE_NOT_REGISTERED: { 322 c.onDeregistered(disconnectInfo); 323 break; 324 } 325 case REGISTRATION_STATE_REGISTERING: { 326 c.onRegistering(getConnectionType()); 327 break; 328 } 329 case REGISTRATION_STATE_REGISTERED: { 330 c.onRegistered(getConnectionType()); 331 break; 332 } 333 case REGISTRATION_STATE_UNKNOWN: { 334 // Do not callback if the state has not been updated yet by the ImsService. 335 break; 336 } 337 } 338 } 339 } 340