Merge "Several renames for consistency. Should help with fragmentizing afterwards"
diff --git a/res/layout-xlarge-land/contact_detail_list_item.xml b/res/layout-xlarge-land/contact_detail_list_item.xml
index 9749f2a..326e7b6 100644
--- a/res/layout-xlarge-land/contact_detail_list_item.xml
+++ b/res/layout-xlarge-land/contact_detail_list_item.xml
@@ -23,11 +23,6 @@
android:layout_height="wrap_content"
android:orientation="vertical">
- <!-- Separating line (between kinds) -->
- <include
- android:id="@+id/kind_divider"
- layout="@layout/contact_detail_divider" />
-
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -118,12 +113,7 @@
</FrameLayout>
</LinearLayout>
- </LinearLayout>
- <!-- Separating line (only for the last row) -->
- <include
- android:id="@+id/line_below_last"
- android:layout_marginBottom="8dip"
- layout="@layout/contact_detail_divider" />
+ </LinearLayout>
</LinearLayout>
diff --git a/res/layout-xlarge/contact_detail_fragment.xml b/res/layout-xlarge/contact_detail_fragment.xml
index 0a4c53c..4d6a900 100644
--- a/res/layout-xlarge/contact_detail_fragment.xml
+++ b/res/layout-xlarge/contact_detail_fragment.xml
@@ -23,25 +23,6 @@
android:layout_height="match_parent"
android:background="@drawable/panel_content">
- <!-- Header View (including social status) -->
- <com.android.contacts.widget.InterpolatingLayout
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- >
- <com.android.contacts.detail.ContactDetailHeaderView
- android:id="@+id/contact_header_widget"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_marginBottom="28dip"
- ex:layout_wideParentWidth="800dip"
- ex:layout_wideMarginLeft="64dip"
- ex:layout_widePaddingRight="48dip"
- ex:layout_narrowParentWidth="500dip"
- ex:layout_narrowMarginLeft="32dip"
- ex:layout_narrowPaddingRight="16dip"
- />
- </com.android.contacts.widget.InterpolatingLayout>
-
<!-- Placeholder for empty list -->
<com.android.contacts.widget.InterpolatingLayout
android:id="@android:id/empty"
diff --git a/res/layout/contact_detail_fragment.xml b/res/layout/contact_detail_fragment.xml
index da37323..72a62db 100644
--- a/res/layout/contact_detail_fragment.xml
+++ b/res/layout/contact_detail_fragment.xml
@@ -20,13 +20,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
- <com.android.contacts.detail.ContactDetailHeaderView
- android:id="@+id/contact_header_widget"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"/>
-
<ListView android:id="@android:id/list"
- android:paddingTop="5dip"
android:layout_width="match_parent"
android:layout_height="0px"
android:layout_weight="1"
diff --git a/res/layout/contact_detail_header_view_list_item.xml b/res/layout/contact_detail_header_view_list_item.xml
new file mode 100644
index 0000000..cf149df
--- /dev/null
+++ b/res/layout/contact_detail_header_view_list_item.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.
+-->
+<com.android.contacts.detail.ContactDetailHeaderView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/contact_header_widget"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"/>
\ No newline at end of file
diff --git a/res/layout/contact_detail_list_item.xml b/res/layout/contact_detail_list_item.xml
index b504fe0..c9067a6 100644
--- a/res/layout/contact_detail_list_item.xml
+++ b/res/layout/contact_detail_list_item.xml
@@ -21,92 +21,71 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="vertical">
-
- <!-- Separating line (between kinds) -->
- <include
- android:id="@+id/kind_divider"
- layout="@layout/contact_detail_divider" />
+ android:paddingLeft="@dimen/detail_item_side_margin"
+ android:orientation="horizontal"
+ android:gravity="center_vertical">
<LinearLayout
- android:layout_width="match_parent"
+ android:layout_width="0dip"
android:layout_height="wrap_content"
- android:layout_marginLeft="@dimen/detail_item_side_margin"
- android:layout_marginBottom="7dip"
- android:minHeight="@dimen/detail_min_line_item_height"
- android:orientation="horizontal"
+ android:layout_weight="1"
+ android:orientation="vertical"
android:gravity="center_vertical">
- <LinearLayout
- android:layout_width="0dip"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:orientation="vertical"
- android:gravity="center_vertical">
+ <TextView
+ android:id="@+id/kind"
+ style="@style/ContactDetailItemType" />
- <TextView
- android:id="@+id/kind"
- style="@style/ContactDetailItemType" />
+ <TextView
+ android:id="@+id/type"
+ style="@style/ContactDetailItemType" />
- <TextView
- android:id="@+id/type"
- style="@style/ContactDetailItemType" />
-
- <TextView
- android:id="@+id/data"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:textAppearance="?android:attr/textAppearanceLarge" />
-
- <TextView
- android:id="@+id/footer"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center_vertical"
- android:textAppearance="?android:attr/textAppearanceSmall"
- android:visibility="gone" />
-
- </LinearLayout>
-
- <ImageView
- android:id="@+id/presence_icon"
- android:layout_width="32dip"
- android:layout_height="wrap_content"
- android:layout_marginLeft="5dip"
- android:gravity="center"
- android:scaleType="centerInside" />
-
- <View
- android:id="@+id/divider"
- android:layout_width="1px"
- android:layout_height="match_parent"
- android:layout_marginTop="15dip"
- android:layout_marginBottom="8dip"
- android:background="?android:attr/dividerVertical" />
-
- <FrameLayout
- android:id="@+id/secondary_action_button_container"
+ <TextView
+ android:id="@+id/data"
android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_marginTop="10dip"
- android:paddingLeft="@dimen/detail_item_icon_margin"
- android:paddingRight="@dimen/detail_item_icon_margin"
- android:duplicateParentState="false"
- android:background="?android:attr/selectableItemBackground">
- <ImageView
- android:id="@+id/secondary_action_button"
- android:layout_width="32dip"
- android:layout_height="match_parent"
- android:duplicateParentState="false" />
- </FrameLayout>
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:paddingBottom="5dip"
+ android:textAppearance="?android:attr/textAppearanceLarge" />
+ <TextView
+ android:id="@+id/footer"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_vertical"
+ android:textAppearance="?android:attr/textAppearanceSmall"
+ android:visibility="gone" />
</LinearLayout>
- <!-- Separating line (only for the last row) -->
- <include
- android:id="@+id/line_below_last"
- android:layout_marginBottom="8dip"
- layout="@layout/contact_detail_divider" />
+ <ImageView
+ android:id="@+id/presence_icon"
+ android:layout_width="32dip"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="5dip"
+ android:gravity="center"
+ android:scaleType="centerInside" />
+ <View
+ android:id="@+id/divider"
+ android:layout_width="1px"
+ android:layout_height="match_parent"
+ android:layout_marginTop="15dip"
+ android:layout_marginBottom="10dip"
+ android:background="?android:attr/dividerVertical" />
+
+ <FrameLayout
+ android:id="@+id/secondary_action_button_container"
+ android:layout_width="wrap_content"
+ android:layout_height="match_parent"
+ android:layout_marginTop="5dip"
+ android:paddingLeft="@dimen/detail_item_icon_margin"
+ android:paddingRight="@dimen/detail_item_icon_margin"
+ android:duplicateParentState="false"
+ android:background="?android:attr/selectableItemBackground">
+ <ImageView
+ android:id="@+id/secondary_action_button"
+ android:layout_width="32dip"
+ android:layout_height="match_parent"
+ android:duplicateParentState="false" />
+ </FrameLayout>
</LinearLayout>
diff --git a/res/layout/contact_detail_divider.xml b/res/layout/contact_detail_separator_list_item.xml
similarity index 100%
rename from res/layout/contact_detail_divider.xml
rename to res/layout/contact_detail_separator_list_item.xml
diff --git a/src/com/android/contacts/detail/ContactDetailFragment.java b/src/com/android/contacts/detail/ContactDetailFragment.java
index dd7b906..88008a3 100644
--- a/src/com/android/contacts/detail/ContactDetailFragment.java
+++ b/src/com/android/contacts/detail/ContactDetailFragment.java
@@ -164,34 +164,26 @@
* A list of distinct contact IDs included in the current contact.
*/
private ArrayList<Long> mRawContactIds = new ArrayList<Long>();
- private ArrayList<ViewEntry> mPhoneEntries = new ArrayList<ViewEntry>();
- private ArrayList<ViewEntry> mSmsEntries = new ArrayList<ViewEntry>();
- private ArrayList<ViewEntry> mEmailEntries = new ArrayList<ViewEntry>();
- private ArrayList<ViewEntry> mPostalEntries = new ArrayList<ViewEntry>();
- private ArrayList<ViewEntry> mImEntries = new ArrayList<ViewEntry>();
- private ArrayList<ViewEntry> mNicknameEntries = new ArrayList<ViewEntry>();
- private ArrayList<ViewEntry> mGroupEntries = new ArrayList<ViewEntry>();
- private ArrayList<ViewEntry> mRelationEntries = new ArrayList<ViewEntry>();
- private ArrayList<ViewEntry> mOtherEntries = new ArrayList<ViewEntry>();
- private ArrayList<ArrayList<ViewEntry>> mSections = new ArrayList<ArrayList<ViewEntry>>();
+ private ArrayList<DetailViewEntry> mPhoneEntries = new ArrayList<DetailViewEntry>();
+ private ArrayList<DetailViewEntry> mSmsEntries = new ArrayList<DetailViewEntry>();
+ private ArrayList<DetailViewEntry> mEmailEntries = new ArrayList<DetailViewEntry>();
+ private ArrayList<DetailViewEntry> mPostalEntries = new ArrayList<DetailViewEntry>();
+ private ArrayList<DetailViewEntry> mImEntries = new ArrayList<DetailViewEntry>();
+ private ArrayList<DetailViewEntry> mNicknameEntries = new ArrayList<DetailViewEntry>();
+ private ArrayList<DetailViewEntry> mGroupEntries = new ArrayList<DetailViewEntry>();
+ private ArrayList<DetailViewEntry> mRelationEntries = new ArrayList<DetailViewEntry>();
+ private ArrayList<DetailViewEntry> mNoteEntries = new ArrayList<DetailViewEntry>();
+ private ArrayList<DetailViewEntry> mWebsiteEntries = new ArrayList<DetailViewEntry>();
+ private ArrayList<DetailViewEntry> mSipEntries = new ArrayList<DetailViewEntry>();
+ private ArrayList<DetailViewEntry> mEventEntries = new ArrayList<DetailViewEntry>();
+ private ArrayList<DetailViewEntry> mOtherEntries = new ArrayList<DetailViewEntry>();
+ private ArrayList<ViewEntry> mAllEntries = new ArrayList<ViewEntry>();
private LayoutInflater mInflater;
private boolean mTransitionAnimationRequested;
public ContactDetailFragment() {
// Explicit constructor for inflation
-
- // Build the list of sections. The order they're added to mSections dictates the
- // order they are displayed in the list.
- mSections.add(mPhoneEntries);
- mSections.add(mSmsEntries);
- mSections.add(mEmailEntries);
- mSections.add(mImEntries);
- mSections.add(mPostalEntries);
- mSections.add(mNicknameEntries);
- mSections.add(mOtherEntries);
- mSections.add(mRelationEntries);
- mSections.add(mGroupEntries);
}
@Override
@@ -223,9 +215,6 @@
mInflater = inflater;
- mHeaderView = (ContactDetailHeaderView) mView.findViewById(R.id.contact_header_widget);
- mHeaderView.setListener(mHeaderViewListener);
-
mListView = (ListView) mView.findViewById(android.R.id.list);
mListView.setScrollBarStyle(ListView.SCROLLBARS_OUTSIDE_OVERLAY);
mListView.setOnItemClickListener(this);
@@ -304,19 +293,22 @@
return;
}
- // Set the header
- mHeaderView.loadData(mContactData);
+ // Clear old header
+ mHeaderView = null;
// Build up the contact entries
buildEntries();
- // Collapse similar data items in select sections.
+ // Collapse similar data items for select {@link DataKind}s.
Collapser.collapseList(mPhoneEntries);
Collapser.collapseList(mSmsEntries);
Collapser.collapseList(mEmailEntries);
Collapser.collapseList(mPostalEntries);
Collapser.collapseList(mImEntries);
+ // Make one aggregated list of all entries for display to the user.
+ flattenAllLists();
+
if (mAdapter == null) {
mAdapter = new ViewAdapter();
mListView.setAdapter(mAdapter);
@@ -350,10 +342,7 @@
mHasSip = PhoneCapabilityTester.isSipPhone(mContext);
// Clear out the old entries
- final int numSections = mSections.size();
- for (int i = 0; i < numSections; i++) {
- mSections.get(i).clear();
- }
+ mAllEntries.clear();
mRawContactIds.clear();
@@ -409,8 +398,8 @@
accountType, mimeType);
if (kind == null) continue;
- final ViewEntry entry = ViewEntry.fromValues(mContext, mimeType, kind, dataId,
- entryValues, mContactData.isDirectoryEntry(),
+ final DetailViewEntry entry = DetailViewEntry.fromValues(mContext, mimeType, kind,
+ dataId, entryValues, mContactData.isDirectoryEntry(),
mContactData.getDirectoryId());
final boolean hasData = !TextUtils.isEmpty(entry.data);
@@ -464,8 +453,8 @@
final String imMime = Im.CONTENT_ITEM_TYPE;
final DataKind imKind = accountTypes.getKindOrFallback(accountType,
imMime);
- final ViewEntry imEntry = ViewEntry.fromValues(mContext, imMime, imKind,
- dataId, entryValues, mContactData.isDirectoryEntry(),
+ final DetailViewEntry imEntry = DetailViewEntry.fromValues(mContext, imMime,
+ imKind, dataId, entryValues, mContactData.isDirectoryEntry(),
mContactData.getDirectoryId());
buildImActions(imEntry, entryValues);
imEntry.applyStatus(status, false);
@@ -507,7 +496,7 @@
// Build note entries
entry.uri = null;
entry.maxLines = 100;
- mOtherEntries.add(entry);
+ mNoteEntries.add(entry);
} else if (Website.CONTENT_ITEM_TYPE.equals(mimeType) && hasData) {
// Build Website entries
entry.uri = null;
@@ -519,7 +508,7 @@
} catch (ParseException e) {
Log.e(TAG, "Couldn't parse website: " + entry.data);
}
- mOtherEntries.add(entry);
+ mWebsiteEntries.add(entry);
} else if (SipAddress.CONTENT_ITEM_TYPE.equals(mimeType) && hasData) {
// Build SipAddress entries
entry.uri = null;
@@ -531,17 +520,17 @@
entry.intent = null;
entry.actionIcon = -1;
}
- mOtherEntries.add(entry);
- // TODO: Consider moving the SipAddress into its own
- // section (rather than lumping it in with mOtherEntries)
- // so that we can reposition it right under the phone number.
+ mSipEntries.add(entry);
+ // TODO: Now that SipAddress is in its own list of entries
+ // (instead of grouped in mOtherEntries), consider
+ // repositioning it right under the phone number.
// (Then, we'd also update FallbackAccountType.java to set
// secondary=false for this field, and tweak the weight
// of its DataKind.)
} else if (Event.CONTENT_ITEM_TYPE.equals(mimeType) && hasData) {
entry.data = DateUtils.formatDate(mContext, entry.data);
entry.uri = null;
- mOtherEntries.add(entry);
+ mEventEntries.add(entry);
} else if (Relation.CONTENT_ITEM_TYPE.equals(mimeType) && hasData) {
entry.intent = new Intent(Intent.ACTION_SEARCH);
entry.intent.putExtra(SearchManager.QUERY, entry.data);
@@ -567,7 +556,7 @@
}
if (!groups.isEmpty()) {
- ViewEntry entry = new ViewEntry();
+ DetailViewEntry entry = new DetailViewEntry();
Collections.sort(groups);
StringBuilder sb = new StringBuilder();
int size = groups.size();
@@ -585,6 +574,49 @@
}
/**
+ * Collapse all contact detail entries into one aggregated list with a {@link HeaderViewEntry}
+ * at the top.
+ */
+ private void flattenAllLists() {
+ // All contacts should have a header view (even if there is no data for the contact).
+ mAllEntries.add(new HeaderViewEntry());
+
+ flattenList(mPhoneEntries);
+ flattenList(mSmsEntries);
+ flattenList(mEmailEntries);
+ flattenList(mImEntries);
+ flattenList(mPostalEntries);
+ flattenList(mNicknameEntries);
+ flattenList(mNoteEntries);
+ flattenList(mWebsiteEntries);
+ flattenList(mSipEntries);
+ flattenList(mEventEntries);
+ flattenList(mOtherEntries);
+ flattenList(mRelationEntries);
+ flattenList(mGroupEntries);
+ }
+
+ /**
+ * Iterate through {@link DetailViewEntry} in the given list and add it to a list of all
+ * entries. Add a {@link SeparatorViewEntry} at the end if the length of the list was not 0.
+ * Clear the original list.
+ */
+ private void flattenList(ArrayList<DetailViewEntry> entries) {
+ int count = entries.size();
+
+ for (int i = 0; i < count; i++) {
+ mAllEntries.add(entries.get(i));
+ }
+
+ if (count > 0) {
+ mAllEntries.add(new SeparatorViewEntry());
+ }
+
+ // Clear old list because it's not needed anymore.
+ entries.clear();
+ }
+
+ /**
* Maps group ID to the corresponding group name, collapses all synonymous groups.
* Ignores default groups (e.g. My Contacts) and favorites groups.
*/
@@ -621,7 +653,7 @@
* {@link Email} row. If the result is non-null, it either contains one or two Intents
* (e.g. [Text, Videochat] or just [Text])
*/
- public static void buildImActions(ViewEntry entry, ContentValues values) {
+ public static void buildImActions(DetailViewEntry entry, ContentValues values) {
final boolean isEmail = Email.CONTENT_ITEM_TYPE.equals(values.getAsString(Data.MIMETYPE));
if (!isEmail && !isProtocolValid(values)) {
@@ -690,15 +722,65 @@
}
/**
- * A basic structure with the data for a contact entry in the list.
+ * Base class for an item in the {@link ViewAdapter} list of data, which is
+ * supplied to the {@link ListView}.
*/
- static class ViewEntry implements Collapsible<ViewEntry> {
+ static class ViewEntry {
+ private final int viewTypeForAdapter;
+ protected long id = -1;
+ /** Whether or not the entry can be focused on or not. */
+ protected boolean isEnabled = false;
+
+ ViewEntry(int viewType) {
+ viewTypeForAdapter = viewType;
+ }
+
+ int getViewType() {
+ return viewTypeForAdapter;
+ }
+
+ long getId() {
+ return id;
+ }
+
+ boolean isEnabled(){
+ return isEnabled;
+ }
+ }
+
+ /**
+ * Header item in the {@link ViewAdapter} list of data.
+ */
+ static class HeaderViewEntry extends ViewEntry {
+
+ HeaderViewEntry() {
+ super(ViewAdapter.VIEW_TYPE_HEADER_ENTRY);
+ }
+
+ }
+
+ /**
+ * Separator between items of the same {@link DataKind} in the
+ * {@link ViewAdapter} list of data.
+ */
+ static class SeparatorViewEntry extends ViewEntry {
+
+ SeparatorViewEntry() {
+ super(ViewAdapter.VIEW_TYPE_SEPARATOR_ENTRY);
+ }
+
+ }
+
+ /**
+ * An item with a single detail for a contact in the {@link ViewAdapter}
+ * list of data.
+ */
+ static class DetailViewEntry extends ViewEntry implements Collapsible<DetailViewEntry> {
public int type = -1;
public String kind;
public String typeString;
public String data;
public Uri uri;
- public long id = 0;
public int maxLines = 1;
public String mimetype;
@@ -717,17 +799,19 @@
public CharSequence footerLine = null;
- ViewEntry() {
+ DetailViewEntry() {
+ super(ViewAdapter.VIEW_TYPE_DETAIL_ENTRY);
+ isEnabled = true;
}
/**
- * Build new {@link ViewEntry} and populate from the given values.
+ * Build new {@link DetailViewEntry} and populate from the given values.
*/
- public static ViewEntry fromValues(Context context, String mimeType, DataKind kind,
+ public static DetailViewEntry fromValues(Context context, String mimeType, DataKind kind,
long dataId, ContentValues values, boolean isDirectoryEntry, long directoryId) {
- final ViewEntry entry = new ViewEntry();
- entry.context = context;
+ final DetailViewEntry entry = new DetailViewEntry();
entry.id = dataId;
+ entry.context = context;
entry.uri = ContentUris.withAppendedId(Data.CONTENT_URI, entry.id);
if (isDirectoryEntry) {
entry.uri = entry.uri.buildUpon().appendQueryParameter(
@@ -770,13 +854,13 @@
}
/**
- * Apply given {@link DataStatus} values over this {@link ViewEntry}
+ * Apply given {@link DataStatus} values over this {@link DetailViewEntry}
*
* @param fillData When true, the given status replaces {@link #data}
* and {@link #footerLine}. Otherwise only {@link #presence}
* is updated.
*/
- public ViewEntry applyStatus(DataStatus status, boolean fillData) {
+ public DetailViewEntry applyStatus(DataStatus status, boolean fillData) {
presence = status.getPresence();
if (fillData && status.isValid()) {
this.data = status.getStatus().toString();
@@ -787,7 +871,7 @@
}
@Override
- public boolean collapseWith(ViewEntry entry) {
+ public boolean collapseWith(DetailViewEntry entry) {
// assert equal collapse keys
if (!shouldCollapseWith(entry)) {
return false;
@@ -816,13 +900,13 @@
// uri, and contactdId, shouldn't make a difference. Just keep the original.
// Keep track of all the ids that have been collapsed with this one.
- ids.add(entry.id);
+ ids.add(entry.getId());
collapseCount++;
return true;
}
@Override
- public boolean shouldCollapseWith(ViewEntry entry) {
+ public boolean shouldCollapseWith(DetailViewEntry entry) {
if (entry == null) {
return false;
}
@@ -845,8 +929,6 @@
/** Cache of the children views of a row */
private static class ViewCache {
- public View kindDivider;
- public View lineBelowLast;
public TextView kind;
public TextView type;
public TextView data;
@@ -858,9 +940,53 @@
}
private final class ViewAdapter extends BaseAdapter {
+
+ public static final int VIEW_TYPE_DETAIL_ENTRY = 0;
+ public static final int VIEW_TYPE_HEADER_ENTRY = 1;
+ public static final int VIEW_TYPE_SEPARATOR_ENTRY = 2;
+ private static final int VIEW_TYPE_COUNT = 3;
+
@Override
public View getView(int position, View convertView, ViewGroup parent) {
- final ViewEntry entry = getEntry(position);
+ switch (getItemViewType(position)) {
+ case VIEW_TYPE_HEADER_ENTRY:
+ return getHeaderEntryView(convertView, parent);
+ case VIEW_TYPE_SEPARATOR_ENTRY:
+ return getSeparatorEntryView(convertView, parent);
+ case VIEW_TYPE_DETAIL_ENTRY:
+ return getDetailEntryView(position, convertView, parent);
+ default:
+ throw new IllegalStateException("Invalid view type ID " +
+ getItemViewType(position));
+ }
+ }
+
+ private View getHeaderEntryView(View convertView, ViewGroup parent) {
+ // We don't want to rely on the recycled header view because it may
+ // have been left over from a previously viewed contact (since we
+ // reuse the adapter), so we would have to bind the data to the
+ // header each time. However, since there is only 1 header per list,
+ // just hold onto the original header view for this contact and
+ // return that each time.
+ if (mHeaderView != null) {
+ return mHeaderView;
+ }
+ mHeaderView = (ContactDetailHeaderView) mInflater.inflate(
+ R.layout.contact_detail_header_view_list_item, parent, false);
+ mHeaderView.setListener(mHeaderViewListener);
+ mHeaderView.loadData(mContactData);
+ return mHeaderView;
+ }
+
+ private View getSeparatorEntryView(View convertView, ViewGroup parent) {
+ if (convertView != null) {
+ return convertView;
+ }
+ return mInflater.inflate(R.layout.contact_detail_separator_list_item, parent, false);
+ }
+
+ private View getDetailEntryView(int position, View convertView, ViewGroup parent) {
+ final DetailViewEntry entry = (DetailViewEntry) getItem(position);
final View v;
final ViewCache viewCache;
@@ -875,8 +1001,6 @@
// Cache the children
viewCache = new ViewCache();
viewCache.kind = (TextView) v.findViewById(R.id.kind);
- viewCache.kindDivider = v.findViewById(R.id.kind_divider);
- viewCache.lineBelowLast = v.findViewById(R.id.line_below_last);
viewCache.type = (TextView) v.findViewById(R.id.type);
viewCache.data = (TextView) v.findViewById(R.id.data);
viewCache.footer = (TextView) v.findViewById(R.id.footer);
@@ -891,17 +1015,16 @@
v.setTag(viewCache);
}
- final ViewEntry previousEntry = position == 0 ? null : getEntry(position - 1);
- final boolean isFirstOfItsKind =
- previousEntry == null ? true : !previousEntry.kind.equals(entry.kind);
+ final ViewEntry previousEntry = position == 0 ? null : getItem(position - 1);
+ final boolean isFirstOfItsKind = (previousEntry == null) ? true :
+ (previousEntry.getViewType() != VIEW_TYPE_DETAIL_ENTRY);
// Bind the data to the view
- bindView(v, entry, position, isFirstOfItsKind);
+ bindView(v, entry, isFirstOfItsKind);
return v;
}
- private void bindView(View view, ViewEntry entry, int position,
- boolean isFirstOfItsKind) {
+ private void bindView(View view, DetailViewEntry entry, boolean isFirstOfItsKind) {
final Resources resources = mContext.getResources();
ViewCache views = (ViewCache) view.getTag();
@@ -912,15 +1035,6 @@
views.kind.setVisibility(View.GONE);
}
- views.kindDivider.setVisibility(isFirstOfItsKind && position != 0 ?
- View.VISIBLE : View.GONE);
-
- if (position == getCount() - 1) {
- views.lineBelowLast.setVisibility(View.VISIBLE);
- } else {
- views.lineBelowLast.setVisibility(View.GONE);
- }
-
if (!TextUtils.isEmpty(entry.typeString)) {
views.type.setText(entry.typeString.toUpperCase());
views.type.setVisibility(View.VISIBLE);
@@ -994,8 +1108,9 @@
if (mListener == null) return;
if (v == null) return;
final ViewEntry entry = (ViewEntry) v.getTag();
- if (entry == null) return;
- final Intent intent = entry.secondaryIntent;
+ if (entry == null || !(entry instanceof DetailViewEntry)) return;
+ final DetailViewEntry detailViewEntry = (DetailViewEntry) entry;
+ final Intent intent = detailViewEntry.secondaryIntent;
if (intent == null) return;
mListener.onItemClicked(intent);
}
@@ -1003,40 +1118,42 @@
@Override
public int getCount() {
- int count = 0;
- final int numSections = mSections.size();
- for (int i = 0; i < numSections; i++) {
- final ArrayList<ViewEntry> section = mSections.get(i);
- count += section.size();
- }
- return count;
+ return mAllEntries.size();
}
@Override
- public Object getItem(int position) {
- return getEntry(position);
+ public ViewEntry getItem(int position) {
+ return mAllEntries.get(position);
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ return mAllEntries.get(position).getViewType();
+ }
+
+ @Override
+ public int getViewTypeCount() {
+ return VIEW_TYPE_COUNT;
}
@Override
public long getItemId(int position) {
- final ViewEntry entry = getEntry(position);
+ final ViewEntry entry = mAllEntries.get(position);
if (entry != null) {
- return entry.id;
+ return entry.getId();
}
return -1;
}
- private ViewEntry getEntry(int position) {
- final int numSections = mSections.size();
- for (int i = 0; i < numSections; i++) {
- final ArrayList<ViewEntry> section = mSections.get(i);
- final int sectionSize = section.size();
- if (position < sectionSize) {
- return section.get(position);
- }
- position -= sectionSize;
- }
- return null;
+ @Override
+ public boolean areAllItemsEnabled() {
+ // Header will always be an item that is not enabled.
+ return false;
+ }
+
+ @Override
+ public boolean isEnabled(int position) {
+ return getItem(position).isEnabled();
}
}
@@ -1182,9 +1299,9 @@
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (mListener == null) return;
- final ViewEntry entry = mAdapter.getEntry(position);
- if (entry == null) return;
- final Intent intent = entry.intent;
+ final ViewEntry entry = mAdapter.getItem(position);
+ if (entry == null || !(entry instanceof DetailViewEntry)) return;
+ final Intent intent = ((DetailViewEntry) entry).intent;
if (intent == null) return;
mListener.onItemClicked(intent);
}
@@ -1220,7 +1337,7 @@
int index = mListView.getSelectedItemPosition();
if (index != -1) {
- final ViewEntry entry = mAdapter.getEntry(index);
+ final DetailViewEntry entry = (DetailViewEntry) mAdapter.getItem(index);
if (entry != null && entry.intent != null &&
entry.intent.getAction() == Intent.ACTION_CALL_PRIVILEGED) {
mContext.startActivity(entry.intent);
diff --git a/tests/src/com/android/contacts/detail/ContactDetailFragmentTests.java b/tests/src/com/android/contacts/detail/ContactDetailFragmentTests.java
index 4cee32c..cfab94a 100644
--- a/tests/src/com/android/contacts/detail/ContactDetailFragmentTests.java
+++ b/tests/src/com/android/contacts/detail/ContactDetailFragmentTests.java
@@ -16,7 +16,7 @@
package com.android.contacts.detail;
-import com.android.contacts.detail.ContactDetailFragment.ViewEntry;
+import com.android.contacts.detail.ContactDetailFragment.DetailViewEntry;
import android.content.ContentValues;
import android.content.Intent;
@@ -42,7 +42,7 @@
values.put(Im.PROTOCOL, Im.PROTOCOL_GOOGLE_TALK);
values.put(Im.DATA, TEST_ADDRESS);
- ViewEntry entry = new ContactDetailFragment.ViewEntry();
+ DetailViewEntry entry = new ContactDetailFragment.DetailViewEntry();
ContactDetailFragment.buildImActions(entry, values);
assertEquals(Intent.ACTION_SENDTO, entry.intent.getAction());
assertEquals("xmpp:" + TEST_ADDRESS + "?message", entry.intent.getData().toString());
@@ -59,7 +59,7 @@
values.put(Im.DATA, TEST_ADDRESS);
values.put(Im.CHAT_CAPABILITY, Im.CAPABILITY_HAS_VOICE | Im.CAPABILITY_HAS_VIDEO);
- ViewEntry entry = new ContactDetailFragment.ViewEntry();
+ DetailViewEntry entry = new ContactDetailFragment.DetailViewEntry();
ContactDetailFragment.buildImActions(entry, values);
assertEquals(Intent.ACTION_SENDTO, entry.intent.getAction());
assertEquals("xmpp:" + TEST_ADDRESS + "?message", entry.intent.getData().toString());
@@ -78,7 +78,7 @@
values.put(Im.CHAT_CAPABILITY, Im.CAPABILITY_HAS_VOICE | Im.CAPABILITY_HAS_VIDEO |
Im.CAPABILITY_HAS_VOICE);
- ViewEntry entry = new ContactDetailFragment.ViewEntry();
+ DetailViewEntry entry = new ContactDetailFragment.DetailViewEntry();
ContactDetailFragment.buildImActions(entry, values);
assertEquals(Intent.ACTION_SENDTO, entry.intent.getAction());
assertEquals("xmpp:" + TEST_ADDRESS + "?message", entry.intent.getData().toString());
@@ -97,7 +97,7 @@
values.put(Im.CUSTOM_PROTOCOL, TEST_PROTOCOL);
values.put(Im.DATA, TEST_ADDRESS);
- ViewEntry entry = new ContactDetailFragment.ViewEntry();
+ DetailViewEntry entry = new ContactDetailFragment.DetailViewEntry();
ContactDetailFragment.buildImActions(entry, values);
assertEquals(Intent.ACTION_SENDTO, entry.intent.getAction());
@@ -120,7 +120,7 @@
values.put(Email.CHAT_CAPABILITY, Im.CAPABILITY_HAS_VOICE | Im.CAPABILITY_HAS_VIDEO |
Im.CAPABILITY_HAS_VOICE);
- ViewEntry entry = new ContactDetailFragment.ViewEntry();
+ DetailViewEntry entry = new ContactDetailFragment.DetailViewEntry();
ContactDetailFragment.buildImActions(entry, values);
assertEquals(Intent.ACTION_SENDTO, entry.intent.getAction());
assertEquals("xmpp:" + TEST_ADDRESS + "?message", entry.intent.getData().toString());