• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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 package com.android.telephony.qns;
17 
18 import static android.telephony.ims.feature.MmTelFeature.MmTelCapabilities.CAPABILITY_TYPE_VOICE;
19 import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_IWLAN;
20 import static android.telephony.ims.stub.ImsRegistrationImplBase.REGISTRATION_TECH_LTE;
21 
22 import android.content.Context;
23 import android.content.pm.PackageManager;
24 import android.os.Handler;
25 import android.os.HandlerThread;
26 import android.os.PersistableBundle;
27 import android.os.SystemProperties;
28 import android.telephony.AccessNetworkConstants;
29 import android.telephony.CarrierConfigManager;
30 import android.telephony.SubscriptionManager;
31 import android.telephony.TelephonyManager;
32 import android.telephony.ims.ImsException;
33 import android.telephony.ims.ImsManager;
34 import android.telephony.ims.ImsMmTelManager;
35 import android.telephony.ims.ImsRcsManager;
36 import android.telephony.ims.ImsReasonInfo;
37 import android.telephony.ims.ImsRegistrationAttributes;
38 import android.telephony.ims.ImsStateCallback;
39 import android.telephony.ims.ProvisioningManager;
40 import android.telephony.ims.RegistrationManager;
41 import android.telephony.ims.SipDelegateManager;
42 import android.telephony.ims.SipDialogState;
43 import android.telephony.ims.SipDialogStateCallback;
44 import android.telephony.ims.feature.ImsFeature;
45 import android.util.Log;
46 
47 import androidx.annotation.NonNull;
48 
49 import com.android.internal.annotations.VisibleForTesting;
50 
51 import java.util.List;
52 import java.util.concurrent.Executor;
53 import java.util.concurrent.Executors;
54 import java.util.concurrent.Semaphore;
55 import java.util.concurrent.TimeUnit;
56 import java.util.concurrent.atomic.AtomicInteger;
57 import java.util.function.Consumer;
58 
59 /**
60  * QnsImsManager is helper class to get wi-fi calling related items from ImsManager
61  *
62  * @hide
63  */
64 class QnsImsManager {
65 
66     static final String PROP_DBG_WFC_AVAIL_OVERRIDE = "persist.dbg.wfc_avail_ovr";
67 
68     private static final int SYS_PROP_NOT_SET = -1;
69 
70     private final String mLogTag;
71     private final Context mContext;
72     private final int mSlotId;
73     private final Executor mExecutor;
74     private final Handler mHandler;
75     private final HandlerThread mHandlerThread;
76     private int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
77     private final SubscriptionManager mSubscriptionManager;
78     private boolean mQnsImsManagerInitialized;
79     private CarrierConfigManager mConfigManager;
80     private ImsManager mImsManager;
81     private ImsMmTelManager mImsMmTelManager;
82     private ImsRcsManager mImsRcsManager;
83     private SipDelegateManager mSipDelegateManager;
84     QnsImsStateCallback mMmTelStateCallback;
85     QnsImsStateCallback mRcsStateCallback;
86     QnsImsRegistrationCallback mMmtelImsRegistrationCallback;
87     QnsImsRegistrationCallback mRcsImsRegistrationCallback;
88     QnsSipDialogStateCallback mRcsSipDialogSessionStateCallback;
89 
90     final QnsRegistrantList mMmTelImsStateListener;
91     final QnsRegistrantList mRcsImsStateListener;
92     final QnsRegistrantList mMmTelImsRegistrationListener;
93     final QnsRegistrantList mRcsImsRegistrationListener;
94     final QnsRegistrantList mRcsSipDialogSessionStateListener;
95 
96     @VisibleForTesting
97     final SubscriptionManager.OnSubscriptionsChangedListener mSubscriptionsChangeListener;
98 
99     /** QnsImsManager default constructor */
QnsImsManager(Context context, int slotId)100     QnsImsManager(Context context, int slotId) {
101         mSlotId = slotId;
102         mLogTag = QnsImsManager.class.getSimpleName() + "_" + mSlotId;
103         mContext = context;
104         mExecutor = new QnsImsManagerExecutor();
105 
106         mHandlerThread = new HandlerThread(mLogTag);
107         mHandlerThread.start();
108         mHandler = new Handler(mHandlerThread.getLooper());
109 
110         mMmTelImsStateListener = new QnsRegistrantList();
111         mRcsImsStateListener = new QnsRegistrantList();
112         mMmTelImsRegistrationListener = new QnsRegistrantList();
113         mRcsImsRegistrationListener = new QnsRegistrantList();
114         mRcsSipDialogSessionStateListener = new QnsRegistrantList();
115 
116         initQnsImsManager();
117 
118         mSubscriptionManager = mContext.getSystemService(SubscriptionManager.class);
119         mSubscriptionsChangeListener = new QnsSubscriptionsChangedListener();
120         if (mSubscriptionManager != null) {
121             mSubscriptionManager.addOnSubscriptionsChangedListener(
122                     new QnsUtils.QnsExecutor(mHandler), mSubscriptionsChangeListener);
123         }
124     }
125 
126     class QnsSubscriptionsChangedListener
127             extends SubscriptionManager.OnSubscriptionsChangedListener {
128 
129         /**
130          * Callback invoked when there is any change to any SubscriptionInfo.
131          */
132         @Override
onSubscriptionsChanged()133         public void onSubscriptionsChanged() {
134             int newSubId = QnsUtils.getSubId(mContext, mSlotId);
135             if (newSubId != mSubId) {
136                 mSubId = newSubId;
137                 if (mSubId == SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
138                     clearQnsImsManager();
139                 } else {
140                     clearQnsImsManager();
141                     initQnsImsManager();
142                 }
143             }
144         }
145     }
146 
147     @VisibleForTesting
initQnsImsManager()148     protected synchronized void initQnsImsManager() {
149         if (mQnsImsManagerInitialized) {
150             return;
151         }
152         log("initQnsImsManager.");
153 
154         if (mConfigManager == null) {
155             mConfigManager = mContext.getSystemService(CarrierConfigManager.class);
156             if (mConfigManager == null) {
157                 loge("initQnsImsManager: couldn't initialize. failed to get CarrierConfigManager.");
158                 clearQnsImsManager();
159                 return;
160             }
161         }
162 
163         if (mImsManager == null) {
164             mImsManager = mContext.getSystemService(ImsManager.class);
165             if (mImsManager == null) {
166                 loge("initQnsImsManager: couldn't initialize. failed to get ImsManager.");
167                 clearQnsImsManager();
168                 return;
169             }
170         }
171 
172         int subId = getSubId();
173         if (!SubscriptionManager.isValidSubscriptionId(subId)) {
174             return;
175         }
176 
177         mImsMmTelManager = mImsManager.getImsMmTelManager(subId);
178         if (mImsMmTelManager == null) {
179             loge("initQnsImsManager: couldn't initialize. failed to get ImsMmTelManager.");
180             clearQnsImsManager();
181             return;
182         }
183 
184         mImsRcsManager = mImsManager.getImsRcsManager(subId);
185         if (mImsRcsManager == null) {
186             loge("initQnsImsManager: couldn't initialize. failed to get ImsRcsManager.");
187             clearQnsImsManager();
188             return;
189         }
190 
191         mSipDelegateManager = mImsManager.getSipDelegateManager(subId);
192         if (mSipDelegateManager == null) {
193             loge("initQnsImsManager: couldn't initialize. failed to get mSipDelegateManager.");
194             clearQnsImsManager();
195             return;
196         }
197 
198         mQnsImsManagerInitialized = true;
199 
200         startTrackingImsState(ImsFeature.FEATURE_MMTEL);
201         startTrackingImsState(ImsFeature.FEATURE_RCS);
202         startTrackingImsRegistration(ImsFeature.FEATURE_MMTEL);
203         startTrackingImsRegistration(ImsFeature.FEATURE_RCS);
204         startTrackingSipDialogSessionState(ImsFeature.FEATURE_RCS);
205     }
206 
207     @VisibleForTesting
startTrackingImsState(int feature)208     protected synchronized void startTrackingImsState(int feature) {
209         if (feature == ImsFeature.FEATURE_MMTEL
210                 && mImsMmTelManager != null
211                 && mMmTelStateCallback == null) {
212             try {
213                 QnsImsStateCallback imsStateCallback = new QnsImsStateCallback(feature);
214                 mImsMmTelManager.registerImsStateCallback(mExecutor, imsStateCallback);
215                 log("startTrackingImsState: registered ImsFeature.MMTEL State Callback.");
216                 mMmTelStateCallback = imsStateCallback;
217             } catch (ImsException e) {
218                 loge("startTrackingImsState: couldn't register MMTEL state callback, " + e);
219             }
220         }
221 
222         if (feature == ImsFeature.FEATURE_RCS
223                 && mImsRcsManager != null
224                 && mRcsStateCallback == null) {
225             try {
226                 QnsImsStateCallback rcsStateCallback = new QnsImsStateCallback(feature);
227                 mImsRcsManager.registerImsStateCallback(mExecutor, rcsStateCallback);
228                 log("startTrackingImsState: registered ImsFeature.RCS State Callback.");
229                 mRcsStateCallback = rcsStateCallback;
230             } catch (ImsException e) {
231                 loge("startTrackingImsState: couldn't register RCS state callback, " + e);
232             }
233         }
234     }
235 
236     @VisibleForTesting
startTrackingImsRegistration(int feature)237     protected synchronized void startTrackingImsRegistration(int feature) {
238         if (feature == ImsFeature.FEATURE_MMTEL
239                 && mImsMmTelManager != null
240                 && mMmtelImsRegistrationCallback == null) {
241             try {
242                 QnsImsRegistrationCallback imsRegistrationCallback =
243                         new QnsImsRegistrationCallback(feature);
244                 mImsMmTelManager.registerImsRegistrationCallback(
245                         mExecutor, imsRegistrationCallback);
246                 log("startTrackingImsRegistration: registered MMTEL registration callback");
247                 mMmtelImsRegistrationCallback = imsRegistrationCallback;
248             } catch (ImsException e) {
249                 loge("startTrackingImsRegistration: couldn't register MMTEL callback, " + e);
250             }
251         }
252 
253         if (feature == ImsFeature.FEATURE_RCS
254                 && mImsRcsManager != null
255                 && mRcsImsRegistrationCallback == null) {
256             try {
257                 QnsImsRegistrationCallback rcsRegistrationCallback =
258                         new QnsImsRegistrationCallback(feature);
259                 mImsRcsManager.registerImsRegistrationCallback(mExecutor, rcsRegistrationCallback);
260                 log("startTrackingImsRegistration: registered RCS registration callback");
261                 mRcsImsRegistrationCallback = rcsRegistrationCallback;
262             } catch (ImsException e) {
263                 loge("startTrackingImsRegistration: couldn't register RCS callback, " + e);
264             }
265         }
266     }
267 
268     @VisibleForTesting
startTrackingSipDialogSessionState(int feature)269     protected synchronized void startTrackingSipDialogSessionState(int feature) {
270         if (feature == ImsFeature.FEATURE_RCS
271                 && mImsRcsManager != null
272                 && mRcsStateCallback != null
273                 && mRcsStateCallback.isImsAvailable()
274                 && mRcsSipDialogSessionStateCallback == null) {
275             try {
276                 QnsSipDialogStateCallback rcsSipDialogStateCallback =
277                         new QnsSipDialogStateCallback();
278                 mSipDelegateManager.registerSipDialogStateCallback(
279                         mExecutor, rcsSipDialogStateCallback);
280                 log("startTrackingSipDialogSessionState: registered SipDialogState callback.");
281                 mRcsSipDialogSessionStateCallback = rcsSipDialogStateCallback;
282             } catch (ImsException e) {
283                 loge("startTrackingSipDialogSessionState: couldn't register callback, " + e);
284             }
285         }
286     }
287 
stopTrackingImsState(int feature)288     protected synchronized void stopTrackingImsState(int feature) {
289         if (feature == ImsFeature.FEATURE_MMTEL
290                 && mImsMmTelManager != null
291                 && mMmTelStateCallback != null) {
292             try {
293                 mImsMmTelManager.unregisterImsStateCallback(mMmTelStateCallback);
294             } catch (Exception e) {
295                 // do-nothing
296             }
297         }
298         if (feature == ImsFeature.FEATURE_RCS
299                 && mImsRcsManager != null
300                 && mRcsStateCallback != null) {
301             try {
302                 mImsRcsManager.unregisterImsStateCallback(mRcsStateCallback);
303             } catch (Exception e) {
304                 // do-nothing
305             }
306         }
307     }
308 
stopTrackingImsRegistration(int feature)309     protected synchronized void stopTrackingImsRegistration(int feature) {
310         if (feature == ImsFeature.FEATURE_MMTEL
311                 && mImsMmTelManager != null
312                 && mMmtelImsRegistrationCallback != null) {
313             try {
314                 mImsMmTelManager.unregisterImsRegistrationCallback(mMmtelImsRegistrationCallback);
315             } catch (Exception e) {
316                 // do-nothing
317             }
318         }
319         if (feature == ImsFeature.FEATURE_RCS
320                 && mImsRcsManager != null
321                 && mRcsImsRegistrationCallback != null) {
322             try {
323                 mImsRcsManager.unregisterImsRegistrationCallback(mRcsImsRegistrationCallback);
324             } catch (Exception e) {
325                 // do-nothing
326             }
327         }
328     }
329 
stopTrackingSipDialogSessionState(int feature)330     protected synchronized void stopTrackingSipDialogSessionState(int feature) {
331         if (feature == ImsFeature.FEATURE_RCS
332                 && mSipDelegateManager != null
333                 && mRcsSipDialogSessionStateCallback != null) {
334             try {
335                 mSipDelegateManager.unregisterSipDialogStateCallback(
336                         mRcsSipDialogSessionStateCallback);
337             } catch (Exception e) {
338                 // do-nothing
339             }
340         }
341     }
342 
343     @VisibleForTesting
clearQnsImsManager()344     protected synchronized void clearQnsImsManager() {
345         log("clearQnsImsManager");
346 
347         stopTrackingImsState(ImsFeature.FEATURE_MMTEL);
348         stopTrackingImsState(ImsFeature.FEATURE_RCS);
349         stopTrackingImsRegistration(ImsFeature.FEATURE_MMTEL);
350         stopTrackingImsRegistration(ImsFeature.FEATURE_RCS);
351         stopTrackingSipDialogSessionState(ImsFeature.FEATURE_RCS);
352 
353         mImsManager = null;
354         mImsMmTelManager = null;
355         mImsRcsManager = null;
356         mSipDelegateManager = null;
357         mMmTelStateCallback = null;
358         mMmtelImsRegistrationCallback = null;
359         mRcsStateCallback = null;
360         mRcsImsRegistrationCallback = null;
361         mRcsSipDialogSessionStateCallback = null;
362         mQnsImsManagerInitialized = false;
363     }
364 
365     @VisibleForTesting
close()366     protected synchronized void close() {
367         if (mSubscriptionManager != null) {
368             mSubscriptionManager.removeOnSubscriptionsChangedListener(mSubscriptionsChangeListener);
369         }
370         mHandlerThread.quitSafely();
371         clearQnsImsManager();
372 
373         mMmTelImsStateListener.removeAll();
374         mRcsImsStateListener.removeAll();
375         mMmTelImsRegistrationListener.removeAll();
376         mRcsImsRegistrationListener.removeAll();
377         mRcsSipDialogSessionStateListener.removeAll();
378     }
379 
getSlotIndex()380     int getSlotIndex() {
381         return mSlotId;
382     }
383 
getImsMmTelManagerOrThrowExceptionIfNotReady()384     private synchronized ImsMmTelManager getImsMmTelManagerOrThrowExceptionIfNotReady()
385             throws ImsException {
386         initQnsImsManager();
387         if (mImsManager == null || mImsMmTelManager == null || mMmTelStateCallback == null) {
388             throw new ImsException(
389                     "IMS service is down.", ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
390         }
391         return mImsMmTelManager;
392     }
393 
394     /**
395      * Get the boolean config from carrier config manager.
396      *
397      * @param key config key defined in CarrierConfigManager
398      * @return boolean value of corresponding key.
399      */
getBooleanCarrierConfig(String key)400     private boolean getBooleanCarrierConfig(String key) {
401         PersistableBundle b = null;
402         if (mConfigManager != null) {
403             // If an invalid subId is used, this bundle will contain default values.
404             b = mConfigManager.getConfigForSubId(getSubId());
405         }
406         if (b != null) {
407             return b.getBoolean(key);
408         } else {
409             // Return static default defined in CarrierConfigManager.
410             return CarrierConfigManager.getDefaultConfig().getBoolean(key);
411         }
412     }
413 
414     /**
415      * Get the int config from carrier config manager.
416      *
417      * @param key config key defined in CarrierConfigManager
418      * @return integer value of corresponding key.
419      */
getIntCarrierConfig(String key)420     private int getIntCarrierConfig(String key) {
421         PersistableBundle b = null;
422         if (mConfigManager != null) {
423             // If an invalid subId is used, this bundle will contain default values.
424             b = mConfigManager.getConfigForSubId(getSubId());
425         }
426         if (b != null) {
427             return b.getInt(key);
428         } else {
429             // Return static default defined in CarrierConfigManager.
430             return CarrierConfigManager.getDefaultConfig().getInt(key);
431         }
432     }
433 
isCrossSimCallingEnabledByUser()434     private boolean isCrossSimCallingEnabledByUser() {
435         boolean crossSimCallingEnabled;
436         try {
437             ImsMmTelManager mmTelManager = getImsMmTelManagerOrThrowExceptionIfNotReady();
438             crossSimCallingEnabled = mmTelManager.isCrossSimCallingEnabled();
439         } catch (Exception e) {
440             crossSimCallingEnabled = false;
441         }
442         log("isCrossSimCallingEnabledByUser:" + crossSimCallingEnabled);
443         return crossSimCallingEnabled;
444     }
445 
isGbaValid()446     private boolean isGbaValid() {
447         if (getBooleanCarrierConfig(CarrierConfigManager.KEY_CARRIER_IMS_GBA_REQUIRED_BOOL)) {
448             TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
449             if (tm == null) {
450                 loge("isGbaValid: TelephonyManager is null, returning false.");
451                 return false;
452             }
453             tm = tm.createForSubscriptionId(getSubId());
454             String efIst = tm.getIsimIst();
455             if (efIst == null) {
456                 loge("isGbaValid - ISF is NULL");
457                 return true;
458             }
459             boolean result = efIst.length() > 1 && (0x02 & (byte) efIst.charAt(1)) != 0;
460             log("isGbaValid - GBA capable=" + result + ", ISF=" + efIst);
461             return result;
462         }
463         return true;
464     }
465 
isCrossSimEnabledByPlatform()466     private boolean isCrossSimEnabledByPlatform() {
467         if (isWfcEnabledByPlatform()) {
468             return getBooleanCarrierConfig(
469                     CarrierConfigManager.KEY_CARRIER_CROSS_SIM_IMS_AVAILABLE_BOOL);
470         }
471         return false;
472     }
473 
isVolteProvisionedOnDevice()474     private boolean isVolteProvisionedOnDevice() {
475         if (isMmTelProvisioningRequired(REGISTRATION_TECH_LTE)) {
476             return isVolteProvisioned();
477         }
478 
479         return true;
480     }
481 
isVolteProvisioned()482     private boolean isVolteProvisioned() {
483         return getImsProvisionedBoolNoException(REGISTRATION_TECH_LTE);
484     }
485 
isWfcProvisioned()486     private boolean isWfcProvisioned() {
487         return getImsProvisionedBoolNoException(REGISTRATION_TECH_IWLAN);
488     }
489 
isMmTelProvisioningRequired(int tech)490     private boolean isMmTelProvisioningRequired(int tech) {
491         if (!SubscriptionManager.isValidSubscriptionId(getSubId())) {
492             return false;
493         }
494 
495         boolean required = false;
496         try {
497             ProvisioningManager p = ProvisioningManager.createForSubscriptionId(getSubId());
498             required = p.isProvisioningRequiredForCapability(CAPABILITY_TYPE_VOICE, tech);
499         } catch (RuntimeException e) {
500             loge("isMmTelProvisioningRequired, tech:" + tech + ". e:" + e);
501         }
502 
503         log("isMmTelProvisioningRequired " + required + " for tech:" + tech);
504         return required;
505     }
506 
getImsProvisionedBoolNoException(int tech)507     private boolean getImsProvisionedBoolNoException(int tech) {
508         if (!SubscriptionManager.isValidSubscriptionId(getSubId())) {
509             return false;
510         }
511 
512         boolean status = false;
513         try {
514             ProvisioningManager p = ProvisioningManager.createForSubscriptionId(getSubId());
515             status = p.getProvisioningStatusForCapability(CAPABILITY_TYPE_VOICE, tech);
516         } catch (RuntimeException e) {
517             loge("getImsProvisionedBoolNoException, tech:" + tech + ". e:" + e);
518         }
519 
520         log("getImsProvisionedBoolNoException " + status + " for tech:" + tech);
521         return status;
522     }
523 
getSubId()524     private int getSubId() {
525         return QnsUtils.getSubId(mContext, mSlotId);
526     }
527 
528     private static class QnsImsManagerExecutor implements Executor {
529         private Executor mExecutor;
530 
531         @Override
execute(Runnable runnable)532         public void execute(Runnable runnable) {
533             startExecutorIfNeeded();
534             mExecutor.execute(runnable);
535         }
536 
startExecutorIfNeeded()537         private synchronized void startExecutorIfNeeded() {
538             if (mExecutor != null) return;
539             mExecutor = Executors.newSingleThreadExecutor();
540         }
541     }
542 
543     private class QnsImsStateCallback extends ImsStateCallback {
544         int mImsFeature;
545         boolean mImsAvailable;
546 
isImsAvailable()547         public boolean isImsAvailable() {
548             return mImsAvailable;
549         }
550 
QnsImsStateCallback(int imsFeature)551         QnsImsStateCallback(int imsFeature) {
552             mImsFeature = imsFeature;
553         }
554 
555         @Override
onUnavailable(int reason)556         public void onUnavailable(int reason) {
557             changeImsState(false);
558         }
559 
560         @Override
onAvailable()561         public void onAvailable() {
562             changeImsState(true);
563         }
564 
565         @Override
onError()566         public void onError() {
567             changeImsState(false);
568         }
569 
changeImsState(boolean imsAvailable)570         private void changeImsState(boolean imsAvailable) {
571             if (mImsAvailable != imsAvailable) {
572                 mImsAvailable = imsAvailable;
573                 onImsStateChanged(mImsFeature, imsAvailable);
574             }
575         }
576     }
577 
578     /** class for the IMS State. */
579     static class ImsState {
580         private final boolean mImsAvailable;
581 
ImsState(boolean imsAvailable)582         ImsState(boolean imsAvailable) {
583             mImsAvailable = imsAvailable;
584         }
585 
isImsAvailable()586         boolean isImsAvailable() {
587             return mImsAvailable;
588         }
589     }
590 
onImsStateChanged(int imsFeature, boolean imsAvailable)591     private void onImsStateChanged(int imsFeature, boolean imsAvailable) {
592         if (imsFeature == ImsFeature.FEATURE_MMTEL) {
593             log("onImsStateChanged ImsFeature.MMTEL:" + imsAvailable);
594         }
595         if (imsFeature == ImsFeature.FEATURE_RCS) {
596             log("onImsStateChanged ImsFeature.RCS:" + imsAvailable);
597         }
598 
599         if (imsAvailable) {
600             startTrackingImsRegistration(imsFeature);
601             startTrackingSipDialogSessionState(imsFeature);
602         }
603 
604         ImsState imsState = new ImsState(imsAvailable);
605         notifyImsStateChanged(imsFeature, imsState);
606     }
607 
608     /**
609      * Registers to monitor Ims State
610      *
611      * @param h Handler to get an event
612      * @param what message id.
613      */
registerImsStateChanged(Handler h, int what)614     void registerImsStateChanged(Handler h, int what) {
615         QnsRegistrant r = new QnsRegistrant(h, what, null);
616         mMmTelImsStateListener.add(r);
617     }
618 
619     /**
620      * Unregisters ims state for given handler.
621      *
622      * @param h Handler
623      */
unregisterImsStateChanged(Handler h)624     void unregisterImsStateChanged(Handler h) {
625         mMmTelImsStateListener.remove(h);
626     }
627 
628     /**
629      * Registers to monitor Rcs State
630      *
631      * @param h Handler to get an event
632      * @param what message id.
633      */
registerRcsStateChanged(Handler h, int what)634     void registerRcsStateChanged(Handler h, int what) {
635         QnsRegistrant r = new QnsRegistrant(h, what, null);
636         mRcsImsStateListener.add(r);
637     }
638 
639     /**
640      * Unregisters rcs state for given handler.
641      *
642      * @param h Handler
643      */
unregisterRcsStateChanged(Handler h)644     void unregisterRcsStateChanged(Handler h) {
645         mRcsImsStateListener.remove(h);
646     }
647 
notifyImsStateChanged(int imsFeature, ImsState imsState)648     protected void notifyImsStateChanged(int imsFeature, ImsState imsState) {
649         if (imsFeature == ImsFeature.FEATURE_MMTEL) {
650             mMmTelImsStateListener.notifyResult(imsState);
651         } else if (imsFeature == ImsFeature.FEATURE_RCS) {
652             mRcsImsStateListener.notifyResult(imsState);
653         }
654     }
655 
656     private static class StateConsumer extends Semaphore implements Consumer<Integer> {
657         private static final long TIMEOUT_MILLIS = 2000;
658 
StateConsumer()659         StateConsumer() {
660             super(0);
661             mValue = new AtomicInteger();
662         }
663 
664         private final AtomicInteger mValue;
665 
getOrTimeOut()666         int getOrTimeOut() throws InterruptedException {
667             if (tryAcquire(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)) {
668                 return mValue.get();
669             }
670             return ImsFeature.STATE_UNAVAILABLE;
671         }
672 
accept(Integer value)673         public void accept(Integer value) {
674             if (value != null) {
675                 mValue.set(value);
676             }
677             release();
678         }
679     }
680 
681     private class QnsImsRegistrationCallback extends RegistrationManager.RegistrationCallback {
682         int mImsFeature;
683         ImsRegistrationState mImsRegistrationState;
684 
QnsImsRegistrationCallback(int imsFeature)685         QnsImsRegistrationCallback(int imsFeature) {
686             mImsFeature = imsFeature;
687             mImsRegistrationState = null;
688         }
689 
690         @Override
onRegistered(ImsRegistrationAttributes attribute)691         public void onRegistered(ImsRegistrationAttributes attribute) {
692             int transportType = attribute.getTransportType();
693             log("on IMS registered on :" + QnsConstants.transportTypeToString(transportType));
694             mImsRegistrationState =
695                     new ImsRegistrationState(
696                             QnsConstants.IMS_REGISTRATION_CHANGED_REGISTERED, transportType, null);
697             notifyImsRegistrationChangedEvent(
698                     mImsFeature, new ImsRegistrationState(mImsRegistrationState));
699         }
700 
701         @Override
onTechnologyChangeFailed(int transportType, ImsReasonInfo reason)702         public void onTechnologyChangeFailed(int transportType, ImsReasonInfo reason) {
703             log(
704                     "onTechnologyChangeFailed["
705                             + QnsConstants.transportTypeToString(transportType)
706                             + "] "
707                             + reason.toString());
708             mImsRegistrationState =
709                     new ImsRegistrationState(
710                             QnsConstants.IMS_REGISTRATION_CHANGED_ACCESS_NETWORK_CHANGE_FAILED,
711                             transportType,
712                             reason);
713             notifyImsRegistrationChangedEvent(
714                     mImsFeature, new ImsRegistrationState(mImsRegistrationState));
715         }
716 
717         @Override
onUnregistered(ImsReasonInfo reason)718         public void onUnregistered(ImsReasonInfo reason) {
719             log("onUnregistered " + reason.toString());
720             mImsRegistrationState =
721                     new ImsRegistrationState(
722                             QnsConstants.IMS_REGISTRATION_CHANGED_UNREGISTERED,
723                             AccessNetworkConstants.TRANSPORT_TYPE_INVALID,
724                             reason);
725             notifyImsRegistrationChangedEvent(
726                     mImsFeature, new ImsRegistrationState(mImsRegistrationState));
727         }
728     }
729 
730     private class QnsSipDialogStateCallback extends SipDialogStateCallback {
731         boolean mIsActive;
732 
isActive()733         public boolean isActive() {
734             return mIsActive;
735         }
736 
737         @Override
onActiveSipDialogsChanged(@onNull List<SipDialogState> dialogs)738         public void onActiveSipDialogsChanged(@NonNull List<SipDialogState> dialogs) {
739             for (SipDialogState state : dialogs) {
740                 if (state.getState() == SipDialogState.STATE_CONFIRMED) {
741                     if (!mIsActive) {
742                         mIsActive = true;
743                         notifySipDialogSessionStateChanged(mIsActive);
744                     }
745                     return;
746                 }
747             }
748             if (mIsActive) {
749                 mIsActive = false;
750                 notifySipDialogSessionStateChanged(mIsActive);
751             }
752         }
753 
754         @Override
onError()755         public void onError() {
756             mIsActive = false;
757             notifySipDialogSessionStateChanged(mIsActive);
758             // TODO do nothing?
759         }
760     }
761 
762     /** State class for the IMS Registration. */
763     static class ImsRegistrationState {
764         @QnsConstants.QnsImsRegiEvent private final int mEvent;
765         private final int mTransportType;
766         private final ImsReasonInfo mReasonInfo;
767 
ImsRegistrationState(int event, int transportType, ImsReasonInfo reason)768         ImsRegistrationState(int event, int transportType, ImsReasonInfo reason) {
769             mEvent = event;
770             mTransportType = transportType;
771             mReasonInfo = reason;
772         }
773 
ImsRegistrationState(ImsRegistrationState state)774         ImsRegistrationState(ImsRegistrationState state) {
775             mEvent = state.mEvent;
776             mTransportType = state.mTransportType;
777             mReasonInfo = state.mReasonInfo;
778         }
779 
getEvent()780         int getEvent() {
781             return mEvent;
782         }
783 
getTransportType()784         int getTransportType() {
785             return mTransportType;
786         }
787 
getReasonInfo()788         ImsReasonInfo getReasonInfo() {
789             return mReasonInfo;
790         }
791 
792         @Override
toString()793         public String toString() {
794             String reason = getReasonInfo() == null ? "null" : mReasonInfo.toString();
795             String event = Integer.toString(mEvent);
796             switch (mEvent) {
797                 case QnsConstants.IMS_REGISTRATION_CHANGED_REGISTERED:
798                     event = "IMS_REGISTERED";
799                     break;
800                 case QnsConstants.IMS_REGISTRATION_CHANGED_UNREGISTERED:
801                     event = "IMS_UNREGISTERED";
802                     break;
803                 case QnsConstants.IMS_REGISTRATION_CHANGED_ACCESS_NETWORK_CHANGE_FAILED:
804                     event = "IMS_ACCESS_NETWORK_CHANGE_FAILED";
805                     break;
806             }
807             return "ImsRegistrationState["
808                     + QnsConstants.transportTypeToString(mTransportType)
809                     + "] "
810                     + "Event:"
811                     + event
812                     + " reason:"
813                     + reason;
814         }
815     }
816 
817     /**
818      * Get the status of whether the IMS is registered or not for given transport type
819      *
820      * @param transportType Transport Type
821      * @return true when ims is registered.
822      */
isImsRegistered(int transportType)823     boolean isImsRegistered(int transportType) {
824         if (mMmtelImsRegistrationCallback == null) {
825             return false;
826         }
827         ImsRegistrationState state = mMmtelImsRegistrationCallback.mImsRegistrationState;
828         return state != null
829                 && state.getTransportType() == transportType
830                 && state.getEvent() == QnsConstants.IMS_REGISTRATION_CHANGED_REGISTERED;
831     }
832 
833     /**
834      * Get the status of whether the Rcs is registered or not for given transport type
835      *
836      * @param transportType Transport Type
837      * @return true when ims is registered.
838      */
isRcsRegistered(int transportType)839     boolean isRcsRegistered(int transportType) {
840         if (mRcsImsRegistrationCallback == null) {
841             return false;
842         }
843         ImsRegistrationState state = mRcsImsRegistrationCallback.mImsRegistrationState;
844         return state != null
845                 && state.getTransportType() == transportType
846                 && state.getEvent() == QnsConstants.IMS_REGISTRATION_CHANGED_REGISTERED;
847     }
848 
849     /**
850      * Registers to monitor Ims registration status
851      *
852      * @param h Handler to get an event
853      * @param what message id.
854      */
registerImsRegistrationStatusChanged(Handler h, int what)855     void registerImsRegistrationStatusChanged(Handler h, int what) {
856         QnsRegistrant r = new QnsRegistrant(h, what, null);
857         mMmTelImsRegistrationListener.add(r);
858     }
859 
860     /**
861      * Unregisters ims registration status for given handler.
862      *
863      * @param h Handler
864      */
unregisterImsRegistrationStatusChanged(Handler h)865     void unregisterImsRegistrationStatusChanged(Handler h) {
866         mMmTelImsRegistrationListener.remove(h);
867     }
868 
869     /**
870      * Registers to monitor Ims registration status
871      *
872      * @param h Handler to get an event
873      * @param what message id.
874      */
registerRcsRegistrationStatusChanged(Handler h, int what)875     void registerRcsRegistrationStatusChanged(Handler h, int what) {
876         QnsRegistrant r = new QnsRegistrant(h, what, null);
877         mRcsImsRegistrationListener.add(r);
878     }
879 
880     /**
881      * Unregisters ims registration status for given handler.
882      *
883      * @param h Handler
884      */
unregisterRcsRegistrationStatusChanged(Handler h)885     void unregisterRcsRegistrationStatusChanged(Handler h) {
886         mRcsImsRegistrationListener.remove(h);
887     }
888 
889     @VisibleForTesting
notifyImsRegistrationChangedEvent(int imsFeature, ImsRegistrationState state)890     protected void notifyImsRegistrationChangedEvent(int imsFeature, ImsRegistrationState state) {
891         if (imsFeature == ImsFeature.FEATURE_MMTEL) {
892             mMmTelImsRegistrationListener.notifyResult(state);
893         } else if (imsFeature == ImsFeature.FEATURE_RCS) {
894             mRcsImsRegistrationListener.notifyResult(state);
895         }
896     }
897 
898     /**
899      * Get the active status of SipDialogState
900      *
901      * @return true when one of Sip Dialogs is active.
902      */
isSipDialogSessionActive()903     boolean isSipDialogSessionActive() {
904         return mRcsSipDialogSessionStateCallback != null
905                 && mRcsSipDialogSessionStateCallback.isActive();
906     }
907 
908     /**
909      * Registers to monitor SipDialogSession State
910      *
911      * @param h Handler to get an event
912      * @param what message id.
913      */
registerSipDialogSessionStateChanged(Handler h, int what)914     void registerSipDialogSessionStateChanged(Handler h, int what) {
915         QnsRegistrant r = new QnsRegistrant(h, what, null);
916         mRcsSipDialogSessionStateListener.add(r);
917     }
918 
919     /**
920      * Unregisters SipDialogState status for given handler.
921      *
922      * @param h Handler
923      */
unregisterSipDialogSessionStateChanged(Handler h)924     void unregisterSipDialogSessionStateChanged(Handler h) {
925         mRcsSipDialogSessionStateListener.remove(h);
926     }
927 
928     @VisibleForTesting
notifySipDialogSessionStateChanged(boolean isActive)929     protected void notifySipDialogSessionStateChanged(boolean isActive) {
930         mRcsSipDialogSessionStateListener.notifyResult(isActive);
931     }
932 
isImsSupportedOnDevice(Context context)933     private static boolean isImsSupportedOnDevice(Context context) {
934         return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY_IMS);
935     }
936 
937     /**
938      * Get the status of the MmTel Feature corresponding to this subscription.
939      *
940      * <p>This function is a blocking function and there may be a timeout of up to 2 seconds.
941      *
942      * @return MmTel Feature Status. Returns one of the following: {@link
943      *     ImsFeature#STATE_UNAVAILABLE}, {@link ImsFeature#STATE_INITIALIZING}, {@link
944      *     ImsFeature#STATE_READY}.
945      * @throws ImsException if the IMS service associated with this subscription is not available or
946      *     the IMS service is not available.
947      * @throws InterruptedException if the thread to get value is timed out. (max 2000ms)
948      */
getImsServiceState()949     int getImsServiceState() throws ImsException, InterruptedException {
950         if (!isImsSupportedOnDevice(mContext)) {
951             throw new ImsException(
952                     "IMS not supported on device.",
953                     ImsReasonInfo.CODE_LOCAL_IMS_NOT_SUPPORTED_ON_DEVICE);
954         }
955         ImsMmTelManager mmTelManager = getImsMmTelManagerOrThrowExceptionIfNotReady();
956         final StateConsumer stateConsumer = new StateConsumer();
957         mmTelManager.getFeatureState(mExecutor, stateConsumer);
958         int state = stateConsumer.getOrTimeOut(); // ImsFeature.STATE_READY
959         log("getImsServiceState state:" + state);
960         return state;
961     }
962 
963     /**
964      * Returns whether wi-fi calling feature is enabled by platform.
965      *
966      * <p>This function is a blocking function and there may be a timeout of up to 2 seconds.
967      *
968      * @return true, if wi-fi calling feature is enabled by platform.
969      */
isWfcEnabledByPlatform()970     boolean isWfcEnabledByPlatform() {
971         // We first read the per slot value. If it doesn't exist, we read the general value.
972         // If still doesn't exist, we use the hardcoded default value.
973         if (SystemProperties.getInt(PROP_DBG_WFC_AVAIL_OVERRIDE + mSlotId, SYS_PROP_NOT_SET) == 1
974                 || SystemProperties.getInt(PROP_DBG_WFC_AVAIL_OVERRIDE, SYS_PROP_NOT_SET) == 1) {
975             return true;
976         }
977 
978         return mContext.getResources()
979                         .getBoolean(com.android.internal.R.bool.config_device_wfc_ims_available)
980                 && getBooleanCarrierConfig(CarrierConfigManager.KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL)
981                 && isGbaValid();
982     }
983 
984     /**
985      * Returns whether wi-fi calling setting is enabled by user.
986      *
987      * @return true, if wi-fi calling setting is enabled by user.
988      */
isWfcEnabledByUser()989     boolean isWfcEnabledByUser() {
990         boolean wfcEnabled;
991         try {
992             ImsMmTelManager mmTelManager = getImsMmTelManagerOrThrowExceptionIfNotReady();
993             wfcEnabled = mmTelManager.isVoWiFiSettingEnabled();
994         } catch (Exception e) {
995             wfcEnabled =
996                     getBooleanCarrierConfig(
997                             CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_ENABLED_BOOL);
998         }
999         log("isWfcEnabledByUser:" + wfcEnabled);
1000         return wfcEnabled;
1001     }
1002 
1003     /**
1004      * Returns whether wi-fi calling roaming setting is enabled by user.
1005      *
1006      * @return true, if wi-fi calling roaming setting is enabled by user.
1007      */
isWfcRoamingEnabledByUser()1008     boolean isWfcRoamingEnabledByUser() {
1009         boolean wfcRoamingEnabled;
1010         try {
1011             ImsMmTelManager mmTelManager = getImsMmTelManagerOrThrowExceptionIfNotReady();
1012             wfcRoamingEnabled = mmTelManager.isVoWiFiRoamingSettingEnabled();
1013         } catch (Exception e) {
1014             wfcRoamingEnabled =
1015                     getBooleanCarrierConfig(
1016                             CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_ENABLED_BOOL);
1017         }
1018         log("isWfcRoamingEnabledByUser:" + wfcRoamingEnabled);
1019         return wfcRoamingEnabled;
1020     }
1021 
1022     /**
1023      * Returns whether cross sim wi-fi calling is enabled.
1024      *
1025      * @return true, if cross sim wi-fi calling is enabled.
1026      */
isCrossSimCallingEnabled()1027     boolean isCrossSimCallingEnabled() {
1028         boolean userEnabled = isCrossSimCallingEnabledByUser();
1029         boolean platformEnabled = isCrossSimEnabledByPlatform();
1030         boolean isProvisioned = isWfcProvisionedOnDevice();
1031 
1032         log(
1033                 "isCrossSimCallingEnabled: platformEnabled = "
1034                         + platformEnabled
1035                         + ", provisioned = "
1036                         + isProvisioned
1037                         + ", userEnabled = "
1038                         + userEnabled);
1039         return userEnabled && platformEnabled && isProvisioned;
1040     }
1041 
1042     /**
1043      * Returns Voice over Wi-Fi mode preference
1044      *
1045      * @param roaming false:mode pref for home, true:mode pref for roaming
1046      * @return voice over Wi-Fi mode preference, which can be one of the following: {@link
1047      *     ImsMmTelManager#WIFI_MODE_WIFI_ONLY}, {@link
1048      *     ImsMmTelManager#WIFI_MODE_CELLULAR_PREFERRED}, {@link
1049      *     ImsMmTelManager#WIFI_MODE_WIFI_PREFERRED}
1050      */
getWfcMode(boolean roaming)1051     int getWfcMode(boolean roaming) {
1052         if (!roaming) {
1053             int wfcMode;
1054             try {
1055                 ImsMmTelManager mmTelManager = getImsMmTelManagerOrThrowExceptionIfNotReady();
1056                 wfcMode = mmTelManager.getVoWiFiModeSetting();
1057             } catch (Exception e) {
1058                 wfcMode =
1059                         getIntCarrierConfig(
1060                                 CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT);
1061             }
1062             log("getWfcMode:" + wfcMode);
1063             return wfcMode;
1064         } else {
1065             int wfcRoamingMode;
1066             try {
1067                 ImsMmTelManager mmTelManager = getImsMmTelManagerOrThrowExceptionIfNotReady();
1068                 wfcRoamingMode = mmTelManager.getVoWiFiRoamingModeSetting();
1069             } catch (Exception e) {
1070                 wfcRoamingMode =
1071                         getIntCarrierConfig(
1072                                 CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_MODE_INT);
1073             }
1074             log("getWfcMode(roaming):" + wfcRoamingMode);
1075             return wfcRoamingMode;
1076         }
1077     }
1078 
1079     /**
1080      * Indicates whether VoWifi is provisioned on slot.
1081      *
1082      * <p>When CarrierConfig KEY_CARRIER_VOLTE_OVERRIDE_WFC_PROVISIONING_BOOL is true, and VoLTE is
1083      * not provisioned on device, this method returns false.
1084      */
isWfcProvisionedOnDevice()1085     boolean isWfcProvisionedOnDevice() {
1086         if (getBooleanCarrierConfig(
1087                 CarrierConfigManager.KEY_CARRIER_VOLTE_OVERRIDE_WFC_PROVISIONING_BOOL)) {
1088             if (!isVolteProvisionedOnDevice()) {
1089                 return false;
1090             }
1091         }
1092 
1093         if (isMmTelProvisioningRequired(REGISTRATION_TECH_IWLAN)) {
1094             return isWfcProvisioned();
1095         }
1096 
1097         return true;
1098     }
1099 
log(String s)1100     protected void log(String s) {
1101         Log.d(mLogTag, s);
1102     }
1103 
loge(String s)1104     protected void loge(String s) {
1105         Log.e(mLogTag, s);
1106     }
1107 }
1108