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