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.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