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