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