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