blob: a7e37d7342437dd2b2dc0d442f5d978c61aad528 [file] [log] [blame]
Walter Jangf9779ef2016-05-25 12:23:05 -07001/*
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
Walter Janga4897212016-06-21 19:02:23 -070018import android.app.Activity;
Walter Jangf9779ef2016-05-25 12:23:05 -070019import android.content.Loader;
20import android.database.Cursor;
21import android.database.CursorWrapper;
Walter Jangf9779ef2016-05-25 12:23:05 -070022import android.os.Bundle;
Wenyi Wang104e93a2016-06-22 18:26:30 -070023import android.provider.ContactsContract.Contacts;
Walter Jangefb1cbe2016-05-28 13:54:12 -070024import android.util.Log;
Walter Jangf9779ef2016-05-25 12:23:05 -070025import android.view.LayoutInflater;
Walter Janga4897212016-06-21 19:02:23 -070026import android.view.Menu;
27import android.view.MenuInflater;
28import android.view.MenuItem;
Walter Jangf9779ef2016-05-25 12:23:05 -070029import android.view.View;
30import android.view.ViewGroup;
31
Walter Janga4897212016-06-21 19:02:23 -070032import com.android.contacts.activities.ContactSelectionActivity;
Walter Jangf9779ef2016-05-25 12:23:05 -070033import com.android.contacts.common.R;
Walter Jang16c29592016-06-14 15:34:39 -070034import com.android.contacts.common.list.ContactListAdapter.ContactQuery;
35import com.android.contacts.common.list.ContactListFilter;
Wenyi Wang104e93a2016-06-22 18:26:30 -070036import com.android.contacts.common.list.ContactsSectionIndexer;
Walter Jang16c29592016-06-14 15:34:39 -070037import com.android.contacts.common.list.DefaultContactListAdapter;
Wenyi Wang1114fde2016-07-11 21:44:02 -070038import com.android.contacts.common.model.account.AccountWithDataSet;
Wenyi Wang38860a52016-06-24 17:47:34 -070039import com.android.contacts.group.GroupUtil;
Walter Jangf9779ef2016-05-25 12:23:05 -070040
41import java.util.ArrayList;
Wenyi Wang104e93a2016-06-22 18:26:30 -070042import java.util.List;
Walter Jangf9779ef2016-05-25 12:23:05 -070043
44/**
45 * Fragment containing raw contacts for a specified account that are not already in a group.
46 */
47public class GroupMemberPickerFragment extends
Walter Janga4897212016-06-21 19:02:23 -070048 MultiSelectContactsListFragment<DefaultContactListAdapter> {
Walter Jangf9779ef2016-05-25 12:23:05 -070049
Walter Jangefb1cbe2016-05-28 13:54:12 -070050 public static final String TAG = "GroupMemberPicker";
51
Walter Jang6c5a5582016-06-16 11:26:53 -070052 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";
Walter Jangdd2d8e22016-09-09 11:07:37 -070055 private static final String KEY_CONTACT_IDS = "contactIds";
Walter Jangf9779ef2016-05-25 12:23:05 -070056
Walter Jang6c5a5582016-06-16 11:26:53 -070057 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";
Walter Jangdd2d8e22016-09-09 11:07:37 -070060 private static final String ARG_CONTACT_IDS = "contactIds";
Walter Jangf9779ef2016-05-25 12:23:05 -070061
62 /** Callbacks for host of {@link GroupMemberPickerFragment}. */
63 public interface Listener {
64
65 /** Invoked when a potential group member is selected. */
Walter Jang16c29592016-06-14 15:34:39 -070066 void onGroupMemberClicked(long contactId);
Walter Janga4897212016-06-21 19:02:23 -070067
Walter Janga4897212016-06-21 19:02:23 -070068 /** Invoked when user has initiated multiple selection mode. */
69 void onSelectGroupMembers();
Walter Jangf9779ef2016-05-25 12:23:05 -070070 }
71
Walter Jang2552c112016-06-17 14:29:09 -070072 /** Filters out raw contacts that are already in the group. */
Walter Jangf9779ef2016-05-25 12:23:05 -070073 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];
Walter Jangefb1cbe2016-05-28 13:54:12 -070084
Wenyi Wang38860a52016-06-24 17:47:34 -070085 final List<Integer> indicesToFilter = new ArrayList<>();
86
Walter Jangefb1cbe2016-05-28 13:54:12 -070087 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Walter Jang2552c112016-06-17 14:29:09 -070088 Log.v(TAG, "RawContacts CursorWrapper start: " + mCount);
Walter Jangefb1cbe2016-05-28 13:54:12 -070089 }
90
Wenyi Wang104e93a2016-06-22 18:26:30 -070091 final Bundle bundle = cursor.getExtras();
Wenyi Wang38860a52016-06-24 17:47:34 -070092 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);
Wenyi Wang104e93a2016-06-22 18:26:30 -070097
Walter Jangf9779ef2016-05-25 12:23:05 -070098 for (int i = 0; i < mCount; i++) {
99 super.moveToPosition(i);
Walter Jang16c29592016-06-14 15:34:39 -0700100 final String contactId = getString(ContactQuery.CONTACT_ID);
Walter Jangdd2d8e22016-09-09 11:07:37 -0700101 if (!mContactIds.contains(contactId)) {
Walter Jangf9779ef2016-05-25 12:23:05 -0700102 mIndex[mPos++] = i;
Wenyi Wang38860a52016-06-24 17:47:34 -0700103 } else {
104 indicesToFilter.add(i);
Walter Jangf9779ef2016-05-25 12:23:05 -0700105 }
106 }
Wenyi Wang104e93a2016-06-22 18:26:30 -0700107
Wenyi Wang38860a52016-06-24 17:47:34 -0700108 if (indexer != null && GroupUtil.needTrimming(mCount, counts, indexer.getPositions())) {
109 GroupUtil.updateBundle(bundle, indexer, indicesToFilter, sections, counts);
Wenyi Wang104e93a2016-06-22 18:26:30 -0700110 }
111
Walter Jangf9779ef2016-05-25 12:23:05 -0700112 mCount = mPos;
113 mPos = 0;
114 super.moveToFirst();
Walter Jangefb1cbe2016-05-28 13:54:12 -0700115
116 if (Log.isLoggable(TAG, Log.VERBOSE)) {
Walter Jang2552c112016-06-17 14:29:09 -0700117 Log.v(TAG, "RawContacts CursorWrapper end: " + mCount);
Walter Jangefb1cbe2016-05-28 13:54:12 -0700118 }
Walter Jangf9779ef2016-05-25 12:23:05 -0700119 }
120
121 @Override
Walter Jangf9779ef2016-05-25 12:23:05 -0700122 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) {
John Shao2b0d2982016-07-26 14:50:05 -0700148 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);
Walter Jangf9779ef2016-05-25 12:23:05 -0700157 }
158
159 @Override
160 public int getCount() {
161 return mCount;
162 }
163
164 @Override
165 public int getPosition() {
166 return mPos;
167 }
168 }
169
Walter Jang6c5a5582016-06-16 11:26:53 -0700170 private String mAccountName;
171 private String mAccountType;
172 private String mAccountDataSet;
Walter Jangdd2d8e22016-09-09 11:07:37 -0700173 private ArrayList<String> mContactIds;
Walter Jangf9779ef2016-05-25 12:23:05 -0700174 private Listener mListener;
175
Walter Jang6c5a5582016-06-16 11:26:53 -0700176 public static GroupMemberPickerFragment newInstance(String accountName, String accountType,
Walter Jangdd2d8e22016-09-09 11:07:37 -0700177 String accountDataSet, ArrayList<String> contactIds) {
Walter Jangf9779ef2016-05-25 12:23:05 -0700178 final Bundle args = new Bundle();
Walter Jang6c5a5582016-06-16 11:26:53 -0700179 args.putString(ARG_ACCOUNT_NAME, accountName);
180 args.putString(ARG_ACCOUNT_TYPE, accountType);
181 args.putString(ARG_ACCOUNT_DATA_SET, accountDataSet);
Walter Jangdd2d8e22016-09-09 11:07:37 -0700182 args.putStringArrayList(ARG_CONTACT_IDS, contactIds);
Walter Jangf9779ef2016-05-25 12:23:05 -0700183
184 final GroupMemberPickerFragment fragment = new GroupMemberPickerFragment();
185 fragment.setArguments(args);
186 return fragment;
187 }
188
189 public GroupMemberPickerFragment() {
Walter Jangf9779ef2016-05-25 12:23:05 -0700190 setPhotoLoaderEnabled(true);
Walter Jangdebf9da2016-06-20 12:42:27 -0700191 setSectionHeaderDisplayEnabled(true);
Walter Jangf9779ef2016-05-25 12:23:05 -0700192 setHasOptionsMenu(true);
Tingting Wang6406adb2016-06-27 17:47:03 -0700193 setDisplayDirectoryHeader(false);
Walter Jangf9779ef2016-05-25 12:23:05 -0700194 }
195
196 @Override
197 public void onCreate(Bundle savedState) {
Walter Jangf9779ef2016-05-25 12:23:05 -0700198 if (savedState == null) {
Walter Jang6c5a5582016-06-16 11:26:53 -0700199 mAccountName = getArguments().getString(ARG_ACCOUNT_NAME);
200 mAccountType = getArguments().getString(ARG_ACCOUNT_TYPE);
201 mAccountDataSet = getArguments().getString(ARG_ACCOUNT_DATA_SET);
Walter Jangdd2d8e22016-09-09 11:07:37 -0700202 mContactIds = getArguments().getStringArrayList(ARG_CONTACT_IDS);
Walter Jangf9779ef2016-05-25 12:23:05 -0700203 } else {
Walter Jang6c5a5582016-06-16 11:26:53 -0700204 mAccountName = savedState.getString(KEY_ACCOUNT_NAME);
205 mAccountType = savedState.getString(KEY_ACCOUNT_TYPE);
206 mAccountDataSet = savedState.getString(KEY_ACCOUNT_DATA_SET);
Walter Jangdd2d8e22016-09-09 11:07:37 -0700207 mContactIds = savedState.getStringArrayList(KEY_CONTACT_IDS);
Walter Jangf9779ef2016-05-25 12:23:05 -0700208 }
Walter Jang16c29592016-06-14 15:34:39 -0700209 super.onCreate(savedState);
Walter Jangf9779ef2016-05-25 12:23:05 -0700210 }
211
212 @Override
213 public void onSaveInstanceState(Bundle outState) {
214 super.onSaveInstanceState(outState);
Walter Jang6c5a5582016-06-16 11:26:53 -0700215 outState.putString(KEY_ACCOUNT_NAME, mAccountName);
216 outState.putString(KEY_ACCOUNT_TYPE, mAccountType);
217 outState.putString(KEY_ACCOUNT_DATA_SET, mAccountDataSet);
Walter Jangdd2d8e22016-09-09 11:07:37 -0700218 outState.putStringArrayList(KEY_CONTACT_IDS, mContactIds);
Walter Jangf9779ef2016-05-25 12:23:05 -0700219 }
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) {
Wenyi Wangecc222b2016-06-06 14:35:51 -0700232 if (data != null) {
Walter Jangdebf9da2016-06-20 12:42:27 -0700233 // Wait until contacts are loaded before showing the scrollbar
234 setVisibleScrollbarEnabled(true);
235
Wenyi Wang1114fde2016-07-11 21:44:02 -0700236 final FilterCursorWrapper cursorWrapper = new FilterCursorWrapper(data);
Tingting Wang6406adb2016-06-27 17:47:03 -0700237 final View accountFilterContainer = getView().findViewById(
238 R.id.account_filter_header_container);
Wenyi Wang1114fde2016-07-11 21:44:02 -0700239 final AccountWithDataSet accountWithDataSet = new AccountWithDataSet(mAccountName,
240 mAccountType, mAccountDataSet);
241 bindListHeader(getContext(), getListView(), accountFilterContainer,
242 accountWithDataSet, cursorWrapper.getCount());
Tingting Wang6406adb2016-06-27 17:47:03 -0700243
Wenyi Wang1114fde2016-07-11 21:44:02 -0700244 super.onLoadFinished(loader, cursorWrapper);
Wenyi Wangecc222b2016-06-06 14:35:51 -0700245 }
Walter Jangf9779ef2016-05-25 12:23:05 -0700246 }
247
248 @Override
Walter Jang16c29592016-06-14 15:34:39 -0700249 protected DefaultContactListAdapter createListAdapter() {
250 final DefaultContactListAdapter adapter = new DefaultContactListAdapter(getActivity());
251 adapter.setFilter(ContactListFilter.createGroupMembersFilter(
Walter Jang6c5a5582016-06-16 11:26:53 -0700252 mAccountType, mAccountName, mAccountDataSet));
Walter Jang16c29592016-06-14 15:34:39 -0700253 adapter.setSectionHeaderDisplayEnabled(true);
Walter Jangf9779ef2016-05-25 12:23:05 -0700254 adapter.setDisplayPhotos(true);
255 return adapter;
256 }
257
258 @Override
Walter Jangf9779ef2016-05-25 12:23:05 -0700259 protected void onItemClick(int position, long id) {
Walter Janga4897212016-06-21 19:02:23 -0700260 if (getAdapter().isDisplayingCheckBoxes()) {
261 super.onItemClick(position, id);
262 return;
263 }
Walter Jangf9779ef2016-05-25 12:23:05 -0700264 if (mListener != null) {
Walter Jang16c29592016-06-14 15:34:39 -0700265 final long contactId = getAdapter().getContactId(position);
266 if (contactId > 0) {
267 mListener.onGroupMemberClicked(contactId);
268 }
Walter Jangf9779ef2016-05-25 12:23:05 -0700269 }
270 }
Walter Janga4897212016-06-21 19:02:23 -0700271
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();
Sean Midforde6342c62016-10-20 15:11:19 -0700281 final boolean hasContacts = mContactIds == null ? false : mContactIds.size() > 0;
Walter Janga4897212016-06-21 19:02:23 -0700282 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);
Sean Midforde6342c62016-10-20 15:11:19 -0700287 setVisible(menu, R.id.menu_select, hasContacts && !isSearchMode && !isSelectionMode);
Walter Janga4897212016-06-21 19:02:23 -0700288 }
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 }
Walter Janga4897212016-06-21 19:02:23 -0700315 case R.id.menu_select: {
316 if (mListener != null) {
317 mListener.onSelectGroupMembers();
318 }
319 return true;
320 }
321 }
322 return super.onOptionsItemSelected(item);
323 }
Walter Jangf9779ef2016-05-25 12:23:05 -0700324}