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