• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
16 package com.android.dialer.calllog.ui;
17 
18 import android.content.Context;
19 import android.database.Cursor;
20 import android.support.annotation.IntDef;
21 import android.support.annotation.Nullable;
22 import android.support.v7.widget.RecyclerView;
23 import android.support.v7.widget.RecyclerView.ViewHolder;
24 import android.view.LayoutInflater;
25 import android.view.ViewGroup;
26 import com.android.dialer.calllogutils.CallLogDates;
27 import com.android.dialer.common.Assert;
28 import com.android.dialer.glidephotomanager.GlidePhotoManager;
29 import com.android.dialer.glidephotomanager.GlidePhotoManagerComponent;
30 import com.android.dialer.time.Clock;
31 import java.lang.annotation.Retention;
32 import java.lang.annotation.RetentionPolicy;
33 
34 /** {@link RecyclerView.Adapter} for the new call log fragment. */
35 final class NewCallLogAdapter extends RecyclerView.Adapter<ViewHolder> {
36 
37   /** IntDef for the different types of rows that can be shown in the call log. */
38   @Retention(RetentionPolicy.SOURCE)
39   @IntDef({
40     RowType.HEADER_TODAY,
41     RowType.HEADER_YESTERDAY,
42     RowType.HEADER_OLDER,
43     RowType.CALL_LOG_ENTRY
44   })
45   @interface RowType {
46     /** Header that displays "Today". */
47     int HEADER_TODAY = 1;
48     /** Header that displays "Yesterday". */
49     int HEADER_YESTERDAY = 2;
50     /** Header that displays "Older". */
51     int HEADER_OLDER = 3;
52     /** A row representing a call log entry (which could represent one or more calls). */
53     int CALL_LOG_ENTRY = 4;
54   }
55 
56   private final Clock clock;
57   private final RealtimeRowProcessor realtimeRowProcessor;
58   private final GlidePhotoManager glidePhotoManager;
59 
60   private Cursor cursor;
61 
62   /** Position of the "Today" header. Null when it should not be displayed. */
63   @Nullable private Integer todayHeaderPosition;
64 
65   /** Position of the "Yesterday" header. Null when it should not be displayed. */
66   @Nullable private Integer yesterdayHeaderPosition;
67 
68   /** Position of the "Older" header. Null when it should not be displayed. */
69   @Nullable private Integer olderHeaderPosition;
70 
NewCallLogAdapter(Context context, Cursor cursor, Clock clock)71   NewCallLogAdapter(Context context, Cursor cursor, Clock clock) {
72     this.cursor = cursor;
73     this.clock = clock;
74     this.realtimeRowProcessor = CallLogUiComponent.get(context).realtimeRowProcessor();
75     this.glidePhotoManager = GlidePhotoManagerComponent.get(context).glidePhotoManager();
76 
77     setHeaderPositions();
78   }
79 
updateCursor(Cursor updatedCursor)80   void updateCursor(Cursor updatedCursor) {
81     this.cursor = updatedCursor;
82     this.realtimeRowProcessor.clearCache();
83 
84     setHeaderPositions();
85     notifyDataSetChanged();
86   }
87 
clearCache()88   void clearCache() {
89     this.realtimeRowProcessor.clearCache();
90   }
91 
setHeaderPositions()92   private void setHeaderPositions() {
93     // If there are no rows to display, set all header positions to null.
94     if (!cursor.moveToFirst()) {
95       todayHeaderPosition = null;
96       yesterdayHeaderPosition = null;
97       olderHeaderPosition = null;
98       return;
99     }
100 
101     long currentTimeMillis = clock.currentTimeMillis();
102 
103     int numItemsInToday = 0;
104     int numItemsInYesterday = 0;
105     do {
106       long timestamp = CoalescedAnnotatedCallLogCursorLoader.getTimestamp(cursor);
107       long dayDifference = CallLogDates.getDayDifference(currentTimeMillis, timestamp);
108       if (dayDifference == 0) {
109         numItemsInToday++;
110       } else if (dayDifference == 1) {
111         numItemsInYesterday++;
112       } else {
113         break;
114       }
115     } while (cursor.moveToNext());
116 
117     if (numItemsInToday > 0) {
118       numItemsInToday++; // including the "Today" header;
119     }
120     if (numItemsInYesterday > 0) {
121       numItemsInYesterday++; // including the "Yesterday" header;
122     }
123 
124     // Set all header positions.
125     // A header position will be null if there is no item to be displayed under that header.
126     todayHeaderPosition = numItemsInToday > 0 ? 0 : null;
127     yesterdayHeaderPosition = numItemsInYesterday > 0 ? numItemsInToday : null;
128     olderHeaderPosition = !cursor.isAfterLast() ? numItemsInToday + numItemsInYesterday : null;
129   }
130 
131   @Override
onCreateViewHolder(ViewGroup viewGroup, @RowType int viewType)132   public ViewHolder onCreateViewHolder(ViewGroup viewGroup, @RowType int viewType) {
133     switch (viewType) {
134       case RowType.HEADER_TODAY:
135       case RowType.HEADER_YESTERDAY:
136       case RowType.HEADER_OLDER:
137         return new HeaderViewHolder(
138             LayoutInflater.from(viewGroup.getContext())
139                 .inflate(R.layout.new_call_log_header, viewGroup, false));
140       case RowType.CALL_LOG_ENTRY:
141         return new NewCallLogViewHolder(
142             LayoutInflater.from(viewGroup.getContext())
143                 .inflate(R.layout.new_call_log_entry, viewGroup, false),
144             clock,
145             realtimeRowProcessor,
146             glidePhotoManager);
147       default:
148         throw Assert.createUnsupportedOperationFailException("Unsupported view type: " + viewType);
149     }
150   }
151 
152   @Override
onBindViewHolder(ViewHolder viewHolder, int position)153   public void onBindViewHolder(ViewHolder viewHolder, int position) {
154     @RowType int viewType = getItemViewType(position);
155     switch (viewType) {
156       case RowType.HEADER_TODAY:
157         ((HeaderViewHolder) viewHolder).setHeader(R.string.new_call_log_header_today);
158         break;
159       case RowType.HEADER_YESTERDAY:
160         ((HeaderViewHolder) viewHolder).setHeader(R.string.new_call_log_header_yesterday);
161         break;
162       case RowType.HEADER_OLDER:
163         ((HeaderViewHolder) viewHolder).setHeader(R.string.new_call_log_header_older);
164         break;
165       case RowType.CALL_LOG_ENTRY:
166         NewCallLogViewHolder newCallLogViewHolder = (NewCallLogViewHolder) viewHolder;
167         int previousHeaders = 0;
168         if (todayHeaderPosition != null && position > todayHeaderPosition) {
169           previousHeaders++;
170         }
171         if (yesterdayHeaderPosition != null && position > yesterdayHeaderPosition) {
172           previousHeaders++;
173         }
174         if (olderHeaderPosition != null && position > olderHeaderPosition) {
175           previousHeaders++;
176         }
177         cursor.moveToPosition(position - previousHeaders);
178         newCallLogViewHolder.bind(cursor);
179         break;
180       default:
181         throw Assert.createIllegalStateFailException(
182             "Unexpected view type " + viewType + " at position: " + position);
183     }
184   }
185 
186   @Override
187   @RowType
getItemViewType(int position)188   public int getItemViewType(int position) {
189     if (todayHeaderPosition != null && position == todayHeaderPosition) {
190       return RowType.HEADER_TODAY;
191     }
192     if (yesterdayHeaderPosition != null && position == yesterdayHeaderPosition) {
193       return RowType.HEADER_YESTERDAY;
194     }
195     if (olderHeaderPosition != null && position == olderHeaderPosition) {
196       return RowType.HEADER_OLDER;
197     }
198     return RowType.CALL_LOG_ENTRY;
199   }
200 
201   @Override
getItemCount()202   public int getItemCount() {
203     int numberOfHeaders = 0;
204     if (todayHeaderPosition != null) {
205       numberOfHeaders++;
206     }
207     if (yesterdayHeaderPosition != null) {
208       numberOfHeaders++;
209     }
210     if (olderHeaderPosition != null) {
211       numberOfHeaders++;
212     }
213     return cursor.getCount() + numberOfHeaders;
214   }
215 }
216