blob: f3489194370afde6864a488153ed6c2e6a96b7ba [file] [log] [blame]
Brad Ebinger89fb5642017-11-06 15:17:32 -08001/*
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
17package com.android.ims;
18
19import android.app.PendingIntent;
20import android.os.IBinder;
21import android.os.Message;
22import android.os.RemoteException;
Brad Ebinger89fb5642017-11-06 15:17:32 -080023import android.telephony.ims.feature.ImsFeature;
24import android.util.Log;
25
26import com.android.ims.internal.IImsCallSession;
27import com.android.ims.internal.IImsCallSessionListener;
28import com.android.ims.internal.IImsConfig;
29import com.android.ims.internal.IImsEcbm;
Brad Ebingerf3cda822017-11-09 10:25:46 -080030import com.android.ims.internal.IImsMMTelFeature;
Brad Ebinger89fb5642017-11-06 15:17:32 -080031import com.android.ims.internal.IImsMultiEndpoint;
32import com.android.ims.internal.IImsRegistrationListener;
Brad Ebingerf3cda822017-11-09 10:25:46 -080033import com.android.ims.internal.IImsServiceFeatureCallback;
Brad Ebinger89fb5642017-11-06 15:17:32 -080034import com.android.ims.internal.IImsUt;
35
36/**
37 * A container of the IImsServiceController binder, which implements all of the ImsFeatures that
38 * the platform currently supports: MMTel and RCS.
39 * @hide
40 */
41
Brad Ebinger3c7f2f42017-11-07 11:08:11 -080042public class ImsServiceProxy {
Brad Ebinger89fb5642017-11-06 15:17:32 -080043
44 protected String LOG_TAG = "ImsServiceProxy";
45 protected final int mSlotId;
46 protected IBinder mBinder;
47 private final int mSupportedFeature;
48
49 // Start by assuming the proxy is available for usage.
50 private boolean mIsAvailable = true;
51 // ImsFeature Status from the ImsService. Cached.
52 private Integer mFeatureStatusCached = null;
53 private ImsServiceProxy.INotifyStatusChanged mStatusCallback;
54 private final Object mLock = new Object();
55
56 public interface INotifyStatusChanged {
57 void notifyStatusChanged();
58 }
59
Brad Ebingerf3cda822017-11-09 10:25:46 -080060 private final IImsServiceFeatureCallback mListenerBinder =
61 new IImsServiceFeatureCallback.Stub() {
Brad Ebinger89fb5642017-11-06 15:17:32 -080062
63 @Override
64 public void imsFeatureCreated(int slotId, int feature) throws RemoteException {
65 // The feature has been re-enabled. This may happen when the service crashes.
66 synchronized (mLock) {
67 if (!mIsAvailable && mSlotId == slotId && feature == mSupportedFeature) {
68 Log.i(LOG_TAG, "Feature enabled on slotId: " + slotId + " for feature: " +
69 feature);
70 mIsAvailable = true;
71 }
72 }
73 }
74
75 @Override
76 public void imsFeatureRemoved(int slotId, int feature) throws RemoteException {
77 synchronized (mLock) {
78 if (mIsAvailable && mSlotId == slotId && feature == mSupportedFeature) {
79 Log.i(LOG_TAG, "Feature disabled on slotId: " + slotId + " for feature: " +
80 feature);
81 mIsAvailable = false;
82 }
83 }
84 }
85
86 @Override
87 public void imsStatusChanged(int slotId, int feature, int status) throws RemoteException {
88 synchronized (mLock) {
89 Log.i(LOG_TAG, "imsStatusChanged: slot: " + slotId + " feature: " + feature +
90 " status: " + status);
91 if (mSlotId == slotId && feature == mSupportedFeature) {
92 mFeatureStatusCached = status;
93 if (mStatusCallback != null) {
94 mStatusCallback.notifyStatusChanged();
95 }
96 }
97 }
98 }
99 };
100
101 public ImsServiceProxy(int slotId, IBinder binder, int featureType) {
102 mSlotId = slotId;
103 mBinder = binder;
104 mSupportedFeature = featureType;
105 }
106
107 public ImsServiceProxy(int slotId, int featureType) {
108 this(slotId, null, featureType);
109 }
110
Brad Ebingerf3cda822017-11-09 10:25:46 -0800111 public IImsServiceFeatureCallback getListener() {
Brad Ebinger89fb5642017-11-06 15:17:32 -0800112 return mListenerBinder;
113 }
114
115 public void setBinder(IBinder binder) {
116 mBinder = binder;
117 }
118
Brad Ebinger89fb5642017-11-06 15:17:32 -0800119 public int startSession(PendingIntent incomingCallIntent, IImsRegistrationListener listener)
120 throws RemoteException {
121 synchronized (mLock) {
122 checkServiceIsReady();
Brad Ebingerf3cda822017-11-09 10:25:46 -0800123 return getServiceInterface(mBinder).startSession(incomingCallIntent, listener);
Brad Ebinger89fb5642017-11-06 15:17:32 -0800124 }
125 }
126
Brad Ebinger89fb5642017-11-06 15:17:32 -0800127 public void endSession(int sessionId) throws RemoteException {
128 synchronized (mLock) {
129 // Only check to make sure the binder connection still exists. This method should
130 // still be able to be called when the state is STATE_NOT_AVAILABLE.
131 checkBinderConnection();
Brad Ebingerf3cda822017-11-09 10:25:46 -0800132 getServiceInterface(mBinder).endSession(sessionId);
Brad Ebinger89fb5642017-11-06 15:17:32 -0800133 }
134 }
135
Brad Ebinger89fb5642017-11-06 15:17:32 -0800136 public boolean isConnected(int callServiceType, int callType)
137 throws RemoteException {
138 synchronized (mLock) {
139 checkServiceIsReady();
Brad Ebingerf3cda822017-11-09 10:25:46 -0800140 return getServiceInterface(mBinder).isConnected(callServiceType, callType);
Brad Ebinger89fb5642017-11-06 15:17:32 -0800141 }
142 }
143
Brad Ebinger89fb5642017-11-06 15:17:32 -0800144 public boolean isOpened() throws RemoteException {
145 synchronized (mLock) {
146 checkServiceIsReady();
Brad Ebingerf3cda822017-11-09 10:25:46 -0800147 return getServiceInterface(mBinder).isOpened();
Brad Ebinger89fb5642017-11-06 15:17:32 -0800148 }
149 }
150
Brad Ebinger89fb5642017-11-06 15:17:32 -0800151 public void addRegistrationListener(IImsRegistrationListener listener)
152 throws RemoteException {
153 synchronized (mLock) {
154 checkServiceIsReady();
Brad Ebingerf3cda822017-11-09 10:25:46 -0800155 getServiceInterface(mBinder).addRegistrationListener(listener);
Brad Ebinger89fb5642017-11-06 15:17:32 -0800156 }
157 }
158
Brad Ebinger89fb5642017-11-06 15:17:32 -0800159 public void removeRegistrationListener(IImsRegistrationListener listener)
160 throws RemoteException {
161 synchronized (mLock) {
162 checkServiceIsReady();
Brad Ebingerf3cda822017-11-09 10:25:46 -0800163 getServiceInterface(mBinder).removeRegistrationListener(listener);
Brad Ebinger89fb5642017-11-06 15:17:32 -0800164 }
165 }
166
Brad Ebinger89fb5642017-11-06 15:17:32 -0800167 public ImsCallProfile createCallProfile(int sessionId, int callServiceType, int callType)
168 throws RemoteException {
169 synchronized (mLock) {
170 checkServiceIsReady();
Brad Ebingerf3cda822017-11-09 10:25:46 -0800171 return getServiceInterface(mBinder).createCallProfile(sessionId, callServiceType,
172 callType);
Brad Ebinger89fb5642017-11-06 15:17:32 -0800173 }
174 }
175
Brad Ebinger89fb5642017-11-06 15:17:32 -0800176 public IImsCallSession createCallSession(int sessionId, ImsCallProfile profile,
177 IImsCallSessionListener listener) throws RemoteException {
178 synchronized (mLock) {
179 checkServiceIsReady();
Brad Ebingerf3cda822017-11-09 10:25:46 -0800180 return getServiceInterface(mBinder).createCallSession(sessionId, profile, listener);
Brad Ebinger89fb5642017-11-06 15:17:32 -0800181 }
182 }
183
Brad Ebinger89fb5642017-11-06 15:17:32 -0800184 public IImsCallSession getPendingCallSession(int sessionId, String callId)
185 throws RemoteException {
186 synchronized (mLock) {
187 checkServiceIsReady();
Brad Ebingerf3cda822017-11-09 10:25:46 -0800188 return getServiceInterface(mBinder).getPendingCallSession(sessionId, callId);
Brad Ebinger89fb5642017-11-06 15:17:32 -0800189 }
190 }
191
Brad Ebinger89fb5642017-11-06 15:17:32 -0800192 public IImsUt getUtInterface() throws RemoteException {
193 synchronized (mLock) {
194 checkServiceIsReady();
Brad Ebingerf3cda822017-11-09 10:25:46 -0800195 return getServiceInterface(mBinder).getUtInterface();
Brad Ebinger89fb5642017-11-06 15:17:32 -0800196 }
197 }
198
Brad Ebinger89fb5642017-11-06 15:17:32 -0800199 public IImsConfig getConfigInterface() throws RemoteException {
200 synchronized (mLock) {
201 checkServiceIsReady();
Brad Ebingerf3cda822017-11-09 10:25:46 -0800202 return getServiceInterface(mBinder).getConfigInterface();
Brad Ebinger89fb5642017-11-06 15:17:32 -0800203 }
204 }
205
Brad Ebinger89fb5642017-11-06 15:17:32 -0800206 public void turnOnIms() throws RemoteException {
207 synchronized (mLock) {
208 checkServiceIsReady();
Brad Ebingerf3cda822017-11-09 10:25:46 -0800209 getServiceInterface(mBinder).turnOnIms();
Brad Ebinger89fb5642017-11-06 15:17:32 -0800210 }
211 }
212
Brad Ebinger89fb5642017-11-06 15:17:32 -0800213 public void turnOffIms() throws RemoteException {
214 synchronized (mLock) {
215 checkServiceIsReady();
Brad Ebingerf3cda822017-11-09 10:25:46 -0800216 getServiceInterface(mBinder).turnOffIms();
Brad Ebinger89fb5642017-11-06 15:17:32 -0800217 }
218 }
219
Brad Ebinger89fb5642017-11-06 15:17:32 -0800220 public IImsEcbm getEcbmInterface() throws RemoteException {
221 synchronized (mLock) {
222 checkServiceIsReady();
Brad Ebingerf3cda822017-11-09 10:25:46 -0800223 return getServiceInterface(mBinder).getEcbmInterface();
Brad Ebinger89fb5642017-11-06 15:17:32 -0800224 }
225 }
226
Brad Ebinger89fb5642017-11-06 15:17:32 -0800227 public void setUiTTYMode(int uiTtyMode, Message onComplete)
228 throws RemoteException {
229 synchronized (mLock) {
230 checkServiceIsReady();
Brad Ebingerf3cda822017-11-09 10:25:46 -0800231 getServiceInterface(mBinder).setUiTTYMode(uiTtyMode, onComplete);
Brad Ebinger89fb5642017-11-06 15:17:32 -0800232 }
233 }
234
Brad Ebinger89fb5642017-11-06 15:17:32 -0800235 public IImsMultiEndpoint getMultiEndpointInterface() throws RemoteException {
236 synchronized (mLock) {
237 checkServiceIsReady();
Brad Ebingerf3cda822017-11-09 10:25:46 -0800238 return getServiceInterface(mBinder).getMultiEndpointInterface();
Brad Ebinger89fb5642017-11-06 15:17:32 -0800239 }
240 }
241
242 /**
243 * @return an integer describing the current Feature Status, defined in
244 * {@link ImsFeature.ImsState}.
245 */
246 public int getFeatureStatus() {
247 synchronized (mLock) {
248 if (isBinderAlive() && mFeatureStatusCached != null) {
249 Log.i(LOG_TAG, "getFeatureStatus - returning cached: " + mFeatureStatusCached);
250 return mFeatureStatusCached;
251 }
252 }
253 // Don't synchronize on Binder call.
254 Integer status = retrieveFeatureStatus();
255 synchronized (mLock) {
256 if (status == null) {
257 return ImsFeature.STATE_NOT_AVAILABLE;
258 }
259 // Cache only non-null value for feature status.
260 mFeatureStatusCached = status;
261 }
262 Log.i(LOG_TAG, "getFeatureStatus - returning " + status);
263 return status;
264 }
265
266 /**
267 * Internal method used to retrieve the feature status from the corresponding ImsService.
268 */
269 private Integer retrieveFeatureStatus() {
270 if (mBinder != null) {
271 try {
Brad Ebingerf3cda822017-11-09 10:25:46 -0800272 return getServiceInterface(mBinder).getFeatureStatus();
Brad Ebinger89fb5642017-11-06 15:17:32 -0800273 } catch (RemoteException e) {
274 // Status check failed, don't update cache
275 }
276 }
277 return null;
278 }
279
280 /**
281 * @param c Callback that will fire when the feature status has changed.
282 */
283 public void setStatusCallback(INotifyStatusChanged c) {
284 mStatusCallback = c;
285 }
286
287 /**
288 * @return Returns true if the ImsService is ready to take commands, false otherwise. If this
289 * method returns false, it doesn't mean that the Binder connection is not available (use
290 * {@link #isBinderReady()} to check that), but that the ImsService is not accepting commands
291 * at this time.
292 *
293 * For example, for DSDS devices, only one slot can be {@link ImsFeature#STATE_READY} to take
294 * commands at a time, so the other slot must stay at {@link ImsFeature#STATE_NOT_AVAILABLE}.
295 */
296 public boolean isBinderReady() {
297 return isBinderAlive() && getFeatureStatus() == ImsFeature.STATE_READY;
298 }
299
300 /**
301 * @return false if the binder connection is no longer alive.
302 */
303 public boolean isBinderAlive() {
304 return mIsAvailable && mBinder != null && mBinder.isBinderAlive();
305 }
306
307 protected void checkServiceIsReady() throws RemoteException {
308 if (!isBinderReady()) {
309 throw new RemoteException("ImsServiceProxy is not ready to accept commands.");
310 }
311 }
312
Brad Ebingerf3cda822017-11-09 10:25:46 -0800313 private IImsMMTelFeature getServiceInterface(IBinder b) {
314 return IImsMMTelFeature.Stub.asInterface(b);
Brad Ebinger89fb5642017-11-06 15:17:32 -0800315 }
316
317 protected void checkBinderConnection() throws RemoteException {
318 if (!isBinderAlive()) {
319 throw new RemoteException("ImsServiceProxy is not available for that feature.");
320 }
321 }
322}