Replace ListView with RecyclerView in call log.
Yay, finally!
+ Replace ListView with RecyclerView in layout and fragment files.
+ Change GroupingListAdapter to extend RecyclerView.Adapter instead
of BaseAdapter.
+ Change CallLogListItemViews to extend RecyclerView.ViewHolder.
+ Adapt onBindViewHolder and onCreateViewHolder methods in the
CallLogAdapter.
+ Update/rework tests for related classes.
+ Fix a bug in the GroupingListAdapter, where childCount was not
updated for standalone views, and the previously cached group size
was used instead. Set childCount to 1 for standalone views.
- Removed the idea of creating different views for standalone vs
group vs group headers from the adapters. This logic has not been
used for quite some time and all these functions funneled into
createView/bindView methods anyways, so there is no logical
difference. If we need to create custom views in the future, we can
leverage onCreateViewHolder's viewType parameter.
Bug: 19372817
Change-Id: I1b7289340600609669db22d8bc89265240d0b561
diff --git a/res/layout/call_log_fragment.xml b/res/layout/call_log_fragment.xml
index 74c6309..c126b77 100644
--- a/res/layout/call_log_fragment.xml
+++ b/res/layout/call_log_fragment.xml
@@ -61,18 +61,11 @@
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
- <!-- clipChildren=false is required to ensure shadows drawn
- within list items aren't clipped by the list item bounds. -->
- <ListView android:id="@android:id/list"
+
+ <android.support.v7.widget.RecyclerView android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:fadingEdge="none"
- android:scrollbarStyle="outsideOverlay"
- android:background="@color/background_dialer_list_items"
- android:divider="@null"
- android:nestedScrollingEnabled="true"
- android:clipChildren="false"
- />
+ android:background="@color/background_dialer_list_items" />
<include
android:id="@+id/empty_list_view"
diff --git a/src/com/android/dialer/calllog/CallLogAdapter.java b/src/com/android/dialer/calllog/CallLogAdapter.java
index fd6b37b..5d5145f 100644
--- a/src/com/android/dialer/calllog/CallLogAdapter.java
+++ b/src/com/android/dialer/calllog/CallLogAdapter.java
@@ -23,6 +23,7 @@
import android.net.Uri;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.PhoneLookup;
+import android.support.v7.widget.RecyclerView.ViewHolder;
import android.telecom.PhoneAccountHandle;
import android.telephony.PhoneNumberUtils;
import android.text.TextUtils;
@@ -225,13 +226,12 @@
mLoading = loading;
}
- @Override
public boolean isEmpty() {
if (mLoading) {
// We don't want the empty state to show when loading.
return false;
} else {
- return super.isEmpty();
+ return getItemCount() == 0;
}
}
@@ -262,48 +262,19 @@
}
@Override
- protected View newStandAloneView(Context context, ViewGroup parent) {
- return newChildView(context, parent);
- }
-
- @Override
- protected View newGroupView(Context context, ViewGroup parent) {
- return newChildView(context, parent);
- }
-
- @Override
- protected View newChildView(Context context, ViewGroup parent) {
- LayoutInflater inflater = LayoutInflater.from(context);
+ public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ LayoutInflater inflater = LayoutInflater.from(mContext);
View view = inflater.inflate(R.layout.call_log_list_item, parent, false);
// Get the views to bind to and cache them.
- CallLogListItemViews views = CallLogListItemViews.fromView(context, view);
+ CallLogListItemViews views = CallLogListItemViews.fromView(mContext, view);
view.setTag(views);
// Set text height to false on the TextViews so they don't have extra padding.
views.phoneCallDetailsViews.nameView.setElegantTextHeight(false);
views.phoneCallDetailsViews.callLocationAndDate.setElegantTextHeight(false);
- return view;
- }
-
- @Override
- protected void bindStandAloneView(View view, Context context, Cursor cursor) {
- bindView(view, cursor, 1);
- }
-
- @Override
- protected void bindChildView(View view, Context context, Cursor cursor) {
- bindView(view, cursor, 1);
- }
-
- @Override
- protected void bindGroupView(View view, Context context, Cursor cursor, int groupSize,
- boolean expanded) {
- bindView(view, cursor, groupSize);
- }
-
- private void findAndCacheViews(View view) {
+ return (CallLogListItemViews) view.getTag();
}
/**
@@ -312,12 +283,17 @@
* should not. It invokes cross-process methods and the repeat execution can get costly.
*
* @param callLogItemView the view corresponding to this entry
- * @param c the cursor pointing to the entry in the call log
* @param count the number of entries in the current item, greater than 1 if it is a group
*/
- public void bindView(View callLogItemView, Cursor c, int count) {
- callLogItemView.setAccessibilityDelegate(mAccessibilityDelegate);
- final CallLogListItemViews views = (CallLogListItemViews) callLogItemView.getTag();
+ public void onBindViewHolder(ViewHolder viewHolder, int position) {
+ Cursor c = (Cursor) getItem(position);
+ if (c == null) {
+ return;
+ }
+ int count = getGroupSize(position);
+
+ CallLogListItemViews views = (CallLogListItemViews) viewHolder;
+ views.rootView.setAccessibilityDelegate(mAccessibilityDelegate);
// Default case: an item in the call log.
views.primaryActionView.setVisibility(View.VISIBLE);
@@ -435,7 +411,7 @@
// Listen for the first draw
if (mViewTreeObserver == null) {
- mViewTreeObserver = callLogItemView.getViewTreeObserver();
+ mViewTreeObserver = views.rootView.getViewTreeObserver();
mViewTreeObserver.addOnPreDrawListener(this);
}
}
diff --git a/src/com/android/dialer/calllog/CallLogFragment.java b/src/com/android/dialer/calllog/CallLogFragment.java
index d69c2ed..4f4fc1b 100644
--- a/src/com/android/dialer/calllog/CallLogFragment.java
+++ b/src/com/android/dialer/calllog/CallLogFragment.java
@@ -21,8 +21,8 @@
import android.animation.ValueAnimator;
import android.app.Activity;
import android.app.DialogFragment;
+import android.app.Fragment;
import android.app.KeyguardManager;
-import android.app.ListFragment;
import android.content.Context;
import android.content.Intent;
import android.database.ContentObserver;
@@ -34,10 +34,11 @@
import android.provider.CallLog.Calls;
import android.provider.ContactsContract;
import android.provider.VoicemailContract.Status;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.LinearLayoutManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.view.ViewTreeObserver;
import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams;
import android.widget.ListView;
@@ -60,7 +61,7 @@
* Displays a list of call log entries. To filter for a particular kind of call
* (all, missed or voicemails), specify it in the constructor.
*/
-public class CallLogFragment extends ListFragment
+public class CallLogFragment extends Fragment
implements CallLogQueryHandler.Listener, CallLogAdapter.OnReportButtonClickListener,
CallLogAdapter.CallFetcher {
private static final String TAG = "CallLogFragment";
@@ -76,6 +77,8 @@
private static final String KEY_LOG_LIMIT = "log_limit";
private static final String KEY_DATE_LIMIT = "date_limit";
+ private RecyclerView mRecyclerView;
+ private LinearLayoutManager mLayoutManager;
private CallLogAdapter mAdapter;
private CallLogQueryHandler mCallLogQueryHandler;
private boolean mScrollToTop;
@@ -172,9 +175,6 @@
}
String currentCountryIso = GeoUtil.getCurrentCountryIso(getActivity());
- mAdapter = ObjectFactory.newCallLogAdapter(getActivity(), this,
- new ContactInfoHelper(getActivity(), currentCountryIso), this);
- setListAdapter(mAdapter);
mCallLogQueryHandler = new CallLogQueryHandler(getActivity().getContentResolver(),
this, mLogLimit);
mKeyguardManager =
@@ -201,9 +201,8 @@
// This will update the state of the "Clear call log" menu item.
getActivity().invalidateOptionsMenu();
- final ListView listView = getListView();
boolean showListView = cursor.getCount() > 0;
- listView.setVisibility(showListView ? View.VISIBLE : View.GONE);
+ mRecyclerView.setVisibility(showListView ? View.VISIBLE : View.GONE);
mEmptyListView.setVisibility(!showListView ? View.VISIBLE : View.GONE);
if (mScrollToTop) {
@@ -213,8 +212,9 @@
// will not experience the illusion of downward motion. Instead,
// if we're not already near the top of the list, we instantly jump
// near the top, and animate from there.
- if (listView.getFirstVisiblePosition() > 5) {
- listView.setSelection(5);
+ if (mLayoutManager.findFirstVisibleItemPosition() > 5) {
+ // TODO: Jump to near the top, then begin smooth scroll.
+ mRecyclerView.smoothScrollToPosition(0);
}
// Workaround for framework issue: the smooth-scroll doesn't
// occur if setSelection() is called immediately before.
@@ -224,7 +224,7 @@
if (getActivity() == null || getActivity().isFinishing()) {
return;
}
- listView.smoothScrollToPosition(0);
+ mRecyclerView.smoothScrollToPosition(0);
}
});
@@ -269,6 +269,17 @@
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) {
View view = inflater.inflate(R.layout.call_log_fragment, container, false);
+
+ mRecyclerView = (RecyclerView) view.findViewById(R.id.recycler_view);
+ mRecyclerView.setHasFixedSize(true);
+ mLayoutManager = new LinearLayoutManager(getActivity());
+ mRecyclerView.setLayoutManager(mLayoutManager);
+
+ String currentCountryIso = GeoUtil.getCurrentCountryIso(getActivity());
+ mAdapter = ObjectFactory.newCallLogAdapter(getActivity(), this,
+ new ContactInfoHelper(getActivity(), currentCountryIso), this);
+ mRecyclerView.setAdapter(mAdapter);
+
mVoicemailStatusHelper = new VoicemailStatusHelperImpl();
mStatusMessageView = view.findViewById(R.id.voicemail_status);
mStatusMessageText = (TextView) view.findViewById(R.id.voicemail_status_message);
@@ -280,7 +291,6 @@
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mEmptyListView = view.findViewById(R.id.empty_list_view);
- getListView().setItemsCanFocus(true);
updateEmptyMessage(mCallTypeFilter);
}
diff --git a/src/com/android/dialer/calllog/CallLogListItemViews.java b/src/com/android/dialer/calllog/CallLogListItemViews.java
index 9d11a3a..f2bed53 100644
--- a/src/com/android/dialer/calllog/CallLogListItemViews.java
+++ b/src/com/android/dialer/calllog/CallLogListItemViews.java
@@ -20,6 +20,7 @@
import android.content.res.Resources;
import android.net.Uri;
import android.provider.CallLog.Calls;
+import android.support.v7.widget.RecyclerView;
import android.telecom.PhoneAccountHandle;
import android.text.TextUtils;
import android.view.View;
@@ -44,7 +45,7 @@
* is a way of isolating view logic from the CallLogAdapter. We should consider moving that logic
* if the call log list item is eventually represented as a UI component.
*/
-public final class CallLogListItemViews {
+public final class CallLogListItemViews extends RecyclerView.ViewHolder {
/** The root view of the call log list item */
public final View rootView;
/** The quick contact badge for the contact. */
@@ -147,6 +148,7 @@
PhoneCallDetailsViews phoneCallDetailsViews,
View callLogEntryView,
TextView dayGroupHeader) {
+ super(rootView);
mContext = context;
this.rootView = rootView;
diff --git a/src/com/android/dialer/calllog/GroupingListAdapter.java b/src/com/android/dialer/calllog/GroupingListAdapter.java
index 7895549..501e88d 100644
--- a/src/com/android/dialer/calllog/GroupingListAdapter.java
+++ b/src/com/android/dialer/calllog/GroupingListAdapter.java
@@ -21,6 +21,8 @@
import android.database.Cursor;
import android.database.DataSetObserver;
import android.os.Handler;
+import android.support.v7.widget.RecyclerView;
+import android.util.Log;
import android.util.SparseIntArray;
import android.view.View;
import android.view.ViewGroup;
@@ -34,7 +36,7 @@
* The list has three types of elements: stand-alone, group header and group child. Groups are
* collapsible and collapsed by default. This is used by the call log to group related entries.
*/
-abstract class GroupingListAdapter extends BaseAdapter {
+abstract class GroupingListAdapter extends RecyclerView.Adapter {
private static final int GROUP_METADATA_ARRAY_INITIAL_SIZE = 16;
private static final int GROUP_METADATA_ARRAY_INCREMENT = 128;
@@ -109,11 +111,6 @@
public void onChanged() {
notifyDataSetChanged();
}
-
- @Override
- public void onInvalidated() {
- notifyDataSetInvalidated();
- }
};
public GroupingListAdapter(Context context) {
@@ -127,15 +124,7 @@
*/
protected abstract void addGroups(Cursor cursor);
- protected abstract View newStandAloneView(Context context, ViewGroup parent);
- protected abstract void bindStandAloneView(View view, Context context, Cursor cursor);
-
- protected abstract View newGroupView(Context context, ViewGroup parent);
- protected abstract void bindGroupView(View view, Context context, Cursor cursor, int groupSize,
- boolean expanded);
-
- protected abstract View newChildView(Context context, ViewGroup parent);
- protected abstract void bindChildView(View view, Context context, Cursor cursor);
+ protected abstract void onContentChanged();
/**
* Cache should be reset whenever the cursor changes or groups are expanded or collapsed.
@@ -149,9 +138,6 @@
mPositionCache.clear();
}
- protected void onContentChanged() {
- }
-
public void changeCursor(Cursor cursor) {
if (cursor == mCursor) {
return;
@@ -171,13 +157,10 @@
cursor.registerDataSetObserver(mDataSetObserver);
mRowIdColumnIndex = cursor.getColumnIndexOrThrow("_id");
notifyDataSetChanged();
- } else {
- // notify the observers about the lack of a data set
- notifyDataSetInvalidated();
}
-
}
+ @NeededForTesting
public Cursor getCursor() {
return mCursor;
}
@@ -231,7 +214,8 @@
return need;
}
- public int getCount() {
+ @Override
+ public int getItemCount() {
if (mCursor == null) {
return 0;
}
@@ -343,6 +327,7 @@
if (position < listPosition) {
metadata.itemType = ITEM_TYPE_STANDALONE;
metadata.cursorPosition = cursorPosition - (listPosition - position);
+ metadata.childCount = 1;
return;
}
@@ -382,6 +367,7 @@
// The required item is past the last group
metadata.itemType = ITEM_TYPE_STANDALONE;
metadata.cursorPosition = cursorPosition + (position - listPosition);
+ metadata.childCount = 1;
}
/**
@@ -421,12 +407,6 @@
notifyDataSetChanged();
}
- @Override
- public int getViewTypeCount() {
- return 3;
- }
-
- @Override
public int getItemViewType(int position) {
obtainPositionMetadata(mPositionMetadata, position);
return mPositionMetadata.itemType;
@@ -454,37 +434,16 @@
}
}
- public View getView(int position, View convertView, ViewGroup parent) {
- obtainPositionMetadata(mPositionMetadata, position);
- View view = convertView;
- if (view == null) {
- switch (mPositionMetadata.itemType) {
- case ITEM_TYPE_STANDALONE:
- view = newStandAloneView(mContext, parent);
- break;
- case ITEM_TYPE_GROUP_HEADER:
- view = newGroupView(mContext, parent);
- break;
- case ITEM_TYPE_IN_GROUP:
- view = newChildView(mContext, parent);
- break;
- }
+ /**
+ * Used for setting the cursor without triggering a UI thread update.
+ */
+ @NeededForTesting
+ public void setCursorForTesting(Cursor cursor) {
+ if (cursor != null) {
+ mCursor = cursor;
+ cursor.registerContentObserver(mChangeObserver);
+ cursor.registerDataSetObserver(mDataSetObserver);
+ mRowIdColumnIndex = cursor.getColumnIndexOrThrow("_id");
}
-
- mCursor.moveToPosition(mPositionMetadata.cursorPosition);
- switch (mPositionMetadata.itemType) {
- case ITEM_TYPE_STANDALONE:
- bindStandAloneView(view, mContext, mCursor);
- break;
- case ITEM_TYPE_GROUP_HEADER:
- bindGroupView(view, mContext, mCursor, mPositionMetadata.childCount,
- mPositionMetadata.isExpanded);
- break;
- case ITEM_TYPE_IN_GROUP:
- bindChildView(view, mContext, mCursor);
- break;
-
- }
- return view;
}
}
diff --git a/tests/src/com/android/dialer/calllog/CallLogAdapterTest.java b/tests/src/com/android/dialer/calllog/CallLogAdapterTest.java
index 845e279..bffbe5c 100644
--- a/tests/src/com/android/dialer/calllog/CallLogAdapterTest.java
+++ b/tests/src/com/android/dialer/calllog/CallLogAdapterTest.java
@@ -87,7 +87,8 @@
mCursor.addRow(createCallLogEntry());
// Bind the views of a single row.
- mAdapter.bindStandAloneView(mView, getContext(), mCursor);
+ mAdapter.changeCursor(mCursor);
+ mAdapter.onBindViewHolder(CallLogListItemViews.fromView(getContext(), mView), 0);
// There is one request for contact details.
assertEquals(1, mAdapter.getContactInfoCache().requests.size());
@@ -105,7 +106,8 @@
mCursor.addRow(createCallLogEntryWithCachedValues());
// Bind the views of a single row.
- mAdapter.bindStandAloneView(mView, getContext(), mCursor);
+ mAdapter.changeCursor(mCursor);
+ mAdapter.onBindViewHolder(CallLogListItemViews.fromView(getContext(), mView), 0);
// There is one request for contact details.
assertEquals(1, mAdapter.getContactInfoCache().requests.size());
@@ -123,7 +125,9 @@
mAdapter.injectContactInfoForTest(TEST_NUMBER, TEST_COUNTRY_ISO, createContactInfo());
// Bind the views of a single row.
- mAdapter.bindStandAloneView(mView, getContext(), mCursor);
+ mAdapter.changeCursor(mCursor);
+ mAdapter.onBindViewHolder(
+ CallLogListItemViews.fromView(getContext(), mView), 0);
// There is one request for contact details.
assertEquals(1, mAdapter.getContactInfoCache().requests.size());
@@ -138,7 +142,8 @@
mAdapter.injectContactInfoForTest(TEST_NUMBER, TEST_COUNTRY_ISO, createContactInfo());
// Bind the views of a single row.
- mAdapter.bindStandAloneView(mView, getContext(), mCursor);
+ mAdapter.changeCursor(mCursor);
+ mAdapter.onBindViewHolder(CallLogListItemViews.fromView(getContext(), mView), 0);
// Cache and call log are up-to-date: no need to request update.
assertEquals(0, mAdapter.getContactInfoCache().requests.size());
@@ -153,7 +158,8 @@
mAdapter.injectContactInfoForTest(TEST_NUMBER, TEST_COUNTRY_ISO, info);
// Bind the views of a single row.
- mAdapter.bindStandAloneView(mView, getContext(), mCursor);
+ mAdapter.changeCursor(mCursor);
+ mAdapter.onBindViewHolder(CallLogListItemViews.fromView(getContext(), mView), 0);
// There is one request for contact details.
assertEquals(1, mAdapter.getContactInfoCache().requests.size());
diff --git a/tests/src/com/android/dialer/calllog/CallLogFragmentTest.java b/tests/src/com/android/dialer/calllog/CallLogFragmentTest.java
index b57489d..fe14f87 100644
--- a/tests/src/com/android/dialer/calllog/CallLogFragmentTest.java
+++ b/tests/src/com/android/dialer/calllog/CallLogFragmentTest.java
@@ -30,6 +30,7 @@
import android.provider.CallLog.Calls;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.VoicemailContract;
+import android.support.v7.widget.RecyclerView.ViewHolder;
import android.telephony.PhoneNumberUtils;
import android.telephony.TelephonyManager;
import android.test.ActivityInstrumentationTestCase2;
@@ -94,9 +95,9 @@
// An item in the call list. All the methods performing checks use it.
private CallLogListItemViews mItem;
- // The list of views representing the data in the DB. View are in
- // reverse order compare to the DB.
- private View[] mList;
+
+ // The list of view holderss representing the data in the DB, in reverse order from the DB.
+ private ViewHolder[] mList;
public CallLogFragmentTest() {
super(FragmentTestActivity.class);
@@ -129,6 +130,7 @@
mAdapter.pauseCache();
mParentView = new FrameLayout(mActivity);
mCursor = new MatrixCursor(CallLogQuery._PROJECTION);
+ mAdapter.setCursorForTesting(mCursor);
}
/**
@@ -140,7 +142,7 @@
@MediumTest
public void testCallViewIsNotVisibleForPrivateAndUnknownNumbers() {
final int SIZE = 100;
- mList = new View[SIZE];
+ mList = new ViewHolder[SIZE];
// Insert the first batch of entries.
mCursor.moveToFirst();
@@ -168,34 +170,34 @@
insertPrivate(NOW, 0);
insertPrivate(NOW, 0);
insertPrivate(NOW, 0);
- View view = mAdapter.newGroupView(getActivity(), mParentView);
- mAdapter.bindGroupView(view, getActivity(), mCursor, 3, false);
+ ViewHolder viewHolder = mAdapter.onCreateViewHolder(mParentView, /* viewType */ 0);
+ mAdapter.onBindViewHolder(viewHolder, /* position */ 0);
}
@MediumTest
public void testCallAndGroupViews_StandAloneView() {
mCursor.moveToFirst();
insertPrivate(NOW, 0);
- View view = mAdapter.newStandAloneView(getActivity(), mParentView);
- bindViewForTest(view, mCursor);
+ ViewHolder viewHolder = mAdapter.onCreateViewHolder(mParentView, 0);
+ bindViewForTest(viewHolder);
}
@MediumTest
public void testCallAndGroupViews_ChildView() {
mCursor.moveToFirst();
insertPrivate(NOW, 0);
- View view = mAdapter.newChildView(getActivity(), mParentView);
- mAdapter.bindChildView(view, getActivity(), mCursor);
+ ViewHolder viewHolder = mAdapter.onCreateViewHolder(mParentView, /* viewType */ 0);
+ mAdapter.onBindViewHolder(viewHolder, /* position */ 0);
}
@MediumTest
public void testBindView_NumberOnlyNoCache() {
mCursor.moveToFirst();
insert(TEST_NUMBER, Calls.PRESENTATION_ALLOWED, NOW, 0, Calls.INCOMING_TYPE);
- View view = mAdapter.newStandAloneView(getActivity(), mParentView);
- bindViewForTest(view, mCursor);
+ ViewHolder viewHolder = mAdapter.onCreateViewHolder(mParentView, /* viewType */ 0);
+ bindViewForTest(viewHolder);
- CallLogListItemViews views = (CallLogListItemViews) view.getTag();
+ CallLogListItemViews views = (CallLogListItemViews) viewHolder;
assertNameIs(views, TEST_NUMBER);
}
@@ -206,10 +208,10 @@
Calls.PRESENTATION_ALLOWED, NOW, 0, Calls.INCOMING_TYPE);
values[CallLogQuery.CACHED_FORMATTED_NUMBER] = TEST_FORMATTED_NUMBER;
insertValues(values);
- View view = mAdapter.newStandAloneView(getActivity(), mParentView);
- bindViewForTest(view, mCursor);
+ ViewHolder viewHolder = mAdapter.onCreateViewHolder(mParentView, /* viewType */ 0);
+ bindViewForTest(viewHolder);
- CallLogListItemViews views = (CallLogListItemViews) view.getTag();
+ CallLogListItemViews views = (CallLogListItemViews) viewHolder;
assertNameIs(views, TEST_FORMATTED_NUMBER);
}
@@ -220,10 +222,10 @@
// {@value com.android.dialer.calllog.ContactInfo#GEOCODE_AS_LABEL}
insertWithCachedValues(TEST_NUMBER, NOW, 0, Calls.INCOMING_TYPE,
"John Doe", Phone.TYPE_HOME, TEST_DEFAULT_CUSTOM_LABEL);
- View view = mAdapter.newStandAloneView(getActivity(), mParentView);
- bindViewForTest(view, mCursor);
+ ViewHolder viewHolder = mAdapter.onCreateViewHolder(mParentView, /* viewType */ 0);
+ bindViewForTest(viewHolder);
- CallLogListItemViews views = (CallLogListItemViews) view.getTag();
+ CallLogListItemViews views = (CallLogListItemViews) viewHolder;
assertNameIs(views, "John Doe");
assertLabel(views, TEST_FORMATTED_NUMBER, getTypeLabel(Phone.TYPE_HOME));
}
@@ -233,10 +235,10 @@
mCursor.moveToFirst();
insertWithCachedValues("sip:johndoe@gmail.com", NOW, 0, Calls.INCOMING_TYPE,
"John Doe", Phone.TYPE_HOME, TEST_DEFAULT_CUSTOM_LABEL);
- View view = mAdapter.newStandAloneView(getActivity(), mParentView);
- bindViewForTest(view, mCursor);
+ ViewHolder viewHolder = mAdapter.onCreateViewHolder(mParentView, /* viewType */ 0);
+ bindViewForTest(viewHolder);
- CallLogListItemViews views = (CallLogListItemViews) view.getTag();
+ CallLogListItemViews views = (CallLogListItemViews) viewHolder;
assertNameIs(views, "John Doe");
assertLabel(views, "sip:johndoe@gmail.com", "sip:johndoe@gmail.com");
}
@@ -248,10 +250,10 @@
// {@value com.android.dialer.calllog.ContactInfo#GEOCODE_AS_LABEL}
insertWithCachedValues(TEST_NUMBER, NOW, 0, Calls.INCOMING_TYPE,
"John Doe", Phone.TYPE_HOME, TEST_DEFAULT_CUSTOM_LABEL);
- View view = mAdapter.newStandAloneView(getActivity(), mParentView);
- bindViewForTest(view, mCursor);
+ ViewHolder viewHolder = mAdapter.onCreateViewHolder(mParentView, /* viewType */ 0);
+ bindViewForTest(viewHolder);
- CallLogListItemViews views = (CallLogListItemViews) view.getTag();
+ CallLogListItemViews views = (CallLogListItemViews) viewHolder;
assertNameIs(views, "John Doe");
assertLabel(views, TEST_FORMATTED_NUMBER, getTypeLabel(Phone.TYPE_HOME));
}
@@ -263,10 +265,10 @@
// {@link com.android.dialer.calllog.ContactInfo#GEOCODE_AS_LABEL}
insertWithCachedValues(TEST_NUMBER, NOW, 0, Calls.INCOMING_TYPE,
"John Doe", Phone.TYPE_WORK, TEST_DEFAULT_CUSTOM_LABEL);
- View view = mAdapter.newStandAloneView(getActivity(), mParentView);
- bindViewForTest(view, mCursor);
+ ViewHolder viewHolder = mAdapter.onCreateViewHolder(mParentView, /* viewType */ 0);
+ bindViewForTest(viewHolder);
- CallLogListItemViews views = (CallLogListItemViews) view.getTag();
+ CallLogListItemViews views = (CallLogListItemViews) viewHolder;
assertNameIs(views, "John Doe");
assertLabel(views, TEST_FORMATTED_NUMBER, getTypeLabel(Phone.TYPE_WORK));
}
@@ -277,10 +279,10 @@
String numberLabel = "My label";
insertWithCachedValues(TEST_NUMBER, NOW, 0, Calls.INCOMING_TYPE,
"John Doe", Phone.TYPE_CUSTOM, numberLabel);
- View view = mAdapter.newStandAloneView(getActivity(), mParentView);
- bindViewForTest(view, mCursor);
+ ViewHolder viewHolder = mAdapter.onCreateViewHolder(mParentView, /* viewType */ 0);
+ bindViewForTest(viewHolder);
- CallLogListItemViews views = (CallLogListItemViews) view.getTag();
+ CallLogListItemViews views = (CallLogListItemViews) viewHolder;
assertNameIs(views, "John Doe");
assertLabel(views, TEST_FORMATTED_NUMBER, numberLabel);
}
@@ -290,10 +292,10 @@
mCursor.moveToFirst();
insertWithCachedValues(TEST_NUMBER, NOW, 0, Calls.INCOMING_TYPE,
"John Doe", Phone.TYPE_HOME, "");
- View view = mAdapter.newStandAloneView(getActivity(), mParentView);
- bindViewForTest(view, mCursor);
+ ViewHolder viewHolder = mAdapter.onCreateViewHolder(mParentView, /* viewType */ 0);
+ bindViewForTest(viewHolder);
- CallLogListItemViews views = (CallLogListItemViews) view.getTag();
+ CallLogListItemViews views = (CallLogListItemViews) viewHolder;
assertTrue(views.quickContactView.isEnabled());
}
@@ -301,10 +303,10 @@
public void testBindView_WithoutQuickContactBadge() {
mCursor.moveToFirst();
insert(TEST_NUMBER, Calls.PRESENTATION_ALLOWED, NOW, 0, Calls.INCOMING_TYPE);
- View view = mAdapter.newStandAloneView(getActivity(), mParentView);
- bindViewForTest(view, mCursor);
+ ViewHolder viewHolder = mAdapter.onCreateViewHolder(mParentView, /* viewType */ 0);
+ bindViewForTest(viewHolder);
- CallLogListItemViews views = (CallLogListItemViews) view.getTag();
+ CallLogListItemViews views = (CallLogListItemViews) viewHolder;
assertFalse(views.quickContactView.isEnabled());
}
@@ -312,10 +314,11 @@
public void testBindView_CallButton() {
mCursor.moveToFirst();
insert(TEST_NUMBER, Calls.PRESENTATION_ALLOWED, NOW, 0, Calls.INCOMING_TYPE);
- View view = mAdapter.newStandAloneView(getActivity(), mParentView);
- bindViewForTest(view, mCursor);
+ mAdapter.changeCursor(mCursor);
+ ViewHolder viewHolder = mAdapter.onCreateViewHolder(mParentView, /* viewType */ 0);
+ bindViewForTest(viewHolder);
- CallLogListItemViews views = (CallLogListItemViews) view.getTag();
+ CallLogListItemViews views = (CallLogListItemViews) viewHolder;
// The primaryActionView tag is set in the
// {@link com.android.dialer.calllog.CallLogAdapter#bindView} method. If it is possible
@@ -333,10 +336,10 @@
public void testBindView_PlayButton() {
mCursor.moveToFirst();
insertVoicemail(TEST_NUMBER, Calls.PRESENTATION_ALLOWED, NOW, 0);
- View view = mAdapter.newStandAloneView(getActivity(), mParentView);
- bindViewForTest(view, mCursor);
+ ViewHolder viewHolder = mAdapter.onCreateViewHolder(mParentView, /* viewType */ 0);
+ bindViewForTest(viewHolder);
- CallLogListItemViews views = (CallLogListItemViews) view.getTag();
+ CallLogListItemViews views = (CallLogListItemViews) viewHolder;
IntentProvider intentProvider = (IntentProvider) views.voicemailButtonView.getTag();
Intent intent = intentProvider.getIntent(mActivity);
// Starts the call detail activity.
@@ -372,7 +375,7 @@
if (null == mList[i]) {
break;
}
- mItem = (CallLogListItemViews) mList[i].getTag();
+ mItem = (CallLogListItemViews) mList[i];
int presentation = getPhoneNumberPresentationForListEntry(i);
if (presentation == Calls.PRESENTATION_RESTRICTED ||
presentation == Calls.PRESENTATION_UNKNOWN) {
@@ -420,11 +423,12 @@
private void buildViewListFromDb() {
int i = 0;
mCursor.moveToLast();
- while(!mCursor.isBeforeFirst()) {
+ while (!mCursor.isBeforeFirst()) {
if (null == mList[i]) {
- mList[i] = mAdapter.newStandAloneView(mActivity, mParentView);
+ mList[i] = mAdapter.onCreateViewHolder(mParentView, /* itemType */ 0);
}
- bindViewForTest(mList[i], mCursor);
+ // Bind to the proper position, despite iterating in reverse.
+ bindViewForTest(mList[i], mCursor.getCount() - i - 1);
mCursor.moveToPrevious();
i++;
}
@@ -446,12 +450,15 @@
* unit tests can access the buttons contained within.
*
* @param view The current call log row.
- * @param cursor The cursor to bind from.
+ * @param position The position of hte item.
*/
- private void bindViewForTest(View view, MatrixCursor cursor) {
- mAdapter.bindView(view, cursor, /* count */ 1);
- CallLogListItemViews views = (CallLogListItemViews) view.getTag();
- mAdapter.expandItem(views, /* expand */ true);
+ private void bindViewForTest(ViewHolder viewHolder, int position) {
+ mAdapter.onBindViewHolder(viewHolder, position);
+ mAdapter.expandItem((CallLogListItemViews) viewHolder, /* expand */ true);
+ }
+
+ private void bindViewForTest(ViewHolder viewHolder) {
+ bindViewForTest(viewHolder, /* position */ 0);
}
/**
diff --git a/tests/src/com/android/dialer/calllog/GroupingListAdapterTests.java b/tests/src/com/android/dialer/calllog/GroupingListAdapterTests.java
index 3eb5f06..53583e0 100644
--- a/tests/src/com/android/dialer/calllog/GroupingListAdapterTests.java
+++ b/tests/src/com/android/dialer/calllog/GroupingListAdapterTests.java
@@ -23,6 +23,7 @@
import android.content.Context;
import android.database.Cursor;
import android.database.MatrixCursor;
+import android.support.v7.widget.RecyclerView;
import android.test.AndroidTestCase;
import android.text.TextUtils;
import android.view.View;
@@ -34,7 +35,7 @@
* Running all tests:
*
* adb shell am instrument -e class com.android.dialer.calllog.GroupingListAdapterTests \
- * -w com.google.android.dialer.tests/android.test.InstrumentationTestRunner
+ * -w com.android.dialer.tests/android.test.InstrumentationTestRunner
*/
public class GroupingListAdapterTests extends AndroidTestCase {
@@ -76,34 +77,22 @@
}
@Override
- protected void bindChildView(View view, Context context, Cursor cursor) {
+ public void onContentChanged() {
+ // Do nothing.
}
@Override
- protected void bindGroupView(View view, Context context, Cursor cursor, int groupSize,
- boolean expanded) {
- }
-
- @Override
- protected void bindStandAloneView(View view, Context context, Cursor cursor) {
- }
-
- @Override
- protected View newChildView(Context context, ViewGroup parent) {
+ public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int position) {
return null;
}
@Override
- protected View newGroupView(Context context, ViewGroup parent) {
- return null;
- }
-
- @Override
- protected View newStandAloneView(Context context, ViewGroup parent) {
- return null;
+ public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
+ // Do nothing.
}
};
+
private void buildCursor(String... numbers) {
mCursor = new MatrixCursor(PROJECTION);
mNextId = 1;
@@ -117,7 +106,7 @@
buildCursor("1", "2", "3");
mAdapter.changeCursor(mCursor);
- assertEquals(3, mAdapter.getCount());
+ assertEquals(3, mAdapter.getItemCount());
assertPositionMetadata(0, ITEM_TYPE_STANDALONE, false, 0);
assertPositionMetadata(1, ITEM_TYPE_STANDALONE, false, 1);
assertPositionMetadata(2, ITEM_TYPE_STANDALONE, false, 2);
@@ -127,7 +116,7 @@
buildCursor("1", "1", "2");
mAdapter.changeCursor(mCursor);
- assertEquals(2, mAdapter.getCount());
+ assertEquals(2, mAdapter.getItemCount());
assertPositionMetadata(0, ITEM_TYPE_GROUP_HEADER, false, 0);
assertPositionMetadata(1, ITEM_TYPE_STANDALONE, false, 2);
}
@@ -137,7 +126,7 @@
mAdapter.changeCursor(mCursor);
mAdapter.toggleGroup(0);
- assertEquals(4, mAdapter.getCount());
+ assertEquals(4, mAdapter.getItemCount());
assertPositionMetadata(0, ITEM_TYPE_GROUP_HEADER, true, 0);
assertPositionMetadata(1, ITEM_TYPE_IN_GROUP, false, 0);
assertPositionMetadata(2, ITEM_TYPE_IN_GROUP, false, 1);
@@ -150,7 +139,7 @@
mAdapter.toggleGroup(0);
mAdapter.toggleGroup(0);
- assertEquals(2, mAdapter.getCount());
+ assertEquals(2, mAdapter.getItemCount());
assertPositionMetadata(0, ITEM_TYPE_GROUP_HEADER, false, 0);
assertPositionMetadata(1, ITEM_TYPE_STANDALONE, false, 2);
}
@@ -159,7 +148,7 @@
buildCursor("1", "2", "2", "2", "3");
mAdapter.changeCursor(mCursor);
- assertEquals(3, mAdapter.getCount());
+ assertEquals(3, mAdapter.getItemCount());
assertPositionMetadata(0, ITEM_TYPE_STANDALONE, false, 0);
assertPositionMetadata(1, ITEM_TYPE_GROUP_HEADER, false, 1);
assertPositionMetadata(2, ITEM_TYPE_STANDALONE, false, 4);
@@ -170,7 +159,7 @@
mAdapter.changeCursor(mCursor);
mAdapter.toggleGroup(1);
- assertEquals(6, mAdapter.getCount());
+ assertEquals(6, mAdapter.getItemCount());
assertPositionMetadata(0, ITEM_TYPE_STANDALONE, false, 0);
assertPositionMetadata(1, ITEM_TYPE_GROUP_HEADER, true, 1);
assertPositionMetadata(2, ITEM_TYPE_IN_GROUP, false, 1);
@@ -183,7 +172,7 @@
buildCursor("1", "2", "3", "3", "3");
mAdapter.changeCursor(mCursor);
- assertEquals(3, mAdapter.getCount());
+ assertEquals(3, mAdapter.getItemCount());
assertPositionMetadata(0, ITEM_TYPE_STANDALONE, false, 0);
assertPositionMetadata(1, ITEM_TYPE_STANDALONE, false, 1);
assertPositionMetadata(2, ITEM_TYPE_GROUP_HEADER, false, 2);
@@ -194,7 +183,7 @@
mAdapter.changeCursor(mCursor);
mAdapter.toggleGroup(2);
- assertEquals(6, mAdapter.getCount());
+ assertEquals(6, mAdapter.getItemCount());
assertPositionMetadata(0, ITEM_TYPE_STANDALONE, false, 0);
assertPositionMetadata(1, ITEM_TYPE_STANDALONE, false, 1);
assertPositionMetadata(2, ITEM_TYPE_GROUP_HEADER, true, 2);
@@ -207,7 +196,7 @@
buildCursor("1", "2", "2", "3", "4", "4", "5", "5", "6");
mAdapter.changeCursor(mCursor);
- assertEquals(6, mAdapter.getCount());
+ assertEquals(6, mAdapter.getItemCount());
assertPositionMetadata(0, ITEM_TYPE_STANDALONE, false, 0);
assertPositionMetadata(1, ITEM_TYPE_GROUP_HEADER, false, 1);
assertPositionMetadata(2, ITEM_TYPE_STANDALONE, false, 3);
@@ -225,7 +214,7 @@
// 4th to the 6th position
mAdapter.toggleGroup(6);
- assertEquals(10, mAdapter.getCount());
+ assertEquals(10, mAdapter.getItemCount());
assertPositionMetadata(0, ITEM_TYPE_STANDALONE, false, 0);
assertPositionMetadata(1, ITEM_TYPE_GROUP_HEADER, true, 1);
assertPositionMetadata(2, ITEM_TYPE_IN_GROUP, false, 1);
@@ -243,7 +232,7 @@
mAdapter.changeCursor(mCursor);
// First pass - building up cache
- assertEquals(6, mAdapter.getCount());
+ assertEquals(6, mAdapter.getItemCount());
assertPositionMetadata(0, ITEM_TYPE_STANDALONE, false, 0);
assertPositionMetadata(1, ITEM_TYPE_GROUP_HEADER, false, 1);
assertPositionMetadata(2, ITEM_TYPE_STANDALONE, false, 3);
@@ -252,7 +241,7 @@
assertPositionMetadata(5, ITEM_TYPE_STANDALONE, false, 8);
// Second pass - using cache
- assertEquals(6, mAdapter.getCount());
+ assertEquals(6, mAdapter.getItemCount());
assertPositionMetadata(0, ITEM_TYPE_STANDALONE, false, 0);
assertPositionMetadata(1, ITEM_TYPE_GROUP_HEADER, false, 1);
assertPositionMetadata(2, ITEM_TYPE_STANDALONE, false, 3);
@@ -295,7 +284,7 @@
buildCursor(numbers);
mAdapter.changeCursor(mCursor);
- assertEquals(250, mAdapter.getCount());
+ assertEquals(250, mAdapter.getItemCount());
}
private void assertPositionMetadata(int position, int itemType, boolean isExpanded,