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