summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--java/com/android/dialer/speeddial/database/SpeedDialEntry.java116
-rw-r--r--java/com/android/dialer/speeddial/database/SpeedDialEntryDao.java57
-rw-r--r--java/com/android/dialer/speeddial/database/SpeedDialEntryDatabaseHelper.java221
3 files changed, 394 insertions, 0 deletions
diff --git a/java/com/android/dialer/speeddial/database/SpeedDialEntry.java b/java/com/android/dialer/speeddial/database/SpeedDialEntry.java
new file mode 100644
index 000000000..aa90909f1
--- /dev/null
+++ b/java/com/android/dialer/speeddial/database/SpeedDialEntry.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2018 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.speeddial.database;
+
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.support.annotation.IntDef;
+import android.support.annotation.Nullable;
+import com.google.auto.value.AutoValue;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/** POJO representation of database rows returned by {@link SpeedDialEntryDao}. */
+@AutoValue
+public abstract class SpeedDialEntry {
+
+ /** Unique ID */
+ public abstract long id();
+
+ /** @see {@link Contacts#_ID} */
+ public abstract long contactId();
+
+ /** @see {@link Contacts#LOOKUP_KEY} */
+ public abstract String lookupKey();
+
+ /**
+ * {@link Channel} that is associated with this entry.
+ *
+ * <p>Contacts with multiple channels do not have a default until specified by the user. Once the
+ * default channel is determined, all calls should be placed to this channel.
+ */
+ @Nullable
+ public abstract Channel defaultChannel();
+
+ public abstract Builder toBuilder();
+
+ public static Builder builder() {
+ return new AutoValue_SpeedDialEntry.Builder();
+ }
+
+ /** Builder class for speed dial entry. */
+ @AutoValue.Builder
+ public abstract static class Builder {
+
+ public abstract Builder setId(long id);
+
+ public abstract Builder setContactId(long contactId);
+
+ public abstract Builder setLookupKey(String lookupKey);
+
+ public abstract Builder setDefaultChannel(@Nullable Channel defaultChannel);
+
+ public abstract SpeedDialEntry build();
+ }
+
+ /** POJO representation of a relevant phone number columns in {@link SpeedDialEntryDao}. */
+ @AutoValue
+ public abstract static class Channel {
+
+ public static final int UNKNOWN = 0;
+ public static final int VOICE = 1;
+ public static final int VIDEO = 2;
+
+ /** Whether the Channel is for an audio or video call. */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef({UNKNOWN, VOICE, VIDEO})
+ public @interface Technology {}
+
+ /**
+ * Raw phone number as the user entered it.
+ *
+ * @see {@link Phone#NUMBER}
+ */
+ public abstract String number();
+
+ /**
+ * Label that the user associated with this number like {@link Phone#TYPE_WORK}, {@link
+ * Phone#TYPE_HOME}, ect.
+ *
+ * @see {@link Phone#LABEL}
+ */
+ public abstract String label();
+
+ public abstract @Technology int technology();
+
+ public static Builder builder() {
+ return new AutoValue_SpeedDialEntry_Channel.Builder();
+ }
+
+ /** Builder class for {@link Channel}. */
+ @AutoValue.Builder
+ public abstract static class Builder {
+
+ public abstract Builder setNumber(String number);
+
+ public abstract Builder setLabel(String label);
+
+ public abstract Builder setTechnology(@Technology int technology);
+
+ public abstract Channel build();
+ }
+ }
+}
diff --git a/java/com/android/dialer/speeddial/database/SpeedDialEntryDao.java b/java/com/android/dialer/speeddial/database/SpeedDialEntryDao.java
new file mode 100644
index 000000000..39cb115c8
--- /dev/null
+++ b/java/com/android/dialer/speeddial/database/SpeedDialEntryDao.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2018 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.speeddial.database;
+
+import java.util.List;
+
+/** Interface that databases support speed dial entries should implement. */
+public interface SpeedDialEntryDao {
+
+ /** Return all entries in the database */
+ List<SpeedDialEntry> getAllEntries();
+
+ /**
+ * Insert new entries.
+ *
+ * <p>Fails if any of the {@link SpeedDialEntry#id()} already exist.
+ */
+ void insert(List<SpeedDialEntry> entries);
+
+ /**
+ * Insert a new entry.
+ *
+ * <p>Fails if the {@link SpeedDialEntry#id()} already exists.
+ */
+ long insert(SpeedDialEntry entry);
+
+ /**
+ * Updates existing entries based on {@link SpeedDialEntry#id}.
+ *
+ * <p>Fails if the {@link SpeedDialEntry#id()} doesn't exist.
+ */
+ void update(List<SpeedDialEntry> entries);
+
+ /**
+ * Delete the passed in entries based on {@link SpeedDialEntry#id}.
+ *
+ * <p>Fails if the {@link SpeedDialEntry#id()} doesn't exist.
+ */
+ void delete(List<Long> entries);
+
+ /** Delete all entries in the database. */
+ void deleteAll();
+}
diff --git a/java/com/android/dialer/speeddial/database/SpeedDialEntryDatabaseHelper.java b/java/com/android/dialer/speeddial/database/SpeedDialEntryDatabaseHelper.java
new file mode 100644
index 000000000..1812dbdc0
--- /dev/null
+++ b/java/com/android/dialer/speeddial/database/SpeedDialEntryDatabaseHelper.java
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2018 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.speeddial.database;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.text.TextUtils;
+import com.android.dialer.common.Assert;
+import com.android.dialer.common.database.Selection;
+import com.android.dialer.speeddial.database.SpeedDialEntry.Channel;
+import java.util.ArrayList;
+import java.util.List;
+
+/** {@link SpeedDialEntryDao} implemented as an SQLite database. */
+public final class SpeedDialEntryDatabaseHelper extends SQLiteOpenHelper
+ implements SpeedDialEntryDao {
+
+ private static final int DATABASE_VERSION = 1;
+ private static final String DATABASE_NAME = "CPSpeedDialEntry";
+
+ // Column names
+ private static final String TABLE_NAME = "speed_dial_entries";
+ private static final String ID = "id";
+ private static final String CONTACT_ID = "contact_id";
+ private static final String LOOKUP_KEY = "lookup_key";
+ private static final String PHONE_NUMBER = "phone_number";
+ private static final String PHONE_LABEL = "phone_label";
+ private static final String PHONE_TYPE = "phone_type";
+
+ // Column positions
+ private static final int POSITION_ID = 0;
+ private static final int POSITION_CONTACT_ID = 1;
+ private static final int POSITION_LOOKUP_KEY = 2;
+ private static final int POSITION_PHONE_NUMBER = 3;
+ private static final int POSITION_PHONE_LABEL = 4;
+ private static final int POSITION_PHONE_TYPE = 5;
+
+ // Create Table Query
+ private static final String CREATE_TABLE_SQL =
+ "create table if not exists "
+ + TABLE_NAME
+ + " ("
+ + (ID + " integer primary key, ")
+ + (CONTACT_ID + " integer, ")
+ + (LOOKUP_KEY + " text, ")
+ + (PHONE_NUMBER + " text, ")
+ + (PHONE_LABEL + " text, ")
+ + (PHONE_TYPE + " integer ")
+ + ");";
+
+ private static final String DELETE_TABLE_SQL = "drop table if exists " + TABLE_NAME;
+
+ public SpeedDialEntryDatabaseHelper(Context context) {
+ super(context, DATABASE_NAME, null, DATABASE_VERSION);
+ }
+
+ @Override
+ public void onCreate(SQLiteDatabase db) {
+ db.execSQL(CREATE_TABLE_SQL);
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ // TODO(calderwoodra): handle upgrades more elegantly
+ db.execSQL(DELETE_TABLE_SQL);
+ this.onCreate(db);
+ }
+
+ @Override
+ public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ // TODO(calderwoodra): handle upgrades more elegantly
+ this.onUpgrade(db, oldVersion, newVersion);
+ }
+
+ @Override
+ public List<SpeedDialEntry> getAllEntries() {
+ List<SpeedDialEntry> entries = new ArrayList<>();
+
+ String query = "SELECT * FROM " + TABLE_NAME;
+ try (SQLiteDatabase db = getReadableDatabase();
+ Cursor cursor = db.rawQuery(query, null)) {
+ cursor.moveToPosition(-1);
+ while (cursor.moveToNext()) {
+ Channel channel =
+ Channel.builder()
+ .setNumber(cursor.getString(POSITION_PHONE_NUMBER))
+ .setLabel(cursor.getString(POSITION_PHONE_LABEL))
+ .setTechnology(cursor.getInt(POSITION_PHONE_TYPE))
+ .build();
+ if (TextUtils.isEmpty(channel.number())) {
+ channel = null;
+ }
+ SpeedDialEntry entry =
+ SpeedDialEntry.builder()
+ .setDefaultChannel(channel)
+ .setContactId(cursor.getLong(POSITION_CONTACT_ID))
+ .setLookupKey(cursor.getString(POSITION_LOOKUP_KEY))
+ .setId(cursor.getInt(POSITION_ID))
+ .build();
+ entries.add(entry);
+ }
+ }
+ return entries;
+ }
+
+ @Override
+ public void insert(List<SpeedDialEntry> entries) {
+ SQLiteDatabase db = getWritableDatabase();
+ db.beginTransaction();
+ try {
+ for (SpeedDialEntry entry : entries) {
+ if (db.insert(TABLE_NAME, null, buildContentValues(entry)) == -1L) {
+ throw Assert.createUnsupportedOperationFailException(
+ "Attempted to insert a row that already exists.");
+ }
+ }
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
+ db.close();
+ }
+ }
+
+ @Override
+ public long insert(SpeedDialEntry entry) {
+ long updateRowId;
+ try (SQLiteDatabase db = getWritableDatabase()) {
+ updateRowId = db.insert(TABLE_NAME, null, buildContentValues(entry));
+ }
+ if (updateRowId == -1) {
+ throw Assert.createUnsupportedOperationFailException(
+ "Attempted to insert a row that already exists.");
+ }
+ return updateRowId;
+ }
+
+ @Override
+ public void update(List<SpeedDialEntry> entries) {
+ SQLiteDatabase db = getWritableDatabase();
+ db.beginTransaction();
+ try {
+ for (SpeedDialEntry entry : entries) {
+ int count =
+ db.update(
+ TABLE_NAME,
+ buildContentValues(entry),
+ ID + " = ?",
+ new String[] {Long.toString(entry.id())});
+ if (count != 1) {
+ throw Assert.createUnsupportedOperationFailException(
+ "Attempted to update an undetermined number of rows: " + count);
+ }
+ }
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
+ db.close();
+ }
+ }
+
+ private ContentValues buildContentValues(SpeedDialEntry entry) {
+ ContentValues values = new ContentValues();
+ values.put(ID, entry.id());
+ values.put(CONTACT_ID, entry.contactId());
+ values.put(LOOKUP_KEY, entry.lookupKey());
+ if (entry.defaultChannel() != null) {
+ values.put(PHONE_NUMBER, entry.defaultChannel().number());
+ values.put(PHONE_LABEL, entry.defaultChannel().label());
+ values.put(PHONE_TYPE, entry.defaultChannel().technology());
+ }
+ return values;
+ }
+
+ @Override
+ public void delete(List<Long> ids) {
+ List<String> idStrings = new ArrayList<>();
+ for (Long id : ids) {
+ idStrings.add(Long.toString(id));
+ }
+
+ Selection selection = Selection.builder().and(Selection.column(ID).in(idStrings)).build();
+ try (SQLiteDatabase db = getWritableDatabase()) {
+ int count = db.delete(TABLE_NAME, selection.getSelection(), selection.getSelectionArgs());
+ if (count != ids.size()) {
+ throw Assert.createUnsupportedOperationFailException(
+ "Attempted to delete an undetermined number of rows: " + count);
+ }
+ }
+ }
+
+ @Override
+ public void deleteAll() {
+ SQLiteDatabase db = getWritableDatabase();
+ db.beginTransaction();
+ try {
+ // Passing null into where clause will delete all rows
+ db.delete(TABLE_NAME, /* whereClause=*/ null, null);
+ db.setTransactionSuccessful();
+ } finally {
+ db.endTransaction();
+ db.close();
+ }
+ }
+}