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 
17 package android.telephony.mockmodem;
18 
19 import static android.telephony.mockmodem.MockSimService.MOCK_SIM_PROFILE_ID_DEFAULT;
20 
21 import static com.android.internal.telephony.RILConstants.RIL_REQUEST_RADIO_POWER;
22 
23 import android.content.Context;
24 import android.hardware.radio.sim.Carrier;
25 import android.hardware.radio.sim.CarrierRestrictions;
26 import android.hardware.radio.voice.CdmaSignalInfoRecord;
27 import android.hardware.radio.voice.UusInfo;
28 import android.os.Build;
29 import android.os.Looper;
30 import android.os.SystemProperties;
31 import android.telephony.Annotation;
32 import android.telephony.BarringInfo;
33 import android.telephony.SubscriptionManager;
34 import android.telephony.TelephonyManager;
35 import android.telephony.cts.util.TelephonyUtils;
36 import android.telephony.ims.feature.ConnectionFailureInfo;
37 import android.telephony.ims.feature.MmTelFeature;
38 import android.telephony.ims.stub.ImsRegistrationImplBase;
39 import android.util.Log;
40 import android.util.SparseArray;
41 
42 import androidx.test.InstrumentationRegistry;
43 
44 import com.android.compatibility.common.util.TestThread;
45 
46 import java.util.List;
47 import java.util.Set;
48 import java.util.concurrent.TimeUnit;
49 import java.util.function.BooleanSupplier;
50 
51 public class MockModemManager {
52     private static final String TAG = "MockModemManager";
53     private static final boolean DEBUG = !"user".equals(Build.TYPE);
54 
55     private static final String ALLOW_MOCK_MODEM_PROPERTY = "persist.radio.allow_mock_modem";
56     private static final String BOOT_ALLOW_MOCK_MODEM_PROPERTY = "ro.boot.radio.allow_mock_modem";
57 
58     private static Context sContext;
59     private static MockModemServiceConnector sServiceConnector;
60     private static final long TIMEOUT_IN_MSEC_FOR_SIM_STATUS_CHANGED = 10000;
61     private static final int WAIT_UPDATE_TIMEOUT_MS = 200;  // 0.2sec delay
62     private MockModemService mMockModemService;
63 
enforceMockModemDeveloperSetting()64     public static void enforceMockModemDeveloperSetting() throws Exception {
65         boolean isAllowed = SystemProperties.getBoolean(ALLOW_MOCK_MODEM_PROPERTY, false);
66         boolean isAllowedForBoot =
67                 SystemProperties.getBoolean(BOOT_ALLOW_MOCK_MODEM_PROPERTY, false);
68         // Check for developer settings for user build. Always allow for debug builds
69         if (!(isAllowed || isAllowedForBoot) && !DEBUG) {
70             throw new IllegalStateException(
71                 "!! Enable Mock Modem before running this test !! "
72                     + "Developer options => Allow Mock Modem");
73         }
74     }
75 
MockModemManager()76     public MockModemManager() {
77         sContext = InstrumentationRegistry.getInstrumentation().getContext();
78     }
79 
waitForTelephonyFrameworkDone(int delayInSec)80     private void waitForTelephonyFrameworkDone(int delayInSec) throws Exception {
81         TimeUnit.SECONDS.sleep(delayInSec);
82     }
83 
waitForSubscriptionCondition(BooleanSupplier condition, long maxWaitMillis)84     private void waitForSubscriptionCondition(BooleanSupplier condition, long maxWaitMillis)
85             throws Exception {
86         final Object lock = new Object();
87         SubscriptionManager sm =
88                 (SubscriptionManager)
89                         sContext.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
90 
91         TestThread t =
92                 new TestThread(
93                         () -> {
94                             Looper.prepare();
95 
96                             SubscriptionManager.OnSubscriptionsChangedListener listener =
97                                     new SubscriptionManager.OnSubscriptionsChangedListener() {
98                                         @Override
99                                         public void onSubscriptionsChanged() {
100                                             synchronized (lock) {
101                                                 if (condition.getAsBoolean()) {
102                                                     lock.notifyAll();
103                                                     Looper.myLooper().quitSafely();
104                                                 }
105                                             }
106                                         }
107                                     };
108 
109                             sm.addOnSubscriptionsChangedListener(listener);
110                             try {
111                                 synchronized (lock) {
112                                     if (condition.getAsBoolean()) lock.notifyAll();
113                                 }
114                                 Log.d(TAG, "before loop()....");
115                                 if (!condition.getAsBoolean()) Looper.loop();
116                                 Log.d(TAG, "after loop()....");
117                             } finally {
118                                 sm.removeOnSubscriptionsChangedListener(listener);
119                             }
120                         });
121 
122         synchronized (lock) {
123             if (condition.getAsBoolean()) return;
124             t.start();
125             lock.wait(maxWaitMillis);
126         }
127     }
128 
129     /* Public APIs */
130 
131     /**
132      * Bring up Mock Modem Service and connect to it.
133      *
134      * @return boolean true if the operation is successful, otherwise false.
135      */
connectMockModemService()136     public boolean connectMockModemService() throws Exception {
137         return connectMockModemService(MOCK_SIM_PROFILE_ID_DEFAULT);
138     }
139 
140     /**
141      * Bring up Mock Modem Service and connect to it.
142      *
143      * @pararm simprofile for initial Sim profile
144      * @return boolean true if the operation is successful, otherwise false.
145      */
connectMockModemService(int simprofile)146     public boolean connectMockModemService(int simprofile) throws Exception {
147         int[] simprofiles = new int[1];
148         simprofiles[0] = Integer.valueOf(simprofile);
149 
150         return connectMockModemService(simprofiles);
151     }
152 
153     /**
154      * Bring up Mock Modem Service and connect to it.
155      *
156      * @param simprofiles for initial Sim profile of multiple Sim slots
157      * @return boolean true if the operation is successful, otherwise false.
158      */
connectMockModemService(int[] simprofiles)159     public boolean connectMockModemService(int[] simprofiles) throws Exception {
160         boolean result = true;
161 
162         if (simprofiles == null) {
163             Log.e(TAG, "The parameter is invalid.");
164             result = false;
165         }
166 
167         if (result && sServiceConnector == null) {
168             sServiceConnector =
169                     new MockModemServiceConnector(InstrumentationRegistry.getInstrumentation());
170         }
171 
172         if (result && sServiceConnector != null) {
173             result = sServiceConnector.connectMockModemService(simprofiles);
174 
175             if (result) {
176                 mMockModemService = sServiceConnector.getMockModemService();
177 
178                 if (mMockModemService != null) {
179                     /*
180                      It needs to have a delay to wait for Telephony Framework to bind with
181                      MockModemService and set radio power as a desired state for initial condition
182                      even get SIM card state. Currently, 1 sec is enough for now.
183                     */
184                     waitForTelephonyFrameworkDone(1);
185                 } else {
186                     Log.e(TAG, "MockModemService get failed!");
187                     result = false;
188                 }
189             }
190         } else {
191             Log.e(TAG, "Create MockModemServiceConnector failed!");
192         }
193 
194         return result;
195     }
196 
197     /**
198      * Disconnect from Mock Modem Service.
199      *
200      * @return boolean true if the operation is successful, otherwise false.
201      */
disconnectMockModemService()202     public boolean disconnectMockModemService() throws Exception {
203         boolean result = false;
204 
205         if (sServiceConnector != null) {
206             result = sServiceConnector.disconnectMockModemService();
207 
208             if (result) {
209                 mMockModemService = null;
210             } else {
211                 Log.e(TAG, "MockModemService disconnected failed!");
212             }
213         } else {
214             Log.e(TAG, "No MockModemServiceConnector exist!");
215         }
216 
217         return result;
218     }
219 
220     /**
221      * Query whether an active SIM card is present on this slot or not.
222      *
223      * @param slotId which slot would be checked.
224      * @return boolean true if any sim card inserted, otherwise false.
225      */
isSimCardPresent(int slotId)226     public boolean isSimCardPresent(int slotId) throws Exception {
227         Log.d(TAG, "isSimCardPresent[" + slotId + "]");
228 
229         MockModemConfigInterface configInterface = mMockModemService.getMockModemConfigInterface();
230         return (configInterface != null) ? configInterface.isSimCardPresent(slotId, TAG) : false;
231     }
232 
233     /**
234      * Insert a SIM card.
235      *
236      * @param slotId which slot would insert.
237      * @param simProfileId which carrier sim card is inserted.
238      * @return boolean true if the operation is successful, otherwise false.
239      */
insertSimCard(int slotId, int simProfileId)240     public boolean insertSimCard(int slotId, int simProfileId) throws Exception {
241         Log.d(TAG, "insertSimCard[" + slotId + "] with profile Id(" + simProfileId + ")");
242         boolean result = true;
243 
244         if (!isSimCardPresent(slotId)) {
245             MockModemConfigInterface configInterface =
246                     mMockModemService.getMockModemConfigInterface();
247             if (configInterface != null) {
248                 TelephonyManager tm = sContext.getSystemService(TelephonyManager.class);
249 
250                 result = configInterface.changeSimProfile(slotId, simProfileId, TAG);
251                 if (result) {
252                     try {
253                         waitForSubscriptionCondition(
254                                 () -> (TelephonyManager.SIM_STATE_PRESENT == tm.getSimCardState()),
255                                 TIMEOUT_IN_MSEC_FOR_SIM_STATUS_CHANGED);
256                     } finally {
257                         Log.d(TAG, "Insert Sim - subscription changed.");
258                     }
259                 }
260             }
261         } else {
262             Log.d(TAG, "There is a SIM inserted. Need to remove first.");
263             result = false;
264         }
265         return result;
266     }
267 
268     /**
269      * Remove a SIM card.
270      *
271      * @param slotId which slot would remove the SIM.
272      * @return boolean true if the operation is successful, otherwise false.
273      */
removeSimCard(int slotId)274     public boolean removeSimCard(int slotId) throws Exception {
275         Log.d(TAG, "removeSimCard[" + slotId + "]");
276         boolean result = true;
277 
278         if (isSimCardPresent(slotId)) {
279             MockModemConfigInterface configInterface =
280                     mMockModemService.getMockModemConfigInterface();
281             if (configInterface != null) {
282                 TelephonyManager tm = sContext.getSystemService(TelephonyManager.class);
283 
284                 result = configInterface.changeSimProfile(slotId, MOCK_SIM_PROFILE_ID_DEFAULT, TAG);
285                 if (result) {
286                     try {
287                         waitForSubscriptionCondition(
288                                 () -> (TelephonyManager.SIM_STATE_ABSENT == tm.getSimCardState()),
289                                 TIMEOUT_IN_MSEC_FOR_SIM_STATUS_CHANGED);
290                     } finally {
291                         Log.d(TAG, "Remove Sim - subscription changed.");
292                     }
293                 }
294             }
295         } else {
296             Log.d(TAG, "There is no SIM inserted.");
297             result = false;
298         }
299         return result;
300     }
301 
302     /**
303      * Modify SIM info of the SIM such as MCC/MNC, IMSI, etc.
304      *
305      * @param slotId for modifying.
306      * @param type the type of SIM info to modify.
307      * @param data to modify for the type of SIM info.
308      * @return boolean true if the operation is successful, otherwise false.
309      */
setSimInfo(int slotId, int type, String[] data)310     public boolean setSimInfo(int slotId, int type, String[] data) throws Exception {
311         Log.d(TAG, "setSimInfo[" + slotId + "]");
312         boolean result = true;
313 
314         if (isSimCardPresent(slotId)) {
315             MockModemConfigInterface configInterface =
316                     mMockModemService.getMockModemConfigInterface();
317             if (configInterface != null) {
318                 configInterface.setSimInfo(slotId, type, data, TAG);
319 
320                 // Wait for telephony framework refresh data and carrier config
321                 waitForTelephonyFrameworkDone(3);
322             } else {
323                 Log.e(TAG, "MockModemConfigInterface == null!");
324                 result = false;
325             }
326         } else {
327             Log.d(TAG, "There is no SIM inserted.");
328             result = false;
329         }
330         return result;
331     }
332 
333     /**
334      * Get SIM info of the SIM slot, e.g. MCC/MNC, IMSI.
335      *
336      * @param slotId for the query.
337      * @param type the type of SIM info.
338      * @return String the SIM info of the queried type.
339      */
getSimInfo(int slotId, int type)340     public String getSimInfo(int slotId, int type) throws Exception {
341         Log.d(TAG, "getSimInfo[" + slotId + "]");
342         String result = "";
343 
344         if (isSimCardPresent(slotId)) {
345             MockModemConfigInterface configInterface =
346                     mMockModemService.getMockModemConfigInterface();
347             if (configInterface != null) {
348                 result = configInterface.getSimInfo(slotId, type, TAG);
349             }
350         } else {
351             Log.d(TAG, "There is no SIM inserted.");
352         }
353         return result;
354     }
355 
356 
357     /**
358      * Sets the logical slots that are currently capable of performing cellular simultaneous
359      * calling.
360      * @param slotId The logical slot ID where the simultaneous calling state has changed
361      * @param enabledLogicalSlots The other logical slots that will have simultaneous calling
362      *     enabled for this slot.
363      * @return true if the operation succeeded, false if it failed
364      */
setSimulCallingEnabledLogicalSlots(int slotId, int[] enabledLogicalSlots)365     public boolean setSimulCallingEnabledLogicalSlots(int slotId,
366             int[] enabledLogicalSlots) throws Exception {
367         Log.d(TAG, "setSimulCallingEnabledLogicalSlots[" + slotId + "]");
368         boolean result = true;
369 
370         if (isSimCardPresent(slotId)) {
371             MockModemConfigInterface configInterface =
372                     mMockModemService.getMockModemConfigInterface();
373             if (configInterface != null) {
374                 configInterface.setSimulCallingEnabledLogicalSlots(slotId, enabledLogicalSlots,
375                         TAG);
376 
377                 // Wait for telephony framework refresh data and carrier config
378                 waitForTelephonyFrameworkDone(3);
379             } else {
380                 Log.e(TAG, "setSimulCallingEnabledLogicalSlots: MockModemConfigInterface"
381                         + " == null!");
382                 result = false;
383             }
384         } else {
385             Log.d(TAG, "setSimulCallingEnabledLogicalSlots: There is no SIM inserted.");
386             result = false;
387         }
388         return result;
389     }
390 
391     /**
392      * Force the response error return for a specific RIL request
393      *
394      * @param slotId which slot needs to be set.
395      * @param requestId the request/response message ID
396      * @param error RIL_Errno and -1 means to disable the modified mechanism, back to original mock
397      *     modem behavior
398      * @return boolean true if the operation is successful, otherwise false.
399      */
forceErrorResponse(int slotId, int requestId, int error)400     public boolean forceErrorResponse(int slotId, int requestId, int error) throws Exception {
401         Log.d(
402                 TAG,
403                 "forceErrorResponse[" + slotId + "] for request:" + requestId + " ,error:" + error);
404         boolean result = true;
405 
406         switch (requestId) {
407             case RIL_REQUEST_RADIO_POWER:
408                 mMockModemService
409                         .getIRadioModem((byte) slotId)
410                         .forceErrorResponse(requestId, error);
411                 break;
412             default:
413                 Log.e(TAG, "request:" + requestId + " not support to change the response error");
414                 result = false;
415                 break;
416         }
417         return result;
418     }
419 
420     /**
421      * Make the modem is in service or not.
422      *
423      * @param slotId which SIM slot is under the carrierId network.
424      * @param carrierId which carrier network is used.
425      * @param registration boolean true if the modem is in service, otherwise false.
426      * @return boolean true if the operation is successful, otherwise false.
427      */
changeNetworkService(int slotId, int carrierId, boolean registration)428     public boolean changeNetworkService(int slotId, int carrierId, boolean registration)
429             throws Exception {
430         Log.d(
431                 TAG,
432                 "changeNetworkService["
433                         + slotId
434                         + "] in carrier ("
435                         + carrierId
436                         + ") "
437                         + registration);
438 
439         boolean result;
440         result =
441                 mMockModemService
442                         .getIRadioNetwork((byte) slotId)
443                         .changeNetworkService(carrierId, registration);
444 
445         waitForTelephonyFrameworkDone(1);
446         return result;
447     }
448 
449     /**
450      * Make the modem is in service or not for CS or PS registration
451      *
452      * @param slotId which SIM slot is under the carrierId network.
453      * @param carrierId which carrier network is used.
454      * @param registration boolean true if the modem is in service, otherwise false.
455      * @param domainBitmask int specify domains (CS only, PS only, or both).
456      * @return boolean true if the operation is successful, otherwise false.
457      */
changeNetworkService( int slotId, int carrierId, boolean registration, int domainBitmask)458     public boolean changeNetworkService(
459             int slotId, int carrierId,
460             boolean registration, int domainBitmask) throws Exception {
461         return changeNetworkService(
462                 slotId, carrierId, registration, domainBitmask, 0 /* regFailCause */);
463     }
464 
465     /**
466      * Make the modem is in service or not for CS or PS registration
467      *
468      * @param slotId which SIM slot is under the carrierId network.
469      * @param carrierId which carrier network is used.
470      * @param registration boolean true if the modem is in service, otherwise false.
471      * @param domainBitmask int specify domains (CS only, PS only, or both).
472      * @param regFailCause int reason code for registration failure.
473      * @return boolean true if the operation is successful, otherwise false.
474      */
changeNetworkService( int slotId, int carrierId, boolean registration, int domainBitmask, int regFailCause)475     public boolean changeNetworkService(
476             int slotId, int carrierId,
477             boolean registration, int domainBitmask,
478             int regFailCause) throws Exception {
479         Log.d(
480                 TAG,
481                 "changeNetworkService["
482                         + slotId
483                         + "] in carrier ("
484                         + carrierId
485                         + ") "
486                         + registration
487                         + " with domainBitmask = "
488                         + domainBitmask
489                         + " with failCause = "
490                         + regFailCause);
491 
492         boolean result;
493         result =
494                 mMockModemService
495                         .getIRadioNetwork((byte) slotId)
496                         .changeNetworkService(
497                                 carrierId, registration, domainBitmask, regFailCause);
498 
499         waitForTelephonyFrameworkDone(1);
500         return result;
501     }
502 
503     /**
504      * get GSM CellBroadcastConfig outputs from IRadioMessagingImpl
505      *
506      * @param slotId which slot would insert
507      * @return Set of broadcast configs
508      */
getGsmBroadcastConfig(int slotId)509     public Set<Integer> getGsmBroadcastConfig(int slotId) {
510         return mMockModemService.getIRadioMessaging((byte) slotId).getGsmBroadcastConfigSet();
511     }
512 
513     /**
514      * get CDMA CellBroadcastConfig outputs from IRadioMessagingImpl
515      *
516      * @param slotId which slot would insert
517      * @return Set of broadcast configs
518      */
getCdmaBroadcastConfig(int slotId)519     public Set<Integer> getCdmaBroadcastConfig(int slotId) {
520         return mMockModemService.getIRadioMessaging((byte) slotId).getCdmaBroadcastConfigSet();
521     }
522 
523     /**
524      * receive new broadcast sms message
525      *
526      * @param slotId which slot would insert
527      * @param data data of broadcast messages to be received
528      */
newBroadcastSms(int slotId, byte[] data)529     public void newBroadcastSms(int slotId, byte[] data) {
530         mMockModemService.getIRadioMessaging((byte) slotId).newBroadcastSms(data);
531     }
532 
533     /**
534      * register callback for monitoring broadcast activation
535      *
536      * @param slotId which slot would insert
537      * @param callback callback to register
538      */
registerBroadcastCallback(int slotId, IRadioMessagingImpl.CallBackWithExecutor callback)539     public void registerBroadcastCallback(int slotId,
540             IRadioMessagingImpl.CallBackWithExecutor callback) {
541         mMockModemService.getIRadioMessaging((byte) slotId).registerBroadcastCallback(callback);
542     }
543 
544     /**
545      * unregister callback for monitoring broadcast activation
546      *
547      * @param slotId which slot would insert
548      * @param callback callback to unregister
549      */
unregisterBroadcastCallback(int slotId, IRadioMessagingImpl.CallBackWithExecutor callback)550     public void unregisterBroadcastCallback(int slotId,
551             IRadioMessagingImpl.CallBackWithExecutor callback) {
552         mMockModemService.getIRadioMessaging((byte) slotId).unregisterBroadcastCallback(callback);
553     }
554 
555     /**
556      * Indicates when Single Radio Voice Call Continuity (SRVCC) progress state has changed.
557      *
558      * @param slotId which slot would insert.
559      * @param state New SRVCC State
560      * @return boolean true if the operation is successful, otherwise false.
561      */
srvccStateNotify(int slotId, int state)562     public boolean srvccStateNotify(int slotId, int state) {
563         Log.d(TAG, "notifySrvccState[" + slotId + "] with state(" + state + ")");
564 
565         boolean result = false;
566         try {
567             IRadioVoiceImpl radioVoice = mMockModemService.getIRadioVoice((byte) slotId);
568             if (radioVoice != null) {
569                 radioVoice.srvccStateNotify(state);
570 
571                 waitForTelephonyFrameworkDone(1);
572                 result = true;
573             }
574         } catch (Exception e) {
575         }
576         return result;
577     }
578 
579     /**
580      * Returns the list of MockSrvccCall
581      *
582      * @param slotId for which slot to get the list
583      * @return the list of {@link MockSrvccCall}
584      */
getSrvccCalls(int slotId)585     public List<MockSrvccCall> getSrvccCalls(int slotId) {
586         Log.d(TAG, "getSrvccCalls[" + slotId + "]");
587 
588         IRadioImsImpl radioIms = mMockModemService.getIRadioIms((byte) slotId);
589         if (radioIms == null) return null;
590         return radioIms.getSrvccCalls();
591     }
592 
593     /**
594      * Triggers IMS deregistration.
595      *
596      * @param slotId which slot would insert.
597      * @param reason the reason why the deregistration is triggered.
598      * @return {@code true} if the operation is successful, otherwise {@code false}.
599      */
triggerImsDeregistration(int slotId, @ImsRegistrationImplBase.ImsDeregistrationReason int reason)600     public boolean triggerImsDeregistration(int slotId,
601             @ImsRegistrationImplBase.ImsDeregistrationReason int reason) {
602         Log.d(TAG, "triggerImsDeregistration[" + slotId + "] reason=" + reason);
603 
604         boolean result = false;
605         try {
606             mMockModemService.getIRadioIms().triggerImsDeregistration(reason);
607 
608             waitForTelephonyFrameworkDone(1);
609             result = true;
610         } catch (Exception e) {
611         }
612         return result;
613     }
614 
615     /**
616      * Clears the Anbr values.
617      *
618      * @param slotId for which slot to get the reason.
619      */
resetAnbrValues(int slotId)620     public void resetAnbrValues(int slotId) {
621         Log.d(TAG, "resetAnbrValues[" + slotId + "]");
622 
623         try {
624             IRadioImsImpl radioIms = mMockModemService.getIRadioIms((byte) slotId);
625             if (radioIms == null) return;
626             radioIms.resetAnbrValues();
627         } catch (Exception e) {
628             Log.e(TAG, "resetAnbrValues - failed");
629         }
630     }
631 
632     /**
633      * Returns the Anbr values.
634      *
635      * @param slotId for which slot to get the reason.
636      * @return the Anbr values triggered by Anbr Query.
637      */
getAnbrValues(int slotId)638     public int[] getAnbrValues(int slotId) {
639         Log.d(TAG, "getAnbrValues[" + slotId + "]");
640 
641         IRadioImsImpl radioIms = mMockModemService.getIRadioIms((byte) slotId);
642         if (radioIms == null) return null;
643         return radioIms.getAnbrValues();
644     }
645 
646     /**
647      * Triggers NotifyAnbr.
648      *
649      * @param slotId which slot would insert.
650      * @param qosSessionId is used to identify media stream such as audio or video.
651      * @param direction Direction of this packet stream (e.g. uplink or downlink).
652      * @param bitsPerSecond is the bitrate received from the NW through the Recommended
653      *        bitrate MAC Control Element message and ImsStack converts this value from MAC bitrate
654      *        to audio/video codec bitrate (defined in TS26.114).
655      * @return {@code true} if the operation is successful, otherwise {@code false}.
656      */
notifyAnbr(int slotId, int qosSessionId, int direction, int bitsPerSecond)657     public boolean notifyAnbr(int slotId, int qosSessionId, int direction, int bitsPerSecond) {
658         Log.d(TAG, "mockmodem - notifyAnbr[" + slotId + "] qosSessionId=" + qosSessionId
659                 + ", direction=" + direction + ", bitsPerSecond" + bitsPerSecond);
660 
661         boolean result = false;
662         try {
663 
664             IRadioImsImpl radioIms = mMockModemService.getIRadioIms((byte) slotId);
665             if (radioIms == null) return false;
666             radioIms.notifyAnbr(qosSessionId, direction, bitsPerSecond);
667 
668             waitForTelephonyFrameworkDone(1);
669             result = true;
670         } catch (Exception e) {
671             Log.e(TAG, "Create notifyAnbr - failed");
672         }
673         return result;
674     }
675 
676     /**
677      * Returns the reason that caused EPS fallback.
678      *
679      * @param slotId for which slot to get the reason
680      * @return the reason that caused EPS fallback.
681      */
getEpsFallbackReason(int slotId)682     public @MmTelFeature.EpsFallbackReason int getEpsFallbackReason(int slotId) {
683         Log.d(TAG, "getEpsFallbackReason[" + slotId + "]");
684 
685         IRadioImsImpl radioIms = mMockModemService.getIRadioIms((byte) slotId);
686         if (radioIms == null) return -1;
687         return radioIms.getEpsFallbackReason();
688     }
689 
690     /**
691      * Clears the EPS fallback reason.
692      *
693      * @param slotId for which slot to get the reason
694      */
resetEpsFallbackReason(int slotId)695     public void resetEpsFallbackReason(int slotId) {
696         Log.d(TAG, "resetEpsFallbackReason[" + slotId + "]");
697 
698         IRadioImsImpl radioIms = mMockModemService.getIRadioIms((byte) slotId);
699         if (radioIms == null) return;
700         radioIms.resetEpsFallbackReason();
701     }
702 
703     /**
704      * Updates the emergency registration state.
705      *
706      * @param slotId the Id of logical sim slot.
707      * @param regResult the emergency registration state.
708      */
setEmergencyRegResult(int slotId, MockEmergencyRegResult regResult)709     public void setEmergencyRegResult(int slotId, MockEmergencyRegResult regResult) {
710         Log.d(TAG, "setEmergencyRegResult[" + slotId + "]");
711         mMockModemService.getIRadioNetwork((byte) slotId).setEmergencyRegResult(regResult);
712     }
713 
714     /**
715      * Notifies the barring information change.
716      *
717      * @param slotId the Id of logical sim slot.
718      * @param barringServiceInfos the barring information.
719      */
unsolBarringInfoChanged(int slotId, SparseArray<BarringInfo.BarringServiceInfo> barringServiceInfos)720     public boolean unsolBarringInfoChanged(int slotId,
721             SparseArray<BarringInfo.BarringServiceInfo> barringServiceInfos) {
722         Log.d(TAG, "unsolBarringInfoChanged[" + slotId + "]");
723         return mMockModemService.getIRadioNetwork((byte) slotId)
724                 .unsolBarringInfoChanged(barringServiceInfos);
725     }
726 
727     /**
728      * Triggers RIL_UNSOL_EMERGENCY_NETWORK_SCAN_RESULT unsol message.
729      *
730      * @param slotId the Id of logical sim slot.
731      * @param regResult the registration result.
732      */
unsolEmergencyNetworkScanResult(int slotId, MockEmergencyRegResult regResult)733     public boolean unsolEmergencyNetworkScanResult(int slotId, MockEmergencyRegResult regResult) {
734         Log.d(TAG, "unsolEmergencyNetworkScanResult[" + slotId + "]");
735         return mMockModemService.getIRadioNetwork((byte) slotId)
736                 .unsolEmergencyNetworkScanResult(regResult);
737     }
738 
739     /**
740      * Resets the current emergency mode.
741      *
742      * @param slotId the Id of logical sim slot.
743      */
resetEmergencyMode(int slotId)744     public void resetEmergencyMode(int slotId) {
745         Log.d(TAG, "resetEmergencyMode[" + slotId + "]");
746         mMockModemService.getIRadioNetwork((byte) slotId).resetEmergencyMode();
747     }
748 
749     /**
750      * @return the current emergency mode.
751      *
752      * @param slotId the Id of logical sim slot.
753      */
getEmergencyMode(int slotId)754     public int getEmergencyMode(int slotId) {
755         Log.d(TAG, "getEmergencyMode[" + slotId + "]");
756         return mMockModemService.getIRadioNetwork((byte) slotId).getEmergencyMode();
757     }
758 
759     /**
760      * Returns whether emergency network scan is triggered.
761      *
762      * @param slotId the Id of logical sim slot.
763      * @return {@code true} if emergency network scan is triggered.
764      */
isEmergencyNetworkScanTriggered(int slotId)765     public boolean isEmergencyNetworkScanTriggered(int slotId) {
766         Log.d(TAG, "isEmergencyNetworkScanTriggered[" + slotId + "]");
767         return mMockModemService.getIRadioNetwork((byte) slotId).isEmergencyNetworkScanTriggered();
768     }
769 
770     /**
771      * Returns whether emergency network scan is canceled.
772      *
773      * @param slotId the Id of logical sim slot.
774      * @return {@code true} if emergency network scan is canceled.
775      */
isEmergencyNetworkScanCanceled(int slotId)776     public boolean isEmergencyNetworkScanCanceled(int slotId) {
777         Log.d(TAG, "isEmergencyNetworkScanCanceled[" + slotId + "]");
778         return mMockModemService.getIRadioNetwork((byte) slotId).isEmergencyNetworkScanCanceled();
779     }
780 
781     /**
782      * Returns the list of preferred network type.
783      *
784      * @param slotId the Id of logical sim slot.
785      * @return the list of preferred network type.
786      */
getEmergencyNetworkScanAccessNetwork(int slotId)787     public int[] getEmergencyNetworkScanAccessNetwork(int slotId) {
788         Log.d(TAG, "getEmergencyNetworkScanAccessNetwork[" + slotId + "]");
789         return mMockModemService.getIRadioNetwork((byte) slotId)
790                 .getEmergencyNetworkScanAccessNetwork();
791     }
792 
793     /**
794      * Returns the preferred scan type.
795      *
796      * @param slotId the Id of logical sim slot.
797      * @return the preferred scan type.
798      */
getEmergencyNetworkScanType(int slotId)799     public int getEmergencyNetworkScanType(int slotId) {
800         Log.d(TAG, "getEmergencyNetworkScanType[" + slotId + "]");
801         return mMockModemService.getIRadioNetwork((byte) slotId).getEmergencyNetworkScanType();
802     }
803 
804     /**
805      * Resets the emergency network scan attributes.
806      *
807      * @param slotId the Id of logical sim slot.
808      */
resetEmergencyNetworkScan(int slotId)809     public void resetEmergencyNetworkScan(int slotId) {
810         Log.d(TAG, "resetEmergencyNetworkScan[" + slotId + "]");
811         mMockModemService.getIRadioNetwork((byte) slotId).resetEmergencyNetworkScan();
812     }
813 
814     /**
815      * Waits for the event of network service.
816      *
817      * @param slotId the Id of logical sim slot.
818      * @param latchIndex The index of the event.
819      * @param waitMs The timeout in milliseconds.
820      */
waitForNetworkLatchCountdown(int slotId, int latchIndex, int waitMs)821     public boolean waitForNetworkLatchCountdown(int slotId, int latchIndex, int waitMs) {
822         Log.d(TAG, "waitForNetworkLatchCountdown[" + slotId + "]");
823         return mMockModemService.getIRadioNetwork((byte) slotId)
824                 .waitForLatchCountdown(latchIndex, waitMs);
825     }
826 
827     /**
828      * Resets the CountDownLatches of network service.
829      *
830      * @param slotId the Id of logical sim slot.
831      */
resetNetworkAllLatchCountdown(int slotId)832     public void resetNetworkAllLatchCountdown(int slotId) {
833         Log.d(TAG, "resetNetworkAllLatchCountdown[" + slotId + "]");
834         mMockModemService.getIRadioNetwork((byte) slotId).resetAllLatchCountdown();
835     }
836 
837     /**
838      * Waits for the event of voice service.
839      *
840      * @param slotId the Id of logical sim slot.
841      * @param latchIndex The index of the event.
842      * @param waitMs The timeout in milliseconds.
843      */
waitForVoiceLatchCountdown(int slotId, int latchIndex, int waitMs)844     public boolean waitForVoiceLatchCountdown(int slotId, int latchIndex, int waitMs) {
845         Log.d(TAG, "waitForVoiceLatchCountdown[" + slotId + "]");
846         return mMockModemService.getIRadioVoice((byte) slotId)
847                 .waitForLatchCountdown(latchIndex, waitMs);
848     }
849 
850     /**
851      * Resets the CountDownLatches of voice service.
852      *
853      * @param slotId the Id of logical sim slot.
854      */
resetVoiceAllLatchCountdown(int slotId)855     public void resetVoiceAllLatchCountdown(int slotId) {
856         Log.d(TAG, "resetVoiceAllLatchCountdown[" + slotId + "]");
857         mMockModemService.getIRadioVoice((byte) slotId).resetAllLatchCountdown();
858     }
859 
860     /**
861      * Stops sending default response to startImsTraffic.
862      *
863      * @param slotId which slot would insert.
864      * @param blocked indicates whether sending response is allowed or not.
865      */
blockStartImsTrafficResponse(int slotId, boolean blocked)866     public void blockStartImsTrafficResponse(int slotId, boolean blocked) {
867         Log.d(TAG, "blockStartImsTrafficResponse[" + slotId + "] blocked(" + blocked + ")");
868 
869         mMockModemService.getIRadioIms((byte) slotId).blockStartImsTrafficResponse(blocked);
870     }
871 
872     /**
873      * Returns whether the given IMS traffic type is started or not.
874      *
875      * @param slotId which slot would insert.
876      * @param trafficType the IMS traffic type
877      * @return boolean true if the given IMS traffic type is started
878      */
isImsTrafficStarted(int slotId, @MmTelFeature.ImsTrafficType int trafficType)879     public boolean isImsTrafficStarted(int slotId,
880             @MmTelFeature.ImsTrafficType int trafficType) {
881         Log.d(TAG, "isImsTrafficStarted[" + slotId + "] trafficType(" + trafficType + ")");
882 
883         return mMockModemService.getIRadioIms((byte) slotId).isImsTrafficStarted(trafficType);
884     }
885 
886     /**
887      * Sends the response with the given information.
888      *
889      * @param slotId which slot would insert.
890      * @param trafficType the IMS traffic type
891      * @param reason The reason of failure.
892      * @param causeCode Failure cause code from network or modem specific to the failure.
893      * @param waitTimeMillis Retry wait time provided by network in milliseconds.
894      * @return boolean true if there is no error
895      */
sendStartImsTrafficResponse(int slotId, @MmTelFeature.ImsTrafficType int trafficType, @ConnectionFailureInfo.FailureReason int reason, int causeCode, int waitTimeMillis)896     public boolean sendStartImsTrafficResponse(int slotId,
897             @MmTelFeature.ImsTrafficType int trafficType,
898             @ConnectionFailureInfo.FailureReason int reason,
899             int causeCode, int waitTimeMillis) {
900         Log.d(TAG, "sendStartImsTrafficResponse[" + slotId
901                 + "] trafficType(" + trafficType + ")"
902                 + " reason(" + reason + ")"
903                 + " cause(" + causeCode + ")"
904                 + " wait(" + waitTimeMillis + ")");
905 
906         boolean result = false;
907         try {
908             mMockModemService.getIRadioIms((byte) slotId).sendStartImsTrafficResponse(
909                     trafficType, reason, causeCode, waitTimeMillis);
910 
911             waitForTelephonyFrameworkDone(1);
912             result = true;
913         } catch (Exception e) {
914             Log.e(TAG, "sendStartImsTrafficResponse e=" + e);
915         }
916         return result;
917     }
918 
919     /**
920      * Notifies the connection failure info
921      *
922      * @param slotId which slot would insert.
923      * @param trafficType the IMS traffic type
924      * @param reason The reason of failure.
925      * @param causeCode Failure cause code from network or modem specific to the failure.
926      * @param waitTimeMillis Retry wait time provided by network in milliseconds.
927      * @return boolean true if there is no error
928      */
sendConnectionFailureInfo(int slotId, @MmTelFeature.ImsTrafficType int trafficType, @ConnectionFailureInfo.FailureReason int reason, int causeCode, int waitTimeMillis)929     public boolean sendConnectionFailureInfo(int slotId,
930             @MmTelFeature.ImsTrafficType int trafficType,
931             @ConnectionFailureInfo.FailureReason int reason,
932             int causeCode, int waitTimeMillis) {
933         Log.d(TAG, "sendConnectionFailureInfo[" + slotId
934                 + "] trafficType(" + trafficType + ")"
935                 + " reason(" + reason + ")"
936                 + " cause(" + causeCode + ")"
937                 + " wait(" + waitTimeMillis + ")");
938 
939         boolean result = false;
940         try {
941             mMockModemService.getIRadioIms((byte) slotId).sendConnectionFailureInfo(
942                     trafficType, reason, causeCode, waitTimeMillis);
943 
944             waitForTelephonyFrameworkDone(1);
945             result = true;
946         } catch (Exception e) {
947             Log.e(TAG, "sendConnectionFailureInfo e=" + e);
948         }
949         return result;
950     }
951 
952     /**
953      * Clears the IMS traffic state.
954      */
clearImsTrafficState()955     public void clearImsTrafficState() {
956         mMockModemService.getIRadioIms().clearImsTrafficState();
957     }
958 
959     /**
960      * Waits for the event of mock IMS state.
961      *
962      * @param latchIndex The index of the event.
963      * @param waitMs The timeout in milliseconds.
964      */
waitForImsLatchCountdown(int latchIndex, int waitMs)965     public boolean waitForImsLatchCountdown(int latchIndex, int waitMs) {
966         return mMockModemService.getIRadioIms().waitForLatchCountdown(latchIndex, waitMs);
967     }
968 
969     /** Resets the CountDownLatches of IMS state. */
resetImsAllLatchCountdown()970     public void resetImsAllLatchCountdown() {
971         mMockModemService.getIRadioIms().resetAllLatchCountdown();
972     }
973 
974     /**
975      * Set/override default call control configuration.
976      *
977      * @param slotId the Id of logical sim slot.
978      * @param callControlInfo the configuration of call control would like to override.
979      * @return boolean true if the operation succeeds, otherwise false.
980      */
setCallControlInfo(int slotId, MockCallControlInfo callControlInfo)981     public boolean setCallControlInfo(int slotId, MockCallControlInfo callControlInfo) {
982         Log.d(TAG, "setCallControlInfo[" + slotId + "]");
983         return mMockModemService
984                 .getMockModemConfigInterface()
985                 .setCallControlInfo(slotId, callControlInfo, TAG);
986     }
987 
988     /**
989      * Get call control configuration.
990      *
991      * @param slotId the Id of logical sim slot.
992      * @return MockCallControlInfo which was set/overridden before.
993      */
getCallControlInfo(int slotId)994     public MockCallControlInfo getCallControlInfo(int slotId) {
995         Log.d(TAG, "getCallControlInfo[" + slotId + "]");
996         return mMockModemService.getMockModemConfigInterface().getCallControlInfo(slotId, TAG);
997     }
998 
999     /**
1000      * Trigger an incoming voice call.
1001      *
1002      * @param slotId the Id of logical sim slot.
1003      * @param address phone number of the incoming call
1004      * @param uusInfo user to user signaling information.
1005      * @param cdmaSignalInfoRecord CDMA Signal Information Record.
1006      * @return boolean true if the operation succeeds, otherwise false.
1007      */
triggerIncomingVoiceCall( int slotId, String address, UusInfo[] uusInfo, CdmaSignalInfoRecord cdmaSignalInfoRecord)1008     public boolean triggerIncomingVoiceCall(
1009             int slotId,
1010             String address,
1011             UusInfo[] uusInfo,
1012             CdmaSignalInfoRecord cdmaSignalInfoRecord)
1013             throws Exception {
1014         return triggerIncomingVoiceCall(slotId, address, uusInfo, cdmaSignalInfoRecord, null);
1015     }
1016 
1017     /**
1018      * Trigger an incoming voice call with a call control configuration.
1019      *
1020      * @param slotId the Id of logical sim slot.
1021      * @param address phone number of the incoming call
1022      * @param uusInfo user to user signaling information.
1023      * @param cdmaSignalInfoRecord CDMA Signal Information Record.
1024      * @param callControlInfo the configuration of call control would like to override.
1025      * @return boolean true if the operation succeeds, otherwise false.
1026      */
triggerIncomingVoiceCall( int slotId, String address, UusInfo[] uusInfo, CdmaSignalInfoRecord cdmaSignalInfoRecord, MockCallControlInfo callControlInfo)1027     public boolean triggerIncomingVoiceCall(
1028             int slotId,
1029             String address,
1030             UusInfo[] uusInfo,
1031             CdmaSignalInfoRecord cdmaSignalInfoRecord,
1032             MockCallControlInfo callControlInfo)
1033             throws Exception {
1034         Log.d(TAG, "triggerIncomingVoiceCall[" + slotId + "] address: " + address);
1035         boolean result;
1036 
1037         result =
1038                 mMockModemService
1039                         .getMockModemConfigInterface()
1040                         .triggerIncomingVoiceCall(
1041                                 slotId,
1042                                 address,
1043                                 uusInfo,
1044                                 cdmaSignalInfoRecord,
1045                                 callControlInfo,
1046                                 TAG);
1047 
1048         waitForTelephonyFrameworkDone(1);
1049         return result;
1050     }
1051 
1052     /**
1053      * Get number of on going CS calls.
1054      *
1055      * @param slotId the Id of logical sim slot.
1056      * @return int the number of CS calls.
1057      */
getNumberOfOngoingCSCalls(int slotId)1058     public int getNumberOfOngoingCSCalls(int slotId) {
1059         Log.d(TAG, "getNumberOfOngoingCSCalls[" + slotId + "]");
1060         return mMockModemService.getMockModemConfigInterface().getNumberOfCalls(slotId, TAG);
1061     }
1062 
1063     /**
1064      * Sets the last call fail cause.
1065      *
1066      * @param slotId the Id of logical sim slot.
1067      * @param cause The disconnect cause.
1068      */
setLastCallFailCause(int slotId, int cause)1069     public void setLastCallFailCause(int slotId, int cause) {
1070         Log.d(TAG, "setLastCallFailCause[" + slotId + "] cause = " + cause);
1071         mMockModemService.getMockModemConfigInterface().setLastCallFailCause(slotId, cause, TAG);
1072     }
1073 
1074     /**
1075      * Clears all calls with the given cause.
1076      *
1077      * @param slotId the Id of logical sim slot.
1078      * @param cause The disconnect cause.
1079      */
clearAllCalls(int slotId, @Annotation.DisconnectCauses int cause)1080     public void clearAllCalls(int slotId, @Annotation.DisconnectCauses int cause) {
1081         Log.d(TAG, "clearAllCalls[" + slotId + "] cause = " + cause);
1082         mMockModemService.getMockModemConfigInterface().clearAllCalls(slotId, cause, TAG);
1083     }
1084 
1085     /**
1086      * Reports the list of emergency numbers.
1087      *
1088      * @param numbers The list of emergency numbers.
1089      */
notifyEmergencyNumberList(int slotId, String[] numbers)1090     public void notifyEmergencyNumberList(int slotId, String[] numbers) {
1091         Log.d(TAG, "notifyEmergencyNumberList[" + slotId + "]");
1092         mMockModemService.getIRadioVoice((byte) slotId).notifyEmergencyNumberList(numbers);
1093     }
1094 
1095     /**
1096      * Sets the new carrierId and CarrierRestriction status values in IRadioSimImpl.java
1097      * @param carrierList
1098      * @param carrierRestrictionStatus
1099      */
updateCarrierRestrictionInfo(Carrier[] carrierList, int carrierRestrictionStatus)1100     public void updateCarrierRestrictionInfo(Carrier[] carrierList, int carrierRestrictionStatus) {
1101         mMockModemService.getIRadioSim().updateCarrierRestrictionStatusInfo(carrierList,
1102                 carrierRestrictionStatus);
1103     }
1104 
1105     /**
1106      * Helper method that can be called from the test suite to change the primary IMEi mapping
1107      * with respect to sim slot.
1108      */
changeImeiMapping()1109     public boolean changeImeiMapping() {
1110         int modemCount = mMockModemService.getActiveMockModemCount();
1111         if (modemCount == 1) {
1112             return false;
1113         }
1114         for (int slotId = 0; slotId < modemCount; slotId++) {
1115             mMockModemService.getIRadioModem((byte) slotId).resetAllLatchCountdown();
1116             mMockModemService.getIRadioModem((byte) slotId).changeImeiMapping();
1117             if (waitForModemLatchCountdown(slotId, WAIT_UPDATE_TIMEOUT_MS)) {
1118                 Log.e(TAG, "Error in waitForModemLatchCountdown");
1119             }
1120         }
1121         return true;
1122     }
1123 
1124     /**
1125      * Wait latch for 0.2 sec or latch to countdown.
1126      * @param slotId : slotId of the device.
1127      * @param waitMs : Wait in milliseconds for the latch-wait timeout.
1128      * @return true if latch is success else fail.
1129      */
waitForModemLatchCountdown(int slotId, int waitMs)1130     public boolean waitForModemLatchCountdown(int slotId, int waitMs) {
1131         Log.d(TAG, "waitForVoiceLatchCountdown[" + slotId + "]");
1132         return mMockModemService.getIRadioModem((byte) slotId)
1133                 .waitForLatchCountdown(slotId, waitMs);
1134     }
1135 
setCarrierRestrictionRules(CarrierRestrictions carrierRestrictionRules, int multiSimPolicy)1136     public void setCarrierRestrictionRules(CarrierRestrictions carrierRestrictionRules,
1137             int multiSimPolicy) {
1138         mMockModemService.getIRadioSim().updateCarrierRestrictionRules(
1139                 carrierRestrictionRules, multiSimPolicy);
1140     }
1141 
1142     /**
1143      * Triggers an incoming SMS.
1144      *
1145      * @param slotId the Id of logical sim slot.
1146      * @return {@code true} if the operation succeeds otherwise false.
1147      */
triggerIncomingSms(int slotId)1148     public boolean triggerIncomingSms(int slotId) {
1149         Log.d(TAG, "triggerIncomingSms[" + slotId + "]");
1150 
1151         boolean result = false;
1152         try {
1153             String pdu = "07916164260220F0040B914151245584F600006060605130308A04D4F29C0E";
1154             mMockModemService.getIRadioMessaging((byte) slotId)
1155                     .newSms(TelephonyUtils.hexStringToByteArray(pdu));
1156 
1157             waitForTelephonyFrameworkDone(1);
1158             result = true;
1159         } catch (Exception e) {
1160             Log.e(TAG, "triggerIncomingSms e=" + e);
1161         }
1162         return result;
1163     }
1164 }
1165