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