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
168077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert        SearchBar searchBar = (SearchBar) findViewById(com.android.internal.R.id.search_bar);
169077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert        searchBar.setSearchDialog(this);
170968ec938399033d280b1648123104ac567f2a093Amith Yamasani        mSearchView = (SearchView) findViewById(com.android.internal.R.id.search_view);
171b4569fb17fada4fdc43e4f4dbfbc79bb097a1f74Amith Yamasani        mSearchView.setIconified(false);
172968ec938399033d280b1648123104ac567f2a093Amith Yamasani        mSearchView.setOnCloseListener(mOnCloseListener);
17301f21354654a315ea2a2a1668bbda50645123d4aAdam Powell        mSearchView.setOnQueryTextListener(mOnQueryChangeListener);
17401f21354654a315ea2a2a1668bbda50645123d4aAdam Powell        mSearchView.setOnSuggestionListener(mOnSuggestionSelectionListener);
1756a7421ba94b1fca0a20ddf146054ebd771ee471eAmith Yamasani        mSearchView.onActionViewExpanded();
176968ec938399033d280b1648123104ac567f2a093Amith Yamasani
177246529891ee289e8393ad4a486db785ef455c778Amith Yamasani        mCloseSearch = findViewById(com.android.internal.R.id.closeButton);
178246529891ee289e8393ad4a486db785ef455c778Amith Yamasani        mCloseSearch.setOnClickListener(new View.OnClickListener() {
179246529891ee289e8393ad4a486db785ef455c778Amith Yamasani            @Override
180246529891ee289e8393ad4a486db785ef455c778Amith Yamasani            public void onClick(View v) {
181246529891ee289e8393ad4a486db785ef455c778Amith Yamasani                dismiss();
182246529891ee289e8393ad4a486db785ef455c778Amith Yamasani            }
183246529891ee289e8393ad4a486db785ef455c778Amith Yamasani        });
184246529891ee289e8393ad4a486db785ef455c778Amith Yamasani
185968ec938399033d280b1648123104ac567f2a093Amith Yamasani        // TODO: Move the badge logic to SearchView or move the badge to search_bar.xml
186968ec938399033d280b1648123104ac567f2a093Amith Yamasani        mBadgeLabel = (TextView) mSearchView.findViewById(com.android.internal.R.id.search_badge);
187968ec938399033d280b1648123104ac567f2a093Amith Yamasani        mSearchAutoComplete = (AutoCompleteTextView)
188968ec938399033d280b1648123104ac567f2a093Amith Yamasani                mSearchView.findViewById(com.android.internal.R.id.search_src_text);
189da5c1bd4443b5b569a0d392cd53b476b4e160c47Bjorn Bringert        mAppIcon = (ImageView) findViewById(com.android.internal.R.id.search_app_icon);
190968ec938399033d280b1648123104ac567f2a093Amith Yamasani        mSearchPlate = mSearchView.findViewById(com.android.internal.R.id.search_plate);
191f4f7046183f0daedd17703fa16cf9026442bdaeeRomain Guy        mWorkingSpinner = getContext().getResources().
1921480eb27f5321ef5fc2faeee87c7464e279a4912Mike LeBeau                getDrawable(com.android.internal.R.drawable.search_spinner);
193a40d7ec7ef5f57d61cc3dcc954009593c7829c70Amith Yamasani        // TODO: Restore the spinner for slow suggestion lookups
194a40d7ec7ef5f57d61cc3dcc954009593c7829c70Amith Yamasani        // mSearchAutoComplete.setCompoundDrawablesWithIntrinsicBounds(
195a40d7ec7ef5f57d61cc3dcc954009593c7829c70Amith Yamasani        //        null, null, mWorkingSpinner, null);
196dfcbc046d7fcd74c8aacd9f26bd48084900d3b4aBryan Mawhinney        setWorking(false);
197dfcbc046d7fcd74c8aacd9f26bd48084900d3b4aBryan Mawhinney
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // pre-hide all the extraneous elements
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mBadgeLabel.setVisibility(View.GONE);
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Additional adjustments to make Dialog work for Search
202662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath        mSearchAutoCompleteImeOptions = mSearchAutoComplete.getImeOptions();
2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Set up the search dialog
2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
208875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * @return true if search dialog launched, false if not
2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean show(String initialQuery, boolean selectInitialQuery,
211479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani            ComponentName componentName, Bundle appSearchData) {
212479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani        boolean success = doShow(initialQuery, selectInitialQuery, componentName, appSearchData);
213fef8d3e4d8f6f46c098d04b3a57409c947ec1c75Satish Sampath        if (success) {
214fef8d3e4d8f6f46c098d04b3a57409c947ec1c75Satish Sampath            // Display the drop down as soon as possible instead of waiting for the rest of the
215fef8d3e4d8f6f46c098d04b3a57409c947ec1c75Satish Sampath            // pending UI stuff to get done, so that things appear faster to the user.
216fef8d3e4d8f6f46c098d04b3a57409c947ec1c75Satish Sampath            mSearchAutoComplete.showDropDownAfterLayout();
217fef8d3e4d8f6f46c098d04b3a57409c947ec1c75Satish Sampath        }
218fef8d3e4d8f6f46c098d04b3a57409c947ec1c75Satish Sampath        return success;
219b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau    }
220da1f4b669ead7813079643b43301f100127aaeedBjorn Bringert
221b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau    /**
222479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani     * Does the rest of the work required to show the search dialog. Called by
223479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani     * {@link #show(String, boolean, ComponentName, Bundle)} and
224479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani     *
225b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau     * @return true if search dialog showed, false if not
226b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau     */
227b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau    private boolean doShow(String initialQuery, boolean selectInitialQuery,
228479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani            ComponentName componentName, Bundle appSearchData) {
229875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        // set up the searchable and show the dialog
230479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani        if (!show(componentName, appSearchData)) {
231875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen            return false;
232875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        }
233b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau
234875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        // finally, load the user's initial text (which may trigger suggestions)
235875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        setUserQuery(initialQuery);
236875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        if (selectInitialQuery) {
237875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen            mSearchAutoComplete.selectAll();
238875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        }
239b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau
240875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        return true;
241875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    }
242b3aab6958120ad8bc8d70c493ebf49dcb4fbc30eMike LeBeau
243875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    /**
244875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * Sets up the search dialog and shows it.
245875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     *
246875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * @return <code>true</code> if search dialog launched
247875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     */
248479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani    private boolean show(ComponentName componentName, Bundle appSearchData) {
249875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen
250875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        if (DBG) {
251875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen            Log.d(LOG_TAG, "show(" + componentName + ", "
252479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani                    + appSearchData + ")");
2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
254875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen
2558d1538237847baf381787b881141f8c0478bef5bBjorn Bringert        SearchManager searchManager = (SearchManager)
2568d1538237847baf381787b881141f8c0478bef5bBjorn Bringert                mContext.getSystemService(Context.SEARCH_SERVICE);
257479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani        // Try to get the searchable info for the provided component.
2586cf7a325e6e9e70d9858e21fbb438341332ed254Bjorn Bringert        mSearchable = searchManager.getSearchableInfo(componentName);
259ee716fa2b03666622a73f8cc54dae4afd091353dBjorn Bringert
260ee716fa2b03666622a73f8cc54dae4afd091353dBjorn Bringert        if (mSearchable == null) {
261ee716fa2b03666622a73f8cc54dae4afd091353dBjorn Bringert            return false;
262ee716fa2b03666622a73f8cc54dae4afd091353dBjorn Bringert        }
263ee716fa2b03666622a73f8cc54dae4afd091353dBjorn Bringert
2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mLaunchComponent = componentName;
2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mAppSearchData = appSearchData;
266875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        mActivityContext = mSearchable.getActivityContext(getContext());
267f36740b2e4a9a187bf688c632c1d0a7ae926c96aBryan Mawhinney
268875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        // show the dialog. this will call onStart().
26911f09bb5cd45a76ae7757b6f20807e836c3692f8Bjorn Bringert        if (!isShowing()) {
27011f09bb5cd45a76ae7757b6f20807e836c3692f8Bjorn Bringert            // Recreate the search bar view every time the dialog is shown, to get rid
27111f09bb5cd45a76ae7757b6f20807e836c3692f8Bjorn Bringert            // of any bad state in the AutoCompleteTextView etc
27211f09bb5cd45a76ae7757b6f20807e836c3692f8Bjorn Bringert            createContentView();
273968ec938399033d280b1648123104ac567f2a093Amith Yamasani            mSearchView.setSearchableInfo(mSearchable);
274940ef38c7c46565a8f8fdd6bb8e0183646d0abdcAmith Yamasani            mSearchView.setAppSearchData(mAppSearchData);
27511f09bb5cd45a76ae7757b6f20807e836c3692f8Bjorn Bringert
276875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen            show();
2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
278875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        updateUI();
2794986044fd3bce877247e425374b47967775081a8Amith Yamasani
2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2834986044fd3bce877247e425374b47967775081a8Amith Yamasani    @Override
2844986044fd3bce877247e425374b47967775081a8Amith Yamasani    public void onStart() {
2854986044fd3bce877247e425374b47967775081a8Amith Yamasani        super.onStart();
2864986044fd3bce877247e425374b47967775081a8Amith Yamasani
2874986044fd3bce877247e425374b47967775081a8Amith Yamasani        // Register a listener for configuration change events.
2884986044fd3bce877247e425374b47967775081a8Amith Yamasani        IntentFilter filter = new IntentFilter();
2894986044fd3bce877247e425374b47967775081a8Amith Yamasani        filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
2904986044fd3bce877247e425374b47967775081a8Amith Yamasani        getContext().registerReceiver(mConfChangeListener, filter);
2914986044fd3bce877247e425374b47967775081a8Amith Yamasani    }
2924986044fd3bce877247e425374b47967775081a8Amith Yamasani
2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The search dialog is being dismissed, so handle all of the local shutdown operations.
2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * This function is designed to be idempotent so that dismiss() can be safely called at any time
2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * (even if already closed) and more likely to really dump any memory.  No leaks!
2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void onStop() {
3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super.onStop();
302444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringert
3034986044fd3bce877247e425374b47967775081a8Amith Yamasani        getContext().unregisterReceiver(mConfChangeListener);
3044986044fd3bce877247e425374b47967775081a8Amith Yamasani
3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // dump extra memory we're hanging on to
3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mLaunchComponent = null;
3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mAppSearchData = null;
3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mSearchable = null;
3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mUserQuery = null;
310875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    }
3111c6907515134c8a2e086d2eed4427f909d301935Mike LeBeau
3121c6907515134c8a2e086d2eed4427f909d301935Mike LeBeau    /**
3131480eb27f5321ef5fc2faeee87c7464e279a4912Mike LeBeau     * Sets the search dialog to the 'working' state, which shows a working spinner in the
3141480eb27f5321ef5fc2faeee87c7464e279a4912Mike LeBeau     * right hand size of the text field.
3151480eb27f5321ef5fc2faeee87c7464e279a4912Mike LeBeau     *
3161480eb27f5321ef5fc2faeee87c7464e279a4912Mike LeBeau     * @param working true to show spinner, false to hide spinner
3171480eb27f5321ef5fc2faeee87c7464e279a4912Mike LeBeau     */
3181480eb27f5321ef5fc2faeee87c7464e279a4912Mike LeBeau    public void setWorking(boolean working) {
319dfcbc046d7fcd74c8aacd9f26bd48084900d3b4aBryan Mawhinney        mWorkingSpinner.setAlpha(working ? 255 : 0);
320dfcbc046d7fcd74c8aacd9f26bd48084900d3b4aBryan Mawhinney        mWorkingSpinner.setVisible(working, false);
321dfcbc046d7fcd74c8aacd9f26bd48084900d3b4aBryan Mawhinney        mWorkingSpinner.invalidateSelf();
3221480eb27f5321ef5fc2faeee87c7464e279a4912Mike LeBeau    }
323479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani
3241480eb27f5321ef5fc2faeee87c7464e279a4912Mike LeBeau    /**
3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Save the minimal set of data necessary to recreate the search
3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
327444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringert     * @return A bundle with the state of the dialog, or {@code null} if the search
328444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringert     *         dialog is not showing.
3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public Bundle onSaveInstanceState() {
332444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringert        if (!isShowing()) return null;
333444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringert
3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Bundle bundle = new Bundle();
335444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringert
3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // setup info so I can recreate this particular search
3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        bundle.putParcelable(INSTANCE_KEY_COMPONENT, mLaunchComponent);
3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        bundle.putBundle(INSTANCE_KEY_APPDATA, mAppSearchData);
339b0ae27f4e10a9e5fe56b9ca549718051fe342bbaBjorn Bringert        bundle.putString(INSTANCE_KEY_USER_QUERY, mUserQuery);
340b0ae27f4e10a9e5fe56b9ca549718051fe342bbaBjorn Bringert
3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return bundle;
3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Restore the state of the dialog from a previously saved bundle.
346875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     *
3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param savedInstanceState The state of the dialog previously saved by
3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *     {@link #onSaveInstanceState()}.
3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void onRestoreInstanceState(Bundle savedInstanceState) {
352444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringert        if (savedInstanceState == null) return;
353444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringert
3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ComponentName launchComponent = savedInstanceState.getParcelable(INSTANCE_KEY_COMPONENT);
3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Bundle appSearchData = savedInstanceState.getBundle(INSTANCE_KEY_APPDATA);
356b0ae27f4e10a9e5fe56b9ca549718051fe342bbaBjorn Bringert        String userQuery = savedInstanceState.getString(INSTANCE_KEY_USER_QUERY);
357b0ae27f4e10a9e5fe56b9ca549718051fe342bbaBjorn Bringert
358b0ae27f4e10a9e5fe56b9ca549718051fe342bbaBjorn Bringert        // show the dialog.
359479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani        if (!doShow(userQuery, false, launchComponent, appSearchData)) {
3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // for some reason, we couldn't re-instantiate
3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
364968ec938399033d280b1648123104ac567f2a093Amith Yamasani
3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
366875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * Called after resources have changed, e.g. after screen rotation or locale change.
3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
368444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringert    public void onConfigurationChanged() {
369479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani        if (mSearchable != null && isShowing()) {
3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Redraw (resources may have changed)
3711fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau            updateSearchAppIcon();
3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            updateSearchBadge();
373d25eb35b6b80b6f8065ab39b1cf1abb1fd801234Amith Yamasani            if (isLandscapeMode(getContext())) {
374d25eb35b6b80b6f8065ab39b1cf1abb1fd801234Amith Yamasani                mSearchAutoComplete.ensureImeVisible(true);
375d25eb35b6b80b6f8065ab39b1cf1abb1fd801234Amith Yamasani            }
376d25eb35b6b80b6f8065ab39b1cf1abb1fd801234Amith Yamasani        }
3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
378d25eb35b6b80b6f8065ab39b1cf1abb1fd801234Amith Yamasani
379d25eb35b6b80b6f8065ab39b1cf1abb1fd801234Amith Yamasani    static boolean isLandscapeMode(Context context) {
380d25eb35b6b80b6f8065ab39b1cf1abb1fd801234Amith Yamasani        return context.getResources().getConfiguration().orientation
381d25eb35b6b80b6f8065ab39b1cf1abb1fd801234Amith Yamasani                == Configuration.ORIENTATION_LANDSCAPE;
382d25eb35b6b80b6f8065ab39b1cf1abb1fd801234Amith Yamasani    }
383d25eb35b6b80b6f8065ab39b1cf1abb1fd801234Amith Yamasani
3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
385875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * Update the UI according to the info in the current value of {@link #mSearchable}.
3869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
387875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    private void updateUI() {
3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mSearchable != null) {
389ea52d29bc46c306f3607d121aa1ad84f0e9eb473Karl Rosaen            mDecor.setVisibility(View.VISIBLE);
390875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen            updateSearchAutoComplete();
3911fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau            updateSearchAppIcon();
3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            updateSearchBadge();
3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // In order to properly configure the input method (if one is being used), we
3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // need to let it know if we'll be providing suggestions.  Although it would be
3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // difficult/expensive to know if every last detail has been configured properly, we
3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // can at least see if a suggestions provider has been configured, and use that
3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // as our trigger.
3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int inputType = mSearchable.getInputType();
4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // We only touch this if the input type is set up for text (which it almost certainly
4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // should be, in the case of search!)
4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if ((inputType & InputType.TYPE_MASK_CLASS) == InputType.TYPE_CLASS_TEXT) {
4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // The existence of a suggestions authority is the proxy for "suggestions
4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // are available here"
4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                inputType &= ~InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE;
4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mSearchable.getSuggestAuthority() != null) {
4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    inputType |= InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE;
4089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
410875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen            mSearchAutoComplete.setInputType(inputType);
411662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath            mSearchAutoCompleteImeOptions = mSearchable.getImeOptions();
412662df0b9630fd685a7cf86bbfec15ac6b6c286c6Satish Sampath            mSearchAutoComplete.setImeOptions(mSearchAutoCompleteImeOptions);
4137df846186d29ddfa4a567deddd04ad1043d32fd8Mike LeBeau
4147df846186d29ddfa4a567deddd04ad1043d32fd8Mike LeBeau            // If the search dialog is going to show a voice search button, then don't let
4157df846186d29ddfa4a567deddd04ad1043d32fd8Mike LeBeau            // the soft keyboard display a microphone button if it would have otherwise.
4167df846186d29ddfa4a567deddd04ad1043d32fd8Mike LeBeau            if (mSearchable.getVoiceSearchEnabled()) {
4177df846186d29ddfa4a567deddd04ad1043d32fd8Mike LeBeau                mSearchAutoComplete.setPrivateImeOptions(IME_OPTION_NO_MICROPHONE);
4187df846186d29ddfa4a567deddd04ad1043d32fd8Mike LeBeau            } else {
4197df846186d29ddfa4a567deddd04ad1043d32fd8Mike LeBeau                mSearchAutoComplete.setPrivateImeOptions(null);
4207df846186d29ddfa4a567deddd04ad1043d32fd8Mike LeBeau            }
4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
423875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen
4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
425875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * Updates the auto-complete text view.
4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
427875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    private void updateSearchAutoComplete() {
4288d17f3f24bbda9a9cd7ea08c5925508dc2c011beBjorn Bringert        // we dismiss the entire dialog instead
4298d17f3f24bbda9a9cd7ea08c5925508dc2c011beBjorn Bringert        mSearchAutoComplete.setDropDownDismissedOnCompletion(false);
430968ec938399033d280b1648123104ac567f2a093Amith Yamasani        mSearchAutoComplete.setForceIgnoreOutsideTouch(false);
4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4331fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau    private void updateSearchAppIcon() {
434968ec938399033d280b1648123104ac567f2a093Amith Yamasani        PackageManager pm = getContext().getPackageManager();
435968ec938399033d280b1648123104ac567f2a093Amith Yamasani        Drawable icon;
436968ec938399033d280b1648123104ac567f2a093Amith Yamasani        try {
437968ec938399033d280b1648123104ac567f2a093Amith Yamasani            ActivityInfo info = pm.getActivityInfo(mLaunchComponent, 0);
438968ec938399033d280b1648123104ac567f2a093Amith Yamasani            icon = pm.getApplicationIcon(info.applicationInfo);
439968ec938399033d280b1648123104ac567f2a093Amith Yamasani            if (DBG)
440968ec938399033d280b1648123104ac567f2a093Amith Yamasani                Log.d(LOG_TAG, "Using app-specific icon");
441968ec938399033d280b1648123104ac567f2a093Amith Yamasani        } catch (NameNotFoundException e) {
442968ec938399033d280b1648123104ac567f2a093Amith Yamasani            icon = pm.getDefaultActivityIcon();
443968ec938399033d280b1648123104ac567f2a093Amith Yamasani            Log.w(LOG_TAG, mLaunchComponent + " not found, using generic app icon");
4441fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau        }
445968ec938399033d280b1648123104ac567f2a093Amith Yamasani        mAppIcon.setImageDrawable(icon);
446968ec938399033d280b1648123104ac567f2a093Amith Yamasani        mAppIcon.setVisibility(View.VISIBLE);
447968ec938399033d280b1648123104ac567f2a093Amith Yamasani        mSearchPlate.setPadding(SEARCH_PLATE_LEFT_PADDING_NON_GLOBAL, mSearchPlate.getPaddingTop(), mSearchPlate.getPaddingRight(), mSearchPlate.getPaddingBottom());
4481fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau    }
4491fd73239dcd2f17603e0819ca9963e04c8267bb2Mike LeBeau
4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
451875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * Setup the search "Badge" if requested by mode flags.
4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void updateSearchBadge() {
4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // assume both hidden
4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int visibility = View.GONE;
4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Drawable icon = null;
457875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        CharSequence text = null;
458968ec938399033d280b1648123104ac567f2a093Amith Yamasani
4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // optionally show one or the other.
460a92041306e4d73baa10fb711fb905b9590f06b26Bjorn Bringert        if (mSearchable.useBadgeIcon()) {
4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            icon = mActivityContext.getResources().getDrawable(mSearchable.getIconId());
4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            visibility = View.VISIBLE;
463875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen            if (DBG) Log.d(LOG_TAG, "Using badge icon: " + mSearchable.getIconId());
464a92041306e4d73baa10fb711fb905b9590f06b26Bjorn Bringert        } else if (mSearchable.useBadgeLabel()) {
4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            text = mActivityContext.getResources().getText(mSearchable.getLabelId()).toString();
4669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            visibility = View.VISIBLE;
467875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen            if (DBG) Log.d(LOG_TAG, "Using badge label: " + mSearchable.getLabelId());
4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
469968ec938399033d280b1648123104ac567f2a093Amith Yamasani
4709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mBadgeLabel.setCompoundDrawablesWithIntrinsicBounds(icon, null, null, null);
4719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mBadgeLabel.setText(text);
4729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mBadgeLabel.setVisibility(visibility);
4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
475479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani    /*
4769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Listeners of various types
4779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
480875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * {@link Dialog#onTouchEvent(MotionEvent)} will cancel the dialog only when the
481875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * touch is outside the window. But the window includes space for the drop-down,
482875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * so we also cancel on taps outside the search bar when the drop-down is not showing.
483875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     */
484875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    @Override
485875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    public boolean onTouchEvent(MotionEvent event) {
486875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        // cancel if the drop-down is not showing and the touch event was outside the search plate
487875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        if (!mSearchAutoComplete.isPopupShowing() && isOutOfBounds(mSearchPlate, event)) {
488875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen            if (DBG) Log.d(LOG_TAG, "Pop-up not showing and outside of search plate.");
489875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen            cancel();
490875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen            return true;
491875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        }
492875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        // Let Dialog handle events outside the window while the pop-up is showing.
493875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        return super.onTouchEvent(event);
494875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    }
495968ec938399033d280b1648123104ac567f2a093Amith Yamasani
496875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    private boolean isOutOfBounds(View v, MotionEvent event) {
497875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        final int x = (int) event.getX();
498875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        final int y = (int) event.getY();
499875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        final int slop = ViewConfiguration.get(mContext).getScaledWindowTouchSlop();
500875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        return (x < -slop) || (y < -slop)
501875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                || (x > (v.getWidth()+slop))
502875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen                || (y > (v.getHeight()+slop));
503875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    }
5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
505a8f556ee8cee24674663fd73c7a5b5a919b2d5bbDianne Hackborn    @Override
506ea52d29bc46c306f3607d121aa1ad84f0e9eb473Karl Rosaen    public void hide() {
507444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringert        if (!isShowing()) return;
508444c727e0eecf83e9d0b9c4e7af5cbf5fc4135f8Bjorn Bringert
509a8f556ee8cee24674663fd73c7a5b5a919b2d5bbDianne Hackborn        // We made sure the IME was displayed, so also make sure it is closed
510a8f556ee8cee24674663fd73c7a5b5a919b2d5bbDianne Hackborn        // when we go away.
511a8f556ee8cee24674663fd73c7a5b5a919b2d5bbDianne Hackborn        InputMethodManager imm = (InputMethodManager)getContext()
512a8f556ee8cee24674663fd73c7a5b5a919b2d5bbDianne Hackborn                .getSystemService(Context.INPUT_METHOD_SERVICE);
513a8f556ee8cee24674663fd73c7a5b5a919b2d5bbDianne Hackborn        if (imm != null) {
514a8f556ee8cee24674663fd73c7a5b5a919b2d5bbDianne Hackborn            imm.hideSoftInputFromWindow(
515a8f556ee8cee24674663fd73c7a5b5a919b2d5bbDianne Hackborn                    getWindow().getDecorView().getWindowToken(), 0);
516a8f556ee8cee24674663fd73c7a5b5a919b2d5bbDianne Hackborn        }
517ea52d29bc46c306f3607d121aa1ad84f0e9eb473Karl Rosaen
518ea52d29bc46c306f3607d121aa1ad84f0e9eb473Karl Rosaen        super.hide();
519a8f556ee8cee24674663fd73c7a5b5a919b2d5bbDianne Hackborn    }
520875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen
521875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    /**
522875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * Launch a search for the text in the query text field.
523875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     */
524968ec938399033d280b1648123104ac567f2a093Amith Yamasani    public void launchQuerySearch() {
525875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        launchQuerySearch(KeyEvent.KEYCODE_UNKNOWN, null);
526875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    }
5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
529875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * Launch a search for the text in the query text field.
530875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     *
531875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * @param actionKey The key code of the action key that was pressed,
532875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     *        or {@link KeyEvent#KEYCODE_UNKNOWN} if none.
533875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * @param actionMsg The message for the action key that was pressed,
534875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     *        or <code>null</code> if none.
535875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     */
536968ec938399033d280b1648123104ac567f2a093Amith Yamasani    protected void launchQuerySearch(int actionKey, String actionMsg) {
537875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        String query = mSearchAutoComplete.getText().toString();
538479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani        String action = Intent.ACTION_SEARCH;
539968ec938399033d280b1648123104ac567f2a093Amith Yamasani        Intent intent = createIntent(action, null, null, query, actionKey, actionMsg);
540875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        launchIntent(intent);
541875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    }
542a058f02b591d971a829cb1e28d48a992e46ad85eKarl Rosaen
543875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    /**
544e9ce3f01d42769f03f10e70c3244500e92d7eee1Amith Yamasani     * Launches an intent, including any special intent handling.
545875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     */
546875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    private void launchIntent(Intent intent) {
547875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        if (intent == null) {
5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
550ea52d29bc46c306f3607d121aa1ad84f0e9eb473Karl Rosaen        Log.d(LOG_TAG, "launching " + intent);
5514899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert        try {
552479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani            // If the intent was created from a suggestion, it will always have an explicit
553479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani            // component here.
554479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani            getContext().startActivity(intent);
555479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani            // If the search switches to a different activity,
556479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani            // SearchDialogWrapper#performActivityResuming
557479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani            // will handle hiding the dialog when the next activity starts, but for
558479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani            // real in-app search, we still need to dismiss the dialog.
559479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani            dismiss();
5604899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert        } catch (RuntimeException ex) {
5614899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert            Log.e(LOG_TAG, "Failed launch activity: " + intent, ex);
5624899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert        }
5634899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert    }
564876627d8c52300608c8c716f980a8686f43bf476Karl Rosaen
5654899e386ff9541e066a37cb5e9449844ded5ae4eBjorn Bringert    /**
566ae9760b62c400e3e7009d4a7b85e9524a5cd44fcMike LeBeau     * Sets the list item selection in the AutoCompleteTextView's ListView.
567ae9760b62c400e3e7009d4a7b85e9524a5cd44fcMike LeBeau     */
568ae9760b62c400e3e7009d4a7b85e9524a5cd44fcMike LeBeau    public void setListSelection(int index) {
569ae9760b62c400e3e7009d4a7b85e9524a5cd44fcMike LeBeau        mSearchAutoComplete.setListSelection(index);
570ae9760b62c400e3e7009d4a7b85e9524a5cd44fcMike LeBeau    }
571a058f02b591d971a829cb1e28d48a992e46ad85eKarl Rosaen
572ae9760b62c400e3e7009d4a7b85e9524a5cd44fcMike LeBeau    /**
573875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * Constructs an intent from the given information and the search dialog state.
574875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     *
575875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * @param action Intent action.
576875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * @param data Intent data, or <code>null</code>.
577875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * @param extraData Data for {@link SearchManager#EXTRA_DATA_KEY} or <code>null</code>.
578bf23fe062ab4321143717c21827d329e087cc72fSatish Sampath     * @param query Intent query, or <code>null</code>.
579875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * @param actionKey The key code of the action key that was pressed,
580875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     *        or {@link KeyEvent#KEYCODE_UNKNOWN} if none.
581875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * @param actionMsg The message for the action key that was pressed,
582875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     *        or <code>null</code> if none.
583be5b73c5926cbebd508d8323bdeaafa2e048a93cBjorn Bringert     * @param mode The search mode, one of the acceptable values for
584be5b73c5926cbebd508d8323bdeaafa2e048a93cBjorn Bringert     *             {@link SearchManager#SEARCH_MODE}, or {@code null}.
585875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     * @return The intent.
586875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen     */
587bf23fe062ab4321143717c21827d329e087cc72fSatish Sampath    private Intent createIntent(String action, Uri data, String extraData, String query,
588e678f46ec45076203f6260f8a26f56d838c6b6ffAmith Yamasani            int actionKey, String actionMsg) {
589875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        // Now build the Intent
590875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        Intent intent = new Intent(action);
5918d17f3f24bbda9a9cd7ea08c5925508dc2c011beBjorn Bringert        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
592442da48b24f75e6075763b89943b513197a0bfe9Bjorn Bringert        // We need CLEAR_TOP to avoid reusing an old task that has other activities
593dc1396c881b80074c99d171aee02d3a5486180caEvan Millar        // on top of the one we want. We don't want to do this in in-app search though,
594dc1396c881b80074c99d171aee02d3a5486180caEvan Millar        // as it can be destructive to the activity stack.
595875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        if (data != null) {
596875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen            intent.setData(data);
597875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        }
5985f80605a0b866f34c74955e190909bd6ab5d992eBjorn Bringert        intent.putExtra(SearchManager.USER_QUERY, mUserQuery);
599875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        if (query != null) {
600875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen            intent.putExtra(SearchManager.QUERY, query);
601875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        }
602875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        if (extraData != null) {
603875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen            intent.putExtra(SearchManager.EXTRA_DATA_KEY, extraData);
604875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        }
605875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        if (mAppSearchData != null) {
606875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen            intent.putExtra(SearchManager.APP_DATA, mAppSearchData);
607875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        }
608875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        if (actionKey != KeyEvent.KEYCODE_UNKNOWN) {
609875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen            intent.putExtra(SearchManager.ACTION_KEY, actionKey);
610875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen            intent.putExtra(SearchManager.ACTION_MSG, actionMsg);
611875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        }
612479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani        intent.setComponent(mSearchable.getSearchActivity());
613875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen        return intent;
614875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    }
615479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani
616875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    /**
617077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert     * The root element in the search bar layout. This is a custom view just to override
618077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert     * the handling of the back button.
619077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert     */
620077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert    public static class SearchBar extends LinearLayout {
621077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert
622077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert        private SearchDialog mSearchDialog;
623077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert
624077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert        public SearchBar(Context context, AttributeSet attrs) {
625077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert            super(context, attrs);
626077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert        }
627077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert
628077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert        public SearchBar(Context context) {
629077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert            super(context);
630077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert        }
631077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert
632077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert        public void setSearchDialog(SearchDialog searchDialog) {
633077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert            mSearchDialog = searchDialog;
634077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert        }
635077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert
636077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert        /**
6378abebcde3fd2317b25629263db6ad4637c8eeb34Adam Powell         * Don't allow action modes in a SearchBar, it looks silly.
6388abebcde3fd2317b25629263db6ad4637c8eeb34Adam Powell         */
6398abebcde3fd2317b25629263db6ad4637c8eeb34Adam Powell        @Override
6408abebcde3fd2317b25629263db6ad4637c8eeb34Adam Powell        public ActionMode startActionModeForChild(View child, ActionMode.Callback callback) {
6418abebcde3fd2317b25629263db6ad4637c8eeb34Adam Powell            return null;
6428abebcde3fd2317b25629263db6ad4637c8eeb34Adam Powell        }
643077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert    }
644077357ccf0c8b35094a69c3fc8bddd9ee605cf78Bjorn Bringert
645968ec938399033d280b1648123104ac567f2a093Amith Yamasani    private boolean isEmpty(AutoCompleteTextView actv) {
646968ec938399033d280b1648123104ac567f2a093Amith Yamasani        return TextUtils.getTrimmedLength(actv.getText()) == 0;
647875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen    }
64887d61f22e13e81550559c92f6cf6fb795a39d37fBjorn Bringert
64987d61f22e13e81550559c92f6cf6fb795a39d37fBjorn Bringert    @Override
65087d61f22e13e81550559c92f6cf6fb795a39d37fBjorn Bringert    public void onBackPressed() {
651a6309c30722ad3aee88ddc2394cea2a499168d99Bjorn Bringert        // If the input method is covering the search dialog completely,
652a6309c30722ad3aee88ddc2394cea2a499168d99Bjorn Bringert        // e.g. in landscape mode with no hard keyboard, dismiss just the input method
653a6309c30722ad3aee88ddc2394cea2a499168d99Bjorn Bringert        InputMethodManager imm = (InputMethodManager)getContext()
654a6309c30722ad3aee88ddc2394cea2a499168d99Bjorn Bringert                .getSystemService(Context.INPUT_METHOD_SERVICE);
655a6309c30722ad3aee88ddc2394cea2a499168d99Bjorn Bringert        if (imm != null && imm.isFullscreenMode() &&
656a6309c30722ad3aee88ddc2394cea2a499168d99Bjorn Bringert                imm.hideSoftInputFromWindow(getWindow().getDecorView().getWindowToken(), 0)) {
657a6309c30722ad3aee88ddc2394cea2a499168d99Bjorn Bringert            return;
658a6309c30722ad3aee88ddc2394cea2a499168d99Bjorn Bringert        }
659479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani        // Close search dialog
660479ae0a28099eb77299fe0f44d4dfabce3115fb6Amith Yamasani        cancel();
6619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
66287d61f22e13e81550559c92f6cf6fb795a39d37fBjorn Bringert
663968ec938399033d280b1648123104ac567f2a093Amith Yamasani    private boolean onClosePressed() {
664968ec938399033d280b1648123104ac567f2a093Amith Yamasani        // Dismiss the dialog if close button is pressed when there's no query text
665968ec938399033d280b1648123104ac567f2a093Amith Yamasani        if (isEmpty(mSearchAutoComplete)) {
666968ec938399033d280b1648123104ac567f2a093Amith Yamasani            dismiss();
667968ec938399033d280b1648123104ac567f2a093Amith Yamasani            return true;
668968ec938399033d280b1648123104ac567f2a093Amith Yamasani        }
669968ec938399033d280b1648123104ac567f2a093Amith Yamasani
670968ec938399033d280b1648123104ac567f2a093Amith Yamasani        return false;
6719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
672875d50a4b9294b2be33cff6493cae7acd1d07ea7Karl Rosaen
673968ec938399033d280b1648123104ac567f2a093Amith Yamasani    private final SearchView.OnCloseListener mOnCloseListener = new SearchView.OnCloseListener() {
6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
675968ec938399033d280b1648123104ac567f2a093Amith Yamasani        public boolean onClose() {
676968ec938399033d280b1648123104ac567f2a093Amith Yamasani            return onClosePressed();
677968ec938399033d280b1648123104ac567f2a093Amith Yamasani        }
678968ec938399033d280b1648123104ac567f2a093Amith Yamasani    };
679968ec938399033d280b1648123104ac567f2a093Amith Yamasani
68001f21354654a315ea2a2a1668bbda50645123d4aAdam Powell    private final SearchView.OnQueryTextListener mOnQueryChangeListener =
68101f21354654a315ea2a2a1668bbda50645123d4aAdam Powell            new SearchView.OnQueryTextListener() {
682968ec938399033d280b1648123104ac567f2a093Amith Yamasani
68301f21354654a315ea2a2a1668bbda50645123d4aAdam Powell        public boolean onQueryTextSubmit(String query) {
684968ec938399033d280b1648123104ac567f2a093Amith Yamasani            dismiss();
685968ec938399033d280b1648123104ac567f2a093Amith Yamasani            return false;
686968ec938399033d280b1648123104ac567f2a093Amith Yamasani        }
687968ec938399033d280b1648123104ac567f2a093Amith Yamasani
68801f21354654a315ea2a2a1668bbda50645123d4aAdam Powell        public boolean onQueryTextChange(String newText) {
689968ec938399033d280b1648123104ac567f2a093Amith Yamasani            return false;
690968ec938399033d280b1648123104ac567f2a093Amith Yamasani        }
691968ec938399033d280b1648123104ac567f2a093Amith Yamasani    };
692968ec938399033d280b1648123104ac567f2a093Amith Yamasani
69301f21354654a315ea2a2a1668bbda50645123d4aAdam Powell    private final SearchView.OnSuggestionListener mOnSuggestionSelectionListener =
69401f21354654a315ea2a2a1668bbda50645123d4aAdam Powell            new SearchView.OnSuggestionListener() {
695968ec938399033d280b1648123104ac567f2a093Amith Yamasani
69601f21354654a315ea2a2a1668bbda50645123d4aAdam Powell        public boolean onSuggestionSelect(int position) {
697968ec938399033d280b1648123104ac567f2a093Amith Yamasani            return false;
698968ec938399033d280b1648123104ac567f2a093Amith Yamasani        }
699968ec938399033d280b1648123104ac567f2a093Amith Yamasani
70001f21354654a315ea2a2a1668bbda50645123d4aAdam Powell        public boolean onSuggestionClick(int position) {
701968ec938399033d280b1648123104ac567f2a093Amith Yamasani            dismiss();
702968ec938399033d280b1648123104ac567f2a093Amith Yamasani            return false;
703968ec938399033d280b1648123104ac567f2a093Amith Yamasani        }
704968ec938399033d280b1648123104ac567f2a093Amith Yamasani    };
7059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
707968ec938399033d280b1648123104ac567f2a093Amith Yamasani     * Sets the text in the query box, updating the suggestions.
7089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
709968ec938399033d280b1648123104ac567f2a093Amith Yamasani    private void setUserQuery(String query) {
710968ec938399033d280b1648123104ac567f2a093Amith Yamasani        if (query == null) {
711968ec938399033d280b1648123104ac567f2a093Amith Yamasani            query = "";
712968ec938399033d280b1648123104ac567f2a093Amith Yamasani        }
713968ec938399033d280b1648123104ac567f2a093Amith Yamasani        mUserQuery = query;
714968ec938399033d280b1648123104ac567f2a093Amith Yamasani        mSearchAutoComplete.setText(query);
715968ec938399033d280b1648123104ac567f2a093Amith Yamasani        mSearchAutoComplete.setSelection(query.length());
7169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
718