GroupMemberPickerFragment.java revision 6c5a5580c49db0e3cc5372beec82231e0aa76901
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.content.Loader;
19import android.database.Cursor;
20import android.database.CursorWrapper;
21import android.os.Bundle;
22import android.util.Log;
23import android.view.LayoutInflater;
24import android.view.View;
25import android.view.ViewGroup;
26
27import com.android.contacts.common.R;
28import com.android.contacts.common.list.ContactEntryListFragment;
29import com.android.contacts.common.list.ContactListAdapter.ContactQuery;
30import com.android.contacts.common.list.ContactListFilter;
31import com.android.contacts.common.list.DefaultContactListAdapter;
32
33import java.util.ArrayList;
34
35/**
36 * Fragment containing raw contacts for a specified account that are not already in a group.
37 */
38public class GroupMemberPickerFragment extends
39        ContactEntryListFragment<DefaultContactListAdapter> {
40
41    public static final String TAG = "GroupMemberPicker";
42
43    private static final String KEY_ACCOUNT_NAME = "accountName";
44    private static final String KEY_ACCOUNT_TYPE = "accountType";
45    private static final String KEY_ACCOUNT_DATA_SET = "accountDataSet";
46    private static final String KEY_RAW_CONTACT_IDS = "rawContactIds";
47
48    private static final String ARG_ACCOUNT_NAME = "accountName";
49    private static final String ARG_ACCOUNT_TYPE = "accountType";
50    private static final String ARG_ACCOUNT_DATA_SET = "accountDataSet";
51    private static final String ARG_RAW_CONTACT_IDS = "rawContactIds";
52
53    /** Callbacks for host of {@link GroupMemberPickerFragment}. */
54    public interface Listener {
55
56        /** Invoked when a potential group member is selected. */
57        void onGroupMemberClicked(long contactId);
58    }
59
60    /**
61     * Filters out raw contacts that are already in the group and also handles queries for contact
62     * photo IDs and lookup keys which cannot be retrieved from the raw contact table directly.
63     */
64    private class FilterCursorWrapper extends CursorWrapper {
65
66        private int[] mIndex;
67        private int mCount = 0;
68        private int mPos = 0;
69
70        public FilterCursorWrapper(Cursor cursor) {
71            super(cursor);
72
73            mCount = super.getCount();
74            mIndex = new int[mCount];
75
76            if (Log.isLoggable(TAG, Log.VERBOSE)) {
77                Log.v(TAG, "FilterCursorWrapper starting cursor size is " + mCount);
78            }
79
80            for (int i = 0; i < mCount; i++) {
81                super.moveToPosition(i);
82                final String contactId = getString(ContactQuery.CONTACT_ID);
83                if (!mRawContactIds.contains(contactId)) {
84                    mIndex[mPos++] = i;
85                }
86            }
87            mCount = mPos;
88            mPos = 0;
89            super.moveToFirst();
90
91            if (Log.isLoggable(TAG, Log.VERBOSE)) {
92                Log.v(TAG, "FilterCursorWrapper ending cursor size is" + mCount);
93            }
94        }
95
96        @Override
97        public boolean move(int offset) {
98            return moveToPosition(mPos + offset);
99        }
100
101        @Override
102        public boolean moveToNext() {
103            return moveToPosition(mPos + 1);
104        }
105
106        @Override
107        public boolean moveToPrevious() {
108            return moveToPosition(mPos - 1);
109        }
110
111        @Override
112        public boolean moveToFirst() {
113            return moveToPosition(0);
114        }
115
116        @Override
117        public boolean moveToLast() {
118            return moveToPosition(mCount - 1);
119        }
120
121        @Override
122        public boolean moveToPosition(int position) {
123            if (position >= mCount || position < 0) return false;
124            return super.moveToPosition(mIndex[position]);
125        }
126
127        @Override
128        public int getCount() {
129            return mCount;
130        }
131
132        @Override
133        public int getPosition() {
134            return mPos;
135        }
136    }
137
138    private String mAccountName;
139    private String mAccountType;
140    private String mAccountDataSet;
141    private ArrayList<String> mRawContactIds;
142    private Listener mListener;
143
144    public static GroupMemberPickerFragment newInstance(String accountName, String accountType,
145            String accountDataSet, ArrayList<String> rawContactIds) {
146        final Bundle args = new Bundle();
147        args.putString(ARG_ACCOUNT_NAME, accountName);
148        args.putString(ARG_ACCOUNT_TYPE, accountType);
149        args.putString(ARG_ACCOUNT_DATA_SET, accountDataSet);
150        args.putStringArrayList(ARG_RAW_CONTACT_IDS, rawContactIds);
151
152        final GroupMemberPickerFragment fragment = new GroupMemberPickerFragment();
153        fragment.setArguments(args);
154        return fragment;
155    }
156
157    public GroupMemberPickerFragment() {
158        setPhotoLoaderEnabled(true);
159        setSectionHeaderDisplayEnabled(false);
160        setVisibleScrollbarEnabled(true);
161
162        setHasOptionsMenu(true);
163    }
164
165    @Override
166    public void onCreate(Bundle savedState) {
167        if (savedState == null) {
168            mAccountName = getArguments().getString(ARG_ACCOUNT_NAME);
169            mAccountType = getArguments().getString(ARG_ACCOUNT_TYPE);
170            mAccountDataSet = getArguments().getString(ARG_ACCOUNT_DATA_SET);
171            mRawContactIds = getArguments().getStringArrayList(ARG_RAW_CONTACT_IDS);
172        } else {
173            mAccountName = savedState.getString(KEY_ACCOUNT_NAME);
174            mAccountType = savedState.getString(KEY_ACCOUNT_TYPE);
175            mAccountDataSet = savedState.getString(KEY_ACCOUNT_DATA_SET);
176            mRawContactIds = savedState.getStringArrayList(KEY_RAW_CONTACT_IDS);
177        }
178        super.onCreate(savedState);
179    }
180
181    @Override
182    public void onSaveInstanceState(Bundle outState) {
183        super.onSaveInstanceState(outState);
184        outState.putString(KEY_ACCOUNT_NAME, mAccountName);
185        outState.putString(KEY_ACCOUNT_TYPE, mAccountType);
186        outState.putString(KEY_ACCOUNT_DATA_SET, mAccountDataSet);
187        outState.putStringArrayList(KEY_RAW_CONTACT_IDS, mRawContactIds);
188    }
189
190    public void setListener(Listener listener) {
191        mListener = listener;
192    }
193
194    @Override
195    protected View inflateView(LayoutInflater inflater, ViewGroup container) {
196        return inflater.inflate(R.layout.contact_list_content, null);
197    }
198
199    @Override
200    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
201        if (data != null) {
202            super.onLoadFinished(loader, new FilterCursorWrapper(data));
203        }
204    }
205
206    @Override
207    protected DefaultContactListAdapter createListAdapter() {
208        final DefaultContactListAdapter adapter = new DefaultContactListAdapter(getActivity());
209        adapter.setFilter(ContactListFilter.createGroupMembersFilter(
210                mAccountType, mAccountName, mAccountDataSet));
211        adapter.setSectionHeaderDisplayEnabled(true);
212        adapter.setDisplayPhotos(true);
213        return adapter;
214    }
215
216    @Override
217    protected void onItemClick(int position, long id) {
218        if (mListener != null) {
219            final long contactId = getAdapter().getContactId(position);
220            if (contactId > 0) {
221                mListener.onGroupMemberClicked(contactId);
222            }
223        }
224    }
225}
226