1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16 17 package com.android.server.telecom.tests; 18 19 20 import android.content.ComponentName; 21 import android.content.ContentProvider; 22 import android.content.ContentValues; 23 import android.content.Context; 24 import android.content.IContentProvider; 25 import android.content.pm.UserInfo; 26 import android.location.Country; 27 import android.location.CountryDetector; 28 import android.location.CountryListener; 29 import android.net.Uri; 30 import android.os.Looper; 31 import android.os.UserHandle; 32 import android.os.UserManager; 33 import android.provider.CallLog; 34 import android.provider.CallLog.Calls; 35 import android.telecom.DisconnectCause; 36 import android.telecom.PhoneAccount; 37 import android.telecom.PhoneAccountHandle; 38 import android.telecom.VideoProfile; 39 import android.telephony.PhoneNumberUtils; 40 import android.test.suitebuilder.annotation.MediumTest; 41 import android.test.suitebuilder.annotation.SmallTest; 42 43 import com.android.server.telecom.Call; 44 import com.android.server.telecom.CallLogManager; 45 import com.android.server.telecom.CallState; 46 import com.android.server.telecom.MissedCallNotifier; 47 import com.android.server.telecom.PhoneAccountRegistrar; 48 import com.android.server.telecom.R; 49 import com.android.server.telecom.TelephonyUtil; 50 51 import static org.mockito.Matchers.any; 52 import static org.mockito.Matchers.anyString; 53 import static org.mockito.Matchers.eq; 54 import static org.mockito.Mockito.doAnswer; 55 import static org.mockito.Mockito.mock; 56 import static org.mockito.Mockito.timeout; 57 import static org.mockito.Mockito.verify; 58 import static org.mockito.Mockito.when; 59 60 import org.mockito.ArgumentCaptor; 61 import org.mockito.Mock; 62 import org.mockito.invocation.InvocationOnMock; 63 import org.mockito.stubbing.Answer; 64 65 import java.util.Arrays; 66 import java.util.Locale; 67 68 public 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 verify(mMissedCallNotifier).showMissedCallNotification(fakeMissedCall); 289 } 290 291 @MediumTest 292 public void testCreationTimeAndAge() { 293 when(mMockPhoneAccountRegistrar.getPhoneAccountUnchecked(any(PhoneAccountHandle.class))) 294 .thenReturn(makeFakePhoneAccount(mDefaultAccountHandle, CURRENT_USER_ID)); 295 long currentTime = System.currentTimeMillis(); 296 long duration = 1000L; 297 Call fakeCall = makeFakeCall( 298 DisconnectCause.OTHER, // disconnectCauseCode 299 false, // isConference 300 false, // isIncoming 301 currentTime, // creationTimeMillis 302 duration, // ageMillis 303 TEL_PHONEHANDLE, // callHandle 304 mDefaultAccountHandle, // phoneAccountHandle 305 NO_VIDEO_STATE, // callVideoState 306 POST_DIAL_STRING, // postDialDigits 307 VIA_NUMBER_STRING, // viaNumber 308 UserHandle.of(CURRENT_USER_ID) 309 ); 310 mCallLogManager.onCallStateChanged(fakeCall, CallState.ACTIVE, CallState.DISCONNECTED); 311 ContentValues insertedValues = verifyInsertionWithCapture(CURRENT_USER_ID); 312 assertEquals(insertedValues.getAsLong(CallLog.Calls.DATE), 313 Long.valueOf(currentTime)); 314 assertEquals(insertedValues.getAsLong(CallLog.Calls.DURATION), 315 Long.valueOf(duration / 1000)); 316 } 317 318 @MediumTest 319 public void testLogPhoneAccountId() { 320 when(mMockPhoneAccountRegistrar.getPhoneAccountUnchecked(any(PhoneAccountHandle.class))) 321 .thenReturn(makeFakePhoneAccount(mDefaultAccountHandle, CURRENT_USER_ID)); 322 Call fakeCall = makeFakeCall( 323 DisconnectCause.OTHER, // disconnectCauseCode 324 false, // isConference 325 true, // isIncoming 326 1L, // creationTimeMillis 327 1000L, // ageMillis 328 TEL_PHONEHANDLE, // callHandle 329 mDefaultAccountHandle, // phoneAccountHandle 330 NO_VIDEO_STATE, // callVideoState 331 POST_DIAL_STRING, // postDialDigits 332 VIA_NUMBER_STRING, // viaNumber 333 UserHandle.of(CURRENT_USER_ID) 334 ); 335 mCallLogManager.onCallStateChanged(fakeCall, CallState.ACTIVE, CallState.DISCONNECTED); 336 ContentValues insertedValues = verifyInsertionWithCapture(CURRENT_USER_ID); 337 assertEquals(insertedValues.getAsString(CallLog.Calls.PHONE_ACCOUNT_ID), 338 TEST_PHONE_ACCOUNT_ID); 339 } 340 341 @MediumTest 342 public void testLogCorrectPhoneNumber() { 343 when(mMockPhoneAccountRegistrar.getPhoneAccountUnchecked(any(PhoneAccountHandle.class))) 344 .thenReturn(makeFakePhoneAccount(mDefaultAccountHandle, CURRENT_USER_ID)); 345 Call fakeCall = makeFakeCall( 346 DisconnectCause.OTHER, // disconnectCauseCode 347 false, // isConference 348 true, // isIncoming 349 1L, // creationTimeMillis 350 1000L, // ageMillis 351 TEL_PHONEHANDLE, // callHandle 352 mDefaultAccountHandle, // phoneAccountHandle 353 NO_VIDEO_STATE, // callVideoState 354 POST_DIAL_STRING, // postDialDigits 355 VIA_NUMBER_STRING, // viaNumber 356 UserHandle.of(CURRENT_USER_ID) 357 ); 358 mCallLogManager.onCallStateChanged(fakeCall, CallState.ACTIVE, CallState.DISCONNECTED); 359 ContentValues insertedValues = verifyInsertionWithCapture(CURRENT_USER_ID); 360 assertEquals(insertedValues.getAsString(CallLog.Calls.NUMBER), 361 TEL_PHONEHANDLE.getSchemeSpecificPart()); 362 assertEquals(insertedValues.getAsString(CallLog.Calls.POST_DIAL_DIGITS), POST_DIAL_STRING); 363 String expectedNumber = PhoneNumberUtils.formatNumber(VIA_NUMBER_STRING, "US"); 364 assertEquals(insertedValues.getAsString(Calls.VIA_NUMBER), expectedNumber); 365 } 366 367 @MediumTest 368 public void testLogCallVideoFeatures() { 369 when(mMockPhoneAccountRegistrar.getPhoneAccountUnchecked(any(PhoneAccountHandle.class))) 370 .thenReturn(makeFakePhoneAccount(mDefaultAccountHandle, CURRENT_USER_ID)); 371 Call fakeVideoCall = makeFakeCall( 372 DisconnectCause.OTHER, // disconnectCauseCode 373 false, // isConference 374 true, // isIncoming 375 1L, // creationTimeMillis 376 1000L, // ageMillis 377 TEL_PHONEHANDLE, // callHandle 378 mDefaultAccountHandle, // phoneAccountHandle 379 BIDIRECTIONAL_VIDEO_STATE, // callVideoState 380 POST_DIAL_STRING, // postDialDigits 381 VIA_NUMBER_STRING, // viaNumber 382 UserHandle.of(CURRENT_USER_ID) 383 ); 384 mCallLogManager.onCallStateChanged(fakeVideoCall, CallState.ACTIVE, CallState.DISCONNECTED); 385 ContentValues insertedValues = verifyInsertionWithCapture(CURRENT_USER_ID); 386 assertTrue((insertedValues.getAsInteger(CallLog.Calls.FEATURES) 387 & CallLog.Calls.FEATURES_VIDEO) == CallLog.Calls.FEATURES_VIDEO); 388 } 389 390 @MediumTest 391 public void testLogCallDirectionOutgoingWithMultiUserCapability() { 392 when(mMockPhoneAccountRegistrar.getPhoneAccountUnchecked(any(PhoneAccountHandle.class))) 393 .thenReturn(makeFakePhoneAccount(mOtherUserAccountHandle, 394 PhoneAccount.CAPABILITY_MULTI_USER)); 395 Call fakeOutgoingCall = makeFakeCall( 396 DisconnectCause.OTHER, // disconnectCauseCode 397 false, // isConference 398 false, // isIncoming 399 1L, // creationTimeMillis 400 1000L, // ageMillis 401 TEL_PHONEHANDLE, // callHandle 402 mDefaultAccountHandle, // phoneAccountHandle 403 NO_VIDEO_STATE, // callVideoState 404 POST_DIAL_STRING, // postDialDigits 405 VIA_NUMBER_STRING, // viaNumber 406 UserHandle.of(CURRENT_USER_ID) 407 ); 408 mCallLogManager.onCallStateChanged(fakeOutgoingCall, CallState.ACTIVE, 409 CallState.DISCONNECTED); 410 411 // Outgoing call placed through a phone account with multi user capability is inserted to 412 // all users except managed profile. 413 ContentValues insertedValues = verifyInsertionWithCapture(CURRENT_USER_ID); 414 assertEquals(insertedValues.getAsInteger(CallLog.Calls.TYPE), 415 Integer.valueOf(CallLog.Calls.OUTGOING_TYPE)); 416 insertedValues = verifyInsertionWithCapture(OTHER_USER_ID); 417 assertEquals(insertedValues.getAsInteger(CallLog.Calls.TYPE), 418 Integer.valueOf(CallLog.Calls.OUTGOING_TYPE)); 419 verifyNoInsertionInUser(MANAGED_USER_ID); 420 } 421 422 @MediumTest 423 public void testLogCallDirectionIncomingWithMultiUserCapability() { 424 when(mMockPhoneAccountRegistrar.getPhoneAccountUnchecked(any(PhoneAccountHandle.class))) 425 .thenReturn(makeFakePhoneAccount(mOtherUserAccountHandle, 426 PhoneAccount.CAPABILITY_MULTI_USER)); 427 Call fakeIncomingCall = makeFakeCall( 428 DisconnectCause.OTHER, // disconnectCauseCode 429 false, // isConference 430 true, // isIncoming 431 1L, // creationTimeMillis 432 1000L, // ageMillis 433 TEL_PHONEHANDLE, // callHandle 434 mDefaultAccountHandle, // phoneAccountHandle 435 NO_VIDEO_STATE, // callVideoState 436 POST_DIAL_STRING, // postDialDigits 437 VIA_NUMBER_STRING, // viaNumber 438 null 439 ); 440 mCallLogManager.onCallStateChanged(fakeIncomingCall, CallState.ACTIVE, 441 CallState.DISCONNECTED); 442 443 // Incoming call using a phone account with multi user capability is inserted to all users 444 // except managed profile. 445 ContentValues insertedValues = verifyInsertionWithCapture(CURRENT_USER_ID); 446 assertEquals(insertedValues.getAsInteger(CallLog.Calls.TYPE), 447 Integer.valueOf(CallLog.Calls.INCOMING_TYPE)); 448 insertedValues = verifyInsertionWithCapture(OTHER_USER_ID); 449 assertEquals(insertedValues.getAsInteger(CallLog.Calls.TYPE), 450 Integer.valueOf(CallLog.Calls.INCOMING_TYPE)); 451 verifyNoInsertionInUser(MANAGED_USER_ID); 452 } 453 454 @MediumTest 455 public void testLogCallDirectionOutgoingWithMultiUserCapabilityFromManagedProfile() { 456 when(mMockPhoneAccountRegistrar.getPhoneAccountUnchecked(any(PhoneAccountHandle.class))) 457 .thenReturn(makeFakePhoneAccount(mManagedProfileAccountHandle, 458 PhoneAccount.CAPABILITY_MULTI_USER)); 459 Call fakeOutgoingCall = makeFakeCall( 460 DisconnectCause.OTHER, // disconnectCauseCode 461 false, // isConference 462 false, // isIncoming 463 1L, // creationTimeMillis 464 1000L, // ageMillis 465 TEL_PHONEHANDLE, // callHandle 466 mManagedProfileAccountHandle, // phoneAccountHandle 467 NO_VIDEO_STATE, // callVideoState 468 POST_DIAL_STRING, // postDialDigits 469 VIA_NUMBER_STRING, // viaNumber 470 UserHandle.of(MANAGED_USER_ID) 471 ); 472 mCallLogManager.onCallStateChanged(fakeOutgoingCall, CallState.ACTIVE, 473 CallState.DISCONNECTED); 474 475 // Outgoing call placed through work dialer should be inserted to managed profile only. 476 verifyNoInsertionInUser(CURRENT_USER_ID); 477 verifyNoInsertionInUser(OTHER_USER_ID); 478 ContentValues insertedValues = verifyInsertionWithCapture(MANAGED_USER_ID); 479 assertEquals(insertedValues.getAsInteger(CallLog.Calls.TYPE), 480 Integer.valueOf(CallLog.Calls.OUTGOING_TYPE)); 481 } 482 483 @MediumTest 484 public void testLogCallDirectionOutgoingFromManagedProfile() { 485 when(mMockPhoneAccountRegistrar.getPhoneAccountUnchecked(any(PhoneAccountHandle.class))) 486 .thenReturn(makeFakePhoneAccount(mManagedProfileAccountHandle, 0)); 487 Call fakeOutgoingCall = makeFakeCall( 488 DisconnectCause.OTHER, // disconnectCauseCode 489 false, // isConference 490 false, // isIncoming 491 1L, // creationTimeMillis 492 1000L, // ageMillis 493 TEL_PHONEHANDLE, // callHandle 494 mManagedProfileAccountHandle, // phoneAccountHandle 495 NO_VIDEO_STATE, // callVideoState 496 POST_DIAL_STRING, // postDialDigits 497 VIA_NUMBER_STRING, // viaNumber 498 UserHandle.of(MANAGED_USER_ID) 499 ); 500 mCallLogManager.onCallStateChanged(fakeOutgoingCall, CallState.ACTIVE, 501 CallState.DISCONNECTED); 502 503 // Outgoing call using phone account in managed profile should be inserted to managed 504 // profile only. 505 verifyNoInsertionInUser(CURRENT_USER_ID); 506 verifyNoInsertionInUser(OTHER_USER_ID); 507 ContentValues insertedValues = verifyInsertionWithCapture(MANAGED_USER_ID); 508 assertEquals(insertedValues.getAsInteger(CallLog.Calls.TYPE), 509 Integer.valueOf(CallLog.Calls.OUTGOING_TYPE)); 510 } 511 512 @MediumTest 513 public void testLogCallDirectionIngoingFromManagedProfile() { 514 when(mMockPhoneAccountRegistrar.getPhoneAccountUnchecked(any(PhoneAccountHandle.class))) 515 .thenReturn(makeFakePhoneAccount(mManagedProfileAccountHandle, 0)); 516 Call fakeOutgoingCall = makeFakeCall( 517 DisconnectCause.OTHER, // disconnectCauseCode 518 false, // isConference 519 true, // isIncoming 520 1L, // creationTimeMillis 521 1000L, // ageMillis 522 TEL_PHONEHANDLE, // callHandle 523 mManagedProfileAccountHandle, // phoneAccountHandle 524 NO_VIDEO_STATE, // callVideoState 525 POST_DIAL_STRING, // postDialDigits 526 VIA_NUMBER_STRING, // viaNumber 527 null 528 ); 529 mCallLogManager.onCallStateChanged(fakeOutgoingCall, CallState.ACTIVE, 530 CallState.DISCONNECTED); 531 532 // Incoming call using phone account in managed profile should be inserted to managed 533 // profile only. 534 verifyNoInsertionInUser(CURRENT_USER_ID); 535 verifyNoInsertionInUser(OTHER_USER_ID); 536 ContentValues insertedValues = verifyInsertionWithCapture(MANAGED_USER_ID); 537 assertEquals(insertedValues.getAsInteger(CallLog.Calls.TYPE), 538 Integer.valueOf(Calls.INCOMING_TYPE)); 539 } 540 541 /** 542 * Ensure call data usage is persisted to the call log when present in the call. 543 */ 544 @MediumTest 545 public void testLogCallDataUsageSet() { 546 when(mMockPhoneAccountRegistrar.getPhoneAccountUnchecked(any(PhoneAccountHandle.class))) 547 .thenReturn(makeFakePhoneAccount(mDefaultAccountHandle, CURRENT_USER_ID)); 548 Call fakeVideoCall = makeFakeCall( 549 DisconnectCause.OTHER, // disconnectCauseCode 550 false, // isConference 551 true, // isIncoming 552 1L, // creationTimeMillis 553 1000L, // ageMillis 554 TEL_PHONEHANDLE, // callHandle 555 mDefaultAccountHandle, // phoneAccountHandle 556 BIDIRECTIONAL_VIDEO_STATE, // callVideoState 557 POST_DIAL_STRING, // postDialDigits 558 VIA_NUMBER_STRING, // viaNumber 559 UserHandle.of(CURRENT_USER_ID), // initiatingUser 560 1000 // callDataUsage 561 ); 562 mCallLogManager.onCallStateChanged(fakeVideoCall, CallState.ACTIVE, CallState.DISCONNECTED); 563 ContentValues insertedValues = verifyInsertionWithCapture(CURRENT_USER_ID); 564 assertEquals(Long.valueOf(1000), insertedValues.getAsLong(CallLog.Calls.DATA_USAGE)); 565 } 566 567 /** 568 * Ensures call data usage is null in the call log when not set on the call. 569 */ 570 @MediumTest 571 public void testLogCallDataUsageNotSet() { 572 when(mMockPhoneAccountRegistrar.getPhoneAccountUnchecked(any(PhoneAccountHandle.class))) 573 .thenReturn(makeFakePhoneAccount(mDefaultAccountHandle, CURRENT_USER_ID)); 574 Call fakeVideoCall = makeFakeCall( 575 DisconnectCause.OTHER, // disconnectCauseCode 576 false, // isConference 577 true, // isIncoming 578 1L, // creationTimeMillis 579 1000L, // ageMillis 580 TEL_PHONEHANDLE, // callHandle 581 mDefaultAccountHandle, // phoneAccountHandle 582 BIDIRECTIONAL_VIDEO_STATE, // callVideoState 583 POST_DIAL_STRING, // postDialDigits 584 VIA_NUMBER_STRING, // viaNumber 585 UserHandle.of(CURRENT_USER_ID), // initiatingUser 586 Call.DATA_USAGE_NOT_SET // callDataUsage 587 ); 588 mCallLogManager.onCallStateChanged(fakeVideoCall, CallState.ACTIVE, CallState.DISCONNECTED); 589 ContentValues insertedValues = verifyInsertionWithCapture(CURRENT_USER_ID); 590 assertNull(insertedValues.getAsLong(CallLog.Calls.DATA_USAGE)); 591 } 592 593 @SmallTest 594 public void testCountryIso_setCache() { 595 Country testCountry = new Country(TEST_ISO, Country.COUNTRY_SOURCE_LOCALE); 596 CountryDetector mockDetector = (CountryDetector) mContext.getSystemService( 597 Context.COUNTRY_DETECTOR); 598 when(mockDetector.detectCountry()).thenReturn(testCountry); 599 600 String resultIso = mCallLogManager.getCountryIso(); 601 602 verifyCountryIso(mockDetector, resultIso); 603 } 604 605 @SmallTest 606 public void testCountryIso_newCountryDetected() { 607 Country testCountry = new Country(TEST_ISO, Country.COUNTRY_SOURCE_LOCALE); 608 Country testCountry2 = new Country(TEST_ISO_2, Country.COUNTRY_SOURCE_LOCALE); 609 CountryDetector mockDetector = (CountryDetector) mContext.getSystemService( 610 Context.COUNTRY_DETECTOR); 611 when(mockDetector.detectCountry()).thenReturn(testCountry); 612 // Put TEST_ISO in the Cache 613 String resultIso = mCallLogManager.getCountryIso(); 614 ArgumentCaptor<CountryListener> captor = verifyCountryIso(mockDetector, resultIso); 615 616 // Change ISO to TEST_ISO_2 617 CountryListener listener = captor.getValue(); 618 listener.onCountryDetected(testCountry2); 619 620 String resultIso2 = mCallLogManager.getCountryIso(); 621 assertEquals(TEST_ISO_2, resultIso2); 622 } 623 624 private ArgumentCaptor<CountryListener> verifyCountryIso(CountryDetector mockDetector, 625 String resultIso) { 626 ArgumentCaptor<CountryListener> captor = ArgumentCaptor.forClass(CountryListener.class); 627 verify(mockDetector).addCountryListener(captor.capture(), any(Looper.class)); 628 assertEquals(TEST_ISO, resultIso); 629 return captor; 630 } 631 632 private void verifyNoInsertion() { 633 try { 634 verify(mContentProvider, timeout(TEST_TIMEOUT_MILLIS).never()).insert(any(String.class), 635 any(Uri.class), any(ContentValues.class)); 636 } catch (android.os.RemoteException e) { 637 fail("Remote exception occurred during test execution"); 638 } 639 } 640 641 642 private void verifyNoInsertionInUser(int userId) { 643 try { 644 Uri uri = ContentProvider.maybeAddUserId(CallLog.Calls.CONTENT_URI, userId); 645 verify(getContentProviderForUser(userId), timeout(TEST_TIMEOUT_MILLIS).never()) 646 .insert(any(String.class), eq(uri), any(ContentValues.class)); 647 } catch (android.os.RemoteException e) { 648 fail("Remote exception occurred during test execution"); 649 } 650 } 651 652 private ContentValues verifyInsertionWithCapture(int userId) { 653 ArgumentCaptor<ContentValues> captor = ArgumentCaptor.forClass(ContentValues.class); 654 try { 655 Uri uri = ContentProvider.maybeAddUserId(CallLog.Calls.CONTENT_URI, userId); 656 verify(getContentProviderForUser(userId), timeout(TEST_TIMEOUT_MILLIS).atLeastOnce()) 657 .insert(any(String.class), eq(uri), captor.capture()); 658 } catch (android.os.RemoteException e) { 659 fail("Remote exception occurred during test execution"); 660 } 661 662 return captor.getValue(); 663 } 664 665 private IContentProvider getContentProviderForUser(int userId) { 666 return mContext.getContentResolver().acquireProvider(userId + "@call_log"); 667 } 668 669 private Call makeFakeCall(int disconnectCauseCode, boolean isConference, boolean isIncoming, 670 long creationTimeMillis, long ageMillis, Uri callHandle, 671 PhoneAccountHandle phoneAccountHandle, int callVideoState, 672 String postDialDigits, String viaNumber, UserHandle initiatingUser) { 673 return makeFakeCall(disconnectCauseCode, isConference, isIncoming, creationTimeMillis, 674 ageMillis, callHandle, phoneAccountHandle, callVideoState, postDialDigits, 675 viaNumber, initiatingUser, Call.DATA_USAGE_NOT_SET); 676 } 677 678 private Call makeFakeCall(int disconnectCauseCode, boolean isConference, boolean isIncoming, 679 long creationTimeMillis, long ageMillis, Uri callHandle, 680 PhoneAccountHandle phoneAccountHandle, int callVideoState, 681 String postDialDigits, String viaNumber, UserHandle initiatingUser, 682 long callDataUsage) { 683 Call fakeCall = mock(Call.class); 684 when(fakeCall.getDisconnectCause()).thenReturn( 685 new DisconnectCause(disconnectCauseCode)); 686 when(fakeCall.isConference()).thenReturn(isConference); 687 when(fakeCall.isIncoming()).thenReturn(isIncoming); 688 when(fakeCall.getCreationTimeMillis()).thenReturn(creationTimeMillis); 689 when(fakeCall.getAgeMillis()).thenReturn(ageMillis); 690 when(fakeCall.getOriginalHandle()).thenReturn(callHandle); 691 when(fakeCall.getTargetPhoneAccount()).thenReturn(phoneAccountHandle); 692 when(fakeCall.getVideoStateHistory()).thenReturn(callVideoState); 693 when(fakeCall.getPostDialDigits()).thenReturn(postDialDigits); 694 when(fakeCall.getViaNumber()).thenReturn(viaNumber); 695 when(fakeCall.getInitiatingUser()).thenReturn(initiatingUser); 696 when(fakeCall.getCallDataUsage()).thenReturn(callDataUsage); 697 return fakeCall; 698 } 699 700 private PhoneAccount makeFakePhoneAccount(PhoneAccountHandle phoneAccountHandle, 701 int capabilities) { 702 return PhoneAccount.builder(phoneAccountHandle, "testing") 703 .setCapabilities(capabilities).build(); 704 } 705 } 706