/* * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.contacts.editor; import com.android.contacts.GroupMetaDataLoader; import com.android.contacts.R; import com.android.contacts.interactions.GroupCreationDialogFragment; import com.android.contacts.model.DataKind; import com.android.contacts.model.EntityDelta; import com.android.contacts.model.EntityDelta.ValuesDelta; import com.android.contacts.model.EntityModifier; import com.android.internal.util.Objects; import android.app.Activity; import android.content.Context; import android.content.res.ColorStateList; import android.content.res.Resources; import android.database.Cursor; import android.provider.ContactsContract.CommonDataKinds.GroupMembership; import android.provider.ContactsContract.RawContacts; import android.text.TextUtils; import android.util.AttributeSet; import android.view.View; import android.view.View.OnClickListener; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.ArrayAdapter; import android.widget.LinearLayout; import android.widget.ListPopupWindow; import android.widget.ListView; import android.widget.TextView; import java.util.ArrayList; /** * An editor for group membership. Displays the current group membership list and * brings up a dialog to change it. */ public class GroupMembershipView extends LinearLayout implements OnClickListener, OnItemClickListener { private static final int CREATE_NEW_GROUP_GROUP_ID = 133; public static final class GroupSelectionItem { private final long mGroupId; private final String mTitle; private boolean mChecked; public GroupSelectionItem(long groupId, String title, boolean checked) { this.mGroupId = groupId; this.mTitle = title; mChecked = checked; } public long getGroupId() { return mGroupId; } public boolean isChecked() { return mChecked; } public void setChecked(boolean checked) { mChecked = checked; } @Override public String toString() { return mTitle; } } private EntityDelta mState; private Cursor mGroupMetaData; private String mAccountName; private String mAccountType; private String mDataSet; private TextView mGroupList; private ArrayAdapter<GroupSelectionItem> mAdapter; private long mDefaultGroupId; private long mFavoritesGroupId; private ListPopupWindow mPopup; private DataKind mKind; private boolean mDefaultGroupVisibilityKnown; private boolean mDefaultGroupVisible; private String mNoGroupString; private int mPrimaryTextColor; private int mSecondaryTextColor; public GroupMembershipView(Context context) { super(context); } public GroupMembershipView(Context context, AttributeSet attrs) { super(context, attrs); } @Override protected void onFinishInflate() { super.onFinishInflate(); Resources resources = mContext.getResources(); mPrimaryTextColor = resources.getColor(R.color.primary_text_color); mSecondaryTextColor = resources.getColor(R.color.secondary_text_color); mNoGroupString = mContext.getString(R.string.group_edit_field_hint_text); } @Override public void setEnabled(boolean enabled) { super.setEnabled(enabled); if (mGroupList != null) { mGroupList.setEnabled(enabled); } } public void setKind(DataKind kind) { mKind = kind; TextView kindTitle = (TextView) findViewById(R.id.kind_title); kindTitle.setText(getResources().getString(kind.titleRes).toUpperCase()); } public void setGroupMetaData(Cursor groupMetaData) { this.mGroupMetaData = groupMetaData; updateView(); } public void setState(EntityDelta state) { mState = state; ValuesDelta values = state.getValues(); mAccountType = values.getAsString(RawContacts.ACCOUNT_TYPE); mAccountName = values.getAsString(RawContacts.ACCOUNT_NAME); mDataSet = values.getAsString(RawContacts.DATA_SET); mDefaultGroupVisibilityKnown = false; updateView(); } private void updateView() { if (mGroupMetaData == null || mGroupMetaData.isClosed() || mAccountType == null || mAccountName == null) { setVisibility(GONE); return; } boolean accountHasGroups = false; mFavoritesGroupId = 0; mDefaultGroupId = 0; StringBuilder sb = new StringBuilder(); mGroupMetaData.moveToPosition(-1); while (mGroupMetaData.moveToNext()) { String accountName = mGroupMetaData.getString(GroupMetaDataLoader.ACCOUNT_NAME); String accountType = mGroupMetaData.getString(GroupMetaDataLoader.ACCOUNT_TYPE); String dataSet = mGroupMetaData.getString(GroupMetaDataLoader.DATA_SET); if (accountName.equals(mAccountName) && accountType.equals(mAccountType) && Objects.equal(dataSet, mDataSet)) { long groupId = mGroupMetaData.getLong(GroupMetaDataLoader.GROUP_ID); if (!mGroupMetaData.isNull(GroupMetaDataLoader.FAVORITES) && mGroupMetaData.getInt(GroupMetaDataLoader.FAVORITES) != 0) { mFavoritesGroupId = groupId; } else if (!mGroupMetaData.isNull(GroupMetaDataLoader.AUTO_ADD) && mGroupMetaData.getInt(GroupMetaDataLoader.AUTO_ADD) != 0) { mDefaultGroupId = groupId; } else { accountHasGroups = true; } // Exclude favorites from the list - they are handled with special UI (star) // Also exclude the default group. if (groupId != mFavoritesGroupId && groupId != mDefaultGroupId && hasMembership(groupId)) { String title = mGroupMetaData.getString(GroupMetaDataLoader.TITLE); if (!TextUtils.isEmpty(title)) { if (sb.length() != 0) { sb.append(", "); } sb.append(title); } } } } if (!accountHasGroups) { setVisibility(GONE); return; } if (mGroupList == null) { mGroupList = (TextView) findViewById(R.id.group_list); mGroupList.setOnClickListener(this); } mGroupList.setEnabled(isEnabled()); if (sb.length() == 0) { mGroupList.setText(mNoGroupString); mGroupList.setTextColor(mSecondaryTextColor); } else { mGroupList.setText(sb); mGroupList.setTextColor(mPrimaryTextColor); } setVisibility(VISIBLE); if (!mDefaultGroupVisibilityKnown) { // Only show the default group (My Contacts) if the contact is NOT in it mDefaultGroupVisible = mDefaultGroupId != 0 && !hasMembership(mDefaultGroupId); mDefaultGroupVisibilityKnown = true; } } @Override public void onClick(View v) { if (mPopup != null && mPopup.isShowing()) { mPopup.dismiss(); return; } mAdapter = new ArrayAdapter<GroupSelectionItem>( getContext(), R.layout.group_membership_list_item); mGroupMetaData.moveToPosition(-1); while (mGroupMetaData.moveToNext()) { String accountName = mGroupMetaData.getString(GroupMetaDataLoader.ACCOUNT_NAME); String accountType = mGroupMetaData.getString(GroupMetaDataLoader.ACCOUNT_TYPE); String dataSet = mGroupMetaData.getString(GroupMetaDataLoader.DATA_SET); if (accountName.equals(mAccountName) && accountType.equals(mAccountType) && Objects.equal(dataSet, mDataSet)) { long groupId = mGroupMetaData.getLong(GroupMetaDataLoader.GROUP_ID); if (groupId != mFavoritesGroupId && (groupId != mDefaultGroupId || mDefaultGroupVisible)) { String title = mGroupMetaData.getString(GroupMetaDataLoader.TITLE); boolean checked = hasMembership(groupId); mAdapter.add(new GroupSelectionItem(groupId, title, checked)); } } } mAdapter.add(new GroupSelectionItem(CREATE_NEW_GROUP_GROUP_ID, getContext().getString(R.string.create_group_item_label), false)); mPopup = new ListPopupWindow(getContext(), null); mPopup.setAnchorView(mGroupList); mPopup.setAdapter(mAdapter); mPopup.setModal(true); mPopup.show(); ListView listView = mPopup.getListView(); listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE); listView.setOverScrollMode(OVER_SCROLL_ALWAYS); int count = mAdapter.getCount(); for (int i = 0; i < count; i++) { listView.setItemChecked(i, mAdapter.getItem(i).isChecked()); } listView.setOnItemClickListener(this); } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); if (mPopup != null) { mPopup.dismiss(); mPopup = null; } } @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { ListView list = (ListView) parent; int count = mAdapter.getCount(); if (list.isItemChecked(count - 1)) { list.setItemChecked(count - 1, false); createNewGroup(); return; } for (int i = 0; i < count; i++) { mAdapter.getItem(i).setChecked(list.isItemChecked(i)); } // First remove the memberships that have been unchecked ArrayList<ValuesDelta> entries = mState.getMimeEntries(GroupMembership.CONTENT_ITEM_TYPE); if (entries != null) { for (ValuesDelta entry : entries) { if (!entry.isDelete()) { Long groupId = entry.getAsLong(GroupMembership.GROUP_ROW_ID); if (groupId != null && groupId != mFavoritesGroupId && (groupId != mDefaultGroupId || mDefaultGroupVisible) && !isGroupChecked(groupId)) { entry.markDeleted(); } } } } // Now add the newly selected items for (int i = 0; i < count; i++) { GroupSelectionItem item = mAdapter.getItem(i); long groupId = item.getGroupId(); if (item.isChecked() && !hasMembership(groupId)) { ValuesDelta entry = EntityModifier.insertChild(mState, mKind); entry.put(GroupMembership.GROUP_ROW_ID, groupId); } } updateView(); } private boolean isGroupChecked(long groupId) { int count = mAdapter.getCount(); for (int i = 0; i < count; i++) { GroupSelectionItem item = mAdapter.getItem(i); if (groupId == item.getGroupId()) { return item.isChecked(); } } return false; } private boolean hasMembership(long groupId) { if (groupId == mDefaultGroupId && mState.isContactInsert()) { return true; } ArrayList<ValuesDelta> entries = mState.getMimeEntries(GroupMembership.CONTENT_ITEM_TYPE); if (entries != null) { for (ValuesDelta values : entries) { if (!values.isDelete()) { Long id = values.getAsLong(GroupMembership.GROUP_ROW_ID); if (id != null && id == groupId) { return true; } } } } return false; } private void createNewGroup() { if (mPopup != null) { mPopup.dismiss(); mPopup = null; } GroupCreationDialogFragment.show( ((Activity) getContext()).getFragmentManager(), mAccountType, mAccountName, mDataSet); } }