Introducing contacts configuration object.
Physically moving code from ContactsListActivity to the
new object as the next step toward full refactoring of
the ContactsListActivity.
Change-Id: Ic169ea53274151c863e2f28df5e545abdf01885c
diff --git a/src/com/android/contacts/ContactsListActivity.java b/src/com/android/contacts/ContactsListActivity.java
index 47f47b7..d6f831a 100644
--- a/src/com/android/contacts/ContactsListActivity.java
+++ b/src/com/android/contacts/ContactsListActivity.java
@@ -17,6 +17,7 @@
package com.android.contacts;
import com.android.contacts.TextHighlightingAnimation.TextWithHighlighting;
+import com.android.contacts.list.config.ContactListConfiguration;
import com.android.contacts.model.ContactsSource;
import com.android.contacts.model.Sources;
import com.android.contacts.ui.ContactsPreferences;
@@ -392,7 +393,6 @@
private ContactListEmptyView mEmptyView;
int mMode = MODE_DEFAULT;
-
private boolean mRunQueriesSynchronously;
private QueryHandler mQueryHandler;
private boolean mJustCreated;
@@ -402,7 +402,7 @@
// private boolean mDisplayAll;
private boolean mDisplayOnlyPhones;
- private Uri mGroupUri;
+ private String mGroupName;
private ArrayList<Long> mWritableRawContactIds = new ArrayList<Long>();
private int mWritableSourcesCnt;
@@ -488,7 +488,7 @@
* A colored chip in MODE_PICK_MULTIPLE_PHONES mode is used to indicate the number of phone
* numbers belong to one contact
*/
- SparseIntArray mContactColor;
+ SparseIntArray mContactColor = new SparseIntArray();
/**
* UI control of action panel in MODE_PICK_MULTIPLE_PHONES mode.
@@ -590,6 +590,12 @@
}
};
+ private ContactListConfiguration mConfig;
+
+ public ContactsListActivity() {
+ mConfig = new ContactListConfiguration(this);
+ }
+
/**
* Visible for testing: makes queries run on the UI thread.
*/
@@ -614,255 +620,42 @@
resolveIntent(intent);
initContentView();
+ if (mMode == MODE_PICK_MULTIPLE_PHONES) {
+ initMultiPicker(intent);
+ }
}
protected void resolveIntent(final Intent intent) {
- // Allow the title to be set to a custom String using an extra on the intent
- String title = intent.getStringExtra(UI.TITLE_EXTRA_KEY);
- if (title != null) {
- setTitle(title);
- }
+ mConfig.setIntent(intent);
- String action = intent.getAction();
- String component = intent.getComponent().getClassName();
- String type = intent.getType();
-
- // When we get a FILTER_CONTACTS_ACTION, it represents search in the context
- // of some other action. Let's retrieve the original action to provide proper
- // context for the search queries.
- if (UI.FILTER_CONTACTS_ACTION.equals(action)) {
- mSearchMode = true;
- mShowSearchSnippets = true;
- Bundle extras = intent.getExtras();
- if (extras != null) {
- mInitialFilter = extras.getString(UI.FILTER_TEXT_EXTRA_KEY);
- String originalAction =
- extras.getString(ContactsSearchManager.ORIGINAL_ACTION_EXTRA_KEY);
- if (originalAction != null) {
- action = originalAction;
- }
- String originalComponent =
- extras.getString(ContactsSearchManager.ORIGINAL_COMPONENT_EXTRA_KEY);
- if (originalComponent != null) {
- component = originalComponent;
- }
- String originalType =
- extras.getString(ContactsSearchManager.ORIGINAL_TYPE_EXTRA_KEY);
- if (originalType != null) {
- type = originalType;
- }
- } else {
- mInitialFilter = null;
- }
- }
-
- Log.i(TAG, "Called with action: " + action);
- mMode = MODE_UNKNOWN;
- if (UI.LIST_DEFAULT.equals(action) || UI.FILTER_CONTACTS_ACTION.equals(action)) {
- mMode = MODE_DEFAULT;
- // 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;
- }
- buildUserGroupUri(groupName);
- } else if (UI.LIST_ALL_CONTACTS_ACTION.equals(action)) {
- mMode = MODE_CUSTOM;
- mDisplayOnlyPhones = false;
- } else if (UI.LIST_STARRED_ACTION.equals(action)) {
- mMode = mSearchMode ? MODE_DEFAULT : MODE_STARRED;
- } else if (UI.LIST_FREQUENT_ACTION.equals(action)) {
- mMode = mSearchMode ? MODE_DEFAULT : MODE_FREQUENT;
- } else if (UI.LIST_STREQUENT_ACTION.equals(action)) {
- mMode = mSearchMode ? MODE_DEFAULT : MODE_STREQUENT;
- } else if (UI.LIST_CONTACTS_WITH_PHONES_ACTION.equals(action)) {
- mMode = MODE_CUSTOM;
- mDisplayOnlyPhones = true;
- } else if (Intent.ACTION_PICK.equals(action)) {
- // XXX These should be showing the data from the URI given in
- // the Intent.
- // TODO : Does it work in mSearchMode?
- final String resolvedType = intent.resolveType(this);
- if (Contacts.CONTENT_TYPE.equals(resolvedType)) {
- mMode = MODE_PICK_CONTACT;
- } else if (People.CONTENT_TYPE.equals(resolvedType)) {
- mMode = MODE_LEGACY_PICK_PERSON;
- } else if (Phone.CONTENT_TYPE.equals(resolvedType)) {
- mMode = MODE_PICK_PHONE;
- } else if (Phones.CONTENT_TYPE.equals(resolvedType)) {
- mMode = MODE_LEGACY_PICK_PHONE;
- } else if (StructuredPostal.CONTENT_TYPE.equals(resolvedType)) {
- mMode = MODE_PICK_POSTAL;
- } else if (ContactMethods.CONTENT_POSTAL_TYPE.equals(resolvedType)) {
- mMode = MODE_LEGACY_PICK_POSTAL;
- }
- } else if (Intent.ACTION_CREATE_SHORTCUT.equals(action)) {
- if (component.equals("alias.DialShortcut")) {
- mMode = MODE_PICK_PHONE;
- mShortcutAction = Intent.ACTION_CALL;
- mShowSearchSnippets = false;
- setTitle(R.string.callShortcutActivityTitle);
- } else if (component.equals("alias.MessageShortcut")) {
- mMode = MODE_PICK_PHONE;
- mShortcutAction = Intent.ACTION_SENDTO;
- mShowSearchSnippets = false;
- setTitle(R.string.messageShortcutActivityTitle);
- } else if (mSearchMode) {
- mMode = MODE_PICK_CONTACT;
- mShortcutAction = Intent.ACTION_VIEW;
- setTitle(R.string.shortcutActivityTitle);
- } else {
- mMode = MODE_PICK_OR_CREATE_CONTACT;
- mShortcutAction = Intent.ACTION_VIEW;
- setTitle(R.string.shortcutActivityTitle);
- }
- } else if (Intent.ACTION_GET_CONTENT.equals(action)) {
- if (Contacts.CONTENT_ITEM_TYPE.equals(type)) {
- if (mSearchMode) {
- mMode = MODE_PICK_CONTACT;
- } else {
- mMode = MODE_PICK_OR_CREATE_CONTACT;
- }
- } else if (Phone.CONTENT_ITEM_TYPE.equals(type)) {
- mMode = MODE_PICK_PHONE;
- } else if (Phones.CONTENT_ITEM_TYPE.equals(type)) {
- mMode = MODE_LEGACY_PICK_PHONE;
- } else if (StructuredPostal.CONTENT_ITEM_TYPE.equals(type)) {
- mMode = MODE_PICK_POSTAL;
- } else if (ContactMethods.CONTENT_POSTAL_ITEM_TYPE.equals(type)) {
- mMode = MODE_LEGACY_PICK_POSTAL;
- } else if (People.CONTENT_ITEM_TYPE.equals(type)) {
- if (mSearchMode) {
- mMode = MODE_LEGACY_PICK_PERSON;
- } else {
- mMode = MODE_LEGACY_PICK_OR_CREATE_PERSON;
- }
- }
-
- } 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;
- mInitialFilter = intent.getStringExtra(Insert.EMAIL);
- } else if (intent.hasExtra(Insert.PHONE)) {
- mMode = MODE_QUERY_PICK_TO_VIEW;
- mQueryMode = QUERY_MODE_TEL;
- mInitialFilter = intent.getStringExtra(Insert.PHONE);
- } else {
- // Otherwise handle the more normal search case
- mMode = MODE_QUERY;
- mShowSearchSnippets = true;
- mInitialFilter = getIntent().getStringExtra(SearchManager.QUERY);
- }
- mSearchResultsMode = true;
- } else if (ACTION_SEARCH_INTERNAL.equals(action)) {
- String originalAction = null;
- Bundle extras = intent.getExtras();
- if (extras != null) {
- originalAction = extras.getString(ContactsSearchManager.ORIGINAL_ACTION_EXTRA_KEY);
- }
- mShortcutAction = intent.getStringExtra(SHORTCUT_ACTION_KEY);
-
- if (Intent.ACTION_INSERT_OR_EDIT.equals(originalAction)) {
- mMode = MODE_QUERY_PICK_TO_EDIT;
- mShowSearchSnippets = true;
- mInitialFilter = getIntent().getStringExtra(SearchManager.QUERY);
- } else if (mShortcutAction != null && intent.hasExtra(Insert.PHONE)) {
- mMode = MODE_QUERY_PICK_PHONE;
- mQueryMode = QUERY_MODE_TEL;
- mInitialFilter = intent.getStringExtra(Insert.PHONE);
- } else {
- mMode = MODE_QUERY_PICK;
- mQueryMode = QUERY_MODE_NONE;
- mShowSearchSnippets = true;
- mInitialFilter = getIntent().getStringExtra(SearchManager.QUERY);
- }
- mSearchResultsMode = true;
- // 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)) {
- Uri data = intent.getData();
- Uri telUri = null;
- if (sContactsIdMatcher.match(data) == CONTACTS_ID) {
- long contactId = Long.valueOf(data.getLastPathSegment());
- final Cursor cursor = queryPhoneNumbers(contactId);
- if (cursor != null) {
- if (cursor.getCount() == 1 && cursor.moveToFirst()) {
- int phoneNumberIndex = cursor.getColumnIndex(Phone.NUMBER);
- String phoneNumber = cursor.getString(phoneNumberIndex);
- telUri = Uri.parse("tel:" + phoneNumber);
- }
- cursor.close();
- }
- }
- // See if the suggestion was clicked with a search action key (call button)
- Intent newIntent;
- if ("call".equals(intent.getStringExtra(SearchManager.ACTION_MSG)) && telUri != null) {
- newIntent = new Intent(Intent.ACTION_CALL_PRIVILEGED, telUri);
- } else {
- newIntent = new Intent(Intent.ACTION_VIEW, data);
- }
- startActivity(newIntent);
+ if (!mConfig.isValid()) { // Invalid intent
+ setResult(RESULT_CANCELED);
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)) {
- // TODO actually support this in EditContactActivity.
- String number = intent.getData().getSchemeSpecificPart();
- Intent newIntent = new Intent(Intent.ACTION_INSERT, Contacts.CONTENT_URI);
- newIntent.putExtra(Intents.Insert.PHONE, number);
- startActivity(newIntent);
- finish();
- return;
- } else if (JoinContactActivity.JOIN_CONTACT.equals(action)) {
- mMode = MODE_PICK_CONTACT;
- } else if (Intents.ACTION_GET_MULTIPLE_PHONES.equals(action)) {
- if (mSearchMode) {
- mShowSearchSnippets = false;
- }
- if (Phone.CONTENT_TYPE.equals(type)) {
- mMode = MODE_PICK_MULTIPLE_PHONES;
- mContactColor = new SparseIntArray();
- initMultiPicker(intent);
- } else {
- // TODO support other content types
- Log.e(TAG, "Intent " + action + " is not supported for type " + type);
- setResult(RESULT_CANCELED);
- finish();
- }
- }
- if (mMode == MODE_UNKNOWN) {
- mMode = MODE_DEFAULT;
}
- if (((mMode & MODE_MASK_SHOW_NUMBER_OF_CONTACTS) != 0 || mSearchMode)
- && !mSearchResultsMode) {
- mShowNumberOfContacts = true;
+ Intent redirect = mConfig.getRedirectIntent();
+ if (redirect != null) { // Need to start a different activity
+ startActivity(redirect);
+ finish();
+ return;
}
+
+ setTitle(mConfig.getActivityTitle());
+
+ // This is strictly temporary. Its purpose is to allow us to refactor this class in
+ // small increments. We should expect all of these modes to go away.
+ mMode = mConfig.mMode;
+ mGroupName = mConfig.mGroupName;
+ mQueryMode = mConfig.mQueryMode;
+ mSearchMode = mConfig.mSearchMode;
+ mShowSearchSnippets = mConfig.mShowSearchSnippets;
+ mInitialFilter = mConfig.mInitialFilter;
+ mDisplayOnlyPhones = mConfig.mDisplayOnlyPhones;
+ mShortcutAction = mConfig.mShortcutAction;
+ mSearchResultsMode = mConfig.mSearchResultsMode;
+ mShowNumberOfContacts = mConfig.mShowNumberOfContacts;
+ mGroupName = mConfig.mGroupName;
}
public void initContentView() {
@@ -991,10 +784,6 @@
}
}
- private void buildUserGroupUri(String group) {
- mGroupUri = Uri.withAppendedPath(Contacts.CONTENT_GROUP_URI, group);
- }
-
/**
* Sets the mode when the request is for "default"
*/
@@ -2190,7 +1979,7 @@
Uri.encode(mInitialFilter));
}
case MODE_GROUP: {
- return mGroupUri;
+ return Uri.withAppendedPath(Contacts.CONTENT_GROUP_URI, mGroupName);
}
default: {
throw new IllegalStateException("Can't generate URI: Unsupported Mode.");
@@ -2733,6 +2522,8 @@
return true;
}
+ // TODO: eliminate
+ @Deprecated
private Cursor queryPhoneNumbers(long contactId) {
Uri baseUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
Uri dataUri = Uri.withAppendedPath(baseUri, Contacts.Data.CONTENT_DIRECTORY);
diff --git a/src/com/android/contacts/list/config/ContactListConfiguration.java b/src/com/android/contacts/list/config/ContactListConfiguration.java
new file mode 100644
index 0000000..ab4731b
--- /dev/null
+++ b/src/com/android/contacts/list/config/ContactListConfiguration.java
@@ -0,0 +1,473 @@
+/*
+ * 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.list.config;
+
+import com.android.contacts.ContactsSearchManager;
+import com.android.contacts.JoinContactActivity;
+import com.android.contacts.R;
+
+import android.app.Activity;
+import android.app.SearchManager;
+import android.content.ContentUris;
+import android.content.Intent;
+import android.content.UriMatcher;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.ContactsContract;
+import android.provider.Contacts.ContactMethods;
+import android.provider.Contacts.People;
+import android.provider.Contacts.Phones;
+import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.Intents;
+import android.provider.ContactsContract.RawContacts;
+import android.provider.ContactsContract.CommonDataKinds.Phone;
+import android.provider.ContactsContract.CommonDataKinds.StructuredPostal;
+import android.provider.ContactsContract.Intents.Insert;
+import android.provider.ContactsContract.Intents.UI;
+import android.text.TextUtils;
+import android.util.Log;
+
+/**
+ * Maintains contact list configuration, which is a transient object that
+ * deals with intents, saved instance configuration etc.
+ */
+@SuppressWarnings("deprecation")
+public class ContactListConfiguration {
+
+ private static final String TAG = "ContactsListActivity";
+
+ private static final String SHORTCUT_ACTION_KEY = "shortcutAction";
+
+ /**
+ * The action for the join contact activity.
+ * <p>
+ * Input: extra field {@link #EXTRA_AGGREGATE_ID} is the aggregate ID.
+ *
+ * TODO: move to {@link ContactsContract}.
+ */
+ public static final String JOIN_AGGREGATE =
+ "com.android.contacts.action.JOIN_AGGREGATE";
+
+ /**
+ * Used with {@link #JOIN_AGGREGATE} to give it the target for aggregation.
+ * <p>
+ * Type: LONG
+ */
+ public static final String EXTRA_AGGREGATE_ID =
+ "com.android.contacts.action.AGGREGATE_ID";
+
+ /** Mask for picker mode */
+ static final int MODE_MASK_PICKER = 0x80000000;
+ /** Mask for no presence mode */
+ static final int MODE_MASK_NO_PRESENCE = 0x40000000;
+ /** Mask for enabling list filtering */
+ static final int MODE_MASK_NO_FILTER = 0x20000000;
+ /** Mask for having a "create new contact" header in the list */
+ static final int MODE_MASK_CREATE_NEW = 0x10000000;
+ /** Mask for showing photos in the list */
+ static final int MODE_MASK_SHOW_PHOTOS = 0x08000000;
+ /** Mask for hiding additional information e.g. primary phone number in the list */
+ static final int MODE_MASK_NO_DATA = 0x04000000;
+ /** Mask for showing a call button in the list */
+ static final int MODE_MASK_SHOW_CALL_BUTTON = 0x02000000;
+ /** Mask to disable quickcontact (images will show as normal images) */
+ static final int MODE_MASK_DISABLE_QUIKCCONTACT = 0x01000000;
+ /** Mask to show the total number of contacts at the top */
+ static final int MODE_MASK_SHOW_NUMBER_OF_CONTACTS = 0x00800000;
+
+ /** Unknown mode */
+ static final int MODE_UNKNOWN = 0;
+ /** Default mode */
+ static final int MODE_DEFAULT = 4 | MODE_MASK_SHOW_PHOTOS | MODE_MASK_SHOW_NUMBER_OF_CONTACTS;
+ /** Custom mode */
+ static final int MODE_CUSTOM = 8;
+ /** Show all starred contacts */
+ static final int MODE_STARRED = 20 | MODE_MASK_SHOW_PHOTOS;
+ /** Show frequently contacted contacts */
+ static final int MODE_FREQUENT = 30 | MODE_MASK_SHOW_PHOTOS;
+ /** Show starred and the frequent */
+ static final int MODE_STREQUENT = 35 | MODE_MASK_SHOW_PHOTOS | MODE_MASK_SHOW_CALL_BUTTON;
+ /** Show all contacts and pick them when clicking */
+ static final int MODE_PICK_CONTACT = 40 | MODE_MASK_PICKER | MODE_MASK_SHOW_PHOTOS
+ | MODE_MASK_DISABLE_QUIKCCONTACT;
+ /** Show all contacts as well as the option to create a new one */
+ static final int MODE_PICK_OR_CREATE_CONTACT = 42 | MODE_MASK_PICKER | MODE_MASK_CREATE_NEW
+ | MODE_MASK_SHOW_PHOTOS | MODE_MASK_DISABLE_QUIKCCONTACT;
+ /** Show all people through the legacy provider and pick them when clicking */
+ static final int MODE_LEGACY_PICK_PERSON = 43 | MODE_MASK_PICKER
+ | MODE_MASK_DISABLE_QUIKCCONTACT;
+ /** Show all people through the legacy provider as well as the option to create a new one */
+ static final int MODE_LEGACY_PICK_OR_CREATE_PERSON = 44 | MODE_MASK_PICKER
+ | MODE_MASK_CREATE_NEW | MODE_MASK_DISABLE_QUIKCCONTACT;
+ /** Show all contacts and pick them when clicking, and allow creating a new contact */
+ static final int MODE_INSERT_OR_EDIT_CONTACT = 45 | MODE_MASK_PICKER | MODE_MASK_CREATE_NEW
+ | MODE_MASK_SHOW_PHOTOS | MODE_MASK_DISABLE_QUIKCCONTACT;
+ /** Show all phone numbers and pick them when clicking */
+ static final int MODE_PICK_PHONE = 50 | MODE_MASK_PICKER | MODE_MASK_NO_PRESENCE;
+ /** Show all phone numbers through the legacy provider and pick them when clicking */
+ static final int MODE_LEGACY_PICK_PHONE =
+ 51 | MODE_MASK_PICKER | MODE_MASK_NO_PRESENCE | MODE_MASK_NO_FILTER;
+ /** Show all postal addresses and pick them when clicking */
+ static final int MODE_PICK_POSTAL =
+ 55 | MODE_MASK_PICKER | MODE_MASK_NO_PRESENCE | MODE_MASK_NO_FILTER;
+ /** Show all postal addresses and pick them when clicking */
+ static final int MODE_LEGACY_PICK_POSTAL =
+ 56 | MODE_MASK_PICKER | MODE_MASK_NO_PRESENCE | MODE_MASK_NO_FILTER;
+ static final int MODE_GROUP = 57 | MODE_MASK_SHOW_PHOTOS;
+ /** Run a search query */
+ static final int MODE_QUERY = 60 | MODE_MASK_SHOW_PHOTOS | MODE_MASK_NO_FILTER
+ | MODE_MASK_SHOW_NUMBER_OF_CONTACTS;
+ /** Run a search query in PICK mode, but that still launches to VIEW */
+ static final int MODE_QUERY_PICK_TO_VIEW = 65 | MODE_MASK_SHOW_PHOTOS | MODE_MASK_PICKER
+ | MODE_MASK_SHOW_NUMBER_OF_CONTACTS;
+
+ /** Show join suggestions followed by an A-Z list */
+ static final int MODE_JOIN_CONTACT = 70 | MODE_MASK_PICKER | MODE_MASK_NO_PRESENCE
+ | MODE_MASK_NO_DATA | MODE_MASK_SHOW_PHOTOS | MODE_MASK_DISABLE_QUIKCCONTACT;
+
+ /** Run a search query in a PICK mode */
+ static final int MODE_QUERY_PICK = 75 | MODE_MASK_SHOW_PHOTOS | MODE_MASK_NO_FILTER
+ | MODE_MASK_PICKER | MODE_MASK_DISABLE_QUIKCCONTACT | MODE_MASK_SHOW_NUMBER_OF_CONTACTS;
+
+ /** Run a search query in a PICK_PHONE mode */
+ static final int MODE_QUERY_PICK_PHONE = 80 | MODE_MASK_NO_FILTER | MODE_MASK_PICKER
+ | MODE_MASK_SHOW_NUMBER_OF_CONTACTS;
+
+ /** Run a search query in PICK mode, but that still launches to EDIT */
+ static final int MODE_QUERY_PICK_TO_EDIT = 85 | MODE_MASK_NO_FILTER | MODE_MASK_SHOW_PHOTOS
+ | MODE_MASK_PICKER | MODE_MASK_SHOW_NUMBER_OF_CONTACTS;
+
+ /**
+ * Show all phone numbers and do multiple pick when clicking. This mode has phone filtering
+ * feature, but doesn't support 'search for all contacts'.
+ */
+ static final int MODE_PICK_MULTIPLE_PHONES = 80 | MODE_MASK_PICKER
+ | MODE_MASK_NO_PRESENCE | MODE_MASK_SHOW_PHOTOS | MODE_MASK_DISABLE_QUIKCCONTACT;
+
+ /**
+ * An action used to do perform search while in a contact picker. It is initiated
+ * by the ContactListActivity itself.
+ */
+ private static final String ACTION_SEARCH_INTERNAL = "com.android.contacts.INTERNAL_SEARCH";
+
+ // Uri matcher for contact id
+ private static final int CONTACTS_ID = 1001;
+ private static final UriMatcher sContactsIdMatcher;
+ static {
+ sContactsIdMatcher = new UriMatcher(UriMatcher.NO_MATCH);
+ sContactsIdMatcher.addURI(ContactsContract.AUTHORITY, "contacts/#", CONTACTS_ID);
+ }
+
+ private final Activity mContext;
+ private boolean mValid = true;
+ private Intent mRedirectIntent;
+ private CharSequence mTitle;
+
+ // TODO: make all these fields private. They should only remain public while we
+ // are refactoring ContactListActivity.
+ public int mMode = MODE_DEFAULT;
+ public int mQueryMode = QUERY_MODE_NONE;
+ public boolean mSearchMode;
+ public boolean mShowSearchSnippets;
+ public String mInitialFilter;
+ public boolean mDisplayOnlyPhones;
+ public String mShortcutAction;
+ public boolean mSearchResultsMode;
+ public boolean mShowNumberOfContacts;
+ public String mGroupName;
+
+ /**
+ * Internal query type when in mode {@link #MODE_QUERY_PICK_TO_VIEW}.
+ */
+ private static final int QUERY_MODE_NONE = -1;
+ private static final int QUERY_MODE_MAILTO = 1;
+ private static final int QUERY_MODE_TEL = 2;
+
+ public ContactListConfiguration(Activity context) {
+ this.mContext = context;
+ }
+
+ public void setIntent(Intent intent) {
+ String action = intent.getAction();
+ String component = intent.getComponent().getClassName();
+
+ // Allow the title to be set to a custom String using an extra on the intent
+ String title = intent.getStringExtra(UI.TITLE_EXTRA_KEY);
+ if (title != null) {
+ mTitle = title;
+ }
+
+ String type = intent.getType();
+
+ // When we get a FILTER_CONTACTS_ACTION, it represents search in the context
+ // of some other action. Let's retrieve the original action to provide proper
+ // context for the search queries.
+ if (UI.FILTER_CONTACTS_ACTION.equals(action)) {
+ mSearchMode = true;
+ mShowSearchSnippets = true;
+ Bundle extras = intent.getExtras();
+ if (extras != null) {
+ mInitialFilter = extras.getString(UI.FILTER_TEXT_EXTRA_KEY);
+ String originalAction =
+ extras.getString(ContactsSearchManager.ORIGINAL_ACTION_EXTRA_KEY);
+ if (originalAction != null) {
+ action = originalAction;
+ }
+ String originalComponent =
+ extras.getString(ContactsSearchManager.ORIGINAL_COMPONENT_EXTRA_KEY);
+ if (originalComponent != null) {
+ component = originalComponent;
+ }
+ String originalType =
+ extras.getString(ContactsSearchManager.ORIGINAL_TYPE_EXTRA_KEY);
+ if (originalType != null) {
+ type = originalType;
+ }
+ } else {
+ mInitialFilter = null;
+ }
+ }
+
+ Log.i(TAG, "Called with action: " + action);
+ mMode = MODE_UNKNOWN;
+ if (UI.LIST_DEFAULT.equals(action) || UI.FILTER_CONTACTS_ACTION.equals(action)) {
+ mMode = MODE_DEFAULT;
+ // 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;
+ mGroupName = intent.getStringExtra(UI.GROUP_NAME_EXTRA_KEY);
+ if (TextUtils.isEmpty(mGroupName)) {
+ mValid = false;
+ return;
+ }
+ } else if (UI.LIST_ALL_CONTACTS_ACTION.equals(action)) {
+ mMode = MODE_CUSTOM;
+ mDisplayOnlyPhones = false;
+ } else if (UI.LIST_STARRED_ACTION.equals(action)) {
+ mMode = mSearchMode ? MODE_DEFAULT : MODE_STARRED;
+ } else if (UI.LIST_FREQUENT_ACTION.equals(action)) {
+ mMode = mSearchMode ? MODE_DEFAULT : MODE_FREQUENT;
+ } else if (UI.LIST_STREQUENT_ACTION.equals(action)) {
+ mMode = mSearchMode ? MODE_DEFAULT : MODE_STREQUENT;
+ } else if (UI.LIST_CONTACTS_WITH_PHONES_ACTION.equals(action)) {
+ mMode = MODE_CUSTOM;
+ mDisplayOnlyPhones = true;
+ } else if (Intent.ACTION_PICK.equals(action)) {
+ // XXX These should be showing the data from the URI given in
+ // the Intent.
+ // TODO : Does it work in mSearchMode?
+ final String resolvedType = intent.resolveType(mContext);
+ if (Contacts.CONTENT_TYPE.equals(resolvedType)) {
+ mMode = MODE_PICK_CONTACT;
+ } else if (People.CONTENT_TYPE.equals(resolvedType)) {
+ mMode = MODE_LEGACY_PICK_PERSON;
+ } else if (Phone.CONTENT_TYPE.equals(resolvedType)) {
+ mMode = MODE_PICK_PHONE;
+ } else if (Phones.CONTENT_TYPE.equals(resolvedType)) {
+ mMode = MODE_LEGACY_PICK_PHONE;
+ } else if (StructuredPostal.CONTENT_TYPE.equals(resolvedType)) {
+ mMode = MODE_PICK_POSTAL;
+ } else if (ContactMethods.CONTENT_POSTAL_TYPE.equals(resolvedType)) {
+ mMode = MODE_LEGACY_PICK_POSTAL;
+ }
+ } else if (Intent.ACTION_CREATE_SHORTCUT.equals(action)) {
+ if (component.equals("alias.DialShortcut")) {
+ mMode = MODE_PICK_PHONE;
+ mShortcutAction = Intent.ACTION_CALL;
+ mShowSearchSnippets = false;
+ mTitle = mContext.getString(R.string.callShortcutActivityTitle);
+ } else if (component.equals("alias.MessageShortcut")) {
+ mMode = MODE_PICK_PHONE;
+ mShortcutAction = Intent.ACTION_SENDTO;
+ mShowSearchSnippets = false;
+ mTitle = mContext.getString(R.string.messageShortcutActivityTitle);
+ } else if (mSearchMode) {
+ mMode = MODE_PICK_CONTACT;
+ mShortcutAction = Intent.ACTION_VIEW;
+ mTitle = mContext.getString(R.string.shortcutActivityTitle);
+ } else {
+ mMode = MODE_PICK_OR_CREATE_CONTACT;
+ mShortcutAction = Intent.ACTION_VIEW;
+ mTitle = mContext.getString(R.string.shortcutActivityTitle);
+ }
+ } else if (Intent.ACTION_GET_CONTENT.equals(action)) {
+ if (Contacts.CONTENT_ITEM_TYPE.equals(type)) {
+ if (mSearchMode) {
+ mMode = MODE_PICK_CONTACT;
+ } else {
+ mMode = MODE_PICK_OR_CREATE_CONTACT;
+ }
+ } else if (Phone.CONTENT_ITEM_TYPE.equals(type)) {
+ mMode = MODE_PICK_PHONE;
+ } else if (Phones.CONTENT_ITEM_TYPE.equals(type)) {
+ mMode = MODE_LEGACY_PICK_PHONE;
+ } else if (StructuredPostal.CONTENT_ITEM_TYPE.equals(type)) {
+ mMode = MODE_PICK_POSTAL;
+ } else if (ContactMethods.CONTENT_POSTAL_ITEM_TYPE.equals(type)) {
+ mMode = MODE_LEGACY_PICK_POSTAL;
+ } else if (People.CONTENT_ITEM_TYPE.equals(type)) {
+ if (mSearchMode) {
+ mMode = MODE_LEGACY_PICK_PERSON;
+ } else {
+ mMode = MODE_LEGACY_PICK_OR_CREATE_PERSON;
+ }
+ }
+
+ } 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));
+ mRedirectIntent = newIntent;
+ }
+ 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;
+ mInitialFilter = intent.getStringExtra(Insert.EMAIL);
+ } else if (intent.hasExtra(Insert.PHONE)) {
+ mMode = MODE_QUERY_PICK_TO_VIEW;
+ mQueryMode = QUERY_MODE_TEL;
+ mInitialFilter = intent.getStringExtra(Insert.PHONE);
+ } else {
+ // Otherwise handle the more normal search case
+ mMode = MODE_QUERY;
+ mShowSearchSnippets = true;
+ mInitialFilter = intent.getStringExtra(SearchManager.QUERY);
+ }
+ mSearchResultsMode = true;
+ } else if (ACTION_SEARCH_INTERNAL.equals(action)) {
+ String originalAction = null;
+ Bundle extras = intent.getExtras();
+ if (extras != null) {
+ originalAction = extras.getString(ContactsSearchManager.ORIGINAL_ACTION_EXTRA_KEY);
+ }
+ mShortcutAction = intent.getStringExtra(SHORTCUT_ACTION_KEY);
+
+ if (Intent.ACTION_INSERT_OR_EDIT.equals(originalAction)) {
+ mMode = MODE_QUERY_PICK_TO_EDIT;
+ mShowSearchSnippets = true;
+ mInitialFilter = intent.getStringExtra(SearchManager.QUERY);
+ } else if (mShortcutAction != null && intent.hasExtra(Insert.PHONE)) {
+ mMode = MODE_QUERY_PICK_PHONE;
+ mQueryMode = QUERY_MODE_TEL;
+ mInitialFilter = intent.getStringExtra(Insert.PHONE);
+ } else {
+ mMode = MODE_QUERY_PICK;
+ mQueryMode = QUERY_MODE_NONE;
+ mShowSearchSnippets = true;
+ mInitialFilter = intent.getStringExtra(SearchManager.QUERY);
+ }
+ mSearchResultsMode = true;
+ // 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)) {
+ Uri data = intent.getData();
+ Uri telUri = null;
+ if (sContactsIdMatcher.match(data) == CONTACTS_ID) {
+ long contactId = Long.valueOf(data.getLastPathSegment());
+ final Cursor cursor = queryPhoneNumbers(contactId);
+ if (cursor != null) {
+ if (cursor.getCount() == 1 && cursor.moveToFirst()) {
+ int phoneNumberIndex = cursor.getColumnIndex(Phone.NUMBER);
+ String phoneNumber = cursor.getString(phoneNumberIndex);
+ telUri = Uri.parse("tel:" + phoneNumber);
+ }
+ cursor.close();
+ }
+ }
+ // See if the suggestion was clicked with a search action key (call button)
+ Intent newIntent;
+ if ("call".equals(intent.getStringExtra(SearchManager.ACTION_MSG)) && telUri != null) {
+ newIntent = new Intent(Intent.ACTION_CALL_PRIVILEGED, telUri);
+ } else {
+ newIntent = new Intent(Intent.ACTION_VIEW, data);
+ }
+ mRedirectIntent = newIntent;
+ return;
+ } else if (Intents.SEARCH_SUGGESTION_DIAL_NUMBER_CLICKED.equals(action)) {
+ Intent newIntent = new Intent(Intent.ACTION_CALL_PRIVILEGED, intent.getData());
+ mRedirectIntent = newIntent;
+ return;
+ } else if (Intents.SEARCH_SUGGESTION_CREATE_CONTACT_CLICKED.equals(action)) {
+ // TODO actually support this in EditContactActivity.
+ String number = intent.getData().getSchemeSpecificPart();
+ Intent newIntent = new Intent(Intent.ACTION_INSERT, Contacts.CONTENT_URI);
+ newIntent.putExtra(Intents.Insert.PHONE, number);
+ mRedirectIntent = newIntent;
+ return;
+ } else if (JoinContactActivity.JOIN_CONTACT.equals(action)) {
+ mMode = MODE_PICK_CONTACT;
+ } else if (Intents.ACTION_GET_MULTIPLE_PHONES.equals(action)) {
+ if (mSearchMode) {
+ mShowSearchSnippets = false;
+ }
+ if (Phone.CONTENT_TYPE.equals(type)) {
+ mMode = MODE_PICK_MULTIPLE_PHONES;
+ } else {
+ // TODO support other content types
+ Log.e(TAG, "Intent " + action + " is not supported for type " + type);
+ mValid = false;
+ }
+ }
+ if (mMode == MODE_UNKNOWN) {
+ mMode = MODE_DEFAULT;
+ }
+
+ if (((mMode & MODE_MASK_SHOW_NUMBER_OF_CONTACTS) != 0 || mSearchMode)
+ && !mSearchResultsMode) {
+ mShowNumberOfContacts = true;
+ }
+ }
+
+ public boolean isValid() {
+ return mValid;
+ }
+
+ public Intent getRedirectIntent() {
+ return mRedirectIntent;
+ }
+
+ public CharSequence getActivityTitle() {
+ return mTitle;
+ }
+
+ private Cursor queryPhoneNumbers(long contactId) {
+ Uri baseUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
+ Uri dataUri = Uri.withAppendedPath(baseUri, Contacts.Data.CONTENT_DIRECTORY);
+
+ Cursor c = mContext.getContentResolver().query(dataUri,
+ new String[] {Phone._ID, Phone.NUMBER, Phone.IS_SUPER_PRIMARY,
+ RawContacts.ACCOUNT_TYPE, Phone.TYPE, Phone.LABEL},
+ Data.MIMETYPE + "=?", new String[] {Phone.CONTENT_ITEM_TYPE}, null);
+ if (c != null && c.moveToFirst()) {
+ return c;
+ }
+ return null;
+ }
+}