author | Lucas Rocha <lucasr@mozilla.com> |
Tue, 25 Jun 2013 17:51:57 +0100 | |
changeset 143352 | 3561c794b2e4f880411672a4d3fcab0f5582f537 |
parent 143351 | 5e477b9520a28f19e18ef24576b7af0186fa4d44 |
child 143353 | dff89eb24573650c47235051a3a93692a69a19d5 |
push id | 25130 |
push user | lrocha@mozilla.com |
push date | Wed, 21 Aug 2013 09:41:27 +0000 |
treeherder | mozilla-central@b2486721572e [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | bnicholson |
bugs | 862794 |
milestone | 24.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/mobile/android/base/Makefile.in +++ b/mobile/android/base/Makefile.in @@ -221,16 +221,17 @@ FENNEC_JAVA_FILES = \ home/HomeListView.java \ home/HomePager.java \ home/HomePagerTabStrip.java \ home/FadedTextView.java \ home/FaviconsLoader.java \ home/TopBookmarkItemView.java \ home/TopBookmarksView.java \ home/TwoLinePageRow.java \ + home/VisitedPage.java \ menu/GeckoMenu.java \ menu/GeckoMenuInflater.java \ menu/GeckoMenuItem.java \ menu/GeckoSubMenu.java \ menu/MenuItemActionBar.java \ menu/MenuItemDefault.java \ menu/MenuPanel.java \ menu/MenuPopup.java \
--- a/mobile/android/base/home/HomePager.java +++ b/mobile/android/base/home/HomePager.java @@ -22,16 +22,17 @@ import java.util.EnumMap; import java.util.EnumSet; public class HomePager extends ViewPager { private final Context mContext; private volatile boolean mLoaded; // List of pages in order. private enum Page { + VISITED, BOOKMARKS } private EnumMap<Page, Fragment> mPages = new EnumMap<Page, Fragment>(Page.class); public interface OnUrlOpenListener { public void onUrlOpen(String url); } @@ -51,16 +52,17 @@ public class HomePager extends ViewPager * * @param fm FragmentManager for the adapter */ public void show(FragmentManager fm) { mLoaded = true; TabsAdapter adapter = new TabsAdapter(fm); // Add the pages to the adapter in order. + adapter.addTab(Page.VISITED, VisitedPage.class, null, getContext().getString(R.string.visited_title)); adapter.addTab(Page.BOOKMARKS, BookmarksPage.class, null, getContext().getString(R.string.bookmarks_title)); setAdapter(adapter); setVisibility(VISIBLE); } /** * Hides the pager and removes all child fragments.
new file mode 100644 --- /dev/null +++ b/mobile/android/base/home/VisitedPage.java @@ -0,0 +1,223 @@ +/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*- + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +package org.mozilla.gecko.home; + +import org.mozilla.gecko.R; +import org.mozilla.gecko.SimpleCursorLoader; +import org.mozilla.gecko.db.BrowserDB; +import org.mozilla.gecko.db.BrowserDB.URLColumns; +import org.mozilla.gecko.gfx.BitmapUtils; +import org.mozilla.gecko.home.HomePager.OnUrlOpenListener; +import org.mozilla.gecko.home.TwoLinePageRow; + +import android.app.Activity; +import android.content.ContentResolver; +import android.content.Context; +import android.database.Cursor; +import android.graphics.Bitmap; +import android.os.Bundle; +import android.support.v4.app.Fragment; +import android.support.v4.app.LoaderManager; +import android.support.v4.app.LoaderManager.LoaderCallbacks; +import android.support.v4.content.Loader; +import android.view.View; +import android.view.ViewGroup; +import android.view.LayoutInflater; +import android.widget.AdapterView; +import android.widget.ListView; +import android.widget.SimpleCursorAdapter; + +/** + * Fragment that displays frecency search results in a ListView. + */ +public class VisitedPage extends HomeFragment { + // Logging tag name + private static final String LOGTAG = "GeckoVisitedPage"; + + // Cursor loader ID for search query + private static final int FRECENCY_LOADER_ID = 0; + + // Cursor loader ID for favicons query + private static final int FAVICONS_LOADER_ID = 1; + + // Adapter for the list of search results + private VisitedAdapter mAdapter; + + // The view shown by the fragment. + private ListView mList; + + // Callbacks used for the search and favicon cursor loaders + private CursorLoaderCallbacks mCursorLoaderCallbacks; + + // Inflater used by the adapter + private LayoutInflater mInflater; + + // On URL open listener + private OnUrlOpenListener mUrlOpenListener; + + public VisitedPage() { + mUrlOpenListener = null; + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + + try { + mUrlOpenListener = (OnUrlOpenListener) activity; + } catch (ClassCastException e) { + throw new ClassCastException(activity.toString() + + " must implement HomePager.OnUrlOpenListener"); + } + + mInflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + } + + @Override + public void onDetach() { + super.onDetach(); + + mInflater = null; + mUrlOpenListener = null; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + // All list views are styled to look the same with a global activity theme. + // If the style of the list changes, inflate it from an XML. + mList = new HomeListView(container.getContext()); + return mList; + } + + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + + mList.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView<?> parent, View view, int position, long id) { + final Cursor c = mAdapter.getCursor(); + if (c == null || !c.moveToPosition(position)) { + return; + } + + final String url = c.getString(c.getColumnIndexOrThrow(URLColumns.URL)); + mUrlOpenListener.onUrlOpen(url); + } + }); + + registerForContextMenu(mList); + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + mList = null; + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + // Intialize the search adapter + mAdapter = new VisitedAdapter(getActivity()); + mList.setAdapter(mAdapter); + + // Create callbacks before the initial loader is started + mCursorLoaderCallbacks = new CursorLoaderCallbacks(); + + // Reconnect to the loader only if present + getLoaderManager().initLoader(FRECENCY_LOADER_ID, null, mCursorLoaderCallbacks); + } + + private static class FrecencyCursorLoader extends SimpleCursorLoader { + // Max number of search results + private static final int SEARCH_LIMIT = 50; + + public FrecencyCursorLoader(Context context) { + super(context); + } + + @Override + public Cursor loadCursor() { + final ContentResolver cr = getContext().getContentResolver(); + return BrowserDB.filter(cr, "", SEARCH_LIMIT); + } + } + + private class VisitedAdapter extends SimpleCursorAdapter { + public VisitedAdapter(Context context) { + super(context, -1, null, new String[] {}, new int[] {}); + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + final TwoLinePageRow row; + if (convertView == null) { + row = (TwoLinePageRow) mInflater.inflate(R.layout.home_item_row, mList, false); + } else { + row = (TwoLinePageRow) convertView; + } + + final Cursor c = getCursor(); + if (!c.moveToPosition(position)) { + throw new IllegalStateException("Couldn't move cursor to position " + position); + } + + row.updateFromCursor(c); + + return row; + } + } + + private class CursorLoaderCallbacks implements LoaderCallbacks<Cursor> { + @Override + public Loader<Cursor> onCreateLoader(int id, Bundle args) { + switch(id) { + case FRECENCY_LOADER_ID: + return new FrecencyCursorLoader(getActivity()); + + case FAVICONS_LOADER_ID: + return FaviconsLoader.createInstance(getActivity(), args); + } + + return null; + } + + @Override + public void onLoadFinished(Loader<Cursor> loader, Cursor c) { + final int loaderId = loader.getId(); + switch(loaderId) { + case FRECENCY_LOADER_ID: + mAdapter.swapCursor(c); + + FaviconsLoader.restartFromCursor(getLoaderManager(), FAVICONS_LOADER_ID, + mCursorLoaderCallbacks, c); + break; + + case FAVICONS_LOADER_ID: + // Causes the listview to recreate its children and use the + // now in-memory favicons. + mAdapter.notifyDataSetChanged(); + break; + } + } + + @Override + public void onLoaderReset(Loader<Cursor> loader) { + final int loaderId = loader.getId(); + switch(loaderId) { + case FRECENCY_LOADER_ID: + mAdapter.swapCursor(null); + break; + + case FAVICONS_LOADER_ID: + // Do nothing + break; + } + } + } +} \ No newline at end of file
--- a/mobile/android/base/locales/en-US/android_strings.dtd +++ b/mobile/android/base/locales/en-US/android_strings.dtd @@ -8,16 +8,17 @@ <!ENTITY no_space_to_start_error "There is not enough space available for &brandShortName; to start."> <!ENTITY error_loading_file "An error occurred when trying to load files required to run &brandShortName;"> <!ENTITY all_pages_title "Top Sites"> <!ENTITY bookmarks_title "Bookmarks"> <!ENTITY history_title "History"> <!ENTITY switch_to_tab "Switch to tab"> +<!ENTITY visited_title "Visited"> <!ENTITY crash_reporter_title "&brandShortName; Crash Reporter"> <!ENTITY crash_message2 "&brandShortName; had a problem and crashed. Your tabs should be listed on the &brandShortName; Start page when you restart."> <!ENTITY crash_send_report_message3 "Tell &vendorShortName; about this crash so they can fix it"> <!ENTITY crash_include_url2 "Include the address of the page I was on"> <!ENTITY crash_sorry "We\'re sorry"> <!ENTITY crash_comment "Add a comment (comments are publicly visible)"> <!ENTITY crash_allow_contact2 "Allow &vendorShortName; to contact me about this report">
--- a/mobile/android/base/strings.xml.in +++ b/mobile/android/base/strings.xml.in @@ -22,16 +22,17 @@ <string name="splash_bookmarks_history">&splash_bookmarks_history;</string> <string name="no_space_to_start_error">&no_space_to_start_error;</string> <string name="error_loading_file">&error_loading_file;</string> <string name="all_pages_title">&all_pages_title;</string> <string name="bookmarks_title">&bookmarks_title;</string> <string name="history_title">&history_title;</string> <string name="switch_to_tab">&switch_to_tab;</string> + <string name="visited_title">&visited_title;</string> <string name="crash_reporter_title">&crash_reporter_title;</string> <string name="crash_message2">&crash_message2;</string> <string name="crash_send_report_message3">&crash_send_report_message3;</string> <string name="crash_include_url2">&crash_include_url2;</string> <string name="crash_sorry">&crash_sorry;</string> <string name="crash_comment">&crash_comment;</string> <string name="crash_allow_contact2">&crash_allow_contact2;</string>