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