1 /*
2  * Copyright (C) 2017 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.dialer.databasepopulator;
18 
19 import android.content.ContentProviderOperation;
20 import android.content.ContentValues;
21 import android.content.Context;
22 import android.content.OperationApplicationException;
23 import android.os.RemoteException;
24 import android.provider.CallLog;
25 import android.provider.CallLog.Calls;
26 import android.support.annotation.NonNull;
27 import android.support.annotation.WorkerThread;
28 import com.android.dialer.common.Assert;
29 import com.google.auto.value.AutoValue;
30 import java.util.ArrayList;
31 import java.util.Arrays;
32 import java.util.List;
33 import java.util.concurrent.TimeUnit;
34 
35 /** Populates the device database with call log entries. */
36 public final class CallLogPopulator {
37   // Phone numbers from https://www.google.com/about/company/facts/locations/
38   private static final CallEntry.Builder[] SIMPLE_CALL_LOG = {
39     CallEntry.builder().setType(Calls.MISSED_TYPE).setNumber("+1-302-6365454"),
40     CallEntry.builder()
41         .setType(Calls.MISSED_TYPE)
42         .setNumber("")
43         .setPresentation(Calls.PRESENTATION_UNKNOWN),
44     CallEntry.builder().setType(Calls.REJECTED_TYPE).setNumber("+1-302-6365454"),
45     CallEntry.builder().setType(Calls.INCOMING_TYPE).setNumber("+1-302-6365454"),
46     CallEntry.builder()
47         .setType(Calls.MISSED_TYPE)
48         .setNumber("1234")
49         .setPresentation(Calls.PRESENTATION_RESTRICTED),
50     CallEntry.builder().setType(Calls.OUTGOING_TYPE).setNumber("+1-302-6365454"),
51     CallEntry.builder().setType(Calls.BLOCKED_TYPE).setNumber("+1-302-6365454"),
52     CallEntry.builder().setType(Calls.OUTGOING_TYPE).setNumber("(425) 739-5600"),
53     CallEntry.builder().setType(Calls.ANSWERED_EXTERNALLY_TYPE).setNumber("(425) 739-5600"),
54     CallEntry.builder().setType(Calls.MISSED_TYPE).setNumber("+1 (425) 739-5600"),
55     CallEntry.builder().setType(Calls.OUTGOING_TYPE).setNumber("739-5600"),
56     CallEntry.builder().setType(Calls.OUTGOING_TYPE).setNumber("711"),
57     CallEntry.builder().setType(Calls.INCOMING_TYPE).setNumber("711"),
58     CallEntry.builder().setType(Calls.OUTGOING_TYPE).setNumber("(425) 739-5600"),
59     CallEntry.builder().setType(Calls.MISSED_TYPE).setNumber("+44 (0) 20 7031 3000"),
60     CallEntry.builder().setType(Calls.OUTGOING_TYPE).setNumber("+1-650-2530000"),
61     CallEntry.builder().setType(Calls.OUTGOING_TYPE).setNumber("+1 303-245-0086;123,456"),
62     CallEntry.builder().setType(Calls.OUTGOING_TYPE).setNumber("+1 303-245-0086"),
63     CallEntry.builder().setType(Calls.INCOMING_TYPE).setNumber("+1-650-2530000"),
64     CallEntry.builder().setType(Calls.MISSED_TYPE).setNumber("650-2530000"),
65     CallEntry.builder().setType(Calls.REJECTED_TYPE).setNumber("2530000"),
66     CallEntry.builder().setType(Calls.OUTGOING_TYPE).setNumber("+1 404-487-9000"),
67     CallEntry.builder().setType(Calls.INCOMING_TYPE).setNumber("+61 2 9374 4001"),
68     CallEntry.builder().setType(Calls.OUTGOING_TYPE).setNumber("+33 (0)1 42 68 53 00"),
69     CallEntry.builder().setType(Calls.OUTGOING_TYPE).setNumber("972-74-746-6245"),
70     CallEntry.builder().setType(Calls.INCOMING_TYPE).setNumber("+971 4 4509500"),
71     CallEntry.builder().setType(Calls.INCOMING_TYPE).setNumber("+971 4 4509500"),
72     CallEntry.builder().setType(Calls.OUTGOING_TYPE).setNumber("55-31-2128-6800"),
73     CallEntry.builder().setType(Calls.MISSED_TYPE).setNumber("611"),
74     CallEntry.builder().setType(Calls.OUTGOING_TYPE).setNumber("*86 512-343-5283"),
75   };
76 
77   @WorkerThread
populateCallLog(@onNull Context context, boolean isWithoutMissedCalls)78   public static void populateCallLog(@NonNull Context context, boolean isWithoutMissedCalls) {
79     populateCallLog(context, isWithoutMissedCalls, false);
80   }
81 
82   @WorkerThread
populateCallLog(@onNull Context context)83   public static void populateCallLog(@NonNull Context context) {
84     populateCallLog(context, false);
85   }
86 
87   @WorkerThread
populateCallLog( @onNull Context context, boolean isWithoutMissedCalls, boolean fastMode)88   public static void populateCallLog(
89       @NonNull Context context, boolean isWithoutMissedCalls, boolean fastMode) {
90     Assert.isWorkerThread();
91     ArrayList<ContentProviderOperation> operations = new ArrayList<>();
92     // Do this 4 times to make the call log 4 times bigger.
93     long timeMillis = System.currentTimeMillis();
94     List<CallEntry.Builder> callLogs = new ArrayList<>();
95     if (fastMode) {
96       callLogs.add(SIMPLE_CALL_LOG[0]);
97     } else {
98       callLogs = Arrays.asList(SIMPLE_CALL_LOG);
99     }
100     for (int i = 0; i < 4; i++) {
101       for (CallEntry.Builder builder : callLogs) {
102         CallEntry callEntry = builder.setTimeMillis(timeMillis).build();
103         if (isWithoutMissedCalls && builder.build().getType() == Calls.MISSED_TYPE) {
104           continue;
105         }
106         operations.add(
107             ContentProviderOperation.newInsert(Calls.CONTENT_URI)
108                 .withValues(callEntry.getAsContentValues())
109                 .withYieldAllowed(true)
110                 .build());
111         timeMillis -= TimeUnit.HOURS.toMillis(1);
112       }
113     }
114     try {
115       context.getContentResolver().applyBatch(CallLog.AUTHORITY, operations);
116     } catch (RemoteException | OperationApplicationException e) {
117       Assert.fail("error adding call entries: " + e);
118     }
119   }
120 
121   @WorkerThread
populateCallLogWithoutMissed(@onNull Context context)122   public static void populateCallLogWithoutMissed(@NonNull Context context) {
123     populateCallLog(context, true);
124   }
125 
126   @WorkerThread
deleteAllCallLog(@onNull Context context)127   public static void deleteAllCallLog(@NonNull Context context) {
128     Assert.isWorkerThread();
129     try {
130       context
131           .getContentResolver()
132           .applyBatch(
133               CallLog.AUTHORITY,
134               new ArrayList<>(
135                   Arrays.asList(ContentProviderOperation.newDelete(Calls.CONTENT_URI).build())));
136     } catch (RemoteException | OperationApplicationException e) {
137       Assert.fail("failed to delete call log: " + e);
138     }
139   }
140 
141 
142 
143   @AutoValue
144   abstract static class CallEntry {
145     @NonNull
getNumber()146     abstract String getNumber();
147 
getType()148     abstract int getType();
149 
getPresentation()150     abstract int getPresentation();
151 
getTimeMillis()152     abstract long getTimeMillis();
153 
builder()154     static Builder builder() {
155       return new AutoValue_CallLogPopulator_CallEntry.Builder()
156           .setPresentation(Calls.PRESENTATION_ALLOWED);
157     }
158 
getAsContentValues()159     ContentValues getAsContentValues() {
160       ContentValues values = new ContentValues();
161       values.put(Calls.TYPE, getType());
162       values.put(Calls.NUMBER, getNumber());
163       values.put(Calls.NUMBER_PRESENTATION, getPresentation());
164       values.put(Calls.DATE, getTimeMillis());
165       return values;
166     }
167 
168     @AutoValue.Builder
169     abstract static class Builder {
setNumber(@onNull String number)170       abstract Builder setNumber(@NonNull String number);
171 
setType(int type)172       abstract Builder setType(int type);
173 
setPresentation(int presentation)174       abstract Builder setPresentation(int presentation);
175 
setTimeMillis(long timeMillis)176       abstract Builder setTimeMillis(long timeMillis);
177 
build()178       abstract CallEntry build();
179     }
180   }
181 
CallLogPopulator()182   private CallLogPopulator() {}
183 }
184