SearchDialog.java revision 479ae0a28099eb77299fe0f44d4dfabce3115fb6
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 19479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasaniimport com.android.common.Patterns; 20479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasaniimport com.android.common.speech.Recognition; 21479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani 22875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaenimport static android.app.SuggestionsAdapter.getColumnString; 23c1f40960644b461b108480b6446c89963441492dBjorn Bringert 249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.ActivityNotFoundException; 259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.ComponentName; 26d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaenimport android.content.ContentResolver; 27d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaenimport android.content.ContentValues; 28444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringertimport android.content.Context; 29444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringertimport android.content.Intent; 30875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaenimport android.content.pm.ActivityInfo; 319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.pm.PackageManager; 3298e333f551a4bf2ebb50bb97a2a56b14bfdcd74bKarl Rosaenimport android.content.pm.ResolveInfo; 33c1f40960644b461b108480b6446c89963441492dBjorn Bringertimport android.content.pm.PackageManager.NameNotFoundException; 349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.res.Resources; 359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.database.Cursor; 36444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringertimport android.graphics.drawable.Drawable; 379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.net.Uri; 389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Bundle; 394899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringertimport android.os.IBinder; 404899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringertimport android.os.RemoteException; 419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.SystemClock; 424899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringertimport android.provider.Browser; 439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.speech.RecognizerIntent; 449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.Editable; 459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.InputType; 469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.TextUtils; 479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.TextWatcher; 484899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringertimport android.util.AndroidRuntimeException; 499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.AttributeSet; 509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log; 51a97f4a117415fd877bc63d6c90a6775ca04eb3feMike LeBeauimport android.view.ContextThemeWrapper; 529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.Gravity; 539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.KeyEvent; 54875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaenimport android.view.MotionEvent; 559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.View; 56875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaenimport android.view.ViewConfiguration; 579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.ViewGroup; 589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.Window; 599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.WindowManager; 60662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampathimport android.view.inputmethod.EditorInfo; 61a8f556ee8cee24674663fd73c7a5b5a919b2d5bbDianne Hackbornimport android.view.inputmethod.InputMethodManager; 629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.widget.AdapterView; 639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.widget.AutoCompleteTextView; 649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.widget.Button; 659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.widget.ImageButton; 66da5c1bd4443b5b569a0d392cd53b476b4e160c47Bjorn Bringertimport android.widget.ImageView; 67077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringertimport android.widget.LinearLayout; 689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.widget.ListView; 699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.widget.TextView; 70c1f40960644b461b108480b6446c89963441492dBjorn Bringertimport android.widget.AdapterView.OnItemClickListener; 71c1f40960644b461b108480b6446c89963441492dBjorn Bringertimport android.widget.AdapterView.OnItemSelectedListener; 729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 73875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaenimport java.util.ArrayList; 74875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaenimport java.util.WeakHashMap; 759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.concurrent.atomic.AtomicLong; 769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 78e9ce3f01d42769f03f10e70c3244500e92d7eee1Amith Yamasani * Search dialog. This is controlled by the 79e9ce3f01d42769f03f10e70c3244500e92d7eee1Amith Yamasani * SearchManager and runs in the current foreground process. 809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @hide 829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class SearchDialog extends Dialog implements OnItemClickListener, OnItemSelectedListener { 849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Debugging support 86875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen private static final boolean DBG = false; 87875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen private static final String LOG_TAG = "SearchDialog"; 88875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen private static final boolean DBG_LOG_TIMING = false; 899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String INSTANCE_KEY_COMPONENT = "comp"; 919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String INSTANCE_KEY_APPDATA = "data"; 92b0ae27f4e10a9e5fe56b9ca549718051fe342bbaBjorn Bringert private static final String INSTANCE_KEY_STORED_APPDATA = "sData"; 93b0ae27f4e10a9e5fe56b9ca549718051fe342bbaBjorn Bringert private static final String INSTANCE_KEY_USER_QUERY = "uQry"; 94260dfb5716eab1dfe9dcb93b3e658cefaad197f9Mike LeBeau 957df846186d29ddfa4a567deddd04ad1043d32fd8Mike LeBeau // The string used for privateImeOptions to identify to the IME that it should not show 967df846186d29ddfa4a567deddd04ad1043d32fd8Mike LeBeau // a microphone button since one already exists in the search dialog. 977df846186d29ddfa4a567deddd04ad1043d32fd8Mike LeBeau private static final String IME_OPTION_NO_MICROPHONE = "nm"; 98b0ae27f4e10a9e5fe56b9ca549718051fe342bbaBjorn Bringert 991fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau private static final int SEARCH_PLATE_LEFT_PADDING_GLOBAL = 12; 1001fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau private static final int SEARCH_PLATE_LEFT_PADDING_NON_GLOBAL = 7; 101444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringert 1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // views & widgets 1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private TextView mBadgeLabel; 104da5c1bd4443b5b569a0d392cd53b476b4e160c47Bjorn Bringert private ImageView mAppIcon; 105875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen private SearchAutoComplete mSearchAutoComplete; 1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Button mGoButton; 1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private ImageButton mVoiceButton; 108875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen private View mSearchPlate; 109f4f7046183f0daedd17703fa16cf9026442bdaeeRomain Guy private Drawable mWorkingSpinner; 1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // interaction with searchable application 112875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen private SearchableInfo mSearchable; 1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private ComponentName mLaunchComponent; 1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Bundle mAppSearchData; 1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Context mActivityContext; 116e9ce3f01d42769f03f10e70c3244500e92d7eee1Amith Yamasani private SearchManager mSearchManager; 117875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // For voice searching 119f36740b2e4a9a187bf688c632c1d0a7ae926c96aBryan Mawhinney private final Intent mVoiceWebSearchIntent; 120f36740b2e4a9a187bf688c632c1d0a7ae926c96aBryan Mawhinney private final Intent mVoiceAppSearchIntent; 1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // support for AutoCompleteTextView suggestions display 1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private SuggestionsAdapter mSuggestionsAdapter; 124875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 125875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // Whether to rewrite queries when selecting suggestions 126cce7dbc31ed100b39c3e1174dd3d9a01de648e5bMike LeBeau private static final boolean REWRITE_QUERIES = true; 127875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 128875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // The query entered by the user. This is not changed when selecting a suggestion 129875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // that modifies the contents of the text field. But if the user then edits 130875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // the suggestion, the resulting string is saved. 131875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen private String mUserQuery; 132875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 133875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // A weak map of drawables we've gotten from other packages, so we don't load them 134875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // more than once. 135dfefa3e915938aa1eeeaa7c0910a882bded7bcf7Bjorn Bringert private final WeakHashMap<String, Drawable.ConstantState> mOutsideDrawablesCache = 136dfefa3e915938aa1eeeaa7c0910a882bded7bcf7Bjorn Bringert new WeakHashMap<String, Drawable.ConstantState>(); 137662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath 138662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath // Last known IME options value for the search edit text. 139662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath private int mSearchAutoCompleteImeOptions; 140662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath 1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Constructor - fires it up and makes it look like the search UI. 1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param context Application Context we can use for system acess 1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 146e9ce3f01d42769f03f10e70c3244500e92d7eee1Amith Yamasani public SearchDialog(Context context, SearchManager searchManager) { 147479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani super(context, com.android.internal.R.style.Theme_SearchBar); 148f36740b2e4a9a187bf688c632c1d0a7ae926c96aBryan Mawhinney 149f36740b2e4a9a187bf688c632c1d0a7ae926c96aBryan Mawhinney // Save voice intent for later queries/launching 150f36740b2e4a9a187bf688c632c1d0a7ae926c96aBryan Mawhinney mVoiceWebSearchIntent = new Intent(RecognizerIntent.ACTION_WEB_SEARCH); 151f36740b2e4a9a187bf688c632c1d0a7ae926c96aBryan Mawhinney mVoiceWebSearchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 152f36740b2e4a9a187bf688c632c1d0a7ae926c96aBryan Mawhinney mVoiceWebSearchIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, 153f36740b2e4a9a187bf688c632c1d0a7ae926c96aBryan Mawhinney RecognizerIntent.LANGUAGE_MODEL_WEB_SEARCH); 154f36740b2e4a9a187bf688c632c1d0a7ae926c96aBryan Mawhinney 155f36740b2e4a9a187bf688c632c1d0a7ae926c96aBryan Mawhinney mVoiceAppSearchIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); 156f36740b2e4a9a187bf688c632c1d0a7ae926c96aBryan Mawhinney mVoiceAppSearchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 157e9ce3f01d42769f03f10e70c3244500e92d7eee1Amith Yamasani mSearchManager = searchManager; 1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 161f36740b2e4a9a187bf688c632c1d0a7ae926c96aBryan Mawhinney * Create the search dialog and any resources that are used for the 162f36740b2e4a9a187bf688c632c1d0a7ae926c96aBryan Mawhinney * entire lifetime of the dialog. 1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected void onCreate(Bundle savedInstanceState) { 1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super.onCreate(savedInstanceState); 1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1688d17f3f24bbda9a9cd7ea08c5925508dc2c011beBjorn Bringert Window theWindow = getWindow(); 1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project WindowManager.LayoutParams lp = theWindow.getAttributes(); 170980a938c1c9a6a5791a8240e5a1e6638ab28dc77Romain Guy lp.width = ViewGroup.LayoutParams.MATCH_PARENT; 1718d17f3f24bbda9a9cd7ea08c5925508dc2c011beBjorn Bringert // taking up the whole window (even when transparent) is less than ideal, 1728d17f3f24bbda9a9cd7ea08c5925508dc2c011beBjorn Bringert // but necessary to show the popup window until the window manager supports 1738d17f3f24bbda9a9cd7ea08c5925508dc2c011beBjorn Bringert // having windows anchored by their parent but not clipped by them. 174980a938c1c9a6a5791a8240e5a1e6638ab28dc77Romain Guy lp.height = ViewGroup.LayoutParams.MATCH_PARENT; 1758d17f3f24bbda9a9cd7ea08c5925508dc2c011beBjorn Bringert lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL; 17698acd54fa6657e8131b3a2a957de7882a2f511abMike LeBeau lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; 1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project theWindow.setAttributes(lp); 1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 179f36740b2e4a9a187bf688c632c1d0a7ae926c96aBryan Mawhinney // Touching outside of the search dialog will dismiss it 180f36740b2e4a9a187bf688c632c1d0a7ae926c96aBryan Mawhinney setCanceledOnTouchOutside(true); 181f36740b2e4a9a187bf688c632c1d0a7ae926c96aBryan Mawhinney } 182f36740b2e4a9a187bf688c632c1d0a7ae926c96aBryan Mawhinney 183f36740b2e4a9a187bf688c632c1d0a7ae926c96aBryan Mawhinney /** 184f36740b2e4a9a187bf688c632c1d0a7ae926c96aBryan Mawhinney * We recreate the dialog view each time it becomes visible so as to limit 185f36740b2e4a9a187bf688c632c1d0a7ae926c96aBryan Mawhinney * the scope of any problems with the contained resources. 186f36740b2e4a9a187bf688c632c1d0a7ae926c96aBryan Mawhinney */ 187f36740b2e4a9a187bf688c632c1d0a7ae926c96aBryan Mawhinney private void createContentView() { 188f36740b2e4a9a187bf688c632c1d0a7ae926c96aBryan Mawhinney setContentView(com.android.internal.R.layout.search_bar); 189f36740b2e4a9a187bf688c632c1d0a7ae926c96aBryan Mawhinney 1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // get the view elements for local access 191077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert SearchBar searchBar = (SearchBar) findViewById(com.android.internal.R.id.search_bar); 192077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert searchBar.setSearchDialog(this); 193077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert 1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mBadgeLabel = (TextView) findViewById(com.android.internal.R.id.search_badge); 195875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mSearchAutoComplete = (SearchAutoComplete) 1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project findViewById(com.android.internal.R.id.search_src_text); 197da5c1bd4443b5b569a0d392cd53b476b4e160c47Bjorn Bringert mAppIcon = (ImageView) findViewById(com.android.internal.R.id.search_app_icon); 1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mGoButton = (Button) findViewById(com.android.internal.R.id.search_go_btn); 1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mVoiceButton = (ImageButton) findViewById(com.android.internal.R.id.search_voice_btn); 200875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mSearchPlate = findViewById(com.android.internal.R.id.search_plate); 201f4f7046183f0daedd17703fa16cf9026442bdaeeRomain Guy mWorkingSpinner = getContext().getResources(). 2021480eb27f5321ef5fc2faeee87c7464e279a4912Mike LeBeau getDrawable(com.android.internal.R.drawable.search_spinner); 203dfcbc046d7fcd74c8aacd9f26bd48084900d3b4aBryan Mawhinney mSearchAutoComplete.setCompoundDrawablesWithIntrinsicBounds( 204dfcbc046d7fcd74c8aacd9f26bd48084900d3b4aBryan Mawhinney null, null, mWorkingSpinner, null); 205dfcbc046d7fcd74c8aacd9f26bd48084900d3b4aBryan Mawhinney setWorking(false); 206dfcbc046d7fcd74c8aacd9f26bd48084900d3b4aBryan Mawhinney 2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // attach listeners 208875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mSearchAutoComplete.addTextChangedListener(mTextWatcher); 209875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mSearchAutoComplete.setOnKeyListener(mTextKeyListener); 210875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mSearchAutoComplete.setOnItemClickListener(this); 211875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mSearchAutoComplete.setOnItemSelectedListener(this); 2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mGoButton.setOnClickListener(mGoButtonClickListener); 2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mGoButton.setOnKeyListener(mButtonsKeyListener); 2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mVoiceButton.setOnClickListener(mVoiceButtonClickListener); 2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mVoiceButton.setOnKeyListener(mButtonsKeyListener); 2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // pre-hide all the extraneous elements 2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mBadgeLabel.setVisibility(View.GONE); 2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Additional adjustments to make Dialog work for Search 221662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath mSearchAutoCompleteImeOptions = mSearchAutoComplete.getImeOptions(); 2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Set up the search dialog 2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 227875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * @return true if search dialog launched, false if not 2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean show(String initialQuery, boolean selectInitialQuery, 230479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani ComponentName componentName, Bundle appSearchData) { 231479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani boolean success = doShow(initialQuery, selectInitialQuery, componentName, appSearchData); 232fef8d3e4d8f6f46c098d04b3a57409c947ec1c75Satish Sampath if (success) { 233fef8d3e4d8f6f46c098d04b3a57409c947ec1c75Satish Sampath // Display the drop down as soon as possible instead of waiting for the rest of the 234fef8d3e4d8f6f46c098d04b3a57409c947ec1c75Satish Sampath // pending UI stuff to get done, so that things appear faster to the user. 235fef8d3e4d8f6f46c098d04b3a57409c947ec1c75Satish Sampath mSearchAutoComplete.showDropDownAfterLayout(); 236fef8d3e4d8f6f46c098d04b3a57409c947ec1c75Satish Sampath } 237fef8d3e4d8f6f46c098d04b3a57409c947ec1c75Satish Sampath return success; 238b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau } 239da1f4b669ead7813079643b43301f100127aaeedBjorn Bringert 240b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau /** 241479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani * Does the rest of the work required to show the search dialog. Called by 242479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani * {@link #show(String, boolean, ComponentName, Bundle)} and 243479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani * 244b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau * @return true if search dialog showed, false if not 245b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau */ 246b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau private boolean doShow(String initialQuery, boolean selectInitialQuery, 247479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani ComponentName componentName, Bundle appSearchData) { 248875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // set up the searchable and show the dialog 249479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani if (!show(componentName, appSearchData)) { 250875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return false; 251875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 252b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau 253875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // finally, load the user's initial text (which may trigger suggestions) 254875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen setUserQuery(initialQuery); 255875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (selectInitialQuery) { 256875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mSearchAutoComplete.selectAll(); 257875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 258b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau 259875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return true; 260875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 261b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau 262875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen /** 263875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * Sets up the search dialog and shows it. 264875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * 265875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * @return <code>true</code> if search dialog launched 266875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen */ 267479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani private boolean show(ComponentName componentName, Bundle appSearchData) { 268875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 269875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (DBG) { 270875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen Log.d(LOG_TAG, "show(" + componentName + ", " 271479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani + appSearchData + ")"); 2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 273875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 2748d1538237847baf381787b881141f8c0478bef5bBjorn Bringert SearchManager searchManager = (SearchManager) 2758d1538237847baf381787b881141f8c0478bef5bBjorn Bringert mContext.getSystemService(Context.SEARCH_SERVICE); 276479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani // Try to get the searchable info for the provided component. 277479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani mSearchable = searchManager.getSearchableInfo(componentName, false); 278ee716fa2b03666622a73f8cc54dae4afd091353dBjorn Bringert 279ee716fa2b03666622a73f8cc54dae4afd091353dBjorn Bringert if (mSearchable == null) { 280ee716fa2b03666622a73f8cc54dae4afd091353dBjorn Bringert return false; 281ee716fa2b03666622a73f8cc54dae4afd091353dBjorn Bringert } 282ee716fa2b03666622a73f8cc54dae4afd091353dBjorn Bringert 2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLaunchComponent = componentName; 2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mAppSearchData = appSearchData; 285875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mActivityContext = mSearchable.getActivityContext(getContext()); 286f36740b2e4a9a187bf688c632c1d0a7ae926c96aBryan Mawhinney 287875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // show the dialog. this will call onStart(). 28811f09bb5cd45a76ae7757b6f20807e836c3692f8Bjorn Bringert if (!isShowing()) { 28911f09bb5cd45a76ae7757b6f20807e836c3692f8Bjorn Bringert // Recreate the search bar view every time the dialog is shown, to get rid 29011f09bb5cd45a76ae7757b6f20807e836c3692f8Bjorn Bringert // of any bad state in the AutoCompleteTextView etc 29111f09bb5cd45a76ae7757b6f20807e836c3692f8Bjorn Bringert createContentView(); 29211f09bb5cd45a76ae7757b6f20807e836c3692f8Bjorn Bringert 293875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen show(); 2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 295875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen updateUI(); 2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The search dialog is being dismissed, so handle all of the local shutdown operations. 3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This function is designed to be idempotent so that dismiss() can be safely called at any time 3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * (even if already closed) and more likely to really dump any memory. No leaks! 3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onStop() { 3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super.onStop(); 309444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringert 310875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen closeSuggestionsAdapter(); 3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // dump extra memory we're hanging on to 3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLaunchComponent = null; 3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mAppSearchData = null; 3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSearchable = null; 3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mActivityContext = null; 3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mUserQuery = null; 318875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 3191c6907515134c8a2e086d2eed4427f909d301935Mike LeBeau 3201c6907515134c8a2e086d2eed4427f909d301935Mike LeBeau /** 3211480eb27f5321ef5fc2faeee87c7464e279a4912Mike LeBeau * Sets the search dialog to the 'working' state, which shows a working spinner in the 3221480eb27f5321ef5fc2faeee87c7464e279a4912Mike LeBeau * right hand size of the text field. 3231480eb27f5321ef5fc2faeee87c7464e279a4912Mike LeBeau * 3241480eb27f5321ef5fc2faeee87c7464e279a4912Mike LeBeau * @param working true to show spinner, false to hide spinner 3251480eb27f5321ef5fc2faeee87c7464e279a4912Mike LeBeau */ 3261480eb27f5321ef5fc2faeee87c7464e279a4912Mike LeBeau public void setWorking(boolean working) { 327dfcbc046d7fcd74c8aacd9f26bd48084900d3b4aBryan Mawhinney mWorkingSpinner.setAlpha(working ? 255 : 0); 328dfcbc046d7fcd74c8aacd9f26bd48084900d3b4aBryan Mawhinney mWorkingSpinner.setVisible(working, false); 329dfcbc046d7fcd74c8aacd9f26bd48084900d3b4aBryan Mawhinney mWorkingSpinner.invalidateSelf(); 3301480eb27f5321ef5fc2faeee87c7464e279a4912Mike LeBeau } 331479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani 3321480eb27f5321ef5fc2faeee87c7464e279a4912Mike LeBeau /** 333875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * Closes and gets rid of the suggestions adapter. 334875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen */ 335875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen private void closeSuggestionsAdapter() { 336875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // remove the adapter from the autocomplete first, to avoid any updates 337875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // when we drop the cursor 338875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mSearchAutoComplete.setAdapter((SuggestionsAdapter)null); 339875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // close any leftover cursor 340875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (mSuggestionsAdapter != null) { 341ba223760895e62ad2fcb85476984cb29018860c9Bjorn Bringert mSuggestionsAdapter.close(); 342875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 343875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mSuggestionsAdapter = null; 3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 345479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani 3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Save the minimal set of data necessary to recreate the search 3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 349444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringert * @return A bundle with the state of the dialog, or {@code null} if the search 350444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringert * dialog is not showing. 3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Bundle onSaveInstanceState() { 354444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringert if (!isShowing()) return null; 355444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringert 3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Bundle bundle = new Bundle(); 357444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringert 3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // setup info so I can recreate this particular search 3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bundle.putParcelable(INSTANCE_KEY_COMPONENT, mLaunchComponent); 3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bundle.putBundle(INSTANCE_KEY_APPDATA, mAppSearchData); 361b0ae27f4e10a9e5fe56b9ca549718051fe342bbaBjorn Bringert bundle.putString(INSTANCE_KEY_USER_QUERY, mUserQuery); 362b0ae27f4e10a9e5fe56b9ca549718051fe342bbaBjorn Bringert 3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return bundle; 3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Restore the state of the dialog from a previously saved bundle. 368875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * 369875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * TODO: go through this and make sure that it saves everything that is saved 3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param savedInstanceState The state of the dialog previously saved by 3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link #onSaveInstanceState()}. 3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onRestoreInstanceState(Bundle savedInstanceState) { 376444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringert if (savedInstanceState == null) return; 377444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringert 3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ComponentName launchComponent = savedInstanceState.getParcelable(INSTANCE_KEY_COMPONENT); 3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Bundle appSearchData = savedInstanceState.getBundle(INSTANCE_KEY_APPDATA); 380b0ae27f4e10a9e5fe56b9ca549718051fe342bbaBjorn Bringert String userQuery = savedInstanceState.getString(INSTANCE_KEY_USER_QUERY); 381b0ae27f4e10a9e5fe56b9ca549718051fe342bbaBjorn Bringert 382b0ae27f4e10a9e5fe56b9ca549718051fe342bbaBjorn Bringert // show the dialog. 383479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani if (!doShow(userQuery, false, launchComponent, appSearchData)) { 3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // for some reason, we couldn't re-instantiate 3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 3869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 390875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * Called after resources have changed, e.g. after screen rotation or locale change. 3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 392444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringert public void onConfigurationChanged() { 393479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani if (mSearchable != null && isShowing()) { 3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Redraw (resources may have changed) 3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project updateSearchButton(); 3961fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau updateSearchAppIcon(); 3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project updateSearchBadge(); 3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project updateQueryHint(); 39929d52e120f36b46d7ef596b1c182db52d3476be7Bryan Mawhinney mSearchAutoComplete.showDropDownAfterLayout(); 4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 402875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 404875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * Update the UI according to the info in the current value of {@link #mSearchable}. 4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 406875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen private void updateUI() { 4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mSearchable != null) { 408ea52d29bc46c306f3607d121aa1ad84f0e9eb473Karl Rosaen mDecor.setVisibility(View.VISIBLE); 409875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen updateSearchAutoComplete(); 4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project updateSearchButton(); 4111fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau updateSearchAppIcon(); 4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project updateSearchBadge(); 4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project updateQueryHint(); 4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project updateVoiceButton(); 4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // In order to properly configure the input method (if one is being used), we 4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // need to let it know if we'll be providing suggestions. Although it would be 4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // difficult/expensive to know if every last detail has been configured properly, we 4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // can at least see if a suggestions provider has been configured, and use that 4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // as our trigger. 4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int inputType = mSearchable.getInputType(); 4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // We only touch this if the input type is set up for text (which it almost certainly 4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // should be, in the case of search!) 4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if ((inputType & InputType.TYPE_MASK_CLASS) == InputType.TYPE_CLASS_TEXT) { 4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // The existence of a suggestions authority is the proxy for "suggestions 4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // are available here" 4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project inputType &= ~InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE; 4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mSearchable.getSuggestAuthority() != null) { 4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project inputType |= InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE; 4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 432875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mSearchAutoComplete.setInputType(inputType); 433662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath mSearchAutoCompleteImeOptions = mSearchable.getImeOptions(); 434662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath mSearchAutoComplete.setImeOptions(mSearchAutoCompleteImeOptions); 4357df846186d29ddfa4a567deddd04ad1043d32fd8Mike LeBeau 4367df846186d29ddfa4a567deddd04ad1043d32fd8Mike LeBeau // If the search dialog is going to show a voice search button, then don't let 4377df846186d29ddfa4a567deddd04ad1043d32fd8Mike LeBeau // the soft keyboard display a microphone button if it would have otherwise. 4387df846186d29ddfa4a567deddd04ad1043d32fd8Mike LeBeau if (mSearchable.getVoiceSearchEnabled()) { 4397df846186d29ddfa4a567deddd04ad1043d32fd8Mike LeBeau mSearchAutoComplete.setPrivateImeOptions(IME_OPTION_NO_MICROPHONE); 4407df846186d29ddfa4a567deddd04ad1043d32fd8Mike LeBeau } else { 4417df846186d29ddfa4a567deddd04ad1043d32fd8Mike LeBeau mSearchAutoComplete.setPrivateImeOptions(null); 4427df846186d29ddfa4a567deddd04ad1043d32fd8Mike LeBeau } 4439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 445875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 4469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 447875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * Updates the auto-complete text view. 4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 449875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen private void updateSearchAutoComplete() { 450875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // close any existing suggestions adapter 451875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen closeSuggestionsAdapter(); 452875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 453875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mSearchAutoComplete.setDropDownAnimationStyle(0); // no animation 454203464af9638e4d5aecd811452af67fff9aa3087Bjorn Bringert mSearchAutoComplete.setThreshold(mSearchable.getSuggestThreshold()); 4558d17f3f24bbda9a9cd7ea08c5925508dc2c011beBjorn Bringert // we dismiss the entire dialog instead 4568d17f3f24bbda9a9cd7ea08c5925508dc2c011beBjorn Bringert mSearchAutoComplete.setDropDownDismissedOnCompletion(false); 457875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 458d4760d77e7e8ab66af0307dcae39e0a8e9d90a14Mike LeBeau mSearchAutoComplete.setForceIgnoreOutsideTouch(true); 459d4760d77e7e8ab66af0307dcae39e0a8e9d90a14Mike LeBeau 460875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // attach the suggestions adapter, if suggestions are available 461875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // The existence of a suggestions authority is the proxy for "suggestions available here" 462875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (mSearchable.getSuggestAuthority() != null) { 4631480eb27f5321ef5fc2faeee87c7464e279a4912Mike LeBeau mSuggestionsAdapter = new SuggestionsAdapter(getContext(), this, mSearchable, 464479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani mOutsideDrawablesCache); 465875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mSearchAutoComplete.setAdapter(mSuggestionsAdapter); 466875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 468875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 4699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 4709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Update the text in the search button. Note: This is deprecated functionality, for 4719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1.0 compatibility only. 4729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void updateSearchButton() { 4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String textLabel = null; 4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Drawable iconLabel = null; 4769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int textId = mSearchable.getSearchButtonText(); 4779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (textId != 0) { 4789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project textLabel = mActivityContext.getResources().getString(textId); 4799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 4809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project iconLabel = getContext().getResources(). 4819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project getDrawable(com.android.internal.R.drawable.ic_btn_search); 4829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 483875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mGoButton.setText(textLabel); 4849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mGoButton.setCompoundDrawablesWithIntrinsicBounds(iconLabel, null, null, null); 4859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4871fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau private void updateSearchAppIcon() { 4885a7d752b65edc83abc1eeef462b8bf01038ebdffMike LeBeau // In Donut, we special-case the case of the browser to hide the app icon as if it were 4895a7d752b65edc83abc1eeef462b8bf01038ebdffMike LeBeau // global search, for extra space for url entry. 4905a7d752b65edc83abc1eeef462b8bf01038ebdffMike LeBeau // 4915a7d752b65edc83abc1eeef462b8bf01038ebdffMike LeBeau // TODO: Remove this special case once the issue has been reconciled in Eclair. 492479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani if (isBrowserSearch()) { 493da5c1bd4443b5b569a0d392cd53b476b4e160c47Bjorn Bringert mAppIcon.setImageResource(0); 494da5c1bd4443b5b569a0d392cd53b476b4e160c47Bjorn Bringert mAppIcon.setVisibility(View.GONE); 4951fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau mSearchPlate.setPadding(SEARCH_PLATE_LEFT_PADDING_GLOBAL, 4961fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau mSearchPlate.getPaddingTop(), 4971fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau mSearchPlate.getPaddingRight(), 4981fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau mSearchPlate.getPaddingBottom()); 4991fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau } else { 5001fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau PackageManager pm = getContext().getPackageManager(); 501f4f7046183f0daedd17703fa16cf9026442bdaeeRomain Guy Drawable icon; 5021fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau try { 5031fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau ActivityInfo info = pm.getActivityInfo(mLaunchComponent, 0); 5041fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau icon = pm.getApplicationIcon(info.applicationInfo); 5051fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau if (DBG) Log.d(LOG_TAG, "Using app-specific icon"); 5061fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau } catch (NameNotFoundException e) { 5071fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau icon = pm.getDefaultActivityIcon(); 5081fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau Log.w(LOG_TAG, mLaunchComponent + " not found, using generic app icon"); 5091fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau } 510da5c1bd4443b5b569a0d392cd53b476b4e160c47Bjorn Bringert mAppIcon.setImageDrawable(icon); 511da5c1bd4443b5b569a0d392cd53b476b4e160c47Bjorn Bringert mAppIcon.setVisibility(View.VISIBLE); 5121fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau mSearchPlate.setPadding(SEARCH_PLATE_LEFT_PADDING_NON_GLOBAL, 5131fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau mSearchPlate.getPaddingTop(), 5141fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau mSearchPlate.getPaddingRight(), 5151fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau mSearchPlate.getPaddingBottom()); 5161fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau } 5171fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau } 5181fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau 5199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 520875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * Setup the search "Badge" if requested by mode flags. 5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void updateSearchBadge() { 5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // assume both hidden 5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int visibility = View.GONE; 5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Drawable icon = null; 526875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen CharSequence text = null; 5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // optionally show one or the other. 529a92041306e4d73baa10fb711fb905b9590f06b26Bjorn Bringert if (mSearchable.useBadgeIcon()) { 5309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project icon = mActivityContext.getResources().getDrawable(mSearchable.getIconId()); 5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project visibility = View.VISIBLE; 532875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (DBG) Log.d(LOG_TAG, "Using badge icon: " + mSearchable.getIconId()); 533a92041306e4d73baa10fb711fb905b9590f06b26Bjorn Bringert } else if (mSearchable.useBadgeLabel()) { 5349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project text = mActivityContext.getResources().getText(mSearchable.getLabelId()).toString(); 5359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project visibility = View.VISIBLE; 536875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (DBG) Log.d(LOG_TAG, "Using badge label: " + mSearchable.getLabelId()); 5379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mBadgeLabel.setCompoundDrawablesWithIntrinsicBounds(icon, null, null, null); 5409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mBadgeLabel.setText(text); 5419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mBadgeLabel.setVisibility(visibility); 5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 5459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Update the hint in the query text field. 5469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void updateQueryHint() { 5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (isShowing()) { 5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String hint = null; 5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mSearchable != null) { 5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int hintId = mSearchable.getHintId(); 5529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (hintId != 0) { 5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project hint = mActivityContext.getString(hintId); 5549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 556875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mSearchAutoComplete.setHint(hint); 5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 5619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Update the visibility of the voice button. There are actually two voice search modes, 5629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * either of which will activate the button. 5639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void updateVoiceButton() { 5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int visibility = View.GONE; 5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mSearchable.getVoiceSearchEnabled()) { 5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Intent testIntent = null; 5689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mSearchable.getVoiceSearchLaunchWebSearch()) { 5699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project testIntent = mVoiceWebSearchIntent; 5709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (mSearchable.getVoiceSearchLaunchRecognizer()) { 5719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project testIntent = mVoiceAppSearchIntent; 5729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (testIntent != null) { 5749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ResolveInfo ri = getContext().getPackageManager(). 5759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project resolveActivity(testIntent, PackageManager.MATCH_DEFAULT_ONLY); 5769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (ri != null) { 5779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project visibility = View.VISIBLE; 5789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mVoiceButton.setVisibility(visibility); 5829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5835a7d752b65edc83abc1eeef462b8bf01038ebdffMike LeBeau 5845a7d752b65edc83abc1eeef462b8bf01038ebdffMike LeBeau /** 5855a7d752b65edc83abc1eeef462b8bf01038ebdffMike LeBeau * Hack to determine whether this is the browser, so we can remove the browser icon 586479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani * to the left of the search field. 5875a7d752b65edc83abc1eeef462b8bf01038ebdffMike LeBeau */ 5885a7d752b65edc83abc1eeef462b8bf01038ebdffMike LeBeau private boolean isBrowserSearch() { 5895a7d752b65edc83abc1eeef462b8bf01038ebdffMike LeBeau return mLaunchComponent.flattenToShortString().startsWith("com.android.browser/"); 5905a7d752b65edc83abc1eeef462b8bf01038ebdffMike LeBeau } 591f4acf39d99d105e1e4fc7c43fa54377bb2f262aeBjorn Bringert 592479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani /* 5939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Listeners of various types 5949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 597875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * {@link Dialog#onTouchEvent(MotionEvent)} will cancel the dialog only when the 598875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * touch is outside the window. But the window includes space for the drop-down, 599875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * so we also cancel on taps outside the search bar when the drop-down is not showing. 600875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen */ 601875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen @Override 602875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen public boolean onTouchEvent(MotionEvent event) { 603875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // cancel if the drop-down is not showing and the touch event was outside the search plate 604875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (!mSearchAutoComplete.isPopupShowing() && isOutOfBounds(mSearchPlate, event)) { 605875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (DBG) Log.d(LOG_TAG, "Pop-up not showing and outside of search plate."); 606875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen cancel(); 607875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return true; 608875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 609875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // Let Dialog handle events outside the window while the pop-up is showing. 610875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return super.onTouchEvent(event); 611875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 612875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 613875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen private boolean isOutOfBounds(View v, MotionEvent event) { 614875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen final int x = (int) event.getX(); 615875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen final int y = (int) event.getY(); 616875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen final int slop = ViewConfiguration.get(mContext).getScaledWindowTouchSlop(); 617875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return (x < -slop) || (y < -slop) 618875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen || (x > (v.getWidth()+slop)) 619875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen || (y > (v.getHeight()+slop)); 620875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 621875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 622875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen /** 6239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Dialog's OnKeyListener implements various search-specific functionality 6249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 6259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param keyCode This is the keycode of the typed key, and is the same value as 626875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * found in the KeyEvent parameter. 6279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param event The complete event record for the typed key 6289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 6299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return Return true if the event was handled here, or false if not. 6309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 6319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 6329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean onKeyDown(int keyCode, KeyEvent event) { 633875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (DBG) Log.d(LOG_TAG, "onKeyDown(" + keyCode + "," + event + ")"); 634ee716fa2b03666622a73f8cc54dae4afd091353dBjorn Bringert if (mSearchable == null) { 635ee716fa2b03666622a73f8cc54dae4afd091353dBjorn Bringert return false; 636ee716fa2b03666622a73f8cc54dae4afd091353dBjorn Bringert } 637ee716fa2b03666622a73f8cc54dae4afd091353dBjorn Bringert 638875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // if it's an action specified by the searchable activity, launch the 639875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // entered query with the action key 640875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen SearchableInfo.ActionKeyInfo actionKey = mSearchable.findActionKey(keyCode); 641a92041306e4d73baa10fb711fb905b9590f06b26Bjorn Bringert if ((actionKey != null) && (actionKey.getQueryActionMsg() != null)) { 642a92041306e4d73baa10fb711fb905b9590f06b26Bjorn Bringert launchQuerySearch(keyCode, actionKey.getQueryActionMsg()); 643875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return true; 644875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 64587d61f22e13e81550559c92f6cf6fb795a39d37fBjorn Bringert 64687d61f22e13e81550559c92f6cf6fb795a39d37fBjorn Bringert return super.onKeyDown(keyCode, event); 6479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 648479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani 6499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 6509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Callback to watch the textedit field for empty/non-empty 6519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 6529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private TextWatcher mTextWatcher = new TextWatcher() { 6539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 654875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen public void beforeTextChanged(CharSequence s, int start, int before, int after) { } 6559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onTextChanged(CharSequence s, int start, 6579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int before, int after) { 658875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (DBG_LOG_TIMING) { 6599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dbgLogTiming("onTextChanged()"); 6609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 661ee716fa2b03666622a73f8cc54dae4afd091353dBjorn Bringert if (mSearchable == null) { 662ee716fa2b03666622a73f8cc54dae4afd091353dBjorn Bringert return; 663ee716fa2b03666622a73f8cc54dae4afd091353dBjorn Bringert } 6649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project updateWidgetState(); 665875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (!mSearchAutoComplete.isPerformingCompletion()) { 666875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // The user changed the query, remember it. 667875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mUserQuery = s == null ? "" : s.toString(); 6689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 671662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath public void afterTextChanged(Editable s) { 672b06ea706530e6d19eb2a1a9a7ae6c5dd77d80af0Dianne Hackborn if (mSearchable == null) { 673b06ea706530e6d19eb2a1a9a7ae6c5dd77d80af0Dianne Hackborn return; 674b06ea706530e6d19eb2a1a9a7ae6c5dd77d80af0Dianne Hackborn } 675d21572cd446e56efe94689324107927ac2bffd2aSatish Sampath if (mSearchable.autoUrlDetect() && !mSearchAutoComplete.isPerformingCompletion()) { 676662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath // The user changed the query, check if it is a URL and if so change the search 677662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath // button in the soft keyboard to the 'Go' button. 678479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani int options = (mSearchAutoComplete.getImeOptions() & (~EditorInfo.IME_MASK_ACTION)) 679479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani | EditorInfo.IME_ACTION_GO; 680662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath if (options != mSearchAutoCompleteImeOptions) { 681662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath mSearchAutoCompleteImeOptions = options; 682662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath mSearchAutoComplete.setImeOptions(options); 683662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath // This call is required to update the soft keyboard UI with latest IME flags. 684662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath mSearchAutoComplete.setInputType(mSearchAutoComplete.getInputType()); 685662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath } 686662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath } 687662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath } 6889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 6899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 6919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Enable/Disable the cancel button based on edit text state (any text?) 6929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 6939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void updateWidgetState() { 6949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // enable the button if we have one or more non-space characters 695875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen boolean enabled = !mSearchAutoComplete.isEmpty(); 6969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mGoButton.setEnabled(enabled); 6979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mGoButton.setFocusable(enabled); 6989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 7019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * React to typing in the GO search button by refocusing to EditText. 7029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Continue typing the query. 7039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 7049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View.OnKeyListener mButtonsKeyListener = new View.OnKeyListener() { 7059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean onKey(View v, int keyCode, KeyEvent event) { 706875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // guard against possible race conditions 707875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (mSearchable == null) { 708875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return false; 709875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 710875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 711875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (!event.isSystem() && 712875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen (keyCode != KeyEvent.KEYCODE_DPAD_UP) && 713875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen (keyCode != KeyEvent.KEYCODE_DPAD_LEFT) && 714875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen (keyCode != KeyEvent.KEYCODE_DPAD_RIGHT) && 715875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen (keyCode != KeyEvent.KEYCODE_DPAD_CENTER)) { 716875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // restore focus and give key to EditText ... 717875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (mSearchAutoComplete.requestFocus()) { 718875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return mSearchAutoComplete.dispatchKeyEvent(event); 719875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 7209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 721875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 7229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 7239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 7259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 7279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * React to a click in the GO button by launching a search. 7289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 7299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View.OnClickListener mGoButtonClickListener = new View.OnClickListener() { 7309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onClick(View v) { 731875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // guard against possible race conditions 732875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (mSearchable == null) { 733875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return; 7349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 735875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen launchQuerySearch(); 7369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 7389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 7409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * React to a click in the voice search button. 7419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 7429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View.OnClickListener mVoiceButtonClickListener = new View.OnClickListener() { 7439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onClick(View v) { 744875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // guard against possible race conditions 745875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (mSearchable == null) { 746875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return; 747875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 7480f55b197aabf6e2a902c33217e9ed7fe58cdf9d4Amith Yamasani SearchableInfo searchable = mSearchable; 7490f55b197aabf6e2a902c33217e9ed7fe58cdf9d4Amith Yamasani // First stop the existing search before starting voice search, or else we'll end 7500f55b197aabf6e2a902c33217e9ed7fe58cdf9d4Amith Yamasani // up showing the search dialog again once we return to the app. 7510f55b197aabf6e2a902c33217e9ed7fe58cdf9d4Amith Yamasani cancel(); 7529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 7530f55b197aabf6e2a902c33217e9ed7fe58cdf9d4Amith Yamasani if (searchable.getVoiceSearchLaunchWebSearch()) { 7549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project getContext().startActivity(mVoiceWebSearchIntent); 7550f55b197aabf6e2a902c33217e9ed7fe58cdf9d4Amith Yamasani } else if (searchable.getVoiceSearchLaunchRecognizer()) { 756479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani Intent appSearchIntent = createVoiceAppSearchIntent(mVoiceAppSearchIntent, 757479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani searchable); 7589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project getContext().startActivity(appSearchIntent); 7599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (ActivityNotFoundException e) { 7619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Should not happen, since we check the availability of 7629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // voice search before showing the button. But just in case... 7639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.w(LOG_TAG, "Could not find voice search activity"); 7649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 7679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 7699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Create and return an Intent that can launch the voice search activity, perform a specific 7709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * voice transcription, and forward the results to the searchable activity. 7719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 7729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param baseIntent The voice app search intent to start from 7739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return A completely-configured intent ready to send to the voice search activity 7749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 775479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani private Intent createVoiceAppSearchIntent(Intent baseIntent, SearchableInfo searchable) { 776479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani ComponentName searchActivity = searchable.getSearchActivity(); 777260dfb5716eab1dfe9dcb93b3e658cefaad197f9Mike LeBeau 7789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // create the necessary intent to set up a search-and-forward operation 7799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // in the voice search system. We have to keep the bundle separate, 7809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // because it becomes immutable once it enters the PendingIntent 7819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Intent queryIntent = new Intent(Intent.ACTION_SEARCH); 782260dfb5716eab1dfe9dcb93b3e658cefaad197f9Mike LeBeau queryIntent.setComponent(searchActivity); 7839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project PendingIntent pending = PendingIntent.getActivity( 7849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project getContext(), 0, queryIntent, PendingIntent.FLAG_ONE_SHOT); 7859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Now set up the bundle that will be inserted into the pending intent 7879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // when it's time to do the search. We always build it here (even if empty) 7889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // because the voice search activity will always need to insert "QUERY" into 7899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // it anyway. 7909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Bundle queryExtras = new Bundle(); 7919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mAppSearchData != null) { 7929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project queryExtras.putBundle(SearchManager.APP_DATA, mAppSearchData); 7939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Now build the intent to launch the voice search. Add all necessary 7969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // extras to launch the voice recognizer, and then all the necessary extras 7979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // to forward the results to the searchable activity 7989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Intent voiceIntent = new Intent(baseIntent); 7999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Add all of the configuration options supplied by the searchable's metadata 8019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String languageModel = RecognizerIntent.LANGUAGE_MODEL_FREE_FORM; 8029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String prompt = null; 8039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String language = null; 8049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int maxResults = 1; 8059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Resources resources = mActivityContext.getResources(); 806479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani if (searchable.getVoiceLanguageModeId() != 0) { 807479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani languageModel = resources.getString(searchable.getVoiceLanguageModeId()); 8089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 809479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani if (searchable.getVoicePromptTextId() != 0) { 810479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani prompt = resources.getString(searchable.getVoicePromptTextId()); 8119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 812479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani if (searchable.getVoiceLanguageId() != 0) { 813479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani language = resources.getString(searchable.getVoiceLanguageId()); 8149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 815479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani if (searchable.getVoiceMaxResults() != 0) { 816479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani maxResults = searchable.getVoiceMaxResults(); 8179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project voiceIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, languageModel); 8199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project voiceIntent.putExtra(RecognizerIntent.EXTRA_PROMPT, prompt); 8209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project voiceIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, language); 8219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project voiceIntent.putExtra(RecognizerIntent.EXTRA_MAX_RESULTS, maxResults); 822c2fd9adf0e804edf530d1cfc805d0c20e8d42c8eMike LeBeau voiceIntent.putExtra(Recognition.EXTRA_CALLING_PACKAGE, 823260dfb5716eab1dfe9dcb93b3e658cefaad197f9Mike LeBeau searchActivity == null ? null : searchActivity.toShortString()); 8249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Add the values that configure forwarding the results 8269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project voiceIntent.putExtra(RecognizerIntent.EXTRA_RESULTS_PENDINGINTENT, pending); 8279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project voiceIntent.putExtra(RecognizerIntent.EXTRA_RESULTS_PENDINGINTENT_BUNDLE, queryExtras); 8289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return voiceIntent; 8309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 833662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath * Corrects http/https typo errors in the given url string, and if the protocol specifier was 834662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath * not present defaults to http. 835662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath * 836662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath * @param inUrl URL to check and fix 837662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath * @return fixed URL string. 838662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath */ 839662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath private String fixUrl(String inUrl) { 840662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath if (inUrl.startsWith("http://") || inUrl.startsWith("https://")) 841662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath return inUrl; 842662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath 843662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath if (inUrl.startsWith("http:") || inUrl.startsWith("https:")) { 844662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath if (inUrl.startsWith("http:/") || inUrl.startsWith("https:/")) { 845662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath inUrl = inUrl.replaceFirst("/", "//"); 846662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath } else { 847662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath inUrl = inUrl.replaceFirst(":", "://"); 848662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath } 849662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath } 850662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath 851662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath if (inUrl.indexOf("://") == -1) { 852662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath inUrl = "http://" + inUrl; 853662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath } 854662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath 855662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath return inUrl; 856662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath } 857662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath 858662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath /** 8599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * React to the user typing "enter" or other hardwired keys while typing in the search box. 8609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This handles these special keys while the edit box has focus. 8619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 8629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View.OnKeyListener mTextKeyListener = new View.OnKeyListener() { 8639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean onKey(View v, int keyCode, KeyEvent event) { 864875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // guard against possible race conditions 865875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (mSearchable == null) { 866875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return false; 8679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 869875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (DBG_LOG_TIMING) dbgLogTiming("doTextKey()"); 870875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (DBG) { 871875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen Log.d(LOG_TAG, "mTextListener.onKey(" + keyCode + "," + event 872875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen + "), selection: " + mSearchAutoComplete.getListSelection()); 8739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 874875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 875875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // If a suggestion is selected, handle enter, search key, and action keys 876875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // as presses on the selected suggestion 877875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (mSearchAutoComplete.isPopupShowing() && 878875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mSearchAutoComplete.getListSelection() != ListView.INVALID_POSITION) { 879875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return onSuggestionsKey(v, keyCode, event); 8809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 881875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 882875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // If there is text in the query box, handle enter, and action keys 883875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // The search key is handled by the dialog's onKeyDown(). 884875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (!mSearchAutoComplete.isEmpty()) { 885875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (keyCode == KeyEvent.KEYCODE_ENTER 886875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen && event.getAction() == KeyEvent.ACTION_UP) { 887875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen v.cancelLongPress(); 888662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath 889b1665f2e15439f693b1ef75cb1c07593f99edde7Satish Sampath // If this is a url entered by the user & we displayed the 'Go' button which 890b1665f2e15439f693b1ef75cb1c07593f99edde7Satish Sampath // the user clicked, launch the url instead of using it as a search query. 891b1665f2e15439f693b1ef75cb1c07593f99edde7Satish Sampath if (mSearchable.autoUrlDetect() && 892b1665f2e15439f693b1ef75cb1c07593f99edde7Satish Sampath (mSearchAutoCompleteImeOptions & EditorInfo.IME_MASK_ACTION) 893d21572cd446e56efe94689324107927ac2bffd2aSatish Sampath == EditorInfo.IME_ACTION_GO) { 894b1665f2e15439f693b1ef75cb1c07593f99edde7Satish Sampath Uri uri = Uri.parse(fixUrl(mSearchAutoComplete.getText().toString())); 895b1665f2e15439f693b1ef75cb1c07593f99edde7Satish Sampath Intent intent = new Intent(Intent.ACTION_VIEW, uri); 896b1665f2e15439f693b1ef75cb1c07593f99edde7Satish Sampath intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 897b1665f2e15439f693b1ef75cb1c07593f99edde7Satish Sampath launchIntent(intent); 898b1665f2e15439f693b1ef75cb1c07593f99edde7Satish Sampath } else { 899b1665f2e15439f693b1ef75cb1c07593f99edde7Satish Sampath // Launch as a regular search. 900b1665f2e15439f693b1ef75cb1c07593f99edde7Satish Sampath launchQuerySearch(); 901662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath } 902875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return true; 903875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 904875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (event.getAction() == KeyEvent.ACTION_DOWN) { 905875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen SearchableInfo.ActionKeyInfo actionKey = mSearchable.findActionKey(keyCode); 906a92041306e4d73baa10fb711fb905b9590f06b26Bjorn Bringert if ((actionKey != null) && (actionKey.getQueryActionMsg() != null)) { 907a92041306e4d73baa10fb711fb905b9590f06b26Bjorn Bringert launchQuerySearch(keyCode, actionKey.getQueryActionMsg()); 908875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return true; 9099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 912875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return false; 9139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 9159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 916a8f556ee8cee24674663fd73c7a5b5a919b2d5bbDianne Hackborn @Override 917ea52d29bc46c306f3607d121aa1ad84f0e9eb473Karl Rosaen public void hide() { 918444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringert if (!isShowing()) return; 919444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringert 920a8f556ee8cee24674663fd73c7a5b5a919b2d5bbDianne Hackborn // We made sure the IME was displayed, so also make sure it is closed 921a8f556ee8cee24674663fd73c7a5b5a919b2d5bbDianne Hackborn // when we go away. 922a8f556ee8cee24674663fd73c7a5b5a919b2d5bbDianne Hackborn InputMethodManager imm = (InputMethodManager)getContext() 923a8f556ee8cee24674663fd73c7a5b5a919b2d5bbDianne Hackborn .getSystemService(Context.INPUT_METHOD_SERVICE); 924a8f556ee8cee24674663fd73c7a5b5a919b2d5bbDianne Hackborn if (imm != null) { 925a8f556ee8cee24674663fd73c7a5b5a919b2d5bbDianne Hackborn imm.hideSoftInputFromWindow( 926a8f556ee8cee24674663fd73c7a5b5a919b2d5bbDianne Hackborn getWindow().getDecorView().getWindowToken(), 0); 927a8f556ee8cee24674663fd73c7a5b5a919b2d5bbDianne Hackborn } 928ea52d29bc46c306f3607d121aa1ad84f0e9eb473Karl Rosaen 929ea52d29bc46c306f3607d121aa1ad84f0e9eb473Karl Rosaen super.hide(); 930a8f556ee8cee24674663fd73c7a5b5a919b2d5bbDianne Hackborn } 931ea52d29bc46c306f3607d121aa1ad84f0e9eb473Karl Rosaen 9329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 933875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * React to the user typing while in the suggestions list. First, check for action 934875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * keys. If not handled, try refocusing regular characters into the EditText. 9359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 936875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen private boolean onSuggestionsKey(View v, int keyCode, KeyEvent event) { 937875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // guard against possible race conditions (late arrival after dismiss) 938875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (mSearchable == null) { 939875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return false; 940875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 9419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mSuggestionsAdapter == null) { 9429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 9439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (event.getAction() == KeyEvent.ACTION_DOWN) { 945875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (DBG_LOG_TIMING) { 946875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen dbgLogTiming("onSuggestionsKey()"); 9479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // First, check for enter or search (both of which we'll treat as a "click") 9509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (keyCode == KeyEvent.KEYCODE_ENTER || keyCode == KeyEvent.KEYCODE_SEARCH) { 951875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen int position = mSearchAutoComplete.getListSelection(); 952875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return launchSuggestion(position); 9539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Next, check for left/right moves, which we use to "return" the user to the edit view 9569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT || keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) { 957875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // give "focus" to text editor, with cursor at the beginning if 958875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // left key, at end if right key 959875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // TODO: Reverse left/right for right-to-left languages, e.g. Arabic 9609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int selPoint = (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) ? 961875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 0 : mSearchAutoComplete.length(); 962875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mSearchAutoComplete.setSelection(selPoint); 963875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mSearchAutoComplete.setListSelection(0); 964875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mSearchAutoComplete.clearListSelection(); 965ffe3ecf2b1ee04288008758c0f60ae22238797c1Mike LeBeau mSearchAutoComplete.ensureImeVisible(); 966ffe3ecf2b1ee04288008758c0f60ae22238797c1Mike LeBeau 9679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 9689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Next, check for an "up and out" move 971875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (keyCode == KeyEvent.KEYCODE_DPAD_UP 972875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen && 0 == mSearchAutoComplete.getListSelection()) { 973875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen restoreUserQuery(); 9749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // let ACTV complete the move 9759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 9769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Next, check for an "action key" 9799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project SearchableInfo.ActionKeyInfo actionKey = mSearchable.findActionKey(keyCode); 9809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if ((actionKey != null) && 981a92041306e4d73baa10fb711fb905b9590f06b26Bjorn Bringert ((actionKey.getSuggestActionMsg() != null) || 982a92041306e4d73baa10fb711fb905b9590f06b26Bjorn Bringert (actionKey.getSuggestActionMsgColumn() != null))) { 983875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // launch suggestion using action key column 984875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen int position = mSearchAutoComplete.getListSelection(); 985875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (position != ListView.INVALID_POSITION) { 9869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Cursor c = mSuggestionsAdapter.getCursor(); 9879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (c.moveToPosition(position)) { 9889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final String actionMsg = getActionKeyMessage(c, actionKey); 9899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (actionMsg != null && (actionMsg.length() > 0)) { 990875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return launchSuggestion(position, keyCode, actionMsg); 9919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 997875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 998875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 999875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen /** 1000875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * Launch a search for the text in the query text field. 1001875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen */ 1002d2d6014f715f12f6263f61ba3eeb6f8cba6d0fa6krosaen public void launchQuerySearch() { 1003875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen launchQuerySearch(KeyEvent.KEYCODE_UNKNOWN, null); 1004875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 10059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1007875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * Launch a search for the text in the query text field. 1008875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * 1009875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * @param actionKey The key code of the action key that was pressed, 1010875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * or {@link KeyEvent#KEYCODE_UNKNOWN} if none. 1011875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * @param actionMsg The message for the action key that was pressed, 1012875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * or <code>null</code> if none. 1013875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen */ 1014875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen protected void launchQuerySearch(int actionKey, String actionMsg) { 1015875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen String query = mSearchAutoComplete.getText().toString(); 1016479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani String action = Intent.ACTION_SEARCH; 10174899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert Intent intent = createIntent(action, null, null, query, null, 1018479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani actionKey, actionMsg); 1019875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen launchIntent(intent); 1020875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 1021875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 1022875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen /** 1023875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * Launches an intent based on a suggestion. 10249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1025875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * @param position The index of the suggestion to create the intent from. 1026875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * @return true if a successful launch, false if could not (e.g. bad position). 10279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1028875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen protected boolean launchSuggestion(int position) { 1029875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return launchSuggestion(position, KeyEvent.KEYCODE_UNKNOWN, null); 1030875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 1031479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani 1032875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen /** 1033875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * Launches an intent based on a suggestion. 1034875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * 1035875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * @param position The index of the suggestion to create the intent from. 1036875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * @param actionKey The key code of the action key that was pressed, 1037875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * or {@link KeyEvent#KEYCODE_UNKNOWN} if none. 1038875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * @param actionMsg The message for the action key that was pressed, 1039875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * or <code>null</code> if none. 1040875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * @return true if a successful launch, false if could not (e.g. bad position). 1041875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen */ 1042875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen protected boolean launchSuggestion(int position, int actionKey, String actionMsg) { 1043875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen Cursor c = mSuggestionsAdapter.getCursor(); 1044875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if ((c != null) && c.moveToPosition(position)) { 1045a058f02b591d971a829cb1e28d48a992e46ad85eKarl Rosaen 1046875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen Intent intent = createIntentFromSuggestion(c, actionKey, actionMsg); 1047d4c98c4c450a95b67fe9746675984333b7653713Karl Rosaen 1048479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani // launch the intent 1049875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen launchIntent(intent); 1050a058f02b591d971a829cb1e28d48a992e46ad85eKarl Rosaen 1051875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return true; 1052875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 1053875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return false; 1054875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 1055a058f02b591d971a829cb1e28d48a992e46ad85eKarl Rosaen 1056875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen /** 1057e9ce3f01d42769f03f10e70c3244500e92d7eee1Amith Yamasani * Launches an intent, including any special intent handling. 1058875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen */ 1059875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen private void launchIntent(Intent intent) { 1060875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (intent == null) { 10619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 10629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1063ea52d29bc46c306f3607d121aa1ad84f0e9eb473Karl Rosaen Log.d(LOG_TAG, "launching " + intent); 10644899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert try { 1065479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani // If the intent was created from a suggestion, it will always have an explicit 1066479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani // component here. 1067479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani Log.i(LOG_TAG, "Starting (as ourselves) " + intent.toURI()); 1068479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani getContext().startActivity(intent); 1069479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani // If the search switches to a different activity, 1070479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani // SearchDialogWrapper#performActivityResuming 1071479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani // will handle hiding the dialog when the next activity starts, but for 1072479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani // real in-app search, we still need to dismiss the dialog. 1073479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani dismiss(); 10744899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert } catch (RuntimeException ex) { 10754899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert Log.e(LOG_TAG, "Failed launch activity: " + intent, ex); 10764899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert } 10774899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert } 1078876627d8c52300608c8c716f980a8686f43bf476Karl Rosaen 10794899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert /** 10804899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert * If the intent is to open an HTTP or HTTPS URL, we set 10814899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert * {@link Browser#EXTRA_APPLICATION_ID} so that any existing browser window that 10824899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert * has been opened by us for the same URL will be reused. 10834899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert */ 10844899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert private void setBrowserApplicationId(Intent intent) { 10854899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert Uri data = intent.getData(); 10864899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert if (Intent.ACTION_VIEW.equals(intent.getAction()) && data != null) { 10874899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert String scheme = data.getScheme(); 10884899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert if (scheme != null && scheme.startsWith("http")) { 10894899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert intent.putExtra(Browser.EXTRA_APPLICATION_ID, data.toString()); 10904899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert } 10914899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert } 10924899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert } 10934899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert 10944899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert /** 1095ae9760b62c400e3e7009d4a7b85e9524a5cd44fcMike LeBeau * Sets the list item selection in the AutoCompleteTextView's ListView. 1096ae9760b62c400e3e7009d4a7b85e9524a5cd44fcMike LeBeau */ 1097ae9760b62c400e3e7009d4a7b85e9524a5cd44fcMike LeBeau public void setListSelection(int index) { 1098ae9760b62c400e3e7009d4a7b85e9524a5cd44fcMike LeBeau mSearchAutoComplete.setListSelection(index); 1099ae9760b62c400e3e7009d4a7b85e9524a5cd44fcMike LeBeau } 1100a058f02b591d971a829cb1e28d48a992e46ad85eKarl Rosaen 1101ae9760b62c400e3e7009d4a7b85e9524a5cd44fcMike LeBeau /** 11029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * When a particular suggestion has been selected, perform the various lookups required 11039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * to use the suggestion. This includes checking the cursor for suggestion-specific data, 11049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * and/or falling back to the XML for defaults; It also creates REST style Uri data when 11059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the suggestion includes a data id. 11069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 11079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param c The suggestions cursor, moved to the row of the user's selection 1108875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * @param actionKey The key code of the action key that was pressed, 1109875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * or {@link KeyEvent#KEYCODE_UNKNOWN} if none. 1110875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * @param actionMsg The message for the action key that was pressed, 1111875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * or <code>null</code> if none. 1112875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * @return An intent for the suggestion at the cursor's position. 11139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1114875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen private Intent createIntentFromSuggestion(Cursor c, int actionKey, String actionMsg) { 11159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { 11169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // use specific action if supplied, or default action if supplied, or fixed default 1117875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen String action = getColumnString(c, SearchManager.SUGGEST_COLUMN_INTENT_ACTION); 1118a058f02b591d971a829cb1e28d48a992e46ad85eKarl Rosaen 1119a058f02b591d971a829cb1e28d48a992e46ad85eKarl Rosaen // some items are display only, or have effect via the cursor respond click reporting. 1120a058f02b591d971a829cb1e28d48a992e46ad85eKarl Rosaen if (SearchManager.INTENT_ACTION_NONE.equals(action)) { 1121a058f02b591d971a829cb1e28d48a992e46ad85eKarl Rosaen return null; 1122a058f02b591d971a829cb1e28d48a992e46ad85eKarl Rosaen } 1123a058f02b591d971a829cb1e28d48a992e46ad85eKarl Rosaen 1124875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (action == null) { 1125875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen action = mSearchable.getSuggestIntentAction(); 11269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1127875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (action == null) { 1128875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen action = Intent.ACTION_SEARCH; 11299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // use specific data if supplied, or default data if supplied 1132875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen String data = getColumnString(c, SearchManager.SUGGEST_COLUMN_INTENT_DATA); 11339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (data == null) { 1134875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen data = mSearchable.getSuggestIntentData(); 11359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // then, if an ID was provided, append it. 11379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (data != null) { 1138875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen String id = getColumnString(c, SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID); 1139875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (id != null) { 1140875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen data = data + "/" + Uri.encode(id); 11419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1143875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen Uri dataUri = (data == null) ? null : Uri.parse(data); 1144875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 1145bf23fe062ab4321143717c21827d329e087cc72fSatish Sampath String componentName = getColumnString( 1146bf23fe062ab4321143717c21827d329e087cc72fSatish Sampath c, SearchManager.SUGGEST_COLUMN_INTENT_COMPONENT_NAME); 1147a058f02b591d971a829cb1e28d48a992e46ad85eKarl Rosaen 1148875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen String query = getColumnString(c, SearchManager.SUGGEST_COLUMN_QUERY); 1149bf23fe062ab4321143717c21827d329e087cc72fSatish Sampath String extraData = getColumnString(c, SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA); 1150875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 1151bf23fe062ab4321143717c21827d329e087cc72fSatish Sampath return createIntent(action, dataUri, extraData, query, componentName, actionKey, 1152479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani actionMsg); 11539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (RuntimeException e ) { 11549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int rowNum; 11559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project try { // be really paranoid now 11569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project rowNum = c.getPosition(); 11579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } catch (RuntimeException e2 ) { 11589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project rowNum = -1; 11599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.w(LOG_TAG, "Search Suggestions cursor at row " + rowNum + 11619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project " returned exception" + e.toString()); 1162875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return null; 11639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 11659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 11669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1167875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * Constructs an intent from the given information and the search dialog state. 1168875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * 1169875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * @param action Intent action. 1170875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * @param data Intent data, or <code>null</code>. 1171875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * @param extraData Data for {@link SearchManager#EXTRA_DATA_KEY} or <code>null</code>. 1172bf23fe062ab4321143717c21827d329e087cc72fSatish Sampath * @param query Intent query, or <code>null</code>. 1173bf23fe062ab4321143717c21827d329e087cc72fSatish Sampath * @param componentName Data for {@link SearchManager#COMPONENT_NAME_KEY} or <code>null</code>. 1174875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * @param actionKey The key code of the action key that was pressed, 1175875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * or {@link KeyEvent#KEYCODE_UNKNOWN} if none. 1176875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * @param actionMsg The message for the action key that was pressed, 1177875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * or <code>null</code> if none. 1178be5b73c5926cbebd508d8323bdeaafa2e048a93cBjorn Bringert * @param mode The search mode, one of the acceptable values for 1179be5b73c5926cbebd508d8323bdeaafa2e048a93cBjorn Bringert * {@link SearchManager#SEARCH_MODE}, or {@code null}. 1180875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * @return The intent. 1181875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen */ 1182bf23fe062ab4321143717c21827d329e087cc72fSatish Sampath private Intent createIntent(String action, Uri data, String extraData, String query, 1183479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani String componentName, int actionKey, String actionMsg) { 1184875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // Now build the Intent 1185875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen Intent intent = new Intent(action); 11868d17f3f24bbda9a9cd7ea08c5925508dc2c011beBjorn Bringert intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 1187442da48b24f75e6075763b89943b513197a0bfe9Bjorn Bringert // We need CLEAR_TOP to avoid reusing an old task that has other activities 1188dc1396c881b80074c99d171aee02d3a5486180caEvan Millar // on top of the one we want. We don't want to do this in in-app search though, 1189dc1396c881b80074c99d171aee02d3a5486180caEvan Millar // as it can be destructive to the activity stack. 1190875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (data != null) { 1191875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen intent.setData(data); 1192875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 11935f80605a0b866f34c74955e190909bd6ab5d992eBjorn Bringert intent.putExtra(SearchManager.USER_QUERY, mUserQuery); 1194875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (query != null) { 1195875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen intent.putExtra(SearchManager.QUERY, query); 1196875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 1197875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (extraData != null) { 1198875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen intent.putExtra(SearchManager.EXTRA_DATA_KEY, extraData); 1199875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 1200875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (mAppSearchData != null) { 1201875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen intent.putExtra(SearchManager.APP_DATA, mAppSearchData); 1202875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 1203875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (actionKey != KeyEvent.KEYCODE_UNKNOWN) { 1204875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen intent.putExtra(SearchManager.ACTION_KEY, actionKey); 1205875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen intent.putExtra(SearchManager.ACTION_MSG, actionMsg); 1206875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 1207479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani intent.setComponent(mSearchable.getSearchActivity()); 1208875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return intent; 1209875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 1210479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani 1211875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen /** 12129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * For a given suggestion and a given cursor row, get the action message. If not provided 12139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * by the specific row/column, also check for a single definition (for the action key). 12149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 12159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param c The cursor providing suggestions 12169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param actionKey The actionkey record being examined 12179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 12189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return Returns a string, or null if no action key message for this suggestion 12199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1220875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen private static String getActionKeyMessage(Cursor c, SearchableInfo.ActionKeyInfo actionKey) { 12219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project String result = null; 12229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // check first in the cursor data, for a suggestion-specific message 1223a92041306e4d73baa10fb711fb905b9590f06b26Bjorn Bringert final String column = actionKey.getSuggestActionMsgColumn(); 12249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (column != null) { 1225875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen result = SuggestionsAdapter.getColumnString(c, column); 12269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // If the cursor didn't give us a message, see if there's a single message defined 12289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // for the actionkey (for all suggestions) 12299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (result == null) { 1230a92041306e4d73baa10fb711fb905b9590f06b26Bjorn Bringert result = actionKey.getSuggestActionMsg(); 12319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return result; 12339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1234077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert 1235077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert /** 1236077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert * The root element in the search bar layout. This is a custom view just to override 1237077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert * the handling of the back button. 1238077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert */ 1239077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert public static class SearchBar extends LinearLayout { 1240077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert 1241077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert private SearchDialog mSearchDialog; 1242077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert 1243077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert public SearchBar(Context context, AttributeSet attrs) { 1244077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert super(context, attrs); 1245077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert } 1246077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert 1247077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert public SearchBar(Context context) { 1248077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert super(context); 1249077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert } 1250077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert 1251077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert public void setSearchDialog(SearchDialog searchDialog) { 1252077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert mSearchDialog = searchDialog; 1253077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert } 1254077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert 1255077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert /** 1256077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert * Overrides the handling of the back key to move back to the previous sources or dismiss 1257077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert * the search dialog, instead of dismissing the input method. 1258077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert */ 1259077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert @Override 1260077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert public boolean dispatchKeyEventPreIme(KeyEvent event) { 1261077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert if (DBG) Log.d(LOG_TAG, "onKeyPreIme(" + event + ")"); 1262077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert if (mSearchDialog != null && event.getKeyCode() == KeyEvent.KEYCODE_BACK) { 12635b6b41241d97ca6c08b610a421b758815a451803Bjorn Bringert KeyEvent.DispatcherState state = getKeyDispatcherState(); 12645b6b41241d97ca6c08b610a421b758815a451803Bjorn Bringert if (state != null) { 12655b6b41241d97ca6c08b610a421b758815a451803Bjorn Bringert if (event.getAction() == KeyEvent.ACTION_DOWN 12665b6b41241d97ca6c08b610a421b758815a451803Bjorn Bringert && event.getRepeatCount() == 0) { 12675b6b41241d97ca6c08b610a421b758815a451803Bjorn Bringert state.startTracking(event, this); 12685b6b41241d97ca6c08b610a421b758815a451803Bjorn Bringert return true; 12695b6b41241d97ca6c08b610a421b758815a451803Bjorn Bringert } else if (event.getAction() == KeyEvent.ACTION_UP 12705b6b41241d97ca6c08b610a421b758815a451803Bjorn Bringert && !event.isCanceled() && state.isTracking(event)) { 12715b6b41241d97ca6c08b610a421b758815a451803Bjorn Bringert mSearchDialog.onBackPressed(); 12725b6b41241d97ca6c08b610a421b758815a451803Bjorn Bringert return true; 12735b6b41241d97ca6c08b610a421b758815a451803Bjorn Bringert } 1274077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert } 1275077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert } 1276077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert return super.dispatchKeyEventPreIme(event); 1277077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert } 1278077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert } 1279077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert 12809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1281875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * Local subclass for AutoCompleteTextView. 12829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 12839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static class SearchAutoComplete extends AutoCompleteTextView { 12849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1285875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen private int mThreshold; 1286077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert 12879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public SearchAutoComplete(Context context) { 12881746d6fefcb1b4869f475a81f5aec35db4695603Marco Nelissen super(context); 1289875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mThreshold = getThreshold(); 12909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public SearchAutoComplete(Context context, AttributeSet attrs) { 12939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super(context, attrs); 1294875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mThreshold = getThreshold(); 12959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 12969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 12979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public SearchAutoComplete(Context context, AttributeSet attrs, int defStyle) { 12989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super(context, attrs, defStyle); 1299875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mThreshold = getThreshold(); 13009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1301875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 13029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 1303875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen public void setThreshold(int threshold) { 1304875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen super.setThreshold(threshold); 1305875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mThreshold = threshold; 13069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1309875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * Returns true if the text field is empty, or contains only whitespace. 13109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1311875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen private boolean isEmpty() { 1312875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return TextUtils.getTrimmedLength(getText()) == 0; 13139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13148d17f3f24bbda9a9cd7ea08c5925508dc2c011beBjorn Bringert 13159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1316875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * We override this method to avoid replacing the query box text 1317875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * when a suggestion is clicked. 13189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 13199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 1320875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen protected void replaceText(CharSequence text) { 13219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1324617202a53a26d1b38a41ce69c40b1fffd784c178Mike LeBeau * We override this method to avoid an extra onItemClick being called on the 1325617202a53a26d1b38a41ce69c40b1fffd784c178Mike LeBeau * drop-down's OnItemClickListener by {@link AutoCompleteTextView#onKeyUp(int, KeyEvent)} 1326617202a53a26d1b38a41ce69c40b1fffd784c178Mike LeBeau * when an item is clicked with the trackball. 1327617202a53a26d1b38a41ce69c40b1fffd784c178Mike LeBeau */ 1328617202a53a26d1b38a41ce69c40b1fffd784c178Mike LeBeau @Override 1329617202a53a26d1b38a41ce69c40b1fffd784c178Mike LeBeau public void performCompletion() { 1330617202a53a26d1b38a41ce69c40b1fffd784c178Mike LeBeau } 13311fffbd97fa756ef7d3e7e885a5c1c8bb64380c20Mike LeBeau 13321fffbd97fa756ef7d3e7e885a5c1c8bb64380c20Mike LeBeau /** 13331fffbd97fa756ef7d3e7e885a5c1c8bb64380c20Mike LeBeau * We override this method to be sure and show the soft keyboard if appropriate when 13341fffbd97fa756ef7d3e7e885a5c1c8bb64380c20Mike LeBeau * the TextView has focus. 13351fffbd97fa756ef7d3e7e885a5c1c8bb64380c20Mike LeBeau */ 13361fffbd97fa756ef7d3e7e885a5c1c8bb64380c20Mike LeBeau @Override 13371fffbd97fa756ef7d3e7e885a5c1c8bb64380c20Mike LeBeau public void onWindowFocusChanged(boolean hasWindowFocus) { 13381fffbd97fa756ef7d3e7e885a5c1c8bb64380c20Mike LeBeau super.onWindowFocusChanged(hasWindowFocus); 13391fffbd97fa756ef7d3e7e885a5c1c8bb64380c20Mike LeBeau 13401fffbd97fa756ef7d3e7e885a5c1c8bb64380c20Mike LeBeau if (hasWindowFocus) { 13411fffbd97fa756ef7d3e7e885a5c1c8bb64380c20Mike LeBeau InputMethodManager inputManager = (InputMethodManager) 13421fffbd97fa756ef7d3e7e885a5c1c8bb64380c20Mike LeBeau getContext().getSystemService(Context.INPUT_METHOD_SERVICE); 13431fffbd97fa756ef7d3e7e885a5c1c8bb64380c20Mike LeBeau inputManager.showSoftInput(this, 0); 13441fffbd97fa756ef7d3e7e885a5c1c8bb64380c20Mike LeBeau } 13451fffbd97fa756ef7d3e7e885a5c1c8bb64380c20Mike LeBeau } 13461fffbd97fa756ef7d3e7e885a5c1c8bb64380c20Mike LeBeau 1347617202a53a26d1b38a41ce69c40b1fffd784c178Mike LeBeau /** 1348875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * We override this method so that we can allow a threshold of zero, which ACTV does not. 13499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 13509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 1351875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen public boolean enoughToFilter() { 1352875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return mThreshold <= 0 || super.enoughToFilter(); 13539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 135498e333f551a4bf2ebb50bb97a2a56b14bfdcd74bKarl Rosaen 1355875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 135687d61f22e13e81550559c92f6cf6fb795a39d37fBjorn Bringert 135787d61f22e13e81550559c92f6cf6fb795a39d37fBjorn Bringert @Override 135887d61f22e13e81550559c92f6cf6fb795a39d37fBjorn Bringert public void onBackPressed() { 1359a6309c30722ad3aee88ddc2394cea2a499168d99Bjorn Bringert // If the input method is covering the search dialog completely, 1360a6309c30722ad3aee88ddc2394cea2a499168d99Bjorn Bringert // e.g. in landscape mode with no hard keyboard, dismiss just the input method 1361a6309c30722ad3aee88ddc2394cea2a499168d99Bjorn Bringert InputMethodManager imm = (InputMethodManager)getContext() 1362a6309c30722ad3aee88ddc2394cea2a499168d99Bjorn Bringert .getSystemService(Context.INPUT_METHOD_SERVICE); 1363a6309c30722ad3aee88ddc2394cea2a499168d99Bjorn Bringert if (imm != null && imm.isFullscreenMode() && 1364a6309c30722ad3aee88ddc2394cea2a499168d99Bjorn Bringert imm.hideSoftInputFromWindow(getWindow().getDecorView().getWindowToken(), 0)) { 1365a6309c30722ad3aee88ddc2394cea2a499168d99Bjorn Bringert return; 1366a6309c30722ad3aee88ddc2394cea2a499168d99Bjorn Bringert } 1367479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani // Close search dialog 1368479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani cancel(); 13699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 137087d61f22e13e81550559c92f6cf6fb795a39d37fBjorn Bringert 13719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 13729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Implements OnItemClickListener 13739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 13749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onItemClick(AdapterView<?> parent, View view, int position, long id) { 1375875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (DBG) Log.d(LOG_TAG, "onItemClick() position " + position); 1376875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen launchSuggestion(position); 13779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1378875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 13799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 13809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Implements OnItemSelectedListener 13819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 13829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { 1383875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (DBG) Log.d(LOG_TAG, "onItemSelected() position " + position); 1384875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // A suggestion has been selected, rewrite the query if possible, 1385875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // otherwise the restore the original query. 1386875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (REWRITE_QUERIES) { 1387875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen rewriteQueryFromSuggestion(position); 1388875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 13899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 13909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 13919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 13929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Implements OnItemSelectedListener 13939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 13949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onNothingSelected(AdapterView<?> parent) { 1395875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (DBG) Log.d(LOG_TAG, "onNothingSelected()"); 1396875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 1397875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 1398875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen /** 1399875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * Query rewriting. 1400875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen */ 1401875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 1402875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen private void rewriteQueryFromSuggestion(int position) { 1403875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen Cursor c = mSuggestionsAdapter.getCursor(); 1404875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (c == null) { 1405875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return; 1406875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 1407875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (c.moveToPosition(position)) { 1408875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // Get the new query from the suggestion. 1409875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen CharSequence newQuery = mSuggestionsAdapter.convertToString(c); 1410875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (newQuery != null) { 1411875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // The suggestion rewrites the query. 1412875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (DBG) Log.d(LOG_TAG, "Rewriting query to '" + newQuery + "'"); 1413875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // Update the text field, without getting new suggestions. 1414875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen setQuery(newQuery); 1415875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } else { 1416875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // The suggestion does not rewrite the query, restore the user's query. 1417875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (DBG) Log.d(LOG_TAG, "Suggestion gives no rewrite, restoring user query."); 1418875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen restoreUserQuery(); 1419875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 1420875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } else { 1421875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // We got a bad position, restore the user's query. 1422875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen Log.w(LOG_TAG, "Bad suggestion position: " + position); 1423875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen restoreUserQuery(); 1424875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 1425875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 1426875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 1427875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen /** 1428875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * Restores the query entered by the user if needed. 1429875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen */ 1430875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen private void restoreUserQuery() { 1431875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (DBG) Log.d(LOG_TAG, "Restoring query to '" + mUserQuery + "'"); 1432875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen setQuery(mUserQuery); 1433875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 1434875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 1435875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen /** 1436875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * Sets the text in the query box, without updating the suggestions. 1437875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen */ 1438875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen private void setQuery(CharSequence query) { 1439875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mSearchAutoComplete.setText(query, false); 1440875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (query != null) { 1441875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mSearchAutoComplete.setSelection(query.length()); 1442875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 1443875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 1444875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 1445875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen /** 1446875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * Sets the text in the query box, updating the suggestions. 1447875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen */ 1448875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen private void setUserQuery(String query) { 1449875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (query == null) { 1450875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen query = ""; 1451875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 1452875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mUserQuery = query; 1453875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mSearchAutoComplete.setText(query); 1454875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mSearchAutoComplete.setSelection(query.length()); 14559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 14589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Debugging Support 14599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 14609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 14619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 14629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * For debugging only, sample the millisecond clock and log it. 14639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Uses AtomicLong so we can use in multiple threads 14649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 14659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private AtomicLong mLastLogTime = new AtomicLong(SystemClock.uptimeMillis()); 14669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void dbgLogTiming(final String caller) { 14679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long millis = SystemClock.uptimeMillis(); 14689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long oldTime = mLastLogTime.getAndSet(millis); 14699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long delta = millis - oldTime; 14709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final String report = millis + " (+" + delta + ") ticks for Search keystroke in " + caller; 14719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Log.d(LOG_TAG,report); 14729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 14739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 1474