• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.calllogbackup;
18 
19 import static org.mockito.ArgumentMatchers.any;
20 import static org.mockito.ArgumentMatchers.anyInt;
21 import static org.mockito.Mockito.verify;
22 import static org.mockito.Mockito.when;
23 import static org.mockito.Mockito.eq;
24 
25 import android.app.backup.BackupDataOutput;
26 import android.content.Context;
27 import android.database.Cursor;
28 import android.provider.CallLog;
29 import android.test.AndroidTestCase;
30 import android.test.suitebuilder.annotation.SmallTest;
31 
32 import androidx.test.InstrumentationRegistry;
33 
34 import com.android.calllogbackup.CallLogBackupAgent.Call;
35 import com.android.calllogbackup.CallLogBackupAgent.CallLogBackupState;
36 
37 import org.mockito.InOrder;
38 import org.mockito.Matchers;
39 import org.mockito.Mock;
40 import org.mockito.Mockito;
41 import org.mockito.MockitoAnnotations;
42 
43 import java.io.DataInput;
44 import java.io.DataOutput;
45 import java.io.EOFException;
46 import java.io.IOException;
47 import java.util.HashMap;
48 import java.util.LinkedList;
49 import java.util.List;
50 import java.util.Map;
51 import java.util.TreeSet;
52 
53 /**
54  * Test cases for {@link com.android.providers.contacts.CallLogBackupAgent}
55  */
56 @SmallTest
57 public class CallLogBackupAgentTest extends AndroidTestCase {
58     static final String TELEPHONY_COMPONENT
59             = "com.android.phone/com.android.services.telephony.TelephonyConnectionService";
60     static final String TEST_PHONE_ACCOUNT_HANDLE_SUB_ID = "666";
61     static final int TEST_PHONE_ACCOUNT_HANDLE_SUB_ID_INT = 666;
62     static final String TEST_PHONE_ACCOUNT_HANDLE_ICC_ID = "891004234814455936F";
63 
64     public int backupRestoreLoggerSuccessCount = 0;
65     public int backupRestoreLoggerFailCount = 0;
66 
67     @Mock DataInput mDataInput;
68     @Mock DataOutput mDataOutput;
69     @Mock BackupDataOutput mBackupDataOutput;
70     @Mock Cursor mCursor;
71 
72     private CallLogBackupAgent.BackupRestoreEventLoggerProxy mBackupRestoreEventLoggerProxy =
73             new CallLogBackupAgent.BackupRestoreEventLoggerProxy() {
74         @Override
75         public void logItemsBackedUp(String dataType, int count) {
76             backupRestoreLoggerSuccessCount += count;
77         }
78 
79         @Override
80         public void logItemsBackupFailed(String dataType, int count, String error) {
81             backupRestoreLoggerFailCount += count;
82         }
83 
84         @Override
85         public void logItemsRestored(String dataType, int count) {
86             backupRestoreLoggerSuccessCount += count;
87         }
88 
89         @Override
90         public void logItemsRestoreFailed(String dataType, int count, String error) {
91             backupRestoreLoggerFailCount += count;
92         }
93     };
94 
95     CallLogBackupAgent mCallLogBackupAgent;
96 
97     MockitoHelper mMockitoHelper = new MockitoHelper();
98 
99     @Override
setUp()100     public void setUp() throws Exception {
101         super.setUp();
102 
103         mMockitoHelper.setUp(getClass());
104         // Since we're testing a system app, AppDataDirGuesser doesn't find our
105         // cache dir, so set it explicitly.
106         System.setProperty("dexmaker.dexcache", getContext().getCacheDir().toString());
107         MockitoAnnotations.initMocks(this);
108 
109         mCallLogBackupAgent = new CallLogBackupAgent();
110         mCallLogBackupAgent.setBackupRestoreEventLoggerProxy(mBackupRestoreEventLoggerProxy);
111     }
112 
113     @Override
tearDown()114     public void tearDown() throws Exception {
115         mMockitoHelper.tearDown();
116     }
117 
118     @Override
getTestContext()119     public Context getTestContext() {
120         return InstrumentationRegistry.getContext();
121     }
122 
testReadState_NoCall()123     public void testReadState_NoCall() throws Exception {
124         when(mDataInput.readInt()).thenThrow(new EOFException());
125 
126         CallLogBackupState state = mCallLogBackupAgent.readState(mDataInput);
127 
128         assertEquals(state.version, CallLogBackupAgent.VERSION_NO_PREVIOUS_STATE);
129         assertEquals(state.callIds.size(), 0);
130     }
131 
testReadState_OneCall()132     public void testReadState_OneCall() throws Exception {
133         when(mDataInput.readInt()).thenReturn(
134                 1 /* version */,
135                 1 /* size */,
136                 101 /* call-ID */ );
137 
138         CallLogBackupState state = mCallLogBackupAgent.readState(mDataInput);
139 
140         assertEquals(1, state.version);
141         assertEquals(1, state.callIds.size());
142         assertTrue(state.callIds.contains(101));
143     }
144 
testReadState_MultipleCalls()145     public void testReadState_MultipleCalls() throws Exception {
146         when(mDataInput.readInt()).thenReturn(
147                 1 /* version */,
148                 2 /* size */,
149                 101 /* call-ID */,
150                 102 /* call-ID */);
151 
152         CallLogBackupState state = mCallLogBackupAgent.readState(mDataInput);
153 
154         assertEquals(1, state.version);
155         assertEquals(2, state.callIds.size());
156         assertTrue(state.callIds.contains(101));
157         assertTrue(state.callIds.contains(102));
158     }
159 
testWriteState_NoCalls()160     public void testWriteState_NoCalls() throws Exception {
161         CallLogBackupState state = new CallLogBackupState();
162         state.version = CallLogBackupAgent.VERSION;
163         state.callIds = new TreeSet<>();
164 
165         mCallLogBackupAgent.writeState(mDataOutput, state);
166 
167         InOrder inOrder = Mockito.inOrder(mDataOutput);
168         inOrder.verify(mDataOutput).writeInt(CallLogBackupAgent.VERSION);
169         inOrder.verify(mDataOutput).writeInt(0 /* size */);
170     }
171 
testWriteState_OneCall()172     public void testWriteState_OneCall() throws Exception {
173         CallLogBackupState state = new CallLogBackupState();
174         state.version = CallLogBackupAgent.VERSION;
175         state.callIds = new TreeSet<>();
176         state.callIds.add(101);
177 
178         mCallLogBackupAgent.writeState(mDataOutput, state);
179 
180         InOrder inOrder = Mockito.inOrder(mDataOutput);
181         inOrder.verify(mDataOutput).writeInt(CallLogBackupAgent.VERSION);
182         inOrder.verify(mDataOutput).writeInt(1);
183         inOrder.verify(mDataOutput).writeInt(101 /* call-ID */);
184     }
185 
testWriteState_MultipleCalls()186     public void testWriteState_MultipleCalls() throws Exception {
187         CallLogBackupState state = new CallLogBackupState();
188         state.version = CallLogBackupAgent.VERSION;
189         state.callIds = new TreeSet<>();
190         state.callIds.add(101);
191         state.callIds.add(102);
192         state.callIds.add(103);
193 
194         mCallLogBackupAgent.writeState(mDataOutput, state);
195 
196         InOrder inOrder = Mockito.inOrder(mDataOutput);
197         inOrder.verify(mDataOutput).writeInt(CallLogBackupAgent.VERSION);
198         inOrder.verify(mDataOutput).writeInt(3 /* size */);
199         inOrder.verify(mDataOutput).writeInt(101 /* call-ID */);
200         inOrder.verify(mDataOutput).writeInt(102 /* call-ID */);
201         inOrder.verify(mDataOutput).writeInt(103 /* call-ID */);
202     }
203 
testRunBackup_NoCalls()204     public void testRunBackup_NoCalls() throws Exception {
205         CallLogBackupState state = new CallLogBackupState();
206         state.version = CallLogBackupAgent.VERSION;
207         state.callIds = new TreeSet<>();
208         List<Call> calls = new LinkedList<>();
209 
210         mCallLogBackupAgent.runBackup(state, mBackupDataOutput, calls);
211 
212         // Ensure the {@link BackupRestoreEventLogger} is not notified as no calls were backed up:
213         assertEquals(backupRestoreLoggerSuccessCount, 0);
214         assertEquals(backupRestoreLoggerFailCount, 0);
215 
216         Mockito.verifyNoMoreInteractions(mBackupDataOutput);
217     }
218 
testRunBackup_OneNewCall_ErrorAddingCall()219     public void testRunBackup_OneNewCall_ErrorAddingCall() throws Exception {
220         CallLogBackupState state = new CallLogBackupState();
221         state.version = CallLogBackupAgent.VERSION;
222         state.callIds = new TreeSet<>();
223         List<Call> calls = new LinkedList<>();
224         calls.add(makeCall(101, 0L, 0L, "555-5555"));
225 
226         // Throw an exception when the call is added to the backup:
227         when(mBackupDataOutput.writeEntityData(any(byte[].class), anyInt()))
228                 .thenThrow(IOException.class);
229         mCallLogBackupAgent.runBackup(state, mBackupDataOutput, calls);
230 
231         // Ensure the {@link BackupRestoreEventLogger} is informed of the failed backed up call:
232         assertEquals(backupRestoreLoggerSuccessCount, 0);
233         assertEquals(backupRestoreLoggerFailCount, 1);
234     }
235 
testRunBackup_OneNewCall_NullBackupDataOutput()236     public void testRunBackup_OneNewCall_NullBackupDataOutput() throws Exception {
237         CallLogBackupState state = new CallLogBackupState();
238         state.version = CallLogBackupAgent.VERSION;
239         state.callIds = new TreeSet<>();
240         List<Call> calls = new LinkedList<>();
241         calls.add(makeCall(101, 0L, 0L, "555-5555"));
242 
243         // Invoke runBackup() with a null value for BackupDataOutput causing an exception:
244         mCallLogBackupAgent.runBackup(state, null, calls);
245 
246         // Ensure the {@link BackupRestoreEventLogger} is informed of the failed backed up call:
247         assertEquals(backupRestoreLoggerSuccessCount, 0);
248         assertEquals(backupRestoreLoggerFailCount, 1);
249     }
250 
testRunBackup_OneNewCall()251     public void testRunBackup_OneNewCall() throws Exception {
252         CallLogBackupState state = new CallLogBackupState();
253         state.version = CallLogBackupAgent.VERSION;
254         state.callIds = new TreeSet<>();
255         List<Call> calls = new LinkedList<>();
256         calls.add(makeCall(101, 0L, 0L, "555-5555"));
257         mCallLogBackupAgent.runBackup(state, mBackupDataOutput, calls);
258 
259         // Ensure the {@link BackupRestoreEventLogger} is informed of the backed up call:
260         assertEquals(backupRestoreLoggerSuccessCount, 1);
261         assertEquals(backupRestoreLoggerFailCount, 0);
262 
263         verify(mBackupDataOutput).writeEntityHeader(eq("101"), Matchers.anyInt());
264         verify(mBackupDataOutput).writeEntityData((byte[]) Matchers.any(), Matchers.anyInt());
265     }
266 
267     /*
268         Test PhoneAccountHandle Migration process during back up
269      */
testReadCallFromCursorForPhoneAccountMigrationBackup()270     public void testReadCallFromCursorForPhoneAccountMigrationBackup() throws Exception {
271         Map<Integer, String> subscriptionInfoMap = new HashMap<>();
272         subscriptionInfoMap.put(TEST_PHONE_ACCOUNT_HANDLE_SUB_ID_INT,
273                 TEST_PHONE_ACCOUNT_HANDLE_ICC_ID);
274         mCallLogBackupAgent.mSubscriptionInfoMap = subscriptionInfoMap;
275 
276         // Mock telephony component name and expect the Sub ID is converted to Icc ID
277         // and the pending status is 1 when backup
278         mockCursor(mCursor, true);
279         Call call = mCallLogBackupAgent.readCallFromCursor(mCursor);
280         assertEquals(TEST_PHONE_ACCOUNT_HANDLE_ICC_ID, call.accountId);
281         assertEquals(1, call.isPhoneAccountMigrationPending);
282 
283         // Mock non-telephony component name and expect the Sub ID not converted to Icc ID
284         // and pending status is 0 when backup.
285         mockCursor(mCursor, false);
286         call = mCallLogBackupAgent.readCallFromCursor(mCursor);
287         assertEquals(TEST_PHONE_ACCOUNT_HANDLE_SUB_ID, call.accountId);
288         assertEquals(0, call.isPhoneAccountMigrationPending);
289     }
290 
testReadCallFromCursor_WithNullAccountComponentName()291     public void testReadCallFromCursor_WithNullAccountComponentName() throws Exception {
292         testReadCallFromCursor_WithNullField(CallLog.Calls.PHONE_ACCOUNT_COMPONENT_NAME);
293     }
294 
testReadCallFromCursor_WithNullNumber()295     public void testReadCallFromCursor_WithNullNumber() throws Exception {
296         testReadCallFromCursor_WithNullField(CallLog.Calls.NUMBER);
297     }
298 
testReadCallFromCursor_WithNullPostDialDigits()299     public void testReadCallFromCursor_WithNullPostDialDigits() throws Exception {
300         testReadCallFromCursor_WithNullField(CallLog.Calls.POST_DIAL_DIGITS);
301     }
302 
testReadCallFromCursor_WithNullViaNumber()303     public void testReadCallFromCursor_WithNullViaNumber() throws Exception {
304         testReadCallFromCursor_WithNullField(CallLog.Calls.VIA_NUMBER);
305     }
306 
testReadCallFromCursor_WithNullPhoneAccountId()307     public void testReadCallFromCursor_WithNullPhoneAccountId() throws Exception {
308         testReadCallFromCursor_WithNullField(CallLog.Calls.PHONE_ACCOUNT_ID);
309     }
310 
testReadCallFromCursor_WithNullCallAccountAddress()311     public void testReadCallFromCursor_WithNullCallAccountAddress() throws Exception {
312         testReadCallFromCursor_WithNullField(CallLog.Calls.PHONE_ACCOUNT_ADDRESS);
313     }
314 
testReadCallFromCursor_WithNullCallScreeningAppName()315     public void testReadCallFromCursor_WithNullCallScreeningAppName() throws Exception {
316         testReadCallFromCursor_WithNullField(CallLog.Calls.CALL_SCREENING_APP_NAME);
317     }
318 
testReadCallFromCursor_WithNullCallScreeningComponentName()319     public void testReadCallFromCursor_WithNullCallScreeningComponentName() throws Exception {
320         testReadCallFromCursor_WithNullField(CallLog.Calls.CALL_SCREENING_COMPONENT_NAME);
321     }
322 
testReadCallFromCursor_WithNullMissedReason()323     public void testReadCallFromCursor_WithNullMissedReason() throws Exception {
324         testReadCallFromCursor_WithNullField(CallLog.Calls.MISSED_REASON);
325     }
326 
testReadCallFromCursor_WithNullField(String field)327     private void testReadCallFromCursor_WithNullField(String field) throws Exception {
328         Map<Integer, String> subscriptionInfoMap = new HashMap<>();
329         subscriptionInfoMap.put(TEST_PHONE_ACCOUNT_HANDLE_SUB_ID_INT,
330             TEST_PHONE_ACCOUNT_HANDLE_ICC_ID);
331         mCallLogBackupAgent.mSubscriptionInfoMap = subscriptionInfoMap;
332 
333         //read from cursor and not throw exception
334         mockCursorWithNullFields(mCursor, field);
335         Call call = mCallLogBackupAgent.readCallFromCursor(mCursor);
336     }
337 
testRunBackup_MultipleCall()338     public void testRunBackup_MultipleCall() throws Exception {
339         CallLogBackupState state = new CallLogBackupState();
340         state.version = CallLogBackupAgent.VERSION;
341         state.callIds = new TreeSet<>();
342         List<Call> calls = new LinkedList<>();
343         calls.add(makeCall(101, 0L, 0L, "555-1234"));
344         calls.add(makeCall(102, 0L, 0L, "555-5555"));
345 
346         mCallLogBackupAgent.runBackup(state, mBackupDataOutput, calls);
347 
348         // Ensure the {@link BackupRestoreEventLogger} is informed of the 2 backed up calls:
349         assertEquals(backupRestoreLoggerSuccessCount, 2);
350         assertEquals(backupRestoreLoggerFailCount, 0);
351 
352         InOrder inOrder = Mockito.inOrder(mBackupDataOutput);
353         inOrder.verify(mBackupDataOutput).writeEntityHeader(eq("101"), Matchers.anyInt());
354         inOrder.verify(mBackupDataOutput).
355                 writeEntityData((byte[]) Matchers.any(), Matchers.anyInt());
356         inOrder.verify(mBackupDataOutput).writeEntityHeader(eq("102"), Matchers.anyInt());
357         inOrder.verify(mBackupDataOutput).
358                 writeEntityData((byte[]) Matchers.any(), Matchers.anyInt());
359     }
360 
testRunBackup_PartialMultipleCall()361     public void testRunBackup_PartialMultipleCall() throws Exception {
362         CallLogBackupState state = new CallLogBackupState();
363 
364         state.version = CallLogBackupAgent.VERSION;
365         state.callIds = new TreeSet<>();
366         state.callIds.add(101);
367 
368         List<Call> calls = new LinkedList<>();
369         calls.add(makeCall(101, 0L, 0L, "555-1234"));
370         calls.add(makeCall(102, 0L, 0L, "555-5555"));
371 
372         mCallLogBackupAgent.runBackup(state, mBackupDataOutput, calls);
373 
374         // Ensure the {@link BackupRestoreEventLogger} is informed of the 2 backed up calls:
375         assertEquals(backupRestoreLoggerSuccessCount, 2);
376         assertEquals(backupRestoreLoggerFailCount, 0);
377 
378         InOrder inOrder = Mockito.inOrder(mBackupDataOutput);
379         inOrder.verify(mBackupDataOutput).writeEntityHeader(eq("102"), Matchers.anyInt());
380         inOrder.verify(mBackupDataOutput).
381                 writeEntityData((byte[]) Matchers.any(), Matchers.anyInt());
382     }
383 
mockCursor(Cursor cursor, boolean isTelephonyComponentName)384     private static void mockCursor(Cursor cursor, boolean isTelephonyComponentName) {
385         when(cursor.moveToNext()).thenReturn(true).thenReturn(false);
386 
387         int CALLS_ID_COLUMN_INDEX = 1;
388         int CALL_ID = 9;
389         when(cursor.getColumnIndex(CallLog.Calls._ID)).thenReturn(CALLS_ID_COLUMN_INDEX);
390         when(cursor.getInt(CALLS_ID_COLUMN_INDEX)).thenReturn(CALL_ID);
391 
392         int CALLS_DATE_COLUMN_INDEX = 2;
393         long CALL_DATE = 20991231;
394         when(cursor.getColumnIndex(CallLog.Calls.DATE)).thenReturn(CALLS_DATE_COLUMN_INDEX);
395         when(cursor.getLong(CALLS_DATE_COLUMN_INDEX)).thenReturn(CALL_DATE);
396 
397         int CALLS_DURATION_COLUMN_INDEX = 3;
398         long CALL_DURATION = 987654321;
399         when(cursor.getColumnIndex(CallLog.Calls.DURATION)).thenReturn(
400                 CALLS_DURATION_COLUMN_INDEX);
401         when(cursor.getLong(CALLS_DURATION_COLUMN_INDEX)).thenReturn(CALL_DURATION);
402 
403         int CALLS_NUMBER_COLUMN_INDEX = 4;
404         String CALL_NUMBER = "6316056461";
405         when(cursor.getColumnIndex(CallLog.Calls.NUMBER)).thenReturn(
406                 CALLS_NUMBER_COLUMN_INDEX);
407         when(cursor.getString(CALLS_NUMBER_COLUMN_INDEX)).thenReturn(CALL_NUMBER);
408 
409         int CALLS_POST_DIAL_DIGITS_COLUMN_INDEX = 5;
410         String CALL_POST_DIAL_DIGITS = "54321";
411         when(cursor.getColumnIndex(CallLog.Calls.POST_DIAL_DIGITS)).thenReturn(
412                 CALLS_POST_DIAL_DIGITS_COLUMN_INDEX);
413         when(cursor.getString(CALLS_POST_DIAL_DIGITS_COLUMN_INDEX)).thenReturn(
414                 CALL_POST_DIAL_DIGITS);
415 
416         int CALLS_VIA_NUMBER_COLUMN_INDEX = 6;
417         String CALL_VIA_NUMBER = "via_number";
418         when(cursor.getColumnIndex(CallLog.Calls.VIA_NUMBER)).thenReturn(
419                 CALLS_VIA_NUMBER_COLUMN_INDEX);
420         when(cursor.getString(CALLS_VIA_NUMBER_COLUMN_INDEX)).thenReturn(
421                 CALL_VIA_NUMBER);
422 
423         int CALLS_TYPE_COLUMN_INDEX = 7;
424         int CALL_TYPE = CallLog.Calls.OUTGOING_TYPE;
425         when(cursor.getColumnIndex(CallLog.Calls.TYPE)).thenReturn(CALLS_TYPE_COLUMN_INDEX);
426         when(cursor.getInt(CALLS_TYPE_COLUMN_INDEX)).thenReturn(CALL_TYPE);
427 
428         int CALLS_NUMBER_PRESENTATION_COLUMN_INDEX = 8;
429         int CALL_NUMBER_PRESENTATION = CallLog.Calls.PRESENTATION_ALLOWED;
430         when(cursor.getColumnIndex(CallLog.Calls.NUMBER_PRESENTATION)).thenReturn(
431                 CALLS_NUMBER_PRESENTATION_COLUMN_INDEX);
432         when(cursor.getInt(CALLS_NUMBER_PRESENTATION_COLUMN_INDEX)).thenReturn(
433                 CALL_NUMBER_PRESENTATION);
434 
435         int CALLS_ACCOUNT_COMPONENT_NAME_COLUMN_INDEX = 9;
436         String CALL_ACCOUNT_COMPONENT_NAME = "NON_TELEPHONY_COMPONENT_NAME";
437         if (isTelephonyComponentName) {
438             CALL_ACCOUNT_COMPONENT_NAME = TELEPHONY_COMPONENT;
439         }
440         when(cursor.getColumnIndex(CallLog.Calls.PHONE_ACCOUNT_COMPONENT_NAME)).thenReturn(
441                 CALLS_ACCOUNT_COMPONENT_NAME_COLUMN_INDEX);
442         when(cursor.getString(CALLS_ACCOUNT_COMPONENT_NAME_COLUMN_INDEX)).thenReturn(
443                 CALL_ACCOUNT_COMPONENT_NAME);
444 
445         int CALLS_ACCOUNT_ID_COLUMN_INDEX = 10;
446         String CALL_ACCOUNT_ID = TEST_PHONE_ACCOUNT_HANDLE_SUB_ID;
447         when(cursor.getColumnIndex(CallLog.Calls.PHONE_ACCOUNT_ID)).thenReturn(
448                 CALLS_ACCOUNT_ID_COLUMN_INDEX);
449         when(cursor.getString(CALLS_ACCOUNT_ID_COLUMN_INDEX)).thenReturn(
450                 CALL_ACCOUNT_ID);
451 
452         int CALLS_ACCOUNT_ADDRESS_COLUMN_INDEX = 11;
453         String CALL_ACCOUNT_ADDRESS = "CALL_ACCOUNT_ADDRESS";
454         when(cursor.getColumnIndex(CallLog.Calls.PHONE_ACCOUNT_ADDRESS)).thenReturn(
455                 CALLS_ACCOUNT_ADDRESS_COLUMN_INDEX);
456         when(cursor.getString(CALLS_ACCOUNT_ADDRESS_COLUMN_INDEX)).thenReturn(
457                 CALL_ACCOUNT_ADDRESS);
458 
459         int CALLS_DATA_USAGE_COLUMN_INDEX = 12;
460         long CALL_DATA_USAGE = 987654321;
461         when(cursor.getColumnIndex(CallLog.Calls.DATA_USAGE)).thenReturn(
462                 CALLS_DATA_USAGE_COLUMN_INDEX);
463         when(cursor.getLong(CALLS_DATA_USAGE_COLUMN_INDEX)).thenReturn(CALL_DATA_USAGE);
464 
465         int CALLS_FEATURES_COLUMN_INDEX = 13;
466         int CALL_FEATURES = 777;
467         when(cursor.getColumnIndex(CallLog.Calls.FEATURES)).thenReturn(
468                 CALLS_FEATURES_COLUMN_INDEX);
469         when(cursor.getInt(CALLS_FEATURES_COLUMN_INDEX)).thenReturn(CALL_FEATURES);
470 
471         int CALLS_ADD_FOR_ALL_USERS_COLUMN_INDEX = 14;
472         int CALL_ADD_FOR_ALL_USERS = 1;
473         when(cursor.getColumnIndex(CallLog.Calls.ADD_FOR_ALL_USERS)).thenReturn(
474                 CALLS_ADD_FOR_ALL_USERS_COLUMN_INDEX);
475         when(cursor.getInt(CALLS_ADD_FOR_ALL_USERS_COLUMN_INDEX)).thenReturn(
476                 CALL_ADD_FOR_ALL_USERS);
477 
478         int CALLS_BLOCK_REASON_COLUMN_INDEX = 15;
479         int CALL_BLOCK_REASON = CallLog.Calls.BLOCK_REASON_NOT_BLOCKED;
480         when(cursor.getColumnIndex(CallLog.Calls.BLOCK_REASON)).thenReturn(
481                 CALLS_BLOCK_REASON_COLUMN_INDEX);
482         when(cursor.getInt(CALLS_BLOCK_REASON_COLUMN_INDEX)).thenReturn(
483                 CALL_BLOCK_REASON);
484 
485         int CALLS_CALL_SCREENING_APP_NAME_COLUMN_INDEX = 16;
486         String CALL_CALL_SCREENING_APP_NAME = "CALL_CALL_SCREENING_APP_NAME";
487         when(cursor.getColumnIndex(CallLog.Calls.CALL_SCREENING_APP_NAME)).thenReturn(
488                 CALLS_CALL_SCREENING_APP_NAME_COLUMN_INDEX);
489         when(cursor.getString(CALLS_CALL_SCREENING_APP_NAME_COLUMN_INDEX)).thenReturn(
490                 CALL_CALL_SCREENING_APP_NAME);
491 
492         int CALLS_CALL_SCREENING_COMPONENT_NAME_COLUMN_INDEX = 17;
493         String CALL_CALL_SCREENING_COMPONENT_NAME = "CALL_CALL_SCREENING_COMPONENT_NAME";
494         when(cursor.getColumnIndex(CallLog.Calls.CALL_SCREENING_COMPONENT_NAME)).thenReturn(
495                 CALLS_CALL_SCREENING_COMPONENT_NAME_COLUMN_INDEX);
496         when(cursor.getString(CALLS_CALL_SCREENING_COMPONENT_NAME_COLUMN_INDEX)).thenReturn(
497                 CALL_CALL_SCREENING_COMPONENT_NAME);
498 
499         int CALLS_MISSED_REASON_COLUMN_INDEX = 18;
500         String CALL_MISSED_REASON = "CALL_MISSED_REASON";
501         when(cursor.getColumnIndex(CallLog.Calls.MISSED_REASON)).thenReturn(
502                 CALLS_MISSED_REASON_COLUMN_INDEX);
503         when(cursor.getString(CALLS_MISSED_REASON_COLUMN_INDEX)).thenReturn(
504                 CALL_MISSED_REASON);
505 
506         int CALLS_IS_PHONE_ACCOUNT_MIGRATION_PENDING_COLUMN_INDEX = 19;
507         int CALL_IS_PHONE_ACCOUNT_MIGRATION_PENDING = 0;
508         when(cursor.getColumnIndex(CallLog.Calls.IS_PHONE_ACCOUNT_MIGRATION_PENDING)).thenReturn(
509                 CALLS_IS_PHONE_ACCOUNT_MIGRATION_PENDING_COLUMN_INDEX);
510         when(cursor.getInt(CALLS_IS_PHONE_ACCOUNT_MIGRATION_PENDING_COLUMN_INDEX)).thenReturn(
511                 CALL_IS_PHONE_ACCOUNT_MIGRATION_PENDING);
512     }
513 
514     //sets up the mock cursor with specified column data (string) set to null
mockCursorWithNullFields(Cursor cursor, String columnToNullify)515     private static void mockCursorWithNullFields(Cursor cursor, String columnToNullify) {
516         when(cursor.moveToNext()).thenReturn(true).thenReturn(false);
517 
518         int CALLS_ID_COLUMN_INDEX = 1;
519         int CALL_ID = 9;
520         when(cursor.getColumnIndex(CallLog.Calls._ID)).thenReturn(CALLS_ID_COLUMN_INDEX);
521         when(cursor.getInt(CALLS_ID_COLUMN_INDEX)).thenReturn(CALL_ID);
522 
523         int CALLS_DATE_COLUMN_INDEX = 2;
524         long CALL_DATE = 20991231;
525         when(cursor.getColumnIndex(CallLog.Calls.DATE)).thenReturn(CALLS_DATE_COLUMN_INDEX);
526         when(cursor.getLong(CALLS_DATE_COLUMN_INDEX)).thenReturn(CALL_DATE);
527 
528         int CALLS_DURATION_COLUMN_INDEX = 3;
529         long CALL_DURATION = 987654321;
530         when(cursor.getColumnIndex(CallLog.Calls.DURATION)).thenReturn(
531             CALLS_DURATION_COLUMN_INDEX);
532         when(cursor.getLong(CALLS_DURATION_COLUMN_INDEX)).thenReturn(CALL_DURATION);
533 
534         int CALLS_NUMBER_COLUMN_INDEX = 4;
535         String CALL_NUMBER = "6316056461";
536         when(cursor.getColumnIndex(CallLog.Calls.NUMBER)).thenReturn(
537             CALLS_NUMBER_COLUMN_INDEX);
538         if (CallLog.Calls.NUMBER.equals(columnToNullify)) {
539             when(cursor.getString(CALLS_NUMBER_COLUMN_INDEX)).thenReturn(null);
540         } else {
541             when(cursor.getString(CALLS_NUMBER_COLUMN_INDEX)).thenReturn(CALL_NUMBER);
542         }
543 
544         int CALLS_POST_DIAL_DIGITS_COLUMN_INDEX = 5;
545         String CALL_POST_DIAL_DIGITS = "54321";
546         when(cursor.getColumnIndex(CallLog.Calls.POST_DIAL_DIGITS)).thenReturn(
547             CALLS_POST_DIAL_DIGITS_COLUMN_INDEX);
548         if (CallLog.Calls.POST_DIAL_DIGITS.equals(columnToNullify)) {
549             when(cursor.getString(CALLS_POST_DIAL_DIGITS_COLUMN_INDEX)).thenReturn(
550                 null);
551         } else {
552             when(cursor.getString(CALLS_POST_DIAL_DIGITS_COLUMN_INDEX)).thenReturn(
553                 CALL_POST_DIAL_DIGITS);
554         }
555 
556         int CALLS_VIA_NUMBER_COLUMN_INDEX = 6;
557         String CALL_VIA_NUMBER = "via_number";
558         when(cursor.getColumnIndex(CallLog.Calls.VIA_NUMBER)).thenReturn(
559             CALLS_VIA_NUMBER_COLUMN_INDEX);
560         if (CallLog.Calls.VIA_NUMBER.equals(columnToNullify)) {
561             when(cursor.getString(CALLS_VIA_NUMBER_COLUMN_INDEX)).thenReturn(
562                 null);
563         } else {
564             when(cursor.getString(CALLS_VIA_NUMBER_COLUMN_INDEX)).thenReturn(
565                 CALL_VIA_NUMBER);
566         }
567 
568         int CALLS_TYPE_COLUMN_INDEX = 7;
569         int CALL_TYPE = CallLog.Calls.OUTGOING_TYPE;
570         when(cursor.getColumnIndex(CallLog.Calls.TYPE)).thenReturn(CALLS_TYPE_COLUMN_INDEX);
571         when(cursor.getInt(CALLS_TYPE_COLUMN_INDEX)).thenReturn(CALL_TYPE);
572 
573         int CALLS_NUMBER_PRESENTATION_COLUMN_INDEX = 8;
574         int CALL_NUMBER_PRESENTATION = CallLog.Calls.PRESENTATION_ALLOWED;
575         when(cursor.getColumnIndex(CallLog.Calls.NUMBER_PRESENTATION)).thenReturn(
576             CALLS_NUMBER_PRESENTATION_COLUMN_INDEX);
577         when(cursor.getInt(CALLS_NUMBER_PRESENTATION_COLUMN_INDEX)).thenReturn(
578             CALL_NUMBER_PRESENTATION);
579 
580         int CALLS_ACCOUNT_COMPONENT_NAME_COLUMN_INDEX = 9;
581         String CALL_ACCOUNT_COMPONENT_NAME = TELEPHONY_COMPONENT;
582         when(cursor.getColumnIndex(CallLog.Calls.PHONE_ACCOUNT_COMPONENT_NAME)).thenReturn(
583             CALLS_ACCOUNT_COMPONENT_NAME_COLUMN_INDEX);
584         if (CallLog.Calls.PHONE_ACCOUNT_COMPONENT_NAME.equals(columnToNullify)) {
585             when(cursor.getString(CALLS_ACCOUNT_COMPONENT_NAME_COLUMN_INDEX)).thenReturn(
586                 null);
587         } else {
588             when(cursor.getString(CALLS_ACCOUNT_COMPONENT_NAME_COLUMN_INDEX)).thenReturn(
589                 CALL_ACCOUNT_COMPONENT_NAME);
590         }
591 
592         int CALLS_ACCOUNT_ID_COLUMN_INDEX = 10;
593         String CALL_ACCOUNT_ID = TEST_PHONE_ACCOUNT_HANDLE_SUB_ID;
594         when(cursor.getColumnIndex(CallLog.Calls.PHONE_ACCOUNT_ID)).thenReturn(
595             CALLS_ACCOUNT_ID_COLUMN_INDEX);
596         if (CallLog.Calls.PHONE_ACCOUNT_ID.equals(columnToNullify)) {
597             when(cursor.getString(CALLS_ACCOUNT_ID_COLUMN_INDEX)).thenReturn(
598                 null);
599         } else {
600             when(cursor.getString(CALLS_ACCOUNT_ID_COLUMN_INDEX)).thenReturn(
601                 CALL_ACCOUNT_ID);
602         }
603 
604         int CALLS_ACCOUNT_ADDRESS_COLUMN_INDEX = 11;
605         String CALL_ACCOUNT_ADDRESS = "CALL_ACCOUNT_ADDRESS";
606         when(cursor.getColumnIndex(CallLog.Calls.PHONE_ACCOUNT_ADDRESS)).thenReturn(
607             CALLS_ACCOUNT_ADDRESS_COLUMN_INDEX);
608         if (CallLog.Calls.PHONE_ACCOUNT_ADDRESS.equals(columnToNullify)) {
609             when(cursor.getString(CALLS_ACCOUNT_ADDRESS_COLUMN_INDEX)).thenReturn(
610                 null);
611         } else {
612             when(cursor.getString(CALLS_ACCOUNT_ADDRESS_COLUMN_INDEX)).thenReturn(
613                 CALL_ACCOUNT_ADDRESS);
614         }
615 
616         int CALLS_DATA_USAGE_COLUMN_INDEX = 12;
617         long CALL_DATA_USAGE = 987654321;
618         when(cursor.getColumnIndex(CallLog.Calls.DATA_USAGE)).thenReturn(
619             CALLS_DATA_USAGE_COLUMN_INDEX);
620         when(cursor.getLong(CALLS_DATA_USAGE_COLUMN_INDEX)).thenReturn(CALL_DATA_USAGE);
621 
622         int CALLS_FEATURES_COLUMN_INDEX = 13;
623         int CALL_FEATURES = 777;
624         when(cursor.getColumnIndex(CallLog.Calls.FEATURES)).thenReturn(
625             CALLS_FEATURES_COLUMN_INDEX);
626         when(cursor.getInt(CALLS_FEATURES_COLUMN_INDEX)).thenReturn(CALL_FEATURES);
627 
628         int CALLS_ADD_FOR_ALL_USERS_COLUMN_INDEX = 14;
629         int CALL_ADD_FOR_ALL_USERS = 1;
630         when(cursor.getColumnIndex(CallLog.Calls.ADD_FOR_ALL_USERS)).thenReturn(
631             CALLS_ADD_FOR_ALL_USERS_COLUMN_INDEX);
632         when(cursor.getInt(CALLS_ADD_FOR_ALL_USERS_COLUMN_INDEX)).thenReturn(
633             CALL_ADD_FOR_ALL_USERS);
634 
635         int CALLS_BLOCK_REASON_COLUMN_INDEX = 15;
636         int CALL_BLOCK_REASON = CallLog.Calls.BLOCK_REASON_NOT_BLOCKED;
637         when(cursor.getColumnIndex(CallLog.Calls.BLOCK_REASON)).thenReturn(
638             CALLS_BLOCK_REASON_COLUMN_INDEX);
639         when(cursor.getInt(CALLS_BLOCK_REASON_COLUMN_INDEX)).thenReturn(
640             CALL_BLOCK_REASON);
641 
642         int CALLS_CALL_SCREENING_APP_NAME_COLUMN_INDEX = 16;
643         String CALL_CALL_SCREENING_APP_NAME = "CALL_CALL_SCREENING_APP_NAME";
644         when(cursor.getColumnIndex(CallLog.Calls.CALL_SCREENING_APP_NAME)).thenReturn(
645             CALLS_CALL_SCREENING_APP_NAME_COLUMN_INDEX);
646         if (CallLog.Calls.CALL_SCREENING_APP_NAME.equals(columnToNullify)) {
647             when(cursor.getString(CALLS_CALL_SCREENING_APP_NAME_COLUMN_INDEX)).thenReturn(
648                 null);
649         } else {
650             when(cursor.getString(CALLS_CALL_SCREENING_APP_NAME_COLUMN_INDEX)).thenReturn(
651                 CALL_CALL_SCREENING_APP_NAME);
652         }
653 
654         int CALLS_CALL_SCREENING_COMPONENT_NAME_COLUMN_INDEX = 17;
655         String CALL_CALL_SCREENING_COMPONENT_NAME = "CALL_CALL_SCREENING_COMPONENT_NAME";
656         when(cursor.getColumnIndex(CallLog.Calls.CALL_SCREENING_COMPONENT_NAME)).thenReturn(
657             CALLS_CALL_SCREENING_COMPONENT_NAME_COLUMN_INDEX);
658         if (CallLog.Calls.CALL_SCREENING_COMPONENT_NAME.equals(columnToNullify)) {
659             when(cursor.getString(CALLS_CALL_SCREENING_COMPONENT_NAME_COLUMN_INDEX)).thenReturn(
660                 null);
661         } else {
662             when(cursor.getString(CALLS_CALL_SCREENING_COMPONENT_NAME_COLUMN_INDEX)).thenReturn(
663                 CALL_CALL_SCREENING_COMPONENT_NAME);
664         }
665 
666         int CALLS_MISSED_REASON_COLUMN_INDEX = 18;
667         String CALL_MISSED_REASON = "CALL_MISSED_REASON";
668         when(cursor.getColumnIndex(CallLog.Calls.MISSED_REASON)).thenReturn(
669             CALLS_MISSED_REASON_COLUMN_INDEX);
670         if (CallLog.Calls.MISSED_REASON.equals(columnToNullify)) {
671             when(cursor.getString(CALLS_MISSED_REASON_COLUMN_INDEX)).thenReturn(
672                 null);
673         } else {
674             when(cursor.getString(CALLS_MISSED_REASON_COLUMN_INDEX)).thenReturn(
675                 CALL_MISSED_REASON);
676         }
677 
678         int CALLS_IS_PHONE_ACCOUNT_MIGRATION_PENDING_COLUMN_INDEX = 19;
679         int CALL_IS_PHONE_ACCOUNT_MIGRATION_PENDING = 0;
680         when(cursor.getColumnIndex(CallLog.Calls.IS_PHONE_ACCOUNT_MIGRATION_PENDING)).thenReturn(
681             CALLS_IS_PHONE_ACCOUNT_MIGRATION_PENDING_COLUMN_INDEX);
682         when(cursor.getInt(CALLS_IS_PHONE_ACCOUNT_MIGRATION_PENDING_COLUMN_INDEX)).thenReturn(
683             CALL_IS_PHONE_ACCOUNT_MIGRATION_PENDING);
684     }
685 
makeCall(int id, long date, long duration, String number)686     private static Call makeCall(int id, long date, long duration, String number) {
687         Call c = new Call();
688         c.id = id;
689         c.date = date;
690         c.duration = duration;
691         c.number = number;
692         c.accountComponentName = "account-component";
693         c.accountId = "account-id";
694         return c;
695     }
696 
697 }
698