Next pass over the contact search UI.
- Search is now a separate activity
- Search bar has animations to make it slide in from the top
- New search plate resources
- Showing a magnifying glass on the right hand side of the search field
- Showing pictures and QuickContact in search result UI
- Search UI now start with no results instead of all visible contacts
- Translucent background for search UI when no filter specified
- Search can now be launched from most activities in the app
- Allowing search in pickers
Bug: 2447965
Change-Id: Ie35ce6df5e850d9c9380a25ed3970e114e9d6929
diff --git a/src/com/android/contacts/CallDetailActivity.java b/src/com/android/contacts/CallDetailActivity.java
index b2baa2c..3228692 100644
--- a/src/com/android/contacts/CallDetailActivity.java
+++ b/src/com/android/contacts/CallDetailActivity.java
@@ -365,4 +365,14 @@
}
}
}
+
+ @Override
+ public void startSearch(String initialQuery, boolean selectInitialQuery, Bundle appSearchData,
+ boolean globalSearch) {
+ if (globalSearch) {
+ super.startSearch(initialQuery, selectInitialQuery, appSearchData, globalSearch);
+ } else {
+ ContactsSearchManager.startSearch(this, initialQuery);
+ }
+ }
}
diff --git a/src/com/android/contacts/ContactOptionsActivity.java b/src/com/android/contacts/ContactOptionsActivity.java
index 38090aa..2c6142a 100644
--- a/src/com/android/contacts/ContactOptionsActivity.java
+++ b/src/com/android/contacts/ContactOptionsActivity.java
@@ -198,6 +198,16 @@
values.put(Contacts.SEND_TO_VOICEMAIL, mSendToVoicemail);
getContentResolver().update(mLookupUri, values, null, null);
}
+
+ @Override
+ public void startSearch(String initialQuery, boolean selectInitialQuery, Bundle appSearchData,
+ boolean globalSearch) {
+ if (globalSearch) {
+ super.startSearch(initialQuery, selectInitialQuery, appSearchData, globalSearch);
+ } else {
+ ContactsSearchManager.startSearch(this, initialQuery);
+ }
+ }
}
diff --git a/src/com/android/contacts/ContactsListActivity.java b/src/com/android/contacts/ContactsListActivity.java
index b85a191..6020710 100644
--- a/src/com/android/contacts/ContactsListActivity.java
+++ b/src/com/android/contacts/ContactsListActivity.java
@@ -57,8 +57,6 @@
import android.net.Uri;
import android.net.Uri.Builder;
import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
import android.os.Parcelable;
import android.preference.PreferenceManager;
import android.provider.ContactsContract;
@@ -92,57 +90,53 @@
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
+import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
-import android.view.ViewParent;
import android.view.ContextMenu.ContextMenuInfo;
+import android.view.View.OnFocusChangeListener;
+import android.view.View.OnTouchListener;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputMethodManager;
import android.widget.AbsListView;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Filter;
-import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.QuickContactBadge;
import android.widget.ResourceCursorAdapter;
import android.widget.SectionIndexer;
-import android.widget.TabHost;
import android.widget.TextView;
import android.widget.AbsListView.OnScrollListener;
-import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
import java.util.List;
import java.util.Random;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
/**
* Displays a list of contacts. Usually is embedded into the ContactsActivity.
*/
@SuppressWarnings("deprecation")
public class ContactsListActivity extends ListActivity implements View.OnCreateContextMenuListener,
- View.OnClickListener, View.OnKeyListener, TextWatcher, TextView.OnEditorActionListener {
+ View.OnClickListener, View.OnKeyListener, TextWatcher, TextView.OnEditorActionListener,
+ OnFocusChangeListener, OnTouchListener {
public static class JoinContactActivity extends ContactsListActivity {
}
+ public static class ContactsSearchActivity extends ContactsListActivity {
+
+ }
+
private static final String TAG = "ContactsListActivity";
private static final boolean ENABLE_ACTION_ICON_OVERLAYS = true;
private static final String LIST_STATE_KEY = "liststate";
-
- /**
- * Saved state key for the flag that indicates if the UI is in the search mode.
- */
- private static final String SEARCH_MODE_KEY = "searchMode";
+ private static final String SHORTCUT_ACTION_KEY = "shortcutAction";
static final int MENU_ITEM_VIEW_CONTACT = 1;
static final int MENU_ITEM_CALL = 2;
@@ -157,6 +151,7 @@
private static final int SUBACTIVITY_VIEW_CONTACT = 2;
private static final int SUBACTIVITY_DISPLAY_GROUP = 3;
private static final int SUBACTIVITY_SEARCH = 4;
+ private static final int SUBACTIVITY_FILTER = 5;
private static final int TEXT_HIGHLIGHTING_ANIMATION_DURATION = 350;
@@ -238,36 +233,41 @@
/** 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;
/** Show all phone numbers and pick them when clicking */
- // TODO fix and reenable search in phone number picker
- static final int MODE_PICK_PHONE = 50 | MODE_MASK_PICKER | MODE_MASK_NO_PRESENCE |
- MODE_MASK_NO_FILTER;
+ 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;
+ 55 | MODE_MASK_PICKER | MODE_MASK_NO_PRESENCE;
/** 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_NO_FILTER | MODE_MASK_SHOW_NUMBER_OF_CONTACTS;
+ 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_NO_FILTER | MODE_MASK_PICKER;
+ 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_NO_FILTER | MODE_MASK_PICKER;
+ 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;
/**
* An action used to do perform search while in a contact picker. It is initiated
* by the ContactListActivity itself.
*/
- private static final String ACTION_INTERNAL_SEARCH = "com.android.contacts.INTERNAL_SEARCH";
+ private static final String ACTION_SEARCH_FOR_SHORTCUT = "com.android.contacts.INTERNAL_SEARCH";
/** Maximum number of suggestions shown for joining aggregates */
static final int MAX_SUGGESTIONS = 4;
@@ -395,8 +395,6 @@
private String mShortcutAction;
- private int mScrollState;
-
/**
* Internal query type when in mode {@link #MODE_QUERY_PICK_TO_VIEW}.
*/
@@ -406,11 +404,10 @@
private static final int QUERY_MODE_MAILTO = 1;
private static final int QUERY_MODE_TEL = 2;
- /**
- * Data to use when in mode {@link #MODE_QUERY_PICK_TO_VIEW}. Usually
- * provided by scheme-specific part of incoming {@link Intent#getData()}.
- */
- private String mQueryData;
+ private boolean mSearchMode;
+ private boolean mShowNumberOfContacts;
+
+ private String mInitialFilter;
private static final String CLAUSE_ONLY_VISIBLE = Contacts.IN_VISIBLE_GROUP + "=1";
private static final String CLAUSE_ONLY_PHONES = Contacts.HAS_PHONE_NUMBER + "=1";
@@ -431,7 +428,6 @@
private static final UriMatcher sContactsIdMatcher;
private ContactPhotoLoader mPhotoLoader;
- private static ExecutorService sImageFetchThreadPool;
static {
sContactsIdMatcher = new UriMatcher(UriMatcher.NO_MATCH);
@@ -489,10 +485,6 @@
private int mSortOrder;
private boolean mHighlightWhenScrolling;
private TextHighlightingAnimation mHighlightingAnimation;
-
- // If true, the activity is in the "search mode" with the search UI displayed.
- private boolean mSearchMode;
- private View mSearchView;
private SearchEditText mSearchEditText;
/**
@@ -508,24 +500,48 @@
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
- // Resolve the intent
- final Intent intent = getIntent();
-
mIconSize = getResources().getDimensionPixelSize(android.R.dimen.app_icon_size);
mContactsPrefs = new ContactsPreferences(this);
mPhotoLoader = new ContactPhotoLoader(this, R.drawable.ic_contact_list_picture);
+ // 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(UI.TITLE_EXTRA_KEY);
if (title != null) {
setTitle(title);
}
- final String action = intent.getAction();
- mMode = MODE_UNKNOWN;
+ String action = intent.getAction();
+ String component = intent.getComponent().getClassName();
+
+ // 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;
+ 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;
+ }
+ } else {
+ mInitialFilter = null;
+ }
+ }
Log.i(TAG, "Called with action: " + action);
- if (UI.LIST_DEFAULT.equals(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
@@ -541,11 +557,11 @@
mMode = MODE_CUSTOM;
mDisplayOnlyPhones = false;
} else if (UI.LIST_STARRED_ACTION.equals(action)) {
- mMode = MODE_STARRED;
+ mMode = mSearchMode ? MODE_DEFAULT : MODE_STARRED;
} else if (UI.LIST_FREQUENT_ACTION.equals(action)) {
- mMode = MODE_FREQUENT;
+ mMode = mSearchMode ? MODE_DEFAULT : MODE_FREQUENT;
} else if (UI.LIST_STREQUENT_ACTION.equals(action)) {
- mMode = MODE_STREQUENT;
+ mMode = mSearchMode ? MODE_DEFAULT : MODE_STREQUENT;
} else if (UI.LIST_CONTACTS_WITH_PHONES_ACTION.equals(action)) {
mMode = MODE_CUSTOM;
mDisplayOnlyPhones = true;
@@ -567,14 +583,18 @@
mMode = MODE_LEGACY_PICK_POSTAL;
}
} else if (Intent.ACTION_CREATE_SHORTCUT.equals(action)) {
- if (intent.getComponent().getClassName().equals("alias.DialShortcut")) {
+ if (component.equals("alias.DialShortcut")) {
mMode = MODE_PICK_PHONE;
mShortcutAction = Intent.ACTION_CALL;
setTitle(R.string.callShortcutActivityTitle);
- } else if (intent.getComponent().getClassName().equals("alias.MessageShortcut")) {
+ } else if (component.equals("alias.MessageShortcut")) {
mMode = MODE_PICK_PHONE;
mShortcutAction = Intent.ACTION_SENDTO;
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;
@@ -583,7 +603,11 @@
} else if (Intent.ACTION_GET_CONTENT.equals(action)) {
final String type = intent.resolveType(this);
if (Contacts.CONTENT_ITEM_TYPE.equals(type)) {
- mMode = MODE_PICK_OR_CREATE_CONTACT;
+ 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)) {
@@ -593,7 +617,11 @@
} else if (ContactMethods.CONTENT_POSTAL_ITEM_TYPE.equals(type)) {
mMode = MODE_LEGACY_PICK_POSTAL;
} else if (People.CONTENT_ITEM_TYPE.equals(type)) {
- mMode = MODE_LEGACY_PICK_OR_CREATE_PERSON;
+ if (mSearchMode) {
+ mMode = MODE_LEGACY_PICK_PERSON;
+ } else {
+ mMode = MODE_LEGACY_PICK_OR_CREATE_PERSON;
+ }
}
} else if (Intent.ACTION_INSERT_OR_EDIT.equals(action)) {
@@ -615,19 +643,28 @@
if (intent.hasExtra(Insert.EMAIL)) {
mMode = MODE_QUERY_PICK_TO_VIEW;
mQueryMode = QUERY_MODE_MAILTO;
- mQueryData = intent.getStringExtra(Insert.EMAIL);
+ mInitialFilter = 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);
+ mInitialFilter = intent.getStringExtra(Insert.PHONE);
} else {
// Otherwise handle the more normal search case
mMode = MODE_QUERY;
- mQueryData = getIntent().getStringExtra(SearchManager.QUERY);
+ mInitialFilter = getIntent().getStringExtra(SearchManager.QUERY);
}
- } else if (ACTION_INTERNAL_SEARCH.equals(action)) {
- mMode = MODE_QUERY_PICK;
- mQueryData = getIntent().getStringExtra(SearchManager.QUERY);
+ } else if (ACTION_SEARCH_FOR_SHORTCUT.equals(action)) {
+ // The search request has extras to specify query
+ mShortcutAction = intent.getStringExtra(SHORTCUT_ACTION_KEY);
+ if (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;
+ mInitialFilter = getIntent().getStringExtra(SearchManager.QUERY);
+ }
// Since this is the filter activity it receives all intents
// dispatched from the SearchManager for security reasons
@@ -673,13 +710,17 @@
}
if (JOIN_AGGREGATE.equals(action)) {
- mMode = MODE_JOIN_CONTACT;
- mQueryAggregateId = intent.getLongExtra(EXTRA_AGGREGATE_ID, -1);
- if (mQueryAggregateId == -1) {
- Log.e(TAG, "Intent " + action + " is missing required extra: "
- + EXTRA_AGGREGATE_ID);
- setResult(RESULT_CANCELED);
- finish();
+ if (mSearchMode) {
+ mMode = MODE_PICK_CONTACT;
+ } else {
+ mMode = MODE_JOIN_CONTACT;
+ mQueryAggregateId = intent.getLongExtra(EXTRA_AGGREGATE_ID, -1);
+ if (mQueryAggregateId == -1) {
+ Log.e(TAG, "Intent " + action + " is missing required extra: "
+ + EXTRA_AGGREGATE_ID);
+ setResult(RESULT_CANCELED);
+ finish();
+ }
}
}
@@ -687,6 +728,10 @@
mMode = MODE_DEFAULT;
}
+ if ((mMode & MODE_MASK_SHOW_NUMBER_OF_CONTACTS) != 0 || mSearchMode) {
+ mShowNumberOfContacts = true;
+ }
+
if (mMode == MODE_JOIN_CONTACT) {
setContentView(R.layout.contacts_list_content_join);
TextView blurbView = (TextView)findViewById(R.id.join_contact_blurb);
@@ -695,12 +740,16 @@
getContactDisplayName(mQueryAggregateId));
blurbView.setText(blurb);
mJoinModeShowAllContacts = true;
+ } else if (mSearchMode) {
+ setContentView(R.layout.contacts_search_content);
} else {
setContentView(R.layout.contacts_list_content);
}
setupListView();
- setupSearchView();
+ if (mSearchMode) {
+ setupSearchView();
+ }
mQueryHandler = new QueryHandler(this);
mJustCreated = true;
@@ -735,12 +784,9 @@
// Tell list view to not show dividers. We'll do it ourself so that we can *not* show
// them when an A-Z headers is visible.
list.setDividerHeight(0);
- list.setFocusable(true);
+ list.setFocusable((mMode & MODE_MASK_NO_FILTER) == 0);
list.setOnCreateContextMenuListener(this);
- // Set the proper empty string
- setEmptyText();
-
mAdapter = new ContactItemListAdapter(this);
setListAdapter(mAdapter);
@@ -754,6 +800,8 @@
list.setOnScrollListener(mAdapter);
list.setOnKeyListener(this);
+ list.setOnFocusChangeListener(this);
+ list.setOnTouchListener(this);
// We manually save/restore the listview state
list.setSaveEnabled(false);
@@ -763,23 +811,10 @@
* Configures search UI.
*/
private void setupSearchView() {
- if ((mMode & MODE_MASK_NO_FILTER) == 0) {
- mSearchView = findViewById(R.id.searchView);
- mSearchEditText = (SearchEditText)mSearchView.findViewById(R.id.search_src_text);
- mSearchEditText.addTextChangedListener(this);
- mSearchEditText.setOnEditorActionListener(this);
-
- ImageButton searchButton = (ImageButton)mSearchView.findViewById(R.id.search_btn);
- searchButton.setOnClickListener(this);
- }
- }
-
- private boolean isPickerMode() {
- return mMode == MODE_PICK_CONTACT
- || mMode == MODE_PICK_OR_CREATE_CONTACT
- || mMode == MODE_LEGACY_PICK_PERSON
- || mMode == MODE_LEGACY_PICK_OR_CREATE_PERSON
- || mMode == MODE_QUERY_PICK;
+ mSearchEditText = (SearchEditText)findViewById(R.id.search_src_text);
+ mSearchEditText.addTextChangedListener(this);
+ mSearchEditText.setOnEditorActionListener(this);
+ mSearchEditText.setText(mInitialFilter);
}
private String getContactDisplayName(long contactId) {
@@ -804,7 +839,6 @@
return contactName;
}
-
private int getSummaryDisplayNameColumnIndex() {
if (mDisplayOrder == ContactsContract.Preferences.DISPLAY_ORDER_PRIMARY) {
return SUMMARY_DISPLAY_NAME_PRIMARY_COLUMN_INDEX;
@@ -826,23 +860,16 @@
}
break;
}
- case R.id.search_btn: {
- doSearch();
- break;
- }
}
}
private void setEmptyText() {
- if (mMode == MODE_JOIN_CONTACT) {
+ if (mMode == MODE_JOIN_CONTACT || mSearchMode) {
return;
}
TextView empty = (TextView) findViewById(R.id.emptyText);
-
- if (mSearchMode) {
- empty.setText(getText(R.string.noMatchingFilteredContacts));
- } else if (mDisplayOnlyPhones) {
+ if (mDisplayOnlyPhones) {
empty.setText(getText(R.string.noContactsWithPhoneNumbers));
} else if (mMode == MODE_STREQUENT || mMode == MODE_STARRED) {
empty.setText(getText(R.string.noFavoritesHelpText));
@@ -881,9 +908,6 @@
mDisplayOnlyPhones = prefs.getBoolean(Prefs.DISPLAY_ONLY_PHONES,
Prefs.DISPLAY_ONLY_PHONES_DEFAULT);
-
- // Update the empty text view with the proper string, as the group may have changed
- setEmptyText();
}
@Override
@@ -897,8 +921,6 @@
super.onResume();
mPhotoLoader.resume();
- mScrollState = OnScrollListener.SCROLL_STATE_IDLE;
- boolean runQuery = true;
Activity parent = getParent();
// Do this before setting the filter. The filter thread relies
@@ -909,11 +931,12 @@
setDefaultMode();
}
+ // See if we were invoked with a filter
if (mSearchMode) {
- startSearchMode(false);
+ mSearchEditText.requestFocus();
}
- if (mJustCreated && runQuery) {
+ if (mJustCreated) {
// We need to start a query here the first time the activity is launched, as long
// as we aren't doing a filter.
startQuery();
@@ -928,12 +951,6 @@
return null;
}
- private void setTextFilter(String filterText) {
- if (mSearchEditText != null) {
- mSearchEditText.setText(filterText);
- }
- }
-
@Override
protected void onRestart() {
super.onRestart();
@@ -953,8 +970,9 @@
protected void onSaveInstanceState(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(SEARCH_MODE_KEY, mSearchMode);
+ if (mList != null) {
+ icicle.putParcelable(LIST_STATE_KEY, mList.onSaveInstanceState());
+ }
}
@Override
@@ -962,7 +980,6 @@
super.onRestoreInstanceState(icicle);
// Retrieve list state. This will be applied after the QueryHandler has run
mListState = icicle.getParcelable(LIST_STATE_KEY);
- mSearchMode = icicle.getBoolean(SEARCH_MODE_KEY);
}
@Override
@@ -1010,7 +1027,7 @@
return true;
}
case R.id.menu_search: {
- startSearchMode(true);
+ onSearchRequested();
return true;
}
case R.id.menu_add: {
@@ -1034,69 +1051,21 @@
return false;
}
- /**
- * Displays and initializes the search UI at the top of the activity. If
- * this activity is part of a tab activity, also removes the tabs.
- *
- * @param showKeyboard a flag indicating whether the soft keyboard should be
- * auto shown automatically.
- */
- private void startSearchMode(boolean showKeyboard) {
- View tabs = findTabWidget();
- if (tabs != null) {
- tabs.setVisibility(View.GONE);
- }
-
- mList.setFocusable(false);
- mSearchEditText.setAutoShowKeyboard(showKeyboard);
- mSearchEditText.requestFocus();
- mSearchView.setVisibility(View.VISIBLE);
- mSearchMode = true;
- setEmptyText();
- }
-
- /**
- * Hides the search UI and shows the tabs if they were hidden before.
- */
- private void stopSearchMode() {
-
- // In case the list view owns the soft keyboard at this point, hide the keyboard
- InputMethodManager inputManager = (InputMethodManager)getSystemService(
- Context.INPUT_METHOD_SERVICE);
- inputManager.hideSoftInputFromWindow(mList.getWindowToken(), 0);
-
- // In case the search text view owns the soft keyboard, do the same
- mSearchEditText.hideKeyboard();
- mSearchView.setVisibility(View.GONE);
-
- View tabs = findTabWidget();
- if (tabs != null) {
- tabs.setVisibility(View.VISIBLE);
- }
-
- mSearchMode = false;
- setEmptyText();
-
- // This will trigger a query
- setTextFilter(null);
-
- mList.setFocusable(true);
- }
-
- /**
- * If this activity is hosted by a tab activity, the method returns the
- * TabWidget from the TabHost activity; otherwise it returns null.
- */
- private View findTabWidget() {
- View start = getListView();
- ViewParent parent = start.getParent();
- while (parent != null) {
- if (parent instanceof TabHost) {
- return ((TabHost)parent).getTabWidget();
+ @Override
+ public void startSearch(String initialQuery, boolean selectInitialQuery, Bundle appSearchData,
+ boolean globalSearch) {
+ if (globalSearch) {
+ super.startSearch(initialQuery, selectInitialQuery, appSearchData, globalSearch);
+ } else {
+ if (!mSearchMode && (mMode & MODE_MASK_NO_FILTER) == 0) {
+ if ((mMode & MODE_MASK_PICKER) != 0) {
+ ContactsSearchManager.startSearchForResult(this, initialQuery,
+ SUBACTIVITY_FILTER);
+ } else {
+ ContactsSearchManager.startSearch(this, initialQuery);
+ }
}
- parent = parent.getParent();
}
- return null;
}
/**
@@ -1104,23 +1073,14 @@
* search text edit.
*/
protected void onSearchTextChanged() {
+ // Set the proper empty string
+ setEmptyText();
+
Filter filter = mAdapter.getFilter();
filter.filter(getTextFilter());
}
/**
- * Closes search UI if shown, otherwise follows the default "back" behavior.
- */
- @Override
- public void onBackPressed() {
- if (mSearchMode) {
- stopSearchMode();
- } else {
- super.onBackPressed();
- }
- }
-
- /**
* Starts a new activity that will run a search query and display search results.
*/
private void doSearch() {
@@ -1129,10 +1089,26 @@
return;
}
- Intent intent = new Intent(this, getClass());
+ Intent intent = new Intent(this, ContactsListActivity.class);
intent.putExtra(SearchManager.QUERY, query);
- if (isPickerMode()) {
- intent.setAction(ACTION_INTERNAL_SEARCH);
+ if ((mMode & MODE_MASK_PICKER) != 0) {
+ intent.setAction(ACTION_SEARCH_FOR_SHORTCUT);
+ intent.putExtra(SHORTCUT_ACTION_KEY, mShortcutAction);
+ if (mShortcutAction != null) {
+ if (Intent.ACTION_CALL.equals(mShortcutAction)
+ || Intent.ACTION_SENDTO.equals(mShortcutAction)) {
+ intent.putExtra(Insert.PHONE, query);
+ }
+ } else {
+ switch (mQueryMode) {
+ case QUERY_MODE_MAILTO:
+ intent.putExtra(Insert.EMAIL, query);
+ break;
+ case QUERY_MODE_TEL:
+ intent.putExtra(Insert.PHONE, query);
+ break;
+ }
+ }
startActivityForResult(intent, SUBACTIVITY_SEARCH);
} else {
intent.setAction(Intent.ACTION_SEARCH);
@@ -1301,10 +1277,12 @@
mJustCreated = true;
break;
+ case SUBACTIVITY_FILTER:
case SUBACTIVITY_SEARCH:
+ // Pass through results of filter or search UI
if (resultCode == RESULT_OK) {
- returnPickerResult(null, data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME),
- data.getData());
+ setResult(RESULT_OK, data);
+ finish();
}
break;
}
@@ -1416,8 +1394,7 @@
if (!mSearchMode && (mMode & MODE_MASK_NO_FILTER) == 0) {
int unicodeChar = event.getUnicodeChar();
if (unicodeChar != 0) {
- setTextFilter(new String(new int[]{unicodeChar}, 0, 1));
- startSearchMode(false);
+ startSearch(new String(new int[]{unicodeChar}, 0, 1), false, null, false);
return true;
}
}
@@ -1441,8 +1418,11 @@
* Event handler for search UI.
*/
public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
- if (actionId == EditorInfo.IME_ACTION_GO) {
- doSearch();
+ if (actionId == EditorInfo.IME_ACTION_DONE) {
+ hideSoftKeyboard();
+ if (TextUtils.isEmpty(getTextFilter())) {
+ finish();
+ }
return true;
}
return false;
@@ -1467,19 +1447,6 @@
}
break;
}
-
- case KeyEvent.KEYCODE_SEARCH: {
- if ((mMode & MODE_MASK_NO_FILTER) == 0) {
- if (mSearchMode) {
- stopSearchMode();
- } else {
- startSearchMode(true);
- }
- return true;
- } else {
- return false;
- }
- }
}
return super.onKeyDown(keyCode, event);
@@ -1525,12 +1492,40 @@
}
}
+ /**
+ * Dismisses the soft keyboard when the list takes focus.
+ */
+ public void onFocusChange(View view, boolean hasFocus) {
+ if (view == getListView() && hasFocus) {
+ hideSoftKeyboard();
+ }
+ }
+
+ /**
+ * Dismisses the soft keyboard when the list takes focus.
+ */
+ public boolean onTouch(View view, MotionEvent event) {
+ if (view == getListView()) {
+ hideSoftKeyboard();
+ }
+ return false;
+ }
+
+ /**
+ * Dismisses the search UI along with the keyboard if the filter text is empty.
+ */
+ public boolean onKeyPreIme(int keyCode, KeyEvent event) {
+ if (mSearchMode && keyCode == KeyEvent.KEYCODE_BACK && TextUtils.isEmpty(getTextFilter())) {
+ hideSoftKeyboard();
+ onBackPressed();
+ return true;
+ }
+ return false;
+ }
+
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
- // Hide soft keyboard, if visible
- InputMethodManager inputMethodManager = (InputMethodManager)
- getSystemService(Context.INPUT_METHOD_SERVICE);
- inputMethodManager.hideSoftInputFromWindow(mList.getWindowToken(), 0);
+ hideSoftKeyboard();
if (mMode == MODE_INSERT_OR_EDIT_CONTACT) {
Intent intent;
@@ -1560,6 +1555,8 @@
} else if (mMode == MODE_JOIN_CONTACT && id == JOIN_MODE_SHOW_ALL_CONTACTS_ID) {
mJoinModeShowAllContacts = false;
startQuery();
+ } else if (mSearchMode && mAdapter.isSearchAllContactsItemPosition(position)) {
+ doSearch();
} else if (id > 0) {
final Uri uri = getSelectedUri(position);
if ((mMode & MODE_MASK_PICKER) == 0) {
@@ -1572,14 +1569,14 @@
final Intent intent = new Intent(Intent.ACTION_VIEW, uri);
startActivity(intent);
finish();
- } else if (isPickerMode()) {
- Cursor c = (Cursor) mAdapter.getItem(position);
- returnPickerResult(c, c.getString(getSummaryDisplayNameColumnIndex()), uri);
- } else if (mMode == MODE_PICK_PHONE) {
+ } else if (mMode == MODE_PICK_PHONE || mMode == MODE_QUERY_PICK_PHONE) {
Cursor c = (Cursor) mAdapter.getItem(position);
long contactId = c.getLong(PHONE_CONTACT_ID_COLUMN_INDEX);
returnPickerResult(c, c.getString(PHONE_DISPLAY_NAME_COLUMN_INDEX),
ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId));
+ } else if ((mMode & MODE_MASK_PICKER) != 0) {
+ Cursor c = (Cursor) mAdapter.getItem(position);
+ returnPickerResult(c, c.getString(getSummaryDisplayNameColumnIndex()), uri);
} else if (mMode == MODE_PICK_POSTAL
|| mMode == MODE_LEGACY_PICK_POSTAL
|| mMode == MODE_LEGACY_PICK_PHONE) {
@@ -1590,6 +1587,13 @@
}
}
+ private void hideSoftKeyboard() {
+ // Hide soft keyboard, if visible
+ InputMethodManager inputMethodManager = (InputMethodManager)
+ getSystemService(Context.INPUT_METHOD_SERVICE);
+ inputMethodManager.hideSoftInputFromWindow(mList.getWindowToken(), 0);
+ }
+
/**
* @param contactUri In most cases, this should be a lookup {@link Uri}, possibly
* generated through {@link Contacts#getLookupUri(long, String)}.
@@ -1835,15 +1839,21 @@
}
case MODE_QUERY_PICK_TO_VIEW: {
if (mQueryMode == QUERY_MODE_MAILTO) {
- return Uri.withAppendedPath(Email.CONTENT_FILTER_URI, Uri.encode(mQueryData));
+ return Uri.withAppendedPath(Email.CONTENT_FILTER_URI,
+ Uri.encode(mInitialFilter));
} else if (mQueryMode == QUERY_MODE_TEL) {
- return Uri.withAppendedPath(Phone.CONTENT_FILTER_URI, Uri.encode(mQueryData));
+ return Uri.withAppendedPath(Phone.CONTENT_FILTER_URI,
+ Uri.encode(mInitialFilter));
}
return CONTACTS_CONTENT_URI_WITH_LETTER_COUNTS;
}
case MODE_QUERY:
case MODE_QUERY_PICK: {
- return getContactFilterUri(mQueryData);
+ return getContactFilterUri(mInitialFilter);
+ }
+ case MODE_QUERY_PICK_PHONE: {
+ return Uri.withAppendedPath(Phone.CONTENT_FILTER_URI,
+ Uri.encode(mInitialFilter));
}
case MODE_GROUP: {
return mGroupUri;
@@ -1895,7 +1905,8 @@
case MODE_LEGACY_PICK_OR_CREATE_PERSON: {
return ContentUris.withAppendedId(People.CONTENT_URI, id);
}
- case MODE_PICK_PHONE: {
+ case MODE_PICK_PHONE:
+ case MODE_QUERY_PICK_PHONE: {
return ContentUris.withAppendedId(Data.CONTENT_URI, id);
}
case MODE_LEGACY_PICK_PHONE: {
@@ -1932,6 +1943,7 @@
case MODE_LEGACY_PICK_OR_CREATE_PERSON: {
return LEGACY_PEOPLE_PROJECTION ;
}
+ case MODE_QUERY_PICK_PHONE:
case MODE_PICK_PHONE: {
return PHONES_PROJECTION;
}
@@ -2044,6 +2056,9 @@
}
void startQuery() {
+ // Set the proper empty string
+ setEmptyText();
+
mAdapter.setLoading(true);
// Cancel any pending queries
@@ -2065,6 +2080,11 @@
}
String[] projection = getProjectionForQuery();
+ if (mSearchMode && TextUtils.isEmpty(getTextFilter())) {
+ mAdapter.changeCursor(new MatrixCursor(projection));
+ return;
+ }
+
String callingPackage = getCallingPackage();
Uri uri = getUriToQuery();
if (!TextUtils.isEmpty(callingPackage)) {
@@ -2077,35 +2097,20 @@
// Kick off the new query
switch (mMode) {
case MODE_GROUP:
- mQueryHandler.startQuery(QUERY_TOKEN, null,
- uri, projection, getContactSelection(), null,
- getSortOrder(projection));
- break;
-
case MODE_DEFAULT:
case MODE_PICK_CONTACT:
case MODE_PICK_OR_CREATE_CONTACT:
case MODE_INSERT_OR_EDIT_CONTACT:
- mQueryHandler.startQuery(QUERY_TOKEN, null, uri,
- projection, getContactSelection(), null,
- getSortOrder(projection));
+ mQueryHandler.startQuery(QUERY_TOKEN, null, uri, projection, getContactSelection(),
+ null, getSortOrder(projection));
break;
case MODE_LEGACY_PICK_PERSON:
case MODE_LEGACY_PICK_OR_CREATE_PERSON:
- mQueryHandler.startQuery(QUERY_TOKEN, null, uri,
- projection, null, null,
- getSortOrder(projection));
- break;
-
+ case MODE_PICK_POSTAL:
case MODE_QUERY:
- case MODE_QUERY_PICK: {
- mQueryHandler.startQuery(QUERY_TOKEN, null, uri,
- projection, null, null,
- getSortOrder(projection));
- break;
- }
-
+ case MODE_QUERY_PICK:
+ case MODE_QUERY_PICK_PHONE:
case MODE_QUERY_PICK_TO_VIEW: {
mQueryHandler.startQuery(QUERY_TOKEN, null, uri, projection, null, null,
getSortOrder(projection));
@@ -2133,12 +2138,7 @@
case MODE_PICK_PHONE:
case MODE_LEGACY_PICK_PHONE:
mQueryHandler.startQuery(QUERY_TOKEN, null, uri,
- projection, null, null, getSortOrder(projection));
- break;
-
- case MODE_PICK_POSTAL:
- mQueryHandler.startQuery(QUERY_TOKEN, null, uri,
- projection, null, null, getSortOrder(projection));
+ projection, CLAUSE_ONLY_VISIBLE, null, getSortOrder(projection));
break;
case MODE_LEGACY_PICK_POSTAL:
@@ -2163,10 +2163,12 @@
* @return a cursor with the results of the filter
*/
Cursor doFilter(String filter) {
- final ContentResolver resolver = getContentResolver();
-
String[] projection = getProjectionForQuery();
+ if (mSearchMode && TextUtils.isEmpty(getTextFilter())) {
+ return new MatrixCursor(projection);
+ }
+ final ContentResolver resolver = getContentResolver();
switch (mMode) {
case MODE_DEFAULT:
case MODE_PICK_CONTACT:
@@ -2211,7 +2213,7 @@
if (!TextUtils.isEmpty(filter)) {
uri = Uri.withAppendedPath(Phone.CONTENT_FILTER_URI, Uri.encode(filter));
}
- return resolver.query(uri, projection, null, null,
+ return resolver.query(uri, projection, CLAUSE_ONLY_VISIBLE, null,
getSortOrder(projection));
}
@@ -2380,7 +2382,7 @@
if (activity.mAdapter.mSuggestionsCursorCount == 0
|| !activity.mJoinModeShowAllContacts) {
startQuery(QUERY_TOKEN, null, activity.getContactFilterUri(
- activity.mQueryData),
+ activity.getTextFilter()),
CONTACTS_SUMMARY_PROJECTION,
Contacts._ID + " != " + activity.mQueryAggregateId
+ " AND " + CLAUSE_ONLY_VISIBLE, null,
@@ -2423,17 +2425,6 @@
public TextWithHighlighting textWithHighlighting;
}
- final static class PhotoInfo {
- public int position;
- public long photoId;
-
- public PhotoInfo(int position, long photoId) {
- this.position = position;
- this.photoId = photoId;
- }
- public QuickContactBadge photoView;
- }
-
final static class PinnedHeaderCache {
public TextView titleView;
public ColorStateList textColor;
@@ -2460,21 +2451,23 @@
switch (mMode) {
case MODE_LEGACY_PICK_POSTAL:
case MODE_PICK_POSTAL:
- mDisplaySectionHeaders = false;
- break;
case MODE_LEGACY_PICK_PHONE:
case MODE_PICK_PHONE:
+ case MODE_STREQUENT:
+ case MODE_FREQUENT:
mDisplaySectionHeaders = false;
break;
- default:
- break;
+ }
+
+ if (mSearchMode) {
+ mDisplaySectionHeaders = false;
}
// Do not display the second line of text if in a specific SEARCH query mode, usually for
// matching a specific E-mail or phone number. Any contact details
// shown would be identical, and columns might not even be present
// in the returned cursor.
- if (mQueryMode != QUERY_MODE_NONE) {
+ if (mMode != MODE_QUERY_PICK_PHONE && mQueryMode != QUERY_MODE_NONE) {
mDisplayAdditionalData = false;
}
@@ -2490,10 +2483,6 @@
mDisplayPhotos = true;
setViewResource(R.layout.contacts_list_item_photo);
}
-
- if (mMode == MODE_STREQUENT || mMode == MODE_FREQUENT) {
- mDisplaySectionHeaders = false;
- }
}
public boolean getDisplaySectionHeadersEnabled() {
@@ -2536,6 +2525,8 @@
// This mode mask adds a header and we always want it to show up, even
// if the list is empty, so always claim the list is not empty.
return false;
+ } else if (mSearchMode) {
+ return TextUtils.isEmpty(getTextFilter());
} else {
if (mCursor == null || mLoading) {
// We don't want the empty state to show when loading.
@@ -2548,18 +2539,23 @@
@Override
public int getItemViewType(int position) {
- if (position == 0
- && ((mMode & MODE_MASK_SHOW_NUMBER_OF_CONTACTS) != 0
- || (mMode & MODE_MASK_CREATE_NEW) != 0)) {
+ if (position == 0 && (mShowNumberOfContacts || (mMode & MODE_MASK_CREATE_NEW) != 0)) {
return IGNORE_ITEM_VIEW_TYPE;
}
+
if (isShowAllContactsItemPosition(position)) {
return IGNORE_ITEM_VIEW_TYPE;
}
+
+ if (isSearchAllContactsItemPosition(position)) {
+ return IGNORE_ITEM_VIEW_TYPE;
+ }
+
if (getSeparatorId(position) != 0) {
// We don't want the separator view to be recycled.
return IGNORE_ITEM_VIEW_TYPE;
}
+
return super.getItemViewType(position);
}
@@ -2571,7 +2567,7 @@
}
// handle the total contacts item
- if (position == 0 && (mMode & MODE_MASK_SHOW_NUMBER_OF_CONTACTS) != 0) {
+ if (position == 0 && mShowNumberOfContacts) {
return getTotalContactCountView(parent);
}
@@ -2585,6 +2581,11 @@
inflate(R.layout.contacts_list_show_all_item, parent, false);
}
+ if (isSearchAllContactsItemPosition(position)) {
+ return getLayoutInflater().
+ inflate(R.layout.contacts_list_search_all_item, parent, false);
+ }
+
// Handle the separator specially
int separatorId = getSeparatorId(position);
if (separatorId != 0) {
@@ -2626,19 +2627,16 @@
View view = inflater.inflate(R.layout.total_contacts, parent, false);
TextView totalContacts = (TextView) view.findViewById(R.id.totalContactsText);
- TextView searchForMore = (TextView) view.findViewById(R.id.searchForMoreText);
String text;
int count = getRealCount();
- if (mMode == MODE_QUERY || mMode == MODE_QUERY_PICK) {
+ if (mMode == MODE_QUERY || mMode == MODE_QUERY_PICK || mMode == MODE_QUERY_PICK_PHONE) {
text = getQuantityText(count, R.string.listFoundAllContactsZero,
R.plurals.listFoundAllContacts);
- searchForMore.setVisibility(View.GONE);
} else if (mSearchMode && !TextUtils.isEmpty(getTextFilter())) {
text = getQuantityText(count, R.string.listFoundAllContactsZero,
R.plurals.searchFoundContacts);
- searchForMore.setVisibility(View.VISIBLE);
} else {
if (mDisplayOnlyPhones) {
text = getQuantityText(count, R.string.listTotalPhoneContactsZero,
@@ -2647,7 +2645,6 @@
text = getQuantityText(count, R.string.listTotalAllContactsZero,
R.plurals.listTotalAllContacts);
}
- searchForMore.setVisibility(View.GONE);
}
totalContacts.setText(text);
return view;
@@ -2668,6 +2665,10 @@
&& mSuggestionsCursorCount != 0 && position == mSuggestionsCursorCount + 2;
}
+ private boolean isSearchAllContactsItemPosition(int position) {
+ return mSearchMode && position == getCount() - 1;
+ }
+
private int getSeparatorId(int position) {
int separatorId = 0;
if (position == mFrequentSeparatorPos) {
@@ -2725,7 +2726,8 @@
boolean highlightingEnabled = false;
switch(mMode) {
case MODE_PICK_PHONE:
- case MODE_LEGACY_PICK_PHONE: {
+ case MODE_LEGACY_PICK_PHONE:
+ case MODE_QUERY_PICK_PHONE: {
nameColumnIndex = PHONE_DISPLAY_NAME_COLUMN_INDEX;
dataColumnIndex = PHONE_NUMBER_COLUMN_INDEX;
typeColumnIndex = PHONE_TYPE_COLUMN_INDEX;
@@ -2987,13 +2989,13 @@
@Override
public boolean areAllItemsEnabled() {
return mMode != MODE_STARRED
- && (mMode & MODE_MASK_SHOW_NUMBER_OF_CONTACTS) == 0
+ && !mShowNumberOfContacts
&& mSuggestionsCursorCount == 0;
}
@Override
public boolean isEnabled(int position) {
- if ((mMode & MODE_MASK_SHOW_NUMBER_OF_CONTACTS) != 0) {
+ if (mShowNumberOfContacts) {
if (position == 0) {
return false;
}
@@ -3012,11 +3014,17 @@
return 0;
}
int superCount = super.getCount();
- if ((mMode & MODE_MASK_SHOW_NUMBER_OF_CONTACTS) != 0 && superCount > 0) {
+ if (mShowNumberOfContacts && (mSearchMode || superCount > 0)) {
// We don't want to count this header if it's the only thing visible, so that
// the empty text will display.
superCount++;
}
+
+ if (mSearchMode) {
+ // Last element in the list is the "Find
+ superCount++;
+ }
+
if (mSuggestionsCursorCount != 0) {
// When showing suggestions, we have 2 additional list items: the "Suggestions"
// and "All contacts" headers.
@@ -3038,7 +3046,7 @@
}
private int getRealPosition(int pos) {
- if ((mMode & MODE_MASK_SHOW_NUMBER_OF_CONTACTS) != 0) {
+ if (mShowNumberOfContacts) {
pos--;
}
@@ -3106,7 +3114,6 @@
}
}
- mScrollState = scrollState;
if (scrollState == OnScrollListener.SCROLL_STATE_FLING) {
mPhotoLoader.pause();
} else if (mDisplayPhotos) {
diff --git a/src/com/android/contacts/ContactsSearchManager.java b/src/com/android/contacts/ContactsSearchManager.java
new file mode 100644
index 0000000..8f42c3a
--- /dev/null
+++ b/src/com/android/contacts/ContactsSearchManager.java
@@ -0,0 +1,63 @@
+/*
+ * 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;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.provider.ContactsContract;
+import android.provider.ContactsContract.Intents.UI;
+
+/**
+ * A convenience class that helps launch contact search from within the app.
+ */
+public class ContactsSearchManager {
+
+ /**
+ * An extra that provides context for search UI and defines the scope for
+ * the search queries.
+ */
+ public static final String ORIGINAL_ACTION_EXTRA_KEY = "originalAction";
+
+ /**
+ * An extra that provides context for search UI and defines the scope for
+ * the search queries.
+ */
+ public static final String ORIGINAL_COMPONENT_EXTRA_KEY = "originalComponent";
+
+ /**
+ * Starts the contact list activity in the search mode.
+ */
+ public static void startSearch(Activity context, String initialQuery) {
+ context.startActivity(buildIntent(context, initialQuery));
+ }
+
+ public static void startSearchForResult(Activity context, String initialQuery,
+ int requestCode) {
+ context.startActivityForResult(buildIntent(context, initialQuery), requestCode);
+ }
+
+ private static Intent buildIntent(Activity context, String initialQuery) {
+ Intent intent = new Intent();
+ intent.setData(ContactsContract.Contacts.CONTENT_URI);
+ intent.setAction(UI.FILTER_CONTACTS_ACTION);
+ intent.putExtra(UI.FILTER_TEXT_EXTRA_KEY, initialQuery);
+ intent.putExtra(ORIGINAL_ACTION_EXTRA_KEY, context.getIntent().getAction());
+ intent.putExtra(ORIGINAL_COMPONENT_EXTRA_KEY,
+ context.getIntent().getComponent().getClassName());
+ return intent;
+ }
+}
diff --git a/src/com/android/contacts/RecentCallsListActivity.java b/src/com/android/contacts/RecentCallsListActivity.java
index 8e553d1..dedc531 100644
--- a/src/com/android/contacts/RecentCallsListActivity.java
+++ b/src/com/android/contacts/RecentCallsListActivity.java
@@ -1083,4 +1083,14 @@
startActivity(intent);
}
}
+
+ @Override
+ public void startSearch(String initialQuery, boolean selectInitialQuery, Bundle appSearchData,
+ boolean globalSearch) {
+ if (globalSearch) {
+ super.startSearch(initialQuery, selectInitialQuery, appSearchData, globalSearch);
+ } else {
+ ContactsSearchManager.startSearch(this, initialQuery);
+ }
+ }
}
diff --git a/src/com/android/contacts/SearchEditText.java b/src/com/android/contacts/SearchEditText.java
index 74a1d30..7683f23 100644
--- a/src/com/android/contacts/SearchEditText.java
+++ b/src/com/android/contacts/SearchEditText.java
@@ -17,60 +17,53 @@
package com.android.contacts;
import android.content.Context;
-import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.text.TextUtils;
import android.util.AttributeSet;
-import android.view.inputmethod.InputMethodManager;
+import android.view.KeyEvent;
import android.widget.EditText;
/**
- * A custom text editor that optionally automatically brings up the soft
- * keyboard when first focused.
+ * A custom text editor that helps automatically dismiss the activity along with the soft
+ * keyboard.
*/
public class SearchEditText extends EditText {
- private boolean mAutoShowKeyboard;
+ private boolean mMagnifyingGlassShown = true;
+ private Drawable mMagnifyingGlass;
public SearchEditText(Context context, AttributeSet attrs) {
super(context, attrs);
+ mMagnifyingGlass = getCompoundDrawables()[2];
}
/**
- * Automatically show the soft keyboard when the field gets focus. This is a
- * single-shot setting - it is reset as soon as the keyboard is shown.
+ * Conditionally shows a magnifying glass icon on the right side of the text field
+ * when the text it empty.
*/
- public void setAutoShowKeyboard(boolean flag) {
- mAutoShowKeyboard = flag;
- }
-
@Override
- public void onWindowFocusChanged(boolean hasWindowFocus) {
- super.onWindowFocusChanged(hasWindowFocus);
- if (hasWindowFocus && mAutoShowKeyboard) {
- showKeyboard();
+ public boolean onPreDraw() {
+ boolean emptyText = TextUtils.isEmpty(getText());
+ if (mMagnifyingGlassShown != emptyText) {
+ mMagnifyingGlassShown = emptyText;
+ if (mMagnifyingGlassShown) {
+ setCompoundDrawables(null, null, mMagnifyingGlass, null);
+ } else {
+ setCompoundDrawables(null, null, null, null);
+ }
+ return false;
}
- }
-
- @Override
- protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {
- super.onFocusChanged(focused, direction, previouslyFocusedRect);
- if (focused && mAutoShowKeyboard) {
- showKeyboard();
- }
+ return super.onPreDraw();
}
/**
- * Explicitly brings up the soft keyboard if necessary.
+ * Forwards the onKeyPreIme call to the view's activity.
*/
- private void showKeyboard() {
- InputMethodManager inputManager = (InputMethodManager)getContext().getSystemService(
- Context.INPUT_METHOD_SERVICE);
- inputManager.showSoftInput(this, 0);
- mAutoShowKeyboard = false;
- }
-
- public void hideKeyboard() {
- InputMethodManager inputManager = (InputMethodManager)getContext().getSystemService(
- Context.INPUT_METHOD_SERVICE);
- inputManager.hideSoftInputFromWindow(getWindowToken(), 0);
+ @Override
+ public boolean onKeyPreIme(int keyCode, KeyEvent event) {
+ if (((ContactsListActivity)getContext()).onKeyPreIme(keyCode, event)) {
+ return true;
+ }
+ return super.onKeyPreIme(keyCode, event);
}
}
diff --git a/src/com/android/contacts/TwelveKeyDialer.java b/src/com/android/contacts/TwelveKeyDialer.java
index c0390eb..1ef3886 100644
--- a/src/com/android/contacts/TwelveKeyDialer.java
+++ b/src/com/android/contacts/TwelveKeyDialer.java
@@ -16,6 +16,10 @@
package com.android.contacts;
+import com.android.internal.telephony.ITelephony;
+import com.android.phone.CallLogAsync;
+import com.android.phone.HapticFeedback;
+
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Context;
@@ -29,22 +33,19 @@
import android.media.ToneGenerator;
import android.net.Uri;
import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
-import android.provider.Contacts.Intents.Insert;
+import android.provider.Settings;
import android.provider.Contacts.People;
import android.provider.Contacts.Phones;
import android.provider.Contacts.PhonesColumns;
-import android.provider.Settings;
+import android.provider.Contacts.Intents.Insert;
import android.telephony.PhoneNumberFormattingTextWatcher;
import android.telephony.PhoneNumberUtils;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.text.Editable;
-import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.text.method.DialerKeyListener;
@@ -64,13 +65,10 @@
import android.widget.ListView;
import android.widget.TextView;
-import com.android.internal.telephony.ITelephony;
-import com.android.phone.CallLogAsync;
-import com.android.phone.HapticFeedback;
-
/**
* Dialer activity that displays the typical twelve key interface.
*/
+@SuppressWarnings("deprecation")
public class TwelveKeyDialer extends Activity implements View.OnClickListener,
View.OnLongClickListener, View.OnKeyListener,
AdapterView.OnItemClickListener, TextWatcher {
@@ -1235,4 +1233,14 @@
});
mCallLog.getLastOutgoingCall(lastCallArgs);
}
+
+ @Override
+ public void startSearch(String initialQuery, boolean selectInitialQuery, Bundle appSearchData,
+ boolean globalSearch) {
+ if (globalSearch) {
+ super.startSearch(initialQuery, selectInitialQuery, appSearchData, globalSearch);
+ } else {
+ ContactsSearchManager.startSearch(this, initialQuery);
+ }
+ }
}
diff --git a/src/com/android/contacts/ViewContactActivity.java b/src/com/android/contacts/ViewContactActivity.java
index 8402b3f..2b0c594 100644
--- a/src/com/android/contacts/ViewContactActivity.java
+++ b/src/com/android/contacts/ViewContactActivity.java
@@ -1259,4 +1259,14 @@
final int _ID = 0;
}
+
+ @Override
+ public void startSearch(String initialQuery, boolean selectInitialQuery, Bundle appSearchData,
+ boolean globalSearch) {
+ if (globalSearch) {
+ super.startSearch(initialQuery, selectInitialQuery, appSearchData, globalSearch);
+ } else {
+ ContactsSearchManager.startSearch(this, initialQuery);
+ }
+ }
}
diff --git a/src/com/android/contacts/ui/ContactsPreferencesActivity.java b/src/com/android/contacts/ui/ContactsPreferencesActivity.java
index d9491be..a2edd8d 100644
--- a/src/com/android/contacts/ui/ContactsPreferencesActivity.java
+++ b/src/com/android/contacts/ui/ContactsPreferencesActivity.java
@@ -16,6 +16,7 @@
package com.android.contacts.ui;
+import com.android.contacts.ContactsSearchManager;
import com.android.contacts.R;
import com.android.contacts.model.ContactsSource;
import com.android.contacts.model.GoogleSource;
@@ -1054,4 +1055,14 @@
context.stopService(new Intent(context, EmptyService.class));
}
}
+
+ @Override
+ public void startSearch(String initialQuery, boolean selectInitialQuery, Bundle appSearchData,
+ boolean globalSearch) {
+ if (globalSearch) {
+ super.startSearch(initialQuery, selectInitialQuery, appSearchData, globalSearch);
+ } else {
+ ContactsSearchManager.startSearch(this, initialQuery);
+ }
+ }
}
diff --git a/src/com/android/contacts/ui/EditContactActivity.java b/src/com/android/contacts/ui/EditContactActivity.java
index 89f9b12..92fdadb 100644
--- a/src/com/android/contacts/ui/EditContactActivity.java
+++ b/src/com/android/contacts/ui/EditContactActivity.java
@@ -16,6 +16,7 @@
package com.android.contacts.ui;
+import com.android.contacts.ContactsSearchManager;
import com.android.contacts.ContactsListActivity;
import com.android.contacts.ContactsUtils;
import com.android.contacts.R;
@@ -1305,4 +1306,14 @@
long twoId = twoValues.getAsLong(RawContacts._ID);
return (int)(oneId - twoId);
}
+
+ @Override
+ public void startSearch(String initialQuery, boolean selectInitialQuery, Bundle appSearchData,
+ boolean globalSearch) {
+ if (globalSearch) {
+ super.startSearch(initialQuery, selectInitialQuery, appSearchData, globalSearch);
+ } else {
+ ContactsSearchManager.startSearch(this, initialQuery);
+ }
+ }
}
diff --git a/src/com/android/contacts/ui/ShowOrCreateActivity.java b/src/com/android/contacts/ui/ShowOrCreateActivity.java
index 0828b3f..e0781d2 100755
--- a/src/com/android/contacts/ui/ShowOrCreateActivity.java
+++ b/src/com/android/contacts/ui/ShowOrCreateActivity.java
@@ -16,6 +16,7 @@
package com.android.contacts.ui;
+import com.android.contacts.ContactsSearchManager;
import com.android.contacts.ContactsListActivity;
import com.android.contacts.R;
import com.android.contacts.util.Constants;
@@ -246,4 +247,14 @@
mParent.finish();
}
}
+
+ @Override
+ public void startSearch(String initialQuery, boolean selectInitialQuery, Bundle appSearchData,
+ boolean globalSearch) {
+ if (globalSearch) {
+ super.startSearch(initialQuery, selectInitialQuery, appSearchData, globalSearch);
+ } else {
+ ContactsSearchManager.startSearch(this, initialQuery);
+ }
+ }
}