blob: 85a050c4911f94a5717981eeb90ff3ed36eb8460 [file] [log] [blame]
/*
* Copyright (C) 2007 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;
import android.content.ContentUris;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.net.Uri;
import android.net.Uri.Builder;
import android.provider.ContactsContract;
import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Contacts.AggregationSuggestions;
import android.text.TextUtils;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
/**
* An activity that shows a list of contacts that can be joined with the target contact.
*/
public class JoinContactActivity extends ContactsListActivity {
private static final String TAG = "JoinContactActivity";
/**
* The action for the join contact activity.
* <p>
* Input: extra field {@link #EXTRA_TARGET_CONTACT_ID} is the aggregate ID.
* TODO: move to {@link ContactsContract}.
*/
public static final String JOIN_CONTACT = "com.android.contacts.action.JOIN_CONTACT";
/**
* Used with {@link #JOIN_CONTACT} to give it the target for aggregation.
* <p>
* Type: LONG
*/
public static final String EXTRA_TARGET_CONTACT_ID = "com.android.contacts.action.CONTACT_ID";
/** Maximum number of suggestions shown for joining aggregates */
private static final int MAX_SUGGESTIONS = 4;
private long mTargetContactId;
/**
* Determines whether we display a list item with the label
* "Show all contacts" or actually show all contacts
*/
private boolean mJoinModeShowAllContacts;
/**
* The ID of the special item described above.
*/
private static final long JOIN_MODE_SHOW_ALL_CONTACTS_ID = -2;
private boolean mLoadingJoinSuggestions;
private JoinContactListAdapter mAdapter;
@Override
protected void resolveIntent(Intent intent) {
mMode = MODE_PICK_CONTACT;
mTargetContactId = intent.getLongExtra(EXTRA_TARGET_CONTACT_ID, -1);
if (mTargetContactId == -1) {
Log.e(TAG, "Intent " + intent.getAction() + " is missing required extra: "
+ EXTRA_TARGET_CONTACT_ID);
setResult(RESULT_CANCELED);
finish();
}
}
@Override
public void initContentView() {
setContentView(R.layout.contacts_list_content_join);
TextView blurbView = (TextView)findViewById(R.id.join_contact_blurb);
String blurb = getString(R.string.blurbJoinContactDataWith,
getContactDisplayName(mTargetContactId));
blurbView.setText(blurb);
mJoinModeShowAllContacts = true;
mAdapter = new JoinContactListAdapter(this);
setupListView(mAdapter);
}
@Override
protected void onListItemClick(int position, long id) {
if (id == JOIN_MODE_SHOW_ALL_CONTACTS_ID) {
mJoinModeShowAllContacts = false;
startQuery();
} else {
final Uri uri = getSelectedUri(position);
returnPickerResult(null, null, uri);
}
}
@Override
protected Uri getUriToQuery() {
return getJoinSuggestionsUri(null);
}
/*
* TODO: move to a background thread.
*/
private String getContactDisplayName(long contactId) {
String contactName = null;
Cursor c = getContentResolver().query(
ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId),
new String[] {Contacts.DISPLAY_NAME}, null, null, null);
try {
if (c != null && c.moveToFirst()) {
contactName = c.getString(0);
}
} finally {
if (c != null) {
c.close();
}
}
if (contactName == null) {
contactName = "";
}
return contactName;
}
private Uri getJoinSuggestionsUri(String filter) {
Builder builder = Contacts.CONTENT_URI.buildUpon();
builder.appendEncodedPath(String.valueOf(mTargetContactId));
builder.appendEncodedPath(AggregationSuggestions.CONTENT_DIRECTORY);
if (!TextUtils.isEmpty(filter)) {
builder.appendEncodedPath(Uri.encode(filter));
}
builder.appendQueryParameter("limit", String.valueOf(MAX_SUGGESTIONS));
return builder.build();
}
@Override
Cursor doFilter(String filter) {
throw new UnsupportedOperationException();
}
private Cursor getShowAllContactsLabelCursor(String[] projection) {
MatrixCursor matrixCursor = new MatrixCursor(projection);
Object[] row = new Object[projection.length];
// The only columns we care about is the id
row[SUMMARY_ID_COLUMN_INDEX] = JOIN_MODE_SHOW_ALL_CONTACTS_ID;
matrixCursor.addRow(row);
return matrixCursor;
}
@Override
protected void startQuery(Uri uri, String[] projection) {
mLoadingJoinSuggestions = true;
startQuery(uri, projection, null, null, null);
}
@Override
protected void onQueryComplete(Cursor cursor) {
// Whenever we get a suggestions cursor, we need to immediately kick off
// another query for the complete list of contacts
if (cursor != null && mLoadingJoinSuggestions) {
mLoadingJoinSuggestions = false;
if (cursor.getCount() > 0) {
mAdapter.setSuggestionsCursor(cursor);
} else {
cursor.close();
mAdapter.setSuggestionsCursor(null);
}
if (mAdapter.mSuggestionsCursorCount == 0
|| !mJoinModeShowAllContacts) {
startQuery(getContactFilterUri(getTextFilter()),
CONTACTS_SUMMARY_PROJECTION,
Contacts._ID + " != " + mTargetContactId
+ " AND " + ContactsContract.Contacts.IN_VISIBLE_GROUP + "=1", null,
getSortOrder(CONTACTS_SUMMARY_PROJECTION));
return;
}
cursor = getShowAllContactsLabelCursor(CONTACTS_SUMMARY_PROJECTION);
}
super.onQueryComplete(cursor);
}
@Override
protected void setEmptyText() {
return;
}
private class JoinContactListAdapter extends ContactItemListAdapter {
Cursor mSuggestionsCursor;
int mSuggestionsCursorCount;
public JoinContactListAdapter(Context context) {
super(context);
}
public void setSuggestionsCursor(Cursor cursor) {
if (mSuggestionsCursor != null) {
mSuggestionsCursor.close();
}
mSuggestionsCursor = cursor;
mSuggestionsCursorCount = cursor == null ? 0 : cursor.getCount();
}
private boolean isShowAllContactsItemPosition(int position) {
return mJoinModeShowAllContacts
&& mSuggestionsCursorCount != 0 && position == mSuggestionsCursorCount + 2;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (!mDataValid) {
throw new IllegalStateException(
"this should only be called when the cursor is valid");
}
if (isShowAllContactsItemPosition(position)) {
return getLayoutInflater().
inflate(R.layout.contacts_list_show_all_item, parent, false);
}
// Handle the separator specially
int separatorId = getSeparatorId(position);
if (separatorId != 0) {
TextView view = (TextView) getLayoutInflater().
inflate(R.layout.list_separator, parent, false);
view.setText(separatorId);
return view;
}
boolean showingSuggestion;
Cursor cursor;
if (mSuggestionsCursorCount != 0 && position < mSuggestionsCursorCount + 2) {
showingSuggestion = true;
cursor = mSuggestionsCursor;
} else {
showingSuggestion = false;
cursor = mCursor;
}
int realPosition = getRealPosition(position);
if (!cursor.moveToPosition(realPosition)) {
throw new IllegalStateException("couldn't move cursor to position " + position);
}
boolean newView;
View v;
if (convertView == null || convertView.getTag() == null) {
newView = true;
v = newView(mContext, cursor, parent);
} else {
newView = false;
v = convertView;
}
bindView(v, mContext, cursor);
bindSectionHeader(v, realPosition, !showingSuggestion);
return v;
}
@Override
public void changeCursor(Cursor cursor) {
if (cursor == null) {
mAdapter.setSuggestionsCursor(null);
}
super.changeCursor(cursor);
}
@Override
public int getItemViewType(int position) {
if (isShowAllContactsItemPosition(position)) {
return IGNORE_ITEM_VIEW_TYPE;
}
return super.getItemViewType(position);
}
private int getSeparatorId(int position) {
if (mSuggestionsCursorCount != 0) {
if (position == 0) {
return R.string.separatorJoinAggregateSuggestions;
} else if (position == mSuggestionsCursorCount + 1) {
return R.string.separatorJoinAggregateAll;
}
}
return 0;
}
@Override
public boolean areAllItemsEnabled() {
return super.areAllItemsEnabled() && mSuggestionsCursorCount == 0;
}
@Override
public boolean isEnabled(int position) {
if (position == 0) {
return false;
}
if (mSuggestionsCursorCount > 0) {
return position != 0 && position != mSuggestionsCursorCount + 1;
}
return true;
}
@Override
public int getCount() {
if (!mDataValid) {
return 0;
}
int superCount = super.getCount();
if (mSuggestionsCursorCount != 0) {
// When showing suggestions, we have 2 additional list items: the "Suggestions"
// and "All contacts" headers.
return mSuggestionsCursorCount + superCount + 2;
}
return superCount;
}
private int getRealPosition(int pos) {
if (mSuggestionsCursorCount != 0) {
// When showing suggestions, we have 2 additional list items: the "Suggestions"
// and "All contacts" separators.
if (pos < mSuggestionsCursorCount + 2) {
// We are in the upper partition (Suggestions). Adjusting for the "Suggestions"
// separator.
return pos - 1;
} else {
// We are in the lower partition (All contacts). Adjusting for the size
// of the upper partition plus the two separators.
return pos - mSuggestionsCursorCount - 2;
}
} else {
// No separator, identity map
return pos;
}
}
@Override
public Object getItem(int pos) {
if (mSuggestionsCursorCount != 0 && pos <= mSuggestionsCursorCount) {
mSuggestionsCursor.moveToPosition(getRealPosition(pos));
return mSuggestionsCursor;
} else {
int realPosition = getRealPosition(pos);
if (realPosition < 0) {
return null;
}
return super.getItem(realPosition);
}
}
@Override
public long getItemId(int pos) {
if (mSuggestionsCursorCount != 0 && pos < mSuggestionsCursorCount + 2) {
if (mSuggestionsCursor.moveToPosition(pos - 1)) {
return mSuggestionsCursor.getLong(mRowIDColumn);
} else {
return 0;
}
}
int realPosition = getRealPosition(pos);
if (realPosition < 0) {
return 0;
}
return super.getItemId(realPosition);
}
}
}