blob: a2df36bdbacc9537e6b999a178cd7211246fd710 [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
Brad Ebinger0e170c72017-12-14 14:24:02 -080019import android.annotation.Nullable;
Brad Ebinger89fb5642017-11-06 15:17:32 -080020import android.app.PendingIntent;
Brad Ebinger0e170c72017-12-14 14:24:02 -080021import android.content.Context;
Brad Ebinger89fb5642017-11-06 15:17:32 -080022import android.os.IBinder;
23import android.os.Message;
24import android.os.RemoteException;
Brad Ebinger0e170c72017-12-14 14:24:02 -080025import android.telephony.Rlog;
26import android.telephony.TelephonyManager;
Brad Ebinger89fb5642017-11-06 15:17:32 -080027import android.telephony.ims.feature.ImsFeature;
28import android.util.Log;
29
30import com.android.ims.internal.IImsCallSession;
31import com.android.ims.internal.IImsCallSessionListener;
32import com.android.ims.internal.IImsConfig;
33import com.android.ims.internal.IImsEcbm;
Brad Ebingerf3cda822017-11-09 10:25:46 -080034import com.android.ims.internal.IImsMMTelFeature;
Brad Ebinger89fb5642017-11-06 15:17:32 -080035import com.android.ims.internal.IImsMultiEndpoint;
Brad Ebinger0e170c72017-12-14 14:24:02 -080036import com.android.ims.internal.IImsRegistration;
Brad Ebinger89fb5642017-11-06 15:17:32 -080037import com.android.ims.internal.IImsRegistrationListener;
Brad Ebingerf3cda822017-11-09 10:25:46 -080038import com.android.ims.internal.IImsServiceFeatureCallback;
Brad Ebinger89fb5642017-11-06 15:17:32 -080039import com.android.ims.internal.IImsUt;
40
41/**
42 * A container of the IImsServiceController binder, which implements all of the ImsFeatures that
43 * the platform currently supports: MMTel and RCS.
44 * @hide
45 */
46
Brad Ebinger3c7f2f42017-11-07 11:08:11 -080047public class ImsServiceProxy {
Brad Ebinger89fb5642017-11-06 15:17:32 -080048
Brad Ebinger0e170c72017-12-14 14:24:02 -080049 protected static final String TAG = "ImsServiceProxy";
Brad Ebinger89fb5642017-11-06 15:17:32 -080050 protected final int mSlotId;
51 protected IBinder mBinder;
52 private final int mSupportedFeature;
Brad Ebinger0e170c72017-12-14 14:24:02 -080053 private Context mContext;
Brad Ebinger89fb5642017-11-06 15:17:32 -080054
55 // Start by assuming the proxy is available for usage.
56 private boolean mIsAvailable = true;
57 // ImsFeature Status from the ImsService. Cached.
58 private Integer mFeatureStatusCached = null;
Brad Ebinger0e170c72017-12-14 14:24:02 -080059 private IFeatureUpdate mStatusCallback;
Brad Ebinger89fb5642017-11-06 15:17:32 -080060 private final Object mLock = new Object();
61
Brad Ebinger0e170c72017-12-14 14:24:02 -080062 public static ImsServiceProxy create(Context context , int slotId) {
63 ImsServiceProxy serviceProxy = new ImsServiceProxy(context, slotId, ImsFeature.MMTEL);
64
65 TelephonyManager tm = getTelephonyManager(context);
66 if (tm == null) {
67 Rlog.w(TAG, "getServiceProxy: TelephonyManager is null!");
68 // Binder can be unset in this case because it will be torn down/recreated as part of
69 // a retry mechanism until the serviceProxy binder is set successfully.
70 return serviceProxy;
71 }
72
73 IImsMMTelFeature binder = tm.getImsMMTelFeatureAndListen(slotId,
74 serviceProxy.getListener());
75 if (binder != null) {
76 serviceProxy.setBinder(binder.asBinder());
77 // Trigger the cache to be updated for feature status.
78 serviceProxy.getFeatureStatus();
79 } else {
80 Rlog.w(TAG, "getServiceProxy: binder is null! Phone Id: " + slotId);
81 }
82 return serviceProxy;
83 }
84
85 public static TelephonyManager getTelephonyManager(Context context) {
86 return (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
87 }
88
89 public interface IFeatureUpdate {
90 /**
91 * Called when the ImsFeature has changed its state. Use
92 * {@link ImsFeature#getFeatureState()} to get the new state.
93 */
94 void notifyStateChanged();
95
96 /**
97 * Called when the ImsFeature has become unavailable due to the binder switching or app
98 * crashing. A new ImsServiceProxy should be requested for that feature.
99 */
100 void notifyUnavailable();
Brad Ebinger89fb5642017-11-06 15:17:32 -0800101 }
102
Brad Ebingerf3cda822017-11-09 10:25:46 -0800103 private final IImsServiceFeatureCallback mListenerBinder =
104 new IImsServiceFeatureCallback.Stub() {
Brad Ebinger89fb5642017-11-06 15:17:32 -0800105
106 @Override
107 public void imsFeatureCreated(int slotId, int feature) throws RemoteException {
108 // The feature has been re-enabled. This may happen when the service crashes.
109 synchronized (mLock) {
110 if (!mIsAvailable && mSlotId == slotId && feature == mSupportedFeature) {
Brad Ebinger0e170c72017-12-14 14:24:02 -0800111 Log.i(TAG, "Feature enabled on slotId: " + slotId + " for feature: " +
Brad Ebinger89fb5642017-11-06 15:17:32 -0800112 feature);
113 mIsAvailable = true;
114 }
115 }
116 }
117
118 @Override
119 public void imsFeatureRemoved(int slotId, int feature) throws RemoteException {
120 synchronized (mLock) {
121 if (mIsAvailable && mSlotId == slotId && feature == mSupportedFeature) {
Brad Ebinger0e170c72017-12-14 14:24:02 -0800122 Log.i(TAG, "Feature disabled on slotId: " + slotId + " for feature: " +
Brad Ebinger89fb5642017-11-06 15:17:32 -0800123 feature);
124 mIsAvailable = false;
Brad Ebinger0e170c72017-12-14 14:24:02 -0800125 if (mStatusCallback != null) {
126 mStatusCallback.notifyUnavailable();
127 }
Brad Ebinger89fb5642017-11-06 15:17:32 -0800128 }
129 }
130 }
131
132 @Override
133 public void imsStatusChanged(int slotId, int feature, int status) throws RemoteException {
134 synchronized (mLock) {
Brad Ebinger0e170c72017-12-14 14:24:02 -0800135 Log.i(TAG, "imsStatusChanged: slot: " + slotId + " feature: " + feature +
Brad Ebinger89fb5642017-11-06 15:17:32 -0800136 " status: " + status);
137 if (mSlotId == slotId && feature == mSupportedFeature) {
138 mFeatureStatusCached = status;
139 if (mStatusCallback != null) {
Brad Ebinger0e170c72017-12-14 14:24:02 -0800140 mStatusCallback.notifyStateChanged();
Brad Ebinger89fb5642017-11-06 15:17:32 -0800141 }
142 }
143 }
144 }
145 };
146
Brad Ebinger3418c132018-01-18 12:03:33 -0800147 public ImsServiceProxy(Context context, int slotId, IBinder binder, int featureType) {
Brad Ebinger89fb5642017-11-06 15:17:32 -0800148 mSlotId = slotId;
149 mBinder = binder;
150 mSupportedFeature = featureType;
Brad Ebinger3418c132018-01-18 12:03:33 -0800151 mContext = context;
Brad Ebinger89fb5642017-11-06 15:17:32 -0800152 }
153
Brad Ebinger0e170c72017-12-14 14:24:02 -0800154 public ImsServiceProxy(Context context, int slotId, int featureType) {
Brad Ebinger3418c132018-01-18 12:03:33 -0800155 this(context, slotId, null, featureType);
Brad Ebinger0e170c72017-12-14 14:24:02 -0800156 }
157
158 public @Nullable IImsRegistration getRegistration() {
159 TelephonyManager tm = getTelephonyManager(mContext);
160 return tm != null ? tm.getImsRegistration(mSlotId, ImsFeature.MMTEL) : null;
Brad Ebinger89fb5642017-11-06 15:17:32 -0800161 }
162
Brad Ebingerf3cda822017-11-09 10:25:46 -0800163 public IImsServiceFeatureCallback getListener() {
Brad Ebinger89fb5642017-11-06 15:17:32 -0800164 return mListenerBinder;
165 }
166
167 public void setBinder(IBinder binder) {
168 mBinder = binder;
169 }
170
Brad Ebinger89fb5642017-11-06 15:17:32 -0800171 public int startSession(PendingIntent incomingCallIntent, IImsRegistrationListener listener)
172 throws RemoteException {
173 synchronized (mLock) {
174 checkServiceIsReady();
Brad Ebingerf3cda822017-11-09 10:25:46 -0800175 return getServiceInterface(mBinder).startSession(incomingCallIntent, listener);
Brad Ebinger89fb5642017-11-06 15:17:32 -0800176 }
177 }
178
Brad Ebinger89fb5642017-11-06 15:17:32 -0800179 public void endSession(int sessionId) throws RemoteException {
180 synchronized (mLock) {
181 // Only check to make sure the binder connection still exists. This method should
182 // still be able to be called when the state is STATE_NOT_AVAILABLE.
183 checkBinderConnection();
Brad Ebingerf3cda822017-11-09 10:25:46 -0800184 getServiceInterface(mBinder).endSession(sessionId);
Brad Ebinger89fb5642017-11-06 15:17:32 -0800185 }
186 }
187
Brad Ebinger89fb5642017-11-06 15:17:32 -0800188 public boolean isConnected(int callServiceType, int callType)
189 throws RemoteException {
190 synchronized (mLock) {
191 checkServiceIsReady();
Brad Ebingerf3cda822017-11-09 10:25:46 -0800192 return getServiceInterface(mBinder).isConnected(callServiceType, callType);
Brad Ebinger89fb5642017-11-06 15:17:32 -0800193 }
194 }
195
Brad Ebinger89fb5642017-11-06 15:17:32 -0800196 public boolean isOpened() throws RemoteException {
197 synchronized (mLock) {
198 checkServiceIsReady();
Brad Ebingerf3cda822017-11-09 10:25:46 -0800199 return getServiceInterface(mBinder).isOpened();
Brad Ebinger89fb5642017-11-06 15:17:32 -0800200 }
201 }
202
Brad Ebinger89fb5642017-11-06 15:17:32 -0800203 public void addRegistrationListener(IImsRegistrationListener listener)
204 throws RemoteException {
205 synchronized (mLock) {
206 checkServiceIsReady();
Brad Ebingerf3cda822017-11-09 10:25:46 -0800207 getServiceInterface(mBinder).addRegistrationListener(listener);
Brad Ebinger89fb5642017-11-06 15:17:32 -0800208 }
209 }
210
Brad Ebinger89fb5642017-11-06 15:17:32 -0800211 public void removeRegistrationListener(IImsRegistrationListener listener)
212 throws RemoteException {
213 synchronized (mLock) {
214 checkServiceIsReady();
Brad Ebingerf3cda822017-11-09 10:25:46 -0800215 getServiceInterface(mBinder).removeRegistrationListener(listener);
Brad Ebinger89fb5642017-11-06 15:17:32 -0800216 }
217 }
218
Brad Ebinger89fb5642017-11-06 15:17:32 -0800219 public ImsCallProfile createCallProfile(int sessionId, int callServiceType, int callType)
220 throws RemoteException {
221 synchronized (mLock) {
222 checkServiceIsReady();
Brad Ebingerf3cda822017-11-09 10:25:46 -0800223 return getServiceInterface(mBinder).createCallProfile(sessionId, callServiceType,
224 callType);
Brad Ebinger89fb5642017-11-06 15:17:32 -0800225 }
226 }
227
Brad Ebinger89fb5642017-11-06 15:17:32 -0800228 public IImsCallSession createCallSession(int sessionId, ImsCallProfile profile,
229 IImsCallSessionListener listener) throws RemoteException {
230 synchronized (mLock) {
231 checkServiceIsReady();
Brad Ebingerf3cda822017-11-09 10:25:46 -0800232 return getServiceInterface(mBinder).createCallSession(sessionId, profile, listener);
Brad Ebinger89fb5642017-11-06 15:17:32 -0800233 }
234 }
235
Brad Ebinger89fb5642017-11-06 15:17:32 -0800236 public IImsCallSession getPendingCallSession(int sessionId, String callId)
237 throws RemoteException {
238 synchronized (mLock) {
239 checkServiceIsReady();
Brad Ebingerf3cda822017-11-09 10:25:46 -0800240 return getServiceInterface(mBinder).getPendingCallSession(sessionId, callId);
Brad Ebinger89fb5642017-11-06 15:17:32 -0800241 }
242 }
243
Brad Ebinger89fb5642017-11-06 15:17:32 -0800244 public IImsUt getUtInterface() throws RemoteException {
245 synchronized (mLock) {
246 checkServiceIsReady();
Brad Ebingerf3cda822017-11-09 10:25:46 -0800247 return getServiceInterface(mBinder).getUtInterface();
Brad Ebinger89fb5642017-11-06 15:17:32 -0800248 }
249 }
250
Brad Ebinger89fb5642017-11-06 15:17:32 -0800251 public IImsConfig getConfigInterface() throws RemoteException {
252 synchronized (mLock) {
253 checkServiceIsReady();
Brad Ebingerf3cda822017-11-09 10:25:46 -0800254 return getServiceInterface(mBinder).getConfigInterface();
Brad Ebinger89fb5642017-11-06 15:17:32 -0800255 }
256 }
257
Brad Ebinger89fb5642017-11-06 15:17:32 -0800258 public void turnOnIms() throws RemoteException {
259 synchronized (mLock) {
260 checkServiceIsReady();
Brad Ebingerf3cda822017-11-09 10:25:46 -0800261 getServiceInterface(mBinder).turnOnIms();
Brad Ebinger89fb5642017-11-06 15:17:32 -0800262 }
263 }
264
Brad Ebinger89fb5642017-11-06 15:17:32 -0800265 public void turnOffIms() throws RemoteException {
266 synchronized (mLock) {
267 checkServiceIsReady();
Brad Ebingerf3cda822017-11-09 10:25:46 -0800268 getServiceInterface(mBinder).turnOffIms();
Brad Ebinger89fb5642017-11-06 15:17:32 -0800269 }
270 }
271
Brad Ebinger89fb5642017-11-06 15:17:32 -0800272 public IImsEcbm getEcbmInterface() throws RemoteException {
273 synchronized (mLock) {
274 checkServiceIsReady();
Brad Ebingerf3cda822017-11-09 10:25:46 -0800275 return getServiceInterface(mBinder).getEcbmInterface();
Brad Ebinger89fb5642017-11-06 15:17:32 -0800276 }
277 }
278
Brad Ebinger89fb5642017-11-06 15:17:32 -0800279 public void setUiTTYMode(int uiTtyMode, Message onComplete)
280 throws RemoteException {
281 synchronized (mLock) {
282 checkServiceIsReady();
Brad Ebingerf3cda822017-11-09 10:25:46 -0800283 getServiceInterface(mBinder).setUiTTYMode(uiTtyMode, onComplete);
Brad Ebinger89fb5642017-11-06 15:17:32 -0800284 }
285 }
286
Brad Ebinger89fb5642017-11-06 15:17:32 -0800287 public IImsMultiEndpoint getMultiEndpointInterface() throws RemoteException {
288 synchronized (mLock) {
289 checkServiceIsReady();
Brad Ebingerf3cda822017-11-09 10:25:46 -0800290 return getServiceInterface(mBinder).getMultiEndpointInterface();
Brad Ebinger89fb5642017-11-06 15:17:32 -0800291 }
292 }
293
294 /**
295 * @return an integer describing the current Feature Status, defined in
296 * {@link ImsFeature.ImsState}.
297 */
298 public int getFeatureStatus() {
299 synchronized (mLock) {
300 if (isBinderAlive() && mFeatureStatusCached != null) {
Brad Ebinger0e170c72017-12-14 14:24:02 -0800301 Log.i(TAG, "getFeatureStatus - returning cached: " + mFeatureStatusCached);
Brad Ebinger89fb5642017-11-06 15:17:32 -0800302 return mFeatureStatusCached;
303 }
304 }
305 // Don't synchronize on Binder call.
306 Integer status = retrieveFeatureStatus();
307 synchronized (mLock) {
308 if (status == null) {
309 return ImsFeature.STATE_NOT_AVAILABLE;
310 }
311 // Cache only non-null value for feature status.
312 mFeatureStatusCached = status;
313 }
Brad Ebinger0e170c72017-12-14 14:24:02 -0800314 Log.i(TAG, "getFeatureStatus - returning " + status);
Brad Ebinger89fb5642017-11-06 15:17:32 -0800315 return status;
316 }
317
318 /**
319 * Internal method used to retrieve the feature status from the corresponding ImsService.
320 */
321 private Integer retrieveFeatureStatus() {
322 if (mBinder != null) {
323 try {
Brad Ebingerf3cda822017-11-09 10:25:46 -0800324 return getServiceInterface(mBinder).getFeatureStatus();
Brad Ebinger89fb5642017-11-06 15:17:32 -0800325 } catch (RemoteException e) {
326 // Status check failed, don't update cache
327 }
328 }
329 return null;
330 }
331
332 /**
333 * @param c Callback that will fire when the feature status has changed.
334 */
Brad Ebinger0e170c72017-12-14 14:24:02 -0800335 public void setStatusCallback(IFeatureUpdate c) {
Brad Ebinger89fb5642017-11-06 15:17:32 -0800336 mStatusCallback = c;
337 }
338
339 /**
340 * @return Returns true if the ImsService is ready to take commands, false otherwise. If this
341 * method returns false, it doesn't mean that the Binder connection is not available (use
342 * {@link #isBinderReady()} to check that), but that the ImsService is not accepting commands
343 * at this time.
344 *
345 * For example, for DSDS devices, only one slot can be {@link ImsFeature#STATE_READY} to take
346 * commands at a time, so the other slot must stay at {@link ImsFeature#STATE_NOT_AVAILABLE}.
347 */
348 public boolean isBinderReady() {
349 return isBinderAlive() && getFeatureStatus() == ImsFeature.STATE_READY;
350 }
351
352 /**
353 * @return false if the binder connection is no longer alive.
354 */
355 public boolean isBinderAlive() {
356 return mIsAvailable && mBinder != null && mBinder.isBinderAlive();
357 }
358
359 protected void checkServiceIsReady() throws RemoteException {
360 if (!isBinderReady()) {
361 throw new RemoteException("ImsServiceProxy is not ready to accept commands.");
362 }
363 }
364
Brad Ebingerf3cda822017-11-09 10:25:46 -0800365 private IImsMMTelFeature getServiceInterface(IBinder b) {
366 return IImsMMTelFeature.Stub.asInterface(b);
Brad Ebinger89fb5642017-11-06 15:17:32 -0800367 }
368
369 protected void checkBinderConnection() throws RemoteException {
370 if (!isBinderAlive()) {
371 throw new RemoteException("ImsServiceProxy is not available for that feature.");
372 }
373 }
374}