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