• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 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 
17 package com.android.contacts.editor;
18 
19 import com.android.contacts.GroupMetaDataLoader;
20 import com.android.contacts.R;
21 import com.android.contacts.interactions.GroupCreationDialogFragment;
22 import com.android.contacts.model.DataKind;
23 import com.android.contacts.model.EntityDelta;
24 import com.android.contacts.model.EntityDelta.ValuesDelta;
25 import com.android.contacts.model.EntityModifier;
26 import com.android.internal.util.Objects;
27 
28 import android.app.Activity;
29 import android.content.Context;
30 import android.content.res.ColorStateList;
31 import android.content.res.Resources;
32 import android.database.Cursor;
33 import android.provider.ContactsContract.CommonDataKinds.GroupMembership;
34 import android.provider.ContactsContract.RawContacts;
35 import android.util.AttributeSet;
36 import android.view.View;
37 import android.view.View.OnClickListener;
38 import android.widget.AdapterView;
39 import android.widget.AdapterView.OnItemClickListener;
40 import android.widget.ArrayAdapter;
41 import android.widget.LinearLayout;
42 import android.widget.ListPopupWindow;
43 import android.widget.ListView;
44 import android.widget.TextView;
45 
46 import java.util.ArrayList;
47 
48 /**
49  * An editor for group membership.  Displays the current group membership list and
50  * brings up a dialog to change it.
51  */
52 public class GroupMembershipView extends LinearLayout
53         implements OnClickListener, OnItemClickListener {
54 
55     private static final int CREATE_NEW_GROUP_GROUP_ID = 133;
56 
57     public static final class GroupSelectionItem {
58         private final long mGroupId;
59         private final String mTitle;
60         private boolean mChecked;
61 
GroupSelectionItem(long groupId, String title, boolean checked)62         public GroupSelectionItem(long groupId, String title, boolean checked) {
63             this.mGroupId = groupId;
64             this.mTitle = title;
65             mChecked = checked;
66         }
67 
getGroupId()68         public long getGroupId() {
69             return mGroupId;
70         }
71 
isChecked()72         public boolean isChecked() {
73             return mChecked;
74         }
75 
setChecked(boolean checked)76         public void setChecked(boolean checked) {
77             mChecked = checked;
78         }
79 
80         @Override
toString()81         public String toString() {
82             return mTitle;
83         }
84     }
85 
86     private EntityDelta mState;
87     private Cursor mGroupMetaData;
88     private String mAccountName;
89     private String mAccountType;
90     private String mDataSet;
91     private TextView mGroupList;
92     private ArrayAdapter<GroupSelectionItem> mAdapter;
93     private long mDefaultGroupId;
94     private long mFavoritesGroupId;
95     private ListPopupWindow mPopup;
96     private DataKind mKind;
97     private boolean mDefaultGroupVisibilityKnown;
98     private boolean mDefaultGroupVisible;
99 
100     private String mNoGroupString;
101     private int mPrimaryTextColor;
102     private int mSecondaryTextColor;
103 
GroupMembershipView(Context context)104     public GroupMembershipView(Context context) {
105         super(context);
106     }
107 
GroupMembershipView(Context context, AttributeSet attrs)108     public GroupMembershipView(Context context, AttributeSet attrs) {
109         super(context, attrs);
110     }
111 
112     @Override
onFinishInflate()113     protected void onFinishInflate() {
114         super.onFinishInflate();
115         Resources resources = mContext.getResources();
116         mPrimaryTextColor = resources.getColor(R.color.primary_text_color);
117         mSecondaryTextColor = resources.getColor(R.color.secondary_text_color);
118         mNoGroupString = mContext.getString(R.string.group_edit_field_hint_text);
119     }
120 
121     @Override
setEnabled(boolean enabled)122     public void setEnabled(boolean enabled) {
123         super.setEnabled(enabled);
124         if (mGroupList != null) {
125             mGroupList.setEnabled(enabled);
126         }
127     }
128 
setKind(DataKind kind)129     public void setKind(DataKind kind) {
130         mKind = kind;
131         TextView kindTitle = (TextView) findViewById(R.id.kind_title);
132         kindTitle.setText(getResources().getString(kind.titleRes).toUpperCase());
133     }
134 
setGroupMetaData(Cursor groupMetaData)135     public void setGroupMetaData(Cursor groupMetaData) {
136         this.mGroupMetaData = groupMetaData;
137         updateView();
138     }
139 
setState(EntityDelta state)140     public void setState(EntityDelta state) {
141         mState = state;
142         ValuesDelta values = state.getValues();
143         mAccountType = values.getAsString(RawContacts.ACCOUNT_TYPE);
144         mAccountName = values.getAsString(RawContacts.ACCOUNT_NAME);
145         mDataSet = values.getAsString(RawContacts.DATA_SET);
146         mDefaultGroupVisibilityKnown = false;
147         updateView();
148     }
149 
updateView()150     private void updateView() {
151         if (mGroupMetaData == null || mGroupMetaData.isClosed() || mAccountType == null
152                 || mAccountName == null) {
153             setVisibility(GONE);
154             return;
155         }
156 
157         boolean accountHasGroups = false;
158         mFavoritesGroupId = 0;
159         mDefaultGroupId = 0;
160 
161         StringBuilder sb = new StringBuilder();
162         mGroupMetaData.moveToPosition(-1);
163         while (mGroupMetaData.moveToNext()) {
164             String accountName = mGroupMetaData.getString(GroupMetaDataLoader.ACCOUNT_NAME);
165             String accountType = mGroupMetaData.getString(GroupMetaDataLoader.ACCOUNT_TYPE);
166             String dataSet = mGroupMetaData.getString(GroupMetaDataLoader.DATA_SET);
167             if (accountName.equals(mAccountName) && accountType.equals(mAccountType)
168                     && Objects.equal(dataSet, mDataSet)) {
169                 long groupId = mGroupMetaData.getLong(GroupMetaDataLoader.GROUP_ID);
170                 if (!mGroupMetaData.isNull(GroupMetaDataLoader.FAVORITES)
171                         && mGroupMetaData.getInt(GroupMetaDataLoader.FAVORITES) != 0) {
172                     mFavoritesGroupId = groupId;
173                 } else if (!mGroupMetaData.isNull(GroupMetaDataLoader.AUTO_ADD)
174                             && mGroupMetaData.getInt(GroupMetaDataLoader.AUTO_ADD) != 0) {
175                     mDefaultGroupId = groupId;
176                 } else {
177                     accountHasGroups = true;
178                 }
179 
180                 // Exclude favorites from the list - they are handled with special UI (star)
181                 // Also exclude the default group.
182                 if (groupId != mFavoritesGroupId && groupId != mDefaultGroupId
183                         && hasMembership(groupId)) {
184                     String title = mGroupMetaData.getString(GroupMetaDataLoader.TITLE);
185                     if (sb.length() != 0) {
186                         sb.append(", ");
187                     }
188                     sb.append(title);
189                 }
190             }
191         }
192 
193         if (!accountHasGroups) {
194             setVisibility(GONE);
195             return;
196         }
197 
198         if (mGroupList == null) {
199             mGroupList = (TextView) findViewById(R.id.group_list);
200             mGroupList.setOnClickListener(this);
201         }
202 
203         mGroupList.setEnabled(isEnabled());
204         if (sb.length() == 0) {
205             mGroupList.setText(mNoGroupString);
206             mGroupList.setTextColor(mSecondaryTextColor);
207         } else {
208             mGroupList.setText(sb);
209             mGroupList.setTextColor(mPrimaryTextColor);
210         }
211         setVisibility(VISIBLE);
212 
213         if (!mDefaultGroupVisibilityKnown) {
214             // Only show the default group (My Contacts) if the contact is NOT in it
215             mDefaultGroupVisible = mDefaultGroupId != 0 && !hasMembership(mDefaultGroupId);
216             mDefaultGroupVisibilityKnown = true;
217         }
218     }
219 
220     @Override
onClick(View v)221     public void onClick(View v) {
222         if (mPopup != null && mPopup.isShowing()) {
223             mPopup.dismiss();
224             return;
225         }
226 
227         mAdapter = new ArrayAdapter<GroupSelectionItem>(
228                 getContext(), R.layout.group_membership_list_item);
229 
230         mGroupMetaData.moveToPosition(-1);
231         while (mGroupMetaData.moveToNext()) {
232             String accountName = mGroupMetaData.getString(GroupMetaDataLoader.ACCOUNT_NAME);
233             String accountType = mGroupMetaData.getString(GroupMetaDataLoader.ACCOUNT_TYPE);
234             String dataSet = mGroupMetaData.getString(GroupMetaDataLoader.DATA_SET);
235             if (accountName.equals(mAccountName) && accountType.equals(mAccountType)
236                     && Objects.equal(dataSet, mDataSet)) {
237                 long groupId = mGroupMetaData.getLong(GroupMetaDataLoader.GROUP_ID);
238                 if (groupId != mFavoritesGroupId
239                         && (groupId != mDefaultGroupId || mDefaultGroupVisible)) {
240                     String title = mGroupMetaData.getString(GroupMetaDataLoader.TITLE);
241                     boolean checked = hasMembership(groupId);
242                     mAdapter.add(new GroupSelectionItem(groupId, title, checked));
243                 }
244             }
245         }
246 
247         mAdapter.add(new GroupSelectionItem(CREATE_NEW_GROUP_GROUP_ID,
248                 getContext().getString(R.string.create_group_item_label), false));
249 
250         mPopup = new ListPopupWindow(getContext(), null);
251         mPopup.setAnchorView(mGroupList);
252         mPopup.setAdapter(mAdapter);
253         mPopup.setModal(true);
254         mPopup.show();
255 
256         ListView listView = mPopup.getListView();
257         listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
258         int count = mAdapter.getCount();
259         for (int i = 0; i < count; i++) {
260             listView.setItemChecked(i, mAdapter.getItem(i).isChecked());
261         }
262 
263         listView.setOnItemClickListener(this);
264     }
265 
266     @Override
onDetachedFromWindow()267     protected void onDetachedFromWindow() {
268         super.onDetachedFromWindow();
269         if (mPopup != null) {
270             mPopup.dismiss();
271             mPopup = null;
272         }
273     }
274 
275     @Override
onItemClick(AdapterView<?> parent, View view, int position, long id)276     public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
277         ListView list = (ListView) parent;
278         int count = mAdapter.getCount();
279 
280         if (list.isItemChecked(count - 1)) {
281             list.setItemChecked(count - 1, false);
282             createNewGroup();
283             return;
284         }
285 
286         for (int i = 0; i < count; i++) {
287             mAdapter.getItem(i).setChecked(list.isItemChecked(i));
288         }
289 
290         // First remove the memberships that have been unchecked
291         ArrayList<ValuesDelta> entries = mState.getMimeEntries(GroupMembership.CONTENT_ITEM_TYPE);
292         if (entries != null) {
293             for (ValuesDelta entry : entries) {
294                 if (!entry.isDelete()) {
295                     Long groupId = entry.getAsLong(GroupMembership.GROUP_ROW_ID);
296                     if (groupId != null && groupId != mFavoritesGroupId
297                             && (groupId != mDefaultGroupId || mDefaultGroupVisible)
298                             && !isGroupChecked(groupId)) {
299                         entry.markDeleted();
300                     }
301                 }
302             }
303         }
304 
305         // Now add the newly selected items
306         for (int i = 0; i < count; i++) {
307             GroupSelectionItem item = mAdapter.getItem(i);
308             long groupId = item.getGroupId();
309             if (item.isChecked() && !hasMembership(groupId)) {
310                 ValuesDelta entry = EntityModifier.insertChild(mState, mKind);
311                 entry.put(GroupMembership.GROUP_ROW_ID, groupId);
312             }
313         }
314 
315         updateView();
316     }
317 
isGroupChecked(long groupId)318     private boolean isGroupChecked(long groupId) {
319         int count = mAdapter.getCount();
320         for (int i = 0; i < count; i++) {
321             GroupSelectionItem item = mAdapter.getItem(i);
322             if (groupId == item.getGroupId()) {
323                 return item.isChecked();
324             }
325         }
326         return false;
327     }
328 
hasMembership(long groupId)329     private boolean hasMembership(long groupId) {
330         if (groupId == mDefaultGroupId && mState.isContactInsert()) {
331             return true;
332         }
333 
334         ArrayList<ValuesDelta> entries = mState.getMimeEntries(GroupMembership.CONTENT_ITEM_TYPE);
335         if (entries != null) {
336             for (ValuesDelta values : entries) {
337                 if (!values.isDelete()) {
338                     Long id = values.getAsLong(GroupMembership.GROUP_ROW_ID);
339                     if (id != null && id == groupId) {
340                         return true;
341                     }
342                 }
343             }
344         }
345         return false;
346     }
347 
createNewGroup()348     private void createNewGroup() {
349         if (mPopup != null) {
350             mPopup.dismiss();
351             mPopup = null;
352         }
353 
354         GroupCreationDialogFragment.show(
355                 ((Activity) getContext()).getFragmentManager(), mAccountType, mAccountName,
356                 mDataSet);
357     }
358 }
359