ContactsListActivitypublic final class ContactsListActivity extends android.app.ListActivity implements View.OnCreateContextMenuListener, DialogInterface.OnClickListenerDisplays a list of contacts. Usually is embedded into the ContactsActivity. |
Fields Summary |
---|
private static final String | TAG | private static final String | LIST_STATE_KEY | private static final String | FOCUS_KEY | static final int | MENU_ITEM_VIEW_CONTACT | static final int | MENU_ITEM_CALL | static final int | MENU_ITEM_EDIT_BEFORE_CALL | static final int | MENU_ITEM_SEND_SMS | static final int | MENU_ITEM_SEND_IM | static final int | MENU_ITEM_EDIT | static final int | MENU_ITEM_DELETE | static final int | MENU_ITEM_TOGGLE_STAR | public static final int | MENU_SEARCH | public static final int | MENU_DIALER | public static final int | MENU_NEW_CONTACT | public static final int | MENU_DISPLAY_GROUP | private static final int | SUBACTIVITY_NEW_CONTACT | static final int | MODE_MASK_PICKERMask for picker mode | static final int | MODE_MASK_NO_PRESENCEMask for no presence mode | static final int | MODE_MASK_NO_FILTERMask for enabling list filtering | static final int | MODE_MASK_CREATE_NEWMask for having a "create new contact" header in the list | static final int | MODE_MASK_SHOW_PHOTOSMask for showing photos in the list | static final int | MODE_UNKNOWNUnknown mode | static final int | MODE_GROUPShow members of the "Contacts" group | static final int | MODE_ALL_CONTACTSShow all contacts sorted alphabetically | static final int | MODE_WITH_PHONESShow all contacts with phone numbers, sorted alphabetically | static final int | MODE_STARREDShow all starred contacts | static final int | MODE_FREQUENTShow frequently contacted contacts | static final int | MODE_STREQUENTShow starred and the frequent | static final int | MODE_PICK_CONTACTShow all contacts and pick them when clicking | static final int | MODE_PICK_OR_CREATE_CONTACTShow all contacts as well as the option to create a new one | static final int | MODE_INSERT_OR_EDIT_CONTACTShow all contacts and pick them when clicking, and allow creating a new contact | static final int | MODE_PICK_PHONEShow all phone numbers and pick them when clicking | static final int | MODE_PICK_POSTALShow all postal addresses and pick them when clicking | static final int | MODE_QUERYRun a search query | static final int | MODE_QUERY_PICK_TO_VIEWRun a search query in PICK mode, but that still launches to VIEW | static final int | DEFAULT_MODE | static final String | PREF_DISPLAY_TYPEThe type of data to display in the main contacts list. | static final int | DISPLAY_TYPE_UNKNOWNUnknown display type. | static final int | DISPLAY_TYPE_ALLDisplay all contacts | static final int | DISPLAY_TYPE_ALL_WITH_PHONESDisplay all contacts that have phone numbers | static final int | DISPLAY_TYPE_SYSTEM_GROUPDisplay a system group | static final int | DISPLAY_TYPE_USER_GROUPDisplay a user group | static final String | PREF_DISPLAY_INFOInfo about what to display. If {@link #PREF_DISPLAY_TYPE}
is {@link #DISPLAY_TYPE_SYSTEM_GROUP} then this will be the system id.
If {@link #PREF_DISPLAY_TYPE} is {@link #DISPLAY_TYPE_USER_GROUP} then this will
be the group name. | static final String | NAME_COLUMN | static final String | SORT_STRING | static final String[] | CONTACTS_PROJECTION | static final String[] | SIMPLE_CONTACTS_PROJECTION | static final String[] | STREQUENT_PROJECTION | static final String[] | PHONES_PROJECTION | static final String[] | CONTACT_METHODS_PROJECTION | static final int | ID_COLUMN_INDEX | static final int | NAME_COLUMN_INDEX | static final int | NUMBER_COLUMN_INDEX | static final int | DATA_COLUMN_INDEX | static final int | TYPE_COLUMN_INDEX | static final int | LABEL_COLUMN_INDEX | static final int | STARRED_COLUMN_INDEX | static final int | PRIMARY_PHONE_ID_COLUMN_INDEX | static final int | PRIMARY_EMAIL_ID_COLUMN_INDEX | static final int | SERVER_STATUS_COLUMN_INDEX | static final int | PHOTO_COLUMN_INDEX | static final int | SORT_STRING_INDEX | static final int | PHONES_PERSON_ID_INDEX | static final int | SIMPLE_CONTACTS_PERSON_ID_INDEX | static final int | DISPLAY_GROUP_INDEX_ALL_CONTACTS | static final int | DISPLAY_GROUP_INDEX_ALL_CONTACTS_WITH_PHONES | static final int | DISPLAY_GROUP_INDEX_MY_CONTACTS | private static final int | QUERY_TOKEN | private static final String[] | GROUPS_PROJECTION | private static final int | GROUPS_COLUMN_INDEX_SYSTEM_ID | private static final int | GROUPS_COLUMN_INDEX_NAME | static final String | GROUP_WITH_PHONES | ContactItemListAdapter | mAdapter | int | mMode | private String | mDisplayInfo | private int | mDisplayType | private CharSequence[] | mDisplayGroups | private boolean | mDisplayGroupsIncludesMyContacts | private int | mDisplayGroupOriginalSelection | private int | mDisplayGroupCurrentSelection | private QueryHandler | mQueryHandler | private String | mQuery | private android.net.Uri | mGroupFilterUri | private android.net.Uri | mGroupUri | private boolean | mJustCreated | private boolean | mSyncEnabled | private int | mQueryPersonIdIndexCursor row index that holds reference back to {@link People#_ID}, such as
{@link ContactMethods#PERSON_ID}. Used when responding to a
{@link Intent#ACTION_SEARCH} in mode {@link #MODE_QUERY_PICK_TO_VIEW}. | private android.os.Parcelable | mListStateUsed to keep track of the scroll state of the list. | private boolean | mListHasFocus | private boolean | mCreateShortcut | private boolean | mDefaultMode | private int | mQueryModeInternal query type when in mode {@link #MODE_QUERY_PICK_TO_VIEW}. | private static final int | QUERY_MODE_NONE | private static final int | QUERY_MODE_MAILTO | private static final int | QUERY_MODE_TEL | private String | mQueryDataData to use when in mode {@link #MODE_QUERY_PICK_TO_VIEW}. Usually
provided by scheme-specific part of incoming {@link Intent#getData()}. |
Methods Summary |
---|
private void | buildSystemGroupUris(java.lang.String systemId)Builds the URIs to query when displaying a system group
mGroupFilterUri = Uri.parse("content://contacts/groups/system_id/" + systemId
+ "/members/filter/");
mGroupUri = Uri.parse("content://contacts/groups/system_id/" + systemId + "/members");
| private void | buildUserGroupUris(java.lang.String groupName)Builds the URIs to query when displaying a user group
mGroupFilterUri = Uri.parse("content://contacts/groups/name/" + groupName
+ "/members/filter/");
mGroupUri = Uri.parse("content://contacts/groups/name/" + groupName + "/members");
| boolean | callSelection()Calls the currently selected list item.
ListView list = getListView();
if (list.hasFocus()) {
Cursor cursor = (Cursor) list.getSelectedItem();
if (cursor != null) {
long phoneId = cursor.getLong(PRIMARY_PHONE_ID_COLUMN_INDEX);
if (phoneId == 0) {
// There is no phone number.
signalError();
return false;
}
Uri uri = ContentUris.withAppendedId(Phones.CONTENT_URI, phoneId);
Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED, uri);
startActivity(intent);
return true;
}
}
return false;
| android.database.Cursor | doFilter(java.lang.String filter)Called from a background thread to do the filter and return the resulting cursor.
final ContentResolver resolver = getContentResolver();
switch (mMode) {
case MODE_GROUP: {
Uri uri;
if (TextUtils.isEmpty(filter)) {
uri = mGroupUri;
} else {
uri = Uri.withAppendedPath(mGroupFilterUri, Uri.encode(filter));
}
return resolver.query(uri, CONTACTS_PROJECTION, null, null,
getSortOrder(CONTACTS_PROJECTION));
}
case MODE_ALL_CONTACTS:
case MODE_PICK_CONTACT:
case MODE_PICK_OR_CREATE_CONTACT:
case MODE_INSERT_OR_EDIT_CONTACT: {
return resolver.query(getPeopleFilterUri(filter), CONTACTS_PROJECTION, null, null,
getSortOrder(CONTACTS_PROJECTION));
}
case MODE_WITH_PHONES: {
return resolver.query(getPeopleFilterUri(filter), CONTACTS_PROJECTION,
People.PRIMARY_PHONE_ID + " IS NOT NULL", null,
getSortOrder(CONTACTS_PROJECTION));
}
case MODE_STARRED: {
return resolver.query(getPeopleFilterUri(filter), CONTACTS_PROJECTION,
People.STARRED + "=1", null, getSortOrder(CONTACTS_PROJECTION));
}
case MODE_FREQUENT: {
return resolver.query(getPeopleFilterUri(filter), CONTACTS_PROJECTION,
People.TIMES_CONTACTED + " > 0", null,
People.TIMES_CONTACTED + " DESC, " + getSortOrder(CONTACTS_PROJECTION));
}
case MODE_STREQUENT: {
Uri uri;
if (!TextUtils.isEmpty(filter)) {
uri = Uri.withAppendedPath(People.CONTENT_URI, "strequent/filter/"
+ Uri.encode(filter));
} else {
uri = Uri.withAppendedPath(People.CONTENT_URI, "strequent");
}
return resolver.query(uri, STREQUENT_PROJECTION, null, null, null);
}
case MODE_PICK_PHONE: {
Uri uri;
if (!TextUtils.isEmpty(filter)) {
uri = Uri.withAppendedPath(Phones.CONTENT_URI, "filter_name/"
+ Uri.encode(filter));
} else {
uri = Phones.CONTENT_URI;
}
return resolver.query(uri, PHONES_PROJECTION, null, null,
getSortOrder(PHONES_PROJECTION));
}
}
throw new UnsupportedOperationException("filtering not allowed in mode " + mMode);
| android.database.Cursor | getItemForView(android.view.View view)
ListView listView = getListView();
int index = listView.getPositionForView(view);
if (index < 0) {
return null;
}
return (Cursor) listView.getAdapter().getItem(index);
| private android.net.Uri | getPeopleFilterUri(java.lang.String filter)
if (!TextUtils.isEmpty(filter)) {
return Uri.withAppendedPath(People.CONTENT_FILTER_URI, Uri.encode(filter));
} else {
return People.CONTENT_URI;
}
| java.lang.String[] | getProjection()
switch (mMode) {
case MODE_GROUP:
case MODE_ALL_CONTACTS:
case MODE_WITH_PHONES:
case MODE_PICK_CONTACT:
case MODE_PICK_OR_CREATE_CONTACT:
case MODE_QUERY:
case MODE_STARRED:
case MODE_FREQUENT:
case MODE_INSERT_OR_EDIT_CONTACT:
return CONTACTS_PROJECTION;
case MODE_STREQUENT:
return STREQUENT_PROJECTION;
case MODE_PICK_PHONE:
return PHONES_PROJECTION;
case MODE_PICK_POSTAL:
return CONTACT_METHODS_PROJECTION;
}
return null;
| private static java.lang.String | getSortOrder(java.lang.String[] projectionType)
if (Locale.getDefault().equals(Locale.JAPAN) &&
projectionType == CONTACTS_PROJECTION) {
return SORT_STRING + " ASC";
} else {
return NAME_COLUMN + " COLLATE LOCALIZED ASC";
}
| protected void | onActivityResult(int requestCode, int resultCode, android.content.Intent data)
switch (requestCode) {
case SUBACTIVITY_NEW_CONTACT:
if (resultCode == RESULT_OK) {
// Contact was created, pass it back
returnPickerResult(data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME),
data.getData());
}
}
| public void | onClick(android.content.DialogInterface dialogInterface, int which)
if (which == DialogInterface.BUTTON_POSITIVE) {
// The OK button was pressed
if (mDisplayGroupOriginalSelection != mDisplayGroupCurrentSelection) {
// Set the group to display
if (mDisplayGroupCurrentSelection == DISPLAY_GROUP_INDEX_ALL_CONTACTS) {
// Display all
mDisplayType = DISPLAY_TYPE_ALL;
mDisplayInfo = null;
} else if (mDisplayGroupCurrentSelection
== DISPLAY_GROUP_INDEX_ALL_CONTACTS_WITH_PHONES) {
// Display all with phone numbers
mDisplayType = DISPLAY_TYPE_ALL_WITH_PHONES;
mDisplayInfo = null;
} else if (mDisplayGroupsIncludesMyContacts &&
mDisplayGroupCurrentSelection == DISPLAY_GROUP_INDEX_MY_CONTACTS) {
mDisplayType = DISPLAY_TYPE_SYSTEM_GROUP;
mDisplayInfo = Groups.GROUP_MY_CONTACTS;
} else {
mDisplayType = DISPLAY_TYPE_USER_GROUP;
mDisplayInfo = mDisplayGroups[mDisplayGroupCurrentSelection].toString();
}
// Save the changes to the preferences
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
prefs.edit()
.putInt(PREF_DISPLAY_TYPE, mDisplayType)
.putString(PREF_DISPLAY_INFO, mDisplayInfo)
.commit();
// Update the display state
updateGroup();
}
} else {
// A list item was selected, cache the position
mDisplayGroupCurrentSelection = which;
}
| public boolean | onContextItemSelected(android.view.MenuItem item)
AdapterView.AdapterContextMenuInfo info;
try {
info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
} catch (ClassCastException e) {
Log.e(TAG, "bad menuInfo", e);
return false;
}
Cursor cursor = (Cursor) getListAdapter().getItem(info.position);
switch (item.getItemId()) {
case MENU_ITEM_TOGGLE_STAR: {
// Toggle the star
ContentValues values = new ContentValues(1);
values.put(People.STARRED, cursor.getInt(STARRED_COLUMN_INDEX) == 0 ? 1 : 0);
Uri personUri = ContentUris.withAppendedId(People.CONTENT_URI,
cursor.getInt(ID_COLUMN_INDEX));
getContentResolver().update(personUri, values, null, null);
return true;
}
case MENU_ITEM_DELETE: {
// Get confirmation
Uri uri = ContentUris.withAppendedId(People.CONTENT_URI,
cursor.getLong(ID_COLUMN_INDEX));
//TODO make this dialog persist across screen rotations
new AlertDialog.Builder(ContactsListActivity.this)
.setTitle(R.string.deleteConfirmation_title)
.setIcon(android.R.drawable.ic_dialog_alert)
.setMessage(R.string.deleteConfirmation)
.setNegativeButton(android.R.string.cancel, null)
.setPositiveButton(android.R.string.ok, new DeleteClickListener(uri))
.show();
return true;
}
}
return super.onContextItemSelected(item);
| protected void | onCreate(android.os.Bundle icicle)
super.onCreate(icicle);
// Resolve the intent
final Intent intent = getIntent();
// Allow the title to be set to a custom String using an extra on the intent
String title = intent.getStringExtra(Contacts.Intents.UI.TITLE_EXTRA_KEY);
if (title != null) {
setTitle(title);
}
final String action = intent.getAction();
mMode = MODE_UNKNOWN;
setContentView(R.layout.contacts_list_content);
if (UI.LIST_DEFAULT.equals(action)) {
mDefaultMode = true;
// When mDefaultMode is true the mode is set in onResume(), since the preferneces
// activity may change it whenever this activity isn't running
} else if (UI.LIST_GROUP_ACTION.equals(action)) {
mMode = MODE_GROUP;
String groupName = intent.getStringExtra(UI.GROUP_NAME_EXTRA_KEY);
if (TextUtils.isEmpty(groupName)) {
finish();
return;
}
buildUserGroupUris(groupName);
} else if (UI.LIST_ALL_CONTACTS_ACTION.equals(action)) {
mMode = MODE_ALL_CONTACTS;
} else if (UI.LIST_STARRED_ACTION.equals(action)) {
mMode = MODE_STARRED;
} else if (UI.LIST_FREQUENT_ACTION.equals(action)) {
mMode = MODE_FREQUENT;
} else if (UI.LIST_STREQUENT_ACTION.equals(action)) {
mMode = MODE_STREQUENT;
} else if (UI.LIST_CONTACTS_WITH_PHONES_ACTION.equals(action)) {
mMode = MODE_WITH_PHONES;
} else if (Intent.ACTION_PICK.equals(action)) {
// XXX These should be showing the data from the URI given in
// the Intent.
final String type = intent.resolveType(this);
if (People.CONTENT_TYPE.equals(type)) {
mMode = MODE_PICK_CONTACT;
} else if (Phones.CONTENT_TYPE.equals(type)) {
mMode = MODE_PICK_PHONE;
} else if (ContactMethods.CONTENT_POSTAL_TYPE.equals(type)) {
mMode = MODE_PICK_POSTAL;
}
} else if (Intent.ACTION_CREATE_SHORTCUT.equals(action)) {
mMode = MODE_PICK_OR_CREATE_CONTACT;
mCreateShortcut = true;
} else if (Intent.ACTION_GET_CONTENT.equals(action)) {
final String type = intent.resolveType(this);
if (People.CONTENT_ITEM_TYPE.equals(type)) {
mMode = MODE_PICK_OR_CREATE_CONTACT;
} else if (Phones.CONTENT_ITEM_TYPE.equals(type)) {
mMode = MODE_PICK_PHONE;
} else if (ContactMethods.CONTENT_POSTAL_ITEM_TYPE.equals(type)) {
mMode = MODE_PICK_POSTAL;
}
} else if (Intent.ACTION_INSERT_OR_EDIT.equals(action)) {
mMode = MODE_INSERT_OR_EDIT_CONTACT;
} else if (Intent.ACTION_SEARCH.equals(action)) {
// See if the suggestion was clicked with a search action key (call button)
if ("call".equals(intent.getStringExtra(SearchManager.ACTION_MSG))) {
String query = intent.getStringExtra(SearchManager.QUERY);
if (!TextUtils.isEmpty(query)) {
Intent newIntent = new Intent(Intent.ACTION_CALL_PRIVILEGED,
Uri.fromParts("tel", query, null));
startActivity(newIntent);
}
finish();
return;
}
// See if search request has extras to specify query
if (intent.hasExtra(Insert.EMAIL)) {
mMode = MODE_QUERY_PICK_TO_VIEW;
mQueryMode = QUERY_MODE_MAILTO;
mQueryData = intent.getStringExtra(Insert.EMAIL);
} else if (intent.hasExtra(Insert.PHONE)) {
mMode = MODE_QUERY_PICK_TO_VIEW;
mQueryMode = QUERY_MODE_TEL;
mQueryData = intent.getStringExtra(Insert.PHONE);
} else {
// Otherwise handle the more normal search case
mMode = MODE_QUERY;
}
// Since this is the filter activity it receives all intents
// dispatched from the SearchManager for security reasons
// so we need to re-dispatch from here to the intended target.
} else if (Intents.SEARCH_SUGGESTION_CLICKED.equals(action)) {
// See if the suggestion was clicked with a search action key (call button)
Intent newIntent;
if ("call".equals(intent.getStringExtra(SearchManager.ACTION_MSG))) {
newIntent = new Intent(Intent.ACTION_CALL_PRIVILEGED, intent.getData());
} else {
newIntent = new Intent(Intent.ACTION_VIEW, intent.getData());
}
startActivity(newIntent);
finish();
return;
} else if (Intents.SEARCH_SUGGESTION_DIAL_NUMBER_CLICKED.equals(action)) {
Intent newIntent = new Intent(Intent.ACTION_CALL_PRIVILEGED, intent.getData());
startActivity(newIntent);
finish();
return;
} else if (Intents.SEARCH_SUGGESTION_CREATE_CONTACT_CLICKED.equals(action)) {
String number = intent.getData().getSchemeSpecificPart();
Intent newIntent = new Intent(Intent.ACTION_INSERT, People.CONTENT_URI);
newIntent.putExtra(Intents.Insert.PHONE, number);
startActivity(newIntent);
finish();
return;
}
if (mMode == MODE_UNKNOWN) {
mMode = DEFAULT_MODE;
}
// Setup the UI
final ListView list = getListView();
list.setFocusable(true);
list.setOnCreateContextMenuListener(this);
if ((mMode & MODE_MASK_NO_FILTER) != MODE_MASK_NO_FILTER) {
list.setTextFilterEnabled(true);
}
if ((mMode & MODE_MASK_CREATE_NEW) != 0) {
// Add the header for creating a new contact
final LayoutInflater inflater = getLayoutInflater();
View header = inflater.inflate(android.R.layout.simple_list_item_1, list, false);
TextView text = (TextView) header.findViewById(android.R.id.text1);
text.setText(R.string.pickerNewContactHeader);
list.addHeaderView(header);
}
// Set the proper empty string
setEmptyText();
mAdapter = new ContactItemListAdapter(this);
setListAdapter(mAdapter);
// We manually save/restore the listview state
list.setSaveEnabled(false);
mQueryHandler = new QueryHandler(this);
mJustCreated = true;
// Check to see if sync is enabled
final ContentResolver resolver = getContentResolver();
IContentProvider provider = resolver.acquireProvider(Contacts.CONTENT_URI);
if (provider == null) {
// No contacts provider, bail.
finish();
return;
}
try {
ISyncAdapter sa = provider.getSyncAdapter();
mSyncEnabled = sa != null;
} catch (RemoteException e) {
mSyncEnabled = false;
} finally {
resolver.releaseProvider(provider);
}
| public void | onCreateContextMenu(android.view.ContextMenu menu, android.view.View view, android.view.ContextMenu.ContextMenuInfo menuInfo)
// If Contacts was invoked by another Activity simply as a way of
// picking a contact, don't show the context menu
if ((mMode & MODE_MASK_PICKER) == MODE_MASK_PICKER) {
return;
}
AdapterView.AdapterContextMenuInfo info;
try {
info = (AdapterView.AdapterContextMenuInfo) menuInfo;
} catch (ClassCastException e) {
Log.e(TAG, "bad menuInfo", e);
return;
}
Cursor cursor = (Cursor) getListAdapter().getItem(info.position);
if (cursor == null) {
// For some reason the requested item isn't available, do nothing
return;
}
long id = info.id;
Uri personUri = ContentUris.withAppendedId(People.CONTENT_URI, id);
// Setup the menu header
menu.setHeaderTitle(cursor.getString(NAME_COLUMN_INDEX));
// View contact details
menu.add(0, MENU_ITEM_VIEW_CONTACT, 0, R.string.menu_viewContact)
.setIntent(new Intent(Intent.ACTION_VIEW, personUri));
// Calling contact
long phoneId = cursor.getLong(PRIMARY_PHONE_ID_COLUMN_INDEX);
if (phoneId > 0) {
// Get the display label for the number
CharSequence label = cursor.getString(LABEL_COLUMN_INDEX);
int type = cursor.getInt(TYPE_COLUMN_INDEX);
label = Phones.getDisplayLabel(this, type, label);
Intent intent = new Intent(Intent.ACTION_CALL_PRIVILEGED,
ContentUris.withAppendedId(Phones.CONTENT_URI, phoneId));
menu.add(0, MENU_ITEM_CALL, 0, String.format(getString(R.string.menu_callNumber), label))
.setIntent(intent);
// Send SMS item
menu.add(0, MENU_ITEM_SEND_SMS, 0, R.string.menu_sendSMS)
.setIntent(new Intent(Intent.ACTION_SENDTO,
Uri.fromParts("sms", cursor.getString(NUMBER_COLUMN_INDEX), null)));
}
// Star toggling
int starState = cursor.getInt(STARRED_COLUMN_INDEX);
if (starState == 0) {
menu.add(0, MENU_ITEM_TOGGLE_STAR, 0, R.string.menu_addStar);
} else {
menu.add(0, MENU_ITEM_TOGGLE_STAR, 0, R.string.menu_removeStar);
}
// Contact editing
menu.add(0, MENU_ITEM_EDIT, 0, R.string.menu_editContact)
.setIntent(new Intent(Intent.ACTION_EDIT, personUri));
menu.add(0, MENU_ITEM_DELETE, 0, R.string.menu_deleteContact);
| public boolean | onCreateOptionsMenu(android.view.Menu menu)
// If Contacts was invoked by another Activity simply as a way of
// picking a contact, don't show the options menu
if ((mMode & MODE_MASK_PICKER) == MODE_MASK_PICKER) {
return false;
}
// Search
menu.add(0, MENU_SEARCH, 0, R.string.menu_search)
.setIcon(android.R.drawable.ic_menu_search);
// New contact
menu.add(0, MENU_NEW_CONTACT, 0, R.string.menu_newContact)
.setIcon(android.R.drawable.ic_menu_add)
.setIntent(new Intent(Intents.Insert.ACTION, People.CONTENT_URI))
.setAlphabeticShortcut('n");
// Display group
if (mDefaultMode) {
menu.add(0, MENU_DISPLAY_GROUP, 0, R.string.menu_displayGroup)
.setIcon(com.android.internal.R.drawable.ic_menu_allfriends);
}
// Sync settings
if (mSyncEnabled) {
Intent syncIntent = new Intent(Intent.ACTION_VIEW);
syncIntent.setClass(this, ContactsGroupSyncSelector.class);
menu.add(0, 0, 0, R.string.syncGroupPreference)
.setIcon(com.android.internal.R.drawable.ic_menu_refresh)
.setIntent(syncIntent);
}
// SIM import
Intent importIntent = new Intent(Intent.ACTION_VIEW);
importIntent.setType("vnd.android.cursor.item/sim-contact");
importIntent.setClassName("com.android.phone", "com.android.phone.SimContacts");
menu.add(0, 0, 0, R.string.importFromSim)
.setIcon(R.drawable.ic_menu_import_contact)
.setIntent(importIntent);
return super.onCreateOptionsMenu(menu);
| public boolean | onKeyDown(int keyCode, android.view.KeyEvent event)
switch (keyCode) {
case KeyEvent.KEYCODE_CALL: {
if (callSelection()) {
return true;
}
break;
}
case KeyEvent.KEYCODE_DEL: {
Object o = getListView().getSelectedItem();
if (o != null) {
Cursor cursor = (Cursor) o;
Uri uri = ContentUris.withAppendedId(People.CONTENT_URI,
cursor.getLong(ID_COLUMN_INDEX));
//TODO make this dialog persist across screen rotations
new AlertDialog.Builder(ContactsListActivity.this)
.setTitle(R.string.deleteConfirmation_title)
.setIcon(android.R.drawable.ic_dialog_alert)
.setMessage(R.string.deleteConfirmation)
.setNegativeButton(android.R.string.cancel, null)
.setPositiveButton(android.R.string.ok, new DeleteClickListener(uri))
.setCancelable(false)
.show();
return true;
}
break;
}
}
return super.onKeyDown(keyCode, event);
| protected void | onListItemClick(android.widget.ListView l, android.view.View v, int position, long id)
// Hide soft keyboard, if visible
InputMethodManager inputMethodManager = (InputMethodManager)
getSystemService(Context.INPUT_METHOD_SERVICE);
inputMethodManager.hideSoftInputFromWindow(mList.getWindowToken(), 0);
if (mMode == MODE_INSERT_OR_EDIT_CONTACT) {
Intent intent;
if (position == 0) {
// Insert
intent = new Intent(Intent.ACTION_INSERT, People.CONTENT_URI);
} else {
// Edit
intent = new Intent(Intent.ACTION_EDIT,
ContentUris.withAppendedId(People.CONTENT_URI, id));
}
intent.setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
final Bundle extras = getIntent().getExtras();
if (extras != null) {
intent.putExtras(extras);
}
startActivity(intent);
finish();
} else if (id != -1) {
if ((mMode & MODE_MASK_PICKER) == 0) {
Intent intent = new Intent(Intent.ACTION_VIEW,
ContentUris.withAppendedId(People.CONTENT_URI, id));
startActivity(intent);
} else if (mMode == MODE_QUERY_PICK_TO_VIEW) {
// Started with query that should launch to view contact
Cursor c = (Cursor) mAdapter.getItem(position);
long personId = c.getLong(mQueryPersonIdIndex);
Intent intent = new Intent(Intent.ACTION_VIEW,
ContentUris.withAppendedId(People.CONTENT_URI, personId));
startActivity(intent);
finish();
} else if (mMode == MODE_PICK_CONTACT
|| mMode == MODE_PICK_OR_CREATE_CONTACT) {
Uri uri = ContentUris.withAppendedId(People.CONTENT_URI, id);
if (mCreateShortcut) {
// Subtract one if we have Create Contact at the top
Cursor c = (Cursor) mAdapter.getItem(position
- (mMode == MODE_PICK_OR_CREATE_CONTACT? 1:0));
returnPickerResult(c.getString(NAME_COLUMN_INDEX), uri);
} else {
returnPickerResult(null, uri);
}
} else if (mMode == MODE_PICK_PHONE) {
setResult(RESULT_OK, new Intent().setData(
ContentUris.withAppendedId(Phones.CONTENT_URI, id)));
finish();
} else if (mMode == MODE_PICK_POSTAL) {
setResult(RESULT_OK, new Intent().setData(
ContentUris.withAppendedId(ContactMethods.CONTENT_URI, id)));
finish();
}
} else if ((mMode & MODE_MASK_CREATE_NEW) == MODE_MASK_CREATE_NEW
&& position == 0) {
Intent newContact = new Intent(Intents.Insert.ACTION, People.CONTENT_URI);
startActivityForResult(newContact, SUBACTIVITY_NEW_CONTACT);
} else {
signalError();
}
| public boolean | onOptionsItemSelected(android.view.MenuItem item)
switch (item.getItemId()) {
case MENU_DISPLAY_GROUP:
AlertDialog.Builder builder = new AlertDialog.Builder(this)
.setTitle(R.string.select_group_title)
.setPositiveButton(android.R.string.ok, this)
.setNegativeButton(android.R.string.cancel, null);
setGroupEntries(builder);
builder.show();
return true;
case MENU_SEARCH:
startSearch(null, false, null, false);
return true;
}
return false;
| protected void | onRestart()
super.onRestart();
// The cursor was killed off in onStop(), so we need to get a new one here
// We do not perform the query if a filter is set on the list because the
// filter will cause the query to happen anyway
if (TextUtils.isEmpty(getListView().getTextFilter())) {
startQuery();
} else {
// Run the filtered query on the adapter
((ContactItemListAdapter) getListAdapter()).onContentChanged();
}
| protected void | onRestoreInstanceState(android.os.Bundle icicle)
super.onRestoreInstanceState(icicle);
// Retrieve list state. This will be applied after the QueryHandler has run
mListState = icicle.getParcelable(LIST_STATE_KEY);
mListHasFocus = icicle.getBoolean(FOCUS_KEY);
| protected void | onResume()
super.onResume();
boolean runQuery = true;
Activity parent = getParent();
// Do this before setting the filter. The filter thread relies
// on some state that is initialized in setDefaultMode
if (mDefaultMode) {
// If we're in default mode we need to possibly reset the mode due to a change
// in the preferences activity while we weren't running
setDefaultMode();
}
// See if we were invoked with a filter
if (parent != null && parent instanceof DialtactsActivity) {
String filterText = ((DialtactsActivity) parent).getAndClearFilterText();
if (filterText != null && filterText.length() > 0) {
getListView().setFilterText(filterText);
// Don't start a new query since it will conflict with the filter
runQuery = false;
} else if (mJustCreated) {
getListView().clearTextFilter();
}
}
if (mJustCreated && runQuery) {
// We need to start a query here the first time the activity is launched, as long
// as we aren't doing a filter.
startQuery();
}
mJustCreated = false;
| protected void | onSaveInstanceState(android.os.Bundle icicle)
super.onSaveInstanceState(icicle);
// Save list state in the bundle so we can restore it after the QueryHandler has run
icicle.putParcelable(LIST_STATE_KEY, mList.onSaveInstanceState());
icicle.putBoolean(FOCUS_KEY, mList.hasFocus());
| protected void | onStop()
super.onStop();
// We don't want the list to display the empty state, since when we resume it will still
// be there and show up while the new query is happening. After the async query finished
// in response to onRestart() setLoading(false) will be called.
mAdapter.setLoading(true);
mAdapter.changeCursor(null);
if (mMode == MODE_QUERY) {
// Make sure the search box is closed
SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE);
searchManager.stopSearch();
}
| private void | returnPickerResult(java.lang.String name, android.net.Uri uri)
final Intent intent = new Intent();
if (mCreateShortcut) {
Intent shortcutIntent = new Intent(Intent.ACTION_VIEW, uri);
shortcutIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, name);
final Bitmap icon = People.loadContactPhoto(this, uri, 0, null);
if (icon != null) {
intent.putExtra(Intent.EXTRA_SHORTCUT_ICON, icon);
} else {
intent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE,
Intent.ShortcutIconResource.fromContext(this,
R.drawable.ic_launcher_shortcut_contact));
}
setResult(RESULT_OK, intent);
} else {
setResult(RESULT_OK, intent.setData(uri));
}
finish();
| private void | setDefaultMode()Sets the mode when the request is for "default"
// Load the preferences
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
// Lookup the group to display
mDisplayType = prefs.getInt(PREF_DISPLAY_TYPE, DISPLAY_TYPE_UNKNOWN);
switch (mDisplayType) {
case DISPLAY_TYPE_ALL_WITH_PHONES: {
mMode = MODE_WITH_PHONES;
mDisplayInfo = null;
break;
}
case DISPLAY_TYPE_SYSTEM_GROUP: {
String systemId = prefs.getString(
PREF_DISPLAY_INFO, null);
if (!TextUtils.isEmpty(systemId)) {
// Display the selected system group
mMode = MODE_GROUP;
buildSystemGroupUris(systemId);
mDisplayInfo = systemId;
} else {
// No valid group is present, display everything
mMode = MODE_WITH_PHONES;
mDisplayInfo = null;
mDisplayType = DISPLAY_TYPE_ALL;
}
break;
}
case DISPLAY_TYPE_USER_GROUP: {
String displayGroup = prefs.getString(
PREF_DISPLAY_INFO, null);
if (!TextUtils.isEmpty(displayGroup)) {
// Display the selected user group
mMode = MODE_GROUP;
buildUserGroupUris(displayGroup);
mDisplayInfo = displayGroup;
} else {
// No valid group is present, display everything
mMode = MODE_WITH_PHONES;
mDisplayInfo = null;
mDisplayType = DISPLAY_TYPE_ALL;
}
break;
}
case DISPLAY_TYPE_ALL: {
mMode = MODE_ALL_CONTACTS;
mDisplayInfo = null;
break;
}
default: {
// We don't know what to display, default to My Contacts
mMode = MODE_GROUP;
mDisplayType = DISPLAY_TYPE_SYSTEM_GROUP;
buildSystemGroupUris(Groups.GROUP_MY_CONTACTS);
mDisplayInfo = Groups.GROUP_MY_CONTACTS;
break;
}
}
// Update the empty text view with the proper string, as the group may have changed
setEmptyText();
| private void | setEmptyText()
TextView empty = (TextView) findViewById(R.id.emptyText);
// Center the text by default
int gravity = Gravity.CENTER;
switch (mMode) {
case MODE_GROUP:
if (Groups.GROUP_MY_CONTACTS.equals(mDisplayInfo)) {
if (mSyncEnabled) {
empty.setText(getText(R.string.noContactsHelpTextWithSync));
} else {
empty.setText(getText(R.string.noContactsHelpText));
}
gravity = Gravity.NO_GRAVITY;
} else {
empty.setText(getString(R.string.groupEmpty, mDisplayInfo));
}
break;
case MODE_STARRED:
case MODE_STREQUENT:
case MODE_FREQUENT:
empty.setText(getText(R.string.noFavorites));
break;
case MODE_WITH_PHONES:
empty.setText(getText(R.string.noContactsWithPhoneNumbers));
break;
default:
empty.setText(getText(R.string.noContacts));
break;
}
empty.setGravity(gravity);
| private void | setGroupEntries(AlertDialog.Builder builder)
boolean syncEverything;
// For now we only support a single account and the UI doesn't know what
// the account name is, so we're using a global setting for SYNC_EVERYTHING.
// Some day when we add multiple accounts to the UI this should use the per
// account setting.
String value = Contacts.Settings.getSetting(getContentResolver(), null,
Contacts.Settings.SYNC_EVERYTHING);
if (value == null) {
// If nothing is set yet we default to syncing everything
syncEverything = true;
} else {
syncEverything = !TextUtils.isEmpty(value) && !"0".equals(value);
}
Cursor cursor;
if (!syncEverything) {
cursor = getContentResolver().query(Groups.CONTENT_URI, GROUPS_PROJECTION,
Groups.SHOULD_SYNC + " != 0", null, Groups.DEFAULT_SORT_ORDER);
} else {
cursor = getContentResolver().query(Groups.CONTENT_URI, GROUPS_PROJECTION,
null, null, Groups.DEFAULT_SORT_ORDER);
}
try {
ArrayList<CharSequence> groups = new ArrayList<CharSequence>();
ArrayList<CharSequence> prefStrings = new ArrayList<CharSequence>();
// Add All Contacts
groups.add(DISPLAY_GROUP_INDEX_ALL_CONTACTS, getString(R.string.showAllGroups));
prefStrings.add("");
// Add Contacts with phones
groups.add(DISPLAY_GROUP_INDEX_ALL_CONTACTS_WITH_PHONES,
getString(R.string.groupNameWithPhones));
prefStrings.add(GROUP_WITH_PHONES);
int currentIndex = DISPLAY_GROUP_INDEX_ALL_CONTACTS;
while (cursor.moveToNext()) {
String systemId = cursor.getString(GROUPS_COLUMN_INDEX_SYSTEM_ID);
String name = cursor.getString(GROUPS_COLUMN_INDEX_NAME);
if (cursor.isNull(GROUPS_COLUMN_INDEX_SYSTEM_ID)
&& !Groups.GROUP_MY_CONTACTS.equals(systemId)) {
// All groups that aren't My Contacts, since that one is localized on the phone
// Localize the "Starred in Android" string which we get from the server side.
if (Groups.GROUP_ANDROID_STARRED.equals(name)) {
name = getString(R.string.starredInAndroid);
}
groups.add(name);
if (name.equals(mDisplayInfo)) {
currentIndex = groups.size() - 1;
}
} else {
// The My Contacts group
groups.add(DISPLAY_GROUP_INDEX_MY_CONTACTS,
getString(R.string.groupNameMyContacts));
if (mDisplayType == DISPLAY_TYPE_SYSTEM_GROUP
&& Groups.GROUP_MY_CONTACTS.equals(mDisplayInfo)) {
currentIndex = DISPLAY_GROUP_INDEX_MY_CONTACTS;
}
mDisplayGroupsIncludesMyContacts = true;
}
}
if (mMode == MODE_ALL_CONTACTS) {
currentIndex = DISPLAY_GROUP_INDEX_ALL_CONTACTS;
} else if (mMode == MODE_WITH_PHONES) {
currentIndex = DISPLAY_GROUP_INDEX_ALL_CONTACTS_WITH_PHONES;
}
mDisplayGroups = groups.toArray(new CharSequence[groups.size()]);
builder.setSingleChoiceItems(mDisplayGroups, currentIndex, this);
mDisplayGroupOriginalSelection = currentIndex;
} finally {
cursor.close();
}
| void | signalError()Signal an error to the user.
//TODO play an error beep or something...
| void | startQuery()
mAdapter.setLoading(true);
// Cancel any pending queries
mQueryHandler.cancelOperation(QUERY_TOKEN);
// Kick off the new query
switch (mMode) {
case MODE_GROUP:
mQueryHandler.startQuery(QUERY_TOKEN, null,
mGroupUri, CONTACTS_PROJECTION, null, null,
getSortOrder(CONTACTS_PROJECTION));
break;
case MODE_ALL_CONTACTS:
case MODE_PICK_CONTACT:
case MODE_PICK_OR_CREATE_CONTACT:
case MODE_INSERT_OR_EDIT_CONTACT:
mQueryHandler.startQuery(QUERY_TOKEN, null, People.CONTENT_URI, CONTACTS_PROJECTION,
null, null, getSortOrder(CONTACTS_PROJECTION));
break;
case MODE_WITH_PHONES:
mQueryHandler.startQuery(QUERY_TOKEN, null, People.CONTENT_URI, CONTACTS_PROJECTION,
People.PRIMARY_PHONE_ID + " IS NOT NULL", null,
getSortOrder(CONTACTS_PROJECTION));
break;
case MODE_QUERY: {
mQuery = getIntent().getStringExtra(SearchManager.QUERY);
mQueryHandler.startQuery(QUERY_TOKEN, null, getPeopleFilterUri(mQuery),
CONTACTS_PROJECTION, null, null,
getSortOrder(CONTACTS_PROJECTION));
break;
}
case MODE_QUERY_PICK_TO_VIEW: {
if (mQueryMode == QUERY_MODE_MAILTO) {
// Find all contacts with the given search string as either
// an E-mail or IM address.
mQueryPersonIdIndex = SIMPLE_CONTACTS_PERSON_ID_INDEX;
Uri uri = Uri.withAppendedPath(People.WITH_EMAIL_OR_IM_FILTER_URI,
Uri.encode(mQueryData));
mQueryHandler.startQuery(QUERY_TOKEN, null,
uri, SIMPLE_CONTACTS_PROJECTION, null, null,
getSortOrder(CONTACTS_PROJECTION));
} else if (mQueryMode == QUERY_MODE_TEL) {
mQueryPersonIdIndex = PHONES_PERSON_ID_INDEX;
mQueryHandler.startQuery(QUERY_TOKEN, null,
Uri.withAppendedPath(Phones.CONTENT_FILTER_URL, mQueryData),
PHONES_PROJECTION, null, null,
getSortOrder(PHONES_PROJECTION));
}
break;
}
case MODE_STARRED:
mQueryHandler.startQuery(QUERY_TOKEN, null, People.CONTENT_URI,
CONTACTS_PROJECTION,
People.STARRED + "=1", null, getSortOrder(CONTACTS_PROJECTION));
break;
case MODE_FREQUENT:
mQueryHandler.startQuery(QUERY_TOKEN, null,
People.CONTENT_URI, CONTACTS_PROJECTION,
People.TIMES_CONTACTED + " > 0", null,
People.TIMES_CONTACTED + " DESC, " + getSortOrder(CONTACTS_PROJECTION));
break;
case MODE_STREQUENT:
mQueryHandler.startQuery(QUERY_TOKEN, null,
Uri.withAppendedPath(People.CONTENT_URI, "strequent"), STREQUENT_PROJECTION,
null, null, null);
break;
case MODE_PICK_PHONE:
mQueryHandler.startQuery(QUERY_TOKEN, null, Phones.CONTENT_URI, PHONES_PROJECTION,
null, null, getSortOrder(PHONES_PROJECTION));
break;
case MODE_PICK_POSTAL:
mQueryHandler.startQuery(QUERY_TOKEN, null, ContactMethods.CONTENT_URI,
CONTACT_METHODS_PROJECTION,
ContactMethods.KIND + "=" + Contacts.KIND_POSTAL, null,
getSortOrder(CONTACT_METHODS_PROJECTION));
break;
}
| private void | updateGroup()
if (mDefaultMode) {
setDefaultMode();
}
// Calling requery here may cause an ANR, so always do the async query
startQuery();
|
|