SearchDialog.java revision 29d52e120f36b46d7ef596b1c182db52d3476be7
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* 29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project 39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License. 69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at 79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and 149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License. 159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.app; 189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 19875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaenimport static android.app.SuggestionsAdapter.getColumnString; 20c1f40960644b461b108480b6446c89963441492dBjorn Bringert 219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.ActivityNotFoundException; 229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.ComponentName; 23d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaenimport android.content.ContentResolver; 24d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaenimport android.content.ContentValues; 25444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringertimport android.content.Context; 26444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringertimport android.content.Intent; 27875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaenimport android.content.pm.ActivityInfo; 289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.pm.PackageManager; 2998e333f551a4bf2ebb50bb97a2a56b14bfdcd74bKarl Rosaenimport android.content.pm.ResolveInfo; 30c1f40960644b461b108480b6446c89963441492dBjorn Bringertimport android.content.pm.PackageManager.NameNotFoundException; 319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.res.Resources; 329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.database.Cursor; 33444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringertimport android.graphics.drawable.Drawable; 349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.net.Uri; 359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Bundle; 364899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringertimport android.os.IBinder; 374899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringertimport android.os.RemoteException; 389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.SystemClock; 394899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringertimport android.provider.Browser; 409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.server.search.SearchableInfo; 419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.speech.RecognizerIntent; 429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.Editable; 439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.InputType; 449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.TextUtils; 459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.TextWatcher; 46662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampathimport android.text.util.Regex; 474899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringertimport android.util.AndroidRuntimeException; 489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.AttributeSet; 499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log; 50a97f4a117415fd877bc63d6c90a6775ca04eb3feMike LeBeauimport android.view.ContextThemeWrapper; 519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.Gravity; 529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.KeyEvent; 53875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaenimport android.view.MotionEvent; 549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.View; 55875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaenimport android.view.ViewConfiguration; 569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.ViewGroup; 579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.Window; 589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.WindowManager; 59662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampathimport android.view.inputmethod.EditorInfo; 60a8f556ee8cee24674663fd73c7a5b5a919b2d5bbDianne Hackbornimport android.view.inputmethod.InputMethodManager; 619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.widget.AdapterView; 629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.widget.AutoCompleteTextView; 639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.widget.Button; 649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.widget.ImageButton; 651fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeauimport android.widget.ImageView; 66077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringertimport android.widget.LinearLayout; 679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.widget.ListView; 689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.widget.TextView; 69c1f40960644b461b108480b6446c89963441492dBjorn Bringertimport android.widget.AdapterView.OnItemClickListener; 70c1f40960644b461b108480b6446c89963441492dBjorn Bringertimport android.widget.AdapterView.OnItemSelectedListener; 719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 72875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaenimport java.util.ArrayList; 73875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaenimport java.util.WeakHashMap; 749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.concurrent.atomic.AtomicLong; 759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 778d17f3f24bbda9a9cd7ea08c5925508dc2c011beBjorn Bringert * System search dialog. This is controlled by the 788d17f3f24bbda9a9cd7ea08c5925508dc2c011beBjorn Bringert * SearchManagerService and runs in the system process. 799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @hide 819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class SearchDialog extends Dialog implements OnItemClickListener, OnItemSelectedListener { 839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Debugging support 85875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen private static final boolean DBG = false; 86875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen private static final String LOG_TAG = "SearchDialog"; 87875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen private static final boolean DBG_LOG_TIMING = false; 889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String INSTANCE_KEY_COMPONENT = "comp"; 909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String INSTANCE_KEY_APPDATA = "data"; 919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String INSTANCE_KEY_GLOBALSEARCH = "glob"; 92b0ae27f4e10a9e5fe56b9ca549718051fe342bbaBjorn Bringert private static final String INSTANCE_KEY_STORED_COMPONENT = "sComp"; 93b0ae27f4e10a9e5fe56b9ca549718051fe342bbaBjorn Bringert private static final String INSTANCE_KEY_STORED_APPDATA = "sData"; 94b0ae27f4e10a9e5fe56b9ca549718051fe342bbaBjorn Bringert private static final String INSTANCE_KEY_PREVIOUS_COMPONENTS = "sPrev"; 95b0ae27f4e10a9e5fe56b9ca549718051fe342bbaBjorn Bringert private static final String INSTANCE_KEY_USER_QUERY = "uQry"; 96260dfb5716eab1dfe9dcb93b3e658cefaad197f9Mike LeBeau 97260dfb5716eab1dfe9dcb93b3e658cefaad197f9Mike LeBeau // The extra key used in an intent to the speech recognizer for in-app voice search. 98260dfb5716eab1dfe9dcb93b3e658cefaad197f9Mike LeBeau private static final String EXTRA_CALLING_PACKAGE = "calling_package"; 99b0ae27f4e10a9e5fe56b9ca549718051fe342bbaBjorn Bringert 1001fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau private static final int SEARCH_PLATE_LEFT_PADDING_GLOBAL = 12; 1011fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau private static final int SEARCH_PLATE_LEFT_PADDING_NON_GLOBAL = 7; 102444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringert 1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // views & widgets 1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private TextView mBadgeLabel; 1051fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau private ImageView mAppIcon; 106875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen private SearchAutoComplete mSearchAutoComplete; 1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Button mGoButton; 1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private ImageButton mVoiceButton; 109875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen private View mSearchPlate; 110f4f7046183f0daedd17703fa16cf9026442bdaeeRomain Guy private Drawable mWorkingSpinner; 1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // interaction with searchable application 113875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen private SearchableInfo mSearchable; 1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private ComponentName mLaunchComponent; 1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Bundle mAppSearchData; 1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private boolean mGlobalSearchMode; 1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Context mActivityContext; 1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 119b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau // Values we store to allow user to toggle between in-app search and global search. 120b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau private ComponentName mStoredComponentName; 121b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau private Bundle mStoredAppSearchData; 122b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau 123875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // stack of previous searchables, to support the BACK key after 124875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // SearchManager.INTENT_ACTION_CHANGE_SEARCH_SOURCE. 125875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // The top of the stack (= previous searchable) is the last element of the list, 126875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // since adding and removing is efficient at the end of an ArrayList. 127875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen private ArrayList<ComponentName> mPreviousComponents; 128875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // For voice searching 1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Intent mVoiceWebSearchIntent; 1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Intent mVoiceAppSearchIntent; 1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // support for AutoCompleteTextView suggestions display 1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private SuggestionsAdapter mSuggestionsAdapter; 135875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 136875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // Whether to rewrite queries when selecting suggestions 137cce7dbc31ed100b39c3e1174dd3d9a01de648e5bMike LeBeau private static final boolean REWRITE_QUERIES = true; 138875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 139875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // The query entered by the user. This is not changed when selecting a suggestion 140875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // that modifies the contents of the text field. But if the user then edits 141875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // the suggestion, the resulting string is saved. 142875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen private String mUserQuery; 143875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 144875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // A weak map of drawables we've gotten from other packages, so we don't load them 145875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // more than once. 146dfefa3e915938aa1eeeaa7c0910a882bded7bcf7Bjorn Bringert private final WeakHashMap<String, Drawable.ConstantState> mOutsideDrawablesCache = 147dfefa3e915938aa1eeeaa7c0910a882bded7bcf7Bjorn Bringert new WeakHashMap<String, Drawable.ConstantState>(); 148662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath 149662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath // Last known IME options value for the search edit text. 150662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath private int mSearchAutoCompleteImeOptions; 151662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath 1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Constructor - fires it up and makes it look like the search UI. 1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param context Application Context we can use for system acess 1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public SearchDialog(Context context) { 158a97f4a117415fd877bc63d6c90a6775ca04eb3feMike LeBeau super(context, com.android.internal.R.style.Theme_GlobalSearchBar); 1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * We create the search dialog just once, and it stays around (hidden) 1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * until activated by the user. 1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected void onCreate(Bundle savedInstanceState) { 1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super.onCreate(savedInstanceState); 1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setContentView(com.android.internal.R.layout.search_bar); 1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1718d17f3f24bbda9a9cd7ea08c5925508dc2c011beBjorn Bringert Window theWindow = getWindow(); 1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project WindowManager.LayoutParams lp = theWindow.getAttributes(); 1738d17f3f24bbda9a9cd7ea08c5925508dc2c011beBjorn Bringert lp.type = WindowManager.LayoutParams.TYPE_SEARCH_BAR; 1748d17f3f24bbda9a9cd7ea08c5925508dc2c011beBjorn Bringert lp.width = ViewGroup.LayoutParams.FILL_PARENT; 1758d17f3f24bbda9a9cd7ea08c5925508dc2c011beBjorn Bringert // taking up the whole window (even when transparent) is less than ideal, 1768d17f3f24bbda9a9cd7ea08c5925508dc2c011beBjorn Bringert // but necessary to show the popup window until the window manager supports 1778d17f3f24bbda9a9cd7ea08c5925508dc2c011beBjorn Bringert // having windows anchored by their parent but not clipped by them. 1788d17f3f24bbda9a9cd7ea08c5925508dc2c011beBjorn Bringert lp.height = ViewGroup.LayoutParams.FILL_PARENT; 1798d17f3f24bbda9a9cd7ea08c5925508dc2c011beBjorn Bringert lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL; 18098acd54fa6657e8131b3a2a957de7882a2f511abMike LeBeau lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; 1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project theWindow.setAttributes(lp); 1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // get the view elements for local access 184077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert SearchBar searchBar = (SearchBar) findViewById(com.android.internal.R.id.search_bar); 185077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert searchBar.setSearchDialog(this); 186077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert 1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mBadgeLabel = (TextView) findViewById(com.android.internal.R.id.search_badge); 188875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mSearchAutoComplete = (SearchAutoComplete) 1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project findViewById(com.android.internal.R.id.search_src_text); 1901fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau mAppIcon = (ImageView) findViewById(com.android.internal.R.id.search_app_icon); 1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mGoButton = (Button) findViewById(com.android.internal.R.id.search_go_btn); 1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mVoiceButton = (ImageButton) findViewById(com.android.internal.R.id.search_voice_btn); 193875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mSearchPlate = findViewById(com.android.internal.R.id.search_plate); 194f4f7046183f0daedd17703fa16cf9026442bdaeeRomain Guy mWorkingSpinner = getContext().getResources(). 1951480eb27f5321ef5fc2faeee87c7464e279a4912Mike LeBeau getDrawable(com.android.internal.R.drawable.search_spinner); 196dfcbc046d7fcd74c8aacd9f26bd48084900d3b4aBryan Mawhinney mSearchAutoComplete.setCompoundDrawablesWithIntrinsicBounds( 197dfcbc046d7fcd74c8aacd9f26bd48084900d3b4aBryan Mawhinney null, null, mWorkingSpinner, null); 198dfcbc046d7fcd74c8aacd9f26bd48084900d3b4aBryan Mawhinney setWorking(false); 199dfcbc046d7fcd74c8aacd9f26bd48084900d3b4aBryan Mawhinney 2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // attach listeners 201875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mSearchAutoComplete.addTextChangedListener(mTextWatcher); 202875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mSearchAutoComplete.setOnKeyListener(mTextKeyListener); 203875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mSearchAutoComplete.setOnItemClickListener(this); 204875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mSearchAutoComplete.setOnItemSelectedListener(this); 2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mGoButton.setOnClickListener(mGoButtonClickListener); 2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mGoButton.setOnKeyListener(mButtonsKeyListener); 2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mVoiceButton.setOnClickListener(mVoiceButtonClickListener); 2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mVoiceButton.setOnKeyListener(mButtonsKeyListener); 2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // pre-hide all the extraneous elements 2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mBadgeLabel.setVisibility(View.GONE); 2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Additional adjustments to make Dialog work for Search 2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Touching outside of the search dialog will dismiss it 2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project setCanceledOnTouchOutside(true); 217444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringert 2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Save voice intent for later queries/launching 2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mVoiceWebSearchIntent = new Intent(RecognizerIntent.ACTION_WEB_SEARCH); 2208d17f3f24bbda9a9cd7ea08c5925508dc2c011beBjorn Bringert mVoiceWebSearchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mVoiceWebSearchIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, 2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project RecognizerIntent.LANGUAGE_MODEL_WEB_SEARCH); 2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mVoiceAppSearchIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); 2258d17f3f24bbda9a9cd7ea08c5925508dc2c011beBjorn Bringert mVoiceAppSearchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 226662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath 227662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath mSearchAutoCompleteImeOptions = mSearchAutoComplete.getImeOptions(); 2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Set up the search dialog 2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 233875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * @return true if search dialog launched, false if not 2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean show(String initialQuery, boolean selectInitialQuery, 2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ComponentName componentName, Bundle appSearchData, boolean globalSearch) { 2378d17f3f24bbda9a9cd7ea08c5925508dc2c011beBjorn Bringert 238b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau // Reset any stored values from last time dialog was shown. 239b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau mStoredComponentName = null; 240b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau mStoredAppSearchData = null; 241fef8d3e4d8f6f46c098d04b3a57409c947ec1c75Satish Sampath 242fef8d3e4d8f6f46c098d04b3a57409c947ec1c75Satish Sampath boolean success = doShow(initialQuery, selectInitialQuery, componentName, appSearchData, 243fef8d3e4d8f6f46c098d04b3a57409c947ec1c75Satish Sampath globalSearch); 244fef8d3e4d8f6f46c098d04b3a57409c947ec1c75Satish Sampath if (success) { 245fef8d3e4d8f6f46c098d04b3a57409c947ec1c75Satish Sampath // Display the drop down as soon as possible instead of waiting for the rest of the 246fef8d3e4d8f6f46c098d04b3a57409c947ec1c75Satish Sampath // pending UI stuff to get done, so that things appear faster to the user. 247fef8d3e4d8f6f46c098d04b3a57409c947ec1c75Satish Sampath mSearchAutoComplete.showDropDownAfterLayout(); 248fef8d3e4d8f6f46c098d04b3a57409c947ec1c75Satish Sampath } 249fef8d3e4d8f6f46c098d04b3a57409c947ec1c75Satish Sampath return success; 250b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau } 251da1f4b669ead7813079643b43301f100127aaeedBjorn Bringert 252da1f4b669ead7813079643b43301f100127aaeedBjorn Bringert private boolean isInRealAppSearch() { 253da1f4b669ead7813079643b43301f100127aaeedBjorn Bringert return !mGlobalSearchMode 254da1f4b669ead7813079643b43301f100127aaeedBjorn Bringert && (mPreviousComponents == null || mPreviousComponents.isEmpty()); 255da1f4b669ead7813079643b43301f100127aaeedBjorn Bringert } 256da1f4b669ead7813079643b43301f100127aaeedBjorn Bringert 257b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau /** 258b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau * Called in response to a press of the hard search button in 259b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau * {@link #onKeyDown(int, KeyEvent)}, this method toggles between in-app 260b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau * search and global search when relevant. 261b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau * 262b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau * If pressed within an in-app search context, this switches the search dialog out to 263b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau * global search. If pressed within a global search context that was originally an in-app 264b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau * search context, this switches back to the in-app search context. If pressed within a 265b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau * global search context that has no original in-app search context (e.g., global search 266b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau * from Home), this does nothing. 267b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau * 268b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau * @return false if we wanted to toggle context but could not do so successfully, true 269b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau * in all other cases 270b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau */ 271b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau private boolean toggleGlobalSearch() { 272b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau String currentSearchText = mSearchAutoComplete.getText().toString(); 273b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau if (!mGlobalSearchMode) { 274b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau mStoredComponentName = mLaunchComponent; 275b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau mStoredAppSearchData = mAppSearchData; 2765a7d752b65edc83abc1eeef462b8bf01038ebdffMike LeBeau 2775a7d752b65edc83abc1eeef462b8bf01038ebdffMike LeBeau // If this is the browser, we have a special case to not show the icon to the left 2785a7d752b65edc83abc1eeef462b8bf01038ebdffMike LeBeau // of the text field, for extra space for url entry (this should be reconciled in 2795a7d752b65edc83abc1eeef462b8bf01038ebdffMike LeBeau // Eclair). So special case a second tap of the search button to remove any 2805a7d752b65edc83abc1eeef462b8bf01038ebdffMike LeBeau // already-entered text so that we can be sure to show the "Quick Search Box" hint 2815a7d752b65edc83abc1eeef462b8bf01038ebdffMike LeBeau // text to still make it clear to the user that we've jumped out to global search. 2825a7d752b65edc83abc1eeef462b8bf01038ebdffMike LeBeau // 2835a7d752b65edc83abc1eeef462b8bf01038ebdffMike LeBeau // TODO: When the browser icon issue is reconciled in Eclair, remove this special case. 2845a7d752b65edc83abc1eeef462b8bf01038ebdffMike LeBeau if (isBrowserSearch()) currentSearchText = ""; 2855a7d752b65edc83abc1eeef462b8bf01038ebdffMike LeBeau 286b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau return doShow(currentSearchText, false, null, mAppSearchData, true); 287b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau } else { 288b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau if (mStoredComponentName != null) { 289b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau // This means we should toggle *back* to an in-app search context from 290b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau // global search. 291b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau return doShow(currentSearchText, false, mStoredComponentName, 292b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau mStoredAppSearchData, false); 293b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau } else { 294b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau return true; 295b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau } 296b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau } 297b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau } 298b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau 299b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau /** 300b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau * Does the rest of the work required to show the search dialog. Called by both 301b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau * {@link #show(String, boolean, ComponentName, Bundle, boolean)} and 302b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau * {@link #toggleGlobalSearch()}. 303b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau * 304b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau * @return true if search dialog showed, false if not 305b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau */ 306b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau private boolean doShow(String initialQuery, boolean selectInitialQuery, 307b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau ComponentName componentName, Bundle appSearchData, 308b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau boolean globalSearch) { 309875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // set up the searchable and show the dialog 310875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (!show(componentName, appSearchData, globalSearch)) { 311875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return false; 312875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 313b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau 314875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // finally, load the user's initial text (which may trigger suggestions) 315875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen setUserQuery(initialQuery); 316875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (selectInitialQuery) { 317875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mSearchAutoComplete.selectAll(); 318875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 319b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau 320875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return true; 321875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 322b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau 323875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen /** 324875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * Sets up the search dialog and shows it. 325875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * 326875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * @return <code>true</code> if search dialog launched 327875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen */ 328875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen private boolean show(ComponentName componentName, Bundle appSearchData, 329875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen boolean globalSearch) { 330875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 331875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (DBG) { 332875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen Log.d(LOG_TAG, "show(" + componentName + ", " 333875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen + appSearchData + ", " + globalSearch + ")"); 3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 335875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 3368d1538237847baf381787b881141f8c0478bef5bBjorn Bringert SearchManager searchManager = (SearchManager) 3378d1538237847baf381787b881141f8c0478bef5bBjorn Bringert mContext.getSystemService(Context.SEARCH_SERVICE); 338a59d7b0f2f9af672d48041b29e147fdce1218c08Mike LeBeau // Try to get the searchable info for the provided component (or for global search, 339a59d7b0f2f9af672d48041b29e147fdce1218c08Mike LeBeau // if globalSearch == true). 3408d1538237847baf381787b881141f8c0478bef5bBjorn Bringert mSearchable = searchManager.getSearchableInfo(componentName, globalSearch); 341a59d7b0f2f9af672d48041b29e147fdce1218c08Mike LeBeau 342a59d7b0f2f9af672d48041b29e147fdce1218c08Mike LeBeau // If we got back nothing, and it wasn't a request for global search, then try again 343a59d7b0f2f9af672d48041b29e147fdce1218c08Mike LeBeau // for global search, as we'll try to launch that in lieu of any component-specific search. 344a59d7b0f2f9af672d48041b29e147fdce1218c08Mike LeBeau if (!globalSearch && mSearchable == null) { 345a59d7b0f2f9af672d48041b29e147fdce1218c08Mike LeBeau globalSearch = true; 3468d1538237847baf381787b881141f8c0478bef5bBjorn Bringert mSearchable = searchManager.getSearchableInfo(componentName, globalSearch); 3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 348ee716fa2b03666622a73f8cc54dae4afd091353dBjorn Bringert 349ee716fa2b03666622a73f8cc54dae4afd091353dBjorn Bringert // If there's not even a searchable info available for global search, then really give up. 350ee716fa2b03666622a73f8cc54dae4afd091353dBjorn Bringert if (mSearchable == null) { 351ee716fa2b03666622a73f8cc54dae4afd091353dBjorn Bringert Log.w(LOG_TAG, "No global search provider."); 352ee716fa2b03666622a73f8cc54dae4afd091353dBjorn Bringert return false; 353ee716fa2b03666622a73f8cc54dae4afd091353dBjorn Bringert } 354ee716fa2b03666622a73f8cc54dae4afd091353dBjorn Bringert 3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLaunchComponent = componentName; 3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mAppSearchData = appSearchData; 357875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // Using globalSearch here is just an optimization, just calling 358875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // isDefaultSearchable() should always give the same result. 3598d1538237847baf381787b881141f8c0478bef5bBjorn Bringert mGlobalSearchMode = globalSearch || searchManager.isDefaultSearchable(mSearchable); 360875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mActivityContext = mSearchable.getActivityContext(getContext()); 3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 362875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // show the dialog. this will call onStart(). 3631fffbd97fa756ef7d3e7e885a5c1c8bb64380c20Mike LeBeau if (!isShowing()) { 364a97f4a117415fd877bc63d6c90a6775ca04eb3feMike LeBeau // The Dialog uses a ContextThemeWrapper for the context; use this to change the 365a97f4a117415fd877bc63d6c90a6775ca04eb3feMike LeBeau // theme out from underneath us, between the global search theme and the in-app 366a97f4a117415fd877bc63d6c90a6775ca04eb3feMike LeBeau // search theme. They are identical except that the global search theme does not 367a97f4a117415fd877bc63d6c90a6775ca04eb3feMike LeBeau // dim the background of the window (because global search is full screen so it's 368a97f4a117415fd877bc63d6c90a6775ca04eb3feMike LeBeau // not needed and this should save a little bit of time on global search invocation). 369a97f4a117415fd877bc63d6c90a6775ca04eb3feMike LeBeau Object context = getContext(); 370a97f4a117415fd877bc63d6c90a6775ca04eb3feMike LeBeau if (context instanceof ContextThemeWrapper) { 371a97f4a117415fd877bc63d6c90a6775ca04eb3feMike LeBeau ContextThemeWrapper wrapper = (ContextThemeWrapper) context; 372a97f4a117415fd877bc63d6c90a6775ca04eb3feMike LeBeau if (globalSearch) { 373a97f4a117415fd877bc63d6c90a6775ca04eb3feMike LeBeau wrapper.setTheme(com.android.internal.R.style.Theme_GlobalSearchBar); 374a97f4a117415fd877bc63d6c90a6775ca04eb3feMike LeBeau } else { 375a97f4a117415fd877bc63d6c90a6775ca04eb3feMike LeBeau wrapper.setTheme(com.android.internal.R.style.Theme_SearchBar); 376a97f4a117415fd877bc63d6c90a6775ca04eb3feMike LeBeau } 377a97f4a117415fd877bc63d6c90a6775ca04eb3feMike LeBeau } 378875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen show(); 3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 380875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen updateUI(); 3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The search dialog is being dismissed, so handle all of the local shutdown operations. 3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This function is designed to be idempotent so that dismiss() can be safely called at any time 3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * (even if already closed) and more likely to really dump any memory. No leaks! 3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onStop() { 3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super.onStop(); 394444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringert 395875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen closeSuggestionsAdapter(); 3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // dump extra memory we're hanging on to 3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLaunchComponent = null; 3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mAppSearchData = null; 4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSearchable = null; 4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mActivityContext = null; 4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mUserQuery = null; 403875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mPreviousComponents = null; 404875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 4051c6907515134c8a2e086d2eed4427f909d301935Mike LeBeau 4061c6907515134c8a2e086d2eed4427f909d301935Mike LeBeau /** 4071480eb27f5321ef5fc2faeee87c7464e279a4912Mike LeBeau * Sets the search dialog to the 'working' state, which shows a working spinner in the 4081480eb27f5321ef5fc2faeee87c7464e279a4912Mike LeBeau * right hand size of the text field. 4091480eb27f5321ef5fc2faeee87c7464e279a4912Mike LeBeau * 4101480eb27f5321ef5fc2faeee87c7464e279a4912Mike LeBeau * @param working true to show spinner, false to hide spinner 4111480eb27f5321ef5fc2faeee87c7464e279a4912Mike LeBeau */ 4121480eb27f5321ef5fc2faeee87c7464e279a4912Mike LeBeau public void setWorking(boolean working) { 413dfcbc046d7fcd74c8aacd9f26bd48084900d3b4aBryan Mawhinney mWorkingSpinner.setAlpha(working ? 255 : 0); 414dfcbc046d7fcd74c8aacd9f26bd48084900d3b4aBryan Mawhinney mWorkingSpinner.setVisible(working, false); 415dfcbc046d7fcd74c8aacd9f26bd48084900d3b4aBryan Mawhinney mWorkingSpinner.invalidateSelf(); 4161480eb27f5321ef5fc2faeee87c7464e279a4912Mike LeBeau } 4171480eb27f5321ef5fc2faeee87c7464e279a4912Mike LeBeau 4181480eb27f5321ef5fc2faeee87c7464e279a4912Mike LeBeau /** 419875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * Closes and gets rid of the suggestions adapter. 420875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen */ 421875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen private void closeSuggestionsAdapter() { 422875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // remove the adapter from the autocomplete first, to avoid any updates 423875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // when we drop the cursor 424875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mSearchAutoComplete.setAdapter((SuggestionsAdapter)null); 425875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // close any leftover cursor 426875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (mSuggestionsAdapter != null) { 427ba223760895e62ad2fcb85476984cb29018860c9Bjorn Bringert mSuggestionsAdapter.close(); 428875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 429875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mSuggestionsAdapter = null; 4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Save the minimal set of data necessary to recreate the search 4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 435444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringert * @return A bundle with the state of the dialog, or {@code null} if the search 436444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringert * dialog is not showing. 4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Bundle onSaveInstanceState() { 440444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringert if (!isShowing()) return null; 441444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringert 4429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Bundle bundle = new Bundle(); 443444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringert 4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // setup info so I can recreate this particular search 4459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bundle.putParcelable(INSTANCE_KEY_COMPONENT, mLaunchComponent); 4469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bundle.putBundle(INSTANCE_KEY_APPDATA, mAppSearchData); 4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bundle.putBoolean(INSTANCE_KEY_GLOBALSEARCH, mGlobalSearchMode); 448b0ae27f4e10a9e5fe56b9ca549718051fe342bbaBjorn Bringert bundle.putParcelable(INSTANCE_KEY_STORED_COMPONENT, mStoredComponentName); 449b0ae27f4e10a9e5fe56b9ca549718051fe342bbaBjorn Bringert bundle.putBundle(INSTANCE_KEY_STORED_APPDATA, mStoredAppSearchData); 450b0ae27f4e10a9e5fe56b9ca549718051fe342bbaBjorn Bringert bundle.putParcelableArrayList(INSTANCE_KEY_PREVIOUS_COMPONENTS, mPreviousComponents); 451b0ae27f4e10a9e5fe56b9ca549718051fe342bbaBjorn Bringert bundle.putString(INSTANCE_KEY_USER_QUERY, mUserQuery); 452b0ae27f4e10a9e5fe56b9ca549718051fe342bbaBjorn Bringert 4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return bundle; 4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Restore the state of the dialog from a previously saved bundle. 458875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * 459875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * TODO: go through this and make sure that it saves everything that is saved 4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param savedInstanceState The state of the dialog previously saved by 4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link #onSaveInstanceState()}. 4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onRestoreInstanceState(Bundle savedInstanceState) { 466444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringert if (savedInstanceState == null) return; 467444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringert 4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ComponentName launchComponent = savedInstanceState.getParcelable(INSTANCE_KEY_COMPONENT); 4699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Bundle appSearchData = savedInstanceState.getBundle(INSTANCE_KEY_APPDATA); 4709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean globalSearch = savedInstanceState.getBoolean(INSTANCE_KEY_GLOBALSEARCH); 471b0ae27f4e10a9e5fe56b9ca549718051fe342bbaBjorn Bringert ComponentName storedComponentName = 472b0ae27f4e10a9e5fe56b9ca549718051fe342bbaBjorn Bringert savedInstanceState.getParcelable(INSTANCE_KEY_STORED_COMPONENT); 473b0ae27f4e10a9e5fe56b9ca549718051fe342bbaBjorn Bringert Bundle storedAppSearchData = 474b0ae27f4e10a9e5fe56b9ca549718051fe342bbaBjorn Bringert savedInstanceState.getBundle(INSTANCE_KEY_STORED_APPDATA); 475b0ae27f4e10a9e5fe56b9ca549718051fe342bbaBjorn Bringert ArrayList<ComponentName> previousComponents = 476b0ae27f4e10a9e5fe56b9ca549718051fe342bbaBjorn Bringert savedInstanceState.getParcelableArrayList(INSTANCE_KEY_PREVIOUS_COMPONENTS); 477b0ae27f4e10a9e5fe56b9ca549718051fe342bbaBjorn Bringert String userQuery = savedInstanceState.getString(INSTANCE_KEY_USER_QUERY); 478b0ae27f4e10a9e5fe56b9ca549718051fe342bbaBjorn Bringert 479b0ae27f4e10a9e5fe56b9ca549718051fe342bbaBjorn Bringert // Set stored state 480b0ae27f4e10a9e5fe56b9ca549718051fe342bbaBjorn Bringert mStoredComponentName = storedComponentName; 481b0ae27f4e10a9e5fe56b9ca549718051fe342bbaBjorn Bringert mStoredAppSearchData = storedAppSearchData; 482b0ae27f4e10a9e5fe56b9ca549718051fe342bbaBjorn Bringert mPreviousComponents = previousComponents; 483b0ae27f4e10a9e5fe56b9ca549718051fe342bbaBjorn Bringert 484b0ae27f4e10a9e5fe56b9ca549718051fe342bbaBjorn Bringert // show the dialog. 485b0ae27f4e10a9e5fe56b9ca549718051fe342bbaBjorn Bringert if (!doShow(userQuery, false, launchComponent, appSearchData, globalSearch)) { 4869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // for some reason, we couldn't re-instantiate 4879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 4889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 492875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * Called after resources have changed, e.g. after screen rotation or locale change. 4939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 494444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringert public void onConfigurationChanged() { 4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (isShowing()) { 4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Redraw (resources may have changed) 4979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project updateSearchButton(); 4981fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau updateSearchAppIcon(); 4999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project updateSearchBadge(); 5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project updateQueryHint(); 50129d52e120f36b46d7ef596b1c182db52d3476be7Bryan Mawhinney mSearchAutoComplete.showDropDownAfterLayout(); 5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 504875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 506875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * Update the UI according to the info in the current value of {@link #mSearchable}. 5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 508875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen private void updateUI() { 5099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mSearchable != null) { 510ea52d29bc46c306f3607d121aa1ad84f0e9eb473Karl Rosaen mDecor.setVisibility(View.VISIBLE); 511875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen updateSearchAutoComplete(); 5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project updateSearchButton(); 5131fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau updateSearchAppIcon(); 5149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project updateSearchBadge(); 5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project updateQueryHint(); 5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project updateVoiceButton(); 5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // In order to properly configure the input method (if one is being used), we 5199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // need to let it know if we'll be providing suggestions. Although it would be 5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // difficult/expensive to know if every last detail has been configured properly, we 5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // can at least see if a suggestions provider has been configured, and use that 5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // as our trigger. 5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int inputType = mSearchable.getInputType(); 5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // We only touch this if the input type is set up for text (which it almost certainly 5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // should be, in the case of search!) 5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if ((inputType & InputType.TYPE_MASK_CLASS) == InputType.TYPE_CLASS_TEXT) { 5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // The existence of a suggestions authority is the proxy for "suggestions 5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // are available here" 5299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project inputType &= ~InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE; 5309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mSearchable.getSuggestAuthority() != null) { 5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project inputType |= InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE; 5329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 534875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mSearchAutoComplete.setInputType(inputType); 535662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath mSearchAutoCompleteImeOptions = mSearchable.getImeOptions(); 536662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath mSearchAutoComplete.setImeOptions(mSearchAutoCompleteImeOptions); 5379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 539875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 5409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 541875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * Updates the auto-complete text view. 5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 543875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen private void updateSearchAutoComplete() { 544875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // close any existing suggestions adapter 545875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen closeSuggestionsAdapter(); 546875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 547875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mSearchAutoComplete.setDropDownAnimationStyle(0); // no animation 548203464af9638e4d5aecd811452af67fff9aa3087Bjorn Bringert mSearchAutoComplete.setThreshold(mSearchable.getSuggestThreshold()); 5498d17f3f24bbda9a9cd7ea08c5925508dc2c011beBjorn Bringert // we dismiss the entire dialog instead 5508d17f3f24bbda9a9cd7ea08c5925508dc2c011beBjorn Bringert mSearchAutoComplete.setDropDownDismissedOnCompletion(false); 551875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 552da1f4b669ead7813079643b43301f100127aaeedBjorn Bringert if (!isInRealAppSearch()) { 553875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mSearchAutoComplete.setDropDownAlwaysVisible(true); // fill space until results come in 554875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } else { 555875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mSearchAutoComplete.setDropDownAlwaysVisible(false); 556875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 557875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 558d4760d77e7e8ab66af0307dcae39e0a8e9d90a14Mike LeBeau mSearchAutoComplete.setForceIgnoreOutsideTouch(true); 559d4760d77e7e8ab66af0307dcae39e0a8e9d90a14Mike LeBeau 560875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // attach the suggestions adapter, if suggestions are available 561875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // The existence of a suggestions authority is the proxy for "suggestions available here" 562875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (mSearchable.getSuggestAuthority() != null) { 5631480eb27f5321ef5fc2faeee87c7464e279a4912Mike LeBeau mSuggestionsAdapter = new SuggestionsAdapter(getContext(), this, mSearchable, 5641480eb27f5321ef5fc2faeee87c7464e279a4912Mike LeBeau mOutsideDrawablesCache, mGlobalSearchMode); 565875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mSearchAutoComplete.setAdapter(mSuggestionsAdapter); 566875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 568875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 5699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 5709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Update the text in the search button. Note: This is deprecated functionality, for 5719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1.0 compatibility only. 5729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void updateSearchButton() { 5749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String textLabel = null; 5759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Drawable iconLabel = null; 5769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int textId = mSearchable.getSearchButtonText(); 5779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (textId != 0) { 5789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project textLabel = mActivityContext.getResources().getString(textId); 5799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 5809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project iconLabel = getContext().getResources(). 5819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project getDrawable(com.android.internal.R.drawable.ic_btn_search); 5829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 583875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mGoButton.setText(textLabel); 5849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mGoButton.setCompoundDrawablesWithIntrinsicBounds(iconLabel, null, null, null); 5859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5871fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau private void updateSearchAppIcon() { 5885a7d752b65edc83abc1eeef462b8bf01038ebdffMike LeBeau // In Donut, we special-case the case of the browser to hide the app icon as if it were 5895a7d752b65edc83abc1eeef462b8bf01038ebdffMike LeBeau // global search, for extra space for url entry. 5905a7d752b65edc83abc1eeef462b8bf01038ebdffMike LeBeau // 5915a7d752b65edc83abc1eeef462b8bf01038ebdffMike LeBeau // TODO: Remove this special case once the issue has been reconciled in Eclair. 5925a7d752b65edc83abc1eeef462b8bf01038ebdffMike LeBeau if (mGlobalSearchMode || isBrowserSearch()) { 5931fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau mAppIcon.setImageResource(0); 5941fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau mAppIcon.setVisibility(View.GONE); 5951fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau mSearchPlate.setPadding(SEARCH_PLATE_LEFT_PADDING_GLOBAL, 5961fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau mSearchPlate.getPaddingTop(), 5971fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau mSearchPlate.getPaddingRight(), 5981fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau mSearchPlate.getPaddingBottom()); 5991fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau } else { 6001fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau PackageManager pm = getContext().getPackageManager(); 601f4f7046183f0daedd17703fa16cf9026442bdaeeRomain Guy Drawable icon; 6021fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau try { 6031fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau ActivityInfo info = pm.getActivityInfo(mLaunchComponent, 0); 6041fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau icon = pm.getApplicationIcon(info.applicationInfo); 6051fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau if (DBG) Log.d(LOG_TAG, "Using app-specific icon"); 6061fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau } catch (NameNotFoundException e) { 6071fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau icon = pm.getDefaultActivityIcon(); 6081fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau Log.w(LOG_TAG, mLaunchComponent + " not found, using generic app icon"); 6091fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau } 6101fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau mAppIcon.setImageDrawable(icon); 6111fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau mAppIcon.setVisibility(View.VISIBLE); 6121fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau mSearchPlate.setPadding(SEARCH_PLATE_LEFT_PADDING_NON_GLOBAL, 6131fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau mSearchPlate.getPaddingTop(), 6141fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau mSearchPlate.getPaddingRight(), 6151fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau mSearchPlate.getPaddingBottom()); 6161fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau } 6171fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau } 6181fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau 6199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 620875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * Setup the search "Badge" if requested by mode flags. 6219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 6229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void updateSearchBadge() { 6239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // assume both hidden 6249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int visibility = View.GONE; 6259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Drawable icon = null; 626875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen CharSequence text = null; 6279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // optionally show one or the other. 629a92041306e4d73baa10fb711fb905b9590f06b26Bjorn Bringert if (mSearchable.useBadgeIcon()) { 6309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project icon = mActivityContext.getResources().getDrawable(mSearchable.getIconId()); 6319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project visibility = View.VISIBLE; 632875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (DBG) Log.d(LOG_TAG, "Using badge icon: " + mSearchable.getIconId()); 633a92041306e4d73baa10fb711fb905b9590f06b26Bjorn Bringert } else if (mSearchable.useBadgeLabel()) { 6349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project text = mActivityContext.getResources().getText(mSearchable.getLabelId()).toString(); 6359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project visibility = View.VISIBLE; 636875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (DBG) Log.d(LOG_TAG, "Using badge label: " + mSearchable.getLabelId()); 6379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mBadgeLabel.setCompoundDrawablesWithIntrinsicBounds(icon, null, null, null); 6409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mBadgeLabel.setText(text); 6419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mBadgeLabel.setVisibility(visibility); 6429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 6459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Update the hint in the query text field. 6469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 6479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void updateQueryHint() { 6489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (isShowing()) { 6499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String hint = null; 6509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mSearchable != null) { 6519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int hintId = mSearchable.getHintId(); 6529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (hintId != 0) { 6539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project hint = mActivityContext.getString(hintId); 6549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 656875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mSearchAutoComplete.setHint(hint); 6579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 6619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Update the visibility of the voice button. There are actually two voice search modes, 6629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * either of which will activate the button. 6639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 6649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void updateVoiceButton() { 6659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int visibility = View.GONE; 6669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mSearchable.getVoiceSearchEnabled()) { 6679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Intent testIntent = null; 6689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mSearchable.getVoiceSearchLaunchWebSearch()) { 6699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project testIntent = mVoiceWebSearchIntent; 6709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (mSearchable.getVoiceSearchLaunchRecognizer()) { 6719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project testIntent = mVoiceAppSearchIntent; 6729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (testIntent != null) { 6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ResolveInfo ri = getContext().getPackageManager(). 6759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project resolveActivity(testIntent, PackageManager.MATCH_DEFAULT_ONLY); 6769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (ri != null) { 6779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project visibility = View.VISIBLE; 6789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mVoiceButton.setVisibility(visibility); 6829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6835a7d752b65edc83abc1eeef462b8bf01038ebdffMike LeBeau 6845a7d752b65edc83abc1eeef462b8bf01038ebdffMike LeBeau /** 6855a7d752b65edc83abc1eeef462b8bf01038ebdffMike LeBeau * Hack to determine whether this is the browser, so we can remove the browser icon 6865a7d752b65edc83abc1eeef462b8bf01038ebdffMike LeBeau * to the left of the search field, as a special requirement for Donut. 6875a7d752b65edc83abc1eeef462b8bf01038ebdffMike LeBeau * 6885a7d752b65edc83abc1eeef462b8bf01038ebdffMike LeBeau * TODO: For Eclair, reconcile this with the rest of the global search UI. 6895a7d752b65edc83abc1eeef462b8bf01038ebdffMike LeBeau */ 6905a7d752b65edc83abc1eeef462b8bf01038ebdffMike LeBeau private boolean isBrowserSearch() { 6915a7d752b65edc83abc1eeef462b8bf01038ebdffMike LeBeau return mLaunchComponent.flattenToShortString().startsWith("com.android.browser/"); 6925a7d752b65edc83abc1eeef462b8bf01038ebdffMike LeBeau } 693f4acf39d99d105e1e4fc7c43fa54377bb2f262aeBjorn Bringert 6949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 6959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Listeners of various types 6969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 6979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 699875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * {@link Dialog#onTouchEvent(MotionEvent)} will cancel the dialog only when the 700875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * touch is outside the window. But the window includes space for the drop-down, 701875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * so we also cancel on taps outside the search bar when the drop-down is not showing. 702875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen */ 703875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen @Override 704875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen public boolean onTouchEvent(MotionEvent event) { 705875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // cancel if the drop-down is not showing and the touch event was outside the search plate 706875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (!mSearchAutoComplete.isPopupShowing() && isOutOfBounds(mSearchPlate, event)) { 707875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (DBG) Log.d(LOG_TAG, "Pop-up not showing and outside of search plate."); 708875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen cancel(); 709875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return true; 710875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 711875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // Let Dialog handle events outside the window while the pop-up is showing. 712875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return super.onTouchEvent(event); 713875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 714875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 715875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen private boolean isOutOfBounds(View v, MotionEvent event) { 716875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen final int x = (int) event.getX(); 717875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen final int y = (int) event.getY(); 718875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen final int slop = ViewConfiguration.get(mContext).getScaledWindowTouchSlop(); 719875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return (x < -slop) || (y < -slop) 720875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen || (x > (v.getWidth()+slop)) 721875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen || (y > (v.getHeight()+slop)); 722875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 723875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 724875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen /** 7259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Dialog's OnKeyListener implements various search-specific functionality 7269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 7279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param keyCode This is the keycode of the typed key, and is the same value as 728875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * found in the KeyEvent parameter. 7299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param event The complete event record for the typed key 7309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 7319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return Return true if the event was handled here, or false if not. 7329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 7339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 7349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean onKeyDown(int keyCode, KeyEvent event) { 735875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (DBG) Log.d(LOG_TAG, "onKeyDown(" + keyCode + "," + event + ")"); 736ee716fa2b03666622a73f8cc54dae4afd091353dBjorn Bringert if (mSearchable == null) { 737ee716fa2b03666622a73f8cc54dae4afd091353dBjorn Bringert return false; 738ee716fa2b03666622a73f8cc54dae4afd091353dBjorn Bringert } 739ee716fa2b03666622a73f8cc54dae4afd091353dBjorn Bringert 7403c5767d8fea785ec8d4ad6de96032cdfe752f5daBryan Mawhinney if (keyCode == KeyEvent.KEYCODE_SEARCH && event.getRepeatCount() == 0) { 7413c5767d8fea785ec8d4ad6de96032cdfe752f5daBryan Mawhinney event.startTracking(); 74283fe3f559249451706957b1a5f660b2b8272f114Dianne Hackborn // Consume search key for later use. 74383fe3f559249451706957b1a5f660b2b8272f114Dianne Hackborn return true; 7449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 745875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 746875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // if it's an action specified by the searchable activity, launch the 747875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // entered query with the action key 748875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen SearchableInfo.ActionKeyInfo actionKey = mSearchable.findActionKey(keyCode); 749a92041306e4d73baa10fb711fb905b9590f06b26Bjorn Bringert if ((actionKey != null) && (actionKey.getQueryActionMsg() != null)) { 750a92041306e4d73baa10fb711fb905b9590f06b26Bjorn Bringert launchQuerySearch(keyCode, actionKey.getQueryActionMsg()); 751875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return true; 752875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 75387d61f22e13e81550559c92f6cf6fb795a39d37fBjorn Bringert 75487d61f22e13e81550559c92f6cf6fb795a39d37fBjorn Bringert return super.onKeyDown(keyCode, event); 7559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 756875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 75783fe3f559249451706957b1a5f660b2b8272f114Dianne Hackborn @Override 75883fe3f559249451706957b1a5f660b2b8272f114Dianne Hackborn public boolean onKeyUp(int keyCode, KeyEvent event) { 75983fe3f559249451706957b1a5f660b2b8272f114Dianne Hackborn if (DBG) Log.d(LOG_TAG, "onKeyUp(" + keyCode + "," + event + ")"); 76083fe3f559249451706957b1a5f660b2b8272f114Dianne Hackborn if (mSearchable == null) { 76183fe3f559249451706957b1a5f660b2b8272f114Dianne Hackborn return false; 76283fe3f559249451706957b1a5f660b2b8272f114Dianne Hackborn } 76383fe3f559249451706957b1a5f660b2b8272f114Dianne Hackborn 76483fe3f559249451706957b1a5f660b2b8272f114Dianne Hackborn if (keyCode == KeyEvent.KEYCODE_SEARCH && event.isTracking() 76583fe3f559249451706957b1a5f660b2b8272f114Dianne Hackborn && !event.isCanceled()) { 76683fe3f559249451706957b1a5f660b2b8272f114Dianne Hackborn // If the search key is pressed, toggle between global and in-app search. If we are 76783fe3f559249451706957b1a5f660b2b8272f114Dianne Hackborn // currently doing global search and there is no in-app search context to toggle to, 76883fe3f559249451706957b1a5f660b2b8272f114Dianne Hackborn // just don't do anything. 76983fe3f559249451706957b1a5f660b2b8272f114Dianne Hackborn return toggleGlobalSearch(); 77083fe3f559249451706957b1a5f660b2b8272f114Dianne Hackborn } 77187d61f22e13e81550559c92f6cf6fb795a39d37fBjorn Bringert 77287d61f22e13e81550559c92f6cf6fb795a39d37fBjorn Bringert return super.onKeyUp(keyCode, event); 77383fe3f559249451706957b1a5f660b2b8272f114Dianne Hackborn } 77483fe3f559249451706957b1a5f660b2b8272f114Dianne Hackborn 7759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 7769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Callback to watch the textedit field for empty/non-empty 7779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 7789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private TextWatcher mTextWatcher = new TextWatcher() { 7799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 780875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen public void beforeTextChanged(CharSequence s, int start, int before, int after) { } 7819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onTextChanged(CharSequence s, int start, 7839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int before, int after) { 784875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (DBG_LOG_TIMING) { 7859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dbgLogTiming("onTextChanged()"); 7869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 787ee716fa2b03666622a73f8cc54dae4afd091353dBjorn Bringert if (mSearchable == null) { 788ee716fa2b03666622a73f8cc54dae4afd091353dBjorn Bringert return; 789ee716fa2b03666622a73f8cc54dae4afd091353dBjorn Bringert } 7909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project updateWidgetState(); 791875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (!mSearchAutoComplete.isPerformingCompletion()) { 792875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // The user changed the query, remember it. 793875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mUserQuery = s == null ? "" : s.toString(); 7949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 797662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath public void afterTextChanged(Editable s) { 798b06ea706530e6d19eb2a1a9a7ae6c5dd77d80af0Dianne Hackborn if (mSearchable == null) { 799b06ea706530e6d19eb2a1a9a7ae6c5dd77d80af0Dianne Hackborn return; 800b06ea706530e6d19eb2a1a9a7ae6c5dd77d80af0Dianne Hackborn } 801d21572cd446e56efe94689324107927ac2bffd2aSatish Sampath if (mSearchable.autoUrlDetect() && !mSearchAutoComplete.isPerformingCompletion()) { 802662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath // The user changed the query, check if it is a URL and if so change the search 803662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath // button in the soft keyboard to the 'Go' button. 804662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath int options = (mSearchAutoComplete.getImeOptions() & (~EditorInfo.IME_MASK_ACTION)); 805662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath if (Regex.WEB_URL_PATTERN.matcher(mUserQuery).matches()) { 806662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath options = options | EditorInfo.IME_ACTION_GO; 807662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath } else { 808662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath options = options | EditorInfo.IME_ACTION_SEARCH; 809662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath } 810662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath if (options != mSearchAutoCompleteImeOptions) { 811662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath mSearchAutoCompleteImeOptions = options; 812662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath mSearchAutoComplete.setImeOptions(options); 813662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath // This call is required to update the soft keyboard UI with latest IME flags. 814662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath mSearchAutoComplete.setInputType(mSearchAutoComplete.getInputType()); 815662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath } 816662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath } 817662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath } 8189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 8199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 8219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Enable/Disable the cancel button based on edit text state (any text?) 8229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 8239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void updateWidgetState() { 8249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // enable the button if we have one or more non-space characters 825875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen boolean enabled = !mSearchAutoComplete.isEmpty(); 8269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mGoButton.setEnabled(enabled); 8279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mGoButton.setFocusable(enabled); 8289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 8319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * React to typing in the GO search button by refocusing to EditText. 8329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Continue typing the query. 8339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 8349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View.OnKeyListener mButtonsKeyListener = new View.OnKeyListener() { 8359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean onKey(View v, int keyCode, KeyEvent event) { 836875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // guard against possible race conditions 837875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (mSearchable == null) { 838875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return false; 839875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 840875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 841875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (!event.isSystem() && 842875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen (keyCode != KeyEvent.KEYCODE_DPAD_UP) && 843875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen (keyCode != KeyEvent.KEYCODE_DPAD_LEFT) && 844875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen (keyCode != KeyEvent.KEYCODE_DPAD_RIGHT) && 845875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen (keyCode != KeyEvent.KEYCODE_DPAD_CENTER)) { 846875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // restore focus and give key to EditText ... 847875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (mSearchAutoComplete.requestFocus()) { 848875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return mSearchAutoComplete.dispatchKeyEvent(event); 849875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 8509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 851875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 8529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 8539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 8559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 8579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * React to a click in the GO button by launching a search. 8589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 8599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View.OnClickListener mGoButtonClickListener = new View.OnClickListener() { 8609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onClick(View v) { 861875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // guard against possible race conditions 862875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (mSearchable == null) { 863875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return; 8649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 865875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen launchQuerySearch(); 8669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 8689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 8709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * React to a click in the voice search button. 8719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 8729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View.OnClickListener mVoiceButtonClickListener = new View.OnClickListener() { 8739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onClick(View v) { 874875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // guard against possible race conditions 875875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (mSearchable == null) { 876875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return; 877875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 8789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 879c5e7fe36fbb79ea888da636779318d3e430aa24cMike LeBeau // First stop the existing search before starting voice search, or else we'll end 880c5e7fe36fbb79ea888da636779318d3e430aa24cMike LeBeau // up showing the search dialog again once we return to the app. 881c5e7fe36fbb79ea888da636779318d3e430aa24cMike LeBeau ((SearchManager) getContext().getSystemService(Context.SEARCH_SERVICE)). 882c5e7fe36fbb79ea888da636779318d3e430aa24cMike LeBeau stopSearch(); 883c5e7fe36fbb79ea888da636779318d3e430aa24cMike LeBeau 8849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mSearchable.getVoiceSearchLaunchWebSearch()) { 8859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project getContext().startActivity(mVoiceWebSearchIntent); 8869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (mSearchable.getVoiceSearchLaunchRecognizer()) { 887c5e7fe36fbb79ea888da636779318d3e430aa24cMike LeBeau Intent appSearchIntent = createVoiceAppSearchIntent(mVoiceAppSearchIntent); 8889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project getContext().startActivity(appSearchIntent); 8899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (ActivityNotFoundException e) { 8919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Should not happen, since we check the availability of 8929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // voice search before showing the button. But just in case... 8939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.w(LOG_TAG, "Could not find voice search activity"); 8949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 8979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 8999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Create and return an Intent that can launch the voice search activity, perform a specific 9009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * voice transcription, and forward the results to the searchable activity. 9019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 9029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param baseIntent The voice app search intent to start from 9039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return A completely-configured intent ready to send to the voice search activity 9049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 9059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Intent createVoiceAppSearchIntent(Intent baseIntent) { 906260dfb5716eab1dfe9dcb93b3e658cefaad197f9Mike LeBeau ComponentName searchActivity = mSearchable.getSearchActivity(); 907260dfb5716eab1dfe9dcb93b3e658cefaad197f9Mike LeBeau 9089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // create the necessary intent to set up a search-and-forward operation 9099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // in the voice search system. We have to keep the bundle separate, 9109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // because it becomes immutable once it enters the PendingIntent 9119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Intent queryIntent = new Intent(Intent.ACTION_SEARCH); 912260dfb5716eab1dfe9dcb93b3e658cefaad197f9Mike LeBeau queryIntent.setComponent(searchActivity); 9139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project PendingIntent pending = PendingIntent.getActivity( 9149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project getContext(), 0, queryIntent, PendingIntent.FLAG_ONE_SHOT); 9159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Now set up the bundle that will be inserted into the pending intent 9179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // when it's time to do the search. We always build it here (even if empty) 9189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // because the voice search activity will always need to insert "QUERY" into 9199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // it anyway. 9209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Bundle queryExtras = new Bundle(); 9219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mAppSearchData != null) { 9229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project queryExtras.putBundle(SearchManager.APP_DATA, mAppSearchData); 9239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Now build the intent to launch the voice search. Add all necessary 9269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // extras to launch the voice recognizer, and then all the necessary extras 9279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // to forward the results to the searchable activity 9289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Intent voiceIntent = new Intent(baseIntent); 9299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Add all of the configuration options supplied by the searchable's metadata 9319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String languageModel = RecognizerIntent.LANGUAGE_MODEL_FREE_FORM; 9329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String prompt = null; 9339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String language = null; 9349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int maxResults = 1; 9359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Resources resources = mActivityContext.getResources(); 9369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mSearchable.getVoiceLanguageModeId() != 0) { 9379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project languageModel = resources.getString(mSearchable.getVoiceLanguageModeId()); 9389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mSearchable.getVoicePromptTextId() != 0) { 9409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project prompt = resources.getString(mSearchable.getVoicePromptTextId()); 9419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mSearchable.getVoiceLanguageId() != 0) { 9439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project language = resources.getString(mSearchable.getVoiceLanguageId()); 9449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mSearchable.getVoiceMaxResults() != 0) { 9469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project maxResults = mSearchable.getVoiceMaxResults(); 9479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project voiceIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, languageModel); 9499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project voiceIntent.putExtra(RecognizerIntent.EXTRA_PROMPT, prompt); 9509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project voiceIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); 9519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project voiceIntent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, maxResults); 952260dfb5716eab1dfe9dcb93b3e658cefaad197f9Mike LeBeau voiceIntent.putExtra(EXTRA_CALLING_PACKAGE, 953260dfb5716eab1dfe9dcb93b3e658cefaad197f9Mike LeBeau searchActivity == null ? null : searchActivity.toShortString()); 9549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Add the values that configure forwarding the results 9569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project voiceIntent.putExtra(RecognizerIntent.EXTRA_RESULTS_PENDINGINTENT, pending); 9579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project voiceIntent.putExtra(RecognizerIntent.EXTRA_RESULTS_PENDINGINTENT_BUNDLE, queryExtras); 9589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return voiceIntent; 9609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 963662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath * Corrects http/https typo errors in the given url string, and if the protocol specifier was 964662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath * not present defaults to http. 965662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath * 966662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath * @param inUrl URL to check and fix 967662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath * @return fixed URL string. 968662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath */ 969662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath private String fixUrl(String inUrl) { 970662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath if (inUrl.startsWith("http://") || inUrl.startsWith("https://")) 971662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath return inUrl; 972662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath 973662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath if (inUrl.startsWith("http:") || inUrl.startsWith("https:")) { 974662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath if (inUrl.startsWith("http:/") || inUrl.startsWith("https:/")) { 975662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath inUrl = inUrl.replaceFirst("/", "//"); 976662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath } else { 977662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath inUrl = inUrl.replaceFirst(":", "://"); 978662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath } 979662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath } 980662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath 981662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath if (inUrl.indexOf("://") == -1) { 982662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath inUrl = "http://" + inUrl; 983662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath } 984662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath 985662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath return inUrl; 986662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath } 987662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath 988662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath /** 9899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * React to the user typing "enter" or other hardwired keys while typing in the search box. 9909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This handles these special keys while the edit box has focus. 9919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 9929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View.OnKeyListener mTextKeyListener = new View.OnKeyListener() { 9939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean onKey(View v, int keyCode, KeyEvent event) { 994875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // guard against possible race conditions 995875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (mSearchable == null) { 996875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return false; 9979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 999875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (DBG_LOG_TIMING) dbgLogTiming("doTextKey()"); 1000875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (DBG) { 1001875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen Log.d(LOG_TAG, "mTextListener.onKey(" + keyCode + "," + event 1002875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen + "), selection: " + mSearchAutoComplete.getListSelection()); 10039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1004875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 1005875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // If a suggestion is selected, handle enter, search key, and action keys 1006875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // as presses on the selected suggestion 1007875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (mSearchAutoComplete.isPopupShowing() && 1008875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mSearchAutoComplete.getListSelection() != ListView.INVALID_POSITION) { 1009875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return onSuggestionsKey(v, keyCode, event); 10109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1011875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 1012875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // If there is text in the query box, handle enter, and action keys 1013875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // The search key is handled by the dialog's onKeyDown(). 1014875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (!mSearchAutoComplete.isEmpty()) { 1015875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (keyCode == KeyEvent.KEYCODE_ENTER 1016875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen && event.getAction() == KeyEvent.ACTION_UP) { 1017875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen v.cancelLongPress(); 1018662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath 1019b1665f2e15439f693b1ef75cb1c07593f99edde7Satish Sampath // If this is a url entered by the user & we displayed the 'Go' button which 1020b1665f2e15439f693b1ef75cb1c07593f99edde7Satish Sampath // the user clicked, launch the url instead of using it as a search query. 1021b1665f2e15439f693b1ef75cb1c07593f99edde7Satish Sampath if (mSearchable.autoUrlDetect() && 1022b1665f2e15439f693b1ef75cb1c07593f99edde7Satish Sampath (mSearchAutoCompleteImeOptions & EditorInfo.IME_MASK_ACTION) 1023d21572cd446e56efe94689324107927ac2bffd2aSatish Sampath == EditorInfo.IME_ACTION_GO) { 1024b1665f2e15439f693b1ef75cb1c07593f99edde7Satish Sampath Uri uri = Uri.parse(fixUrl(mSearchAutoComplete.getText().toString())); 1025b1665f2e15439f693b1ef75cb1c07593f99edde7Satish Sampath Intent intent = new Intent(Intent.ACTION_VIEW, uri); 1026b1665f2e15439f693b1ef75cb1c07593f99edde7Satish Sampath intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 1027b1665f2e15439f693b1ef75cb1c07593f99edde7Satish Sampath launchIntent(intent); 1028b1665f2e15439f693b1ef75cb1c07593f99edde7Satish Sampath } else { 1029b1665f2e15439f693b1ef75cb1c07593f99edde7Satish Sampath // Launch as a regular search. 1030b1665f2e15439f693b1ef75cb1c07593f99edde7Satish Sampath launchQuerySearch(); 1031662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath } 1032875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return true; 1033875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 1034875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (event.getAction() == KeyEvent.ACTION_DOWN) { 1035875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen SearchableInfo.ActionKeyInfo actionKey = mSearchable.findActionKey(keyCode); 1036a92041306e4d73baa10fb711fb905b9590f06b26Bjorn Bringert if ((actionKey != null) && (actionKey.getQueryActionMsg() != null)) { 1037a92041306e4d73baa10fb711fb905b9590f06b26Bjorn Bringert launchQuerySearch(keyCode, actionKey.getQueryActionMsg()); 1038875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return true; 10399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1042875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return false; 10439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 10459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1046a8f556ee8cee24674663fd73c7a5b5a919b2d5bbDianne Hackborn @Override 1047ea52d29bc46c306f3607d121aa1ad84f0e9eb473Karl Rosaen public void hide() { 1048444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringert if (!isShowing()) return; 1049444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringert 1050a8f556ee8cee24674663fd73c7a5b5a919b2d5bbDianne Hackborn // We made sure the IME was displayed, so also make sure it is closed 1051a8f556ee8cee24674663fd73c7a5b5a919b2d5bbDianne Hackborn // when we go away. 1052a8f556ee8cee24674663fd73c7a5b5a919b2d5bbDianne Hackborn InputMethodManager imm = (InputMethodManager)getContext() 1053a8f556ee8cee24674663fd73c7a5b5a919b2d5bbDianne Hackborn .getSystemService(Context.INPUT_METHOD_SERVICE); 1054a8f556ee8cee24674663fd73c7a5b5a919b2d5bbDianne Hackborn if (imm != null) { 1055a8f556ee8cee24674663fd73c7a5b5a919b2d5bbDianne Hackborn imm.hideSoftInputFromWindow( 1056a8f556ee8cee24674663fd73c7a5b5a919b2d5bbDianne Hackborn getWindow().getDecorView().getWindowToken(), 0); 1057a8f556ee8cee24674663fd73c7a5b5a919b2d5bbDianne Hackborn } 1058ea52d29bc46c306f3607d121aa1ad84f0e9eb473Karl Rosaen 1059ea52d29bc46c306f3607d121aa1ad84f0e9eb473Karl Rosaen super.hide(); 1060a8f556ee8cee24674663fd73c7a5b5a919b2d5bbDianne Hackborn } 1061ea52d29bc46c306f3607d121aa1ad84f0e9eb473Karl Rosaen 10629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1063875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * React to the user typing while in the suggestions list. First, check for action 1064875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * keys. If not handled, try refocusing regular characters into the EditText. 10659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1066875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen private boolean onSuggestionsKey(View v, int keyCode, KeyEvent event) { 1067875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // guard against possible race conditions (late arrival after dismiss) 1068875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (mSearchable == null) { 1069875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return false; 1070875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 10719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mSuggestionsAdapter == null) { 10729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 10739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (event.getAction() == KeyEvent.ACTION_DOWN) { 1075875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (DBG_LOG_TIMING) { 1076875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen dbgLogTiming("onSuggestionsKey()"); 10779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // First, check for enter or search (both of which we'll treat as a "click") 10809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (keyCode == KeyEvent.KEYCODE_ENTER || keyCode == KeyEvent.KEYCODE_SEARCH) { 1081875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen int position = mSearchAutoComplete.getListSelection(); 1082875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return launchSuggestion(position); 10839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Next, check for left/right moves, which we use to "return" the user to the edit view 10869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT || keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) { 1087875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // give "focus" to text editor, with cursor at the beginning if 1088875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // left key, at end if right key 1089875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // TODO: Reverse left/right for right-to-left languages, e.g. Arabic 10909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int selPoint = (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) ? 1091875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 0 : mSearchAutoComplete.length(); 1092875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mSearchAutoComplete.setSelection(selPoint); 1093875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mSearchAutoComplete.setListSelection(0); 1094875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mSearchAutoComplete.clearListSelection(); 1095ffe3ecf2b1ee04288008758c0f60ae22238797c1Mike LeBeau mSearchAutoComplete.ensureImeVisible(); 1096ffe3ecf2b1ee04288008758c0f60ae22238797c1Mike LeBeau 10979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 10989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Next, check for an "up and out" move 1101875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (keyCode == KeyEvent.KEYCODE_DPAD_UP 1102875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen && 0 == mSearchAutoComplete.getListSelection()) { 1103875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen restoreUserQuery(); 11049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // let ACTV complete the move 11059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 11069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Next, check for an "action key" 11099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SearchableInfo.ActionKeyInfo actionKey = mSearchable.findActionKey(keyCode); 11109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if ((actionKey != null) && 1111a92041306e4d73baa10fb711fb905b9590f06b26Bjorn Bringert ((actionKey.getSuggestActionMsg() != null) || 1112a92041306e4d73baa10fb711fb905b9590f06b26Bjorn Bringert (actionKey.getSuggestActionMsgColumn() != null))) { 1113875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // launch suggestion using action key column 1114875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen int position = mSearchAutoComplete.getListSelection(); 1115875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (position != ListView.INVALID_POSITION) { 11169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Cursor c = mSuggestionsAdapter.getCursor(); 11179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (c.moveToPosition(position)) { 11189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final String actionMsg = getActionKeyMessage(c, actionKey); 11199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (actionMsg != null && (actionMsg.length() > 0)) { 1120875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return launchSuggestion(position, keyCode, actionMsg); 11219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 1127875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 1128875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 1129875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen /** 1130875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * Launch a search for the text in the query text field. 1131875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen */ 1132d2d6014f715f12f6263f61ba3eeb6f8cba6d0fa6krosaen public void launchQuerySearch() { 1133875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen launchQuerySearch(KeyEvent.KEYCODE_UNKNOWN, null); 1134875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 11359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1137875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * Launch a search for the text in the query text field. 1138875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * 1139875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * @param actionKey The key code of the action key that was pressed, 1140875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * or {@link KeyEvent#KEYCODE_UNKNOWN} if none. 1141875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * @param actionMsg The message for the action key that was pressed, 1142875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * or <code>null</code> if none. 1143875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen */ 1144875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen protected void launchQuerySearch(int actionKey, String actionMsg) { 1145875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen String query = mSearchAutoComplete.getText().toString(); 11464899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert String action = mGlobalSearchMode ? Intent.ACTION_WEB_SEARCH : Intent.ACTION_SEARCH; 11474899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert Intent intent = createIntent(action, null, null, query, null, 1148be5b73c5926cbebd508d8323bdeaafa2e048a93cBjorn Bringert actionKey, actionMsg, null); 11492fcaf79a1856186e3823390c488e806c5955c8a6Bjorn Bringert // Allow GlobalSearch to log and create shortcut for searches launched by 11502fcaf79a1856186e3823390c488e806c5955c8a6Bjorn Bringert // the search button, enter key or an action key. 11512fcaf79a1856186e3823390c488e806c5955c8a6Bjorn Bringert if (mGlobalSearchMode) { 11522fcaf79a1856186e3823390c488e806c5955c8a6Bjorn Bringert mSuggestionsAdapter.reportSearch(query); 11532fcaf79a1856186e3823390c488e806c5955c8a6Bjorn Bringert } 1154875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen launchIntent(intent); 1155875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 1156875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 1157875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen /** 1158875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * Launches an intent based on a suggestion. 11599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1160875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * @param position The index of the suggestion to create the intent from. 1161875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * @return true if a successful launch, false if could not (e.g. bad position). 11629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1163875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen protected boolean launchSuggestion(int position) { 1164875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return launchSuggestion(position, KeyEvent.KEYCODE_UNKNOWN, null); 1165875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 1166875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 1167875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen /** 1168875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * Launches an intent based on a suggestion. 1169875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * 1170875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * @param position The index of the suggestion to create the intent from. 1171875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * @param actionKey The key code of the action key that was pressed, 1172875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * or {@link KeyEvent#KEYCODE_UNKNOWN} if none. 1173875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * @param actionMsg The message for the action key that was pressed, 1174875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * or <code>null</code> if none. 1175875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * @return true if a successful launch, false if could not (e.g. bad position). 1176875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen */ 1177875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen protected boolean launchSuggestion(int position, int actionKey, String actionMsg) { 1178875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen Cursor c = mSuggestionsAdapter.getCursor(); 1179875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if ((c != null) && c.moveToPosition(position)) { 1180a058f02b591d971a829cb1e28d48a992e46ad85eKarl Rosaen 1181875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen Intent intent = createIntentFromSuggestion(c, actionKey, actionMsg); 1182d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen 1183d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen // report back about the click 1184d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen if (mGlobalSearchMode) { 1185d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen // in global search mode, do it via cursor 11865417f09c141713c62be697fe10fe149d6d3d0eb4Bjorn Bringert mSuggestionsAdapter.callCursorOnClick(c, position, actionKey, actionMsg); 1187d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen } else if (intent != null 1188d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen && mPreviousComponents != null 1189d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen && !mPreviousComponents.isEmpty()) { 1190d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen // in-app search (and we have pivoted in as told by mPreviousComponents, 1191d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen // which is used for keeping track of what we pop back to when we are pivoting into 1192d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen // in app search.) 1193d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen reportInAppClickToGlobalSearch(c, intent); 1194d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen } 1195d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen 1196d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen // launch the intent 1197875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen launchIntent(intent); 1198a058f02b591d971a829cb1e28d48a992e46ad85eKarl Rosaen 1199875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return true; 1200875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 1201875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return false; 1202875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 1203a058f02b591d971a829cb1e28d48a992e46ad85eKarl Rosaen 1204875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen /** 1205d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen * Report a click from an in app search result back to global search for shortcutting porpoises. 1206d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen * 1207d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen * @param c The cursor that is pointing to the clicked position. 1208d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen * @param intent The intent that will be launched for the click. 1209d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen */ 1210d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen private void reportInAppClickToGlobalSearch(Cursor c, Intent intent) { 1211d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen // for in app search, still tell global search via content provider 1212d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen Uri uri = getClickReportingUri(); 1213d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen final ContentValues cv = new ContentValues(); 1214d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen cv.put(SearchManager.SEARCH_CLICK_REPORT_COLUMN_QUERY, mUserQuery); 1215d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen final ComponentName source = mSearchable.getSearchActivity(); 1216d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen cv.put(SearchManager.SEARCH_CLICK_REPORT_COLUMN_COMPONENT, source.flattenToShortString()); 1217d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen 1218d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen // grab the intent columns from the intent we created since it has additional 1219d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen // logic for falling back on the searchable default 1220d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen cv.put(SearchManager.SUGGEST_COLUMN_INTENT_ACTION, intent.getAction()); 1221d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen cv.put(SearchManager.SUGGEST_COLUMN_INTENT_DATA, intent.getDataString()); 1222bf23fe062ab4321143717c21827d329e087cc72fSatish Sampath cv.put(SearchManager.SUGGEST_COLUMN_INTENT_COMPONENT_NAME, 12230e62e2df369b1f5a8e8ed38d3a6af6f568caf5e4Bjorn Bringert intent.getComponent().flattenToShortString()); 1224d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen 1225d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen // ensure the icons will work for global search 1226d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen cv.put(SearchManager.SUGGEST_COLUMN_ICON_1, 1227d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen wrapIconForPackage( 122883dba19a8e9d5be6f18a4c9e2e254386c25c66feBjorn Bringert mSearchable.getSuggestPackage(), 1229d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen getColumnString(c, SearchManager.SUGGEST_COLUMN_ICON_1))); 1230d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen cv.put(SearchManager.SUGGEST_COLUMN_ICON_2, 1231d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen wrapIconForPackage( 123283dba19a8e9d5be6f18a4c9e2e254386c25c66feBjorn Bringert mSearchable.getSuggestPackage(), 1233d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen getColumnString(c, SearchManager.SUGGEST_COLUMN_ICON_2))); 1234d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen 1235d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen // the rest can be passed through directly 1236d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen cv.put(SearchManager.SUGGEST_COLUMN_FORMAT, 1237d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen getColumnString(c, SearchManager.SUGGEST_COLUMN_FORMAT)); 1238d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen cv.put(SearchManager.SUGGEST_COLUMN_TEXT_1, 1239d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen getColumnString(c, SearchManager.SUGGEST_COLUMN_TEXT_1)); 1240d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen cv.put(SearchManager.SUGGEST_COLUMN_TEXT_2, 1241d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen getColumnString(c, SearchManager.SUGGEST_COLUMN_TEXT_2)); 1242d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen cv.put(SearchManager.SUGGEST_COLUMN_QUERY, 1243d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen getColumnString(c, SearchManager.SUGGEST_COLUMN_QUERY)); 1244d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen cv.put(SearchManager.SUGGEST_COLUMN_SHORTCUT_ID, 1245d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen getColumnString(c, SearchManager.SUGGEST_COLUMN_SHORTCUT_ID)); 1246d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen // note: deliberately omitting background color since it is only for global search 1247d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen // "more results" entries 1248d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen mContext.getContentResolver().insert(uri, cv); 1249d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen } 1250d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen 1251d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen /** 1252d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen * @return A URI appropriate for reporting a click. 1253d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen */ 1254d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen private Uri getClickReportingUri() { 1255d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen Uri.Builder uriBuilder = new Uri.Builder() 1256d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen .scheme(ContentResolver.SCHEME_CONTENT) 1257d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen .authority(SearchManager.SEARCH_CLICK_REPORT_AUTHORITY); 1258d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen 1259d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen uriBuilder.appendPath(SearchManager.SEARCH_CLICK_REPORT_URI_PATH); 1260d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen 1261d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen return uriBuilder 1262d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen .query("") // TODO: Remove, workaround for a bug in Uri.writeToParcel() 1263d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen .fragment("") // TODO: Remove, workaround for a bug in Uri.writeToParcel() 1264d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen .build(); 1265d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen } 1266d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen 1267d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen /** 1268d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen * Wraps an icon for a particular package. If the icon is a resource id, it is converted into 1269d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen * an android.resource:// URI. 1270d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen * 127183dba19a8e9d5be6f18a4c9e2e254386c25c66feBjorn Bringert * @param packageName The source of the icon 1272d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen * @param icon The icon retrieved from a suggestion column 1273d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen * @return An icon string appropriate for the package. 1274d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen */ 127583dba19a8e9d5be6f18a4c9e2e254386c25c66feBjorn Bringert private String wrapIconForPackage(String packageName, String icon) { 1276d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen if (icon == null || icon.length() == 0 || "0".equals(icon)) { 1277d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen // SearchManager specifies that null or zero can be returned to indicate 1278d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen // no icon. We also allow empty string. 1279d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen return null; 1280d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen } else if (!Character.isDigit(icon.charAt(0))){ 1281d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen return icon; 1282d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen } else { 1283d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen return new Uri.Builder() 1284d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen .scheme(ContentResolver.SCHEME_ANDROID_RESOURCE) 1285d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen .authority(packageName) 1286d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen .encodedPath(icon) 1287d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen .toString(); 1288d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen } 1289d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen } 1290d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen 1291d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen /** 1292ea52d29bc46c306f3607d121aa1ad84f0e9eb473Karl Rosaen * Launches an intent, including any special intent handling. Doesn't dismiss the dialog 1293ea52d29bc46c306f3607d121aa1ad84f0e9eb473Karl Rosaen * since that will be handled in {@link SearchDialogWrapper#performActivityResuming} 1294875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen */ 1295875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen private void launchIntent(Intent intent) { 1296875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (intent == null) { 12979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 12989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1299875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (handleSpecialIntent(intent)){ 1300875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return; 1301875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 1302ea52d29bc46c306f3607d121aa1ad84f0e9eb473Karl Rosaen Log.d(LOG_TAG, "launching " + intent); 13034899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert try { 13044899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert // in global search mode, we send the activity straight to the original suggestion 13054899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert // source. this is because GlobalSearch may not have permission to launch the 13064899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert // intent, and to avoid the extra step of going through GlobalSearch. 13074899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert if (mGlobalSearchMode) { 130842b7af57c59d8b7cb9be3fea713478424b53b7fcBryan Mawhinney if (mStoredComponentName != null) { 130942b7af57c59d8b7cb9be3fea713478424b53b7fcBryan Mawhinney // If we're embedded in an application, dismiss the dialog. 131042b7af57c59d8b7cb9be3fea713478424b53b7fcBryan Mawhinney // This ensures that if the intent is handled by the current 131142b7af57c59d8b7cb9be3fea713478424b53b7fcBryan Mawhinney // activity, it's not obscured by the dialog. 131242b7af57c59d8b7cb9be3fea713478424b53b7fcBryan Mawhinney dismiss(); 131342b7af57c59d8b7cb9be3fea713478424b53b7fcBryan Mawhinney } 13144899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert launchGlobalSearchIntent(intent); 13154899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert } else { 1316725d8ff6c5b4e27c8b7f2969ce1ddf6ec715ea6dBjorn Bringert // If the intent was created from a suggestion, it will always have an explicit 1317725d8ff6c5b4e27c8b7f2969ce1ddf6ec715ea6dBjorn Bringert // component here. 1318725d8ff6c5b4e27c8b7f2969ce1ddf6ec715ea6dBjorn Bringert Log.i(LOG_TAG, "Starting (as ourselves) " + intent.toURI()); 13194899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert getContext().startActivity(intent); 1320da1f4b669ead7813079643b43301f100127aaeedBjorn Bringert // If the search switches to a different activity, 1321da1f4b669ead7813079643b43301f100127aaeedBjorn Bringert // SearchDialogWrapper#performActivityResuming 13224899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert // will handle hiding the dialog when the next activity starts, but for 1323da1f4b669ead7813079643b43301f100127aaeedBjorn Bringert // real in-app search, we still need to dismiss the dialog. 1324da1f4b669ead7813079643b43301f100127aaeedBjorn Bringert if (isInRealAppSearch()) { 1325da1f4b669ead7813079643b43301f100127aaeedBjorn Bringert dismiss(); 1326da1f4b669ead7813079643b43301f100127aaeedBjorn Bringert } 13274899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert } 13284899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert } catch (RuntimeException ex) { 13294899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert Log.e(LOG_TAG, "Failed launch activity: " + intent, ex); 13304899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert } 13314899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert } 1332876627d8c52300608c8c716f980a8686f43bf476Karl Rosaen 13334899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert private void launchGlobalSearchIntent(Intent intent) { 13344899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert final String packageName; 13354899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert // GlobalSearch puts the original source of the suggestion in the 13364899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert // 'component name' column. If set, we send the intent to that activity. 13374899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert // We trust GlobalSearch to always set this to the suggestion source. 13384899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert String intentComponent = intent.getStringExtra(SearchManager.COMPONENT_NAME_KEY); 13394899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert if (intentComponent != null) { 13404899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert ComponentName componentName = ComponentName.unflattenFromString(intentComponent); 13414899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert intent.setComponent(componentName); 13424899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert intent.removeExtra(SearchManager.COMPONENT_NAME_KEY); 13434899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert // Launch the intent as the suggestion source. 13444899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert // This prevents sources from using the search dialog to launch 13454899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert // intents that they don't have permission for themselves. 13464899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert packageName = componentName.getPackageName(); 13474899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert } else { 13484899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert // If there is no component in the suggestion, it must be a built-in suggestion 13494899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert // from GlobalSearch (e.g. "Search the web for") or the intent 13504899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert // launched when pressing the search/go button in the search dialog. 13514899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert // Launch the intent with the permissions of GlobalSearch. 13524899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert packageName = mSearchable.getSearchActivity().getPackageName(); 1353876627d8c52300608c8c716f980a8686f43bf476Karl Rosaen } 13544899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert 13554899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert // Launch all global search suggestions as new tasks, since they don't relate 13564899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert // to the current task. 13574899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 13584899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert setBrowserApplicationId(intent); 13594899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert 13604899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert startActivityInPackage(intent, packageName); 13619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13624899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert 13634899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert /** 13644899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert * If the intent is to open an HTTP or HTTPS URL, we set 13654899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert * {@link Browser#EXTRA_APPLICATION_ID} so that any existing browser window that 13664899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert * has been opened by us for the same URL will be reused. 13674899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert */ 13684899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert private void setBrowserApplicationId(Intent intent) { 13694899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert Uri data = intent.getData(); 13704899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert if (Intent.ACTION_VIEW.equals(intent.getAction()) && data != null) { 13714899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert String scheme = data.getScheme(); 13724899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert if (scheme != null && scheme.startsWith("http")) { 13734899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert intent.putExtra(Browser.EXTRA_APPLICATION_ID, data.toString()); 13744899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert } 13754899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert } 13764899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert } 13774899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert 13784899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert /** 13794899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert * Starts an activity as if it had been started by the given package. 13804899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert * 13814899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert * @param intent The description of the activity to start. 13824899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert * @param packageName 13834899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert * @throws ActivityNotFoundException If the intent could not be resolved to 13844899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert * and existing activity. 13854899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert * @throws SecurityException If the package does not have permission to start 13864899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert * start the activity. 13874899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert * @throws AndroidRuntimeException If some other error occurs. 13884899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert */ 13894899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert private void startActivityInPackage(Intent intent, String packageName) { 13904899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert try { 13914899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert int uid = ActivityThread.getPackageManager().getPackageUid(packageName); 13924899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert if (uid < 0) { 13934899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert throw new AndroidRuntimeException("Package UID not found " + packageName); 13944899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert } 13954899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert String resolvedType = intent.resolveTypeIfNeeded(getContext().getContentResolver()); 13964899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert IBinder resultTo = null; 13974899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert String resultWho = null; 13984899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert int requestCode = -1; 13994899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert boolean onlyIfNeeded = false; 1400725d8ff6c5b4e27c8b7f2969ce1ddf6ec715ea6dBjorn Bringert Log.i(LOG_TAG, "Starting (uid " + uid + ", " + packageName + ") " + intent.toURI()); 14014899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert int result = ActivityManagerNative.getDefault().startActivityInPackage( 14024899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert uid, intent, resolvedType, resultTo, resultWho, requestCode, onlyIfNeeded); 14034899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert checkStartActivityResult(result, intent); 14044899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert } catch (RemoteException ex) { 14054899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert throw new AndroidRuntimeException(ex); 14064899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert } 14074899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert } 14084899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert 14094899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert // Stolen from Instrumentation.checkStartActivityResult() 14104899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert private static void checkStartActivityResult(int res, Intent intent) { 14114899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert if (res >= IActivityManager.START_SUCCESS) { 14124899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert return; 14134899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert } 14144899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert switch (res) { 14154899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert case IActivityManager.START_INTENT_NOT_RESOLVED: 14164899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert case IActivityManager.START_CLASS_NOT_FOUND: 14174899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert if (intent.getComponent() != null) 14184899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert throw new ActivityNotFoundException( 14194899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert "Unable to find explicit activity class " 14204899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert + intent.getComponent().toShortString() 14214899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert + "; have you declared this activity in your AndroidManifest.xml?"); 14224899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert throw new ActivityNotFoundException( 14234899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert "No Activity found to handle " + intent); 14244899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert case IActivityManager.START_PERMISSION_DENIED: 14254899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert throw new SecurityException("Not allowed to start activity " 14264899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert + intent); 14274899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert case IActivityManager.START_FORWARD_AND_REQUEST_CONFLICT: 14284899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert throw new AndroidRuntimeException( 14294899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert "FORWARD_RESULT_FLAG used while also requesting a result"); 14304899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert default: 14314899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert throw new AndroidRuntimeException("Unknown error code " 14324899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert + res + " when starting " + intent); 14334899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert } 14344899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert } 14354899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert 14369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1437875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * Handles the special intent actions declared in {@link SearchManager}. 1438875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * 1439875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * @return <code>true</code> if the intent was handled. 14409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1441875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen private boolean handleSpecialIntent(Intent intent) { 1442875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen String action = intent.getAction(); 1443875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (SearchManager.INTENT_ACTION_CHANGE_SEARCH_SOURCE.equals(action)) { 1444875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen handleChangeSourceIntent(intent); 1445875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return true; 14469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1447875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return false; 1448875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 1449875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 1450875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen /** 1451d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen * Handles {@link SearchManager#INTENT_ACTION_CHANGE_SEARCH_SOURCE}. 1452875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen */ 1453875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen private void handleChangeSourceIntent(Intent intent) { 1454875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen Uri dataUri = intent.getData(); 1455875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (dataUri == null) { 1456875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen Log.w(LOG_TAG, "SearchManager.INTENT_ACTION_CHANGE_SOURCE without intent data."); 1457875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return; 14589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1459875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen ComponentName componentName = ComponentName.unflattenFromString(dataUri.toString()); 1460875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (componentName == null) { 1461875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen Log.w(LOG_TAG, "Invalid ComponentName: " + dataUri); 1462875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return; 14639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1464875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (DBG) Log.d(LOG_TAG, "Switching to " + componentName); 1465da1f4b669ead7813079643b43301f100127aaeedBjorn Bringert 1466da1f4b669ead7813079643b43301f100127aaeedBjorn Bringert pushPreviousComponent(mLaunchComponent); 1467875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (!show(componentName, mAppSearchData, false)) { 1468875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen Log.w(LOG_TAG, "Failed to switch to source " + componentName); 1469da1f4b669ead7813079643b43301f100127aaeedBjorn Bringert popPreviousComponent(); 1470875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return; 14719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1473875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen String query = intent.getStringExtra(SearchManager.QUERY); 1474875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen setUserQuery(query); 147535df87c6319863beed9fd95d0a279e34ff94e92eMike LeBeau mSearchAutoComplete.showDropDown(); 14769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1477a058f02b591d971a829cb1e28d48a992e46ad85eKarl Rosaen 1478875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen /** 1479ae9760b62c400e3e7009d4a7b85e9524a5cd44fcMike LeBeau * Sets the list item selection in the AutoCompleteTextView's ListView. 1480ae9760b62c400e3e7009d4a7b85e9524a5cd44fcMike LeBeau */ 1481ae9760b62c400e3e7009d4a7b85e9524a5cd44fcMike LeBeau public void setListSelection(int index) { 1482ae9760b62c400e3e7009d4a7b85e9524a5cd44fcMike LeBeau mSearchAutoComplete.setListSelection(index); 1483ae9760b62c400e3e7009d4a7b85e9524a5cd44fcMike LeBeau } 1484a058f02b591d971a829cb1e28d48a992e46ad85eKarl Rosaen 1485ae9760b62c400e3e7009d4a7b85e9524a5cd44fcMike LeBeau /** 148687d61f22e13e81550559c92f6cf6fb795a39d37fBjorn Bringert * Checks if there are any previous searchable components in the history stack. 148787d61f22e13e81550559c92f6cf6fb795a39d37fBjorn Bringert */ 148887d61f22e13e81550559c92f6cf6fb795a39d37fBjorn Bringert private boolean hasPreviousComponent() { 148987d61f22e13e81550559c92f6cf6fb795a39d37fBjorn Bringert return mPreviousComponents != null && !mPreviousComponents.isEmpty(); 149087d61f22e13e81550559c92f6cf6fb795a39d37fBjorn Bringert } 149187d61f22e13e81550559c92f6cf6fb795a39d37fBjorn Bringert 149287d61f22e13e81550559c92f6cf6fb795a39d37fBjorn Bringert /** 1493875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * Saves the previous component that was searched, so that we can go 1494875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * back to it. 1495875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen */ 1496875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen private void pushPreviousComponent(ComponentName componentName) { 1497875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (mPreviousComponents == null) { 1498875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mPreviousComponents = new ArrayList<ComponentName>(); 1499875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 1500875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mPreviousComponents.add(componentName); 1501875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 1502875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 1503875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen /** 1504875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * Pops the previous component off the stack and returns it. 1505875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * 1506875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * @return The component name, or <code>null</code> if there was 1507875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * no previous component. 1508875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen */ 1509875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen private ComponentName popPreviousComponent() { 151087d61f22e13e81550559c92f6cf6fb795a39d37fBjorn Bringert if (!hasPreviousComponent()) { 1511875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return null; 1512875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 151387d61f22e13e81550559c92f6cf6fb795a39d37fBjorn Bringert return mPreviousComponents.remove(mPreviousComponents.size() - 1); 1514875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 1515875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 1516875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen /** 1517875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * Goes back to the previous component that was searched, if any. 1518875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * 1519875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * @return <code>true</code> if there was a previous component that we could go back to. 1520875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen */ 152187d61f22e13e81550559c92f6cf6fb795a39d37fBjorn Bringert private boolean backToPreviousComponent() { 1522875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen ComponentName previous = popPreviousComponent(); 1523875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (previous == null) { 1524875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return false; 1525875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 152687d61f22e13e81550559c92f6cf6fb795a39d37fBjorn Bringert 152787d61f22e13e81550559c92f6cf6fb795a39d37fBjorn Bringert if (!show(previous, mAppSearchData, false)) { 152887d61f22e13e81550559c92f6cf6fb795a39d37fBjorn Bringert Log.w(LOG_TAG, "Failed to switch to source " + previous); 152987d61f22e13e81550559c92f6cf6fb795a39d37fBjorn Bringert return false; 153083fe3f559249451706957b1a5f660b2b8272f114Dianne Hackborn } 153187d61f22e13e81550559c92f6cf6fb795a39d37fBjorn Bringert 153287d61f22e13e81550559c92f6cf6fb795a39d37fBjorn Bringert // must touch text to trigger suggestions 153387d61f22e13e81550559c92f6cf6fb795a39d37fBjorn Bringert // TODO: should this be the text as it was when the user left 153487d61f22e13e81550559c92f6cf6fb795a39d37fBjorn Bringert // the source that we are now going back to? 153587d61f22e13e81550559c92f6cf6fb795a39d37fBjorn Bringert String query = mSearchAutoComplete.getText().toString(); 153687d61f22e13e81550559c92f6cf6fb795a39d37fBjorn Bringert setUserQuery(query); 1537875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return true; 15389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 15419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * When a particular suggestion has been selected, perform the various lookups required 15429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * to use the suggestion. This includes checking the cursor for suggestion-specific data, 15439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * and/or falling back to the XML for defaults; It also creates REST style Uri data when 15449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the suggestion includes a data id. 15459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 15469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param c The suggestions cursor, moved to the row of the user's selection 1547875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * @param actionKey The key code of the action key that was pressed, 1548875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * or {@link KeyEvent#KEYCODE_UNKNOWN} if none. 1549875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * @param actionMsg The message for the action key that was pressed, 1550875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * or <code>null</code> if none. 1551875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * @return An intent for the suggestion at the cursor's position. 15529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1553875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen private Intent createIntentFromSuggestion(Cursor c, int actionKey, String actionMsg) { 15549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 15559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // use specific action if supplied, or default action if supplied, or fixed default 1556875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen String action = getColumnString(c, SearchManager.SUGGEST_COLUMN_INTENT_ACTION); 1557a058f02b591d971a829cb1e28d48a992e46ad85eKarl Rosaen 1558a058f02b591d971a829cb1e28d48a992e46ad85eKarl Rosaen // some items are display only, or have effect via the cursor respond click reporting. 1559a058f02b591d971a829cb1e28d48a992e46ad85eKarl Rosaen if (SearchManager.INTENT_ACTION_NONE.equals(action)) { 1560a058f02b591d971a829cb1e28d48a992e46ad85eKarl Rosaen return null; 1561a058f02b591d971a829cb1e28d48a992e46ad85eKarl Rosaen } 1562a058f02b591d971a829cb1e28d48a992e46ad85eKarl Rosaen 1563875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (action == null) { 1564875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen action = mSearchable.getSuggestIntentAction(); 15659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1566875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (action == null) { 1567875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen action = Intent.ACTION_SEARCH; 15689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 15709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // use specific data if supplied, or default data if supplied 1571875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen String data = getColumnString(c, SearchManager.SUGGEST_COLUMN_INTENT_DATA); 15729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (data == null) { 1573875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen data = mSearchable.getSuggestIntentData(); 15749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // then, if an ID was provided, append it. 15769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (data != null) { 1577875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen String id = getColumnString(c, SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID); 1578875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (id != null) { 1579875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen data = data + "/" + Uri.encode(id); 15809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 15819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1582875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen Uri dataUri = (data == null) ? null : Uri.parse(data); 1583875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 1584bf23fe062ab4321143717c21827d329e087cc72fSatish Sampath String componentName = getColumnString( 1585bf23fe062ab4321143717c21827d329e087cc72fSatish Sampath c, SearchManager.SUGGEST_COLUMN_INTENT_COMPONENT_NAME); 1586a058f02b591d971a829cb1e28d48a992e46ad85eKarl Rosaen 1587875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen String query = getColumnString(c, SearchManager.SUGGEST_COLUMN_QUERY); 1588bf23fe062ab4321143717c21827d329e087cc72fSatish Sampath String extraData = getColumnString(c, SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA); 1589be5b73c5926cbebd508d8323bdeaafa2e048a93cBjorn Bringert String mode = mGlobalSearchMode ? SearchManager.MODE_GLOBAL_SEARCH_SUGGESTION : null; 1590875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 1591bf23fe062ab4321143717c21827d329e087cc72fSatish Sampath return createIntent(action, dataUri, extraData, query, componentName, actionKey, 1592be5b73c5926cbebd508d8323bdeaafa2e048a93cBjorn Bringert actionMsg, mode); 15939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (RuntimeException e ) { 15949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int rowNum; 15959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { // be really paranoid now 15969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project rowNum = c.getPosition(); 15979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (RuntimeException e2 ) { 15989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project rowNum = -1; 15999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.w(LOG_TAG, "Search Suggestions cursor at row " + rowNum + 16019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project " returned exception" + e.toString()); 1602875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return null; 16039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 16069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1607875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * Constructs an intent from the given information and the search dialog state. 1608875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * 1609875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * @param action Intent action. 1610875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * @param data Intent data, or <code>null</code>. 1611875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * @param extraData Data for {@link SearchManager#EXTRA_DATA_KEY} or <code>null</code>. 1612bf23fe062ab4321143717c21827d329e087cc72fSatish Sampath * @param query Intent query, or <code>null</code>. 1613bf23fe062ab4321143717c21827d329e087cc72fSatish Sampath * @param componentName Data for {@link SearchManager#COMPONENT_NAME_KEY} or <code>null</code>. 1614875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * @param actionKey The key code of the action key that was pressed, 1615875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * or {@link KeyEvent#KEYCODE_UNKNOWN} if none. 1616875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * @param actionMsg The message for the action key that was pressed, 1617875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * or <code>null</code> if none. 1618be5b73c5926cbebd508d8323bdeaafa2e048a93cBjorn Bringert * @param mode The search mode, one of the acceptable values for 1619be5b73c5926cbebd508d8323bdeaafa2e048a93cBjorn Bringert * {@link SearchManager#SEARCH_MODE}, or {@code null}. 1620875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * @return The intent. 1621875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen */ 1622bf23fe062ab4321143717c21827d329e087cc72fSatish Sampath private Intent createIntent(String action, Uri data, String extraData, String query, 1623be5b73c5926cbebd508d8323bdeaafa2e048a93cBjorn Bringert String componentName, int actionKey, String actionMsg, String mode) { 1624875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // Now build the Intent 1625875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen Intent intent = new Intent(action); 16268d17f3f24bbda9a9cd7ea08c5925508dc2c011beBjorn Bringert intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 1627442da48b24f75e6075763b89943b513197a0bfe9Bjorn Bringert // We need CLEAR_TOP to avoid reusing an old task that has other activities 1628442da48b24f75e6075763b89943b513197a0bfe9Bjorn Bringert // on top of the one we want. 1629442da48b24f75e6075763b89943b513197a0bfe9Bjorn Bringert intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); 1630875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (data != null) { 1631875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen intent.setData(data); 1632875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 16335f80605a0b866f34c74955e190909bd6ab5d992eBjorn Bringert intent.putExtra(SearchManager.USER_QUERY, mUserQuery); 1634875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (query != null) { 1635875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen intent.putExtra(SearchManager.QUERY, query); 1636875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 1637875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (extraData != null) { 1638875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen intent.putExtra(SearchManager.EXTRA_DATA_KEY, extraData); 1639875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 1640bf23fe062ab4321143717c21827d329e087cc72fSatish Sampath if (componentName != null) { 1641bf23fe062ab4321143717c21827d329e087cc72fSatish Sampath intent.putExtra(SearchManager.COMPONENT_NAME_KEY, componentName); 1642bf23fe062ab4321143717c21827d329e087cc72fSatish Sampath } 1643875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (mAppSearchData != null) { 1644875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen intent.putExtra(SearchManager.APP_DATA, mAppSearchData); 1645875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 1646875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (actionKey != KeyEvent.KEYCODE_UNKNOWN) { 1647875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen intent.putExtra(SearchManager.ACTION_KEY, actionKey); 1648875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen intent.putExtra(SearchManager.ACTION_MSG, actionMsg); 1649875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 1650be5b73c5926cbebd508d8323bdeaafa2e048a93cBjorn Bringert if (mode != null) { 1651be5b73c5926cbebd508d8323bdeaafa2e048a93cBjorn Bringert intent.putExtra(SearchManager.SEARCH_MODE, mode); 1652be5b73c5926cbebd508d8323bdeaafa2e048a93cBjorn Bringert } 16534899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert // Only allow 3rd-party intents from GlobalSearch 16544899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert if (!mGlobalSearchMode) { 16554899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert intent.setComponent(mSearchable.getSearchActivity()); 16564899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert } 1657875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return intent; 1658875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 1659875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 1660875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen /** 16619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * For a given suggestion and a given cursor row, get the action message. If not provided 16629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * by the specific row/column, also check for a single definition (for the action key). 16639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 16649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param c The cursor providing suggestions 16659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param actionKey The actionkey record being examined 16669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 16679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return Returns a string, or null if no action key message for this suggestion 16689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1669875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen private static String getActionKeyMessage(Cursor c, SearchableInfo.ActionKeyInfo actionKey) { 16709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String result = null; 16719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // check first in the cursor data, for a suggestion-specific message 1672a92041306e4d73baa10fb711fb905b9590f06b26Bjorn Bringert final String column = actionKey.getSuggestActionMsgColumn(); 16739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (column != null) { 1674875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen result = SuggestionsAdapter.getColumnString(c, column); 16759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // If the cursor didn't give us a message, see if there's a single message defined 16779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // for the actionkey (for all suggestions) 16789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (result == null) { 1679a92041306e4d73baa10fb711fb905b9590f06b26Bjorn Bringert result = actionKey.getSuggestActionMsg(); 16809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 16819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return result; 16829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1683077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert 1684077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert /** 1685077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert * The root element in the search bar layout. This is a custom view just to override 1686077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert * the handling of the back button. 1687077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert */ 1688077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert public static class SearchBar extends LinearLayout { 1689077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert 1690077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert private SearchDialog mSearchDialog; 1691077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert 1692077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert public SearchBar(Context context, AttributeSet attrs) { 1693077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert super(context, attrs); 1694077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert } 1695077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert 1696077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert public SearchBar(Context context) { 1697077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert super(context); 1698077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert } 1699077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert 1700077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert public void setSearchDialog(SearchDialog searchDialog) { 1701077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert mSearchDialog = searchDialog; 1702077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert } 1703077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert 1704077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert /** 1705077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert * Overrides the handling of the back key to move back to the previous sources or dismiss 1706077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert * the search dialog, instead of dismissing the input method. 1707077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert */ 1708077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert @Override 1709077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert public boolean dispatchKeyEventPreIme(KeyEvent event) { 1710077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert if (DBG) Log.d(LOG_TAG, "onKeyPreIme(" + event + ")"); 1711077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert if (mSearchDialog != null && event.getKeyCode() == KeyEvent.KEYCODE_BACK) { 1712077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert if (event.getAction() == KeyEvent.ACTION_DOWN 1713077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert && event.getRepeatCount() == 0) { 1714077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert getKeyDispatcherState().startTracking(event, this); 1715077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert return true; 1716077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert } else if (event.getAction() == KeyEvent.ACTION_UP 1717077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert && !event.isCanceled() && getKeyDispatcherState().isTracking(event)) { 1718077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert mSearchDialog.onBackPressed(); 1719077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert return true; 1720077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert } 1721077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert } 1722077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert return super.dispatchKeyEventPreIme(event); 1723077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert } 1724077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert } 1725077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert 17269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1727875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * Local subclass for AutoCompleteTextView. 17289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 17299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static class SearchAutoComplete extends AutoCompleteTextView { 17309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1731875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen private int mThreshold; 1732077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert 17339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public SearchAutoComplete(Context context) { 17341746d6fefcb1b4869f475a81f5aec35db4695603Marco Nelissen super(context); 1735875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mThreshold = getThreshold(); 17369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public SearchAutoComplete(Context context, AttributeSet attrs) { 17399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super(context, attrs); 1740875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mThreshold = getThreshold(); 17419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public SearchAutoComplete(Context context, AttributeSet attrs, int defStyle) { 17449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super(context, attrs, defStyle); 1745875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mThreshold = getThreshold(); 17469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1747875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 17489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 1749875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen public void setThreshold(int threshold) { 1750875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen super.setThreshold(threshold); 1751875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mThreshold = threshold; 17529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1755875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * Returns true if the text field is empty, or contains only whitespace. 17569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1757875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen private boolean isEmpty() { 1758875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return TextUtils.getTrimmedLength(getText()) == 0; 17599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17608d17f3f24bbda9a9cd7ea08c5925508dc2c011beBjorn Bringert 17619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1762875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * We override this method to avoid replacing the query box text 1763875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * when a suggestion is clicked. 17649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 17659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 1766875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen protected void replaceText(CharSequence text) { 17679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 17689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 17699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1770617202a53a26d1b38a41ce69c40b1fffd784c178Mike LeBeau * We override this method to avoid an extra onItemClick being called on the 1771617202a53a26d1b38a41ce69c40b1fffd784c178Mike LeBeau * drop-down's OnItemClickListener by {@link AutoCompleteTextView#onKeyUp(int, KeyEvent)} 1772617202a53a26d1b38a41ce69c40b1fffd784c178Mike LeBeau * when an item is clicked with the trackball. 1773617202a53a26d1b38a41ce69c40b1fffd784c178Mike LeBeau */ 1774617202a53a26d1b38a41ce69c40b1fffd784c178Mike LeBeau @Override 1775617202a53a26d1b38a41ce69c40b1fffd784c178Mike LeBeau public void performCompletion() { 1776617202a53a26d1b38a41ce69c40b1fffd784c178Mike LeBeau } 17771fffbd97fa756ef7d3e7e885a5c1c8bb64380c20Mike LeBeau 17781fffbd97fa756ef7d3e7e885a5c1c8bb64380c20Mike LeBeau /** 17791fffbd97fa756ef7d3e7e885a5c1c8bb64380c20Mike LeBeau * We override this method to be sure and show the soft keyboard if appropriate when 17801fffbd97fa756ef7d3e7e885a5c1c8bb64380c20Mike LeBeau * the TextView has focus. 17811fffbd97fa756ef7d3e7e885a5c1c8bb64380c20Mike LeBeau */ 17821fffbd97fa756ef7d3e7e885a5c1c8bb64380c20Mike LeBeau @Override 17831fffbd97fa756ef7d3e7e885a5c1c8bb64380c20Mike LeBeau public void onWindowFocusChanged(boolean hasWindowFocus) { 17841fffbd97fa756ef7d3e7e885a5c1c8bb64380c20Mike LeBeau super.onWindowFocusChanged(hasWindowFocus); 17851fffbd97fa756ef7d3e7e885a5c1c8bb64380c20Mike LeBeau 17861fffbd97fa756ef7d3e7e885a5c1c8bb64380c20Mike LeBeau if (hasWindowFocus) { 17871fffbd97fa756ef7d3e7e885a5c1c8bb64380c20Mike LeBeau InputMethodManager inputManager = (InputMethodManager) 17881fffbd97fa756ef7d3e7e885a5c1c8bb64380c20Mike LeBeau getContext().getSystemService(Context.INPUT_METHOD_SERVICE); 17891fffbd97fa756ef7d3e7e885a5c1c8bb64380c20Mike LeBeau inputManager.showSoftInput(this, 0); 17901fffbd97fa756ef7d3e7e885a5c1c8bb64380c20Mike LeBeau } 17911fffbd97fa756ef7d3e7e885a5c1c8bb64380c20Mike LeBeau } 17921fffbd97fa756ef7d3e7e885a5c1c8bb64380c20Mike LeBeau 1793617202a53a26d1b38a41ce69c40b1fffd784c178Mike LeBeau /** 1794875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * We override this method so that we can allow a threshold of zero, which ACTV does not. 17959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 17969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 1797875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen public boolean enoughToFilter() { 1798875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return mThreshold <= 0 || super.enoughToFilter(); 17999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 180098e333f551a4bf2ebb50bb97a2a56b14bfdcd74bKarl Rosaen 1801875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 180287d61f22e13e81550559c92f6cf6fb795a39d37fBjorn Bringert 180387d61f22e13e81550559c92f6cf6fb795a39d37fBjorn Bringert @Override 180487d61f22e13e81550559c92f6cf6fb795a39d37fBjorn Bringert public void onBackPressed() { 180587d61f22e13e81550559c92f6cf6fb795a39d37fBjorn Bringert if (!backToPreviousComponent()) { 180687d61f22e13e81550559c92f6cf6fb795a39d37fBjorn Bringert cancel(); 18079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 180987d61f22e13e81550559c92f6cf6fb795a39d37fBjorn Bringert 18109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 18119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Implements OnItemClickListener 18129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 18139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onItemClick(AdapterView<?> parent, View view, int position, long id) { 1814875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (DBG) Log.d(LOG_TAG, "onItemClick() position " + position); 1815875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen launchSuggestion(position); 18169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1817875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 18189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 18199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Implements OnItemSelectedListener 18209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 18219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { 1822875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (DBG) Log.d(LOG_TAG, "onItemSelected() position " + position); 1823875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // A suggestion has been selected, rewrite the query if possible, 1824875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // otherwise the restore the original query. 1825875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (REWRITE_QUERIES) { 1826875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen rewriteQueryFromSuggestion(position); 1827875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 18289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 18309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 18319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Implements OnItemSelectedListener 18329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 18339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onNothingSelected(AdapterView<?> parent) { 1834875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (DBG) Log.d(LOG_TAG, "onNothingSelected()"); 1835875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 1836875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 1837875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen /** 1838875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * Query rewriting. 1839875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen */ 1840875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 1841875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen private void rewriteQueryFromSuggestion(int position) { 1842875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen Cursor c = mSuggestionsAdapter.getCursor(); 1843875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (c == null) { 1844875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return; 1845875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 1846875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (c.moveToPosition(position)) { 1847875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // Get the new query from the suggestion. 1848875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen CharSequence newQuery = mSuggestionsAdapter.convertToString(c); 1849875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (newQuery != null) { 1850875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // The suggestion rewrites the query. 1851875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (DBG) Log.d(LOG_TAG, "Rewriting query to '" + newQuery + "'"); 1852875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // Update the text field, without getting new suggestions. 1853875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen setQuery(newQuery); 1854875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } else { 1855875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // The suggestion does not rewrite the query, restore the user's query. 1856875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (DBG) Log.d(LOG_TAG, "Suggestion gives no rewrite, restoring user query."); 1857875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen restoreUserQuery(); 1858875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 1859875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } else { 1860875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // We got a bad position, restore the user's query. 1861875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen Log.w(LOG_TAG, "Bad suggestion position: " + position); 1862875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen restoreUserQuery(); 1863875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 1864875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 1865875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 1866875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen /** 1867875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * Restores the query entered by the user if needed. 1868875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen */ 1869875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen private void restoreUserQuery() { 1870875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (DBG) Log.d(LOG_TAG, "Restoring query to '" + mUserQuery + "'"); 1871875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen setQuery(mUserQuery); 1872875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 1873875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 1874875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen /** 1875875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * Sets the text in the query box, without updating the suggestions. 1876875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen */ 1877875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen private void setQuery(CharSequence query) { 1878875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mSearchAutoComplete.setText(query, false); 1879875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (query != null) { 1880875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mSearchAutoComplete.setSelection(query.length()); 1881875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 1882875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 1883875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 1884875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen /** 1885875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * Sets the text in the query box, updating the suggestions. 1886875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen */ 1887875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen private void setUserQuery(String query) { 1888875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (query == null) { 1889875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen query = ""; 1890875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 1891875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mUserQuery = query; 1892875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mSearchAutoComplete.setText(query); 1893875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mSearchAutoComplete.setSelection(query.length()); 18949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 18959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 18969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 18979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Debugging Support 18989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 18999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 19009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 19019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * For debugging only, sample the millisecond clock and log it. 19029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Uses AtomicLong so we can use in multiple threads 19039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 19049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private AtomicLong mLastLogTime = new AtomicLong(SystemClock.uptimeMillis()); 19059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void dbgLogTiming(final String caller) { 19069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long millis = SystemClock.uptimeMillis(); 19079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long oldTime = mLastLogTime.getAndSet(millis); 19089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long delta = millis - oldTime; 19099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final String report = millis + " (+" + delta + ") ticks for Search keystroke in " + caller; 19109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.d(LOG_TAG,report); 19119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 19129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 1913