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