michael@0: /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*- michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: package org.mozilla.gecko.home; michael@0: michael@0: import org.mozilla.gecko.R; michael@0: import org.mozilla.gecko.db.BrowserDB.URLColumns; michael@0: michael@0: import android.content.Context; michael@0: import android.database.Cursor; michael@0: import android.os.Bundle; michael@0: import android.support.v4.app.DialogFragment; michael@0: import android.support.v4.app.LoaderManager; michael@0: import android.support.v4.app.LoaderManager.LoaderCallbacks; michael@0: import android.support.v4.content.Loader; michael@0: import android.support.v4.widget.CursorAdapter; michael@0: import android.text.Editable; michael@0: import android.text.TextUtils; michael@0: import android.text.TextWatcher; michael@0: import android.view.KeyEvent; michael@0: import android.view.LayoutInflater; michael@0: import android.view.View; michael@0: import android.view.ViewGroup; michael@0: import android.view.WindowManager; michael@0: import android.widget.AdapterView; michael@0: import android.widget.EditText; michael@0: import android.widget.ListView; michael@0: michael@0: /** michael@0: * Dialog fragment that displays frecency search results, for pinning a site, in a GridView. michael@0: */ michael@0: class PinSiteDialog extends DialogFragment { michael@0: // Listener for url selection michael@0: public static interface OnSiteSelectedListener { michael@0: public void onSiteSelected(String url, String title); michael@0: } michael@0: michael@0: // Cursor loader ID for search query michael@0: private static final int LOADER_ID_SEARCH = 0; michael@0: michael@0: // Holds the current search term to use in the query michael@0: private String mSearchTerm; michael@0: michael@0: // Adapter for the list of search results michael@0: private SearchAdapter mAdapter; michael@0: michael@0: // Search entry michael@0: private EditText mSearch; michael@0: michael@0: // Search results michael@0: private ListView mList; michael@0: michael@0: // Callbacks used for the search loader michael@0: private CursorLoaderCallbacks mLoaderCallbacks; michael@0: michael@0: // Bookmark selected listener michael@0: private OnSiteSelectedListener mOnSiteSelectedListener; michael@0: michael@0: public static PinSiteDialog newInstance() { michael@0: return new PinSiteDialog(); michael@0: } michael@0: michael@0: private PinSiteDialog() { michael@0: } michael@0: michael@0: @Override michael@0: public void onCreate(Bundle savedInstanceState) { michael@0: super.onCreate(savedInstanceState); michael@0: michael@0: setStyle(DialogFragment.STYLE_NO_TITLE, android.R.style.Theme_Holo_Light_Dialog); michael@0: } michael@0: michael@0: @Override michael@0: public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { michael@0: // All list views are styled to look the same with a global activity theme. michael@0: // If the style of the list changes, inflate it from an XML. michael@0: return inflater.inflate(R.layout.pin_site_dialog, container, false); michael@0: } michael@0: michael@0: @Override michael@0: public void onViewCreated(View view, Bundle savedInstanceState) { michael@0: super.onViewCreated(view, savedInstanceState); michael@0: michael@0: mSearch = (EditText) view.findViewById(R.id.search); michael@0: mSearch.addTextChangedListener(new TextWatcher() { michael@0: @Override michael@0: public void afterTextChanged(Editable s) { michael@0: } michael@0: michael@0: @Override michael@0: public void beforeTextChanged(CharSequence s, int start, int count, int after) { michael@0: } michael@0: michael@0: @Override michael@0: public void onTextChanged(CharSequence s, int start, int before, int count) { michael@0: setSearchTerm(mSearch.getText().toString()); michael@0: filter(mSearchTerm); michael@0: } michael@0: }); michael@0: michael@0: mSearch.setOnKeyListener(new View.OnKeyListener() { michael@0: @Override michael@0: public boolean onKey(View v, int keyCode, KeyEvent event) { michael@0: if (keyCode != KeyEvent.KEYCODE_ENTER || mOnSiteSelectedListener == null) { michael@0: return false; michael@0: } michael@0: michael@0: // If the user manually entered a search term or URL, wrap the value in michael@0: // a special URI until we can get a valid URL for this bookmark. michael@0: final String text = mSearch.getText().toString().trim(); michael@0: if (!TextUtils.isEmpty(text)) { michael@0: final String url = TopSitesPanel.encodeUserEnteredUrl(text); michael@0: mOnSiteSelectedListener.onSiteSelected(url, text); michael@0: dismiss(); michael@0: } michael@0: michael@0: return true; michael@0: } michael@0: }); michael@0: michael@0: mSearch.setOnFocusChangeListener(new View.OnFocusChangeListener() { michael@0: @Override michael@0: public void onFocusChange(View v, boolean hasFocus) { michael@0: if (hasFocus) { michael@0: getDialog().getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE); michael@0: } michael@0: } michael@0: }); michael@0: michael@0: mList = (HomeListView) view.findViewById(R.id.list); michael@0: mList.setOnItemClickListener(new AdapterView.OnItemClickListener() { michael@0: @Override michael@0: public void onItemClick(AdapterView parent, View view, int position, long id) { michael@0: if (mOnSiteSelectedListener != null) { michael@0: final Cursor c = mAdapter.getCursor(); michael@0: if (c == null || !c.moveToPosition(position)) { michael@0: return; michael@0: } michael@0: michael@0: final String url = c.getString(c.getColumnIndexOrThrow(URLColumns.URL)); michael@0: final String title = c.getString(c.getColumnIndexOrThrow(URLColumns.TITLE)); michael@0: mOnSiteSelectedListener.onSiteSelected(url, title); michael@0: } michael@0: michael@0: // Dismiss the fragment and the dialog. michael@0: dismiss(); michael@0: } michael@0: }); michael@0: } michael@0: michael@0: @Override michael@0: public void onActivityCreated(Bundle savedInstanceState) { michael@0: super.onActivityCreated(savedInstanceState); michael@0: michael@0: final LoaderManager manager = getLoaderManager(); michael@0: michael@0: // Initialize the search adapter michael@0: mAdapter = new SearchAdapter(getActivity()); michael@0: mList.setAdapter(mAdapter); michael@0: michael@0: // Create callbacks before the initial loader is started michael@0: mLoaderCallbacks = new CursorLoaderCallbacks(); michael@0: michael@0: // Reconnect to the loader only if present michael@0: manager.initLoader(LOADER_ID_SEARCH, null, mLoaderCallbacks); michael@0: michael@0: // If there is a search term, put it in the text field michael@0: if (!TextUtils.isEmpty(mSearchTerm)) { michael@0: mSearch.setText(mSearchTerm); michael@0: mSearch.selectAll(); michael@0: } michael@0: michael@0: // Always start with an empty filter michael@0: filter(""); michael@0: } michael@0: michael@0: @Override michael@0: public void onDestroyView() { michael@0: super.onDestroyView(); michael@0: michael@0: // Discard any additional site selection as the dialog michael@0: // is getting destroyed (see bug 935542). michael@0: setOnSiteSelectedListener(null); michael@0: } michael@0: michael@0: public void setSearchTerm(String searchTerm) { michael@0: mSearchTerm = searchTerm; michael@0: } michael@0: michael@0: private void filter(String searchTerm) { michael@0: // Restart loaders with the new search term michael@0: SearchLoader.restart(getLoaderManager(), LOADER_ID_SEARCH, mLoaderCallbacks, searchTerm); michael@0: } michael@0: michael@0: public void setOnSiteSelectedListener(OnSiteSelectedListener listener) { michael@0: mOnSiteSelectedListener = listener; michael@0: } michael@0: michael@0: private static class SearchAdapter extends CursorAdapter { michael@0: private LayoutInflater mInflater; michael@0: michael@0: public SearchAdapter(Context context) { michael@0: super(context, null, 0); michael@0: mInflater = LayoutInflater.from(context); michael@0: } michael@0: michael@0: @Override michael@0: public void bindView(View view, Context context, Cursor cursor) { michael@0: TwoLinePageRow row = (TwoLinePageRow) view; michael@0: row.setShowIcons(false); michael@0: row.updateFromCursor(cursor); michael@0: } michael@0: michael@0: @Override michael@0: public View newView(Context context, Cursor cursor, ViewGroup parent) { michael@0: return (TwoLinePageRow) mInflater.inflate(R.layout.home_item_row, parent, false); michael@0: } michael@0: } michael@0: michael@0: private class CursorLoaderCallbacks implements LoaderCallbacks { michael@0: @Override michael@0: public Loader onCreateLoader(int id, Bundle args) { michael@0: return SearchLoader.createInstance(getActivity(), args); michael@0: } michael@0: michael@0: @Override michael@0: public void onLoadFinished(Loader loader, Cursor c) { michael@0: mAdapter.swapCursor(c); michael@0: } michael@0: michael@0: @Override michael@0: public void onLoaderReset(Loader loader) { michael@0: mAdapter.swapCursor(null); michael@0: } michael@0: } michael@0: }