CorpusSelectionDialog.java revision 62adab88055fd0ef6779242245cdc8c3ae5f999c
1/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.quicksearchbox;
18
19import com.android.quicksearchbox.ui.CorporaAdapter;
20import com.android.quicksearchbox.ui.CorpusViewFactory;
21
22import android.app.Dialog;
23import android.app.SearchManager;
24import android.content.ActivityNotFoundException;
25import android.content.Context;
26import android.content.Intent;
27import android.os.Bundle;
28import android.util.Log;
29import android.view.KeyEvent;
30import android.view.Menu;
31import android.view.MotionEvent;
32import android.view.View;
33import android.view.Window;
34import android.view.WindowManager;
35import android.widget.AdapterView;
36import android.widget.GridView;
37
38
39/**
40 * Corpus selection dialog.
41 */
42public class CorpusSelectionDialog extends Dialog {
43
44    private static final boolean DBG = true;
45    private static final String TAG = "QSB.SelectSearchSourceDialog";
46
47    private static final int NUM_COLUMNS = 4;
48
49    private GridView mCorpusGrid;
50
51    private Corpus mCorpus;
52
53    private String mQuery;
54
55    private Bundle mAppData;
56
57    private CorporaAdapter mAdapter;
58
59    public CorpusSelectionDialog(Context context) {
60        super(context, R.style.Theme_SelectSearchSource);
61        setContentView(R.layout.corpus_selection_dialog);
62        mCorpusGrid = (GridView) findViewById(R.id.corpus_grid);
63        mCorpusGrid.setNumColumns(NUM_COLUMNS);
64        mCorpusGrid.setOnItemClickListener(new CorpusClickListener());
65        // TODO: for some reason, putting this in the XML layout instead makes
66        // the list items unclickable.
67        mCorpusGrid.setFocusable(true);
68        positionWindow();
69    }
70
71    public void setCorpus(Corpus corpus) {
72        mCorpus = corpus;
73    }
74
75    public void setQuery(String query) {
76        mQuery = query;
77    }
78
79    public void setAppData(Bundle appData) {
80        mAppData = appData;
81    }
82
83    private void positionWindow() {
84        Window window = getWindow();
85        WindowManager.LayoutParams lp = window.getAttributes();
86        lp.width = WindowManager.LayoutParams.MATCH_PARENT;
87        lp.height = WindowManager.LayoutParams.MATCH_PARENT;
88        // Put window on top of input method
89        lp.flags |= WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
90        window.setAttributes(lp);
91        if (DBG) Log.d(TAG, "Window params: " + lp);
92    }
93
94    @Override
95    protected void onStart() {
96        super.onStart();
97        CorporaAdapter adapter =
98                CorporaAdapter.createGridAdapter(getViewFactory(), getCorpusRanker());
99        setAdapter(adapter);
100        mCorpusGrid.setSelection(adapter.getCorpusPosition(mCorpus));
101    }
102
103    @Override
104    protected void onStop() {
105        setAdapter(null);
106        super.onStop();
107    }
108
109    @Override
110    public boolean onCreateOptionsMenu(Menu menu) {
111        super.onCreateOptionsMenu(menu);
112        SearchSettings.addSearchSettingsMenuItem(getContext(), menu);
113        return true;
114    }
115
116    @Override
117    public boolean onTouchEvent(MotionEvent event) {
118        if (event.getAction() == MotionEvent.ACTION_DOWN) {
119            // Cancel dialog on any touch down event which is not handled by the corpus grid
120            cancel();
121            return true;
122        }
123        return false;
124    }
125
126    @Override
127    public boolean onKeyDown(int keyCode, KeyEvent event) {
128        boolean handled = super.onKeyDown(keyCode, event);
129        if (handled) {
130            return handled;
131        }
132        // Dismiss dialog on up move when nothing, or an item on the top row, is selected.
133        if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {
134            int selectedRow = mCorpusGrid.getSelectedItemPosition() / NUM_COLUMNS;
135            if (selectedRow <= 0) {
136                cancel();
137                return true;
138            }
139        }
140        // Dismiss dialog when typing on hard keyboard (soft keyboard is behind the dialog,
141        // so that can't be typed on)
142        if (event.isPrintingKey()) {
143            cancel();
144            return true;
145        }
146        return false;
147    }
148
149    private void setAdapter(CorporaAdapter adapter) {
150        if (adapter == mAdapter) return;
151        if (mAdapter != null) mAdapter.close();
152        mAdapter = adapter;
153        mCorpusGrid.setAdapter(mAdapter);
154    }
155
156    private QsbApplication getQsbApplication() {
157        return (QsbApplication) getContext().getApplicationContext();
158    }
159
160    private CorpusRanker getCorpusRanker() {
161        return getQsbApplication().getCorpusRanker();
162    }
163
164    private CorpusViewFactory getViewFactory() {
165        return getQsbApplication().getCorpusViewFactory();
166    }
167
168    protected void selectCorpus(Corpus corpus) {
169        dismiss();
170        // If a new source was selected, start QSB with that source.
171        // If the old source was selected, just finish.
172        if (!isCurrentCorpus(corpus)) {
173            switchCorpus(corpus);
174        }
175    }
176
177    private boolean isCurrentCorpus(Corpus corpus) {
178        if (corpus == null) return mCorpus == null;
179        return corpus.equals(mCorpus);
180    }
181
182    private void switchCorpus(Corpus corpus) {
183        if (DBG) Log.d(TAG, "switchSource(" + corpus + ")");
184
185        Intent searchIntent = new Intent(SearchManager.INTENT_ACTION_GLOBAL_SEARCH);
186        searchIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
187        searchIntent.setData(SearchActivity.getCorpusUri(corpus));
188        searchIntent.putExtra(SearchManager.QUERY, mQuery);
189        searchIntent.putExtra(SearchManager.APP_DATA, mAppData);
190
191        try {
192            if (DBG) Log.d(TAG, "startActivity(" + searchIntent.toUri(0) + ")");
193            getOwnerActivity().startActivity(searchIntent);
194        } catch (ActivityNotFoundException ex) {
195            Log.e(TAG, "Couldn't start QSB: " + ex);
196        }
197    }
198
199    private class CorpusClickListener implements AdapterView.OnItemClickListener {
200        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
201            Corpus corpus = (Corpus) parent.getItemAtPosition(position);
202            selectCorpus(corpus);
203        }
204    }
205}
206