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