summaryrefslogtreecommitdiff
path: root/java/com/android/dialer/databasepopulator
diff options
context:
space:
mode:
Diffstat (limited to 'java/com/android/dialer/databasepopulator')
-rw-r--r--java/com/android/dialer/databasepopulator/AndroidManifest.xml18
-rw-r--r--java/com/android/dialer/databasepopulator/CallLogPopulator.java168
-rw-r--r--java/com/android/dialer/databasepopulator/ContactsPopulator.java356
-rw-r--r--java/com/android/dialer/databasepopulator/VoicemailPopulator.java164
4 files changed, 706 insertions, 0 deletions
diff --git a/java/com/android/dialer/databasepopulator/AndroidManifest.xml b/java/com/android/dialer/databasepopulator/AndroidManifest.xml
new file mode 100644
index 000000000..0a3728566
--- /dev/null
+++ b/java/com/android/dialer/databasepopulator/AndroidManifest.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2017 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+<manifest package="com.android.dialer.databasepopulator">
+</manifest> \ No newline at end of file
diff --git a/java/com/android/dialer/databasepopulator/CallLogPopulator.java b/java/com/android/dialer/databasepopulator/CallLogPopulator.java
new file mode 100644
index 000000000..7c387ecd1
--- /dev/null
+++ b/java/com/android/dialer/databasepopulator/CallLogPopulator.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.dialer.databasepopulator;
+
+import android.content.ContentProviderOperation;
+import android.content.ContentValues;
+import android.content.Context;
+import android.content.OperationApplicationException;
+import android.os.RemoteException;
+import android.provider.CallLog;
+import android.provider.CallLog.Calls;
+import android.support.annotation.NonNull;
+import android.support.annotation.WorkerThread;
+import com.android.dialer.common.Assert;
+import com.google.auto.value.AutoValue;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.concurrent.TimeUnit;
+
+/** Populates the device database with call log entries. */
+public final class CallLogPopulator {
+ // Phone numbers from https://www.google.com/about/company/facts/locations/
+ private static final CallEntry.Builder[] SIMPLE_CALL_LOG = {
+ CallEntry.builder().setType(Calls.MISSED_TYPE).setNumber("+1-302-6365454"),
+ CallEntry.builder()
+ .setType(Calls.MISSED_TYPE)
+ .setNumber("")
+ .setPresentation(Calls.PRESENTATION_UNKNOWN),
+ CallEntry.builder().setType(Calls.REJECTED_TYPE).setNumber("+1-302-6365454"),
+ CallEntry.builder().setType(Calls.INCOMING_TYPE).setNumber("+1-302-6365454"),
+ CallEntry.builder()
+ .setType(Calls.MISSED_TYPE)
+ .setNumber("1234")
+ .setPresentation(Calls.PRESENTATION_RESTRICTED),
+ CallEntry.builder().setType(Calls.OUTGOING_TYPE).setNumber("+1-302-6365454"),
+ CallEntry.builder().setType(Calls.BLOCKED_TYPE).setNumber("+1-302-6365454"),
+ CallEntry.builder().setType(Calls.OUTGOING_TYPE).setNumber("(425) 739-5600"),
+ CallEntry.builder().setType(Calls.ANSWERED_EXTERNALLY_TYPE).setNumber("(425) 739-5600"),
+ CallEntry.builder().setType(Calls.MISSED_TYPE).setNumber("+1 (425) 739-5600"),
+ CallEntry.builder().setType(Calls.OUTGOING_TYPE).setNumber("739-5600"),
+ CallEntry.builder().setType(Calls.OUTGOING_TYPE).setNumber("711"),
+ CallEntry.builder().setType(Calls.INCOMING_TYPE).setNumber("711"),
+ CallEntry.builder().setType(Calls.OUTGOING_TYPE).setNumber("(425) 739-5600"),
+ CallEntry.builder().setType(Calls.MISSED_TYPE).setNumber("+44 (0) 20 7031 3000"),
+ CallEntry.builder().setType(Calls.OUTGOING_TYPE).setNumber("+1-650-2530000"),
+ CallEntry.builder().setType(Calls.OUTGOING_TYPE).setNumber("+1 303-245-0086;123,456"),
+ CallEntry.builder().setType(Calls.OUTGOING_TYPE).setNumber("+1 303-245-0086"),
+ CallEntry.builder().setType(Calls.INCOMING_TYPE).setNumber("+1-650-2530000"),
+ CallEntry.builder().setType(Calls.MISSED_TYPE).setNumber("650-2530000"),
+ CallEntry.builder().setType(Calls.REJECTED_TYPE).setNumber("2530000"),
+ CallEntry.builder().setType(Calls.OUTGOING_TYPE).setNumber("+1 404-487-9000"),
+ CallEntry.builder().setType(Calls.INCOMING_TYPE).setNumber("+61 2 9374 4001"),
+ CallEntry.builder().setType(Calls.OUTGOING_TYPE).setNumber("+33 (0)1 42 68 53 00"),
+ CallEntry.builder().setType(Calls.OUTGOING_TYPE).setNumber("972-74-746-6245"),
+ CallEntry.builder().setType(Calls.INCOMING_TYPE).setNumber("+971 4 4509500"),
+ CallEntry.builder().setType(Calls.INCOMING_TYPE).setNumber("+971 4 4509500"),
+ CallEntry.builder().setType(Calls.OUTGOING_TYPE).setNumber("55-31-2128-6800"),
+ CallEntry.builder().setType(Calls.MISSED_TYPE).setNumber("611"),
+ CallEntry.builder().setType(Calls.OUTGOING_TYPE).setNumber("*86 512-343-5283"),
+ };
+
+ @WorkerThread
+ public static void populateCallLog(@NonNull Context context) {
+ populateCallLog(context, false);
+ }
+
+ @WorkerThread
+ public static void populateCallLogWithoutMissed(@NonNull Context context) {
+ populateCallLog(context, true);
+ }
+
+ @WorkerThread
+ public static void populateCallLog(@NonNull Context context, boolean isWithoutMissedCalls) {
+ Assert.isWorkerThread();
+ ArrayList<ContentProviderOperation> operations = new ArrayList<>();
+ // Do this 4 times to make the call log 4 times bigger.
+ long timeMillis = System.currentTimeMillis();
+ for (int i = 0; i < 4; i++) {
+ for (CallEntry.Builder builder : SIMPLE_CALL_LOG) {
+ CallEntry callEntry = builder.setTimeMillis(timeMillis).build();
+ if (isWithoutMissedCalls && builder.build().getType() == Calls.MISSED_TYPE) {
+ continue;
+ }
+ operations.add(
+ ContentProviderOperation.newInsert(Calls.CONTENT_URI)
+ .withValues(callEntry.getAsContentValues())
+ .withYieldAllowed(true)
+ .build());
+ timeMillis -= TimeUnit.HOURS.toMillis(1);
+ }
+ }
+ try {
+ context.getContentResolver().applyBatch(CallLog.AUTHORITY, operations);
+ } catch (RemoteException | OperationApplicationException e) {
+ Assert.fail("error adding call entries: " + e);
+ }
+ }
+
+ @WorkerThread
+ public static void deleteAllCallLog(@NonNull Context context) {
+ Assert.isWorkerThread();
+ try {
+ context
+ .getContentResolver()
+ .applyBatch(
+ CallLog.AUTHORITY,
+ new ArrayList<>(
+ Arrays.asList(ContentProviderOperation.newDelete(Calls.CONTENT_URI).build())));
+ } catch (RemoteException | OperationApplicationException e) {
+ Assert.fail("failed to delete call log: " + e);
+ }
+ }
+
+ @AutoValue
+ abstract static class CallEntry {
+ @NonNull
+ abstract String getNumber();
+
+ abstract int getType();
+
+ abstract int getPresentation();
+
+ abstract long getTimeMillis();
+
+ static Builder builder() {
+ return new AutoValue_CallLogPopulator_CallEntry.Builder()
+ .setPresentation(Calls.PRESENTATION_ALLOWED);
+ }
+
+ ContentValues getAsContentValues() {
+ ContentValues values = new ContentValues();
+ values.put(Calls.TYPE, getType());
+ values.put(Calls.NUMBER, getNumber());
+ values.put(Calls.NUMBER_PRESENTATION, getPresentation());
+ values.put(Calls.DATE, getTimeMillis());
+ return values;
+ }
+
+ @AutoValue.Builder
+ abstract static class Builder {
+ abstract Builder setNumber(@NonNull String number);
+
+ abstract Builder setType(int type);
+
+ abstract Builder setPresentation(int presentation);
+
+ abstract Builder setTimeMillis(long timeMillis);
+
+ abstract CallEntry build();
+ }
+ }
+
+ private CallLogPopulator() {}
+}
diff --git a/java/com/android/dialer/databasepopulator/ContactsPopulator.java b/java/com/android/dialer/databasepopulator/ContactsPopulator.java
new file mode 100644
index 000000000..e93c5697a
--- /dev/null
+++ b/java/com/android/dialer/databasepopulator/ContactsPopulator.java
@@ -0,0 +1,356 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.dialer.databasepopulator;
+
+import android.content.ContentProviderOperation;
+import android.content.Context;
+import android.content.OperationApplicationException;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.os.RemoteException;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.RawContacts;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.WorkerThread;
+import android.text.TextUtils;
+import com.android.dialer.common.Assert;
+import com.google.auto.value.AutoValue;
+import java.io.ByteArrayOutputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/** Populates the device database with contacts. */
+public final class ContactsPopulator {
+ // Phone numbers from https://www.google.com/about/company/facts/locations/
+ private static final Contact[] SIMPLE_CONTACTS = {
+ // US, contact with e164 number.
+ Contact.builder()
+ .setName("Michelangelo")
+ .addPhoneNumber(new PhoneNumber("+1-302-6365454", Phone.TYPE_MOBILE))
+ .addEmail(new Email("m@example.com"))
+ .setIsStarred(true)
+ .setPinned(1)
+ .setOrangePhoto()
+ .build(),
+ // US, contact with a non-e164 number.
+ Contact.builder()
+ .setName("Leonardo da Vinci")
+ .addPhoneNumber(new PhoneNumber("(425) 739-5600", Phone.TYPE_MOBILE))
+ .addEmail(new Email("l@example.com"))
+ .setIsStarred(true)
+ .setPinned(2)
+ .setBluePhoto()
+ .build(),
+ // UK, number where the (0) should be dropped.
+ Contact.builder()
+ .setName("Raphael")
+ .addPhoneNumber(new PhoneNumber("+44 (0) 20 7031 3000", Phone.TYPE_MOBILE))
+ .addEmail(new Email("r@example.com"))
+ .setIsStarred(true)
+ .setPinned(3)
+ .setRedPhoto()
+ .build(),
+ // US and Australia, contact with a long name and multiple phone numbers.
+ Contact.builder()
+ .setName("Donatello di Niccolò di Betto Bardi")
+ .addPhoneNumber(new PhoneNumber("+1-650-2530000", Phone.TYPE_HOME))
+ .addPhoneNumber(new PhoneNumber("+1 404-487-9000", Phone.TYPE_WORK))
+ .addPhoneNumber(new PhoneNumber("+61 2 9374 4001", Phone.TYPE_FAX_HOME))
+ .setIsStarred(true)
+ .setPinned(4)
+ .setPurplePhoto()
+ .build(),
+ // US, phone number shared with another contact and 2nd phone number with wait and pause.
+ Contact.builder()
+ .setName("Splinter")
+ .addPhoneNumber(new PhoneNumber("+1-650-2530000", Phone.TYPE_HOME))
+ .addPhoneNumber(new PhoneNumber("+1 303-245-0086;123,456", Phone.TYPE_WORK))
+ .setBluePhoto()
+ .build(),
+ // France, number with Japanese name.
+ Contact.builder()
+ .setName("スパイク・スピーゲル")
+ .addPhoneNumber(new PhoneNumber("+33 (0)1 42 68 53 00", Phone.TYPE_MOBILE))
+ .setBluePhoto()
+ .build(),
+ // Israel, RTL name and non-e164 number.
+ Contact.builder()
+ .setName("עקב אריה טברסק")
+ .addPhoneNumber(new PhoneNumber("+33 (0)1 42 68 53 00", Phone.TYPE_MOBILE))
+ .setBluePhoto()
+ .build(),
+ // UAE, RTL name.
+ Contact.builder()
+ .setName("سلام دنیا")
+ .addPhoneNumber(new PhoneNumber("+971 4 4509500", Phone.TYPE_MOBILE))
+ .setBluePhoto()
+ .build(),
+ // Brazil, contact with no name.
+ Contact.builder()
+ .addPhoneNumber(new PhoneNumber("+55-31-2128-6800", Phone.TYPE_MOBILE))
+ .setBluePhoto()
+ .build(),
+ // Short number, contact with no name.
+ Contact.builder().addPhoneNumber(new PhoneNumber("611", Phone.TYPE_MOBILE)).build(),
+ // US, number with an anonymous prefix.
+ Contact.builder()
+ .setName("Anonymous")
+ .addPhoneNumber(new PhoneNumber("*86 512-343-5283", Phone.TYPE_MOBILE))
+ .setBluePhoto()
+ .build(),
+ // None, contact with no phone number.
+ Contact.builder()
+ .setName("No Phone Number")
+ .addEmail(new Email("no@example.com"))
+ .setIsStarred(true)
+ .setBluePhoto()
+ .build(),
+ };
+
+ @WorkerThread
+ public static void populateContacts(@NonNull Context context) {
+ Assert.isWorkerThread();
+ ArrayList<ContentProviderOperation> operations = new ArrayList<>();
+ for (Contact contact : SIMPLE_CONTACTS) {
+ addContact(contact, operations);
+ }
+ try {
+ context.getContentResolver().applyBatch(ContactsContract.AUTHORITY, operations);
+ } catch (RemoteException | OperationApplicationException e) {
+ Assert.fail("error adding contacts: " + e);
+ }
+ }
+
+ @WorkerThread
+ public static void deleteAllContacts(@NonNull Context context) {
+ Assert.isWorkerThread();
+ try {
+ context
+ .getContentResolver()
+ .applyBatch(
+ ContactsContract.AUTHORITY,
+ new ArrayList<>(
+ Arrays.asList(
+ ContentProviderOperation.newDelete(RawContacts.CONTENT_URI).build())));
+ } catch (RemoteException | OperationApplicationException e) {
+ Assert.fail("failed to delete contacts: " + e);
+ }
+ }
+
+ private static void addContact(Contact contact, List<ContentProviderOperation> operations) {
+ int index = operations.size();
+
+ operations.add(
+ ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
+ .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, contact.getAccountType())
+ .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, contact.getAccountName())
+ .withValue(ContactsContract.RawContacts.STARRED, contact.getIsStarred() ? 1 : 0)
+ .withValue(
+ ContactsContract.RawContacts.PINNED,
+ contact.getIsStarred() ? contact.getPinned() : 0)
+ .withYieldAllowed(true)
+ .build());
+
+ if (!TextUtils.isEmpty(contact.getName())) {
+ operations.add(
+ ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
+ .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, index)
+ .withValue(
+ ContactsContract.Data.MIMETYPE,
+ ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
+ .withValue(
+ ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, contact.getName())
+ .build());
+ }
+
+ if (contact.getPhotoStream() != null) {
+ operations.add(
+ ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
+ .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, index)
+ .withValue(
+ ContactsContract.Data.MIMETYPE,
+ ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE)
+ .withValue(
+ ContactsContract.CommonDataKinds.Photo.PHOTO,
+ contact.getPhotoStream().toByteArray())
+ .build());
+ }
+
+ for (PhoneNumber phoneNumber : contact.getPhoneNumbers()) {
+ operations.add(
+ ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
+ .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, index)
+ .withValue(
+ ContactsContract.Data.MIMETYPE,
+ ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
+ .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, phoneNumber.value)
+ .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, phoneNumber.type)
+ .withValue(ContactsContract.CommonDataKinds.Phone.LABEL, phoneNumber.label)
+ .build());
+ }
+
+ for (Email email : contact.getEmails()) {
+ operations.add(
+ ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
+ .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, index)
+ .withValue(
+ ContactsContract.Data.MIMETYPE,
+ ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE)
+ .withValue(ContactsContract.CommonDataKinds.Email.DATA, email.value)
+ .withValue(ContactsContract.CommonDataKinds.Email.TYPE, email.type)
+ .withValue(ContactsContract.CommonDataKinds.Email.LABEL, email.label)
+ .build());
+ }
+ }
+
+ @AutoValue
+ abstract static class Contact {
+ @NonNull
+ abstract String getAccountType();
+
+ @NonNull
+ abstract String getAccountName();
+
+ @Nullable
+ abstract String getName();
+
+ abstract boolean getIsStarred();
+
+ abstract int getPinned();
+
+ @Nullable
+ abstract ByteArrayOutputStream getPhotoStream();
+
+ @NonNull
+ abstract List<PhoneNumber> getPhoneNumbers();
+
+ @NonNull
+ abstract List<Email> getEmails();
+
+ static Builder builder() {
+ return new AutoValue_ContactsPopulator_Contact.Builder()
+ .setAccountType("com.google")
+ .setAccountName("foo@example")
+ .setPinned(0)
+ .setIsStarred(false)
+ .setPhoneNumbers(new ArrayList<>())
+ .setEmails(new ArrayList<>());
+ }
+
+ @AutoValue.Builder
+ abstract static class Builder {
+ @NonNull private final List<PhoneNumber> phoneNumbers = new ArrayList<>();
+ @NonNull private final List<Email> emails = new ArrayList<>();
+
+ abstract Builder setAccountType(@NonNull String accountType);
+
+ abstract Builder setAccountName(@NonNull String accountName);
+
+ abstract Builder setName(@NonNull String name);
+
+ abstract Builder setIsStarred(boolean isStarred);
+
+ abstract Builder setPinned(int position);
+
+ abstract Builder setPhotoStream(ByteArrayOutputStream photoStream);
+
+ abstract Builder setPhoneNumbers(@NonNull List<PhoneNumber> phoneNumbers);
+
+ abstract Builder setEmails(@NonNull List<Email> emails);
+
+ abstract Contact build();
+
+ Builder addPhoneNumber(PhoneNumber phoneNumber) {
+ phoneNumbers.add(phoneNumber);
+ return setPhoneNumbers(phoneNumbers);
+ }
+
+ Builder addEmail(Email email) {
+ emails.add(email);
+ return setEmails(emails);
+ }
+
+ Builder setRedPhoto() {
+ setPhotoStream(getPhotoStreamWithColor(Color.rgb(0xe3, 0x33, 0x1c)));
+ return this;
+ }
+
+ Builder setBluePhoto() {
+ setPhotoStream(getPhotoStreamWithColor(Color.rgb(0x00, 0xaa, 0xe6)));
+ return this;
+ }
+
+ Builder setOrangePhoto() {
+ setPhotoStream(getPhotoStreamWithColor(Color.rgb(0xea, 0x95, 0x00)));
+ return this;
+ }
+
+ Builder setPurplePhoto() {
+ setPhotoStream(getPhotoStreamWithColor(Color.rgb(0x99, 0x5a, 0xa0)));
+ return this;
+ }
+
+ /** Creates a contact photo with a green background and a circle of the given color. */
+ private static ByteArrayOutputStream getPhotoStreamWithColor(int color) {
+ int width = 300;
+ int height = 300;
+ Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(bitmap);
+ canvas.drawColor(Color.argb(0xff, 0x4c, 0x9c, 0x23));
+ Paint paint = new Paint();
+ paint.setColor(color);
+ paint.setStyle(Paint.Style.FILL);
+ canvas.drawCircle(width / 2, height / 2, width / 3, paint);
+
+ ByteArrayOutputStream photoStream = new ByteArrayOutputStream();
+ bitmap.compress(Bitmap.CompressFormat.PNG, 75, photoStream);
+ return photoStream;
+ }
+ }
+ }
+
+ static class PhoneNumber {
+ public final String value;
+ public final int type;
+ public final String label;
+
+ PhoneNumber(String value, int type) {
+ this.value = value;
+ this.type = type;
+ label = "simulator phone number";
+ }
+ }
+
+ static class Email {
+ public final String value;
+ public final int type;
+ public final String label;
+
+ Email(String simpleEmail) {
+ value = simpleEmail;
+ type = ContactsContract.CommonDataKinds.Email.TYPE_WORK;
+ label = "simulator email";
+ }
+ }
+
+ private ContactsPopulator() {}
+}
diff --git a/java/com/android/dialer/databasepopulator/VoicemailPopulator.java b/java/com/android/dialer/databasepopulator/VoicemailPopulator.java
new file mode 100644
index 000000000..e99f7c7d4
--- /dev/null
+++ b/java/com/android/dialer/databasepopulator/VoicemailPopulator.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.dialer.databasepopulator;
+
+import android.content.ComponentName;
+import android.content.ContentValues;
+import android.content.Context;
+import android.provider.VoicemailContract.Status;
+import android.provider.VoicemailContract.Voicemails;
+import android.support.annotation.NonNull;
+import android.support.annotation.WorkerThread;
+import android.telecom.PhoneAccountHandle;
+import android.telephony.TelephonyManager;
+import com.android.dialer.common.Assert;
+import com.google.auto.value.AutoValue;
+import java.util.concurrent.TimeUnit;
+
+/** Populates the device database with voicemail entries. */
+public final class VoicemailPopulator {
+ private static final String ACCOUNT_ID = "ACCOUNT_ID";
+
+ private static final Voicemail.Builder[] SIMPLE_VOICEMAILS = {
+ // Long transcription with an embedded phone number.
+ Voicemail.builder()
+ .setPhoneNumber("+1-302-6365454")
+ .setTranscription(
+ "Hi, this is a very long voicemail. Please call me back at 650 253 0000. "
+ + "I hope you listen to all of it. This is very important. "
+ + "Hi, this is a very long voicemail. "
+ + "I hope you listen to all of it. It's very important.")
+ .setDurationSeconds(10)
+ .setIsRead(false),
+ // RTL transcription.
+ Voicemail.builder()
+ .setPhoneNumber("+1-302-6365454")
+ .setTranscription("هزاران دوست کم اند و یک دشمن زیاد")
+ .setDurationSeconds(60)
+ .setIsRead(true),
+ // Empty number.
+ Voicemail.builder()
+ .setPhoneNumber("")
+ .setTranscription("")
+ .setDurationSeconds(60)
+ .setIsRead(true),
+ // No duration.
+ Voicemail.builder()
+ .setPhoneNumber("+1-302-6365454")
+ .setTranscription("")
+ .setDurationSeconds(0)
+ .setIsRead(true),
+ // Short number.
+ Voicemail.builder()
+ .setPhoneNumber("711")
+ .setTranscription("This is a short voicemail.")
+ .setDurationSeconds(12)
+ .setIsRead(true),
+ };
+
+ @WorkerThread
+ public static void populateVoicemail(@NonNull Context context) {
+ Assert.isWorkerThread();
+ enableVoicemail(context);
+
+ // Do this 4 times to make the voicemail database 4 times bigger.
+ long timeMillis = System.currentTimeMillis();
+ for (int i = 0; i < 4; i++) {
+ for (Voicemail.Builder builder : SIMPLE_VOICEMAILS) {
+ Voicemail voicemail = builder.setTimeMillis(timeMillis).build();
+ context
+ .getContentResolver()
+ .insert(
+ Voicemails.buildSourceUri(context.getPackageName()),
+ voicemail.getAsContentValues(context));
+ timeMillis -= TimeUnit.HOURS.toMillis(2);
+ }
+ }
+ }
+
+ @WorkerThread
+ public static void deleteAllVoicemail(@NonNull Context context) {
+ Assert.isWorkerThread();
+ context
+ .getContentResolver()
+ .delete(Voicemails.buildSourceUri(context.getPackageName()), "", new String[] {});
+ }
+
+ private static void enableVoicemail(@NonNull Context context) {
+ PhoneAccountHandle handle =
+ new PhoneAccountHandle(new ComponentName(context, VoicemailPopulator.class), ACCOUNT_ID);
+
+ ContentValues values = new ContentValues();
+ values.put(Status.SOURCE_PACKAGE, handle.getComponentName().getPackageName());
+ values.put(Status.SOURCE_TYPE, TelephonyManager.VVM_TYPE_OMTP);
+ values.put(Status.PHONE_ACCOUNT_COMPONENT_NAME, handle.getComponentName().flattenToString());
+ values.put(Status.PHONE_ACCOUNT_ID, handle.getId());
+ values.put(Status.CONFIGURATION_STATE, Status.CONFIGURATION_STATE_OK);
+ values.put(Status.DATA_CHANNEL_STATE, Status.DATA_CHANNEL_STATE_OK);
+ values.put(Status.NOTIFICATION_CHANNEL_STATE, Status.NOTIFICATION_CHANNEL_STATE_OK);
+ context.getContentResolver().insert(Status.buildSourceUri(context.getPackageName()), values);
+ }
+
+ /** Data for a single voicemail entry. */
+ @AutoValue
+ public abstract static class Voicemail {
+ @NonNull
+ public abstract String getPhoneNumber();
+
+ @NonNull
+ public abstract String getTranscription();
+
+ public abstract long getDurationSeconds();
+
+ public abstract long getTimeMillis();
+
+ public abstract boolean getIsRead();
+
+ public static Builder builder() {
+ return new AutoValue_VoicemailPopulator_Voicemail.Builder();
+ }
+
+ public ContentValues getAsContentValues(Context context) {
+ ContentValues values = new ContentValues();
+ values.put(Voicemails.DATE, getTimeMillis());
+ values.put(Voicemails.NUMBER, getPhoneNumber());
+ values.put(Voicemails.DURATION, getDurationSeconds());
+ values.put(Voicemails.SOURCE_PACKAGE, context.getPackageName());
+ values.put(Voicemails.IS_READ, getIsRead() ? 1 : 0);
+ values.put(Voicemails.TRANSCRIPTION, getTranscription());
+ return values;
+ }
+
+ /** Builder for a single voicemail entry. */
+ @AutoValue.Builder
+ public abstract static class Builder {
+ public abstract Builder setPhoneNumber(@NonNull String phoneNumber);
+
+ public abstract Builder setTranscription(@NonNull String transcription);
+
+ public abstract Builder setDurationSeconds(long durationSeconds);
+
+ public abstract Builder setTimeMillis(long timeMillis);
+
+ public abstract Builder setIsRead(boolean isRead);
+
+ public abstract Voicemail build();
+ }
+ }
+
+ private VoicemailPopulator() {}
+}