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