1 /* 2 * Copyright (C) 2015 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 com.android.server.telecom.tests; 18 19 20 import android.content.ComponentName; 21 import android.content.ContentProvider; 22 import android.content.ContentValues; 23 import android.content.Context; 24 import android.content.IContentProvider; 25 import android.content.pm.UserInfo; 26 import android.location.Country; 27 import android.location.CountryDetector; 28 import android.location.CountryListener; 29 import android.net.Uri; 30 import android.os.Looper; 31 import android.os.PersistableBundle; 32 import android.os.UserHandle; 33 import android.os.UserManager; 34 import android.provider.CallLog; 35 import android.provider.CallLog.Calls; 36 import android.support.test.filters.FlakyTest; 37 import android.telecom.DisconnectCause; 38 import android.telecom.PhoneAccount; 39 import android.telecom.PhoneAccountHandle; 40 import android.telecom.VideoProfile; 41 import android.telephony.CarrierConfigManager; 42 import android.telephony.PhoneNumberUtils; 43 import android.test.suitebuilder.annotation.MediumTest; 44 import android.test.suitebuilder.annotation.SmallTest; 45 46 import com.android.server.telecom.Call; 47 import com.android.server.telecom.CallLogManager; 48 import com.android.server.telecom.CallState; 49 import com.android.server.telecom.HandoverState; 50 import com.android.server.telecom.MissedCallNotifier; 51 import com.android.server.telecom.PhoneAccountRegistrar; 52 import com.android.server.telecom.TelephonyUtil; 53 54 import static org.junit.Assert.assertEquals; 55 import static org.junit.Assert.assertNull; 56 import static org.junit.Assert.assertTrue; 57 import static org.junit.Assert.fail; 58 import static org.mockito.Matchers.any; 59 import static org.mockito.Matchers.anyString; 60 import static org.mockito.Matchers.eq; 61 import static org.mockito.Mockito.doAnswer; 62 import static org.mockito.Mockito.mock; 63 import static org.mockito.Mockito.never; 64 import static org.mockito.Mockito.timeout; 65 import static org.mockito.Mockito.verify; 66 import static org.mockito.Mockito.when; 67 68 import org.junit.Before; 69 import org.junit.Test; 70 import org.junit.runner.RunWith; 71 import org.junit.runners.JUnit4; 72 import org.mockito.ArgumentCaptor; 73 import org.mockito.Mock; 74 import org.mockito.invocation.InvocationOnMock; 75 import org.mockito.stubbing.Answer; 76 77 import java.util.Arrays; 78 79 @RunWith(JUnit4.class) 80 public class CallLogManagerTest extends TelecomTestCase { 81 82 private CallLogManager mCallLogManager; 83 private IContentProvider mContentProvider; 84 private PhoneAccountHandle mDefaultAccountHandle; 85 private PhoneAccountHandle mOtherUserAccountHandle; 86 private PhoneAccountHandle mManagedProfileAccountHandle; 87 private PhoneAccountHandle mSelfManagedAccountHandle; 88 89 private static final Uri TEL_PHONEHANDLE = Uri.parse("tel:5555551234"); 90 91 private static final PhoneAccountHandle EMERGENCY_ACCT_HANDLE = TelephonyUtil 92 .getDefaultEmergencyPhoneAccount() 93 .getAccountHandle(); 94 95 private static final int NO_VIDEO_STATE = VideoProfile.STATE_AUDIO_ONLY; 96 private static final int BIDIRECTIONAL_VIDEO_STATE = VideoProfile.STATE_BIDIRECTIONAL; 97 private static final String POST_DIAL_STRING = ";12345"; 98 private static final String VIA_NUMBER_STRING = "5555555678"; 99 private static final String TEST_PHONE_ACCOUNT_ID= "testPhoneAccountId"; 100 private static final String TEST_SELF_MGD_PHONE_ACCOUNT_ID= "testPhoneAccountId"; 101 102 private static final int TEST_TIMEOUT_MILLIS = 200; 103 private static final int CURRENT_USER_ID = 0; 104 private static final int OTHER_USER_ID = 10; 105 private static final int MANAGED_USER_ID = 11; 106 107 private static final String TEST_ISO = "KR"; 108 private static final String TEST_ISO_2 = "JP"; 109 110 @Mock PhoneAccountRegistrar mMockPhoneAccountRegistrar; 111 112 @Mock 113 MissedCallNotifier mMissedCallNotifier; 114 115 @Override 116 @Before 117 public void setUp() throws Exception { 118 super.setUp(); 119 mContext = mComponentContextFixture.getTestDouble().getApplicationContext(); 120 mCallLogManager = new CallLogManager(mContext, mMockPhoneAccountRegistrar, 121 mMissedCallNotifier); 122 mContentProvider = 123 mContext.getContentResolver().acquireProvider("0@call_log"); 124 mDefaultAccountHandle = new PhoneAccountHandle( 125 new ComponentName("com.android.server.telecom.tests", "CallLogManagerTest"), 126 TEST_PHONE_ACCOUNT_ID, 127 UserHandle.of(CURRENT_USER_ID) 128 ); 129 130 mOtherUserAccountHandle = new PhoneAccountHandle( 131 new ComponentName("com.android.server.telecom.tests", "CallLogManagerTest"), 132 TEST_PHONE_ACCOUNT_ID, 133 UserHandle.of(OTHER_USER_ID) 134 ); 135 136 mManagedProfileAccountHandle = new PhoneAccountHandle( 137 new ComponentName("com.android.server.telecom.tests", "CallLogManagerTest"), 138 TEST_PHONE_ACCOUNT_ID, 139 UserHandle.of(MANAGED_USER_ID) 140 ); 141 142 mSelfManagedAccountHandle = new PhoneAccountHandle( 143 new ComponentName("com.android.server.telecom.tests", "CallLogManagerSelfMgdTest"), 144 TEST_SELF_MGD_PHONE_ACCOUNT_ID, 145 UserHandle.of(CURRENT_USER_ID) 146 ); 147 148 UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE); 149 UserInfo userInfo = new UserInfo(CURRENT_USER_ID, "test", 0); 150 UserInfo otherUserInfo = new UserInfo(OTHER_USER_ID, "test2", 0); 151 UserInfo managedProfileUserInfo = new UserInfo(MANAGED_USER_ID, "test3", 152 UserInfo.FLAG_MANAGED_PROFILE); 153 154 doAnswer(new Answer<Uri>() { 155 @Override 156 public Uri answer(InvocationOnMock invocation) throws Throwable { 157 return (Uri) invocation.getArguments()[1]; 158 } 159 }).when(mContentProvider).insert(anyString(), any(Uri.class), any(ContentValues.class)); 160 161 when(userManager.isUserRunning(any(UserHandle.class))).thenReturn(true); 162 when(userManager.isUserUnlocked(any(UserHandle.class))).thenReturn(true); 163 when(userManager.hasUserRestriction(any(String.class), any(UserHandle.class))) 164 .thenReturn(false); 165 when(userManager.getUsers(any(Boolean.class))) 166 .thenReturn(Arrays.asList(userInfo, otherUserInfo, managedProfileUserInfo)); 167 when(userManager.getUserInfo(eq(CURRENT_USER_ID))).thenReturn(userInfo); 168 when(userManager.getUserInfo(eq(OTHER_USER_ID))).thenReturn(otherUserInfo); 169 when(userManager.getUserInfo(eq(MANAGED_USER_ID))).thenReturn(managedProfileUserInfo); 170 } 171 172 @MediumTest 173 @Test 174 public void testDontLogCancelledCall() { 175 Call fakeCall = makeFakeCall( 176 DisconnectCause.CANCELED, 177 false, // isConference 178 false, // isIncoming 179 1L, // creationTimeMillis 180 1000L, // ageMillis 181 TEL_PHONEHANDLE, // callHandle 182 mDefaultAccountHandle, // phoneAccountHandle 183 NO_VIDEO_STATE, // callVideoState 184 POST_DIAL_STRING, // postDialDigits 185 VIA_NUMBER_STRING, // viaNumber 186 UserHandle.of(CURRENT_USER_ID) 187 ); 188 mCallLogManager.onCallStateChanged(fakeCall, CallState.DIALING, CallState.DISCONNECTED); 189 verifyNoInsertion(); 190 mCallLogManager.onCallStateChanged(fakeCall, CallState.DIALING, CallState.ABORTED); 191 verifyNoInsertion(); 192 } 193 194 @MediumTest 195 @Test 196 public void testDontLogChoosingAccountCall() { 197 when(mMockPhoneAccountRegistrar.getPhoneAccountUnchecked(any(PhoneAccountHandle.class))) 198 .thenReturn(makeFakePhoneAccount(mDefaultAccountHandle, CURRENT_USER_ID)); 199 Call fakeCall = makeFakeCall( 200 DisconnectCause.OTHER, // disconnectCauseCode 201 false, // isConference 202 false, // isIncoming 203 1L, // creationTimeMillis 204 1000L, // ageMillis 205 TEL_PHONEHANDLE, // callHandle 206 mDefaultAccountHandle, // phoneAccountHandle 207 NO_VIDEO_STATE, // callVideoState 208 POST_DIAL_STRING, // postDialDigits 209 VIA_NUMBER_STRING, // viaNumber 210 UserHandle.of(CURRENT_USER_ID) 211 ); 212 mCallLogManager.onCallStateChanged(fakeCall, CallState.SELECT_PHONE_ACCOUNT, 213 CallState.DISCONNECTED); 214 verifyNoInsertion(); 215 } 216 217 @MediumTest 218 @Test 219 public void testDontLogCallsFromEmergencyAccount() { 220 when(mMockPhoneAccountRegistrar.getPhoneAccountUnchecked(any(PhoneAccountHandle.class))) 221 .thenReturn(makeFakePhoneAccount(EMERGENCY_ACCT_HANDLE, 0)); 222 CarrierConfigManager mockCarrierConfigManager = 223 (CarrierConfigManager) mComponentContextFixture.getTestDouble() 224 .getApplicationContext().getSystemService(Context.CARRIER_CONFIG_SERVICE); 225 PersistableBundle bundle = new PersistableBundle(); 226 bundle.putBoolean(CarrierConfigManager.KEY_ALLOW_EMERGENCY_NUMBERS_IN_CALL_LOG_BOOL, false); 227 when(mockCarrierConfigManager.getConfig()).thenReturn(bundle); 228 229 Call fakeCall = makeFakeCall( 230 DisconnectCause.OTHER, // disconnectCauseCode 231 false, // isConference 232 false, // isIncoming 233 1L, // creationTimeMillis 234 1000L, // ageMillis 235 TEL_PHONEHANDLE, // callHandle 236 EMERGENCY_ACCT_HANDLE, // phoneAccountHandle 237 NO_VIDEO_STATE, // callVideoState 238 POST_DIAL_STRING, // postDialDigits 239 VIA_NUMBER_STRING, // viaNumber 240 UserHandle.of(CURRENT_USER_ID) 241 ); 242 mCallLogManager.onCallStateChanged(fakeCall, CallState.ACTIVE, CallState.DISCONNECTED); 243 verifyNoInsertion(); 244 } 245 246 @MediumTest 247 @Test 248 public void testLogCallDirectionOutgoing() { 249 when(mMockPhoneAccountRegistrar.getPhoneAccountUnchecked(any(PhoneAccountHandle.class))) 250 .thenReturn(makeFakePhoneAccount(mDefaultAccountHandle, CURRENT_USER_ID)); 251 Call fakeOutgoingCall = makeFakeCall( 252 DisconnectCause.OTHER, // disconnectCauseCode 253 false, // isConference 254 false, // isIncoming 255 1L, // creationTimeMillis 256 1000L, // ageMillis 257 TEL_PHONEHANDLE, // callHandle 258 mDefaultAccountHandle, // phoneAccountHandle 259 NO_VIDEO_STATE, // callVideoState 260 POST_DIAL_STRING, // postDialDigits 261 VIA_NUMBER_STRING, // viaNumber 262 UserHandle.of(CURRENT_USER_ID) 263 ); 264 mCallLogManager.onCallStateChanged(fakeOutgoingCall, CallState.ACTIVE, 265 CallState.DISCONNECTED); 266 ContentValues insertedValues = verifyInsertionWithCapture(CURRENT_USER_ID); 267 assertEquals(insertedValues.getAsInteger(CallLog.Calls.TYPE), 268 Integer.valueOf(CallLog.Calls.OUTGOING_TYPE)); 269 } 270 271 @MediumTest 272 @Test 273 public void testLogCallDirectionIncoming() { 274 when(mMockPhoneAccountRegistrar.getPhoneAccountUnchecked(any(PhoneAccountHandle.class))) 275 .thenReturn(makeFakePhoneAccount(mDefaultAccountHandle, CURRENT_USER_ID)); 276 Call fakeIncomingCall = makeFakeCall( 277 DisconnectCause.OTHER, // disconnectCauseCode 278 false, // isConference 279 true, // isIncoming 280 1L, // creationTimeMillis 281 1000L, // ageMillis 282 TEL_PHONEHANDLE, // callHandle 283 mDefaultAccountHandle, // phoneAccountHandle 284 NO_VIDEO_STATE, // callVideoState 285 POST_DIAL_STRING, // postDialDigits 286 VIA_NUMBER_STRING, // viaNumber 287 null 288 ); 289 mCallLogManager.onCallStateChanged(fakeIncomingCall, CallState.ACTIVE, 290 CallState.DISCONNECTED); 291 ContentValues insertedValues = verifyInsertionWithCapture(CURRENT_USER_ID); 292 assertEquals(insertedValues.getAsInteger(CallLog.Calls.TYPE), 293 Integer.valueOf(CallLog.Calls.INCOMING_TYPE)); 294 } 295 296 @MediumTest 297 @Test 298 public void testLogCallDirectionMissed() { 299 when(mMockPhoneAccountRegistrar.getPhoneAccountUnchecked(any(PhoneAccountHandle.class))) 300 .thenReturn(makeFakePhoneAccount(mDefaultAccountHandle, CURRENT_USER_ID)); 301 Call fakeMissedCall = makeFakeCall( 302 DisconnectCause.MISSED, // disconnectCauseCode 303 false, // isConference 304 true, // isIncoming 305 1L, // creationTimeMillis 306 1000L, // ageMillis 307 TEL_PHONEHANDLE, // callHandle 308 mDefaultAccountHandle, // phoneAccountHandle 309 NO_VIDEO_STATE, // callVideoState 310 POST_DIAL_STRING, // postDialDigits 311 VIA_NUMBER_STRING, // viaNumber 312 null 313 ); 314 315 mCallLogManager.onCallStateChanged(fakeMissedCall, CallState.ACTIVE, 316 CallState.DISCONNECTED); 317 ContentValues insertedValues = verifyInsertionWithCapture(CURRENT_USER_ID); 318 assertEquals(insertedValues.getAsInteger(CallLog.Calls.TYPE), 319 Integer.valueOf(CallLog.Calls.MISSED_TYPE)); 320 // Timeout needed because showMissedCallNotification is called from onPostExecute. 321 verify(mMissedCallNotifier, timeout(TEST_TIMEOUT_MILLIS)) 322 .showMissedCallNotification(any(MissedCallNotifier.CallInfo.class)); 323 } 324 325 @MediumTest 326 @Test 327 public void testLogCallDirectionRejected() { 328 when(mMockPhoneAccountRegistrar.getPhoneAccountUnchecked(any(PhoneAccountHandle.class))) 329 .thenReturn(makeFakePhoneAccount(mDefaultAccountHandle, CURRENT_USER_ID)); 330 Call fakeMissedCall = makeFakeCall( 331 DisconnectCause.REJECTED, // disconnectCauseCode 332 false, // isConference 333 true, // isIncoming 334 1L, // creationTimeMillis 335 1000L, // ageMillis 336 TEL_PHONEHANDLE, // callHandle 337 mDefaultAccountHandle, // phoneAccountHandle 338 NO_VIDEO_STATE, // callVideoState 339 POST_DIAL_STRING, // postDialDigits 340 VIA_NUMBER_STRING, // viaNumber 341 null 342 ); 343 344 mCallLogManager.onCallStateChanged(fakeMissedCall, CallState.ACTIVE, 345 CallState.DISCONNECTED); 346 ContentValues insertedValues = verifyInsertionWithCapture(CURRENT_USER_ID); 347 assertEquals(insertedValues.getAsInteger(CallLog.Calls.TYPE), 348 Integer.valueOf(Calls.REJECTED_TYPE)); 349 } 350 351 @MediumTest 352 @Test 353 public void testCreationTimeAndAge() { 354 when(mMockPhoneAccountRegistrar.getPhoneAccountUnchecked(any(PhoneAccountHandle.class))) 355 .thenReturn(makeFakePhoneAccount(mDefaultAccountHandle, CURRENT_USER_ID)); 356 long currentTime = System.currentTimeMillis(); 357 long duration = 1000L; 358 Call fakeCall = makeFakeCall( 359 DisconnectCause.OTHER, // disconnectCauseCode 360 false, // isConference 361 false, // isIncoming 362 currentTime, // creationTimeMillis 363 duration, // ageMillis 364 TEL_PHONEHANDLE, // callHandle 365 mDefaultAccountHandle, // phoneAccountHandle 366 NO_VIDEO_STATE, // callVideoState 367 POST_DIAL_STRING, // postDialDigits 368 VIA_NUMBER_STRING, // viaNumber 369 UserHandle.of(CURRENT_USER_ID) 370 ); 371 mCallLogManager.onCallStateChanged(fakeCall, CallState.ACTIVE, CallState.DISCONNECTED); 372 ContentValues insertedValues = verifyInsertionWithCapture(CURRENT_USER_ID); 373 assertEquals(insertedValues.getAsLong(CallLog.Calls.DATE), 374 Long.valueOf(currentTime)); 375 assertEquals(insertedValues.getAsLong(CallLog.Calls.DURATION), 376 Long.valueOf(duration / 1000)); 377 } 378 379 @MediumTest 380 @Test 381 public void testLogPhoneAccountId() { 382 when(mMockPhoneAccountRegistrar.getPhoneAccountUnchecked(any(PhoneAccountHandle.class))) 383 .thenReturn(makeFakePhoneAccount(mDefaultAccountHandle, CURRENT_USER_ID)); 384 Call fakeCall = makeFakeCall( 385 DisconnectCause.OTHER, // disconnectCauseCode 386 false, // isConference 387 true, // isIncoming 388 1L, // creationTimeMillis 389 1000L, // ageMillis 390 TEL_PHONEHANDLE, // callHandle 391 mDefaultAccountHandle, // phoneAccountHandle 392 NO_VIDEO_STATE, // callVideoState 393 POST_DIAL_STRING, // postDialDigits 394 VIA_NUMBER_STRING, // viaNumber 395 UserHandle.of(CURRENT_USER_ID) 396 ); 397 mCallLogManager.onCallStateChanged(fakeCall, CallState.ACTIVE, CallState.DISCONNECTED); 398 ContentValues insertedValues = verifyInsertionWithCapture(CURRENT_USER_ID); 399 assertEquals(insertedValues.getAsString(CallLog.Calls.PHONE_ACCOUNT_ID), 400 TEST_PHONE_ACCOUNT_ID); 401 } 402 403 @MediumTest 404 @Test 405 public void testLogCorrectPhoneNumber() { 406 when(mMockPhoneAccountRegistrar.getPhoneAccountUnchecked(any(PhoneAccountHandle.class))) 407 .thenReturn(makeFakePhoneAccount(mDefaultAccountHandle, CURRENT_USER_ID)); 408 Call fakeCall = makeFakeCall( 409 DisconnectCause.OTHER, // disconnectCauseCode 410 false, // isConference 411 true, // isIncoming 412 1L, // creationTimeMillis 413 1000L, // ageMillis 414 TEL_PHONEHANDLE, // callHandle 415 mDefaultAccountHandle, // phoneAccountHandle 416 NO_VIDEO_STATE, // callVideoState 417 POST_DIAL_STRING, // postDialDigits 418 VIA_NUMBER_STRING, // viaNumber 419 UserHandle.of(CURRENT_USER_ID) 420 ); 421 mCallLogManager.onCallStateChanged(fakeCall, CallState.ACTIVE, CallState.DISCONNECTED); 422 ContentValues insertedValues = verifyInsertionWithCapture(CURRENT_USER_ID); 423 assertEquals(insertedValues.getAsString(CallLog.Calls.NUMBER), 424 TEL_PHONEHANDLE.getSchemeSpecificPart()); 425 assertEquals(insertedValues.getAsString(CallLog.Calls.POST_DIAL_DIGITS), POST_DIAL_STRING); 426 String expectedNumber = PhoneNumberUtils.formatNumber(VIA_NUMBER_STRING, "US"); 427 assertEquals(insertedValues.getAsString(Calls.VIA_NUMBER), expectedNumber); 428 } 429 430 @MediumTest 431 @Test 432 public void testLogCallVideoFeatures() { 433 when(mMockPhoneAccountRegistrar.getPhoneAccountUnchecked(any(PhoneAccountHandle.class))) 434 .thenReturn(makeFakePhoneAccount(mDefaultAccountHandle, CURRENT_USER_ID)); 435 Call fakeVideoCall = makeFakeCall( 436 DisconnectCause.OTHER, // disconnectCauseCode 437 false, // isConference 438 true, // isIncoming 439 1L, // creationTimeMillis 440 1000L, // ageMillis 441 TEL_PHONEHANDLE, // callHandle 442 mDefaultAccountHandle, // phoneAccountHandle 443 BIDIRECTIONAL_VIDEO_STATE, // callVideoState 444 POST_DIAL_STRING, // postDialDigits 445 VIA_NUMBER_STRING, // viaNumber 446 UserHandle.of(CURRENT_USER_ID) 447 ); 448 mCallLogManager.onCallStateChanged(fakeVideoCall, CallState.ACTIVE, CallState.DISCONNECTED); 449 ContentValues insertedValues = verifyInsertionWithCapture(CURRENT_USER_ID); 450 assertTrue((insertedValues.getAsInteger(CallLog.Calls.FEATURES) 451 & CallLog.Calls.FEATURES_VIDEO) == CallLog.Calls.FEATURES_VIDEO); 452 } 453 454 @MediumTest 455 @FlakyTest 456 @Test 457 public void testLogCallDirectionOutgoingWithMultiUserCapability() { 458 when(mMockPhoneAccountRegistrar.getPhoneAccountUnchecked(any(PhoneAccountHandle.class))) 459 .thenReturn(makeFakePhoneAccount(mOtherUserAccountHandle, 460 PhoneAccount.CAPABILITY_MULTI_USER)); 461 Call fakeOutgoingCall = makeFakeCall( 462 DisconnectCause.OTHER, // disconnectCauseCode 463 false, // isConference 464 false, // isIncoming 465 1L, // creationTimeMillis 466 1000L, // ageMillis 467 TEL_PHONEHANDLE, // callHandle 468 mDefaultAccountHandle, // phoneAccountHandle 469 NO_VIDEO_STATE, // callVideoState 470 POST_DIAL_STRING, // postDialDigits 471 VIA_NUMBER_STRING, // viaNumber 472 UserHandle.of(CURRENT_USER_ID) 473 ); 474 mCallLogManager.onCallStateChanged(fakeOutgoingCall, CallState.ACTIVE, 475 CallState.DISCONNECTED); 476 477 // Outgoing call placed through a phone account with multi user capability is inserted to 478 // all users except managed profile. 479 ContentValues insertedValues = verifyInsertionWithCapture(CURRENT_USER_ID); 480 assertEquals(insertedValues.getAsInteger(CallLog.Calls.TYPE), 481 Integer.valueOf(CallLog.Calls.OUTGOING_TYPE)); 482 insertedValues = verifyInsertionWithCapture(OTHER_USER_ID); 483 assertEquals(insertedValues.getAsInteger(CallLog.Calls.TYPE), 484 Integer.valueOf(CallLog.Calls.OUTGOING_TYPE)); 485 verifyNoInsertionInUser(MANAGED_USER_ID); 486 } 487 488 @MediumTest 489 @Test 490 public void testLogCallDirectionIncomingWithMultiUserCapability() { 491 when(mMockPhoneAccountRegistrar.getPhoneAccountUnchecked(any(PhoneAccountHandle.class))) 492 .thenReturn(makeFakePhoneAccount(mOtherUserAccountHandle, 493 PhoneAccount.CAPABILITY_MULTI_USER)); 494 Call fakeIncomingCall = makeFakeCall( 495 DisconnectCause.OTHER, // disconnectCauseCode 496 false, // isConference 497 true, // isIncoming 498 1L, // creationTimeMillis 499 1000L, // ageMillis 500 TEL_PHONEHANDLE, // callHandle 501 mDefaultAccountHandle, // phoneAccountHandle 502 NO_VIDEO_STATE, // callVideoState 503 POST_DIAL_STRING, // postDialDigits 504 VIA_NUMBER_STRING, // viaNumber 505 null 506 ); 507 mCallLogManager.onCallStateChanged(fakeIncomingCall, CallState.ACTIVE, 508 CallState.DISCONNECTED); 509 510 // Incoming call using a phone account with multi user capability is inserted to all users 511 // except managed profile. 512 ContentValues insertedValues = verifyInsertionWithCapture(CURRENT_USER_ID); 513 assertEquals(insertedValues.getAsInteger(CallLog.Calls.TYPE), 514 Integer.valueOf(CallLog.Calls.INCOMING_TYPE)); 515 insertedValues = verifyInsertionWithCapture(OTHER_USER_ID); 516 assertEquals(insertedValues.getAsInteger(CallLog.Calls.TYPE), 517 Integer.valueOf(CallLog.Calls.INCOMING_TYPE)); 518 verifyNoInsertionInUser(MANAGED_USER_ID); 519 } 520 521 @MediumTest 522 @Test 523 public void testLogCallDirectionOutgoingWithMultiUserCapabilityFromManagedProfile() { 524 when(mMockPhoneAccountRegistrar.getPhoneAccountUnchecked(any(PhoneAccountHandle.class))) 525 .thenReturn(makeFakePhoneAccount(mManagedProfileAccountHandle, 526 PhoneAccount.CAPABILITY_MULTI_USER)); 527 Call fakeOutgoingCall = makeFakeCall( 528 DisconnectCause.OTHER, // disconnectCauseCode 529 false, // isConference 530 false, // isIncoming 531 1L, // creationTimeMillis 532 1000L, // ageMillis 533 TEL_PHONEHANDLE, // callHandle 534 mManagedProfileAccountHandle, // phoneAccountHandle 535 NO_VIDEO_STATE, // callVideoState 536 POST_DIAL_STRING, // postDialDigits 537 VIA_NUMBER_STRING, // viaNumber 538 UserHandle.of(MANAGED_USER_ID) 539 ); 540 mCallLogManager.onCallStateChanged(fakeOutgoingCall, CallState.ACTIVE, 541 CallState.DISCONNECTED); 542 543 // Outgoing call placed through work dialer should be inserted to managed profile only. 544 verifyNoInsertionInUser(CURRENT_USER_ID); 545 verifyNoInsertionInUser(OTHER_USER_ID); 546 ContentValues insertedValues = verifyInsertionWithCapture(MANAGED_USER_ID); 547 assertEquals(insertedValues.getAsInteger(CallLog.Calls.TYPE), 548 Integer.valueOf(CallLog.Calls.OUTGOING_TYPE)); 549 } 550 551 @MediumTest 552 @FlakyTest 553 @Test 554 public void testLogCallDirectionOutgoingFromManagedProfile() { 555 when(mMockPhoneAccountRegistrar.getPhoneAccountUnchecked(any(PhoneAccountHandle.class))) 556 .thenReturn(makeFakePhoneAccount(mManagedProfileAccountHandle, 0)); 557 Call fakeOutgoingCall = makeFakeCall( 558 DisconnectCause.OTHER, // disconnectCauseCode 559 false, // isConference 560 false, // isIncoming 561 1L, // creationTimeMillis 562 1000L, // ageMillis 563 TEL_PHONEHANDLE, // callHandle 564 mManagedProfileAccountHandle, // phoneAccountHandle 565 NO_VIDEO_STATE, // callVideoState 566 POST_DIAL_STRING, // postDialDigits 567 VIA_NUMBER_STRING, // viaNumber 568 UserHandle.of(MANAGED_USER_ID) 569 ); 570 mCallLogManager.onCallStateChanged(fakeOutgoingCall, CallState.ACTIVE, 571 CallState.DISCONNECTED); 572 573 // Outgoing call using phone account in managed profile should be inserted to managed 574 // profile only. 575 verifyNoInsertionInUser(CURRENT_USER_ID); 576 verifyNoInsertionInUser(OTHER_USER_ID); 577 ContentValues insertedValues = verifyInsertionWithCapture(MANAGED_USER_ID); 578 assertEquals(insertedValues.getAsInteger(CallLog.Calls.TYPE), 579 Integer.valueOf(CallLog.Calls.OUTGOING_TYPE)); 580 } 581 582 @MediumTest 583 @Test 584 public void testLogCallDirectionIngoingFromManagedProfile() { 585 when(mMockPhoneAccountRegistrar.getPhoneAccountUnchecked(any(PhoneAccountHandle.class))) 586 .thenReturn(makeFakePhoneAccount(mManagedProfileAccountHandle, 0)); 587 Call fakeOutgoingCall = makeFakeCall( 588 DisconnectCause.OTHER, // disconnectCauseCode 589 false, // isConference 590 true, // isIncoming 591 1L, // creationTimeMillis 592 1000L, // ageMillis 593 TEL_PHONEHANDLE, // callHandle 594 mManagedProfileAccountHandle, // phoneAccountHandle 595 NO_VIDEO_STATE, // callVideoState 596 POST_DIAL_STRING, // postDialDigits 597 VIA_NUMBER_STRING, // viaNumber 598 null 599 ); 600 mCallLogManager.onCallStateChanged(fakeOutgoingCall, CallState.ACTIVE, 601 CallState.DISCONNECTED); 602 603 // Incoming call using phone account in managed profile should be inserted to managed 604 // profile only. 605 verifyNoInsertionInUser(CURRENT_USER_ID); 606 verifyNoInsertionInUser(OTHER_USER_ID); 607 ContentValues insertedValues = verifyInsertionWithCapture(MANAGED_USER_ID); 608 assertEquals(insertedValues.getAsInteger(CallLog.Calls.TYPE), 609 Integer.valueOf(Calls.INCOMING_TYPE)); 610 } 611 612 /** 613 * Ensure call data usage is persisted to the call log when present in the call. 614 */ 615 @MediumTest 616 @Test 617 public void testLogCallDataUsageSet() { 618 when(mMockPhoneAccountRegistrar.getPhoneAccountUnchecked(any(PhoneAccountHandle.class))) 619 .thenReturn(makeFakePhoneAccount(mDefaultAccountHandle, CURRENT_USER_ID)); 620 Call fakeVideoCall = makeFakeCall( 621 DisconnectCause.OTHER, // disconnectCauseCode 622 false, // isConference 623 true, // isIncoming 624 1L, // creationTimeMillis 625 1000L, // ageMillis 626 TEL_PHONEHANDLE, // callHandle 627 mDefaultAccountHandle, // phoneAccountHandle 628 BIDIRECTIONAL_VIDEO_STATE, // callVideoState 629 POST_DIAL_STRING, // postDialDigits 630 VIA_NUMBER_STRING, // viaNumber 631 UserHandle.of(CURRENT_USER_ID), // initiatingUser 632 1000 // callDataUsage 633 ); 634 mCallLogManager.onCallStateChanged(fakeVideoCall, CallState.ACTIVE, CallState.DISCONNECTED); 635 ContentValues insertedValues = verifyInsertionWithCapture(CURRENT_USER_ID); 636 assertEquals(Long.valueOf(1000), insertedValues.getAsLong(CallLog.Calls.DATA_USAGE)); 637 } 638 639 /** 640 * Ensures call data usage is null in the call log when not set on the call. 641 */ 642 @MediumTest 643 @Test 644 public void testLogCallDataUsageNotSet() { 645 when(mMockPhoneAccountRegistrar.getPhoneAccountUnchecked(any(PhoneAccountHandle.class))) 646 .thenReturn(makeFakePhoneAccount(mDefaultAccountHandle, CURRENT_USER_ID)); 647 Call fakeVideoCall = makeFakeCall( 648 DisconnectCause.OTHER, // disconnectCauseCode 649 false, // isConference 650 true, // isIncoming 651 1L, // creationTimeMillis 652 1000L, // ageMillis 653 TEL_PHONEHANDLE, // callHandle 654 mDefaultAccountHandle, // phoneAccountHandle 655 BIDIRECTIONAL_VIDEO_STATE, // callVideoState 656 POST_DIAL_STRING, // postDialDigits 657 VIA_NUMBER_STRING, // viaNumber 658 UserHandle.of(CURRENT_USER_ID), // initiatingUser 659 Call.DATA_USAGE_NOT_SET // callDataUsage 660 ); 661 mCallLogManager.onCallStateChanged(fakeVideoCall, CallState.ACTIVE, CallState.DISCONNECTED); 662 ContentValues insertedValues = verifyInsertionWithCapture(CURRENT_USER_ID); 663 assertNull(insertedValues.getAsLong(CallLog.Calls.DATA_USAGE)); 664 } 665 666 /** 667 * Ensures missed self-managed calls are marked as read.. 668 */ 669 @MediumTest 670 @Test 671 public void testLogMissedSelfManaged() { 672 when(mMockPhoneAccountRegistrar.getPhoneAccountUnchecked(any(PhoneAccountHandle.class))) 673 .thenReturn(makeFakePhoneAccount(mDefaultAccountHandle, 674 PhoneAccount.CAPABILITY_SELF_MANAGED)); 675 Call fakeMissedCall = makeFakeCall( 676 DisconnectCause.MISSED, // disconnectCauseCode 677 false, // isConference 678 true, // isIncoming 679 1L, // creationTimeMillis 680 1000L, // ageMillis 681 TEL_PHONEHANDLE, // callHandle 682 mSelfManagedAccountHandle, // phoneAccountHandle 683 NO_VIDEO_STATE, // callVideoState 684 POST_DIAL_STRING, // postDialDigits 685 VIA_NUMBER_STRING, // viaNumber 686 UserHandle.of(CURRENT_USER_ID) 687 ); 688 when(fakeMissedCall.isSelfManaged()).thenReturn(true); 689 when(fakeMissedCall.isLoggedSelfManaged()).thenReturn(true); 690 when(fakeMissedCall.getHandoverState()).thenReturn(HandoverState.HANDOVER_NONE); 691 mCallLogManager.onCallStateChanged(fakeMissedCall, CallState.ACTIVE, 692 CallState.DISCONNECTED); 693 ContentValues insertedValues = verifyInsertionWithCapture(CURRENT_USER_ID); 694 assertEquals(1, insertedValues.getAsInteger(Calls.IS_READ).intValue()); 695 } 696 697 @SmallTest 698 @Test 699 public void testCountryIso_setCache() { 700 Country testCountry = new Country(TEST_ISO, Country.COUNTRY_SOURCE_LOCALE); 701 CountryDetector mockDetector = (CountryDetector) mContext.getSystemService( 702 Context.COUNTRY_DETECTOR); 703 when(mockDetector.detectCountry()).thenReturn(testCountry); 704 705 String resultIso = mCallLogManager.getCountryIso(); 706 707 verifyCountryIso(mockDetector, resultIso); 708 } 709 710 @SmallTest 711 @Test 712 public void testCountryIso_newCountryDetected() { 713 Country testCountry = new Country(TEST_ISO, Country.COUNTRY_SOURCE_LOCALE); 714 Country testCountry2 = new Country(TEST_ISO_2, Country.COUNTRY_SOURCE_LOCALE); 715 CountryDetector mockDetector = (CountryDetector) mContext.getSystemService( 716 Context.COUNTRY_DETECTOR); 717 when(mockDetector.detectCountry()).thenReturn(testCountry); 718 // Put TEST_ISO in the Cache 719 String resultIso = mCallLogManager.getCountryIso(); 720 ArgumentCaptor<CountryListener> captor = verifyCountryIso(mockDetector, resultIso); 721 722 // Change ISO to TEST_ISO_2 723 CountryListener listener = captor.getValue(); 724 listener.onCountryDetected(testCountry2); 725 726 String resultIso2 = mCallLogManager.getCountryIso(); 727 assertEquals(TEST_ISO_2, resultIso2); 728 } 729 730 private ArgumentCaptor<CountryListener> verifyCountryIso(CountryDetector mockDetector, 731 String resultIso) { 732 ArgumentCaptor<CountryListener> captor = ArgumentCaptor.forClass(CountryListener.class); 733 verify(mockDetector).addCountryListener(captor.capture(), any(Looper.class)); 734 assertEquals(TEST_ISO, resultIso); 735 return captor; 736 } 737 738 private void verifyNoInsertion() { 739 try { 740 Thread.sleep(TEST_TIMEOUT_MILLIS); 741 verify(mContentProvider, never()).insert(any(String.class), 742 any(Uri.class), any(ContentValues.class)); 743 } catch (android.os.RemoteException e) { 744 fail("Remote exception occurred during test execution"); 745 } catch (InterruptedException e) { 746 e.printStackTrace(); 747 } 748 } 749 750 751 private void verifyNoInsertionInUser(int userId) { 752 try { 753 Uri uri = ContentProvider.maybeAddUserId(CallLog.Calls.CONTENT_URI, userId); 754 Thread.sleep(TEST_TIMEOUT_MILLIS); 755 verify(getContentProviderForUser(userId), never()) 756 .insert(any(String.class), eq(uri), any(ContentValues.class)); 757 } catch (android.os.RemoteException e) { 758 fail("Remote exception occurred during test execution"); 759 } catch (InterruptedException e) { 760 e.printStackTrace(); 761 } 762 } 763 764 private ContentValues verifyInsertionWithCapture(int userId) { 765 ArgumentCaptor<ContentValues> captor = ArgumentCaptor.forClass(ContentValues.class); 766 try { 767 Uri uri = ContentProvider.maybeAddUserId(CallLog.Calls.CONTENT_URI, userId); 768 verify(getContentProviderForUser(userId), timeout(TEST_TIMEOUT_MILLIS).atLeastOnce()) 769 .insert(any(String.class), eq(uri), captor.capture()); 770 } catch (android.os.RemoteException e) { 771 fail("Remote exception occurred during test execution"); 772 } 773 774 return captor.getValue(); 775 } 776 777 private IContentProvider getContentProviderForUser(int userId) { 778 return mContext.getContentResolver().acquireProvider(userId + "@call_log"); 779 } 780 781 private Call makeFakeCall(int disconnectCauseCode, boolean isConference, boolean isIncoming, 782 long creationTimeMillis, long ageMillis, Uri callHandle, 783 PhoneAccountHandle phoneAccountHandle, int callVideoState, 784 String postDialDigits, String viaNumber, UserHandle initiatingUser) { 785 return makeFakeCall(disconnectCauseCode, isConference, isIncoming, creationTimeMillis, 786 ageMillis, callHandle, phoneAccountHandle, callVideoState, postDialDigits, 787 viaNumber, initiatingUser, Call.DATA_USAGE_NOT_SET); 788 } 789 790 private Call makeFakeCall(int disconnectCauseCode, boolean isConference, boolean isIncoming, 791 long creationTimeMillis, long ageMillis, Uri callHandle, 792 PhoneAccountHandle phoneAccountHandle, int callVideoState, 793 String postDialDigits, String viaNumber, UserHandle initiatingUser, 794 long callDataUsage) { 795 Call fakeCall = mock(Call.class); 796 when(fakeCall.getDisconnectCause()).thenReturn( 797 new DisconnectCause(disconnectCauseCode)); 798 when(fakeCall.isConference()).thenReturn(isConference); 799 when(fakeCall.isIncoming()).thenReturn(isIncoming); 800 when(fakeCall.getCreationTimeMillis()).thenReturn(creationTimeMillis); 801 when(fakeCall.getAgeMillis()).thenReturn(ageMillis); 802 when(fakeCall.getOriginalHandle()).thenReturn(callHandle); 803 when(fakeCall.getTargetPhoneAccount()).thenReturn(phoneAccountHandle); 804 when(fakeCall.getVideoStateHistory()).thenReturn(callVideoState); 805 when(fakeCall.getPostDialDigits()).thenReturn(postDialDigits); 806 when(fakeCall.getViaNumber()).thenReturn(viaNumber); 807 when(fakeCall.getInitiatingUser()).thenReturn(initiatingUser); 808 when(fakeCall.getCallDataUsage()).thenReturn(callDataUsage); 809 when(fakeCall.isEmergencyCall()).thenReturn( 810 phoneAccountHandle.equals(EMERGENCY_ACCT_HANDLE)); 811 return fakeCall; 812 } 813 814 private PhoneAccount makeFakePhoneAccount(PhoneAccountHandle phoneAccountHandle, 815 int capabilities) { 816 return PhoneAccount.builder(phoneAccountHandle, "testing") 817 .setCapabilities(capabilities).build(); 818 } 819 } 820