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 android.annotation.NonNull;
20 import android.hardware.radio.RadioError;
21 import android.hardware.radio.RadioIndicationType;
22 import android.hardware.radio.RadioResponseInfo;
23 import android.hardware.radio.ims.ConnectionFailureInfo;
24 import android.hardware.radio.ims.IRadioIms;
25 import android.hardware.radio.ims.IRadioImsIndication;
26 import android.hardware.radio.ims.IRadioImsResponse;
27 import android.hardware.radio.ims.ImsDeregistrationReason;
28 import android.os.RemoteException;
29 import android.telephony.ims.feature.MmTelFeature;
30 import android.telephony.ims.stub.ImsRegistrationImplBase;
31 import android.util.Log;
32 
33 import java.util.List;
34 
35 public class IRadioImsImpl extends IRadioIms.Stub {
36     private static final String TAG = "MRIMS";
37 
38     private final MockModemService mService;
39     private IRadioImsResponse mRadioImsResponse;
40     private IRadioImsIndication mRadioImsIndication;
41     private final MockModemConfigInterface mMockModemConfigInterface;
42     private final int mSubId;
43     private final String mTag;
44 
45     private final MockImsService mImsState = new MockImsService();
46 
47     private boolean mBlockStartImsTrafficResponse = false;
48 
IRadioImsImpl( MockModemService service, MockModemConfigInterface configInterface, int instanceId)49     public IRadioImsImpl(
50             MockModemService service, MockModemConfigInterface configInterface, int instanceId) {
51         mTag = TAG + "-" + instanceId;
52         Log.d(mTag, "Instantiated");
53 
54         this.mService = service;
55         mMockModemConfigInterface = configInterface;
56         mSubId = instanceId;
57     }
58 
59     // Implementation of IRadioIms functions
60     @Override
setResponseFunctions( IRadioImsResponse radioImsResponse, IRadioImsIndication radioImsIndication)61     public void setResponseFunctions(
62             IRadioImsResponse radioImsResponse, IRadioImsIndication radioImsIndication) {
63         Log.d(mTag, "setResponseFunctions");
64         mRadioImsResponse = radioImsResponse;
65         mRadioImsIndication = radioImsIndication;
66         mService.countDownLatch(MockModemService.LATCH_RADIO_INTERFACES_READY);
67     }
68 
69     @Override
setSrvccCallInfo(int serial, android.hardware.radio.ims.SrvccCall[] srvccCalls)70     public void setSrvccCallInfo(int serial, android.hardware.radio.ims.SrvccCall[] srvccCalls) {
71         Log.d(mTag, "setSrvccCallInfo");
72 
73         mImsState.setSrvccCallInfo(srvccCalls);
74 
75         RadioResponseInfo rsp = mService.makeSolRsp(serial);
76         try {
77             mRadioImsResponse.setSrvccCallInfoResponse(rsp);
78         } catch (RemoteException ex) {
79             Log.e(mTag, "Failed to setSrvccCallInfo from AIDL. Exception" + ex);
80         }
81     }
82 
83     @Override
updateImsRegistrationInfo(int serial, android.hardware.radio.ims.ImsRegistration imsRegistration)84     public void updateImsRegistrationInfo(int serial,
85             android.hardware.radio.ims.ImsRegistration imsRegistration) {
86         Log.d(mTag, "updateImsRegistrationInfo");
87 
88         RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
89         try {
90             mRadioImsResponse.updateImsRegistrationInfoResponse(rsp);
91         } catch (RemoteException ex) {
92             Log.e(mTag, "Failed to updateImsRegistrationInfo from AIDL. Exception" + ex);
93         }
94     }
95 
96     @Override
startImsTraffic(int serial, int token, int imsTrafficType, int accessNetworkType, int trafficDirection)97     public void startImsTraffic(int serial,
98             int token, int imsTrafficType, int accessNetworkType, int trafficDirection) {
99         Log.d(mTag, "startImsTraffic");
100 
101         mImsState.startImsTraffic(serial, token, imsTrafficType);
102 
103         if (mBlockStartImsTrafficResponse) return;
104 
105         ConnectionFailureInfo failureInfo = null;
106         RadioResponseInfo rsp = mService.makeSolRsp(serial);
107         try {
108             mRadioImsResponse.startImsTrafficResponse(rsp, failureInfo);
109         } catch (RemoteException ex) {
110             Log.e(mTag, "Failed to startImsTraffic from AIDL. Exception" + ex);
111         }
112     }
113 
114     @Override
stopImsTraffic(int serial, int token)115     public void stopImsTraffic(int serial, int token) {
116         Log.d(mTag, "stopImsTraffic");
117 
118         mImsState.stopImsTraffic(token);
119 
120         RadioResponseInfo rsp = mService.makeSolRsp(serial);
121         try {
122             mRadioImsResponse.stopImsTrafficResponse(rsp);
123         } catch (RemoteException ex) {
124             Log.e(mTag, "Failed to stopImsTraffic from AIDL. Exception" + ex);
125         }
126     }
127 
128     @Override
triggerEpsFallback(int serial, int reason)129     public void triggerEpsFallback(int serial, int reason) {
130         Log.d(mTag, "triggerEpsFallback");
131 
132         mImsState.setEpsFallbackReason(reason);
133 
134         RadioResponseInfo rsp = mService.makeSolRsp(serial);
135         try {
136             mRadioImsResponse.triggerEpsFallbackResponse(rsp);
137         } catch (RemoteException ex) {
138             Log.e(mTag, "Failed to triggerEpsFallback from AIDL. Exception" + ex);
139         }
140     }
141 
142     @Override
sendAnbrQuery(int serial, int qosSessionId, int direction, int bitsPerSecond)143     public void sendAnbrQuery(int serial, int qosSessionId, int direction, int bitsPerSecond) {
144         Log.d(mTag, "sendAnbrQuery");
145 
146         mImsState.sendAnbrQuery(qosSessionId, direction, bitsPerSecond);
147 
148         RadioResponseInfo rsp = mService.makeSolRsp(serial);
149         try {
150             mRadioImsResponse.sendAnbrQueryResponse(rsp);
151         } catch (RemoteException ex) {
152             Log.e(mTag, "Failed to sendAnbrQuery from AIDL. Exception" + ex);
153         }
154     }
155 
onConnectionSetupFailure(int token, @NonNull ConnectionFailureInfo failureInfo)156     public void onConnectionSetupFailure(int token, @NonNull ConnectionFailureInfo failureInfo) {
157         Log.d(mTag, "onConnectionSetupFailure");
158 
159         if (mRadioImsIndication != null) {
160             try {
161                 mRadioImsIndication.onConnectionSetupFailure(
162                         RadioIndicationType.UNSOLICITED, token, failureInfo);
163             } catch (RemoteException ex) {
164                 Log.e(mTag, "Failed to onConnectionSetupFailure indication from AIDL. Exception"
165                         + ex);
166             }
167         } else {
168             Log.e(mTag, "null mRadioImsIndication");
169         }
170     }
171 
notifyAnbr(int qosSessionId, int direction, int bitsPerSecond)172     public void notifyAnbr(int qosSessionId, int direction, int bitsPerSecond) {
173         Log.d(mTag, "notifyAnbr");
174 
175         if (mRadioImsIndication != null) {
176             try {
177                 mRadioImsIndication.notifyAnbr(RadioIndicationType.UNSOLICITED,
178                         qosSessionId, direction, bitsPerSecond);
179             } catch (RemoteException ex) {
180                 Log.e(mTag, "Failed to notifyAnbr indication from AIDL. Exception" + ex);
181             }
182         } else {
183             Log.e(mTag, "null mRadioImsIndication");
184         }
185     }
186 
triggerImsDeregistration( @msRegistrationImplBase.ImsDeregistrationReason int reason)187     public void triggerImsDeregistration(
188             @ImsRegistrationImplBase.ImsDeregistrationReason int reason) {
189         Log.d(mTag, "triggerImsDeregistration");
190 
191         int halReason;
192         switch (reason) {
193             case ImsRegistrationImplBase.REASON_SIM_REFRESH:
194                 halReason = ImsDeregistrationReason.REASON_SIM_REFRESH;
195                 break;
196             case ImsRegistrationImplBase.REASON_ALLOWED_NETWORK_TYPES_CHANGED:
197                 halReason = ImsDeregistrationReason.REASON_ALLOWED_NETWORK_TYPES_CHANGED;
198                 break;
199             default:
200                 halReason = ImsDeregistrationReason.REASON_SIM_REMOVED;
201                 break;
202         }
203 
204         if (mRadioImsIndication != null) {
205             try {
206                 mRadioImsIndication.triggerImsDeregistration(
207                         RadioIndicationType.UNSOLICITED, halReason);
208             } catch (RemoteException ex) {
209                 Log.e(mTag, "Failed to triggerImsDeregistration indication from AIDL. Exception"
210                         + ex);
211             }
212         } else {
213             Log.e(mTag, "null mRadioImsIndication");
214         }
215     }
216 
217     /** @return The list of {@link MockSrvccCall} instances. */
getSrvccCalls()218     public List<MockSrvccCall> getSrvccCalls() {
219         return mImsState.getSrvccCalls();
220     }
221 
222     /**
223      * Stop sending default response to startImsTraffic.
224      *
225      * @param blocked indicates whether sending response is allowed or not.
226      */
blockStartImsTrafficResponse(boolean blocked)227     public void blockStartImsTrafficResponse(boolean blocked) {
228         mBlockStartImsTrafficResponse = blocked;
229     }
230 
231     /**
232      * Returns whether the given IMS traffic type is started or not.
233      *
234      * @param trafficType the IMS traffic type
235      * @return boolean true if the given IMS traffic type is started
236      */
isImsTrafficStarted( @ndroid.telephony.ims.feature.MmTelFeature.ImsTrafficType int trafficType)237     public boolean isImsTrafficStarted(
238             @android.telephony.ims.feature.MmTelFeature.ImsTrafficType int trafficType) {
239         return mImsState.isImsTrafficStarted(trafficType);
240     }
241 
242     /**
243      * Clears the IMS traffic state.
244      */
clearImsTrafficState()245     public void clearImsTrafficState() {
246         mBlockStartImsTrafficResponse = false;
247         mImsState.clearImsTrafficState();
248     }
249 
250     /**
251      * Sends the response with the given information.
252      *
253      * @param trafficType the IMS traffic type
254      * @param reason The reason of failure.
255      * @param causeCode Failure cause code from network or modem specific to the failure.
256      * @param waitTimeMillis Retry wait time provided by network in milliseconds.
257      */
sendStartImsTrafficResponse( @ndroid.telephony.ims.feature.MmTelFeature.ImsTrafficType int trafficType, @android.telephony.ims.feature.ConnectionFailureInfo.FailureReason int reason, int causeCode, int waitTimeMillis)258     public void sendStartImsTrafficResponse(
259             @android.telephony.ims.feature.MmTelFeature.ImsTrafficType int trafficType,
260             @android.telephony.ims.feature.ConnectionFailureInfo.FailureReason int reason,
261             int causeCode, int waitTimeMillis) {
262 
263         ConnectionFailureInfo failureInfo = null;
264         if (reason != 0) {
265             failureInfo = new ConnectionFailureInfo();
266             failureInfo.failureReason = reason;
267             failureInfo.causeCode = causeCode;
268             failureInfo.waitTimeMillis = waitTimeMillis;
269         }
270 
271         RadioResponseInfo rsp = mService.makeSolRsp(mImsState.getImsTrafficSerial(trafficType));
272         try {
273             mRadioImsResponse.startImsTrafficResponse(rsp, failureInfo);
274         } catch (RemoteException ex) {
275             Log.e(TAG, "Failed to startImsTrafficResponse from AIDL. Exception" + ex);
276         }
277     }
278 
279     /**
280      * Notifies the connection failure info
281      *
282      * @param trafficType the IMS traffic type
283      * @param reason The reason of failure.
284      * @param causeCode Failure cause code from network or modem specific to the failure.
285      * @param waitTimeMillis Retry wait time provided by network in milliseconds.
286      */
sendConnectionFailureInfo( @ndroid.telephony.ims.feature.MmTelFeature.ImsTrafficType int trafficType, @android.telephony.ims.feature.ConnectionFailureInfo.FailureReason int reason, int causeCode, int waitTimeMillis)287     public void sendConnectionFailureInfo(
288             @android.telephony.ims.feature.MmTelFeature.ImsTrafficType int trafficType,
289             @android.telephony.ims.feature.ConnectionFailureInfo.FailureReason int reason,
290             int causeCode, int waitTimeMillis) {
291 
292         ConnectionFailureInfo failureInfo = new ConnectionFailureInfo();
293         failureInfo.failureReason = reason;
294         failureInfo.causeCode = causeCode;
295         failureInfo.waitTimeMillis = waitTimeMillis;
296 
297         onConnectionSetupFailure(mImsState.getImsTrafficToken(trafficType), failureInfo);
298     }
299 
300     @Override
updateImsCallStatus(int serial, android.hardware.radio.ims.ImsCall[] imsCalls)301     public void updateImsCallStatus(int serial, android.hardware.radio.ims.ImsCall[] imsCalls) {
302         Log.d(mTag, "updateImsCallStatus");
303 
304         RadioResponseInfo rsp = mService.makeSolRsp(serial, RadioError.REQUEST_NOT_SUPPORTED);
305         try {
306             mRadioImsResponse.updateImsCallStatusResponse(rsp);
307         } catch (RemoteException ex) {
308             Log.e(mTag, "Failed to updateImsCallStatus from AIDL. Exception" + ex);
309         }
310     }
311 
312     /**
313      * Returns the reason that caused EPS fallback.
314      *
315      * @return the reason that caused EPS fallback.
316      */
getEpsFallbackReason()317     public @MmTelFeature.EpsFallbackReason int getEpsFallbackReason() {
318         return mImsState.getEpsFallbackReason();
319     }
320 
321     /**
322      * Clears the EPS fallback reason.
323      */
resetEpsFallbackReason()324     public void resetEpsFallbackReason() {
325         mImsState.resetEpsFallbackReason();
326     }
327 
328     /**
329      * Returns the Anbr values triggered by Anbr Query.
330      *
331      * @return the Anbr values triggered by Anbr Query.
332      */
getAnbrValues()333     public int[] getAnbrValues() {
334         return mImsState.getAnbrValues();
335     }
336 
337     /**
338      * Clears the Anbr values.
339      */
resetAnbrValues()340     public void resetAnbrValues() {
341         mImsState.resetAnbrValues();
342     }
343 
344     /**
345      * Waits for the event of IMS state.
346      *
347      * @param latchIndex The index of the event.
348      * @param waitMs The timeout in milliseconds.
349      */
waitForLatchCountdown(int latchIndex, int waitMs)350     public boolean waitForLatchCountdown(int latchIndex, int waitMs) {
351         return mImsState.waitForLatchCountdown(latchIndex, waitMs);
352     }
353 
354     /**
355      * Resets the CountDownLatches
356      */
resetAllLatchCountdown()357     public void resetAllLatchCountdown() {
358         mImsState.resetAllLatchCountdown();
359     }
360 
361     @Override
getInterfaceHash()362     public String getInterfaceHash() {
363         return IRadioIms.HASH;
364     }
365 
366     @Override
getInterfaceVersion()367     public int getInterfaceVersion() {
368         return IRadioIms.VERSION;
369     }
370 }
371