Home | History | Annotate | Download | only in tests
      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