Loading java/com/android/dialer/speeddial/database/SpeedDialEntry.java 0 → 100644 +116 −0 Original line number Diff line number Diff line /* * 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(); } } } java/com/android/dialer/speeddial/database/SpeedDialEntryDao.java 0 → 100644 +57 −0 Original line number Diff line number Diff line /* * 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(); } java/com/android/dialer/speeddial/database/SpeedDialEntryDatabaseHelper.java 0 → 100644 +221 −0 Original line number Diff line number Diff line /* * 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(); } } } Loading
java/com/android/dialer/speeddial/database/SpeedDialEntry.java 0 → 100644 +116 −0 Original line number Diff line number Diff line /* * 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(); } } }
java/com/android/dialer/speeddial/database/SpeedDialEntryDao.java 0 → 100644 +57 −0 Original line number Diff line number Diff line /* * 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(); }
java/com/android/dialer/speeddial/database/SpeedDialEntryDatabaseHelper.java 0 → 100644 +221 −0 Original line number Diff line number Diff line /* * 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(); } } }