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