Adding "aggregates" table. Adding a test. Removing test app Contacts2.
diff --git a/src/com/android/providers/contacts2/ContactsContract.java b/src/com/android/providers/contacts2/ContactsContract.java
index e991118..228a5f2 100644
--- a/src/com/android/providers/contacts2/ContactsContract.java
+++ b/src/com/android/providers/contacts2/ContactsContract.java
@@ -31,31 +31,7 @@
/** A content:// style uri to the authority for the contacts provider */
public static final Uri AUTHORITY_URI = Uri.parse("content://" + AUTHORITY);
- private interface ContactsColumns {
- /**
- * The given name for the contact.
- * <P>Type: TEXT</P>
- */
- public static final String GIVEN_NAME = "given_name";
-
- /**
- * The phonetic version of the given name for the contact.
- * <P>Type: TEXT</P>
- */
- public static final String PHONETIC_GIVEN_NAME = "phonetic_given_name";
-
- /**
- * The family name for the contact.
- * <P>Type: TEXT</P>
- */
- public static final String FAMILY_NAME = "family_name";
-
- /**
- * The phonetic version of the family name for the contact.
- * <P>Type: TEXT</P>
- */
- public static final String PHONETIC_FAMILY_NAME = "phonetic_family_name";
-
+ public interface AggregatesColumns {
/**
* The display name for the contact.
* <P>Type: TEXT</P>
@@ -75,6 +51,72 @@
public static final String LAST_TIME_CONTACTED = "last_time_contacted";
/**
+ * Is the contact starred?
+ * <P>Type: INTEGER (boolean)</P>
+ */
+ public static final String STARRED = "starred";
+ }
+
+ /**
+ * Constants for the aggregates table, which contains a record per group
+ * of contact representing the same person.
+ */
+ public static final class Aggregates implements BaseColumns, AggregatesColumns {
+ /**
+ * This utility class cannot be instantiated
+ */
+ private Aggregates() {}
+
+ /**
+ * The content:// style URI for this table
+ */
+ public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "aggregates");
+
+ /**
+ * The MIME type of {@link #CONTENT_URI} providing a directory of
+ * people.
+ */
+ public static final String CONTENT_TYPE = "vnd.android.cursor.dir/person_aggregate";
+
+ /**
+ * The MIME type of a {@link #CONTENT_URI} subdirectory of a single
+ * person.
+ */
+ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/person_aggregate";
+
+ /**
+ * A sub-directory of a single contact aggregate that contains all of their
+ * {@link Data} rows.
+ */
+ public static final class Data implements BaseColumns, DataColumns {
+ /**
+ * no public constructor since this is a utility class
+ */
+ private Data() {}
+
+ /**
+ * The directory twig for this sub-table
+ */
+ public static final String CONTENT_DIRECTORY = "data";
+ }
+ }
+
+
+ /**
+ * Constants for the contacts table, which contains the base contact information.
+ */
+ public static final class Contacts implements BaseColumns {
+ /**
+ * This utility class cannot be instantiated
+ */
+ private Contacts() {}
+
+ /**
+ * A reference to the {@link Aggregates#_ID} that this data belongs to.
+ */
+ public static final String AGGREGATE_ID = "aggregate_id";
+
+ /**
* A custom ringtone associated with a person. Not always present.
* <P>Type: TEXT (URI to the ringtone)</P>
*/
@@ -88,22 +130,6 @@
public static final String SEND_TO_VOICEMAIL = "send_to_voicemail";
/**
- * Is the contact starred?
- * <P>Type: INTEGER (boolean)</P>
- */
- public static final String STARRED = "starred";
- }
-
- /**
- * Constants for the contacts table, which contains the base contact information.
- */
- public static final class Contacts implements BaseColumns, ContactsColumns {
- /**
- * This utility class cannot be instantiated
- */
- private Contacts() {}
-
- /**
* The content:// style URI for this table
*/
public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "contacts");
@@ -203,7 +229,7 @@
* The table joins that data row for the phone number with the contact that owns the number.
* To perform a lookup you must append the number you want to find to {@link #CONTENT_URI}.
*/
- public static final class PhoneLookup implements BaseColumns, DataColumns, ContactsColumns {
+ public static final class PhoneLookup implements BaseColumns, DataColumns, AggregatesColumns {
/**
* This utility class cannot be instantiated
*/
@@ -280,6 +306,102 @@
}
/**
+ * Parts of the name.
+ */
+ public static final class StructuredName {
+ private StructuredName() {}
+
+ /** Mime-type used when storing this in data table. */
+ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/name";
+
+ /**
+ * The contact's honorific prefix, e.g. "Sir"
+ */
+ public static final String PREFIX = "data1";
+
+ /**
+ * The given name for the contact.
+ * <P>Type: TEXT</P>
+ */
+ public static final String GIVEN_NAME = "data2";
+
+ /**
+ * The contact's middle name
+ * <P>Type: TEXT</P>
+ */
+ public static final String MIDDLE_NAME = "data3";
+
+ /**
+ * The family name for the contact.
+ * <P>Type: TEXT</P>
+ */
+ public static final String FAMILY_NAME = "data4";
+
+ /**
+ * The contact's honorific suffix, e.g. "Jr"
+ */
+ public static final String SUFFIX = "data5";
+
+ /**
+ * The phonetic version of the given name for the contact.
+ * <P>Type: TEXT</P>
+ */
+ public static final String PHONETIC_GIVEN_NAME = "data6";
+
+ /**
+ * The phonetic version of the additional name for the contact.
+ * <P>Type: TEXT</P>
+ */
+ public static final String PHONETIC_MIDDLE_NAME = "data7";
+
+ /**
+ * The phonetic version of the family name for the contact.
+ * <P>Type: TEXT</P>
+ */
+ public static final String PHONETIC_FAMILY_NAME = "data8";
+
+ /**
+ * The name that should be used to display the contact.
+ * <P>Type: TEXT</P>
+ */
+ public static final String DISPLAY_NAME = "data9";
+ }
+
+ /**
+ * A nickname.
+ */
+ public static final class Nickname {
+ private Nickname() {}
+
+ /** Mime-type used when storing this in data table. */
+ public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/nickname";
+
+ /**
+ * The type of data, for example Home or Work.
+ * <P>Type: INTEGER</P>
+ */
+ public static final String TYPE = "data1";
+
+ public static final int TYPE_CUSTOM = 1;
+ public static final int TYPE_DEFAULT = 2;
+ public static final int TYPE_OTHER_NAME = 3;
+ public static final int TYPE_MAINDEN_NAME = 4;
+ public static final int TYPE_SHORT_NAME = 5;
+ public static final int TYPE_INITIALS = 6;
+
+ /**
+ * The user provided label, only used if TYPE is {@link #TYPE_CUSTOM}.
+ * <P>Type: TEXT</P>
+ */
+ public static final String LABEL = "data2";
+
+ /**
+ * The name itself
+ */
+ public static final String NAME = "data3";
+ }
+
+ /**
* Common data definition for telephone numbers.
*/
public static final class Phone implements BaseCommonColumns {
diff --git a/src/com/android/providers/contacts2/ContactsProvider2.java b/src/com/android/providers/contacts2/ContactsProvider2.java
index 536ac82..3e487ae 100644
--- a/src/com/android/providers/contacts2/ContactsProvider2.java
+++ b/src/com/android/providers/contacts2/ContactsProvider2.java
@@ -16,6 +16,7 @@
package com.android.providers.contacts2;
+import com.android.providers.contacts2.ContactsContract.Aggregates;
import com.android.providers.contacts2.ContactsContract.CommonDataKinds;
import com.android.providers.contacts2.ContactsContract.Contacts;
import com.android.providers.contacts2.ContactsContract.Data;
@@ -47,20 +48,26 @@
public class ContactsProvider2 extends ContentProvider {
private static final String TAG = "~~~~~~~~~~~~~"; // TODO: set to class name
- private static final int DATABASE_VERSION = 11;
+ private static final int DATABASE_VERSION = 12;
private static final String DATABASE_NAME = "contacts2.db";
private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
- private static final int CONTACTS = 1000;
- private static final int CONTACTS_ID = 1001;
- private static final int CONTACTS_DATA = 1002;
+ private static final int AGGREGATES = 1000;
+ private static final int AGGREGATES_ID = 1001;
+ private static final int AGGREGATES_DATA = 1002;
- private static final int DATA = 2000;
- private static final int DATA_ID = 2001;
+ private static final int CONTACTS = 2002;
+ private static final int CONTACTS_ID = 2003;
+ private static final int CONTACTS_DATA = 2004;
- private static final int PHONE_LOOKUP = 3000;
+ private static final int DATA = 3000;
+ private static final int DATA_ID = 3001;
+ private static final int PHONE_LOOKUP = 4000;
+
+ /** Contains just the contacts columns */
+ private static final HashMap<String, String> sAggregatesProjectionMap;
/** Contains just the contacts columns */
private static final HashMap<String, String> sContactsProjectionMap;
/** Contains just the data columns */
@@ -73,6 +80,7 @@
/** In-memory cache of previously found package name mappings */
private static HashMap<String, Long> sPackageCache;
+ private static final String TABLE_AGGREGATES = "aggregates";
private static final String TABLE_CONTACTS = "contacts";
private static final String TABLE_PACKAGE = "package";
private static final String TABLE_MIMETYPE = "mimetype";
@@ -86,6 +94,15 @@
+ "LEFT OUTER JOIN package ON (data.package_id = package._id)"
+ "LEFT OUTER JOIN mimetype ON (data.mimetype_id = mimetype._id)";
+ private static final String TABLE_DATA_JOIN_AGGREGATES_PACKAGE_MIMETYPE = "data "
+ + "LEFT OUTER JOIN package ON (data.package_id = package._id)"
+ + "LEFT OUTER JOIN mimetype ON (data.mimetype_id = mimetype._id)"
+ + "LEFT JOIN contacts ON (data.contact_id = contacts._id) "
+ + "LEFT JOIN aggregates ON (contacts.aggregate_id = aggregates._id)";
+
+ private static final String FIELD_AGGREGATION_NEEDED = "aggregation_needed";
+
+
private interface PackageColumns {
public static final String _ID = BaseColumns._ID;
public static final String PACKAGE = "package";
@@ -111,6 +128,9 @@
static {
// Contacts URI matching table
final UriMatcher matcher = sUriMatcher;
+ matcher.addURI(ContactsContract.AUTHORITY, "aggregates", AGGREGATES);
+ matcher.addURI(ContactsContract.AUTHORITY, "aggregates/#", AGGREGATES_ID);
+ matcher.addURI(ContactsContract.AUTHORITY, "aggregates/#/data", AGGREGATES_DATA);
matcher.addURI(ContactsContract.AUTHORITY, "contacts", CONTACTS);
matcher.addURI(ContactsContract.AUTHORITY, "contacts/#", CONTACTS_ID);
matcher.addURI(ContactsContract.AUTHORITY, "contacts/#/data", CONTACTS_DATA);
@@ -120,17 +140,19 @@
HashMap<String, String> columns;
+ // Aggregates projection map
+ columns = new HashMap<String, String>();
+ columns.put(Aggregates.DISPLAY_NAME, Aggregates.DISPLAY_NAME);
+ columns.put(Aggregates.LAST_TIME_CONTACTED, Aggregates.LAST_TIME_CONTACTED);
+ columns.put(Aggregates.STARRED, Aggregates.STARRED);
+ sAggregatesProjectionMap = columns;
+
// Contacts projection map
columns = new HashMap<String, String>();
columns.put(Contacts._ID, "contacts._id AS _id");
- columns.put(Contacts.GIVEN_NAME, Contacts.GIVEN_NAME);
- columns.put(Contacts.PHONETIC_GIVEN_NAME, Contacts.PHONETIC_GIVEN_NAME);
- columns.put(Contacts.FAMILY_NAME, Contacts.FAMILY_NAME);
- columns.put(Contacts.PHONETIC_FAMILY_NAME, Contacts.PHONETIC_FAMILY_NAME);
- columns.put(Contacts.DISPLAY_NAME,
- Contacts.GIVEN_NAME + " || ' ' || " + Contacts.FAMILY_NAME +
- " AS " + Contacts.DISPLAY_NAME);
- columns.put(Contacts.LAST_TIME_CONTACTED, Contacts.LAST_TIME_CONTACTED);
+ columns.put(Contacts.AGGREGATE_ID, Contacts.AGGREGATE_ID);
+ columns.put(Contacts.CUSTOM_RINGTONE, Contacts.CUSTOM_RINGTONE);
+ columns.put(Contacts.SEND_TO_VOICEMAIL, Contacts.SEND_TO_VOICEMAIL);
sContactsProjectionMap = columns;
// Data projection map
@@ -196,18 +218,22 @@
public void onCreate(SQLiteDatabase db) {
Log.i(TAG, "Bootstrapping database");
- // Public contacts table
+ // One row per group of contacts corresponding to the same person
+ db.execSQL("CREATE TABLE " + TABLE_AGGREGATES + " (" +
+ BaseColumns._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
+ Aggregates.DISPLAY_NAME + " TEXT," +
+ Aggregates.TIMES_CONTACTED + " INTEGER," +
+ Aggregates.LAST_TIME_CONTACTED + " INTEGER," +
+ Aggregates.STARRED + " INTEGER" +
+ ");");
+
+ // Contacts table
db.execSQL("CREATE TABLE " + TABLE_CONTACTS + " (" +
Contacts._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
- Contacts.GIVEN_NAME + " TEXT," +
- Contacts.PHONETIC_GIVEN_NAME + " TEXT," +
- Contacts.FAMILY_NAME + " TEXT," +
- Contacts.PHONETIC_FAMILY_NAME + " TEXT," +
- Contacts.TIMES_CONTACTED + " INTEGER," +
- Contacts.LAST_TIME_CONTACTED + " INTEGER," +
+ Contacts.AGGREGATE_ID + " INTEGER, " +
+ FIELD_AGGREGATION_NEEDED + " INTEGER," +
Contacts.CUSTOM_RINGTONE + " TEXT," +
- Contacts.SEND_TO_VOICEMAIL + " INTEGER," +
- Contacts.STARRED + " INTEGER" +
+ Contacts.SEND_TO_VOICEMAIL + " INTEGER" +
");");
// Package name mapping table
@@ -260,6 +286,7 @@
Log.i(TAG, "Upgraing from version " + oldVersion + " to " + newVersion
+ ", data will be lost!");
+ db.execSQL("DROP TABLE IF EXISTS " + TABLE_AGGREGATES + ";");
db.execSQL("DROP TABLE IF EXISTS " + TABLE_CONTACTS + ";");
db.execSQL("DROP TABLE IF EXISTS " + TABLE_PACKAGE + ";");
db.execSQL("DROP TABLE IF EXISTS " + TABLE_MIMETYPE + ";");
@@ -299,6 +326,11 @@
final int match = sUriMatcher.match(uri);
long id = 0;
switch (match) {
+ case AGGREGATES: {
+ id = insertAggregate(values);
+ break;
+ }
+
case CONTACTS: {
id = insertContact(values);
break;
@@ -325,14 +357,34 @@
}
/**
+ * Inserts an item in the aggregates table
+ *
+ * @param values the values for the new row
+ * @return the row ID of the newly created row
+ */
+ private long insertAggregate(ContentValues values) {
+ final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+ return db.insert(TABLE_AGGREGATES, Aggregates.DISPLAY_NAME, values);
+ }
+
+ /**
* Inserts an item in the contacts table
*
* @param values the values for the new row
* @return the row ID of the newly created row
*/
private long insertContact(ContentValues values) {
+
+ /*
+ * The contact record is inserted in the contacts table, but it needs to
+ * be processed by the aggregator before it will be returned by the
+ * "aggregates" queries.
+ */
final SQLiteDatabase db = mOpenHelper.getWritableDatabase();
- return db.insert(TABLE_CONTACTS, Contacts.GIVEN_NAME, values);
+
+ ContentValues augmentedValues = new ContentValues(values);
+ augmentedValues.put(FIELD_AGGREGATION_NEEDED, true);
+ return db.insert(TABLE_CONTACTS, Contacts.AGGREGATE_ID, augmentedValues);
}
/**
@@ -465,6 +517,17 @@
final int match = sUriMatcher.match(uri);
switch (match) {
+ case AGGREGATES_ID: {
+ long aggregateId = ContentUris.parseId(uri);
+
+ // Remove references to the aggregate first
+ ContentValues values = new ContentValues();
+ values.putNull(Contacts.AGGREGATE_ID);
+ db.update(TABLE_CONTACTS, values, Contacts.AGGREGATE_ID + "=" + aggregateId, null);
+
+ return db.delete(TABLE_AGGREGATES, BaseColumns._ID + "=" + aggregateId, null);
+ }
+
case CONTACTS_ID: {
long contactId = ContentUris.parseId(uri);
int contactsDeleted = db.delete(TABLE_CONTACTS, Contacts._ID + "=" + contactId, null);
@@ -474,7 +537,7 @@
case DATA_ID: {
long dataId = ContentUris.parseId(uri);
- return db.delete(TABLE_DATA, Data._ID + "=" + dataId, null);
+ return db.delete("data", Data._ID + "=" + dataId, null);
}
default:
@@ -495,6 +558,26 @@
final int match = sUriMatcher.match(uri);
switch (match) {
+ case AGGREGATES: {
+ qb.setTables(TABLE_AGGREGATES);
+ qb.setProjectionMap(sAggregatesProjectionMap);
+ break;
+ }
+
+ case AGGREGATES_ID: {
+ qb.setTables(TABLE_AGGREGATES);
+ qb.setProjectionMap(sAggregatesProjectionMap);
+ qb.appendWhere(BaseColumns._ID + " = " + uri.getLastPathSegment());
+ break;
+ }
+
+ case AGGREGATES_DATA: {
+ qb.setTables(TABLE_DATA_JOIN_AGGREGATES_PACKAGE_MIMETYPE);
+ qb.setProjectionMap(sDataProjectionMap);
+ qb.appendWhere(Contacts.AGGREGATE_ID + " = " + uri.getPathSegments().get(1));
+ break;
+ }
+
case CONTACTS: {
qb.setTables(TABLE_CONTACTS);
qb.setProjectionMap(sContactsProjectionMap);
@@ -561,11 +644,12 @@
public String getType(Uri uri) {
final int match = sUriMatcher.match(uri);
switch (match) {
+ case AGGREGATES: return Aggregates.CONTENT_TYPE;
+ case AGGREGATES_ID: return Aggregates.CONTENT_ITEM_TYPE;
case CONTACTS: return Contacts.CONTENT_TYPE;
case CONTACTS_ID: return Contacts.CONTENT_ITEM_TYPE;
- case CONTACTS_DATA: return Data.CONTENT_TYPE;
- case DATA: return Data.CONTENT_TYPE;
case DATA_ID:
+ final SQLiteDatabase db = mOpenHelper.getReadableDatabase();
long dataId = ContentUris.parseId(uri);
return getDataMimeType(dataId);
}
diff --git a/tests/Android.mk b/tests/Android.mk
index 7eebbe0..6904962 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -1,13 +1,17 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_MODULE_TAGS := user
+# We only want this apk build for tests.
+LOCAL_MODULE_TAGS := tests
# Only compile source java files in this apk.
LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_SRC_FILES += ../src/com/android/providers/contacts2/ContactsContract.java
+LOCAL_PACKAGE_NAME := ContactsProvider2Tests
-LOCAL_PACKAGE_NAME := Contacts2
+LOCAL_JAVA_LIBRARIES := android.test.runner
+
+LOCAL_INSTRUMENTATION_FOR := ContactsProvider2
+LOCAL_CERTIFICATE := shared
include $(BUILD_PACKAGE)
diff --git a/tests/AndroidManifest.xml b/tests/AndroidManifest.xml
index f2a9bb7..7023063 100644
--- a/tests/AndroidManifest.xml
+++ b/tests/AndroidManifest.xml
@@ -1,16 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 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 xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.contacts2"
->
+ package="com.android.providers.contacts2.tests"
+ android:sharedUserId="android.uid.shared">
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
- <application android:label="@string/app_name">
- <activity android:name="Contacts2">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
+ <application>
+ <uses-library android:name="android.test.runner" />
</application>
+
+ <!--
+ The test delcared in this instrumentation will be run along with tests declared by
+ all other applications via the command: "adb shell itr".
+ The "itr" command will find all tests declared by all applications. If you want to run just these
+ tests on their own then use the command:
+ "adb shell am instrument -w com.android.providers.contacts2.tests/android.test.InstrumentationTestRunner"
+ -->
+ <instrumentation android:name="android.test.InstrumentationTestRunner"
+ android:targetPackage="com.android.providers.contacts2"
+ android:label="Contacts2 provider tests">
+ </instrumentation>
+
</manifest>
diff --git a/tests/res/values/strings.xml b/tests/res/values/strings.xml
deleted file mode 100644
index a7b49f1..0000000
--- a/tests/res/values/strings.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<resources>
- <string name="app_name">Contacts2</string>
-</resources>
-
diff --git a/tests/src/com/android/contacts2/ContactDetails2.java b/tests/src/com/android/contacts2/ContactDetails2.java
deleted file mode 100644
index e85304e..0000000
--- a/tests/src/com/android/contacts2/ContactDetails2.java
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Copyright (C) 2009 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.contacts2;
-
-import com.android.providers.contacts2.ContactsContract.Contacts;
-import com.android.providers.contacts2.ContactsContract.Data;
-
-import android.app.ListActivity;
-import android.content.Context;
-import android.database.Cursor;
-import android.net.Uri;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.view.View;
-import android.widget.ResourceCursorAdapter;
-import android.widget.TextView;
-
-/**
- * Simple test activity to display the data entries for a contact in the contacts2 provider.
- */
-public class ContactDetails2 extends ListActivity {
-
- static final String[] PROJECTION = new String[] {
- Data.PACKAGE, // 0
- Data.MIMETYPE, // 1
- Data.DATA1, // 2
- Data.DATA2, // 3
- Data.DATA3, // 4
- Data.DATA4, // 5
- Data.DATA5, // 6
- Data.DATA6, // 7
- Data.DATA7, // 8
- Data.DATA8, // 9
- Data.DATA9, // 10
- Data.DATA10, // 11
- Data._ID,
- };
- static final int COLUMN_INDEX_PACKAGE = 0;
- static final int COLUMN_INDEX_MIMETYPE = 1;
- static final int COLUMN_INDEX_DATA1 = 2;
- static final int COLUMN_INDEX_DATA2 = 3;
- static final int COLUMN_INDEX_DATA3 = 4;
- static final int COLUMN_INDEX_DATA4 = 5;
- static final int COLUMN_INDEX_DATA5 = 6;
- static final int COLUMN_INDEX_DATA6 = 7;
- static final int COLUMN_INDEX_DATA7 = 8;
- static final int COLUMN_INDEX_DATA8 = 9;
- static final int COLUMN_INDEX_DATA9 = 10;
- static final int COLUMN_INDEX_DATA10 = 11;
-
- DetailsAdapter mAdapter;
-
- /**
- * Simple task for doing an async query.
- */
- final class QueryTask extends AsyncTask<Uri, Void, Cursor> {
- @Override
- protected Cursor doInBackground(Uri... params) {
- final Cursor c = getContentResolver().query(params[0], PROJECTION, null,
- null, null);
- if (c != null) {
- c.getCount();
- }
- return c;
- }
-
- @Override
- protected void onPostExecute(Cursor c) {
- if (isFinishing()) {
- if (c != null) {
- c.close();
- }
- return;
- }
-
- mAdapter.changeCursor(c);
- }
- }
-
- /**
- * Simple list adapter to display the data rows.
- */
- final class DetailsAdapter extends ResourceCursorAdapter {
- public DetailsAdapter() {
- super(ContactDetails2.this, android.R.layout.simple_list_item_1, null);
- }
-
- @Override
- public void bindView(View view, Context context, Cursor cursor) {
- final StringBuilder text = new StringBuilder();
-
- text.append("Package: ");
- text.append(cursor.getString(COLUMN_INDEX_PACKAGE));
- text.append("\nMime-type: ");
- text.append(cursor.getLong(COLUMN_INDEX_MIMETYPE));
- text.append("\nData1: ");
- text.append(cursor.getString(COLUMN_INDEX_DATA1));
- text.append("\nData2: ");
- text.append(cursor.getString(COLUMN_INDEX_DATA2));
- text.append("\nData3: ");
- text.append(cursor.getString(COLUMN_INDEX_DATA3));
- text.append("\nData4: ");
- text.append(cursor.getString(COLUMN_INDEX_DATA4));
- text.append("\nData5: ");
- text.append(cursor.getString(COLUMN_INDEX_DATA5));
- text.append("\nData6: ");
- text.append(cursor.getString(COLUMN_INDEX_DATA6));
- text.append("\nData7: ");
- text.append(cursor.getString(COLUMN_INDEX_DATA7));
- text.append("\nData8: ");
- text.append(cursor.getString(COLUMN_INDEX_DATA8));
- text.append("\nData9: ");
- text.append(cursor.getString(COLUMN_INDEX_DATA9));
- text.append("\nData10: ");
- text.append(cursor.getString(COLUMN_INDEX_DATA10));
-
- ((TextView) view).setText(text);
- }
- }
-
- @Override
- public void onCreate(Bundle savedState) {
- super.onCreate(savedState);
-
- mAdapter = new DetailsAdapter();
- setListAdapter(mAdapter);
- }
-
- @Override
- public void onResume() {
- super.onResume();
-
- new QueryTask().execute(Uri.withAppendedPath(getIntent().getData(),
- Contacts.Data.CONTENT_DIRECTORY));
- }
-}
diff --git a/tests/src/com/android/contacts2/Contacts2.java b/tests/src/com/android/contacts2/Contacts2.java
deleted file mode 100644
index 47de636..0000000
--- a/tests/src/com/android/contacts2/Contacts2.java
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (C) 2009 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.contacts2;
-
-import com.android.providers.contacts2.ContactsContract.CommonDataKinds;
-import com.android.providers.contacts2.ContactsContract.Contacts;
-import com.android.providers.contacts2.ContactsContract.PhoneLookup;
-import com.android.providers.contacts2.ContactsContract.CommonDataKinds.Phone;
-import com.android.providers.contacts2.ContactsContract.Contacts.Data;
-
-import android.app.ListActivity;
-import android.content.ContentResolver;
-import android.content.ContentUris;
-import android.content.ContentValues;
-import android.content.Intent;
-import android.database.Cursor;
-import android.database.DatabaseUtils;
-import android.net.Uri;
-import android.os.AsyncTask;
-import android.os.Bundle;
-import android.util.Log;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-import android.widget.ListView;
-import android.widget.SimpleCursorAdapter;
-
-public class Contacts2 extends ListActivity {
- static final String[] PROJECTION = {
- Contacts._ID, // 0
- Contacts.DISPLAY_NAME, // 1
- };
- static final int COLUMN_INDEX_ID = 0;
- static final int COLUMN_INDEX_DISPLAY_NAME = 1;
-
- SimpleCursorAdapter mAdapter;
-
- public class QueryTask extends AsyncTask<Void, Void, Cursor> {
- @Override
- protected Cursor doInBackground(Void... params) {
- final Cursor c = getContentResolver().query(Contacts.CONTENT_URI, PROJECTION, null,
- null, Contacts.DISPLAY_NAME + " ASC");
- if (c != null) {
- c.getCount();
- }
- return c;
- }
-
- @Override
- protected void onPostExecute(Cursor c) {
- if (isFinishing()) {
- if (c != null) {
- c.close();
- }
- return;
- }
-
- mAdapter.changeCursor(c);
- }
- }
-
- @Override
- public void onCreate(Bundle savedState) {
- super.onCreate(savedState);
-
- mAdapter = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_1, null,
- new String[] { Contacts.DISPLAY_NAME }, new int[] { android.R.id.text1 });
- setListAdapter(mAdapter);
- }
-
- @Override
- public void onResume() {
- super.onResume();
-
- new QueryTask().execute((Void[]) null);
- }
-
- @Override
- protected void onListItemClick(ListView l, View v, int position, long id) {
- final Uri uri = ContentUris.withAppendedId(Contacts.CONTENT_URI, id);
- final Intent intent = new Intent(Intent.ACTION_VIEW, uri);
- intent.setClass(this, ContactDetails2.class);
- startActivity(intent);
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- menu.add(0, 42, 0, "Add data");
- menu.add(0, 43, 0, "Phone lookup");
- return true;
- }
-
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- switch (item.getItemId()) {
- case 42: {
- final ContentResolver resolver = getContentResolver();
- final ContentValues values = new ContentValues();
- values.put(Contacts.GIVEN_NAME, "Bob");
- values.put(Contacts.FAMILY_NAME, "Smith");
- final Uri contactUri = resolver.insert(Contacts.CONTENT_URI, values);
-
- final Uri dataUri = Uri.withAppendedPath(contactUri, Data.CONTENT_DIRECTORY);
- values.clear();
- values.put(Phone.MIMETYPE, Phone.CONTENT_ITEM_TYPE);
- values.put(Phone.NUMBER, "512-555-1212");
- values.put(Phone.TYPE, Phone.TYPE_MOBILE);
- resolver.insert(dataUri, values);
-
- return true;
- }
-
- case 43: {
- final ContentResolver resolver = getContentResolver();
- final Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_URI, "555-1212");
- final Cursor c = resolver.query(uri, null, null, null, null);
- final StringBuilder sb = new StringBuilder();
- DatabaseUtils.dumpCursor(c, sb);
- Log.i("!!!!!!!!", sb.toString());
- }
- }
- return false;
- }
-}
diff --git a/tests/src/com/android/providers/contacts2/ContactsProvider2Test.java b/tests/src/com/android/providers/contacts2/ContactsProvider2Test.java
new file mode 100644
index 0000000..d1e9af8
--- /dev/null
+++ b/tests/src/com/android/providers/contacts2/ContactsProvider2Test.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2009 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.providers.contacts2;
+
+import android.content.ContentUris;
+import android.content.ContentValues;
+import android.content.Context;
+import android.net.Uri;
+import android.test.ProviderTestCase2;
+import android.test.mock.MockContentResolver;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import com.android.providers.contacts2.ContactsContract.Aggregates;
+
+/**
+ * Unit tests for ContactsProvider2
+ *
+ * Run the test like this:
+ * <code>
+ * adb shell am instrument -w \
+ * com.android.providers.contacts2.tests/android.test.InstrumentationTestRunner
+ * </code>
+ */
+@LargeTest
+public class ContactsProvider2Test extends ProviderTestCase2<ContactsProvider2> {
+
+ private Context mContext;
+ private MockContentResolver mResolver;
+
+ public ContactsProvider2Test() {
+ super(ContactsProvider2.class, ContactsContract.AUTHORITY);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mContext = getMockContext();
+ mResolver = getMockContentResolver();
+ }
+
+ public void testInsertAggregate() {
+ ContentValues values = new ContentValues();
+ values.put(Aggregates.DISPLAY_NAME, "Bob Smith");
+ Uri aggregatesUri = mResolver.insert(Aggregates.CONTENT_URI, values);
+
+ // Parse the URI and confirm that it contains an ID
+ assertTrue(ContentUris.parseId(aggregatesUri) > 0);
+ }
+
+ // TODO: move relevant tests from GoogleContactsProvider and add more tests
+}