1 /* 2 * Copyright (C) 2015 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.contacts.list; 18 19 import android.content.Context; 20 import android.database.Cursor; 21 import android.provider.ContactsContract; 22 import android.view.View; 23 import android.widget.CheckBox; 24 25 import com.android.contacts.ContactPhotoManager; 26 import com.android.contacts.group.GroupUtil; 27 28 import java.util.TreeSet; 29 30 /** 31 * An extension of the default contact adapter that adds checkboxes and the ability 32 * to select multiple contacts. 33 */ 34 public abstract class MultiSelectEntryContactListAdapter extends ContactEntryListAdapter { 35 36 private SelectedContactsListener mSelectedContactsListener; 37 private DeleteContactListener mDeleteContactListener; 38 private TreeSet<Long> mSelectedContactIds = new TreeSet<>(); 39 private boolean mDisplayCheckBoxes; 40 private final int mContactIdColumnIndex; 41 42 public interface SelectedContactsListener { onSelectedContactsChanged()43 void onSelectedContactsChanged(); 44 } 45 46 public interface DeleteContactListener { onContactDeleteClicked(int position)47 void onContactDeleteClicked(int position); 48 } 49 50 /** 51 * @param contactIdColumnIndex the column index of the contact ID in the underlying cursor; 52 * it is passed in so that this adapter can support different kinds of contact 53 * lists (e.g. aggregate contacts or raw contacts). 54 */ MultiSelectEntryContactListAdapter(Context context, int contactIdColumnIndex)55 public MultiSelectEntryContactListAdapter(Context context, int contactIdColumnIndex) { 56 super(context); 57 mContactIdColumnIndex = contactIdColumnIndex; 58 } 59 60 /** 61 * Returns the column index of the contact ID in the underlying cursor; the contact ID 62 * retrieved using this index is the value that is selected by this adapter (and returned 63 * by {@link #getSelectedContactIds}). 64 */ getContactColumnIdIndex()65 public int getContactColumnIdIndex() { 66 return mContactIdColumnIndex; 67 } 68 getDeleteContactListener()69 public DeleteContactListener getDeleteContactListener() { 70 return mDeleteContactListener; 71 } 72 setDeleteContactListener(DeleteContactListener deleteContactListener)73 public void setDeleteContactListener(DeleteContactListener deleteContactListener) { 74 mDeleteContactListener = deleteContactListener; 75 } 76 setSelectedContactsListener(SelectedContactsListener listener)77 public void setSelectedContactsListener(SelectedContactsListener listener) { 78 mSelectedContactsListener = listener; 79 } 80 81 /** 82 * Returns set of selected contacts. 83 */ getSelectedContactIds()84 public TreeSet<Long> getSelectedContactIds() { 85 return mSelectedContactIds; 86 } 87 hasSelectedItems()88 public boolean hasSelectedItems() { 89 return mSelectedContactIds.size() > 0; 90 } 91 92 /** 93 * Returns the selected contacts as an array. 94 */ getSelectedContactIdsArray()95 public long[] getSelectedContactIdsArray() { 96 return GroupUtil.convertLongSetToLongArray(mSelectedContactIds); 97 } 98 99 /** 100 * Update set of selected contacts. This changes which checkboxes are set. 101 */ setSelectedContactIds(TreeSet<Long> selectedContactIds)102 public void setSelectedContactIds(TreeSet<Long> selectedContactIds) { 103 this.mSelectedContactIds = selectedContactIds; 104 notifyDataSetChanged(); 105 if (mSelectedContactsListener != null) { 106 mSelectedContactsListener.onSelectedContactsChanged(); 107 } 108 } 109 110 /** 111 * Shows checkboxes beside contacts if {@param displayCheckBoxes} is {@code TRUE}. 112 * Not guaranteed to work with all configurations of this adapter. 113 */ setDisplayCheckBoxes(boolean showCheckBoxes)114 public void setDisplayCheckBoxes(boolean showCheckBoxes) { 115 mDisplayCheckBoxes = showCheckBoxes; 116 notifyDataSetChanged(); 117 if (mSelectedContactsListener != null) { 118 mSelectedContactsListener.onSelectedContactsChanged(); 119 } 120 } 121 122 /** 123 * Checkboxes are being displayed beside contacts. 124 */ isDisplayingCheckBoxes()125 public boolean isDisplayingCheckBoxes() { 126 return mDisplayCheckBoxes; 127 } 128 129 /** 130 * Toggle the checkbox beside the contact for {@param contactId}. 131 */ toggleSelectionOfContactId(long contactId)132 public void toggleSelectionOfContactId(long contactId) { 133 if (mSelectedContactIds.contains(contactId)) { 134 mSelectedContactIds.remove(contactId); 135 } else { 136 mSelectedContactIds.add(contactId); 137 } 138 notifyDataSetChanged(); 139 if (mSelectedContactsListener != null) { 140 mSelectedContactsListener.onSelectedContactsChanged(); 141 } 142 } 143 144 @Override getItemId(int position)145 public long getItemId(int position) { 146 Cursor cursor = (Cursor) getItem(position); 147 if (cursor != null) { 148 return cursor.getLong(getContactColumnIdIndex()); 149 } 150 return 0; 151 } 152 153 @Override bindView(View itemView, int partition, Cursor cursor, int position)154 protected void bindView(View itemView, int partition, Cursor cursor, int position) { 155 super.bindView(itemView, partition, cursor, position); 156 final ContactListItemView view = (ContactListItemView) itemView; 157 bindViewId(view, cursor, getContactColumnIdIndex()); 158 bindCheckBox(view, cursor, partition == ContactsContract.Directory.DEFAULT); 159 } 160 161 /** 162 * Loads the photo for the photo view. 163 * @param photoIdColumn Index of the photo id column 164 * @param lookUpKeyColumn Index of the lookup key column 165 * @param displayNameColumn Index of the display name column 166 */ bindPhoto(final ContactListItemView view, final Cursor cursor, final int photoIdColumn, final int lookUpKeyColumn, final int displayNameColumn)167 protected void bindPhoto(final ContactListItemView view, final Cursor cursor, 168 final int photoIdColumn, final int lookUpKeyColumn, final int displayNameColumn) { 169 final long photoId = cursor.isNull(photoIdColumn) 170 ? 0 : cursor.getLong(photoIdColumn); 171 final ContactPhotoManager.DefaultImageRequest imageRequest = photoId == 0 172 ? getDefaultImageRequestFromCursor(cursor, displayNameColumn, 173 lookUpKeyColumn) 174 : null; 175 getPhotoLoader().loadThumbnail(view.getPhotoView(), photoId, false, getCircularPhotos(), 176 imageRequest); 177 } 178 bindCheckBox(ContactListItemView view, Cursor cursor, boolean isLocalDirectory)179 private void bindCheckBox(ContactListItemView view, Cursor cursor, boolean isLocalDirectory) { 180 // Disable clicking on all contacts from remote directories when showing check boxes. We do 181 // this by telling the view to handle clicking itself. 182 view.setClickable(!isLocalDirectory && mDisplayCheckBoxes); 183 // Only show checkboxes if mDisplayCheckBoxes is enabled. Also, never show the 184 // checkbox for other directory contacts except local directory. 185 if (!mDisplayCheckBoxes || !isLocalDirectory) { 186 view.hideCheckBox(); 187 return; 188 } 189 final CheckBox checkBox = view.getCheckBox(); 190 final long contactId = cursor.getLong(mContactIdColumnIndex); 191 checkBox.setChecked(mSelectedContactIds.contains(contactId)); 192 checkBox.setClickable(false); 193 checkBox.setTag(contactId); 194 } 195 } 196