• 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 
17 package com.android.dialer.contactsfragment;
18 
19 import android.content.Context;
20 import android.database.Cursor;
21 import android.net.Uri;
22 import android.provider.ContactsContract.Contacts;
23 import android.support.v4.util.ArrayMap;
24 import android.support.v7.widget.RecyclerView;
25 import android.view.LayoutInflater;
26 import android.view.ViewGroup;
27 import android.widget.TextView;
28 import com.android.contacts.common.ContactPhotoManager;
29 import com.android.dialer.common.Assert;
30 
31 /** List adapter for the union of all contacts associated with every account on the device. */
32 final class ContactsAdapter extends RecyclerView.Adapter<ContactViewHolder> {
33 
34   private final ArrayMap<ContactViewHolder, Integer> holderMap = new ArrayMap<>();
35   private final Context context;
36   private final Cursor cursor;
37 
38   // List of contact sublist headers
39   private final String[] headers;
40 
41   // Number of contacts that correspond to each header in {@code headers}.
42   private final int[] counts;
43 
ContactsAdapter(Context context, Cursor cursor)44   public ContactsAdapter(Context context, Cursor cursor) {
45     this.context = context;
46     this.cursor = cursor;
47     headers = cursor.getExtras().getStringArray(Contacts.EXTRA_ADDRESS_BOOK_INDEX_TITLES);
48     counts = cursor.getExtras().getIntArray(Contacts.EXTRA_ADDRESS_BOOK_INDEX_COUNTS);
49   }
50 
51   @Override
onCreateViewHolder(ViewGroup parent, int position)52   public ContactViewHolder onCreateViewHolder(ViewGroup parent, int position) {
53     return new ContactViewHolder(
54         LayoutInflater.from(context).inflate(R.layout.contact_row, parent, false));
55   }
56 
57   @Override
onBindViewHolder(ContactViewHolder contactViewHolder, int position)58   public void onBindViewHolder(ContactViewHolder contactViewHolder, int position) {
59     holderMap.put(contactViewHolder, position);
60     cursor.moveToPosition(position);
61 
62     String name = getDisplayName(cursor);
63     String header = getHeaderString(position);
64     Uri contactUri = getContactUri(cursor);
65 
66     ContactPhotoManager.getInstance(context)
67         .loadDialerThumbnailOrPhoto(
68             contactViewHolder.getPhoto(),
69             contactUri,
70             getPhotoId(cursor),
71             getPhotoUri(cursor),
72             name,
73             0);
74 
75     String photoDescription =
76         context.getString(com.android.contacts.common.R.string.description_quick_contact_for, name);
77     contactViewHolder.getPhoto().setContentDescription(photoDescription);
78 
79     // Always show the view holder's header if it's the first item in the list. Otherwise, compare
80     // it to the previous element and only show the anchored header if the row elements fall into
81     // the same sublists.
82     if (position == 0) {
83       contactViewHolder.bind(header, name, contactUri, true);
84     } else {
85       boolean showHeader = !header.equals(getHeaderString(position - 1));
86       contactViewHolder.bind(header, name, contactUri, showHeader);
87     }
88   }
89 
refreshHeaders()90   public void refreshHeaders() {
91     for (ContactViewHolder holder : holderMap.keySet()) {
92       onBindViewHolder(holder, holderMap.get(holder));
93     }
94   }
95 
96   @Override
getItemCount()97   public int getItemCount() {
98     return cursor == null ? 0 : cursor.getCount();
99   }
100 
getHeader(int position)101   public String getHeader(int position) {
102     return getHolderAt(position).getHeader();
103   }
104 
getHeaderView(int position)105   public TextView getHeaderView(int position) {
106     return getHolderAt(position).getHeaderView();
107   }
108 
setHeaderVisibility(int position, int visibility)109   public void setHeaderVisibility(int position, int visibility) {
110     getHolderAt(position).getHeaderView().setVisibility(visibility);
111   }
112 
getHolderAt(int position)113   private ContactViewHolder getHolderAt(int position) {
114     for (ContactViewHolder holder : holderMap.keySet()) {
115       if (holderMap.get(holder) == position) {
116         return holder;
117       }
118     }
119     throw Assert.createIllegalStateFailException("No holder for position: " + position);
120   }
121 
getDisplayName(Cursor cursor)122   private static String getDisplayName(Cursor cursor) {
123     return cursor.getString(ContactsCursorLoader.CONTACT_DISPLAY_NAME);
124   }
125 
getPhotoId(Cursor cursor)126   private static long getPhotoId(Cursor cursor) {
127     return cursor.getLong(ContactsCursorLoader.CONTACT_PHOTO_ID);
128   }
129 
getPhotoUri(Cursor cursor)130   private static Uri getPhotoUri(Cursor cursor) {
131     String photoUri = cursor.getString(ContactsCursorLoader.CONTACT_PHOTO_URI);
132     return photoUri == null ? null : Uri.parse(photoUri);
133   }
134 
getContactUri(Cursor cursor)135   private static Uri getContactUri(Cursor cursor) {
136     long contactId = cursor.getLong(ContactsCursorLoader.CONTACT_ID);
137     String lookupKey = cursor.getString(ContactsCursorLoader.CONTACT_LOOKUP_KEY);
138     return Contacts.getLookupUri(contactId, lookupKey);
139   }
140 
getHeaderString(int position)141   private String getHeaderString(int position) {
142     int index = -1;
143     int sum = 0;
144     while (sum <= position) {
145       sum += counts[++index];
146     }
147     return headers[index];
148   }
149 }
150