• 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 
17 package android.telephony.mockmodem;
18 
19 import static android.hardware.radio.ims.EpsFallbackReason.NO_NETWORK_RESPONSE;
20 import static android.hardware.radio.ims.EpsFallbackReason.NO_NETWORK_TRIGGER;
21 import static android.telephony.ims.feature.MmTelFeature.EPS_FALLBACK_REASON_INVALID;
22 import static android.telephony.ims.feature.MmTelFeature.EPS_FALLBACK_REASON_NO_NETWORK_RESPONSE;
23 import static android.telephony.ims.feature.MmTelFeature.EPS_FALLBACK_REASON_NO_NETWORK_TRIGGER;
24 import static android.telephony.ims.feature.MmTelFeature.IMS_TRAFFIC_TYPE_UT_XCAP;
25 
26 import android.telephony.ims.feature.MmTelFeature;
27 import android.util.Log;
28 
29 import java.util.ArrayList;
30 import java.util.List;
31 import java.util.concurrent.CountDownLatch;
32 import java.util.concurrent.TimeUnit;
33 
34 public class MockImsService {
35     private static final String TAG = "MockImsService";
36     private static final int INVALID = -1;
37 
38     public static final int LATCH_WAIT_FOR_SRVCC_CALL_INFO = 0;
39     public static final int LATCH_WAIT_FOR_TRIGGER_EPS_FALLBACK = 1;
40     public static final int LATCH_WAIT_FOR_START_IMS_TRAFFIC = 2;
41     public static final int LATCH_WAIT_FOR_STOP_IMS_TRAFFIC = 3;
42     private static final int LATCH_MAX = 4;
43 
44     private final CountDownLatch[] mLatches = new CountDownLatch[LATCH_MAX];
45     private final List<MockSrvccCall> mSrvccCalls = new ArrayList<>();
46     private int mEpsFallbackReason = INVALID;
47 
48     private final int[] mStartImsTrafficSerial = new int[IMS_TRAFFIC_TYPE_UT_XCAP + 1];
49     private final boolean[] mImsTrafficState = new boolean[IMS_TRAFFIC_TYPE_UT_XCAP + 1];
50     private final int[] mImsTrafficToken = new int[IMS_TRAFFIC_TYPE_UT_XCAP + 1];
51     private int[] mAnbrValues = new int[3];
52 
MockImsService()53     public MockImsService() {
54         for (int i = 0; i < LATCH_MAX; i++) {
55             mLatches[i] = new CountDownLatch(1);
56         }
57     }
58 
59     /**
60      * Sets SRVCC call information.
61      * @param srvccCalls The list of call information.
62      */
setSrvccCallInfo(android.hardware.radio.ims.SrvccCall[] srvccCalls)63     public void setSrvccCallInfo(android.hardware.radio.ims.SrvccCall[] srvccCalls) {
64         mSrvccCalls.clear();
65 
66         if (srvccCalls != null) {
67             for (android.hardware.radio.ims.SrvccCall call : srvccCalls) {
68                 mSrvccCalls.add(new MockSrvccCall(call));
69             }
70         }
71         countDownLatch(LATCH_WAIT_FOR_SRVCC_CALL_INFO);
72     }
73 
74     /** @return The list of {@link MockSrvccCall} instances. */
getSrvccCalls()75     public List<MockSrvccCall> getSrvccCalls() {
76         return mSrvccCalls;
77     }
78 
79     /**
80      * Sets the reason that caused EPS fallback.
81      *
82      * @param reason The reason that caused EPS fallback.
83      */
setEpsFallbackReason(int reason)84     public void setEpsFallbackReason(int reason) {
85         mEpsFallbackReason = reason;
86         countDownLatch(LATCH_WAIT_FOR_TRIGGER_EPS_FALLBACK);
87     }
88 
89     /**
90      * Returns the reason that caused EPS fallback.
91      *
92      * @return the reason that caused EPS fallback.
93      */
getEpsFallbackReason()94     public @MmTelFeature.EpsFallbackReason int getEpsFallbackReason() {
95         switch (mEpsFallbackReason) {
96             case NO_NETWORK_TRIGGER: return EPS_FALLBACK_REASON_NO_NETWORK_TRIGGER;
97             case NO_NETWORK_RESPONSE: return EPS_FALLBACK_REASON_NO_NETWORK_RESPONSE;
98             default: return EPS_FALLBACK_REASON_INVALID;
99         }
100     }
101 
102     /**
103      * Clears the EPS fallback reason.
104      */
resetEpsFallbackReason()105     public void resetEpsFallbackReason() {
106         mEpsFallbackReason = INVALID;
107     }
108 
109     /**
110      * Notifies the type of upcoming IMS traffic.
111      *
112      * @param serial Serial number of request.
113      * @param token A nonce to identify the request.
114      * @param trafficType IMS traffic type like registration, voice, video, SMS, emergency, and etc.
115      */
startImsTraffic(int serial, int token, int trafficType)116     public void startImsTraffic(int serial, int token, int trafficType) {
117         mStartImsTrafficSerial[trafficType] = serial;
118         mImsTrafficState[trafficType] = true;
119         mImsTrafficToken[trafficType] = token;
120         countDownLatch(LATCH_WAIT_FOR_START_IMS_TRAFFIC);
121     }
122 
123     /**
124      * Notifies IMS traffic has been stopped.
125      *
126      * @param token The token assigned by startImsTraffic.
127      */
stopImsTraffic(int token)128     public void stopImsTraffic(int token) {
129         for (int i = 0; i < mImsTrafficToken.length; i++) {
130             if (mImsTrafficToken[i] == token) {
131                 mImsTrafficState[i] = false;
132                 mImsTrafficToken[i] = INVALID;
133                 break;
134             }
135         }
136         countDownLatch(LATCH_WAIT_FOR_STOP_IMS_TRAFFIC);
137     }
138 
139     /**
140      * Returns whether the given IMS traffic type is started or not.
141      *
142      * @param trafficType The IMS traffic type.
143      * @return boolean true if the given IMS traffic type is started.
144      */
isImsTrafficStarted(@mTelFeature.ImsTrafficType int trafficType)145     public boolean isImsTrafficStarted(@MmTelFeature.ImsTrafficType int trafficType) {
146         if (trafficType < 0 || trafficType >= mImsTrafficState.length) return false;
147         return mImsTrafficState[trafficType];
148     }
149 
150     /**
151      * Gets the token of the given IMS traffic type.
152      *
153      * @param trafficType The IMS traffic type.
154      * @return The token associated with given traffic type.
155      */
getImsTrafficToken(@mTelFeature.ImsTrafficType int trafficType)156     public int getImsTrafficToken(@MmTelFeature.ImsTrafficType int trafficType) {
157         if (trafficType < 0 || trafficType >= mImsTrafficState.length) return 0;
158         return mImsTrafficToken[trafficType];
159     }
160 
161     /**
162      * Gets the token of the given IMS traffic type.
163      *
164      * @param trafficType The IMS traffic type.
165      * @return The serial of startImsTraffic request.
166      */
getImsTrafficSerial(@mTelFeature.ImsTrafficType int trafficType)167     public int getImsTrafficSerial(@MmTelFeature.ImsTrafficType int trafficType) {
168         if (trafficType < 0 || trafficType >= mImsTrafficState.length) return 0;
169         return mStartImsTrafficSerial[trafficType];
170     }
171 
172     /**
173      * Clears the IMS traffic state.
174      */
clearImsTrafficState()175     public void clearImsTrafficState() {
176         for (int i = 0; i < mImsTrafficToken.length; i++) {
177             mStartImsTrafficSerial[i] = 0;
178             mImsTrafficState[i] = false;
179             mImsTrafficToken[i] = INVALID;
180         }
181     }
182 
183     /**
184      * Access Network Bitrate Recommendation Query (ANBRQ), see 3GPP TS 26.114.
185      * This API triggers radio to send ANBRQ message to the access network to query the
186      * desired bitrate.
187      *
188      * @param mediaType MediaType is used to identify media stream such as audio or video.
189      * @param direction Direction of this packet stream (e.g. uplink or downlink).
190      * @param bitsPerSecond This value is the bitrate requested by the other party UE through
191      *        RTP CMR, RTCPAPP or TMMBR, and ImsStack converts this value to the MAC bitrate
192      *        (defined in TS36.321, range: 0 ~ 8000 kbit/s).
193      */
sendAnbrQuery(int mediaType, int direction, int bitsPerSecond)194     public void sendAnbrQuery(int mediaType, int direction, int bitsPerSecond) {
195         Log.d(TAG, "mockImsService - sendAnbrQuery mediaType=" + mediaType + ", direction="
196                 + direction + ", bitsPerSecond" + bitsPerSecond);
197 
198         try {
199             mAnbrValues[0] = mediaType;
200             mAnbrValues[1] = direction;
201             mAnbrValues[2] = bitsPerSecond;
202         } catch (Exception e) {
203             Log.e(TAG, "SendAnbrQuery is not called");
204         }
205     }
206 
207     /**
208      * Clears the Anbr values.
209      */
resetAnbrValues()210     public void resetAnbrValues() {
211         mAnbrValues[0] = INVALID;
212         mAnbrValues[1] = INVALID;
213         mAnbrValues[2] = INVALID;
214     }
215 
216     /**
217      * Returns the Anbr values triggered by Anbr Query.
218      *
219      * @return the Anbr values triggered by Anbr Query.
220      */
getAnbrValues()221     public int[] getAnbrValues() {
222         return mAnbrValues;
223     }
224 
countDownLatch(int latchIndex)225     private void countDownLatch(int latchIndex) {
226         synchronized (mLatches) {
227             mLatches[latchIndex].countDown();
228         }
229     }
230 
resetLatch(int latchIndex)231     private void resetLatch(int latchIndex) {
232         synchronized (mLatches) {
233             mLatches[latchIndex] = new CountDownLatch(1);
234         }
235     }
236 
237     /**
238      * Waits for the event of voice service.
239      *
240      * @param latchIndex The index of the event.
241      * @param waitMs The timeout in milliseconds.
242      * @return {@code true} if the event happens.
243      */
waitForLatchCountdown(int latchIndex, long waitMs)244     public boolean waitForLatchCountdown(int latchIndex, long waitMs) {
245         boolean complete = false;
246         try {
247             CountDownLatch latch;
248             synchronized (mLatches) {
249                 latch = mLatches[latchIndex];
250             }
251             long startTime = System.currentTimeMillis();
252             complete = latch.await(waitMs, TimeUnit.MILLISECONDS);
253             Log.i(TAG, "Latch " + latchIndex + " took "
254                     + (System.currentTimeMillis() - startTime) + " ms to count down.");
255         } catch (InterruptedException e) {
256         }
257         synchronized (mLatches) {
258             mLatches[latchIndex] = new CountDownLatch(1);
259         }
260         return complete;
261     }
262 
263     /**
264      * Resets the CountDownLatches
265      */
resetAllLatchCountdown()266     public void resetAllLatchCountdown() {
267         synchronized (mLatches) {
268             for (int i = 0; i < LATCH_MAX; i++) {
269                 mLatches[i] = new CountDownLatch(1);
270             }
271         }
272     }
273 }
274