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); 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); 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, IImsRcsFeature feature, IImsConfig c, IImsRegistration r, ISipTransport s)121 public RcsFeatureConnection(Context context, int slotId, IImsRcsFeature feature, IImsConfig c, 122 IImsRegistration r, ISipTransport s) { 123 super(context, slotId, 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.removeCallbackForSubscription(cb, subId); 188 } 189 removeCallbackForSubscription(int subId, IImsRegistrationCallback cb)190 public void removeCallbackForSubscription(int subId, IImsRegistrationCallback cb) { 191 mRegistrationCallbackManager.removeCallbackForSubscription(cb, subId); 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