1 /* 2 * Copyright (C) 2017 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.telecom.cts; 18 19 import android.os.Bundle; 20 import android.telecom.Call; 21 import android.telecom.Connection; 22 import android.telecom.TelecomManager; 23 24 import java.io.IOException; 25 26 public class RttOperationsTest extends BaseTelecomTestWithMockServices { 27 private static final int RTT_SEND_TIMEOUT_MILLIS = 1000; 28 private static final String[] TEST_STRINGS = { 29 "A", 30 "AB", 31 "ABCDEFG", 32 "", 33 "" 34 }; 35 private static final int RTT_FAILURE_REASON = 2; 36 37 private boolean mInitialRttMode; 38 39 @Override 40 protected void setUp() throws Exception { 41 super.setUp(); 42 if (mShouldTestTelecom) { 43 setupConnectionService(null, FLAG_REGISTER | FLAG_ENABLE); 44 mInitialRttMode = getRttMasterSwitch(); 45 setRttMasterSwitch(false); 46 } 47 } 48 49 @Override 50 protected void tearDown() throws Exception { 51 super.tearDown(); 52 if (mShouldTestTelecom) { 53 setRttMasterSwitch(mInitialRttMode); 54 } 55 } 56 57 public void testOutgoingRttCall() throws Exception { 58 if (!mShouldTestTelecom) { 59 return; 60 } 61 62 placeRttCall(false); 63 final MockConnection connection = verifyConnectionForOutgoingCall(); 64 final MockInCallService inCallService = mInCallCallbacks.getService(); 65 final Call call = inCallService.getLastCall(); 66 TestUtils.waitOnAllHandlers(getInstrumentation()); 67 verifyRttEnabled(call, connection); 68 } 69 70 public void testIncomingRttCall() throws Exception { 71 if (!mShouldTestTelecom) { 72 return; 73 } 74 75 setRttMasterSwitch(true); 76 placeRttCall(true); 77 final MockConnection connection = verifyConnectionForIncomingCall(); 78 final MockInCallService inCallService = mInCallCallbacks.getService(); 79 final Call call = inCallService.getLastCall(); 80 TestUtils.waitOnAllHandlers(getInstrumentation()); 81 verifyRttEnabled(call, connection); 82 } 83 84 public void testLocalRttUpgradeAccepted() throws Exception { 85 if (!mShouldTestTelecom) { 86 return; 87 } 88 89 placeAndVerifyCall(); 90 final MockConnection connection = verifyConnectionForOutgoingCall(); 91 final MockInCallService inCallService = mInCallCallbacks.getService(); 92 final Call call = inCallService.getLastCall(); 93 verifyRttDisabled(call); 94 95 TestUtils.InvokeCounter startRttCounter = 96 connection.getInvokeCounter(MockConnection.ON_START_RTT); 97 call.sendRttRequest(); 98 startRttCounter.waitForCount(1, TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS); 99 100 connection.setRttTextStream((Connection.RttTextStream) startRttCounter.getArgs(0)[0]); 101 connection.setConnectionProperties( 102 connection.getConnectionProperties() | Connection.PROPERTY_IS_RTT); 103 connection.sendRttInitiationSuccess(); 104 TestUtils.waitOnAllHandlers(getInstrumentation()); 105 verifyRttEnabled(call, connection); 106 } 107 108 public void testLocalRttUpgradeRejected() throws Exception { 109 if (!mShouldTestTelecom) { 110 return; 111 } 112 113 placeAndVerifyCall(); 114 final MockConnection connection = verifyConnectionForOutgoingCall(); 115 final MockInCallService inCallService = mInCallCallbacks.getService(); 116 final Call call = inCallService.getLastCall(); 117 verifyRttDisabled(call); 118 119 TestUtils.InvokeCounter startRttCounter = 120 connection.getInvokeCounter(MockConnection.ON_START_RTT); 121 call.sendRttRequest(); 122 startRttCounter.waitForCount(1, TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS); 123 124 connection.sendRttInitiationFailure(RTT_FAILURE_REASON); 125 TestUtils.waitOnAllHandlers(getInstrumentation()); 126 mOnRttInitiationFailedCounter.waitForCount(1, TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS); 127 assertEquals(call, mOnRttInitiationFailedCounter.getArgs(0)[0]); 128 assertEquals(RTT_FAILURE_REASON, mOnRttInitiationFailedCounter.getArgs(0)[1]); 129 verifyRttDisabled(call); 130 } 131 132 public void testAcceptRemoteRttUpgrade() throws Exception { 133 if (!mShouldTestTelecom) { 134 return; 135 } 136 137 placeAndVerifyCall(); 138 final MockConnection connection = verifyConnectionForOutgoingCall(); 139 final MockInCallService inCallService = mInCallCallbacks.getService(); 140 final Call call = inCallService.getLastCall(); 141 verifyRttDisabled(call); 142 143 TestUtils.InvokeCounter rttRequestResponseCounter = 144 connection.getInvokeCounter(MockConnection.ON_RTT_REQUEST_RESPONSE); 145 connection.sendRemoteRttRequest(); 146 mOnRttRequestCounter.waitForCount(1, TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS); 147 int requestId = (Integer) mOnRttRequestCounter.getArgs(0)[1]; 148 call.respondToRttRequest(requestId, true /* accept */); 149 150 rttRequestResponseCounter.waitForCount(1, TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS); 151 TestUtils.waitOnAllHandlers(getInstrumentation()); 152 verifyRttEnabled(call, connection); 153 } 154 155 public void testRejectRemoteRttRequest() throws Exception { 156 if (!mShouldTestTelecom) { 157 return; 158 } 159 160 placeAndVerifyCall(); 161 final MockConnection connection = verifyConnectionForOutgoingCall(); 162 final MockInCallService inCallService = mInCallCallbacks.getService(); 163 final Call call = inCallService.getLastCall(); 164 verifyRttDisabled(call); 165 166 TestUtils.InvokeCounter rttRequestResponseCounter = 167 connection.getInvokeCounter(MockConnection.ON_RTT_REQUEST_RESPONSE); 168 connection.sendRemoteRttRequest(); 169 mOnRttRequestCounter.waitForCount(1, TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS); 170 int requestId = (Integer) mOnRttRequestCounter.getArgs(0)[1]; 171 call.respondToRttRequest(requestId, false /* accept */); 172 173 rttRequestResponseCounter.waitForCount(1, TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS); 174 assertNull(rttRequestResponseCounter.getArgs(0)[0]); 175 TestUtils.waitOnAllHandlers(getInstrumentation()); 176 verifyRttDisabled(call); 177 } 178 179 public void testLocalRttTermination() throws Exception { 180 if (!mShouldTestTelecom) { 181 return; 182 } 183 184 placeRttCall(false); 185 final MockConnection connection = verifyConnectionForOutgoingCall(); 186 final MockInCallService inCallService = mInCallCallbacks.getService(); 187 final Call call = inCallService.getLastCall(); 188 189 // Skipping RTT verification since that's tested by another test 190 TestUtils.InvokeCounter stopRttCounter = 191 connection.getInvokeCounter(MockConnection.ON_STOP_RTT); 192 call.stopRtt(); 193 stopRttCounter.waitForCount(1, TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS); 194 connection.setConnectionProperties( 195 connection.getConnectionProperties() & ~Connection.PROPERTY_IS_RTT); 196 TestUtils.waitOnAllHandlers(getInstrumentation()); 197 verifyRttDisabled(call); 198 } 199 200 public void testRemoteRttTermination() throws Exception { 201 if (!mShouldTestTelecom) { 202 return; 203 } 204 205 placeRttCall(false); 206 final MockConnection connection = verifyConnectionForOutgoingCall(); 207 final MockInCallService inCallService = mInCallCallbacks.getService(); 208 final Call call = inCallService.getLastCall(); 209 210 // Skipping RTT verification since that's tested by another test 211 connection.sendRttSessionRemotelyTerminated(); 212 TestUtils.InvokeCounter stopRttCounter = 213 connection.getInvokeCounter(MockConnection.ON_STOP_RTT); 214 call.stopRtt(); 215 stopRttCounter.waitForCount(1, TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS); 216 connection.setConnectionProperties( 217 connection.getConnectionProperties() & ~Connection.PROPERTY_IS_RTT); 218 TestUtils.waitOnAllHandlers(getInstrumentation()); 219 verifyRttDisabled(call); 220 } 221 222 private void verifyRttDisabled(Call call) { 223 TestUtils.waitOnLocalMainLooper(TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS); 224 assertFalse(call.isRttActive()); 225 assertNull(call.getRttCall()); 226 } 227 228 private void verifyRttEnabled(Call call, MockConnection connection) { 229 TestUtils.waitOnLocalMainLooper(TestUtils.WAIT_FOR_STATE_CHANGE_TIMEOUT_MS); 230 Connection.RttTextStream connectionSideRtt = connection.getRttTextStream(); 231 Call.RttCall inCallSideRtt = call.getRttCall(); 232 assertNotNull(connectionSideRtt); 233 assertTrue(call.isRttActive()); 234 assertNotNull(inCallSideRtt); 235 236 verifyRttPipeIntegrity(inCallSideRtt, connectionSideRtt); 237 verifyRttPipeReadBlocking(connectionSideRtt); 238 } 239 240 private void verifyRttPipeReadBlocking(Connection.RttTextStream connectionSide) { 241 // Make sure that nothing gets read from the pipe 242 boolean[] flag = new boolean[1]; 243 flag[0] = false; 244 Thread t = new Thread(() -> { 245 try { 246 connectionSide.read(); 247 flag[0] = true; 248 } catch (Exception e) { 249 // do nothing 250 } 251 }); 252 t.start(); 253 sleep(500); 254 t.interrupt(); 255 assertFalse(flag[0]); 256 } 257 258 private void verifyRttPipeIntegrity(Call.RttCall inCallSide, Connection.RttTextStream 259 connectionSide) { 260 for (String s : TEST_STRINGS) { 261 try { 262 inCallSide.write(s); 263 waitUntilConditionIsTrueOrTimeout(new Condition() { 264 String readSoFar = ""; 265 @Override 266 public Object expected() { 267 return s; 268 } 269 270 @Override 271 public Object actual() { 272 try { 273 String newRead = connectionSide.readImmediately(); 274 if (newRead != null) { 275 readSoFar += newRead; 276 } 277 return readSoFar; 278 } catch (IOException e) { 279 fail("IOException while reading from connection side"); 280 return null; 281 } 282 } 283 }, RTT_SEND_TIMEOUT_MILLIS, String.format("%s failed to send correctly.", s)); 284 285 connectionSide.write(s); 286 waitUntilConditionIsTrueOrTimeout(new Condition() { 287 String readSoFar = ""; 288 @Override 289 public Object expected() { 290 return s; 291 } 292 293 @Override 294 public Object actual() { 295 try { 296 String newRead = inCallSide.readImmediately(); 297 if (newRead != null) { 298 readSoFar += newRead; 299 } 300 return readSoFar; 301 } catch (IOException e) { 302 fail("IOException while reading from incall side"); 303 return null; 304 } 305 } 306 }, RTT_SEND_TIMEOUT_MILLIS, String.format("%s failed to send correctly.", s)); 307 } catch (IOException e) { 308 fail(String.format( 309 "Caught IOException when verifying %s", s)); 310 } 311 312 } 313 } 314 315 private void placeRttCall(boolean incoming) { 316 Bundle extras = new Bundle(); 317 extras.putBoolean(TelecomManager.EXTRA_START_CALL_WITH_RTT, true); 318 if (incoming) { 319 addAndVerifyNewIncomingCall(createTestNumber(), extras); 320 } else { 321 Bundle outgoingCallExtras = new Bundle(); 322 outgoingCallExtras.putParcelable(TelecomManager.EXTRA_OUTGOING_CALL_EXTRAS, extras); 323 placeAndVerifyCall(outgoingCallExtras); 324 } 325 } 326 327 private void setRttMasterSwitch(boolean on) throws Exception { 328 TestUtils.executeShellCommand(getInstrumentation(), 329 "settings put system rtt_calling_mode " + (on ? 1 : 0)); 330 } 331 332 private boolean getRttMasterSwitch() throws Exception { 333 try { 334 return Integer.valueOf(TestUtils.executeShellCommand( 335 getInstrumentation(), "settings get system rtt_calling_mode")) == 1; 336 } catch (NumberFormatException e) { 337 // If the setting hasn't been set yet, assume it's off 338 return false; 339 } 340 } 341 } 342