NewCallLogAdapter.java revision a0df9f7f52b4d7f926581f30bd0a7774a6abac43
1/* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16package com.android.dialer.calllog.ui; 17 18import android.database.Cursor; 19import android.support.annotation.IntDef; 20import android.support.annotation.Nullable; 21import android.support.v7.widget.RecyclerView; 22import android.support.v7.widget.RecyclerView.ViewHolder; 23import android.view.LayoutInflater; 24import android.view.ViewGroup; 25import com.android.dialer.calllogutils.CallLogDates; 26import com.android.dialer.common.Assert; 27import com.android.dialer.time.Clock; 28import java.lang.annotation.Retention; 29import java.lang.annotation.RetentionPolicy; 30 31/** {@link RecyclerView.Adapter} for the new call log fragment. */ 32final class NewCallLogAdapter extends RecyclerView.Adapter<ViewHolder> { 33 34 /** IntDef for the different types of rows that can be shown in the call log. */ 35 @Retention(RetentionPolicy.SOURCE) 36 @IntDef({RowType.HEADER_TODAY, RowType.HEADER_OLDER, RowType.CALL_LOG_ENTRY}) 37 @interface RowType { 38 /** Header that displays "Today". */ 39 int HEADER_TODAY = 1; 40 /** Header that displays "Older". */ 41 int HEADER_OLDER = 2; 42 /** A row representing a call log entry (which could represent one or more calls). */ 43 int CALL_LOG_ENTRY = 3; 44 } 45 46 private final Cursor cursor; 47 private final Clock clock; 48 49 /** Null when the "Today" header should not be displayed. */ 50 @Nullable private final Integer todayHeaderPosition; 51 /** Null when the "Older" header should not be displayed. */ 52 @Nullable private final Integer olderHeaderPosition; 53 54 NewCallLogAdapter(Cursor cursor, Clock clock) { 55 this.cursor = cursor; 56 this.clock = clock; 57 58 // Calculate header adapter positions by reading cursor. 59 long currentTimeMillis = clock.currentTimeMillis(); 60 if (cursor.moveToNext()) { 61 long firstTimestamp = CoalescedAnnotatedCallLogCursorLoader.getTimestamp(cursor); 62 if (CallLogDates.isSameDay(currentTimeMillis, firstTimestamp)) { 63 this.todayHeaderPosition = 0; 64 int adapterPosition = 2; // Accounted for "Today" header and first row. 65 while (cursor.moveToNext()) { 66 long timestamp = CoalescedAnnotatedCallLogCursorLoader.getTimestamp(cursor); 67 68 if (CallLogDates.isSameDay(currentTimeMillis, timestamp)) { 69 adapterPosition++; 70 } else { 71 this.olderHeaderPosition = adapterPosition; 72 return; 73 } 74 } 75 this.olderHeaderPosition = null; // Didn't find any "Older" rows. 76 } else { 77 this.todayHeaderPosition = null; // Didn't find any "Today" rows. 78 this.olderHeaderPosition = 0; 79 } 80 } else { // There are no rows, just need to set these because they are final. 81 this.todayHeaderPosition = null; 82 this.olderHeaderPosition = null; 83 } 84 } 85 86 @Override 87 public ViewHolder onCreateViewHolder(ViewGroup viewGroup, @RowType int viewType) { 88 switch (viewType) { 89 case RowType.HEADER_TODAY: 90 case RowType.HEADER_OLDER: 91 return new HeaderViewHolder( 92 LayoutInflater.from(viewGroup.getContext()) 93 .inflate(R.layout.new_call_log_header, viewGroup, false)); 94 case RowType.CALL_LOG_ENTRY: 95 return new NewCallLogViewHolder( 96 LayoutInflater.from(viewGroup.getContext()) 97 .inflate(R.layout.new_call_log_entry, viewGroup, false), 98 clock); 99 default: 100 throw Assert.createUnsupportedOperationFailException("Unsupported view type: " + viewType); 101 } 102 } 103 104 @Override 105 public void onBindViewHolder(ViewHolder viewHolder, int position) { 106 if (viewHolder instanceof HeaderViewHolder) { 107 HeaderViewHolder headerViewHolder = (HeaderViewHolder) viewHolder; 108 @RowType int viewType = getItemViewType(position); 109 if (viewType == RowType.HEADER_OLDER) { 110 headerViewHolder.setHeader(R.string.new_call_log_header_older); 111 } else if (viewType == RowType.HEADER_TODAY) { 112 headerViewHolder.setHeader(R.string.new_call_log_header_today); 113 } else { 114 throw Assert.createIllegalStateFailException( 115 "Unexpected view type " + viewType + " at position: " + position); 116 } 117 return; 118 } 119 NewCallLogViewHolder newCallLogViewHolder = (NewCallLogViewHolder) viewHolder; 120 int previousHeaders = 0; 121 if (todayHeaderPosition != null && position > todayHeaderPosition) { 122 previousHeaders++; 123 } 124 if (olderHeaderPosition != null && position > olderHeaderPosition) { 125 previousHeaders++; 126 } 127 cursor.moveToPosition(position - previousHeaders); 128 newCallLogViewHolder.bind(cursor); 129 } 130 131 @Override 132 @RowType 133 public int getItemViewType(int position) { 134 if (todayHeaderPosition != null && position == todayHeaderPosition) { 135 return RowType.HEADER_TODAY; 136 } 137 if (olderHeaderPosition != null && position == olderHeaderPosition) { 138 return RowType.HEADER_OLDER; 139 } 140 return RowType.CALL_LOG_ENTRY; 141 } 142 143 @Override 144 public int getItemCount() { 145 int numberOfHeaders = 0; 146 if (todayHeaderPosition != null) { 147 numberOfHeaders++; 148 } 149 if (olderHeaderPosition != null) { 150 numberOfHeaders++; 151 } 152 return cursor.getCount() + numberOfHeaders; 153 } 154} 155