• 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("registerImsRegistrationCallback: 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             } catch (UnsupportedOperationException e) {
285                 loge("registerSipDialogStateCallback: couldn't register callback, " + e);
286             }
287         }
288     }
289 
stopTrackingImsState(int feature)290     protected synchronized void stopTrackingImsState(int feature) {
291         if (feature == ImsFeature.FEATURE_MMTEL
292                 && mImsMmTelManager != null
293                 && mMmTelStateCallback != null) {
294             try {
295                 mImsMmTelManager.unregisterImsStateCallback(mMmTelStateCallback);
296             } catch (Exception e) {
297                 // do-nothing
298             }
299         }
300         if (feature == ImsFeature.FEATURE_RCS
301                 && mImsRcsManager != null
302                 && mRcsStateCallback != null) {
303             try {
304                 mImsRcsManager.unregisterImsStateCallback(mRcsStateCallback);
305             } catch (Exception e) {
306                 // do-nothing
307             }
308         }
309     }
310 
stopTrackingImsRegistration(int feature)311     protected synchronized void stopTrackingImsRegistration(int feature) {
312         if (feature == ImsFeature.FEATURE_MMTEL
313                 && mImsMmTelManager != null
314                 && mMmtelImsRegistrationCallback != null) {
315             try {
316                 mImsMmTelManager.unregisterImsRegistrationCallback(mMmtelImsRegistrationCallback);
317             } catch (Exception e) {
318                 // do-nothing
319             }
320         }
321         if (feature == ImsFeature.FEATURE_RCS
322                 && mImsRcsManager != null
323                 && mRcsImsRegistrationCallback != null) {
324             try {
325                 mImsRcsManager.unregisterImsRegistrationCallback(mRcsImsRegistrationCallback);
326             } catch (Exception e) {
327                 // do-nothing
328             }
329         }
330     }
331 
stopTrackingSipDialogSessionState(int feature)332     protected synchronized void stopTrackingSipDialogSessionState(int feature) {
333         if (feature == ImsFeature.FEATURE_RCS
334                 && mSipDelegateManager != null
335                 && mRcsSipDialogSessionStateCallback != null) {
336             try {
337                 mSipDelegateManager.unregisterSipDialogStateCallback(
338                         mRcsSipDialogSessionStateCallback);
339             } catch (Exception e) {
340                 // do-nothing
341             }
342         }
343     }
344 
345     @VisibleForTesting
clearQnsImsManager()346     protected synchronized void clearQnsImsManager() {
347         log("clearQnsImsManager");
348 
349         stopTrackingImsState(ImsFeature.FEATURE_MMTEL);
350         stopTrackingImsState(ImsFeature.FEATURE_RCS);
351         stopTrackingImsRegistration(ImsFeature.FEATURE_MMTEL);
352         stopTrackingImsRegistration(ImsFeature.FEATURE_RCS);
353         stopTrackingSipDialogSessionState(ImsFeature.FEATURE_RCS);
354 
355         mImsManager = null;
356         mImsMmTelManager = null;
357         mImsRcsManager = null;
358         mSipDelegateManager = null;
359         mMmTelStateCallback = null;
360         mMmtelImsRegistrationCallback = null;
361         mRcsStateCallback = null;
362         mRcsImsRegistrationCallback = null;
363         mRcsSipDialogSessionStateCallback = null;
364         mQnsImsManagerInitialized = false;
365     }
366 
367     @VisibleForTesting
close()368     protected synchronized void close() {
369         if (mSubscriptionManager != null) {
370             mSubscriptionManager.removeOnSubscriptionsChangedListener(mSubscriptionsChangeListener);
371         }
372         mHandlerThread.quitSafely();
373         clearQnsImsManager();
374 
375         mMmTelImsStateListener.removeAll();
376         mRcsImsStateListener.removeAll();
377         mMmTelImsRegistrationListener.removeAll();
378         mRcsImsRegistrationListener.removeAll();
379         mRcsSipDialogSessionStateListener.removeAll();
380     }
381 
getSlotIndex()382     int getSlotIndex() {
383         return mSlotId;
384     }
385 
getImsMmTelManagerOrThrowExceptionIfNotReady()386     private synchronized ImsMmTelManager getImsMmTelManagerOrThrowExceptionIfNotReady()
387             throws ImsException {
388         initQnsImsManager();
389         if (mImsManager == null || mImsMmTelManager == null || mMmTelStateCallback == null) {
390             throw new ImsException(
391                     "IMS service is down.", ImsReasonInfo.CODE_LOCAL_IMS_SERVICE_DOWN);
392         }
393         return mImsMmTelManager;
394     }
395 
396     /**
397      * Get the boolean config from carrier config manager.
398      *
399      * @param key config key defined in CarrierConfigManager
400      * @return boolean value of corresponding key.
401      */
getBooleanCarrierConfig(String key)402     private boolean getBooleanCarrierConfig(String key) {
403         PersistableBundle b = null;
404         if (mConfigManager != null) {
405             // If an invalid subId is used, this bundle will contain default values.
406             b = mConfigManager.getConfigForSubId(getSubId());
407         }
408         if (b != null) {
409             return b.getBoolean(key);
410         } else {
411             // Return static default defined in CarrierConfigManager.
412             return CarrierConfigManager.getDefaultConfig().getBoolean(key);
413         }
414     }
415 
416     /**
417      * Get the int config from carrier config manager.
418      *
419      * @param key config key defined in CarrierConfigManager
420      * @return integer value of corresponding key.
421      */
getIntCarrierConfig(String key)422     private int getIntCarrierConfig(String key) {
423         PersistableBundle b = null;
424         if (mConfigManager != null) {
425             // If an invalid subId is used, this bundle will contain default values.
426             b = mConfigManager.getConfigForSubId(getSubId());
427         }
428         if (b != null) {
429             return b.getInt(key);
430         } else {
431             // Return static default defined in CarrierConfigManager.
432             return CarrierConfigManager.getDefaultConfig().getInt(key);
433         }
434     }
435 
isCrossSimCallingEnabledByUser()436     private boolean isCrossSimCallingEnabledByUser() {
437         boolean crossSimCallingEnabled;
438         try {
439             ImsMmTelManager mmTelManager = getImsMmTelManagerOrThrowExceptionIfNotReady();
440             crossSimCallingEnabled = mmTelManager.isCrossSimCallingEnabled();
441         } catch (Exception e) {
442             crossSimCallingEnabled = false;
443         }
444         log("isCrossSimCallingEnabledByUser:" + crossSimCallingEnabled);
445         return crossSimCallingEnabled;
446     }
447 
isGbaValid()448     private boolean isGbaValid() {
449         if (getBooleanCarrierConfig(CarrierConfigManager.KEY_CARRIER_IMS_GBA_REQUIRED_BOOL)) {
450             TelephonyManager tm = mContext.getSystemService(TelephonyManager.class);
451             if (tm == null) {
452                 loge("isGbaValid: TelephonyManager is null, returning false.");
453                 return false;
454             }
455             tm = tm.createForSubscriptionId(getSubId());
456             String efIst = tm.getIsimIst();
457             if (efIst == null) {
458                 loge("isGbaValid - ISF is NULL");
459                 return true;
460             }
461             boolean result = efIst.length() > 1 && (0x02 & (byte) efIst.charAt(1)) != 0;
462             log("isGbaValid - GBA capable=" + result + ", ISF=" + efIst);
463             return result;
464         }
465         return true;
466     }
467 
isCrossSimEnabledByPlatform()468     private boolean isCrossSimEnabledByPlatform() {
469         if (isWfcEnabledByPlatform()) {
470             return getBooleanCarrierConfig(
471                     CarrierConfigManager.KEY_CARRIER_CROSS_SIM_IMS_AVAILABLE_BOOL);
472         }
473         return false;
474     }
475 
isVolteProvisionedOnDevice()476     private boolean isVolteProvisionedOnDevice() {
477         if (isMmTelProvisioningRequired(REGISTRATION_TECH_LTE)) {
478             return isVolteProvisioned();
479         }
480 
481         return true;
482     }
483 
isVolteProvisioned()484     private boolean isVolteProvisioned() {
485         return getImsProvisionedBoolNoException(REGISTRATION_TECH_LTE);
486     }
487 
isWfcProvisioned()488     private boolean isWfcProvisioned() {
489         return getImsProvisionedBoolNoException(REGISTRATION_TECH_IWLAN);
490     }
491 
isMmTelProvisioningRequired(int tech)492     private boolean isMmTelProvisioningRequired(int tech) {
493         if (!SubscriptionManager.isValidSubscriptionId(getSubId())) {
494             return false;
495         }
496 
497         boolean required = false;
498         try {
499             ProvisioningManager p = ProvisioningManager.createForSubscriptionId(getSubId());
500             required = p.isProvisioningRequiredForCapability(CAPABILITY_TYPE_VOICE, tech);
501         } catch (RuntimeException e) {
502             loge("isMmTelProvisioningRequired, tech:" + tech + ". e:" + e);
503         }
504 
505         log("isMmTelProvisioningRequired " + required + " for tech:" + tech);
506         return required;
507     }
508 
getImsProvisionedBoolNoException(int tech)509     private boolean getImsProvisionedBoolNoException(int tech) {
510         if (!SubscriptionManager.isValidSubscriptionId(getSubId())) {
511             return false;
512         }
513 
514         boolean status = false;
515         try {
516             ProvisioningManager p = ProvisioningManager.createForSubscriptionId(getSubId());
517             status = p.getProvisioningStatusForCapability(CAPABILITY_TYPE_VOICE, tech);
518         } catch (RuntimeException e) {
519             loge("getImsProvisionedBoolNoException, tech:" + tech + ". e:" + e);
520         }
521 
522         log("getImsProvisionedBoolNoException " + status + " for tech:" + tech);
523         return status;
524     }
525 
getSubId()526     private int getSubId() {
527         return QnsUtils.getSubId(mContext, mSlotId);
528     }
529 
530     private static class QnsImsManagerExecutor implements Executor {
531         private Executor mExecutor;
532 
533         @Override
execute(Runnable runnable)534         public void execute(Runnable runnable) {
535             startExecutorIfNeeded();
536             mExecutor.execute(runnable);
537         }
538 
startExecutorIfNeeded()539         private synchronized void startExecutorIfNeeded() {
540             if (mExecutor != null) return;
541             mExecutor = Executors.newSingleThreadExecutor();
542         }
543     }
544 
545     private class QnsImsStateCallback extends ImsStateCallback {
546         int mImsFeature;
547         boolean mImsAvailable;
548 
isImsAvailable()549         public boolean isImsAvailable() {
550             return mImsAvailable;
551         }
552 
QnsImsStateCallback(int imsFeature)553         QnsImsStateCallback(int imsFeature) {
554             mImsFeature = imsFeature;
555         }
556 
557         @Override
onUnavailable(int reason)558         public void onUnavailable(int reason) {
559             changeImsState(false);
560         }
561 
562         @Override
onAvailable()563         public void onAvailable() {
564             changeImsState(true);
565         }
566 
567         @Override
onError()568         public void onError() {
569             changeImsState(false);
570         }
571 
changeImsState(boolean imsAvailable)572         private void changeImsState(boolean imsAvailable) {
573             if (mImsAvailable != imsAvailable) {
574                 mImsAvailable = imsAvailable;
575                 onImsStateChanged(mImsFeature, imsAvailable);
576             }
577         }
578     }
579 
580     /** class for the IMS State. */
581     static class ImsState {
582         private final boolean mImsAvailable;
583 
ImsState(boolean imsAvailable)584         ImsState(boolean imsAvailable) {
585             mImsAvailable = imsAvailable;
586         }
587 
isImsAvailable()588         boolean isImsAvailable() {
589             return mImsAvailable;
590         }
591     }
592 
onImsStateChanged(int imsFeature, boolean imsAvailable)593     private void onImsStateChanged(int imsFeature, boolean imsAvailable) {
594         if (imsFeature == ImsFeature.FEATURE_MMTEL) {
595             log("onImsStateChanged ImsFeature.MMTEL:" + imsAvailable);
596         }
597         if (imsFeature == ImsFeature.FEATURE_RCS) {
598             log("onImsStateChanged ImsFeature.RCS:" + imsAvailable);
599         }
600 
601         if (imsAvailable) {
602             startTrackingImsRegistration(imsFeature);
603             if (imsFeature == ImsFeature.FEATURE_RCS) {
604                 startTrackingSipDialogSessionState(imsFeature);
605             }
606         }
607 
608         ImsState imsState = new ImsState(imsAvailable);
609         notifyImsStateChanged(imsFeature, imsState);
610     }
611 
612     /**
613      * Registers to monitor Ims State
614      *
615      * @param h Handler to get an event
616      * @param what message id.
617      */
registerImsStateChanged(Handler h, int what)618     void registerImsStateChanged(Handler h, int what) {
619         QnsRegistrant r = new QnsRegistrant(h, what, null);
620         mMmTelImsStateListener.add(r);
621     }
622 
623     /**
624      * Unregisters ims state for given handler.
625      *
626      * @param h Handler
627      */
unregisterImsStateChanged(Handler h)628     void unregisterImsStateChanged(Handler h) {
629         mMmTelImsStateListener.remove(h);
630     }
631 
632     /**
633      * Registers to monitor Rcs State
634      *
635      * @param h Handler to get an event
636      * @param what message id.
637      */
registerRcsStateChanged(Handler h, int what)638     void registerRcsStateChanged(Handler h, int what) {
639         QnsRegistrant r = new QnsRegistrant(h, what, null);
640         mRcsImsStateListener.add(r);
641     }
642 
643     /**
644      * Unregisters rcs state for given handler.
645      *
646      * @param h Handler
647      */
unregisterRcsStateChanged(Handler h)648     void unregisterRcsStateChanged(Handler h) {
649         mRcsImsStateListener.remove(h);
650     }
651 
notifyImsStateChanged(int imsFeature, ImsState imsState)652     protected void notifyImsStateChanged(int imsFeature, ImsState imsState) {
653         if (imsFeature == ImsFeature.FEATURE_MMTEL) {
654             mMmTelImsStateListener.notifyResult(imsState);
655         } else if (imsFeature == ImsFeature.FEATURE_RCS) {
656             mRcsImsStateListener.notifyResult(imsState);
657         }
658     }
659 
660     private static class StateConsumer extends Semaphore implements Consumer<Integer> {
661         private static final long TIMEOUT_MILLIS = 2000;
662 
StateConsumer()663         StateConsumer() {
664             super(0);
665             mValue = new AtomicInteger();
666         }
667 
668         private final AtomicInteger mValue;
669 
getOrTimeOut()670         int getOrTimeOut() throws InterruptedException {
671             if (tryAcquire(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)) {
672                 return mValue.get();
673             }
674             return ImsFeature.STATE_UNAVAILABLE;
675         }
676 
accept(Integer value)677         public void accept(Integer value) {
678             if (value != null) {
679                 mValue.set(value);
680             }
681             release();
682         }
683     }
684 
685     private class QnsImsRegistrationCallback extends RegistrationManager.RegistrationCallback {
686         int mImsFeature;
687         ImsRegistrationState mImsRegistrationState;
688 
QnsImsRegistrationCallback(int imsFeature)689         QnsImsRegistrationCallback(int imsFeature) {
690             mImsFeature = imsFeature;
691             mImsRegistrationState = null;
692         }
693 
694         @Override
onRegistered(ImsRegistrationAttributes attribute)695         public void onRegistered(ImsRegistrationAttributes attribute) {
696             int transportType = attribute.getTransportType();
697             log("on IMS registered on :" + QnsConstants.transportTypeToString(transportType));
698             mImsRegistrationState =
699                     new ImsRegistrationState(
700                             QnsConstants.IMS_REGISTRATION_CHANGED_REGISTERED, transportType, null);
701             notifyImsRegistrationChangedEvent(
702                     mImsFeature, new ImsRegistrationState(mImsRegistrationState));
703         }
704 
705         @Override
onTechnologyChangeFailed(int transportType, ImsReasonInfo reason)706         public void onTechnologyChangeFailed(int transportType, ImsReasonInfo reason) {
707             log(
708                     "onTechnologyChangeFailed["
709                             + QnsConstants.transportTypeToString(transportType)
710                             + "] "
711                             + reason.toString());
712             mImsRegistrationState =
713                     new ImsRegistrationState(
714                             QnsConstants.IMS_REGISTRATION_CHANGED_ACCESS_NETWORK_CHANGE_FAILED,
715                             transportType,
716                             reason);
717             notifyImsRegistrationChangedEvent(
718                     mImsFeature, new ImsRegistrationState(mImsRegistrationState));
719         }
720 
721         @Override
onUnregistered(ImsReasonInfo reason)722         public void onUnregistered(ImsReasonInfo reason) {
723             log("onUnregistered " + reason.toString());
724             mImsRegistrationState =
725                     new ImsRegistrationState(
726                             QnsConstants.IMS_REGISTRATION_CHANGED_UNREGISTERED,
727                             AccessNetworkConstants.TRANSPORT_TYPE_INVALID,
728                             reason);
729             notifyImsRegistrationChangedEvent(
730                     mImsFeature, new ImsRegistrationState(mImsRegistrationState));
731         }
732     }
733 
734     private class QnsSipDialogStateCallback extends SipDialogStateCallback {
735         boolean mIsActive;
736 
isActive()737         public boolean isActive() {
738             return mIsActive;
739         }
740 
741         @Override
onActiveSipDialogsChanged(@onNull List<SipDialogState> dialogs)742         public void onActiveSipDialogsChanged(@NonNull List<SipDialogState> dialogs) {
743             for (SipDialogState state : dialogs) {
744                 if (state.getState() == SipDialogState.STATE_CONFIRMED) {
745                     if (!mIsActive) {
746                         mIsActive = true;
747                         notifySipDialogSessionStateChanged(mIsActive);
748                     }
749                     return;
750                 }
751             }
752             if (mIsActive) {
753                 mIsActive = false;
754                 notifySipDialogSessionStateChanged(mIsActive);
755             }
756         }
757 
758         @Override
onError()759         public void onError() {
760             mIsActive = false;
761             notifySipDialogSessionStateChanged(mIsActive);
762             // TODO do nothing?
763         }
764     }
765 
766     /** State class for the IMS Registration. */
767     static class ImsRegistrationState {
768         @QnsConstants.QnsImsRegiEvent private final int mEvent;
769         private final int mTransportType;
770         private final ImsReasonInfo mReasonInfo;
771 
ImsRegistrationState(int event, int transportType, ImsReasonInfo reason)772         ImsRegistrationState(int event, int transportType, ImsReasonInfo reason) {
773             mEvent = event;
774             mTransportType = transportType;
775             mReasonInfo = reason;
776         }
777 
ImsRegistrationState(ImsRegistrationState state)778         ImsRegistrationState(ImsRegistrationState state) {
779             mEvent = state.mEvent;
780             mTransportType = state.mTransportType;
781             mReasonInfo = state.mReasonInfo;
782         }
783 
getEvent()784         int getEvent() {
785             return mEvent;
786         }
787 
getTransportType()788         int getTransportType() {
789             return mTransportType;
790         }
791 
getReasonInfo()792         ImsReasonInfo getReasonInfo() {
793             return mReasonInfo;
794         }
795 
796         @Override
toString()797         public String toString() {
798             String reason = getReasonInfo() == null ? "null" : mReasonInfo.toString();
799             String event = Integer.toString(mEvent);
800             switch (mEvent) {
801                 case QnsConstants.IMS_REGISTRATION_CHANGED_REGISTERED:
802                     event = "IMS_REGISTERED";
803                     break;
804                 case QnsConstants.IMS_REGISTRATION_CHANGED_UNREGISTERED:
805                     event = "IMS_UNREGISTERED";
806                     break;
807                 case QnsConstants.IMS_REGISTRATION_CHANGED_ACCESS_NETWORK_CHANGE_FAILED:
808                     event = "IMS_ACCESS_NETWORK_CHANGE_FAILED";
809                     break;
810             }
811             return "ImsRegistrationState["
812                     + QnsConstants.transportTypeToString(mTransportType)
813                     + "] "
814                     + "Event:"
815                     + event
816                     + " reason:"
817                     + reason;
818         }
819     }
820 
821     /**
822      * Get the status of whether the IMS is registered or not for given transport type
823      *
824      * @param transportType Transport Type
825      * @return true when ims is registered.
826      */
isImsRegistered(int transportType)827     boolean isImsRegistered(int transportType) {
828         if (mMmtelImsRegistrationCallback == null) {
829             return false;
830         }
831         ImsRegistrationState state = mMmtelImsRegistrationCallback.mImsRegistrationState;
832         return state != null
833                 && state.getTransportType() == transportType
834                 && state.getEvent() == QnsConstants.IMS_REGISTRATION_CHANGED_REGISTERED;
835     }
836 
837     /**
838      * Get the status of whether the Rcs is registered or not for given transport type
839      *
840      * @param transportType Transport Type
841      * @return true when ims is registered.
842      */
isRcsRegistered(int transportType)843     boolean isRcsRegistered(int transportType) {
844         if (mRcsImsRegistrationCallback == null) {
845             return false;
846         }
847         ImsRegistrationState state = mRcsImsRegistrationCallback.mImsRegistrationState;
848         return state != null
849                 && state.getTransportType() == transportType
850                 && state.getEvent() == QnsConstants.IMS_REGISTRATION_CHANGED_REGISTERED;
851     }
852 
853     /**
854      * Registers to monitor Ims registration status
855      *
856      * @param h Handler to get an event
857      * @param what message id.
858      */
registerImsRegistrationStatusChanged(Handler h, int what)859     void registerImsRegistrationStatusChanged(Handler h, int what) {
860         QnsRegistrant r = new QnsRegistrant(h, what, null);
861         mMmTelImsRegistrationListener.add(r);
862     }
863 
864     /**
865      * Unregisters ims registration status for given handler.
866      *
867      * @param h Handler
868      */
unregisterImsRegistrationStatusChanged(Handler h)869     void unregisterImsRegistrationStatusChanged(Handler h) {
870         mMmTelImsRegistrationListener.remove(h);
871     }
872 
873     /**
874      * Registers to monitor Ims registration status
875      *
876      * @param h Handler to get an event
877      * @param what message id.
878      */
registerRcsRegistrationStatusChanged(Handler h, int what)879     void registerRcsRegistrationStatusChanged(Handler h, int what) {
880         QnsRegistrant r = new QnsRegistrant(h, what, null);
881         mRcsImsRegistrationListener.add(r);
882     }
883 
884     /**
885      * Unregisters ims registration status for given handler.
886      *
887      * @param h Handler
888      */
unregisterRcsRegistrationStatusChanged(Handler h)889     void unregisterRcsRegistrationStatusChanged(Handler h) {
890         mRcsImsRegistrationListener.remove(h);
891     }
892 
893     @VisibleForTesting
notifyImsRegistrationChangedEvent(int imsFeature, ImsRegistrationState state)894     protected void notifyImsRegistrationChangedEvent(int imsFeature, ImsRegistrationState state) {
895         if (imsFeature == ImsFeature.FEATURE_MMTEL) {
896             mMmTelImsRegistrationListener.notifyResult(state);
897         } else if (imsFeature == ImsFeature.FEATURE_RCS) {
898             mRcsImsRegistrationListener.notifyResult(state);
899         }
900     }
901 
902     /**
903      * Get the active status of SipDialogState
904      *
905      * @return true when one of Sip Dialogs is active.
906      */
isSipDialogSessionActive()907     boolean isSipDialogSessionActive() {
908         return mRcsSipDialogSessionStateCallback != null
909                 && mRcsSipDialogSessionStateCallback.isActive();
910     }
911 
912     /**
913      * Registers to monitor SipDialogSession State
914      *
915      * @param h Handler to get an event
916      * @param what message id.
917      */
registerSipDialogSessionStateChanged(Handler h, int what)918     void registerSipDialogSessionStateChanged(Handler h, int what) {
919         QnsRegistrant r = new QnsRegistrant(h, what, null);
920         mRcsSipDialogSessionStateListener.add(r);
921     }
922 
923     /**
924      * Unregisters SipDialogState status for given handler.
925      *
926      * @param h Handler
927      */
unregisterSipDialogSessionStateChanged(Handler h)928     void unregisterSipDialogSessionStateChanged(Handler h) {
929         mRcsSipDialogSessionStateListener.remove(h);
930     }
931 
932     @VisibleForTesting
notifySipDialogSessionStateChanged(boolean isActive)933     protected void notifySipDialogSessionStateChanged(boolean isActive) {
934         mRcsSipDialogSessionStateListener.notifyResult(isActive);
935     }
936 
isImsSupportedOnDevice(Context context)937     private static boolean isImsSupportedOnDevice(Context context) {
938         return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY_IMS);
939     }
940 
941     /**
942      * Get the status of the MmTel Feature corresponding to this subscription.
943      *
944      * <p>This function is a blocking function and there may be a timeout of up to 2 seconds.
945      *
946      * @return MmTel Feature Status. Returns one of the following: {@link
947      *     ImsFeature#STATE_UNAVAILABLE}, {@link ImsFeature#STATE_INITIALIZING}, {@link
948      *     ImsFeature#STATE_READY}.
949      * @throws ImsException if the IMS service associated with this subscription is not available or
950      *     the IMS service is not available.
951      * @throws InterruptedException if the thread to get value is timed out. (max 2000ms)
952      */
getImsServiceState()953     int getImsServiceState() throws ImsException, InterruptedException {
954         if (!isImsSupportedOnDevice(mContext)) {
955             throw new ImsException(
956                     "IMS not supported on device.",
957                     ImsReasonInfo.CODE_LOCAL_IMS_NOT_SUPPORTED_ON_DEVICE);
958         }
959         ImsMmTelManager mmTelManager = getImsMmTelManagerOrThrowExceptionIfNotReady();
960         final StateConsumer stateConsumer = new StateConsumer();
961         mmTelManager.getFeatureState(mExecutor, stateConsumer);
962         int state = stateConsumer.getOrTimeOut(); // ImsFeature.STATE_READY
963         log("getImsServiceState state:" + state);
964         return state;
965     }
966 
967     /**
968      * Returns whether wi-fi calling feature is enabled by platform.
969      *
970      * <p>This function is a blocking function and there may be a timeout of up to 2 seconds.
971      *
972      * @return true, if wi-fi calling feature is enabled by platform.
973      */
isWfcEnabledByPlatform()974     boolean isWfcEnabledByPlatform() {
975         // We first read the per slot value. If it doesn't exist, we read the general value.
976         // If still doesn't exist, we use the hardcoded default value.
977         if (SystemProperties.getInt(PROP_DBG_WFC_AVAIL_OVERRIDE + mSlotId, SYS_PROP_NOT_SET) == 1
978                 || SystemProperties.getInt(PROP_DBG_WFC_AVAIL_OVERRIDE, SYS_PROP_NOT_SET) == 1) {
979             return true;
980         }
981 
982         return mContext.getResources()
983                         .getBoolean(com.android.internal.R.bool.config_device_wfc_ims_available)
984                 && getBooleanCarrierConfig(CarrierConfigManager.KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL)
985                 && isGbaValid();
986     }
987 
988     /**
989      * Returns whether wi-fi calling setting is enabled by user.
990      *
991      * @return true, if wi-fi calling setting is enabled by user.
992      */
isWfcEnabledByUser()993     boolean isWfcEnabledByUser() {
994         boolean wfcEnabled;
995         try {
996             ImsMmTelManager mmTelManager = getImsMmTelManagerOrThrowExceptionIfNotReady();
997             wfcEnabled = mmTelManager.isVoWiFiSettingEnabled();
998         } catch (Exception e) {
999             wfcEnabled =
1000                     getBooleanCarrierConfig(
1001                             CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_ENABLED_BOOL);
1002         }
1003         log("isWfcEnabledByUser:" + wfcEnabled);
1004         return wfcEnabled;
1005     }
1006 
1007     /**
1008      * Returns whether wi-fi calling roaming setting is enabled by user.
1009      *
1010      * @return true, if wi-fi calling roaming setting is enabled by user.
1011      */
isWfcRoamingEnabledByUser()1012     boolean isWfcRoamingEnabledByUser() {
1013         boolean wfcRoamingEnabled;
1014         try {
1015             ImsMmTelManager mmTelManager = getImsMmTelManagerOrThrowExceptionIfNotReady();
1016             wfcRoamingEnabled = mmTelManager.isVoWiFiRoamingSettingEnabled();
1017         } catch (Exception e) {
1018             wfcRoamingEnabled =
1019                     getBooleanCarrierConfig(
1020                             CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_ENABLED_BOOL);
1021         }
1022         log("isWfcRoamingEnabledByUser:" + wfcRoamingEnabled);
1023         return wfcRoamingEnabled;
1024     }
1025 
1026     /**
1027      * Returns whether cross sim wi-fi calling is enabled.
1028      *
1029      * @return true, if cross sim wi-fi calling is enabled.
1030      */
isCrossSimCallingEnabled()1031     boolean isCrossSimCallingEnabled() {
1032         boolean userEnabled = isCrossSimCallingEnabledByUser();
1033         boolean platformEnabled = isCrossSimEnabledByPlatform();
1034         boolean isProvisioned = isWfcProvisionedOnDevice();
1035 
1036         log(
1037                 "isCrossSimCallingEnabled: platformEnabled = "
1038                         + platformEnabled
1039                         + ", provisioned = "
1040                         + isProvisioned
1041                         + ", userEnabled = "
1042                         + userEnabled);
1043         return userEnabled && platformEnabled && isProvisioned;
1044     }
1045 
1046     /**
1047      * Returns Voice over Wi-Fi mode preference
1048      *
1049      * @param roaming false:mode pref for home, true:mode pref for roaming
1050      * @return voice over Wi-Fi mode preference, which can be one of the following: {@link
1051      *     ImsMmTelManager#WIFI_MODE_WIFI_ONLY}, {@link
1052      *     ImsMmTelManager#WIFI_MODE_CELLULAR_PREFERRED}, {@link
1053      *     ImsMmTelManager#WIFI_MODE_WIFI_PREFERRED}
1054      */
getWfcMode(boolean roaming)1055     int getWfcMode(boolean roaming) {
1056         if (!roaming) {
1057             int wfcMode;
1058             try {
1059                 ImsMmTelManager mmTelManager = getImsMmTelManagerOrThrowExceptionIfNotReady();
1060                 wfcMode = mmTelManager.getVoWiFiModeSetting();
1061             } catch (Exception e) {
1062                 wfcMode =
1063                         getIntCarrierConfig(
1064                                 CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_MODE_INT);
1065             }
1066             log("getWfcMode:" + wfcMode);
1067             return wfcMode;
1068         } else {
1069             int wfcRoamingMode;
1070             try {
1071                 ImsMmTelManager mmTelManager = getImsMmTelManagerOrThrowExceptionIfNotReady();
1072                 wfcRoamingMode = mmTelManager.getVoWiFiRoamingModeSetting();
1073             } catch (Exception e) {
1074                 wfcRoamingMode =
1075                         getIntCarrierConfig(
1076                                 CarrierConfigManager.KEY_CARRIER_DEFAULT_WFC_IMS_ROAMING_MODE_INT);
1077             }
1078             log("getWfcMode(roaming):" + wfcRoamingMode);
1079             return wfcRoamingMode;
1080         }
1081     }
1082 
1083     /**
1084      * Indicates whether VoWifi is provisioned on slot.
1085      *
1086      * <p>When CarrierConfig KEY_CARRIER_VOLTE_OVERRIDE_WFC_PROVISIONING_BOOL is true, and VoLTE is
1087      * not provisioned on device, this method returns false.
1088      */
isWfcProvisionedOnDevice()1089     boolean isWfcProvisionedOnDevice() {
1090         if (getBooleanCarrierConfig(
1091                 CarrierConfigManager.KEY_CARRIER_VOLTE_OVERRIDE_WFC_PROVISIONING_BOOL)) {
1092             if (!isVolteProvisionedOnDevice()) {
1093                 return false;
1094             }
1095         }
1096 
1097         if (isMmTelProvisioningRequired(REGISTRATION_TECH_IWLAN)) {
1098             return isWfcProvisioned();
1099         }
1100 
1101         return true;
1102     }
1103 
log(String s)1104     protected void log(String s) {
1105         Log.d(mLogTag, s);
1106     }
1107 
loge(String s)1108     protected void loge(String s) {
1109         Log.e(mLogTag, s);
1110     }
1111 }
1112