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