summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chips/java/com/android/ex/chips/BaseRecipientAdapter.java185
-rw-r--r--chips/res/drawable-hdpi/bg_separator.9.pngbin0 -> 153 bytes
-rw-r--r--chips/res/drawable-hdpi/ic_contact_picture.pngbin0 -> 2270 bytes
-rw-r--r--chips/res/drawable-mdpi/bg_separator.9.pngbin0 -> 153 bytes
-rw-r--r--chips/res/drawable-mdpi/ic_contact_picture.pngbin0 -> 1553 bytes
-rw-r--r--chips/res/drawable/bg_separator_inset.xml19
-rw-r--r--chips/res/layout/chips_recipient_dropdown_item.xml60
-rw-r--r--chips/res/layout/chips_separator.xml20
-rw-r--r--chips/res/layout/chips_separator_within_group.xml20
9 files changed, 245 insertions, 59 deletions
diff --git a/chips/java/com/android/ex/chips/BaseRecipientAdapter.java b/chips/java/com/android/ex/chips/BaseRecipientAdapter.java
index e34821a..4f27b8d 100644
--- a/chips/java/com/android/ex/chips/BaseRecipientAdapter.java
+++ b/chips/java/com/android/ex/chips/BaseRecipientAdapter.java
@@ -30,6 +30,7 @@ import android.os.Handler;
import android.os.HandlerThread;
import android.provider.ContactsContract;
import android.provider.ContactsContract.CommonDataKinds.Email;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.CommonDataKinds.Photo;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Directory;
@@ -37,6 +38,7 @@ import android.text.TextUtils;
import android.text.util.Rfc822Token;
import android.util.Log;
import android.util.LruCache;
+import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AutoCompleteTextView;
@@ -76,6 +78,9 @@ public abstract class BaseRecipientAdapter extends BaseAdapter implements Filter
/** The number of photos cached in this Adapter. */
private static final int PHOTO_CACHE_SIZE = 20;
+ public static final int QUERY_TYPE_EMAIL = 0;
+ public static final int QUERY_TYPE_PHONE = 1;
+
/**
* Model object for a {@link Directory} row.
*/
@@ -103,7 +108,18 @@ public abstract class BaseRecipientAdapter extends BaseAdapter implements Filter
public static final int PHOTO_THUMBNAIL_URI = 3;
}
- // TODO: PhoneQuery
+ private static class PhoneQuery {
+ public static final String[] PROJECTION = {
+ Contacts.DISPLAY_NAME, // 0
+ Phone.DATA, // 1
+ Phone.CONTACT_ID, // 2
+ Contacts.PHOTO_THUMBNAIL_URI // 3
+ };
+ public static final int NAME = 0;
+ public static final int NUMBER = 1;
+ public static final int CONTACT_ID = 2;
+ public static final int PHOTO_THUMBNAIL_URI = 3;
+ }
private static class PhotoQuery {
public static final String[] PROJECTION = {
@@ -145,12 +161,7 @@ public abstract class BaseRecipientAdapter extends BaseAdapter implements Filter
final FilterResults results = new FilterResults();
Cursor cursor = null;
if (!TextUtils.isEmpty(constraint)) {
- Uri uri = Email.CONTENT_FILTER_URI.buildUpon()
- .appendPath(constraint.toString())
- .appendQueryParameter(ContactsContract.LIMIT_PARAM_KEY,
- String.valueOf(mPreferredMaxResultCount))
- .build();
- cursor = mContentResolver.query(uri, EmailQuery.PROJECTION, null, null, null);
+ cursor = doQuery(constraint, mPreferredMaxResultCount, null);
if (cursor != null) {
results.count = cursor.getCount();
}
@@ -219,15 +230,7 @@ public abstract class BaseRecipientAdapter extends BaseAdapter implements Filter
protected FilterResults performFiltering(CharSequence constraint) {
final FilterResults results = new FilterResults();
if (!TextUtils.isEmpty(constraint)) {
- final Uri uri = Email.CONTENT_FILTER_URI.buildUpon()
- .appendPath(constraint.toString())
- .appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY,
- String.valueOf(mParams.directoryId))
- .appendQueryParameter(ContactsContract.LIMIT_PARAM_KEY,
- String.valueOf(getLimit() + ALLOWANCE_FOR_DUPLICATES))
- .build();
- final Cursor cursor = mContentResolver.query(
- uri, EmailQuery.PROJECTION, null, null, null);
+ final Cursor cursor = doQuery(constraint, getLimit(), mParams.directoryId);
if (cursor != null) {
results.values = cursor;
}
@@ -253,6 +256,8 @@ public abstract class BaseRecipientAdapter extends BaseAdapter implements Filter
private final Context mContext;
private final ContentResolver mContentResolver;
+ private final LayoutInflater mInflater;
+ private final int mQueryType;
private Account mAccount;
private final int mPreferredMaxResultCount;
private final Handler mHandler = new Handler();
@@ -284,13 +289,22 @@ public abstract class BaseRecipientAdapter extends BaseAdapter implements Filter
private final Handler mPhotoHandler;
private final LruCache<Uri, byte[]> mPhotoCacheMap;
+ /**
+ * Constructor for email queries.
+ */
public BaseRecipientAdapter(Context context) {
- this(context, DEFAULT_PREFERRED_MAX_RESULT_COUNT);
+ this(context, QUERY_TYPE_EMAIL, DEFAULT_PREFERRED_MAX_RESULT_COUNT);
+ }
+
+ public BaseRecipientAdapter(Context context, int queryType) {
+ this(context, queryType, DEFAULT_PREFERRED_MAX_RESULT_COUNT);
}
- public BaseRecipientAdapter(Context context, int preferredMaxResultCount) {
+ public BaseRecipientAdapter(Context context, int queryType, int preferredMaxResultCount) {
mContext = context;
mContentResolver = context.getContentResolver();
+ mInflater = LayoutInflater.from(context);
+ mQueryType = queryType;
mPreferredMaxResultCount = preferredMaxResultCount;
mEntryMap = new HashMap<Integer, List<RecipientListEntry>>();
mNonAggregatedEntries = new ArrayList<RecipientListEntry>();
@@ -461,11 +475,23 @@ public abstract class BaseRecipientAdapter extends BaseAdapter implements Filter
private void putEntriesWithCursor(Cursor cursor, boolean validContactId) {
cursor.move(-1);
while (cursor.moveToNext()) {
- final String displayName = cursor.getString(EmailQuery.NAME);
- final String destination = cursor.getString(EmailQuery.ADDRESS);
- // Contact ID can be invalid if the contact isn't locally stored and thus aggregated.
- final int contactId = cursor.getInt(EmailQuery.CONTACT_ID);
- final String thumbnailUriString = cursor.getString(EmailQuery.PHOTO_THUMBNAIL_URI);
+ final String displayName;
+ final String destination;
+ final int contactId;
+ final String thumbnailUriString;
+ if (mQueryType == QUERY_TYPE_EMAIL) {
+ displayName = cursor.getString(EmailQuery.NAME);
+ destination = cursor.getString(EmailQuery.ADDRESS);
+ contactId = cursor.getInt(EmailQuery.CONTACT_ID);
+ thumbnailUriString = cursor.getString(EmailQuery.PHOTO_THUMBNAIL_URI);
+ } else if (mQueryType == QUERY_TYPE_PHONE) {
+ displayName = cursor.getString(PhoneQuery.NAME);
+ destination = cursor.getString(PhoneQuery.NUMBER);
+ contactId = cursor.getInt(PhoneQuery.CONTACT_ID);
+ thumbnailUriString = cursor.getString(PhoneQuery.PHOTO_THUMBNAIL_URI);
+ } else {
+ throw new IndexOutOfBoundsException("Unexpected query type: " + mQueryType);
+ }
// Note: At this point each entry doesn't contain have any photo (thus getPhotoBytes()
// returns null).
@@ -583,6 +609,36 @@ public abstract class BaseRecipientAdapter extends BaseAdapter implements Filter
});
}
+ private Cursor doQuery(CharSequence constraint, int limit, Long directoryId) {
+ final Cursor cursor;
+ if (mQueryType == QUERY_TYPE_EMAIL) {
+ final Uri.Builder builder = Email.CONTENT_FILTER_URI.buildUpon()
+ .appendPath(constraint.toString())
+ .appendQueryParameter(ContactsContract.LIMIT_PARAM_KEY,
+ String.valueOf(limit + ALLOWANCE_FOR_DUPLICATES));
+ if (directoryId != null) {
+ builder.appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY,
+ String.valueOf(directoryId));
+ }
+ cursor = mContentResolver.query(
+ builder.build(), EmailQuery.PROJECTION, null, null, null);
+ } else if (mQueryType == QUERY_TYPE_PHONE){
+ final Uri.Builder builder = Phone.CONTENT_FILTER_URI.buildUpon()
+ .appendPath(constraint.toString())
+ .appendQueryParameter(ContactsContract.LIMIT_PARAM_KEY,
+ String.valueOf(limit + ALLOWANCE_FOR_DUPLICATES));
+ if (directoryId != null) {
+ builder.appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY,
+ String.valueOf(directoryId));
+ }
+ cursor = mContentResolver.query(
+ builder.build(), PhoneQuery.PROJECTION, null, null, null);
+ } else {
+ cursor = null;
+ }
+ return cursor;
+ }
+
public void close() {
mEntryMap.clear();
mNonAggregatedEntries.clear();
@@ -624,11 +680,12 @@ public abstract class BaseRecipientAdapter extends BaseAdapter implements Filter
final RecipientListEntry entry = mEntries.get(position);
switch (entry.getEntryType()) {
case RecipientListEntry.ENTRY_TYPE_SEP_NORMAL: {
- return convertView != null ? convertView : inflateSeparatorView(parent);
+ return convertView != null ? convertView
+ : mInflater.inflate(getSeparatorLayout(), parent, false);
}
case RecipientListEntry.ENTRY_TYPE_SEP_WITHIN_GROUP: {
return convertView != null ? convertView
- : inflateSeparatorViewWithinGroup(parent);
+ : mInflater.inflate(getSeparatorWithinGroupLayout(), parent, false);
}
default: {
String displayName = entry.getDisplayName();
@@ -639,21 +696,21 @@ public abstract class BaseRecipientAdapter extends BaseAdapter implements Filter
emailAddress = null;
}
- final View itemView = convertView != null ? convertView : inflateItemView(parent);
- final TextView displayNameView = getDisplayNameView(itemView);
- final TextView emailAddressView = getDestinationView(itemView);
- final ImageView imageView = getPhotoView(itemView);
- final View photoContainerView = getPhotoContainerView(itemView);
+ final View itemView = convertView != null ? convertView
+ : mInflater.inflate(getItemLayout(), parent, false);
+ final TextView displayNameView =
+ (TextView)itemView.findViewById(getDisplayNameId());
+ final TextView emailAddressView =
+ (TextView)itemView.findViewById(getDestinationId());
+ final ImageView imageView = (ImageView)itemView.findViewById(getPhotoId());
displayNameView.setText(displayName);
if (!TextUtils.isEmpty(emailAddress)) {
emailAddressView.setText(emailAddress);
}
if (entry.isFirstLevel()) {
displayNameView.setVisibility(View.VISIBLE);
- if (photoContainerView != null) {
- photoContainerView.setVisibility(View.VISIBLE);
- }
if (imageView != null) {
+ imageView.setVisibility(View.VISIBLE);
final byte[] photoBytes = entry.getPhotoBytes();
if (photoBytes != null && imageView != null) {
final Bitmap photo = BitmapFactory.decodeByteArray(
@@ -665,9 +722,7 @@ public abstract class BaseRecipientAdapter extends BaseAdapter implements Filter
}
} else {
displayNameView.setVisibility(View.GONE);
- if (photoContainerView != null) {
- photoContainerView.setVisibility(View.GONE);
- }
+ if (imageView != null) imageView.setVisibility(View.GONE);
}
return itemView;
}
@@ -675,36 +730,48 @@ public abstract class BaseRecipientAdapter extends BaseAdapter implements Filter
}
/**
- * Inflates a View for each item inside auto-complete list. Subclasses must return the View
- * containing two TextViews (for display name and destination) and one ImageView (for photo).
- * The photo View should be surrounded by container (like FrameLayout)
- * @see #getDisplayNameView(View)
- * @see #getDestinationView(View)
- * @see #getPhotoView(View)
- * @see #getPhotoContainerView(View)
- */
- protected abstract View inflateItemView(ViewGroup parent);
- /** Inflates a View for a separator dividing two person or groups. */
- protected abstract View inflateSeparatorView(ViewGroup parent);
- /** Inflates a View for a separator dividing two destinations for a same person or group. */
- protected abstract View inflateSeparatorViewWithinGroup(ViewGroup parent);
-
- /** Returns TextView in itemView for showing a display name. */
- protected abstract TextView getDisplayNameView(View itemView);
- /**
- * Returns TextView in itemView for showing a destination (an email address or a phone number).
+ * Returns a layout id for each item inside auto-complete list.
+ *
+ * Each View must contain two TextViews (for display name and destination) and one ImageView
+ * (for photo). Ids for those should be available via {@link #getDisplayNameId()},
+ * {@link #getDestinationId()}, and {@link #getPhotoId()}.
*/
- protected abstract TextView getDestinationView(View itemView);
- /** Returns ImageView in itemView for showing photo image for a person. */
- protected abstract ImageView getPhotoView(View itemView);
+ protected abstract int getItemLayout();
+ /** Returns a layout id for a separator dividing two person or groups. */
+ protected abstract int getSeparatorLayout();
/**
- * Returns a View containing ImageView given by {@link #getPhotoView(View)}. Can be null.
+ * Returns a layout id for a separator dividing two destinations for a same person or group.
*/
- protected abstract View getPhotoContainerView(View itemView);
+ protected abstract int getSeparatorWithinGroupLayout();
/**
* Returns a resource ID representing an image which should be shown when ther's no relevant
* photo is available.
*/
protected abstract int getDefaultPhotoResource();
+
+ /**
+ * Returns an id for TextView in an item View for showing a display name. In default
+ * {@link android.R.id#text1} is returned.
+ */
+ protected int getDisplayNameId() {
+ return android.R.id.text1;
+ }
+
+ /**
+ * Returns an id for TextView in an item View for showing a destination
+ * (an email address or a phone number).
+ * In default {@link android.R.id#text2} is returned.
+ */
+ protected int getDestinationId() {
+ return android.R.id.text2;
+ }
+
+ /**
+ * Returns an id for ImageView in an item View for showing photo image for a person. In default
+ * {@link android.R.id#icon} is returned.
+ */
+ protected int getPhotoId() {
+ return android.R.id.icon;
+ }
}
diff --git a/chips/res/drawable-hdpi/bg_separator.9.png b/chips/res/drawable-hdpi/bg_separator.9.png
new file mode 100644
index 0000000..2b269e5
--- /dev/null
+++ b/chips/res/drawable-hdpi/bg_separator.9.png
Binary files differ
diff --git a/chips/res/drawable-hdpi/ic_contact_picture.png b/chips/res/drawable-hdpi/ic_contact_picture.png
new file mode 100644
index 0000000..31953dd
--- /dev/null
+++ b/chips/res/drawable-hdpi/ic_contact_picture.png
Binary files differ
diff --git a/chips/res/drawable-mdpi/bg_separator.9.png b/chips/res/drawable-mdpi/bg_separator.9.png
new file mode 100644
index 0000000..2b269e5
--- /dev/null
+++ b/chips/res/drawable-mdpi/bg_separator.9.png
Binary files differ
diff --git a/chips/res/drawable-mdpi/ic_contact_picture.png b/chips/res/drawable-mdpi/ic_contact_picture.png
new file mode 100644
index 0000000..ff6c61a
--- /dev/null
+++ b/chips/res/drawable-mdpi/ic_contact_picture.png
Binary files differ
diff --git a/chips/res/drawable/bg_separator_inset.xml b/chips/res/drawable/bg_separator_inset.xml
new file mode 100644
index 0000000..e263b81
--- /dev/null
+++ b/chips/res/drawable/bg_separator_inset.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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.
+-->
+
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+ android:drawable="@drawable/bg_separator"
+ android:insetLeft="50dip"/>
diff --git a/chips/res/layout/chips_recipient_dropdown_item.xml b/chips/res/layout/chips_recipient_dropdown_item.xml
new file mode 100644
index 0000000..b5c4e9d
--- /dev/null
+++ b/chips/res/layout/chips_recipient_dropdown_item.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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.
+-->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="30dip"
+ android:orientation="horizontal"
+ android:gravity="left|center_vertical">
+ <FrameLayout
+ android:layout_width="50dip"
+ android:layout_height="wrap_content">
+ <ImageView
+ android:id="@android:id/icon"
+ android:layout_width="42dip"
+ android:layout_height="42dip"
+ android:layout_margin="4dip"
+ android:src="@drawable/ic_contact_picture"
+ android:cropToPadding="true"
+ android:scaleType="centerCrop" />
+ </FrameLayout>
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:gravity="left|center_vertical">
+ <TextView android:id="@android:id/text1"
+ android:textColor="?android:attr/textColorPrimary"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="center_vertical"
+ android:paddingLeft="6dip"
+ android:singleLine="true"
+ android:ellipsize="end" />
+ <TextView android:id="@android:id/text2"
+ android:textColor="?android:attr/textColorSecondary"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:gravity="center_vertical"
+ android:paddingLeft="6dip"
+ android:singleLine="true"
+ android:ellipsize="end" />
+ </LinearLayout>
+</LinearLayout>
diff --git a/chips/res/layout/chips_separator.xml b/chips/res/layout/chips_separator.xml
new file mode 100644
index 0000000..f9193d4
--- /dev/null
+++ b/chips/res/layout/chips_separator.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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.
+-->
+
+<View xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="2px"
+ android:background="#ff444444" />
diff --git a/chips/res/layout/chips_separator_within_group.xml b/chips/res/layout/chips_separator_within_group.xml
new file mode 100644
index 0000000..f823b6e
--- /dev/null
+++ b/chips/res/layout/chips_separator_within_group.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 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.
+-->
+
+<View xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="1px"
+ android:background="@drawable/bg_separator_inset" />