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 Yamasani 20d25eb35b6b80b6f8065ab39b1cf1abb1fd801234Amith Yamasaniimport android.content.BroadcastReceiver; 219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.ComponentName; 22444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringertimport android.content.Context; 23444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringertimport android.content.Intent; 24d25eb35b6b80b6f8065ab39b1cf1abb1fd801234Amith Yamasaniimport android.content.IntentFilter; 25875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaenimport android.content.pm.ActivityInfo; 269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.pm.PackageManager; 27c1f40960644b461b108480b6446c89963441492dBjorn Bringertimport android.content.pm.PackageManager.NameNotFoundException; 28d25eb35b6b80b6f8065ab39b1cf1abb1fd801234Amith Yamasaniimport android.content.res.Configuration; 29444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringertimport android.graphics.drawable.Drawable; 309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.net.Uri; 319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Bundle; 329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.speech.RecognizerIntent; 339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.InputType; 349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.text.TextUtils; 359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.AttributeSet; 369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log; 378abebcde3fd2317b25629263db6ad4637c8eeb34Adam Powellimport android.util.TypedValue; 388abebcde3fd2317b25629263db6ad4637c8eeb34Adam Powellimport android.view.ActionMode; 399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.Gravity; 409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.KeyEvent; 41875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaenimport android.view.MotionEvent; 429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.View; 43875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaenimport android.view.ViewConfiguration; 449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.ViewGroup; 459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.Window; 469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.WindowManager; 47a8f556ee8cee24674663fd73c7a5b5a919b2d5bbDianne Hackbornimport android.view.inputmethod.InputMethodManager; 489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.widget.AutoCompleteTextView; 49da5c1bd4443b5b569a0d392cd53b476b4e160c47Bjorn Bringertimport android.widget.ImageView; 50077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringertimport android.widget.LinearLayout; 51968ec938399033d280b1648123104ac567f2a093Amith Yamasaniimport android.widget.SearchView; 529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.widget.TextView; 53968ec938399033d280b1648123104ac567f2a093Amith Yamasani 549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/** 55e9ce3f01d42769f03f10e70c3244500e92d7eee1Amith Yamasani * Search dialog. This is controlled by the 56e9ce3f01d42769f03f10e70c3244500e92d7eee1Amith Yamasani * SearchManager and runs in the current foreground process. 579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @hide 599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 60968ec938399033d280b1648123104ac567f2a093Amith Yamasanipublic class SearchDialog extends Dialog { 619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Debugging support 63875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen private static final boolean DBG = false; 64875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen private static final String LOG_TAG = "SearchDialog"; 659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String INSTANCE_KEY_COMPONENT = "comp"; 679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final String INSTANCE_KEY_APPDATA = "data"; 68b0ae27f4e10a9e5fe56b9ca549718051fe342bbaBjorn Bringert private static final String INSTANCE_KEY_USER_QUERY = "uQry"; 69968ec938399033d280b1648123104ac567f2a093Amith Yamasani 707df846186d29ddfa4a567deddd04ad1043d32fd8Mike LeBeau // The string used for privateImeOptions to identify to the IME that it should not show 717df846186d29ddfa4a567deddd04ad1043d32fd8Mike LeBeau // a microphone button since one already exists in the search dialog. 727df846186d29ddfa4a567deddd04ad1043d32fd8Mike LeBeau private static final String IME_OPTION_NO_MICROPHONE = "nm"; 73b0ae27f4e10a9e5fe56b9ca549718051fe342bbaBjorn Bringert 741fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau private static final int SEARCH_PLATE_LEFT_PADDING_NON_GLOBAL = 7; 75444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringert 769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // views & widgets 779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private TextView mBadgeLabel; 78da5c1bd4443b5b569a0d392cd53b476b4e160c47Bjorn Bringert private ImageView mAppIcon; 79968ec938399033d280b1648123104ac567f2a093Amith Yamasani private AutoCompleteTextView mSearchAutoComplete; 80875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen private View mSearchPlate; 81968ec938399033d280b1648123104ac567f2a093Amith Yamasani private SearchView mSearchView; 82f4f7046183f0daedd17703fa16cf9026442bdaeeRomain Guy private Drawable mWorkingSpinner; 83246529891ee289e8393ad4a486db785ef455c778Amith Yamasani private View mCloseSearch; 849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // interaction with searchable application 86875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen private SearchableInfo mSearchable; 879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private ComponentName mLaunchComponent; 889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Bundle mAppSearchData; 899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private Context mActivityContext; 90875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // For voice searching 92f36740b2e4a9a187bf688c632c1d0a7ae926c96aBryan Mawhinney private final Intent mVoiceWebSearchIntent; 93f36740b2e4a9a187bf688c632c1d0a7ae926c96aBryan Mawhinney private final Intent mVoiceAppSearchIntent; 949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 95875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // The query entered by the user. This is not changed when selecting a suggestion 96875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // that modifies the contents of the text field. But if the user then edits 97875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // the suggestion, the resulting string is saved. 98875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen private String mUserQuery; 99662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath 100662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath // Last known IME options value for the search edit text. 101662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath private int mSearchAutoCompleteImeOptions; 102662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath 1034986044fd3bce877247e425374b47967775081a8Amith Yamasani private BroadcastReceiver mConfChangeListener = new BroadcastReceiver() { 1044986044fd3bce877247e425374b47967775081a8Amith Yamasani @Override 1054986044fd3bce877247e425374b47967775081a8Amith Yamasani public void onReceive(Context context, Intent intent) { 1064986044fd3bce877247e425374b47967775081a8Amith Yamasani if (intent.getAction().equals(Intent.ACTION_CONFIGURATION_CHANGED)) { 1074986044fd3bce877247e425374b47967775081a8Amith Yamasani onConfigurationChanged(); 1084986044fd3bce877247e425374b47967775081a8Amith Yamasani } 1094986044fd3bce877247e425374b47967775081a8Amith Yamasani } 1104986044fd3bce877247e425374b47967775081a8Amith Yamasani }; 1114986044fd3bce877247e425374b47967775081a8Amith Yamasani 1128abebcde3fd2317b25629263db6ad4637c8eeb34Adam Powell static int resolveDialogTheme(Context context) { 1138abebcde3fd2317b25629263db6ad4637c8eeb34Adam Powell TypedValue outValue = new TypedValue(); 1148abebcde3fd2317b25629263db6ad4637c8eeb34Adam Powell context.getTheme().resolveAttribute(com.android.internal.R.attr.searchDialogTheme, 1158abebcde3fd2317b25629263db6ad4637c8eeb34Adam Powell outValue, true); 1168abebcde3fd2317b25629263db6ad4637c8eeb34Adam Powell return outValue.resourceId; 1178abebcde3fd2317b25629263db6ad4637c8eeb34Adam Powell } 1188abebcde3fd2317b25629263db6ad4637c8eeb34Adam Powell 1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Constructor - fires it up and makes it look like the search UI. 1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param context Application Context we can use for system acess 1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 124e9ce3f01d42769f03f10e70c3244500e92d7eee1Amith Yamasani public SearchDialog(Context context, SearchManager searchManager) { 1258abebcde3fd2317b25629263db6ad4637c8eeb34Adam Powell super(context, resolveDialogTheme(context)); 126f36740b2e4a9a187bf688c632c1d0a7ae926c96aBryan Mawhinney 127f36740b2e4a9a187bf688c632c1d0a7ae926c96aBryan Mawhinney // Save voice intent for later queries/launching 128f36740b2e4a9a187bf688c632c1d0a7ae926c96aBryan Mawhinney mVoiceWebSearchIntent = new Intent(RecognizerIntent.ACTION_WEB_SEARCH); 129f36740b2e4a9a187bf688c632c1d0a7ae926c96aBryan Mawhinney mVoiceWebSearchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 130f36740b2e4a9a187bf688c632c1d0a7ae926c96aBryan Mawhinney mVoiceWebSearchIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, 131f36740b2e4a9a187bf688c632c1d0a7ae926c96aBryan Mawhinney RecognizerIntent.LANGUAGE_MODEL_WEB_SEARCH); 132f36740b2e4a9a187bf688c632c1d0a7ae926c96aBryan Mawhinney 133f36740b2e4a9a187bf688c632c1d0a7ae926c96aBryan Mawhinney mVoiceAppSearchIntent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); 134f36740b2e4a9a187bf688c632c1d0a7ae926c96aBryan Mawhinney mVoiceAppSearchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 138f36740b2e4a9a187bf688c632c1d0a7ae926c96aBryan Mawhinney * Create the search dialog and any resources that are used for the 139f36740b2e4a9a187bf688c632c1d0a7ae926c96aBryan Mawhinney * entire lifetime of the dialog. 1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected void onCreate(Bundle savedInstanceState) { 1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super.onCreate(savedInstanceState); 1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1458d17f3f24bbda9a9cd7ea08c5925508dc2c011beBjorn Bringert Window theWindow = getWindow(); 1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project WindowManager.LayoutParams lp = theWindow.getAttributes(); 147980a938c1c9a6a5791a8240e5a1e6638ab28dc77Romain Guy lp.width = ViewGroup.LayoutParams.MATCH_PARENT; 1488d17f3f24bbda9a9cd7ea08c5925508dc2c011beBjorn Bringert // taking up the whole window (even when transparent) is less than ideal, 1498d17f3f24bbda9a9cd7ea08c5925508dc2c011beBjorn Bringert // but necessary to show the popup window until the window manager supports 1508d17f3f24bbda9a9cd7ea08c5925508dc2c011beBjorn Bringert // having windows anchored by their parent but not clipped by them. 151980a938c1c9a6a5791a8240e5a1e6638ab28dc77Romain Guy lp.height = ViewGroup.LayoutParams.MATCH_PARENT; 1528d17f3f24bbda9a9cd7ea08c5925508dc2c011beBjorn Bringert lp.gravity = Gravity.TOP | Gravity.FILL_HORIZONTAL; 15398acd54fa6657e8131b3a2a957de7882a2f511abMike LeBeau lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; 1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project theWindow.setAttributes(lp); 1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 156f36740b2e4a9a187bf688c632c1d0a7ae926c96aBryan Mawhinney // Touching outside of the search dialog will dismiss it 157f36740b2e4a9a187bf688c632c1d0a7ae926c96aBryan Mawhinney setCanceledOnTouchOutside(true); 158f36740b2e4a9a187bf688c632c1d0a7ae926c96aBryan Mawhinney } 159f36740b2e4a9a187bf688c632c1d0a7ae926c96aBryan Mawhinney 160f36740b2e4a9a187bf688c632c1d0a7ae926c96aBryan Mawhinney /** 161f36740b2e4a9a187bf688c632c1d0a7ae926c96aBryan Mawhinney * We recreate the dialog view each time it becomes visible so as to limit 162f36740b2e4a9a187bf688c632c1d0a7ae926c96aBryan Mawhinney * the scope of any problems with the contained resources. 163f36740b2e4a9a187bf688c632c1d0a7ae926c96aBryan Mawhinney */ 164f36740b2e4a9a187bf688c632c1d0a7ae926c96aBryan Mawhinney private void createContentView() { 165f36740b2e4a9a187bf688c632c1d0a7ae926c96aBryan Mawhinney setContentView(com.android.internal.R.layout.search_bar); 166f36740b2e4a9a187bf688c632c1d0a7ae926c96aBryan Mawhinney 1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // get the view elements for local access 168968ec938399033d280b1648123104ac567f2a093Amith Yamasani mSearchView = (SearchView) findViewById(com.android.internal.R.id.search_view); 169b4569fb17fada4fdc43e4f4dbfbc79bb097a1f74Amith Yamasani mSearchView.setIconified(false); 170968ec938399033d280b1648123104ac567f2a093Amith Yamasani mSearchView.setOnCloseListener(mOnCloseListener); 17101f21354654a315ea2a2a1668bbda50645123d4aAdam Powell mSearchView.setOnQueryTextListener(mOnQueryChangeListener); 17201f21354654a315ea2a2a1668bbda50645123d4aAdam Powell mSearchView.setOnSuggestionListener(mOnSuggestionSelectionListener); 1736a7421ba94b1fca0a20ddf146054ebd771ee471eAmith Yamasani mSearchView.onActionViewExpanded(); 174968ec938399033d280b1648123104ac567f2a093Amith Yamasani 175246529891ee289e8393ad4a486db785ef455c778Amith Yamasani mCloseSearch = findViewById(com.android.internal.R.id.closeButton); 176246529891ee289e8393ad4a486db785ef455c778Amith Yamasani mCloseSearch.setOnClickListener(new View.OnClickListener() { 177246529891ee289e8393ad4a486db785ef455c778Amith Yamasani @Override 178246529891ee289e8393ad4a486db785ef455c778Amith Yamasani public void onClick(View v) { 179246529891ee289e8393ad4a486db785ef455c778Amith Yamasani dismiss(); 180246529891ee289e8393ad4a486db785ef455c778Amith Yamasani } 181246529891ee289e8393ad4a486db785ef455c778Amith Yamasani }); 182246529891ee289e8393ad4a486db785ef455c778Amith Yamasani 183968ec938399033d280b1648123104ac567f2a093Amith Yamasani // TODO: Move the badge logic to SearchView or move the badge to search_bar.xml 184968ec938399033d280b1648123104ac567f2a093Amith Yamasani mBadgeLabel = (TextView) mSearchView.findViewById(com.android.internal.R.id.search_badge); 185968ec938399033d280b1648123104ac567f2a093Amith Yamasani mSearchAutoComplete = (AutoCompleteTextView) 186968ec938399033d280b1648123104ac567f2a093Amith Yamasani mSearchView.findViewById(com.android.internal.R.id.search_src_text); 187da5c1bd4443b5b569a0d392cd53b476b4e160c47Bjorn Bringert mAppIcon = (ImageView) findViewById(com.android.internal.R.id.search_app_icon); 188968ec938399033d280b1648123104ac567f2a093Amith Yamasani mSearchPlate = mSearchView.findViewById(com.android.internal.R.id.search_plate); 1898eea3ea5591e59f55cbb4f6b2b7e9363a285ced3Alan Viverette mWorkingSpinner = getContext().getDrawable(com.android.internal.R.drawable.search_spinner); 190a40d7ec7ef5f57d61cc3dcc954009593c7829c70Amith Yamasani // TODO: Restore the spinner for slow suggestion lookups 191a40d7ec7ef5f57d61cc3dcc954009593c7829c70Amith Yamasani // mSearchAutoComplete.setCompoundDrawablesWithIntrinsicBounds( 192a40d7ec7ef5f57d61cc3dcc954009593c7829c70Amith Yamasani // null, null, mWorkingSpinner, null); 193dfcbc046d7fcd74c8aacd9f26bd48084900d3b4aBryan Mawhinney setWorking(false); 194dfcbc046d7fcd74c8aacd9f26bd48084900d3b4aBryan Mawhinney 1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // pre-hide all the extraneous elements 1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mBadgeLabel.setVisibility(View.GONE); 1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Additional adjustments to make Dialog work for Search 199662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath mSearchAutoCompleteImeOptions = mSearchAutoComplete.getImeOptions(); 2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Set up the search dialog 2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 205875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * @return true if search dialog launched, false if not 2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean show(String initialQuery, boolean selectInitialQuery, 208479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani ComponentName componentName, Bundle appSearchData) { 209479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani boolean success = doShow(initialQuery, selectInitialQuery, componentName, appSearchData); 210fef8d3e4d8f6f46c098d04b3a57409c947ec1c75Satish Sampath if (success) { 211fef8d3e4d8f6f46c098d04b3a57409c947ec1c75Satish Sampath // Display the drop down as soon as possible instead of waiting for the rest of the 212fef8d3e4d8f6f46c098d04b3a57409c947ec1c75Satish Sampath // pending UI stuff to get done, so that things appear faster to the user. 213fef8d3e4d8f6f46c098d04b3a57409c947ec1c75Satish Sampath mSearchAutoComplete.showDropDownAfterLayout(); 214fef8d3e4d8f6f46c098d04b3a57409c947ec1c75Satish Sampath } 215fef8d3e4d8f6f46c098d04b3a57409c947ec1c75Satish Sampath return success; 216b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau } 217da1f4b669ead7813079643b43301f100127aaeedBjorn Bringert 218b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau /** 219479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani * Does the rest of the work required to show the search dialog. Called by 220479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani * {@link #show(String, boolean, ComponentName, Bundle)} and 221479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani * 222b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau * @return true if search dialog showed, false if not 223b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau */ 224b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau private boolean doShow(String initialQuery, boolean selectInitialQuery, 225479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani ComponentName componentName, Bundle appSearchData) { 226875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // set up the searchable and show the dialog 227479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani if (!show(componentName, appSearchData)) { 228875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return false; 229875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 230b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau 231875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // finally, load the user's initial text (which may trigger suggestions) 232875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen setUserQuery(initialQuery); 233875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (selectInitialQuery) { 234875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mSearchAutoComplete.selectAll(); 235875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 236b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau 237875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return true; 238875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 239b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau 240875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen /** 241875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * Sets up the search dialog and shows it. 242875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * 243875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * @return <code>true</code> if search dialog launched 244875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen */ 245479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani private boolean show(ComponentName componentName, Bundle appSearchData) { 246875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 247875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (DBG) { 248875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen Log.d(LOG_TAG, "show(" + componentName + ", " 249479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani + appSearchData + ")"); 2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 251875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 2528d1538237847baf381787b881141f8c0478bef5bBjorn Bringert SearchManager searchManager = (SearchManager) 2538d1538237847baf381787b881141f8c0478bef5bBjorn Bringert mContext.getSystemService(Context.SEARCH_SERVICE); 254479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani // Try to get the searchable info for the provided component. 2556cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert mSearchable = searchManager.getSearchableInfo(componentName); 256ee716fa2b03666622a73f8cc54dae4afd091353dBjorn Bringert 257ee716fa2b03666622a73f8cc54dae4afd091353dBjorn Bringert if (mSearchable == null) { 258ee716fa2b03666622a73f8cc54dae4afd091353dBjorn Bringert return false; 259ee716fa2b03666622a73f8cc54dae4afd091353dBjorn Bringert } 260ee716fa2b03666622a73f8cc54dae4afd091353dBjorn Bringert 2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLaunchComponent = componentName; 2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mAppSearchData = appSearchData; 263875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mActivityContext = mSearchable.getActivityContext(getContext()); 264f36740b2e4a9a187bf688c632c1d0a7ae926c96aBryan Mawhinney 265875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // show the dialog. this will call onStart(). 26611f09bb5cd45a76ae7757b6f20807e836c3692f8Bjorn Bringert if (!isShowing()) { 26711f09bb5cd45a76ae7757b6f20807e836c3692f8Bjorn Bringert // Recreate the search bar view every time the dialog is shown, to get rid 26811f09bb5cd45a76ae7757b6f20807e836c3692f8Bjorn Bringert // of any bad state in the AutoCompleteTextView etc 26911f09bb5cd45a76ae7757b6f20807e836c3692f8Bjorn Bringert createContentView(); 270968ec938399033d280b1648123104ac567f2a093Amith Yamasani mSearchView.setSearchableInfo(mSearchable); 271940ef38c7c46565a8f8fdd6bb8e0183646d0abdcAmith Yamasani mSearchView.setAppSearchData(mAppSearchData); 27211f09bb5cd45a76ae7757b6f20807e836c3692f8Bjorn Bringert 273875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen show(); 2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 275875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen updateUI(); 2764986044fd3bce877247e425374b47967775081a8Amith Yamasani 2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 2804986044fd3bce877247e425374b47967775081a8Amith Yamasani @Override 2814986044fd3bce877247e425374b47967775081a8Amith Yamasani public void onStart() { 2824986044fd3bce877247e425374b47967775081a8Amith Yamasani super.onStart(); 2834986044fd3bce877247e425374b47967775081a8Amith Yamasani 2844986044fd3bce877247e425374b47967775081a8Amith Yamasani // Register a listener for configuration change events. 2854986044fd3bce877247e425374b47967775081a8Amith Yamasani IntentFilter filter = new IntentFilter(); 2864986044fd3bce877247e425374b47967775081a8Amith Yamasani filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); 2874986044fd3bce877247e425374b47967775081a8Amith Yamasani getContext().registerReceiver(mConfChangeListener, filter); 2884986044fd3bce877247e425374b47967775081a8Amith Yamasani } 2894986044fd3bce877247e425374b47967775081a8Amith Yamasani 2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The search dialog is being dismissed, so handle all of the local shutdown operations. 2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This function is designed to be idempotent so that dismiss() can be safely called at any time 2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * (even if already closed) and more likely to really dump any memory. No leaks! 2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onStop() { 2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project super.onStop(); 299444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringert 3004986044fd3bce877247e425374b47967775081a8Amith Yamasani getContext().unregisterReceiver(mConfChangeListener); 3014986044fd3bce877247e425374b47967775081a8Amith Yamasani 3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // dump extra memory we're hanging on to 3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mLaunchComponent = null; 3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mAppSearchData = null; 3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mSearchable = null; 3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mUserQuery = null; 307875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 3081c6907515134c8a2e086d2eed4427f909d301935Mike LeBeau 3091c6907515134c8a2e086d2eed4427f909d301935Mike LeBeau /** 3101480eb27f5321ef5fc2faeee87c7464e279a4912Mike LeBeau * Sets the search dialog to the 'working' state, which shows a working spinner in the 3111480eb27f5321ef5fc2faeee87c7464e279a4912Mike LeBeau * right hand size of the text field. 3121480eb27f5321ef5fc2faeee87c7464e279a4912Mike LeBeau * 3131480eb27f5321ef5fc2faeee87c7464e279a4912Mike LeBeau * @param working true to show spinner, false to hide spinner 3141480eb27f5321ef5fc2faeee87c7464e279a4912Mike LeBeau */ 3151480eb27f5321ef5fc2faeee87c7464e279a4912Mike LeBeau public void setWorking(boolean working) { 316dfcbc046d7fcd74c8aacd9f26bd48084900d3b4aBryan Mawhinney mWorkingSpinner.setAlpha(working ? 255 : 0); 317dfcbc046d7fcd74c8aacd9f26bd48084900d3b4aBryan Mawhinney mWorkingSpinner.setVisible(working, false); 318dfcbc046d7fcd74c8aacd9f26bd48084900d3b4aBryan Mawhinney mWorkingSpinner.invalidateSelf(); 3191480eb27f5321ef5fc2faeee87c7464e279a4912Mike LeBeau } 320479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani 3211480eb27f5321ef5fc2faeee87c7464e279a4912Mike LeBeau /** 3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Save the minimal set of data necessary to recreate the search 3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 324444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringert * @return A bundle with the state of the dialog, or {@code null} if the search 325444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringert * dialog is not showing. 3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Bundle onSaveInstanceState() { 329444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringert if (!isShowing()) return null; 330444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringert 3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Bundle bundle = new Bundle(); 332444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringert 3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // setup info so I can recreate this particular search 3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bundle.putParcelable(INSTANCE_KEY_COMPONENT, mLaunchComponent); 3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project bundle.putBundle(INSTANCE_KEY_APPDATA, mAppSearchData); 336b0ae27f4e10a9e5fe56b9ca549718051fe342bbaBjorn Bringert bundle.putString(INSTANCE_KEY_USER_QUERY, mUserQuery); 337b0ae27f4e10a9e5fe56b9ca549718051fe342bbaBjorn Bringert 3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return bundle; 3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Restore the state of the dialog from a previously saved bundle. 343875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * 3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param savedInstanceState The state of the dialog previously saved by 3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link #onSaveInstanceState()}. 3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onRestoreInstanceState(Bundle savedInstanceState) { 349444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringert if (savedInstanceState == null) return; 350444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringert 3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ComponentName launchComponent = savedInstanceState.getParcelable(INSTANCE_KEY_COMPONENT); 3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Bundle appSearchData = savedInstanceState.getBundle(INSTANCE_KEY_APPDATA); 353b0ae27f4e10a9e5fe56b9ca549718051fe342bbaBjorn Bringert String userQuery = savedInstanceState.getString(INSTANCE_KEY_USER_QUERY); 354b0ae27f4e10a9e5fe56b9ca549718051fe342bbaBjorn Bringert 355b0ae27f4e10a9e5fe56b9ca549718051fe342bbaBjorn Bringert // show the dialog. 356479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani if (!doShow(userQuery, false, launchComponent, appSearchData)) { 3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // for some reason, we couldn't re-instantiate 3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 361968ec938399033d280b1648123104ac567f2a093Amith Yamasani 3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 363875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * Called after resources have changed, e.g. after screen rotation or locale change. 3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 365444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringert public void onConfigurationChanged() { 366479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani if (mSearchable != null && isShowing()) { 3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Redraw (resources may have changed) 3681fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau updateSearchAppIcon(); 3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project updateSearchBadge(); 370d25eb35b6b80b6f8065ab39b1cf1abb1fd801234Amith Yamasani if (isLandscapeMode(getContext())) { 371d25eb35b6b80b6f8065ab39b1cf1abb1fd801234Amith Yamasani mSearchAutoComplete.ensureImeVisible(true); 372d25eb35b6b80b6f8065ab39b1cf1abb1fd801234Amith Yamasani } 373d25eb35b6b80b6f8065ab39b1cf1abb1fd801234Amith Yamasani } 3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 375d25eb35b6b80b6f8065ab39b1cf1abb1fd801234Amith Yamasani 376d25eb35b6b80b6f8065ab39b1cf1abb1fd801234Amith Yamasani static boolean isLandscapeMode(Context context) { 377d25eb35b6b80b6f8065ab39b1cf1abb1fd801234Amith Yamasani return context.getResources().getConfiguration().orientation 378d25eb35b6b80b6f8065ab39b1cf1abb1fd801234Amith Yamasani == Configuration.ORIENTATION_LANDSCAPE; 379d25eb35b6b80b6f8065ab39b1cf1abb1fd801234Amith Yamasani } 380d25eb35b6b80b6f8065ab39b1cf1abb1fd801234Amith Yamasani 3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 382875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * Update the UI according to the info in the current value of {@link #mSearchable}. 3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 384875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen private void updateUI() { 3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mSearchable != null) { 386ea52d29bc46c306f3607d121aa1ad84f0e9eb473Karl Rosaen mDecor.setVisibility(View.VISIBLE); 387875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen updateSearchAutoComplete(); 3881fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau updateSearchAppIcon(); 3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project updateSearchBadge(); 3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // In order to properly configure the input method (if one is being used), we 3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // need to let it know if we'll be providing suggestions. Although it would be 3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // difficult/expensive to know if every last detail has been configured properly, we 3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // can at least see if a suggestions provider has been configured, and use that 3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // as our trigger. 3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int inputType = mSearchable.getInputType(); 3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // We only touch this if the input type is set up for text (which it almost certainly 3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // should be, in the case of search!) 3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if ((inputType & InputType.TYPE_MASK_CLASS) == InputType.TYPE_CLASS_TEXT) { 4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // The existence of a suggestions authority is the proxy for "suggestions 4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // are available here" 4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project inputType &= ~InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE; 4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mSearchable.getSuggestAuthority() != null) { 4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project inputType |= InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE; 4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 407875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen mSearchAutoComplete.setInputType(inputType); 408662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath mSearchAutoCompleteImeOptions = mSearchable.getImeOptions(); 409662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath mSearchAutoComplete.setImeOptions(mSearchAutoCompleteImeOptions); 4107df846186d29ddfa4a567deddd04ad1043d32fd8Mike LeBeau 4117df846186d29ddfa4a567deddd04ad1043d32fd8Mike LeBeau // If the search dialog is going to show a voice search button, then don't let 4127df846186d29ddfa4a567deddd04ad1043d32fd8Mike LeBeau // the soft keyboard display a microphone button if it would have otherwise. 4137df846186d29ddfa4a567deddd04ad1043d32fd8Mike LeBeau if (mSearchable.getVoiceSearchEnabled()) { 4147df846186d29ddfa4a567deddd04ad1043d32fd8Mike LeBeau mSearchAutoComplete.setPrivateImeOptions(IME_OPTION_NO_MICROPHONE); 4157df846186d29ddfa4a567deddd04ad1043d32fd8Mike LeBeau } else { 4167df846186d29ddfa4a567deddd04ad1043d32fd8Mike LeBeau mSearchAutoComplete.setPrivateImeOptions(null); 4177df846186d29ddfa4a567deddd04ad1043d32fd8Mike LeBeau } 4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 420875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 422875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * Updates the auto-complete text view. 4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 424875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen private void updateSearchAutoComplete() { 4258d17f3f24bbda9a9cd7ea08c5925508dc2c011beBjorn Bringert // we dismiss the entire dialog instead 4268d17f3f24bbda9a9cd7ea08c5925508dc2c011beBjorn Bringert mSearchAutoComplete.setDropDownDismissedOnCompletion(false); 427968ec938399033d280b1648123104ac567f2a093Amith Yamasani mSearchAutoComplete.setForceIgnoreOutsideTouch(false); 4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4301fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau private void updateSearchAppIcon() { 431968ec938399033d280b1648123104ac567f2a093Amith Yamasani PackageManager pm = getContext().getPackageManager(); 432968ec938399033d280b1648123104ac567f2a093Amith Yamasani Drawable icon; 433968ec938399033d280b1648123104ac567f2a093Amith Yamasani try { 434968ec938399033d280b1648123104ac567f2a093Amith Yamasani ActivityInfo info = pm.getActivityInfo(mLaunchComponent, 0); 435968ec938399033d280b1648123104ac567f2a093Amith Yamasani icon = pm.getApplicationIcon(info.applicationInfo); 436968ec938399033d280b1648123104ac567f2a093Amith Yamasani if (DBG) 437968ec938399033d280b1648123104ac567f2a093Amith Yamasani Log.d(LOG_TAG, "Using app-specific icon"); 438968ec938399033d280b1648123104ac567f2a093Amith Yamasani } catch (NameNotFoundException e) { 439968ec938399033d280b1648123104ac567f2a093Amith Yamasani icon = pm.getDefaultActivityIcon(); 440968ec938399033d280b1648123104ac567f2a093Amith Yamasani Log.w(LOG_TAG, mLaunchComponent + " not found, using generic app icon"); 4411fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau } 442968ec938399033d280b1648123104ac567f2a093Amith Yamasani mAppIcon.setImageDrawable(icon); 443968ec938399033d280b1648123104ac567f2a093Amith Yamasani mAppIcon.setVisibility(View.VISIBLE); 444968ec938399033d280b1648123104ac567f2a093Amith Yamasani mSearchPlate.setPadding(SEARCH_PLATE_LEFT_PADDING_NON_GLOBAL, mSearchPlate.getPaddingTop(), mSearchPlate.getPaddingRight(), mSearchPlate.getPaddingBottom()); 4451fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau } 4461fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau 4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 448875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * Setup the search "Badge" if requested by mode flags. 4499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void updateSearchBadge() { 4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // assume both hidden 4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int visibility = View.GONE; 4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Drawable icon = null; 454875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen CharSequence text = null; 455968ec938399033d280b1648123104ac567f2a093Amith Yamasani 4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // optionally show one or the other. 457a92041306e4d73baa10fb711fb905b9590f06b26Bjorn Bringert if (mSearchable.useBadgeIcon()) { 4588eea3ea5591e59f55cbb4f6b2b7e9363a285ced3Alan Viverette icon = mActivityContext.getDrawable(mSearchable.getIconId()); 4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project visibility = View.VISIBLE; 460875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (DBG) Log.d(LOG_TAG, "Using badge icon: " + mSearchable.getIconId()); 461a92041306e4d73baa10fb711fb905b9590f06b26Bjorn Bringert } else if (mSearchable.useBadgeLabel()) { 4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project text = mActivityContext.getResources().getText(mSearchable.getLabelId()).toString(); 4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project visibility = View.VISIBLE; 464875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (DBG) Log.d(LOG_TAG, "Using badge label: " + mSearchable.getLabelId()); 4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 466968ec938399033d280b1648123104ac567f2a093Amith Yamasani 4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mBadgeLabel.setCompoundDrawablesWithIntrinsicBounds(icon, null, null, null); 4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mBadgeLabel.setText(text); 4699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mBadgeLabel.setVisibility(visibility); 4709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 472479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani /* 4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Listeners of various types 4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 477875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * {@link Dialog#onTouchEvent(MotionEvent)} will cancel the dialog only when the 478875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * touch is outside the window. But the window includes space for the drop-down, 479875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * so we also cancel on taps outside the search bar when the drop-down is not showing. 480875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen */ 481875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen @Override 482875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen public boolean onTouchEvent(MotionEvent event) { 483875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // cancel if the drop-down is not showing and the touch event was outside the search plate 484875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (!mSearchAutoComplete.isPopupShowing() && isOutOfBounds(mSearchPlate, event)) { 485875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (DBG) Log.d(LOG_TAG, "Pop-up not showing and outside of search plate."); 486875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen cancel(); 487875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return true; 488875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 489875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // Let Dialog handle events outside the window while the pop-up is showing. 490875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return super.onTouchEvent(event); 491875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 492968ec938399033d280b1648123104ac567f2a093Amith Yamasani 493875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen private boolean isOutOfBounds(View v, MotionEvent event) { 494875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen final int x = (int) event.getX(); 495875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen final int y = (int) event.getY(); 496875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen final int slop = ViewConfiguration.get(mContext).getScaledWindowTouchSlop(); 497875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return (x < -slop) || (y < -slop) 498875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen || (x > (v.getWidth()+slop)) 499875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen || (y > (v.getHeight()+slop)); 500875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 502a8f556ee8cee24674663fd73c7a5b5a919b2d5bbDianne Hackborn @Override 503ea52d29bc46c306f3607d121aa1ad84f0e9eb473Karl Rosaen public void hide() { 504444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringert if (!isShowing()) return; 505444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringert 506a8f556ee8cee24674663fd73c7a5b5a919b2d5bbDianne Hackborn // We made sure the IME was displayed, so also make sure it is closed 507a8f556ee8cee24674663fd73c7a5b5a919b2d5bbDianne Hackborn // when we go away. 508777ef95ebf18c61ff09e7567a06058d351c530caYohei Yukawa InputMethodManager imm = getContext().getSystemService(InputMethodManager.class); 509a8f556ee8cee24674663fd73c7a5b5a919b2d5bbDianne Hackborn if (imm != null) { 510a8f556ee8cee24674663fd73c7a5b5a919b2d5bbDianne Hackborn imm.hideSoftInputFromWindow( 511a8f556ee8cee24674663fd73c7a5b5a919b2d5bbDianne Hackborn getWindow().getDecorView().getWindowToken(), 0); 512a8f556ee8cee24674663fd73c7a5b5a919b2d5bbDianne Hackborn } 513ea52d29bc46c306f3607d121aa1ad84f0e9eb473Karl Rosaen 514ea52d29bc46c306f3607d121aa1ad84f0e9eb473Karl Rosaen super.hide(); 515a8f556ee8cee24674663fd73c7a5b5a919b2d5bbDianne Hackborn } 516875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 517875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen /** 518875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * Launch a search for the text in the query text field. 519875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen */ 520968ec938399033d280b1648123104ac567f2a093Amith Yamasani public void launchQuerySearch() { 521875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen launchQuerySearch(KeyEvent.KEYCODE_UNKNOWN, null); 522875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 525875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * Launch a search for the text in the query text field. 526875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * 527875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * @param actionKey The key code of the action key that was pressed, 528875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * or {@link KeyEvent#KEYCODE_UNKNOWN} if none. 529875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * @param actionMsg The message for the action key that was pressed, 530875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * or <code>null</code> if none. 531875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen */ 532968ec938399033d280b1648123104ac567f2a093Amith Yamasani protected void launchQuerySearch(int actionKey, String actionMsg) { 533875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen String query = mSearchAutoComplete.getText().toString(); 534479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani String action = Intent.ACTION_SEARCH; 535968ec938399033d280b1648123104ac567f2a093Amith Yamasani Intent intent = createIntent(action, null, null, query, actionKey, actionMsg); 536875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen launchIntent(intent); 537875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 538a058f02b591d971a829cb1e28d48a992e46ad85eKarl Rosaen 539875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen /** 540e9ce3f01d42769f03f10e70c3244500e92d7eee1Amith Yamasani * Launches an intent, including any special intent handling. 541875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen */ 542875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen private void launchIntent(Intent intent) { 543875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (intent == null) { 5449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 5459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 546ea52d29bc46c306f3607d121aa1ad84f0e9eb473Karl Rosaen Log.d(LOG_TAG, "launching " + intent); 5474899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert try { 548479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani // If the intent was created from a suggestion, it will always have an explicit 549479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani // component here. 550479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani getContext().startActivity(intent); 551479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani // If the search switches to a different activity, 552479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani // SearchDialogWrapper#performActivityResuming 553479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani // will handle hiding the dialog when the next activity starts, but for 554479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani // real in-app search, we still need to dismiss the dialog. 555479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani dismiss(); 5564899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert } catch (RuntimeException ex) { 5574899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert Log.e(LOG_TAG, "Failed launch activity: " + intent, ex); 5584899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert } 5594899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert } 560876627d8c52300608c8c716f980a8686f43bf476Karl Rosaen 5614899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert /** 562ae9760b62c400e3e7009d4a7b85e9524a5cd44fcMike LeBeau * Sets the list item selection in the AutoCompleteTextView's ListView. 563ae9760b62c400e3e7009d4a7b85e9524a5cd44fcMike LeBeau */ 564ae9760b62c400e3e7009d4a7b85e9524a5cd44fcMike LeBeau public void setListSelection(int index) { 565ae9760b62c400e3e7009d4a7b85e9524a5cd44fcMike LeBeau mSearchAutoComplete.setListSelection(index); 566ae9760b62c400e3e7009d4a7b85e9524a5cd44fcMike LeBeau } 567a058f02b591d971a829cb1e28d48a992e46ad85eKarl Rosaen 568ae9760b62c400e3e7009d4a7b85e9524a5cd44fcMike LeBeau /** 569875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * Constructs an intent from the given information and the search dialog state. 570875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * 571875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * @param action Intent action. 572875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * @param data Intent data, or <code>null</code>. 573875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * @param extraData Data for {@link SearchManager#EXTRA_DATA_KEY} or <code>null</code>. 574bf23fe062ab4321143717c21827d329e087cc72fSatish Sampath * @param query Intent query, or <code>null</code>. 575875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * @param actionKey The key code of the action key that was pressed, 576875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * or {@link KeyEvent#KEYCODE_UNKNOWN} if none. 577875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * @param actionMsg The message for the action key that was pressed, 578875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * or <code>null</code> if none. 579be5b73c5926cbebd508d8323bdeaafa2e048a93cBjorn Bringert * @param mode The search mode, one of the acceptable values for 580be5b73c5926cbebd508d8323bdeaafa2e048a93cBjorn Bringert * {@link SearchManager#SEARCH_MODE}, or {@code null}. 581875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen * @return The intent. 582875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen */ 583bf23fe062ab4321143717c21827d329e087cc72fSatish Sampath private Intent createIntent(String action, Uri data, String extraData, String query, 584e678f46ec45076203f6260f8a26f56d838c6b6ffAmith Yamasani int actionKey, String actionMsg) { 585875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen // Now build the Intent 586875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen Intent intent = new Intent(action); 5878d17f3f24bbda9a9cd7ea08c5925508dc2c011beBjorn Bringert intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 588442da48b24f75e6075763b89943b513197a0bfe9Bjorn Bringert // We need CLEAR_TOP to avoid reusing an old task that has other activities 589dc1396c881b80074c99d171aee02d3a5486180caEvan Millar // on top of the one we want. We don't want to do this in in-app search though, 590dc1396c881b80074c99d171aee02d3a5486180caEvan Millar // as it can be destructive to the activity stack. 591875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (data != null) { 592875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen intent.setData(data); 593875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 5945f80605a0b866f34c74955e190909bd6ab5d992eBjorn Bringert intent.putExtra(SearchManager.USER_QUERY, mUserQuery); 595875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (query != null) { 596875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen intent.putExtra(SearchManager.QUERY, query); 597875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 598875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (extraData != null) { 599875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen intent.putExtra(SearchManager.EXTRA_DATA_KEY, extraData); 600875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 601875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (mAppSearchData != null) { 602875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen intent.putExtra(SearchManager.APP_DATA, mAppSearchData); 603875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 604875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen if (actionKey != KeyEvent.KEYCODE_UNKNOWN) { 605875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen intent.putExtra(SearchManager.ACTION_KEY, actionKey); 606875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen intent.putExtra(SearchManager.ACTION_MSG, actionMsg); 607875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 608479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani intent.setComponent(mSearchable.getSearchActivity()); 609875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen return intent; 610875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 611479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani 612875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen /** 613077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert * The root element in the search bar layout. This is a custom view just to override 614077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert * the handling of the back button. 615077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert */ 616077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert public static class SearchBar extends LinearLayout { 617077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert 618077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert public SearchBar(Context context, AttributeSet attrs) { 619077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert super(context, attrs); 620077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert } 621077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert 622077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert public SearchBar(Context context) { 623077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert super(context); 624077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert } 625077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert 6264423d91de5300d3fd318bf5bc2d4d7e5bb856abfClara Bayarri @Override 6274423d91de5300d3fd318bf5bc2d4d7e5bb856abfClara Bayarri public ActionMode startActionModeForChild( 6284423d91de5300d3fd318bf5bc2d4d7e5bb856abfClara Bayarri View child, ActionMode.Callback callback, int type) { 6290433ae61e2a1dd3dd765aa517fecd94479601ec3Clara Bayarri // Disable Primary Action Modes in the SearchBar, as they overlap. 6300433ae61e2a1dd3dd765aa517fecd94479601ec3Clara Bayarri if (type != ActionMode.TYPE_PRIMARY) { 6310433ae61e2a1dd3dd765aa517fecd94479601ec3Clara Bayarri return super.startActionModeForChild(child, callback, type); 6320433ae61e2a1dd3dd765aa517fecd94479601ec3Clara Bayarri } 6334423d91de5300d3fd318bf5bc2d4d7e5bb856abfClara Bayarri return null; 6344423d91de5300d3fd318bf5bc2d4d7e5bb856abfClara Bayarri } 635077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert } 636077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert 637968ec938399033d280b1648123104ac567f2a093Amith Yamasani private boolean isEmpty(AutoCompleteTextView actv) { 638968ec938399033d280b1648123104ac567f2a093Amith Yamasani return TextUtils.getTrimmedLength(actv.getText()) == 0; 639875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen } 64087d61f22e13e81550559c92f6cf6fb795a39d37fBjorn Bringert 64187d61f22e13e81550559c92f6cf6fb795a39d37fBjorn Bringert @Override 64287d61f22e13e81550559c92f6cf6fb795a39d37fBjorn Bringert public void onBackPressed() { 643a6309c30722ad3aee88ddc2394cea2a499168d99Bjorn Bringert // If the input method is covering the search dialog completely, 644a6309c30722ad3aee88ddc2394cea2a499168d99Bjorn Bringert // e.g. in landscape mode with no hard keyboard, dismiss just the input method 645777ef95ebf18c61ff09e7567a06058d351c530caYohei Yukawa InputMethodManager imm = getContext().getSystemService(InputMethodManager.class); 646a6309c30722ad3aee88ddc2394cea2a499168d99Bjorn Bringert if (imm != null && imm.isFullscreenMode() && 647a6309c30722ad3aee88ddc2394cea2a499168d99Bjorn Bringert imm.hideSoftInputFromWindow(getWindow().getDecorView().getWindowToken(), 0)) { 648a6309c30722ad3aee88ddc2394cea2a499168d99Bjorn Bringert return; 649a6309c30722ad3aee88ddc2394cea2a499168d99Bjorn Bringert } 650479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani // Close search dialog 651479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani cancel(); 6529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 65387d61f22e13e81550559c92f6cf6fb795a39d37fBjorn Bringert 654968ec938399033d280b1648123104ac567f2a093Amith Yamasani private boolean onClosePressed() { 655968ec938399033d280b1648123104ac567f2a093Amith Yamasani // Dismiss the dialog if close button is pressed when there's no query text 656968ec938399033d280b1648123104ac567f2a093Amith Yamasani if (isEmpty(mSearchAutoComplete)) { 657968ec938399033d280b1648123104ac567f2a093Amith Yamasani dismiss(); 658968ec938399033d280b1648123104ac567f2a093Amith Yamasani return true; 659968ec938399033d280b1648123104ac567f2a093Amith Yamasani } 660968ec938399033d280b1648123104ac567f2a093Amith Yamasani 661968ec938399033d280b1648123104ac567f2a093Amith Yamasani return false; 6629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 663875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen 664968ec938399033d280b1648123104ac567f2a093Amith Yamasani private final SearchView.OnCloseListener mOnCloseListener = new SearchView.OnCloseListener() { 6659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 666968ec938399033d280b1648123104ac567f2a093Amith Yamasani public boolean onClose() { 667968ec938399033d280b1648123104ac567f2a093Amith Yamasani return onClosePressed(); 668968ec938399033d280b1648123104ac567f2a093Amith Yamasani } 669968ec938399033d280b1648123104ac567f2a093Amith Yamasani }; 670968ec938399033d280b1648123104ac567f2a093Amith Yamasani 67101f21354654a315ea2a2a1668bbda50645123d4aAdam Powell private final SearchView.OnQueryTextListener mOnQueryChangeListener = 67201f21354654a315ea2a2a1668bbda50645123d4aAdam Powell new SearchView.OnQueryTextListener() { 673968ec938399033d280b1648123104ac567f2a093Amith Yamasani 67401f21354654a315ea2a2a1668bbda50645123d4aAdam Powell public boolean onQueryTextSubmit(String query) { 675968ec938399033d280b1648123104ac567f2a093Amith Yamasani dismiss(); 676968ec938399033d280b1648123104ac567f2a093Amith Yamasani return false; 677968ec938399033d280b1648123104ac567f2a093Amith Yamasani } 678968ec938399033d280b1648123104ac567f2a093Amith Yamasani 67901f21354654a315ea2a2a1668bbda50645123d4aAdam Powell public boolean onQueryTextChange(String newText) { 680968ec938399033d280b1648123104ac567f2a093Amith Yamasani return false; 681968ec938399033d280b1648123104ac567f2a093Amith Yamasani } 682968ec938399033d280b1648123104ac567f2a093Amith Yamasani }; 683968ec938399033d280b1648123104ac567f2a093Amith Yamasani 68401f21354654a315ea2a2a1668bbda50645123d4aAdam Powell private final SearchView.OnSuggestionListener mOnSuggestionSelectionListener = 68501f21354654a315ea2a2a1668bbda50645123d4aAdam Powell new SearchView.OnSuggestionListener() { 686968ec938399033d280b1648123104ac567f2a093Amith Yamasani 68701f21354654a315ea2a2a1668bbda50645123d4aAdam Powell public boolean onSuggestionSelect(int position) { 688968ec938399033d280b1648123104ac567f2a093Amith Yamasani return false; 689968ec938399033d280b1648123104ac567f2a093Amith Yamasani } 690968ec938399033d280b1648123104ac567f2a093Amith Yamasani 69101f21354654a315ea2a2a1668bbda50645123d4aAdam Powell public boolean onSuggestionClick(int position) { 692968ec938399033d280b1648123104ac567f2a093Amith Yamasani dismiss(); 693968ec938399033d280b1648123104ac567f2a093Amith Yamasani return false; 694968ec938399033d280b1648123104ac567f2a093Amith Yamasani } 695968ec938399033d280b1648123104ac567f2a093Amith Yamasani }; 6969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 698968ec938399033d280b1648123104ac567f2a093Amith Yamasani * Sets the text in the query box, updating the suggestions. 6999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 700968ec938399033d280b1648123104ac567f2a093Amith Yamasani private void setUserQuery(String query) { 701968ec938399033d280b1648123104ac567f2a093Amith Yamasani if (query == null) { 702968ec938399033d280b1648123104ac567f2a093Amith Yamasani query = ""; 703968ec938399033d280b1648123104ac567f2a093Amith Yamasani } 704968ec938399033d280b1648123104ac567f2a093Amith Yamasani mUserQuery = query; 705968ec938399033d280b1648123104ac567f2a093Amith Yamasani mSearchAutoComplete.setText(query); 706968ec938399033d280b1648123104ac567f2a093Amith Yamasani mSearchAutoComplete.setSelection(query.length()); 7079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 709