GroupMemberPickerFragment.java revision e6342c6ccc165314075ade40ea2187e0442c98b0
1/* 2 * Copyright (C) 2016 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.contacts.list; 17 18import android.app.Activity; 19import android.content.Loader; 20import android.database.Cursor; 21import android.database.CursorWrapper; 22import android.os.Bundle; 23import android.provider.ContactsContract.Contacts; 24import android.util.Log; 25import android.view.LayoutInflater; 26import android.view.Menu; 27import android.view.MenuInflater; 28import android.view.MenuItem; 29import android.view.View; 30import android.view.ViewGroup; 31 32import com.android.contacts.activities.ContactSelectionActivity; 33import com.android.contacts.common.R; 34import com.android.contacts.common.list.ContactListAdapter.ContactQuery; 35import com.android.contacts.common.list.ContactListFilter; 36import com.android.contacts.common.list.ContactsSectionIndexer; 37import com.android.contacts.common.list.DefaultContactListAdapter; 38import com.android.contacts.common.model.account.AccountWithDataSet; 39import com.android.contacts.group.GroupUtil; 40 41import java.util.ArrayList; 42import java.util.List; 43 44/** 45 * Fragment containing raw contacts for a specified account that are not already in a group. 46 */ 47public class GroupMemberPickerFragment extends 48 MultiSelectContactsListFragment<DefaultContactListAdapter> { 49 50 public static final String TAG = "GroupMemberPicker"; 51 52 private static final String KEY_ACCOUNT_NAME = "accountName"; 53 private static final String KEY_ACCOUNT_TYPE = "accountType"; 54 private static final String KEY_ACCOUNT_DATA_SET = "accountDataSet"; 55 private static final String KEY_CONTACT_IDS = "contactIds"; 56 57 private static final String ARG_ACCOUNT_NAME = "accountName"; 58 private static final String ARG_ACCOUNT_TYPE = "accountType"; 59 private static final String ARG_ACCOUNT_DATA_SET = "accountDataSet"; 60 private static final String ARG_CONTACT_IDS = "contactIds"; 61 62 /** Callbacks for host of {@link GroupMemberPickerFragment}. */ 63 public interface Listener { 64 65 /** Invoked when a potential group member is selected. */ 66 void onGroupMemberClicked(long contactId); 67 68 /** Invoked when user has initiated multiple selection mode. */ 69 void onSelectGroupMembers(); 70 } 71 72 /** Filters out raw contacts that are already in the group. */ 73 private class FilterCursorWrapper extends CursorWrapper { 74 75 private int[] mIndex; 76 private int mCount = 0; 77 private int mPos = 0; 78 79 public FilterCursorWrapper(Cursor cursor) { 80 super(cursor); 81 82 mCount = super.getCount(); 83 mIndex = new int[mCount]; 84 85 final List<Integer> indicesToFilter = new ArrayList<>(); 86 87 if (Log.isLoggable(TAG, Log.VERBOSE)) { 88 Log.v(TAG, "RawContacts CursorWrapper start: " + mCount); 89 } 90 91 final Bundle bundle = cursor.getExtras(); 92 final String sections[] = bundle.getStringArray(Contacts 93 .EXTRA_ADDRESS_BOOK_INDEX_TITLES); 94 final int counts[] = bundle.getIntArray(Contacts.EXTRA_ADDRESS_BOOK_INDEX_COUNTS); 95 final ContactsSectionIndexer indexer = (sections == null || counts == null) 96 ? null : new ContactsSectionIndexer(sections, counts); 97 98 for (int i = 0; i < mCount; i++) { 99 super.moveToPosition(i); 100 final String contactId = getString(ContactQuery.CONTACT_ID); 101 if (!mContactIds.contains(contactId)) { 102 mIndex[mPos++] = i; 103 } else { 104 indicesToFilter.add(i); 105 } 106 } 107 108 if (indexer != null && GroupUtil.needTrimming(mCount, counts, indexer.getPositions())) { 109 GroupUtil.updateBundle(bundle, indexer, indicesToFilter, sections, counts); 110 } 111 112 mCount = mPos; 113 mPos = 0; 114 super.moveToFirst(); 115 116 if (Log.isLoggable(TAG, Log.VERBOSE)) { 117 Log.v(TAG, "RawContacts CursorWrapper end: " + mCount); 118 } 119 } 120 121 @Override 122 public boolean move(int offset) { 123 return moveToPosition(mPos + offset); 124 } 125 126 @Override 127 public boolean moveToNext() { 128 return moveToPosition(mPos + 1); 129 } 130 131 @Override 132 public boolean moveToPrevious() { 133 return moveToPosition(mPos - 1); 134 } 135 136 @Override 137 public boolean moveToFirst() { 138 return moveToPosition(0); 139 } 140 141 @Override 142 public boolean moveToLast() { 143 return moveToPosition(mCount - 1); 144 } 145 146 @Override 147 public boolean moveToPosition(int position) { 148 if (position >= mCount) { 149 mPos = mCount; 150 return false; 151 } else if (position < 0) { 152 mPos = -1; 153 return false; 154 } 155 mPos = mIndex[position]; 156 return super.moveToPosition(mPos); 157 } 158 159 @Override 160 public int getCount() { 161 return mCount; 162 } 163 164 @Override 165 public int getPosition() { 166 return mPos; 167 } 168 } 169 170 private String mAccountName; 171 private String mAccountType; 172 private String mAccountDataSet; 173 private ArrayList<String> mContactIds; 174 private Listener mListener; 175 176 public static GroupMemberPickerFragment newInstance(String accountName, String accountType, 177 String accountDataSet, ArrayList<String> contactIds) { 178 final Bundle args = new Bundle(); 179 args.putString(ARG_ACCOUNT_NAME, accountName); 180 args.putString(ARG_ACCOUNT_TYPE, accountType); 181 args.putString(ARG_ACCOUNT_DATA_SET, accountDataSet); 182 args.putStringArrayList(ARG_CONTACT_IDS, contactIds); 183 184 final GroupMemberPickerFragment fragment = new GroupMemberPickerFragment(); 185 fragment.setArguments(args); 186 return fragment; 187 } 188 189 public GroupMemberPickerFragment() { 190 setPhotoLoaderEnabled(true); 191 setSectionHeaderDisplayEnabled(true); 192 setHasOptionsMenu(true); 193 setDisplayDirectoryHeader(false); 194 } 195 196 @Override 197 public void onCreate(Bundle savedState) { 198 if (savedState == null) { 199 mAccountName = getArguments().getString(ARG_ACCOUNT_NAME); 200 mAccountType = getArguments().getString(ARG_ACCOUNT_TYPE); 201 mAccountDataSet = getArguments().getString(ARG_ACCOUNT_DATA_SET); 202 mContactIds = getArguments().getStringArrayList(ARG_CONTACT_IDS); 203 } else { 204 mAccountName = savedState.getString(KEY_ACCOUNT_NAME); 205 mAccountType = savedState.getString(KEY_ACCOUNT_TYPE); 206 mAccountDataSet = savedState.getString(KEY_ACCOUNT_DATA_SET); 207 mContactIds = savedState.getStringArrayList(KEY_CONTACT_IDS); 208 } 209 super.onCreate(savedState); 210 } 211 212 @Override 213 public void onSaveInstanceState(Bundle outState) { 214 super.onSaveInstanceState(outState); 215 outState.putString(KEY_ACCOUNT_NAME, mAccountName); 216 outState.putString(KEY_ACCOUNT_TYPE, mAccountType); 217 outState.putString(KEY_ACCOUNT_DATA_SET, mAccountDataSet); 218 outState.putStringArrayList(KEY_CONTACT_IDS, mContactIds); 219 } 220 221 public void setListener(Listener listener) { 222 mListener = listener; 223 } 224 225 @Override 226 protected View inflateView(LayoutInflater inflater, ViewGroup container) { 227 return inflater.inflate(R.layout.contact_list_content, null); 228 } 229 230 @Override 231 public void onLoadFinished(Loader<Cursor> loader, Cursor data) { 232 if (data != null) { 233 // Wait until contacts are loaded before showing the scrollbar 234 setVisibleScrollbarEnabled(true); 235 236 final FilterCursorWrapper cursorWrapper = new FilterCursorWrapper(data); 237 final View accountFilterContainer = getView().findViewById( 238 R.id.account_filter_header_container); 239 final AccountWithDataSet accountWithDataSet = new AccountWithDataSet(mAccountName, 240 mAccountType, mAccountDataSet); 241 bindListHeader(getContext(), getListView(), accountFilterContainer, 242 accountWithDataSet, cursorWrapper.getCount()); 243 244 super.onLoadFinished(loader, cursorWrapper); 245 } 246 } 247 248 @Override 249 protected DefaultContactListAdapter createListAdapter() { 250 final DefaultContactListAdapter adapter = new DefaultContactListAdapter(getActivity()); 251 adapter.setFilter(ContactListFilter.createGroupMembersFilter( 252 mAccountType, mAccountName, mAccountDataSet)); 253 adapter.setSectionHeaderDisplayEnabled(true); 254 adapter.setDisplayPhotos(true); 255 return adapter; 256 } 257 258 @Override 259 protected void onItemClick(int position, long id) { 260 if (getAdapter().isDisplayingCheckBoxes()) { 261 super.onItemClick(position, id); 262 return; 263 } 264 if (mListener != null) { 265 final long contactId = getAdapter().getContactId(position); 266 if (contactId > 0) { 267 mListener.onGroupMemberClicked(contactId); 268 } 269 } 270 } 271 272 @Override 273 public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater) { 274 super.onCreateOptionsMenu(menu, menuInflater); 275 menuInflater.inflate(R.menu.group_member_picker, menu); 276 } 277 278 @Override 279 public void onPrepareOptionsMenu(Menu menu) { 280 final ContactSelectionActivity activity = getContactSelectionActivity(); 281 final boolean hasContacts = mContactIds == null ? false : mContactIds.size() > 0; 282 final boolean isSearchMode = activity == null ? false : activity.isSearchMode(); 283 final boolean isSelectionMode = activity == null ? false : activity.isSelectionMode(); 284 285 // Added in ContactSelectionActivity but we must account for selection mode 286 setVisible(menu, R.id.menu_search, !isSearchMode && !isSelectionMode); 287 setVisible(menu, R.id.menu_select, hasContacts && !isSearchMode && !isSelectionMode); 288 } 289 290 private ContactSelectionActivity getContactSelectionActivity() { 291 final Activity activity = getActivity(); 292 if (activity != null && activity instanceof ContactSelectionActivity) { 293 return (ContactSelectionActivity) activity; 294 } 295 return null; 296 } 297 298 private static void setVisible(Menu menu, int id, boolean visible) { 299 final MenuItem menuItem = menu.findItem(id); 300 if (menuItem != null) { 301 menuItem.setVisible(visible); 302 } 303 } 304 305 @Override 306 public boolean onOptionsItemSelected(MenuItem item) { 307 switch (item.getItemId()) { 308 case android.R.id.home: { 309 final Activity activity = getActivity(); 310 if (activity != null) { 311 activity.onBackPressed(); 312 } 313 return true; 314 } 315 case R.id.menu_select: { 316 if (mListener != null) { 317 mListener.onSelectGroupMembers(); 318 } 319 return true; 320 } 321 } 322 return super.onOptionsItemSelected(item); 323 } 324} 325