summaryrefslogtreecommitdiffstats
path: root/src/com/android/launcher/Search.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/launcher/Search.java')
-rw-r--r--src/com/android/launcher/Search.java668
1 files changed, 0 insertions, 668 deletions
diff --git a/src/com/android/launcher/Search.java b/src/com/android/launcher/Search.java
deleted file mode 100644
index d33fd69fa..000000000
--- a/src/com/android/launcher/Search.java
+++ /dev/null
@@ -1,668 +0,0 @@
-/*
- * Copyright (C) 2008 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.launcher;
-
-import android.app.ISearchManager;
-import android.app.SearchManager;
-import android.content.ActivityNotFoundException;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
-import android.content.res.Resources;
-import android.content.res.Resources.NotFoundException;
-import android.database.Cursor;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.server.search.SearchableInfo;
-import android.text.Editable;
-import android.text.TextUtils;
-import android.text.TextWatcher;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.View.OnClickListener;
-import android.view.View.OnKeyListener;
-import android.view.View.OnLongClickListener;
-import android.widget.AdapterView;
-import android.widget.AutoCompleteTextView;
-import android.widget.CursorAdapter;
-import android.widget.Filter;
-import android.widget.ImageButton;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.SimpleCursorAdapter;
-import android.widget.TextView;
-import android.widget.AdapterView.OnItemClickListener;
-import android.widget.AdapterView.OnItemSelectedListener;
-
-import java.util.List;
-
-public class Search extends LinearLayout implements OnClickListener, OnKeyListener,
- OnLongClickListener, TextWatcher, OnItemClickListener, OnItemSelectedListener {
-
- private final String TAG = "SearchGadget";
-
- private AutoCompleteTextView mSearchText;
- private ImageButton mGoButton;
- private ImageButton mVoiceButton;
- private OnLongClickListener mLongClickListener;
-
- // Support for suggestions
- private SuggestionsAdapter mSuggestionsAdapter;
- private SearchableInfo mSearchable;
- private String mSuggestionAction = null;
- private Uri mSuggestionData = null;
- private String mSuggestionQuery = null;
- private int mItemSelected = -1;
-
- // For voice searching
- private Intent mVoiceSearchIntent;
-
- private Rect mTempRect = new Rect();
-
- /**
- * Used to inflate the Workspace from XML.
- *
- * @param context The application's context.
- * @param attrs The attributes set containing the Workspace's customization values.
- */
- public Search(Context context, AttributeSet attrs) {
- super(context, attrs);
-
- mVoiceSearchIntent = new Intent(android.speech.RecognizerIntent.ACTION_WEB_SEARCH);
- mVoiceSearchIntent.putExtra(android.speech.RecognizerIntent.EXTRA_LANGUAGE_MODEL,
- android.speech.RecognizerIntent.LANGUAGE_MODEL_WEB_SEARCH);
- }
-
- /**
- * Implements OnClickListener (for button)
- */
- public void onClick(View v) {
- if (v == mGoButton) {
- query();
- } else if (v == mVoiceButton) {
- try {
- getContext().startActivity(mVoiceSearchIntent);
- } catch (ActivityNotFoundException ex) {
- // Should not happen, since we check the availability of
- // voice search before showing the button. But just in case...
- Log.w(TAG, "Could not find voice search activity");
- }
- }
- }
-
- private void query() {
- String query = mSearchText.getText().toString();
- if (TextUtils.getTrimmedLength(mSearchText.getText()) == 0) {
- return;
- }
- Bundle appData = new Bundle();
- appData.putString(SearchManager.SOURCE, "launcher-widget");
- sendLaunchIntent(Intent.ACTION_SEARCH, null, query, appData, 0, null, mSearchable);
- clearQuery();
- }
-
- /**
- * Assemble a search intent and send it.
- *
- * This is copied from SearchDialog.
- *
- * @param action The intent to send, typically Intent.ACTION_SEARCH
- * @param data The data for the intent
- * @param query The user text entered (so far)
- * @param appData The app data bundle (if supplied)
- * @param actionKey If the intent was triggered by an action key, e.g. KEYCODE_CALL, it will
- * be sent here. Pass KeyEvent.KEYCODE_UNKNOWN for no actionKey code.
- * @param actionMsg If the intent was triggered by an action key, e.g. KEYCODE_CALL, the
- * corresponding tag message will be sent here. Pass null for no actionKey message.
- * @param si Reference to the current SearchableInfo. Passed here so it can be used even after
- * we've called dismiss(), which attempts to null mSearchable.
- */
- private void sendLaunchIntent(final String action, final Uri data, final String query,
- final Bundle appData, int actionKey, final String actionMsg, final SearchableInfo si) {
- Intent launcher = new Intent(action);
- launcher.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-
- if (query != null) {
- launcher.putExtra(SearchManager.QUERY, query);
- }
-
- if (data != null) {
- launcher.setData(data);
- }
-
- if (appData != null) {
- launcher.putExtra(SearchManager.APP_DATA, appData);
- }
-
- // add launch info (action key, etc.)
- if (actionKey != KeyEvent.KEYCODE_UNKNOWN) {
- launcher.putExtra(SearchManager.ACTION_KEY, actionKey);
- launcher.putExtra(SearchManager.ACTION_MSG, actionMsg);
- }
-
- // attempt to enforce security requirement (no 3rd-party intents)
- if (si != null) {
- launcher.setComponent(si.mSearchActivity);
- }
-
- getContext().startActivity(launcher);
- }
-
- /**
- * Implements TextWatcher (for EditText)
- */
- public void beforeTextChanged(CharSequence s, int start, int before, int after) {
- }
-
- /**
- * Implements TextWatcher (for EditText)
- */
- public void onTextChanged(CharSequence s, int start, int before, int after) {
- // enable the button if we have one or more non-space characters
- boolean enabled = TextUtils.getTrimmedLength(mSearchText.getText()) != 0;
- mGoButton.setEnabled(enabled);
- mGoButton.setFocusable(enabled);
- }
-
- /**
- * Implements TextWatcher (for EditText)
- */
- public void afterTextChanged(Editable s) {
- }
-
- /**
- * Implements OnKeyListener (for EditText and for button)
- *
- * This plays some games with state in order to "soften" the strength of suggestions
- * presented. Suggestions should not be used unless the user specifically navigates to them
- * (or clicks them, in which case it's obvious). This is not the way that AutoCompleteTextBox
- * normally works.
- */
- public final boolean onKey(View v, int keyCode, KeyEvent event) {
- if (v == mSearchText) {
- boolean searchTrigger = (keyCode == KeyEvent.KEYCODE_ENTER ||
- keyCode == KeyEvent.KEYCODE_SEARCH ||
- keyCode == KeyEvent.KEYCODE_DPAD_CENTER);
- if (event.getAction() == KeyEvent.ACTION_UP) {
-// Log.d(TAG, "onKey() ACTION_UP isPopupShowing:" + mSearchText.isPopupShowing());
- if (!mSearchText.isPopupShowing()) {
- if (searchTrigger) {
- query();
- return true;
- }
- }
- } else {
-// Log.d(TAG, "onKey() ACTION_DOWN isPopupShowing:" + mSearchText.isPopupShowing() +
-// " mItemSelected="+ mItemSelected);
- if (searchTrigger && mItemSelected < 0) {
- query();
- return true;
- }
- }
- } else if (v == mGoButton || v == mVoiceButton) {
- boolean handled = false;
- if (!event.isSystem() &&
- (keyCode != KeyEvent.KEYCODE_DPAD_UP) &&
- (keyCode != KeyEvent.KEYCODE_DPAD_DOWN) &&
- (keyCode != KeyEvent.KEYCODE_DPAD_LEFT) &&
- (keyCode != KeyEvent.KEYCODE_DPAD_RIGHT) &&
- (keyCode != KeyEvent.KEYCODE_DPAD_CENTER)) {
- if (mSearchText.requestFocus()) {
- handled = mSearchText.dispatchKeyEvent(event);
- }
- }
- return handled;
- }
-
- return false;
- }
-
- @Override
- public void setOnLongClickListener(OnLongClickListener l) {
- super.setOnLongClickListener(l);
- mLongClickListener = l;
- }
-
- /**
- * Implements OnLongClickListener (for button)
- */
- public boolean onLongClick(View v) {
- // Pretend that a long press on a child view is a long press on the search widget
- if (mLongClickListener != null) {
- return mLongClickListener.onLongClick(this);
- }
- return false;
- }
-
- @Override
- public boolean onInterceptTouchEvent(MotionEvent ev) {
- // Request focus unless the user tapped on the voice search button
- final int x = (int) ev.getX();
- final int y = (int) ev.getY();
- final Rect frame = mTempRect;
- mVoiceButton.getHitRect(frame);
- if (!frame.contains(x, y)) {
- requestFocusFromTouch();
- }
- return super.onInterceptTouchEvent(ev);
- }
-
- /**
- * In order to keep things simple, the external trigger will clear the query just before
- * focusing, so as to give you a fresh query. This way we eliminate any sources of
- * accidental query launching.
- */
- public void clearQuery() {
- mSearchText.setText(null);
- }
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
-
- mSearchText = (AutoCompleteTextView) findViewById(R.id.input);
- // TODO: This can be confusing when the user taps the text field to give the focus
- // (it is not necessary but I ran into this issue several times myself)
- // mTitleInput.setOnClickListener(this);
- mSearchText.setOnKeyListener(this);
- mSearchText.addTextChangedListener(this);
-
- mGoButton = (ImageButton) findViewById(R.id.search_go_btn);
- mVoiceButton = (ImageButton) findViewById(R.id.search_voice_btn);
- mGoButton.setOnClickListener(this);
- mVoiceButton.setOnClickListener(this);
- mGoButton.setOnKeyListener(this);
- mVoiceButton.setOnKeyListener(this);
-
- mSearchText.setOnLongClickListener(this);
- mGoButton.setOnLongClickListener(this);
- mVoiceButton.setOnLongClickListener(this);
-
- // disable the button since we start out w/empty input
- mGoButton.setEnabled(false);
- mGoButton.setFocusable(false);
-
- configureSearchableInfo();
- configureSuggestions();
- configureVoiceSearchButton();
- }
-
- /**
- * Read the searchable info from the search manager
- */
- private void configureSearchableInfo() {
- ISearchManager sms;
- SearchableInfo searchable;
- sms = ISearchManager.Stub.asInterface(ServiceManager.getService(Context.SEARCH_SERVICE));
- try {
- // TODO null isn't the published use of this API, but it works when global=true
- // TODO better implementation: defer all of this, let Home set it up
- searchable = sms.getSearchableInfo(null, true);
- } catch (RemoteException e) {
- searchable = null;
- }
- if (searchable == null) {
- // no suggestions so just get out (no need to continue)
- return;
- }
- mSearchable = searchable;
- }
-
- /**
- * If appropriate & available, configure voice search
- *
- * Note: Because the home screen search widget is always web search, we only check for
- * getVoiceSearchLaunchWebSearch() modes. We don't support the alternate form of app-specific
- * voice search.
- */
- private void configureVoiceSearchButton() {
- boolean voiceSearchVisible = false;
- if (mSearchable.getVoiceSearchEnabled() && mSearchable.getVoiceSearchLaunchWebSearch()) {
- // Enable the voice search button if there is an activity that can handle it
- PackageManager pm = getContext().getPackageManager();
- ResolveInfo ri = pm.resolveActivity(mVoiceSearchIntent,
- PackageManager.MATCH_DEFAULT_ONLY);
- voiceSearchVisible = ri != null;
- }
-
- // finally, set visible state of voice search button, as appropriate
- mVoiceButton.setVisibility(voiceSearchVisible ? View.VISIBLE : View.GONE);
- }
-
- /** The rest of the class deals with providing search suggestions */
-
- /**
- * Set up the suggestions provider mechanism
- */
- private void configureSuggestions() {
- // get SearchableInfo
-
- mSearchText.setOnItemClickListener(this);
- mSearchText.setOnItemSelectedListener(this);
-
- // attach the suggestions adapter
- mSuggestionsAdapter = new SuggestionsAdapter(mContext,
- com.android.internal.R.layout.search_dropdown_item_2line, null,
- SuggestionsAdapter.TWO_LINE_FROM, SuggestionsAdapter.TWO_LINE_TO, mSearchable);
- mSearchText.setAdapter(mSuggestionsAdapter);
- }
-
- /**
- * Implements OnItemClickListener
- */
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
-// Log.d(TAG, "onItemClick() position " + position);
- launchSuggestion(mSuggestionsAdapter, position);
- }
-
- /**
- * Implements OnItemSelectedListener
- */
- public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
-// Log.d(TAG, "onItemSelected() position " + position);
- mItemSelected = position;
- }
-
- /**
- * Implements OnItemSelectedListener
- */
- public void onNothingSelected(AdapterView<?> parent) {
-// Log.d(TAG, "onNothingSelected()");
- mItemSelected = -1;
- }
-
- /**
- * Code to launch a suggestion query.
- *
- * This is copied from SearchDialog.
- *
- * @param ca The CursorAdapter containing the suggestions
- * @param position The suggestion we'll be launching from
- *
- * @return Returns true if a successful launch, false if could not (e.g. bad position)
- */
- private boolean launchSuggestion(CursorAdapter ca, int position) {
- if (ca != null) {
- Cursor c = ca.getCursor();
- if ((c != null) && c.moveToPosition(position)) {
- setupSuggestionIntent(c, mSearchable);
-
- SearchableInfo si = mSearchable;
- String suggestionAction = mSuggestionAction;
- Uri suggestionData = mSuggestionData;
- String suggestionQuery = mSuggestionQuery;
- sendLaunchIntent(suggestionAction, suggestionData, suggestionQuery, null,
- KeyEvent.KEYCODE_UNKNOWN, null, si);
- clearQuery();
- return true;
- }
- }
- return false;
- }
-
- /**
- * When a particular suggestion has been selected, perform the various lookups required
- * to use the suggestion. This includes checking the cursor for suggestion-specific data,
- * and/or falling back to the XML for defaults; It also creates REST style Uri data when
- * the suggestion includes a data id.
- *
- * NOTE: Return values are in member variables mSuggestionAction, mSuggestionData and
- * mSuggestionQuery.
- *
- * This is copied from SearchDialog.
- *
- * @param c The suggestions cursor, moved to the row of the user's selection
- * @param si The searchable activity's info record
- */
- void setupSuggestionIntent(Cursor c, SearchableInfo si) {
- try {
- // use specific action if supplied, or default action if supplied, or fixed default
- mSuggestionAction = null;
- int column = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_INTENT_ACTION);
- if (column >= 0) {
- final String action = c.getString(column);
- if (action != null) {
- mSuggestionAction = action;
- }
- }
- if (mSuggestionAction == null) {
- mSuggestionAction = si.getSuggestIntentAction();
- }
- if (mSuggestionAction == null) {
- mSuggestionAction = Intent.ACTION_SEARCH;
- }
-
- // use specific data if supplied, or default data if supplied
- String data = null;
- column = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_INTENT_DATA);
- if (column >= 0) {
- final String rowData = c.getString(column);
- if (rowData != null) {
- data = rowData;
- }
- }
- if (data == null) {
- data = si.getSuggestIntentData();
- }
-
- // then, if an ID was provided, append it.
- if (data != null) {
- column = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID);
- if (column >= 0) {
- final String id = c.getString(column);
- if (id != null) {
- data = data + "/" + Uri.encode(id);
- }
- }
- }
- mSuggestionData = (data == null) ? null : Uri.parse(data);
-
- mSuggestionQuery = null;
- column = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_QUERY);
- if (column >= 0) {
- final String query = c.getString(column);
- if (query != null) {
- mSuggestionQuery = query;
- }
- }
- } catch (RuntimeException e ) {
- int rowNum;
- try { // be really paranoid now
- rowNum = c.getPosition();
- } catch (RuntimeException e2 ) {
- rowNum = -1;
- }
- Log.w(TAG, "Search Suggestions cursor at row " + rowNum +
- " returned exception" + e.toString());
- }
- }
-
- /**
- * This class provides the filtering-based interface to suggestions providers.
- * It is hardwired in a couple of places to support GoogleSearch - for example, it supports
- * two-line suggestions, but it does not support icons.
- */
- private static class SuggestionsAdapter extends SimpleCursorAdapter {
- public final static String[] TWO_LINE_FROM = {SearchManager.SUGGEST_COLUMN_TEXT_1,
- SearchManager.SUGGEST_COLUMN_TEXT_2 };
- public final static int[] TWO_LINE_TO = {com.android.internal.R.id.text1,
- com.android.internal.R.id.text2};
-
- private final String TAG = "SuggestionsAdapter";
-
- Filter mFilter;
- SearchableInfo mSearchable;
- private Resources mProviderResources;
- String[] mFromStrings;
-
- public SuggestionsAdapter(Context context, int layout, Cursor c,
- String[] from, int[] to, SearchableInfo searchable) {
- super(context, layout, c, from, to);
- mFromStrings = from;
- mSearchable = searchable;
-
- // set up provider resources (gives us icons, etc.)
- Context activityContext = mSearchable.getActivityContext(mContext);
- Context providerContext = mSearchable.getProviderContext(mContext, activityContext);
- mProviderResources = providerContext.getResources();
- }
-
- /**
- * Use the search suggestions provider to obtain a live cursor. This will be called
- * in a worker thread, so it's OK if the query is slow (e.g. round trip for suggestions).
- * The results will be processed in the UI thread and changeCursor() will be called.
- */
- @Override
- public Cursor runQueryOnBackgroundThread(CharSequence constraint) {
- String query = (constraint == null) ? "" : constraint.toString();
- return getSuggestions(mSearchable, query);
- }
-
- /**
- * Overriding this allows us to write the selected query back into the box.
- * NOTE: This is a vastly simplified version of SearchDialog.jamQuery() and does
- * not universally support the search API. But it is sufficient for Google Search.
- */
- @Override
- public CharSequence convertToString(Cursor cursor) {
- CharSequence result = null;
- if (cursor != null) {
- int column = cursor.getColumnIndex(SearchManager.SUGGEST_COLUMN_QUERY);
- if (column >= 0) {
- final String query = cursor.getString(column);
- if (query != null) {
- result = query;
- }
- }
- }
- return result;
- }
-
- /**
- * Get the query cursor for the search suggestions.
- *
- * TODO this is functionally identical to the version in SearchDialog.java. Perhaps it
- * could be hoisted into SearchableInfo or some other shared spot.
- *
- * @param query The search text entered (so far)
- * @return Returns a cursor with suggestions, or null if no suggestions
- */
- private Cursor getSuggestions(final SearchableInfo searchable, final String query) {
- Cursor cursor = null;
- if (searchable.getSuggestAuthority() != null) {
- try {
- StringBuilder uriStr = new StringBuilder("content://");
- uriStr.append(searchable.getSuggestAuthority());
-
- // if content path provided, insert it now
- final String contentPath = searchable.getSuggestPath();
- if (contentPath != null) {
- uriStr.append('/');
- uriStr.append(contentPath);
- }
-
- // append standard suggestion query path
- uriStr.append('/' + SearchManager.SUGGEST_URI_PATH_QUERY);
-
- // inject query, either as selection args or inline
- String[] selArgs = null;
- if (searchable.getSuggestSelection() != null) { // use selection if provided
- selArgs = new String[] {query};
- } else {
- uriStr.append('/'); // no sel, use REST pattern
- uriStr.append(Uri.encode(query));
- }
-
- // finally, make the query
- cursor = mContext.getContentResolver().query(
- Uri.parse(uriStr.toString()), null,
- searchable.getSuggestSelection(), selArgs,
- null);
- } catch (RuntimeException e) {
- Log.w(TAG, "Search Suggestions query returned exception " + e.toString());
- cursor = null;
- }
- }
-
- return cursor;
- }
-
- /**
- * Overriding this allows us to affect the way that an icon is loaded. Specifically,
- * we can be more controlling about the resource path (and allow icons to come from other
- * packages).
- *
- * TODO: This is 100% identical to the version in SearchDialog.java
- *
- * @param v ImageView to receive an image
- * @param value the value retrieved from the cursor
- */
- @Override
- public void setViewImage(ImageView v, String value) {
- int resID;
- Drawable img = null;
-
- try {
- resID = Integer.parseInt(value);
- if (resID != 0) {
- img = mProviderResources.getDrawable(resID);
- }
- } catch (NumberFormatException nfe) {
- // img = null;
- } catch (NotFoundException e2) {
- // img = null;
- }
-
- // finally, set the image to whatever we've gotten
- v.setImageDrawable(img);
- }
-
- /**
- * This method is overridden purely to provide a bit of protection against
- * flaky content providers.
- *
- * TODO: This is 100% identical to the version in SearchDialog.java
- *
- * @see android.widget.ListAdapter#getView(int, View, ViewGroup)
- */
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- try {
- return super.getView(position, convertView, parent);
- } catch (RuntimeException e) {
- Log.w(TAG, "Search Suggestions cursor returned exception " + e.toString());
- // what can I return here?
- View v = newView(mContext, mCursor, parent);
- if (v != null) {
- TextView tv = (TextView) v.findViewById(com.android.internal.R.id.text1);
- tv.setText(e.toString());
- }
- return v;
- }
- }
-
- }
-}