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.annotation.NonNull; 20 import android.content.Context; 21 import android.net.Uri; 22 import android.os.IBinder; 23 import android.os.RemoteException; 24 import android.telephony.ims.aidl.ICapabilityExchangeEventListener; 25 import android.telephony.ims.aidl.IImsCapabilityCallback; 26 import android.telephony.ims.aidl.IImsConfig; 27 import android.telephony.ims.aidl.IImsRcsFeature; 28 import android.telephony.ims.aidl.IImsRegistration; 29 import android.telephony.ims.aidl.IImsRegistrationCallback; 30 import android.telephony.ims.aidl.IPublishResponseCallback; 31 import android.telephony.ims.aidl.IOptionsResponseCallback; 32 import android.telephony.ims.aidl.ISipTransport; 33 import android.telephony.ims.aidl.ISubscribeResponseCallback; 34 import android.telephony.ims.feature.CapabilityChangeRequest; 35 36 import com.android.internal.annotations.VisibleForTesting; 37 import com.android.telephony.Rlog; 38 39 import java.util.List; 40 41 /** 42 * A container of the IImsServiceController binder, which implements all of the RcsFeatures that 43 * the platform currently supports: RCS 44 */ 45 public class RcsFeatureConnection extends FeatureConnection { 46 private static final String TAG = "RcsFeatureConnection"; 47 48 public class AvailabilityCallbackManager extends 49 ImsCallbackAdapterManager<IImsCapabilityCallback> { 50 AvailabilityCallbackManager(Context context)51 AvailabilityCallbackManager(Context context) { 52 super(context, new Object() /* Lock object */, mSlotId, mSubId); 53 } 54 55 @Override registerCallback(IImsCapabilityCallback localCallback)56 public void registerCallback(IImsCapabilityCallback localCallback) { 57 try { 58 addCapabilityCallback(localCallback); 59 } catch (RemoteException e) { 60 loge("Register capability callback error: " + e); 61 throw new IllegalStateException( 62 " CapabilityCallbackManager: Register callback error"); 63 } 64 } 65 66 @Override unregisterCallback(IImsCapabilityCallback localCallback)67 public void unregisterCallback(IImsCapabilityCallback localCallback) { 68 try { 69 removeCapabilityCallback(localCallback); 70 } catch (RemoteException e) { 71 loge("Cannot remove capability callback: " + e); 72 } 73 } 74 } 75 76 private class RegistrationCallbackManager extends 77 ImsCallbackAdapterManager<IImsRegistrationCallback> { 78 RegistrationCallbackManager(Context context)79 public RegistrationCallbackManager(Context context) { 80 super(context, new Object() /* Lock object */, mSlotId, mSubId); 81 } 82 83 @Override registerCallback(IImsRegistrationCallback localCallback)84 public void registerCallback(IImsRegistrationCallback localCallback) { 85 IImsRegistration imsRegistration = getRegistration(); 86 if (imsRegistration == null) { 87 loge("Register IMS registration callback: ImsRegistration is null"); 88 throw new IllegalStateException("RegistrationCallbackAdapter: RcsFeature is" 89 + " not available!"); 90 } 91 92 try { 93 imsRegistration.addRegistrationCallback(localCallback); 94 } catch (RemoteException e) { 95 throw new IllegalStateException("RegistrationCallbackAdapter: RcsFeature" 96 + " binder is dead."); 97 } 98 } 99 100 @Override unregisterCallback(IImsRegistrationCallback localCallback)101 public void unregisterCallback(IImsRegistrationCallback localCallback) { 102 IImsRegistration imsRegistration = getRegistration(); 103 if (imsRegistration == null) { 104 logi("Unregister IMS registration callback: ImsRegistration is null"); 105 return; 106 } 107 108 try { 109 imsRegistration.removeRegistrationCallback(localCallback); 110 } catch (RemoteException e) { 111 loge("Cannot remove registration callback: " + e); 112 } 113 } 114 } 115 116 @VisibleForTesting 117 public AvailabilityCallbackManager mAvailabilityCallbackManager; 118 @VisibleForTesting 119 public RegistrationCallbackManager mRegistrationCallbackManager; 120 RcsFeatureConnection(Context context, int slotId, int subId, IImsRcsFeature feature, IImsConfig c, IImsRegistration r, ISipTransport s)121 public RcsFeatureConnection(Context context, int slotId, int subId, IImsRcsFeature feature, 122 IImsConfig c, IImsRegistration r, ISipTransport s) { 123 super(context, slotId, subId, c, r, s); 124 setBinder(feature != null ? feature.asBinder() : null); 125 mAvailabilityCallbackManager = new AvailabilityCallbackManager(mContext); 126 mRegistrationCallbackManager = new RegistrationCallbackManager(mContext); 127 } 128 close()129 public void close() { 130 removeCapabilityExchangeEventListener(); 131 mAvailabilityCallbackManager.close(); 132 mRegistrationCallbackManager.close(); 133 } 134 135 @Override onRemovedOrDied()136 protected void onRemovedOrDied() { 137 close(); 138 super.onRemovedOrDied(); 139 } 140 setCapabilityExchangeEventListener(ICapabilityExchangeEventListener listener)141 public void setCapabilityExchangeEventListener(ICapabilityExchangeEventListener listener) 142 throws RemoteException { 143 synchronized (mLock) { 144 // Only check if service is alive. The feature status may not be READY. 145 checkServiceIsAlive(); 146 getServiceInterface(mBinder).setCapabilityExchangeEventListener(listener); 147 } 148 } 149 removeCapabilityExchangeEventListener()150 public void removeCapabilityExchangeEventListener() { 151 try { 152 setCapabilityExchangeEventListener(null); 153 } catch (RemoteException e) { 154 // If we are not still connected, there is no need to fail removing. 155 } 156 } 157 checkServiceIsAlive()158 private void checkServiceIsAlive() throws RemoteException { 159 if (!sImsSupportedOnDevice) { 160 throw new RemoteException("IMS is not supported on this device."); 161 } 162 if (!isBinderAlive()) { 163 throw new RemoteException("ImsServiceProxy is not alive."); 164 } 165 } 166 queryCapabilityStatus()167 public int queryCapabilityStatus() throws RemoteException { 168 synchronized (mLock) { 169 checkServiceIsReady(); 170 return getServiceInterface(mBinder).queryCapabilityStatus(); 171 } 172 } 173 addCallbackForSubscription(int subId, IImsCapabilityCallback cb)174 public void addCallbackForSubscription(int subId, IImsCapabilityCallback cb) { 175 mAvailabilityCallbackManager.addCallbackForSubscription(cb, subId); 176 } 177 addCallbackForSubscription(int subId, IImsRegistrationCallback cb)178 public void addCallbackForSubscription(int subId, IImsRegistrationCallback cb) { 179 mRegistrationCallbackManager.addCallbackForSubscription(cb, subId); 180 } 181 addCallback(IImsRegistrationCallback cb)182 public void addCallback(IImsRegistrationCallback cb) { 183 mRegistrationCallbackManager.addCallback(cb); 184 } 185 removeCallbackForSubscription(int subId, IImsCapabilityCallback cb)186 public void removeCallbackForSubscription(int subId, IImsCapabilityCallback cb) { 187 mAvailabilityCallbackManager.removeCallback(cb); 188 } 189 removeCallbackForSubscription(int subId, IImsRegistrationCallback cb)190 public void removeCallbackForSubscription(int subId, IImsRegistrationCallback cb) { 191 mRegistrationCallbackManager.removeCallback(cb); 192 } 193 removeCallback(IImsRegistrationCallback cb)194 public void removeCallback(IImsRegistrationCallback cb) { 195 mRegistrationCallbackManager.removeCallback(cb); 196 } 197 198 // Add callback to remote service addCapabilityCallback(IImsCapabilityCallback callback)199 private void addCapabilityCallback(IImsCapabilityCallback callback) throws RemoteException { 200 synchronized (mLock) { 201 checkServiceIsReady(); 202 getServiceInterface(mBinder).addCapabilityCallback(callback); 203 } 204 } 205 206 // Remove callback to remote service removeCapabilityCallback(IImsCapabilityCallback callback)207 private void removeCapabilityCallback(IImsCapabilityCallback callback) throws RemoteException { 208 synchronized (mLock) { 209 checkServiceIsReady(); 210 getServiceInterface(mBinder).removeCapabilityCallback(callback); 211 } 212 } 213 queryCapabilityConfiguration(int capability, int radioTech, IImsCapabilityCallback c)214 public void queryCapabilityConfiguration(int capability, int radioTech, 215 IImsCapabilityCallback c) throws RemoteException { 216 synchronized (mLock) { 217 checkServiceIsReady(); 218 getServiceInterface(mBinder).queryCapabilityConfiguration(capability, radioTech, c); 219 } 220 } 221 changeEnabledCapabilities(CapabilityChangeRequest request, IImsCapabilityCallback callback)222 public void changeEnabledCapabilities(CapabilityChangeRequest request, 223 IImsCapabilityCallback callback) throws RemoteException { 224 synchronized (mLock) { 225 checkServiceIsReady(); 226 getServiceInterface(mBinder).changeCapabilitiesConfiguration(request, callback); 227 } 228 } 229 requestPublication(String pidfXml, IPublishResponseCallback responseCallback)230 public void requestPublication(String pidfXml, IPublishResponseCallback responseCallback) 231 throws RemoteException { 232 synchronized (mLock) { 233 checkServiceIsReady(); 234 getServiceInterface(mBinder).publishCapabilities(pidfXml, responseCallback); 235 } 236 } 237 requestCapabilities(List<Uri> uris, ISubscribeResponseCallback c)238 public void requestCapabilities(List<Uri> uris, ISubscribeResponseCallback c) 239 throws RemoteException { 240 synchronized (mLock) { 241 checkServiceIsReady(); 242 getServiceInterface(mBinder).subscribeForCapabilities(uris, c); 243 } 244 } 245 sendOptionsCapabilityRequest(Uri contactUri, List<String> myCapabilities, IOptionsResponseCallback callback)246 public void sendOptionsCapabilityRequest(Uri contactUri, List<String> myCapabilities, 247 IOptionsResponseCallback callback) throws RemoteException { 248 synchronized (mLock) { 249 checkServiceIsReady(); 250 getServiceInterface(mBinder).sendOptionsCapabilityRequest(contactUri, myCapabilities, 251 callback); 252 } 253 } 254 255 @Override 256 @VisibleForTesting retrieveFeatureState()257 public Integer retrieveFeatureState() { 258 if (mBinder != null) { 259 try { 260 return getServiceInterface(mBinder).getFeatureState(); 261 } catch (RemoteException e) { 262 // Status check failed, don't update cache 263 } 264 } 265 return null; 266 } 267 268 @Override onFeatureCapabilitiesUpdated(long capabilities)269 public void onFeatureCapabilitiesUpdated(long capabilities) 270 { 271 // doesn't do anything for RCS yet. 272 } 273 274 @VisibleForTesting getServiceInterface(IBinder b)275 public IImsRcsFeature getServiceInterface(IBinder b) { 276 return IImsRcsFeature.Stub.asInterface(b); 277 } log(String s)278 private void log(String s) { 279 Rlog.d(TAG + " [" + mSlotId + "]", s); 280 } 281 logi(String s)282 private void logi(String s) { 283 Rlog.i(TAG + " [" + mSlotId + "]", s); 284 } 285 loge(String s)286 private void loge(String s) { 287 Rlog.e(TAG + " [" + mSlotId + "]", s); 288 } 289 } 290