blob: d6954f3f6960487fda0203f3c9c5cff977d2a52f [file] [log] [blame]
Brad Ebinger936a7d12018-01-16 09:36:56 -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.annotation.Nullable;
20import android.content.Context;
21import android.net.Uri;
22import android.os.IBinder;
23import android.os.Message;
24import android.os.RemoteException;
25import android.telephony.Rlog;
26import android.telephony.TelephonyManager;
Brad Ebingered690772018-01-23 13:41:32 -080027import android.telephony.ims.ImsCallProfile;
28import android.telephony.ims.ImsReasonInfo;
Brad Ebinger936a7d12018-01-16 09:36:56 -080029import android.telephony.ims.aidl.IImsConfig;
30import android.telephony.ims.aidl.IImsMmTelFeature;
31import android.telephony.ims.aidl.IImsRegistration;
32import android.telephony.ims.aidl.IImsRegistrationCallback;
33import android.telephony.ims.aidl.IImsSmsListener;
34import android.telephony.ims.feature.CapabilityChangeRequest;
35import android.telephony.ims.feature.ImsFeature;
36import android.telephony.ims.feature.MmTelFeature;
37import android.telephony.ims.stub.ImsRegistrationImplBase;
38import android.telephony.ims.stub.ImsSmsImplBase;
39import android.util.Log;
40
41import com.android.ims.internal.IImsCallSession;
42import com.android.ims.internal.IImsEcbm;
43import com.android.ims.internal.IImsMultiEndpoint;
44import com.android.ims.internal.IImsServiceFeatureCallback;
45import com.android.ims.internal.IImsUt;
46
Brad Ebinger1050b072018-04-17 16:50:51 -070047import java.util.Collections;
Brad Ebinger936a7d12018-01-16 09:36:56 -080048import java.util.HashSet;
49import java.util.Set;
Brad Ebinger1050b072018-04-17 16:50:51 -070050import java.util.concurrent.ConcurrentHashMap;
Brad Ebinger936a7d12018-01-16 09:36:56 -080051
52/**
53 * A container of the IImsServiceController binder, which implements all of the ImsFeatures that
54 * the platform currently supports: MMTel and RCS.
55 * @hide
56 */
57
58public class MmTelFeatureConnection {
59
60 protected static final String TAG = "MmTelFeatureConnection";
61 protected final int mSlotId;
62 protected IBinder mBinder;
63 private Context mContext;
64
Brad Ebingerfe2b2222018-03-08 16:16:15 -080065 private volatile boolean mIsAvailable = false;
Brad Ebinger936a7d12018-01-16 09:36:56 -080066 // ImsFeature Status from the ImsService. Cached.
67 private Integer mFeatureStateCached = null;
68 private IFeatureUpdate mStatusCallback;
69 private final Object mLock = new Object();
Brad Ebingerfe2b2222018-03-08 16:16:15 -080070 // Updated by IImsServiceFeatureCallback when FEATURE_EMERGENCY_MMTEL is sent.
71 private boolean mSupportsEmergencyCalling = false;
Brad Ebinger936a7d12018-01-16 09:36:56 -080072
Brad Ebinger48632582018-03-16 11:46:30 -070073 // Cache the Registration and Config interfaces as long as the MmTel feature is connected. If
74 // it becomes disconnected, invalidate.
75 private IImsRegistration mRegistrationBinder;
76 private IImsConfig mConfigBinder;
Brad Ebinger936a7d12018-01-16 09:36:56 -080077
Brad Ebinger6d1186c2018-04-26 14:23:45 -070078 private IBinder.DeathRecipient mDeathRecipient = () -> {
79 Log.w(TAG, "DeathRecipient triggered, binder died.");
80 onRemovedOrDied();
81 };
82
Brad Ebinger936a7d12018-01-16 09:36:56 -080083 private abstract class CallbackAdapterManager<T> {
84 private static final String TAG = "CallbackAdapterManager";
85
Brad Ebinger1050b072018-04-17 16:50:51 -070086 protected final Set<T> mLocalCallbacks =
87 Collections.newSetFromMap(new ConcurrentHashMap<>());
Brad Ebinger936a7d12018-01-16 09:36:56 -080088 private boolean mHasConnected = false;
89
90 public void addCallback(T localCallback) throws RemoteException {
91 // We only one one binding to the ImsService per process.
92 // Store any more locally.
93 synchronized (mLock) {
Brad Ebinger1050b072018-04-17 16:50:51 -070094 if (!mHasConnected) {
Brad Ebinger936a7d12018-01-16 09:36:56 -080095 // throws a RemoteException if a connection can not be established.
Brad Ebinger1050b072018-04-17 16:50:51 -070096 if (createConnection()) {
Brad Ebinger936a7d12018-01-16 09:36:56 -080097 mHasConnected = true;
98 } else {
99 throw new RemoteException("Can not create connection!");
100 }
101 }
Brad Ebinger936a7d12018-01-16 09:36:56 -0800102 }
Brad Ebinger1050b072018-04-17 16:50:51 -0700103 Log.i(TAG, "Local callback added: " + localCallback);
104 mLocalCallbacks.add(localCallback);
Brad Ebinger936a7d12018-01-16 09:36:56 -0800105 }
106
107 public void removeCallback(T localCallback) {
108 // We only maintain one binding to the ImsService per process.
Brad Ebinger1050b072018-04-17 16:50:51 -0700109 Log.i(TAG, "Local callback removed: " + localCallback);
110 mLocalCallbacks.remove(localCallback);
Brad Ebinger936a7d12018-01-16 09:36:56 -0800111 synchronized (mLock) {
Brad Ebinger1050b072018-04-17 16:50:51 -0700112 // If we have removed all local callbacks, remove callback to ImsService.
Brad Ebinger936a7d12018-01-16 09:36:56 -0800113 if(mHasConnected) {
114 if (mLocalCallbacks.isEmpty()) {
115 removeConnection();
116 mHasConnected = false;
117 }
118 }
119 }
120 }
121
122 public void close() {
123 synchronized (mLock) {
124 if (mHasConnected) {
125 removeConnection();
126 // Still mark the connection as disconnected, even if this fails.
127 mHasConnected = false;
128 }
Brad Ebinger936a7d12018-01-16 09:36:56 -0800129 }
Brad Ebinger1050b072018-04-17 16:50:51 -0700130 Log.i(TAG, "Closing connection and clearing callbacks");
131 mLocalCallbacks.clear();
Brad Ebinger936a7d12018-01-16 09:36:56 -0800132 }
133
134 abstract boolean createConnection() throws RemoteException;
135
136 abstract void removeConnection();
137 }
138 private ImsRegistrationCallbackAdapter mRegistrationCallbackManager
139 = new ImsRegistrationCallbackAdapter();
140 private class ImsRegistrationCallbackAdapter
141 extends CallbackAdapterManager<ImsRegistrationImplBase.Callback> {
142 private final RegistrationCallbackAdapter mRegistrationCallbackAdapter
143 = new RegistrationCallbackAdapter();
144
145 private class RegistrationCallbackAdapter extends IImsRegistrationCallback.Stub {
146
147 @Override
148 public void onRegistered(int imsRadioTech) {
149 Log.i(TAG, "onRegistered ::");
150
Brad Ebinger1050b072018-04-17 16:50:51 -0700151 mLocalCallbacks.forEach(l -> l.onRegistered(imsRadioTech));
Brad Ebinger936a7d12018-01-16 09:36:56 -0800152 }
153
154 @Override
155 public void onRegistering(int imsRadioTech) {
156 Log.i(TAG, "onRegistering ::");
157
Brad Ebinger1050b072018-04-17 16:50:51 -0700158 mLocalCallbacks.forEach(l -> l.onRegistering(imsRadioTech));
Brad Ebinger936a7d12018-01-16 09:36:56 -0800159 }
160
161 @Override
162 public void onDeregistered(ImsReasonInfo imsReasonInfo) {
163 Log.i(TAG, "onDeregistered ::");
164
Brad Ebinger1050b072018-04-17 16:50:51 -0700165 mLocalCallbacks.forEach(l -> l.onDeregistered(imsReasonInfo));
Brad Ebinger936a7d12018-01-16 09:36:56 -0800166 }
167
168 @Override
169 public void onTechnologyChangeFailed(int targetRadioTech, ImsReasonInfo imsReasonInfo) {
170 Log.i(TAG, "onTechnologyChangeFailed :: targetAccessTech=" + targetRadioTech +
171 ", imsReasonInfo=" + imsReasonInfo);
172
Brad Ebinger936a7d12018-01-16 09:36:56 -0800173 mLocalCallbacks.forEach(l -> l.onTechnologyChangeFailed(targetRadioTech,
174 imsReasonInfo));
Brad Ebinger936a7d12018-01-16 09:36:56 -0800175 }
176
177 @Override
178 public void onSubscriberAssociatedUriChanged(Uri[] uris) {
179 Log.i(TAG, "onSubscriberAssociatedUriChanged");
Brad Ebinger1050b072018-04-17 16:50:51 -0700180
181 mLocalCallbacks.forEach(l -> l.onSubscriberAssociatedUriChanged(uris));
Brad Ebinger936a7d12018-01-16 09:36:56 -0800182 }
183 }
184
185 @Override
186 boolean createConnection() throws RemoteException {
187 IImsRegistration imsRegistration = getRegistration();
188 if (imsRegistration != null) {
189 getRegistration().addRegistrationCallback(mRegistrationCallbackAdapter);
190 return true;
191 } else {
192 Log.e(TAG, "ImsRegistration is null");
193 return false;
194 }
195 }
196
197 @Override
198 void removeConnection() {
199 IImsRegistration imsRegistration = getRegistration();
200 if (imsRegistration != null) {
201 try {
Brad Ebingerd1b1a3c2018-03-08 11:37:35 -0800202 getRegistration().removeRegistrationCallback(mRegistrationCallbackAdapter);
Brad Ebinger936a7d12018-01-16 09:36:56 -0800203 } catch (RemoteException e) {
204 Log.w(TAG, "removeConnection: couldn't remove registration callback");
205 }
206 } else {
207 Log.e(TAG, "ImsRegistration is null");
208 }
209 }
210 }
211
212 private final CapabilityCallbackManager mCapabilityCallbackManager
213 = new CapabilityCallbackManager();
214 private class CapabilityCallbackManager
215 extends CallbackAdapterManager<ImsFeature.CapabilityCallback> {
216 private final CapabilityCallbackAdapter mCallbackAdapter = new CapabilityCallbackAdapter();
217
218 private class CapabilityCallbackAdapter extends ImsFeature.CapabilityCallback {
219 // Called when the Capabilities Status on this connection have changed.
220 @Override
221 public void onCapabilitiesStatusChanged(ImsFeature.Capabilities config) {
Brad Ebinger1050b072018-04-17 16:50:51 -0700222 mLocalCallbacks.forEach(
223 callback -> callback.onCapabilitiesStatusChanged(config));
Brad Ebinger936a7d12018-01-16 09:36:56 -0800224 }
225 }
226
227 @Override
228 boolean createConnection() throws RemoteException {
Brad Ebinger1050b072018-04-17 16:50:51 -0700229 IImsMmTelFeature binder;
230 synchronized (mLock) {
231 checkServiceIsReady();
232 binder = getServiceInterface(mBinder);
233 }
Brad Ebinger936a7d12018-01-16 09:36:56 -0800234 if (binder != null) {
235 binder.addCapabilityCallback(mCallbackAdapter);
236 return true;
237 } else {
238 Log.w(TAG, "create: Couldn't get IImsMmTelFeature binder");
239 return false;
240 }
241 }
242
243 @Override
244 void removeConnection() {
Brad Ebinger1050b072018-04-17 16:50:51 -0700245 IImsMmTelFeature binder = null;
246 synchronized (mLock) {
247 try {
248 checkServiceIsReady();
249 binder = getServiceInterface(mBinder);
250 } catch (RemoteException e) {
251 // binder is null
252 }
253 }
Brad Ebinger936a7d12018-01-16 09:36:56 -0800254 if (binder != null) {
255 try {
256 binder.removeCapabilityCallback(mCallbackAdapter);
257 } catch (RemoteException e) {
258 Log.w(TAG, "remove: IImsMmTelFeature binder is dead");
259 }
260 } else {
261 Log.w(TAG, "remove: Couldn't get IImsMmTelFeature binder");
262 }
263 }
264 }
265
266
267 public static MmTelFeatureConnection create(Context context , int slotId) {
268 MmTelFeatureConnection serviceProxy = new MmTelFeatureConnection(context, slotId);
269
270 TelephonyManager tm = getTelephonyManager(context);
271 if (tm == null) {
272 Rlog.w(TAG, "create: TelephonyManager is null!");
273 // Binder can be unset in this case because it will be torn down/recreated as part of
274 // a retry mechanism until the serviceProxy binder is set successfully.
275 return serviceProxy;
276 }
277
278 IImsMmTelFeature binder = tm.getImsMmTelFeatureAndListen(slotId,
279 serviceProxy.getListener());
280 if (binder != null) {
281 serviceProxy.setBinder(binder.asBinder());
282 // Trigger the cache to be updated for feature status.
283 serviceProxy.getFeatureState();
284 } else {
285 Rlog.w(TAG, "create: binder is null! Slot Id: " + slotId);
286 }
287 return serviceProxy;
288 }
289
290 public static TelephonyManager getTelephonyManager(Context context) {
291 return (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
292 }
293
294 public interface IFeatureUpdate {
295 /**
296 * Called when the ImsFeature has changed its state. Use
297 * {@link ImsFeature#getFeatureState()} to get the new state.
298 */
299 void notifyStateChanged();
300
301 /**
302 * Called when the ImsFeature has become unavailable due to the binder switching or app
303 * crashing. A new ImsServiceProxy should be requested for that feature.
304 */
305 void notifyUnavailable();
306 }
307
308 private final IImsServiceFeatureCallback mListenerBinder =
309 new IImsServiceFeatureCallback.Stub() {
310
311 @Override
312 public void imsFeatureCreated(int slotId, int feature) throws RemoteException {
Brad Ebingerfe2b2222018-03-08 16:16:15 -0800313 // The feature has been enabled. This happens when the feature is first created and may
314 // happen when the feature is re-enabled.
Brad Ebinger936a7d12018-01-16 09:36:56 -0800315 synchronized (mLock) {
Brad Ebingerfe2b2222018-03-08 16:16:15 -0800316 if(mSlotId != slotId) {
317 return;
Brad Ebinger936a7d12018-01-16 09:36:56 -0800318 }
Brad Ebingerfe2b2222018-03-08 16:16:15 -0800319 switch (feature) {
320 case ImsFeature.FEATURE_MMTEL: {
321 if (!mIsAvailable) {
322 Log.i(TAG, "MmTel enabled on slotId: " + slotId);
323 mIsAvailable = true;
324 }
325 break;
326 }
327 case ImsFeature.FEATURE_EMERGENCY_MMTEL: {
328 mSupportsEmergencyCalling = true;
329 Log.i(TAG, "Emergency calling enabled on slotId: " + slotId);
330 break;
331 }
332 }
333
Brad Ebinger936a7d12018-01-16 09:36:56 -0800334 }
335 }
336
337 @Override
338 public void imsFeatureRemoved(int slotId, int feature) throws RemoteException {
339 synchronized (mLock) {
Brad Ebingerfe2b2222018-03-08 16:16:15 -0800340 if(mSlotId != slotId) {
341 return;
342 }
343 switch (feature) {
344 case ImsFeature.FEATURE_MMTEL: {
Brad Ebinger6d1186c2018-04-26 14:23:45 -0700345 Log.i(TAG, "MmTel removed on slotId: " + slotId);
346 onRemovedOrDied();
Brad Ebingerfe2b2222018-03-08 16:16:15 -0800347 break;
348 }
349 case ImsFeature.FEATURE_EMERGENCY_MMTEL : {
350 mSupportsEmergencyCalling = false;
351 Log.i(TAG, "Emergency calling disabled on slotId: " + slotId);
352 break;
Brad Ebinger936a7d12018-01-16 09:36:56 -0800353 }
354 }
355 }
356 }
357
358 @Override
359 public void imsStatusChanged(int slotId, int feature, int status) throws RemoteException {
360 synchronized (mLock) {
361 Log.i(TAG, "imsStatusChanged: slot: " + slotId + " feature: " + feature +
362 " status: " + status);
363 if (mSlotId == slotId && feature == ImsFeature.FEATURE_MMTEL) {
364 mFeatureStateCached = status;
365 if (mStatusCallback != null) {
366 mStatusCallback.notifyStateChanged();
367 }
368 }
369 }
370 }
371 };
372
373 public MmTelFeatureConnection(Context context, int slotId) {
374 mSlotId = slotId;
375 mContext = context;
376 }
377
Brad Ebinger6d1186c2018-04-26 14:23:45 -0700378 /**
379 * Called when the MmTelFeature has either been removed by Telephony or crashed.
380 */
381 private void onRemovedOrDied() {
Brad Ebinger48632582018-03-16 11:46:30 -0700382 synchronized (mLock) {
Brad Ebinger6d1186c2018-04-26 14:23:45 -0700383 if (mIsAvailable) {
384 mIsAvailable = false;
385 // invalidate caches.
386 mRegistrationBinder = null;
387 mConfigBinder = null;
388 if (mBinder != null) {
389 mBinder.unlinkToDeath(mDeathRecipient, 0);
390 }
391 if (mStatusCallback != null) {
392 mStatusCallback.notifyUnavailable();
393 }
394 }
Brad Ebinger48632582018-03-16 11:46:30 -0700395 }
396 }
397
Brad Ebinger936a7d12018-01-16 09:36:56 -0800398 private @Nullable IImsRegistration getRegistration() {
Brad Ebinger48632582018-03-16 11:46:30 -0700399 synchronized (mLock) {
400 // null if cache is invalid;
401 if (mRegistrationBinder != null) {
402 return mRegistrationBinder;
403 }
404 }
Brad Ebinger936a7d12018-01-16 09:36:56 -0800405 TelephonyManager tm = getTelephonyManager(mContext);
Brad Ebinger48632582018-03-16 11:46:30 -0700406 // We don't want to synchronize on a binder call to another process.
407 IImsRegistration regBinder = tm != null
408 ? tm.getImsRegistration(mSlotId, ImsFeature.FEATURE_MMTEL) : null;
409 synchronized (mLock) {
410 // mRegistrationBinder may have changed while we tried to get the registration
411 // interface.
412 if (mRegistrationBinder == null) {
413 mRegistrationBinder = regBinder;
414 }
415 }
416 return mRegistrationBinder;
Brad Ebinger936a7d12018-01-16 09:36:56 -0800417 }
418
419 private IImsConfig getConfig() {
Brad Ebinger48632582018-03-16 11:46:30 -0700420 synchronized (mLock) {
421 // null if cache is invalid;
422 if (mConfigBinder != null) {
423 return mConfigBinder;
424 }
425 }
Brad Ebinger936a7d12018-01-16 09:36:56 -0800426 TelephonyManager tm = getTelephonyManager(mContext);
Brad Ebinger48632582018-03-16 11:46:30 -0700427 IImsConfig configBinder = tm != null
428 ? tm.getImsConfig(mSlotId, ImsFeature.FEATURE_MMTEL) : null;
429 synchronized (mLock) {
430 // mConfigBinder may have changed while we tried to get the config interface.
431 if (mConfigBinder == null) {
432 mConfigBinder = configBinder;
433 }
434 }
435 return mConfigBinder;
Brad Ebinger936a7d12018-01-16 09:36:56 -0800436 }
437
Brad Ebingerd449b232018-02-12 14:33:05 -0800438 public boolean isEmergencyMmTelAvailable() {
Brad Ebingerfe2b2222018-03-08 16:16:15 -0800439 return mSupportsEmergencyCalling;
Brad Ebingerd449b232018-02-12 14:33:05 -0800440 }
441
Brad Ebinger936a7d12018-01-16 09:36:56 -0800442 public IImsServiceFeatureCallback getListener() {
443 return mListenerBinder;
444 }
445
446 public void setBinder(IBinder binder) {
Brad Ebinger6d1186c2018-04-26 14:23:45 -0700447 synchronized (mLock) {
448 mBinder = binder;
449 try {
450 if (mBinder != null) {
451 mBinder.linkToDeath(mDeathRecipient, 0);
452 }
453 } catch (RemoteException e) {
454 // No need to do anything if the binder is already dead.
455 }
456 }
Brad Ebinger936a7d12018-01-16 09:36:56 -0800457 }
458
459 /**
460 * Opens the connection to the {@link MmTelFeature} and establishes a listener back to the
461 * framework. Calling this method multiple times will reset the listener attached to the
462 * {@link MmTelFeature}.
463 * @param listener A {@link MmTelFeature.Listener} that will be used by the {@link MmTelFeature}
464 * to notify the framework of updates.
465 */
466 public void openConnection(MmTelFeature.Listener listener) throws RemoteException {
467 synchronized (mLock) {
468 checkServiceIsReady();
Brad Ebinger48632582018-03-16 11:46:30 -0700469 getServiceInterface(mBinder).setListener(listener);
Brad Ebinger936a7d12018-01-16 09:36:56 -0800470 }
471 }
472
473 public void closeConnection() {
474 mRegistrationCallbackManager.close();
475 mCapabilityCallbackManager.close();
476 try {
Brad Ebinger23916132018-04-06 09:37:50 -0700477 synchronized (mLock) {
478 if (isBinderAlive()) {
479 getServiceInterface(mBinder).setListener(null);
480 }
481 }
Brad Ebinger936a7d12018-01-16 09:36:56 -0800482 } catch (RemoteException e) {
483 Log.w(TAG, "closeConnection: couldn't remove listener!");
484 }
485 }
486
487 public void addRegistrationCallback(ImsRegistrationImplBase.Callback callback)
488 throws RemoteException {
489 mRegistrationCallbackManager.addCallback(callback);
490 }
491
492 public void removeRegistrationCallback(ImsRegistrationImplBase.Callback callback)
493 throws RemoteException {
494 mRegistrationCallbackManager.removeCallback(callback);
495 }
496
497 public void addCapabilityCallback(ImsFeature.CapabilityCallback callback)
498 throws RemoteException {
499 mCapabilityCallbackManager.addCallback(callback);
500 }
501
502 public void removeCapabilityCallback(ImsFeature.CapabilityCallback callback)
503 throws RemoteException {
504 mCapabilityCallbackManager.removeCallback(callback);
505 }
506
507 public void changeEnabledCapabilities(CapabilityChangeRequest request,
508 ImsFeature.CapabilityCallback callback) throws RemoteException {
509 synchronized (mLock) {
510 checkServiceIsReady();
511 getServiceInterface(mBinder).changeCapabilitiesConfiguration(request, callback);
512 }
513 }
514
515 public void queryEnabledCapabilities(int capability, int radioTech,
516 ImsFeature.CapabilityCallback callback) throws RemoteException {
517 synchronized (mLock) {
518 checkServiceIsReady();
519 getServiceInterface(mBinder).queryCapabilityConfiguration(capability, radioTech,
520 callback);
521 }
522 }
523
524 public MmTelFeature.MmTelCapabilities queryCapabilityStatus() throws RemoteException {
525 synchronized (mLock) {
526 checkServiceIsReady();
527 return new MmTelFeature.MmTelCapabilities(
528 getServiceInterface(mBinder).queryCapabilityStatus());
529 }
530 }
531
532 public ImsCallProfile createCallProfile(int callServiceType, int callType)
533 throws RemoteException {
534 synchronized (mLock) {
535 checkServiceIsReady();
536 return getServiceInterface(mBinder).createCallProfile(callServiceType, callType);
537 }
538 }
539
540 public IImsCallSession createCallSession(ImsCallProfile profile)
541 throws RemoteException {
542 synchronized (mLock) {
543 checkServiceIsReady();
544 return getServiceInterface(mBinder).createCallSession(profile);
545 }
546 }
547
548 public IImsUt getUtInterface() throws RemoteException {
549 synchronized (mLock) {
550 checkServiceIsReady();
551 return getServiceInterface(mBinder).getUtInterface();
552 }
553 }
554
555 public IImsConfig getConfigInterface() throws RemoteException {
Brad Ebinger57f6a852018-03-08 13:14:38 -0800556 return getConfig();
Brad Ebinger936a7d12018-01-16 09:36:56 -0800557 }
558
559 public @ImsRegistrationImplBase.ImsRegistrationTech int getRegistrationTech()
Brad Ebinger57f6a852018-03-08 13:14:38 -0800560 throws RemoteException {
561 IImsRegistration registration = getRegistration();
562 if (registration != null) {
Brad Ebinger936a7d12018-01-16 09:36:56 -0800563 return registration.getRegistrationTechnology();
Brad Ebinger57f6a852018-03-08 13:14:38 -0800564 } else {
565 return ImsRegistrationImplBase.REGISTRATION_TECH_NONE;
Brad Ebinger936a7d12018-01-16 09:36:56 -0800566 }
567 }
568
569 public IImsEcbm getEcbmInterface() throws RemoteException {
570 synchronized (mLock) {
571 checkServiceIsReady();
572 return getServiceInterface(mBinder).getEcbmInterface();
573 }
574 }
575
576 public void setUiTTYMode(int uiTtyMode, Message onComplete)
577 throws RemoteException {
578 synchronized (mLock) {
579 checkServiceIsReady();
580 getServiceInterface(mBinder).setUiTtyMode(uiTtyMode, onComplete);
581 }
582 }
583
584 public IImsMultiEndpoint getMultiEndpointInterface() throws RemoteException {
585 synchronized (mLock) {
586 checkServiceIsReady();
587 return getServiceInterface(mBinder).getMultiEndpointInterface();
588 }
589 }
590
591 public void sendSms(int token, int messageRef, String format, String smsc, boolean isRetry,
592 byte[] pdu) throws RemoteException {
593 synchronized (mLock) {
594 checkServiceIsReady();
595 getServiceInterface(mBinder).sendSms(token, messageRef, format, smsc, isRetry,
596 pdu);
597 }
598 }
599
600 public void acknowledgeSms(int token, int messageRef,
601 @ImsSmsImplBase.SendStatusResult int result) throws RemoteException {
602 synchronized (mLock) {
603 checkServiceIsReady();
604 getServiceInterface(mBinder).acknowledgeSms(token, messageRef, result);
605 }
606 }
607
608 public void acknowledgeSmsReport(int token, int messageRef,
609 @ImsSmsImplBase.StatusReportResult int result) throws RemoteException {
610 synchronized (mLock) {
611 checkServiceIsReady();
612 getServiceInterface(mBinder).acknowledgeSmsReport(token, messageRef, result);
613 }
614 }
615
616 public String getSmsFormat() throws RemoteException {
617 synchronized (mLock) {
618 checkServiceIsReady();
619 return getServiceInterface(mBinder).getSmsFormat();
620 }
621 }
622
Brad Ebingered690772018-01-23 13:41:32 -0800623 public void onSmsReady() throws RemoteException {
624 synchronized (mLock) {
625 checkServiceIsReady();
626 getServiceInterface(mBinder).onSmsReady();
627 }
628 }
629
Brad Ebinger936a7d12018-01-16 09:36:56 -0800630 public void setSmsListener(IImsSmsListener listener) throws RemoteException {
631 synchronized (mLock) {
632 checkServiceIsReady();
633 getServiceInterface(mBinder).setSmsListener(listener);
634 }
635 }
636
Brad Ebingerd449b232018-02-12 14:33:05 -0800637 public @MmTelFeature.ProcessCallResult int shouldProcessCall(boolean isEmergency,
638 String[] numbers) throws RemoteException {
639 if (isEmergency && !isEmergencyMmTelAvailable()) {
640 // Don't query the ImsService if emergency calling is not available on the ImsService.
641 Log.i(TAG, "MmTel does not support emergency over IMS, fallback to CS.");
642 return MmTelFeature.PROCESS_CALL_CSFB;
643 }
644 synchronized (mLock) {
645 checkServiceIsReady();
646 return getServiceInterface(mBinder).shouldProcessCall(numbers);
647 }
648 }
649
Brad Ebinger936a7d12018-01-16 09:36:56 -0800650 /**
651 * @return an integer describing the current Feature Status, defined in
652 * {@link ImsFeature.ImsState}.
653 */
654 public int getFeatureState() {
655 synchronized (mLock) {
656 if (isBinderAlive() && mFeatureStateCached != null) {
Brad Ebinger936a7d12018-01-16 09:36:56 -0800657 return mFeatureStateCached;
658 }
659 }
660 // Don't synchronize on Binder call.
661 Integer status = retrieveFeatureState();
662 synchronized (mLock) {
663 if (status == null) {
664 return ImsFeature.STATE_UNAVAILABLE;
665 }
666 // Cache only non-null value for feature status.
667 mFeatureStateCached = status;
668 }
669 Log.i(TAG, "getFeatureState - returning " + status);
670 return status;
671 }
672
673 /**
674 * Internal method used to retrieve the feature status from the corresponding ImsService.
675 */
676 private Integer retrieveFeatureState() {
677 if (mBinder != null) {
678 try {
679 return getServiceInterface(mBinder).getFeatureState();
680 } catch (RemoteException e) {
681 // Status check failed, don't update cache
682 }
683 }
684 return null;
685 }
686
687 /**
688 * @param c Callback that will fire when the feature status has changed.
689 */
690 public void setStatusCallback(IFeatureUpdate c) {
691 mStatusCallback = c;
692 }
693
694 /**
695 * @return Returns true if the ImsService is ready to take commands, false otherwise. If this
696 * method returns false, it doesn't mean that the Binder connection is not available (use
697 * {@link #isBinderReady()} to check that), but that the ImsService is not accepting commands
698 * at this time.
699 *
700 * For example, for DSDS devices, only one slot can be {@link ImsFeature#STATE_READY} to take
701 * commands at a time, so the other slot must stay at {@link ImsFeature#STATE_UNAVAILABLE}.
702 */
703 public boolean isBinderReady() {
704 return isBinderAlive() && getFeatureState() == ImsFeature.STATE_READY;
705 }
706
707 /**
708 * @return false if the binder connection is no longer alive.
709 */
710 public boolean isBinderAlive() {
711 return mIsAvailable && mBinder != null && mBinder.isBinderAlive();
712 }
713
714 protected void checkServiceIsReady() throws RemoteException {
715 if (!isBinderReady()) {
716 throw new RemoteException("ImsServiceProxy is not ready to accept commands.");
717 }
718 }
719
720 private IImsMmTelFeature getServiceInterface(IBinder b) {
721 return IImsMmTelFeature.Stub.asInterface(b);
722 }
723
724 protected void checkBinderConnection() throws RemoteException {
725 if (!isBinderAlive()) {
726 throw new RemoteException("ImsServiceProxy is not available for that feature.");
727 }
728 }
729}