diff options
Diffstat (limited to 'src')
4 files changed, 60 insertions, 113 deletions
diff --git a/src/com/android/dialer/calllog/CallLogAdapter.java b/src/com/android/dialer/calllog/CallLogAdapter.java index fd6b37b8c..5d5145fe4 100644 --- a/src/com/android/dialer/calllog/CallLogAdapter.java +++ b/src/com/android/dialer/calllog/CallLogAdapter.java @@ -23,6 +23,7 @@ import android.database.Cursor; 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 @@ public class CallLogAdapter extends GroupingListAdapter 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 @@ public class CallLogAdapter extends GroupingListAdapter } @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 @@ public class CallLogAdapter extends GroupingListAdapter * 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 @@ public class CallLogAdapter extends GroupingListAdapter // 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 d69c2ed7e..4f4fc1b94 100644 --- a/src/com/android/dialer/calllog/CallLogFragment.java +++ b/src/com/android/dialer/calllog/CallLogFragment.java @@ -21,8 +21,8 @@ import android.animation.AnimatorListenerAdapter; 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; 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 @@ import java.util.List; * 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 @@ public class CallLogFragment extends ListFragment 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 @@ public class CallLogFragment extends ListFragment } 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 @@ public class CallLogFragment extends ListFragment // 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 @@ public class CallLogFragment extends ListFragment // 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 @@ public class CallLogFragment extends ListFragment if (getActivity() == null || getActivity().isFinishing()) { return; } - listView.smoothScrollToPosition(0); + mRecyclerView.smoothScrollToPosition(0); } }); @@ -269,6 +269,17 @@ public class CallLogFragment extends ListFragment @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 class CallLogFragment extends ListFragment 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 9d11a3ab6..f2bed531f 100644 --- a/src/com/android/dialer/calllog/CallLogListItemViews.java +++ b/src/com/android/dialer/calllog/CallLogListItemViews.java @@ -20,6 +20,7 @@ import android.content.Context; 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 @@ import com.android.dialer.R; * 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 @@ public final class CallLogListItemViews { 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 78955492e..501e88df0 100644 --- a/src/com/android/dialer/calllog/GroupingListAdapter.java +++ b/src/com/android/dialer/calllog/GroupingListAdapter.java @@ -21,6 +21,8 @@ import android.database.ContentObserver; 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 @@ import com.android.contacts.common.testing.NeededForTesting; * 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 @@ abstract class GroupingListAdapter extends BaseAdapter { public void onChanged() { notifyDataSetChanged(); } - - @Override - public void onInvalidated() { - notifyDataSetInvalidated(); - } }; public GroupingListAdapter(Context context) { @@ -127,15 +124,7 @@ abstract class GroupingListAdapter extends BaseAdapter { */ 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 @@ abstract class GroupingListAdapter extends BaseAdapter { mPositionCache.clear(); } - protected void onContentChanged() { - } - public void changeCursor(Cursor cursor) { if (cursor == mCursor) { return; @@ -171,13 +157,10 @@ abstract class GroupingListAdapter extends BaseAdapter { 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 @@ abstract class GroupingListAdapter extends BaseAdapter { return need; } - public int getCount() { + @Override + public int getItemCount() { if (mCursor == null) { return 0; } @@ -343,6 +327,7 @@ abstract class GroupingListAdapter extends BaseAdapter { if (position < listPosition) { metadata.itemType = ITEM_TYPE_STANDALONE; metadata.cursorPosition = cursorPosition - (listPosition - position); + metadata.childCount = 1; return; } @@ -382,6 +367,7 @@ abstract class GroupingListAdapter extends BaseAdapter { // 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 @@ abstract class GroupingListAdapter extends BaseAdapter { notifyDataSetChanged(); } - @Override - public int getViewTypeCount() { - return 3; - } - - @Override public int getItemViewType(int position) { obtainPositionMetadata(mPositionMetadata, position); return mPositionMetadata.itemType; @@ -454,37 +434,16 @@ abstract class GroupingListAdapter extends BaseAdapter { } } - 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; - } - } - - 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; - + /** + * 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"); } - return view; } } |