Wed, 31 Dec 2014 07:22:50 +0100
Correct previous dual key logic pending first delivery installment.
1 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 package org.mozilla.gecko.home;
8 import org.mozilla.gecko.R;
9 import org.mozilla.gecko.db.BrowserDB.URLColumns;
11 import android.content.Context;
12 import android.database.Cursor;
13 import android.os.Bundle;
14 import android.support.v4.app.DialogFragment;
15 import android.support.v4.app.LoaderManager;
16 import android.support.v4.app.LoaderManager.LoaderCallbacks;
17 import android.support.v4.content.Loader;
18 import android.support.v4.widget.CursorAdapter;
19 import android.text.Editable;
20 import android.text.TextUtils;
21 import android.text.TextWatcher;
22 import android.view.KeyEvent;
23 import android.view.LayoutInflater;
24 import android.view.View;
25 import android.view.ViewGroup;
26 import android.view.WindowManager;
27 import android.widget.AdapterView;
28 import android.widget.EditText;
29 import android.widget.ListView;
31 /**
32 * Dialog fragment that displays frecency search results, for pinning a site, in a GridView.
33 */
34 class PinSiteDialog extends DialogFragment {
35 // Listener for url selection
36 public static interface OnSiteSelectedListener {
37 public void onSiteSelected(String url, String title);
38 }
40 // Cursor loader ID for search query
41 private static final int LOADER_ID_SEARCH = 0;
43 // Holds the current search term to use in the query
44 private String mSearchTerm;
46 // Adapter for the list of search results
47 private SearchAdapter mAdapter;
49 // Search entry
50 private EditText mSearch;
52 // Search results
53 private ListView mList;
55 // Callbacks used for the search loader
56 private CursorLoaderCallbacks mLoaderCallbacks;
58 // Bookmark selected listener
59 private OnSiteSelectedListener mOnSiteSelectedListener;
61 public static PinSiteDialog newInstance() {
62 return new PinSiteDialog();
63 }
65 private PinSiteDialog() {
66 }
68 @Override
69 public void onCreate(Bundle savedInstanceState) {
70 super.onCreate(savedInstanceState);
72 setStyle(DialogFragment.STYLE_NO_TITLE, android.R.style.Theme_Holo_Light_Dialog);
73 }
75 @Override
76 public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
77 // All list views are styled to look the same with a global activity theme.
78 // If the style of the list changes, inflate it from an XML.
79 return inflater.inflate(R.layout.pin_site_dialog, container, false);
80 }
82 @Override
83 public void onViewCreated(View view, Bundle savedInstanceState) {
84 super.onViewCreated(view, savedInstanceState);
86 mSearch = (EditText) view.findViewById(R.id.search);
87 mSearch.addTextChangedListener(new TextWatcher() {
88 @Override
89 public void afterTextChanged(Editable s) {
90 }
92 @Override
93 public void beforeTextChanged(CharSequence s, int start, int count, int after) {
94 }
96 @Override
97 public void onTextChanged(CharSequence s, int start, int before, int count) {
98 setSearchTerm(mSearch.getText().toString());
99 filter(mSearchTerm);
100 }
101 });
103 mSearch.setOnKeyListener(new View.OnKeyListener() {
104 @Override
105 public boolean onKey(View v, int keyCode, KeyEvent event) {
106 if (keyCode != KeyEvent.KEYCODE_ENTER || mOnSiteSelectedListener == null) {
107 return false;
108 }
110 // If the user manually entered a search term or URL, wrap the value in
111 // a special URI until we can get a valid URL for this bookmark.
112 final String text = mSearch.getText().toString().trim();
113 if (!TextUtils.isEmpty(text)) {
114 final String url = TopSitesPanel.encodeUserEnteredUrl(text);
115 mOnSiteSelectedListener.onSiteSelected(url, text);
116 dismiss();
117 }
119 return true;
120 }
121 });
123 mSearch.setOnFocusChangeListener(new View.OnFocusChangeListener() {
124 @Override
125 public void onFocusChange(View v, boolean hasFocus) {
126 if (hasFocus) {
127 getDialog().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
128 }
129 }
130 });
132 mList = (HomeListView) view.findViewById(R.id.list);
133 mList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
134 @Override
135 public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
136 if (mOnSiteSelectedListener != null) {
137 final Cursor c = mAdapter.getCursor();
138 if (c == null || !c.moveToPosition(position)) {
139 return;
140 }
142 final String url = c.getString(c.getColumnIndexOrThrow(URLColumns.URL));
143 final String title = c.getString(c.getColumnIndexOrThrow(URLColumns.TITLE));
144 mOnSiteSelectedListener.onSiteSelected(url, title);
145 }
147 // Dismiss the fragment and the dialog.
148 dismiss();
149 }
150 });
151 }
153 @Override
154 public void onActivityCreated(Bundle savedInstanceState) {
155 super.onActivityCreated(savedInstanceState);
157 final LoaderManager manager = getLoaderManager();
159 // Initialize the search adapter
160 mAdapter = new SearchAdapter(getActivity());
161 mList.setAdapter(mAdapter);
163 // Create callbacks before the initial loader is started
164 mLoaderCallbacks = new CursorLoaderCallbacks();
166 // Reconnect to the loader only if present
167 manager.initLoader(LOADER_ID_SEARCH, null, mLoaderCallbacks);
169 // If there is a search term, put it in the text field
170 if (!TextUtils.isEmpty(mSearchTerm)) {
171 mSearch.setText(mSearchTerm);
172 mSearch.selectAll();
173 }
175 // Always start with an empty filter
176 filter("");
177 }
179 @Override
180 public void onDestroyView() {
181 super.onDestroyView();
183 // Discard any additional site selection as the dialog
184 // is getting destroyed (see bug 935542).
185 setOnSiteSelectedListener(null);
186 }
188 public void setSearchTerm(String searchTerm) {
189 mSearchTerm = searchTerm;
190 }
192 private void filter(String searchTerm) {
193 // Restart loaders with the new search term
194 SearchLoader.restart(getLoaderManager(), LOADER_ID_SEARCH, mLoaderCallbacks, searchTerm);
195 }
197 public void setOnSiteSelectedListener(OnSiteSelectedListener listener) {
198 mOnSiteSelectedListener = listener;
199 }
201 private static class SearchAdapter extends CursorAdapter {
202 private LayoutInflater mInflater;
204 public SearchAdapter(Context context) {
205 super(context, null, 0);
206 mInflater = LayoutInflater.from(context);
207 }
209 @Override
210 public void bindView(View view, Context context, Cursor cursor) {
211 TwoLinePageRow row = (TwoLinePageRow) view;
212 row.setShowIcons(false);
213 row.updateFromCursor(cursor);
214 }
216 @Override
217 public View newView(Context context, Cursor cursor, ViewGroup parent) {
218 return (TwoLinePageRow) mInflater.inflate(R.layout.home_item_row, parent, false);
219 }
220 }
222 private class CursorLoaderCallbacks implements LoaderCallbacks<Cursor> {
223 @Override
224 public Loader<Cursor> onCreateLoader(int id, Bundle args) {
225 return SearchLoader.createInstance(getActivity(), args);
226 }
228 @Override
229 public void onLoadFinished(Loader<Cursor> loader, Cursor c) {
230 mAdapter.swapCursor(c);
231 }
233 @Override
234 public void onLoaderReset(Loader<Cursor> loader) {
235 mAdapter.swapCursor(null);
236 }
237 }
238 }