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 { 43 void onSelectedContactsChanged(); 44 } 45 46 public interface DeleteContactListener { 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 */ 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 */ 65 public int getContactColumnIdIndex() { 66 return mContactIdColumnIndex; 67 } 68 69 public DeleteContactListener getDeleteContactListener() { 70 return mDeleteContactListener; 71 } 72 73 public void setDeleteContactListener(DeleteContactListener deleteContactListener) { 74 mDeleteContactListener = deleteContactListener; 75 } 76 77 public void setSelectedContactsListener(SelectedContactsListener listener) { 78 mSelectedContactsListener = listener; 79 } 80 81 /** 82 * Returns set of selected contacts. 83 */ 84 public TreeSet<Long> getSelectedContactIds() { 85 return mSelectedContactIds; 86 } 87 88 public boolean hasSelectedItems() { 89 return mSelectedContactIds.size() > 0; 90 } 91 92 /** 93 * Returns the selected contacts as an array. 94 */ 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 */ 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 */ 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 */ 125 public boolean isDisplayingCheckBoxes() { 126 return mDisplayCheckBoxes; 127 } 128 129 /** 130 * Toggle the checkbox beside the contact for {@param contactId}. 131 */ 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 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 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 */ 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 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