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