diff --git a/mobile/android/base/BrowserApp.java b/mobile/android/base/BrowserApp.java index 46ee33c810d..7b5b0ef2ffc 100644 --- a/mobile/android/base/BrowserApp.java +++ b/mobile/android/base/BrowserApp.java @@ -1323,7 +1323,7 @@ abstract public class BrowserApp extends GeckoApp animator.setUseHardwareLayer(false); mBrowserToolbar.startEditing(url, animator); - showHomePagerWithAnimator(HomePager.Page.HISTORY, animator); + showHomePagerWithAnimator(HomePager.Page.VISITED, animator); animator.start(); } @@ -1402,6 +1402,14 @@ abstract public class BrowserApp extends GeckoApp return; } + // Hide any visible homepager subpages + final FragmentManager fm = getSupportFragmentManager(); + final Fragment subPage = fm.findFragmentByTag(HomePager.SUBPAGE_TAG); + if (subPage != null) { + fm.beginTransaction().remove(subPage).commitAllowingStateLoss(); + fm.popBackStack(); + } + // FIXME: do animation if animate is true mHomePager.hide(); diff --git a/mobile/android/base/Makefile.in b/mobile/android/base/Makefile.in index e2d524f8348..f5b00559c95 100644 --- a/mobile/android/base/Makefile.in +++ b/mobile/android/base/Makefile.in @@ -229,8 +229,6 @@ FENNEC_JAVA_FILES = \ home/FadedTextView.java \ home/FaviconsLoader.java \ home/LastTabsPage.java \ - home/MostRecentPage.java \ - home/MostVisitedPage.java \ home/PinBookmarkDialog.java \ home/ReadingListPage.java \ home/SearchEngine.java \ @@ -242,6 +240,7 @@ FENNEC_JAVA_FILES = \ home/TopBookmarksAdapter.java \ home/TopBookmarksView.java \ home/TwoLinePageRow.java \ + home/VisitedPage.java \ menu/GeckoMenu.java \ menu/GeckoMenuInflater.java \ menu/GeckoMenuItem.java \ @@ -466,13 +465,11 @@ RES_LAYOUT = \ res/layout/home_item_row.xml \ res/layout/home_header_row.xml \ res/layout/home_history_page.xml \ - res/layout/home_history_tabs_indicator.xml \ res/layout/home_last_tabs_page.xml \ res/layout/home_list_with_title.xml \ - res/layout/home_most_recent_page.xml \ - res/layout/home_most_visited_page.xml \ res/layout/home_search_item_row.xml \ res/layout/home_suggestion_prompt.xml \ + res/layout/home_visited_page.xml \ res/layout/web_app.xml \ res/layout/launch_app_list.xml \ res/layout/launch_app_listitem.xml \ @@ -635,9 +632,6 @@ RES_DRAWABLE_MDPI = \ res/drawable-mdpi/ic_url_bar_search.png \ res/drawable-mdpi/ic_url_bar_star.png \ res/drawable-mdpi/ic_url_bar_tab.png \ - res/drawable-mdpi/icon_last_tabs.png \ - res/drawable-mdpi/icon_most_recent.png \ - res/drawable-mdpi/icon_most_visited.png \ res/drawable-mdpi/icon_pageaction.png \ res/drawable-mdpi/progress_spinner_1.png \ res/drawable-mdpi/progress_spinner_2.png \ @@ -710,7 +704,6 @@ RES_DRAWABLE_MDPI = \ res/drawable-mdpi/shadow.png \ res/drawable-mdpi/start.png \ res/drawable-mdpi/marketplace.png \ - res/drawable-mdpi/history_tabs_indicator_selected.9.png \ res/drawable-mdpi/warning.png \ res/drawable-mdpi/warning_doorhanger.png \ $(NULL) @@ -751,9 +744,6 @@ RES_DRAWABLE_HDPI = \ res/drawable-hdpi/ic_url_bar_search.png \ res/drawable-hdpi/ic_url_bar_star.png \ res/drawable-hdpi/ic_url_bar_tab.png \ - res/drawable-hdpi/icon_last_tabs.png \ - res/drawable-hdpi/icon_most_recent.png \ - res/drawable-hdpi/icon_most_visited.png \ res/drawable-hdpi/icon_pageaction.png \ res/drawable-hdpi/tab_indicator_divider.9.png \ res/drawable-hdpi/tab_indicator_selected.9.png \ @@ -804,7 +794,6 @@ RES_DRAWABLE_HDPI = \ res/drawable-hdpi/handle_end.png \ res/drawable-hdpi/handle_middle.png \ res/drawable-hdpi/handle_start.png \ - res/drawable-hdpi/history_tabs_indicator_selected.9.png \ res/drawable-hdpi/warning.png \ res/drawable-hdpi/warning_doorhanger.png \ $(NULL) @@ -843,9 +832,6 @@ RES_DRAWABLE_XHDPI = \ res/drawable-xhdpi/ic_url_bar_search.png \ res/drawable-xhdpi/ic_url_bar_star.png \ res/drawable-xhdpi/ic_url_bar_tab.png \ - res/drawable-xhdpi/icon_last_tabs.png \ - res/drawable-xhdpi/icon_most_recent.png \ - res/drawable-xhdpi/icon_most_visited.png \ res/drawable-xhdpi/icon_pageaction.png \ res/drawable-xhdpi/spinner_default.9.png \ res/drawable-xhdpi/spinner_focused.9.png \ @@ -891,7 +877,6 @@ RES_DRAWABLE_XHDPI = \ res/drawable-xhdpi/handle_end.png \ res/drawable-xhdpi/handle_middle.png \ res/drawable-xhdpi/handle_start.png \ - res/drawable-xhdpi/history_tabs_indicator_selected.9.png \ res/drawable-xhdpi/warning.png \ res/drawable-xhdpi/warning_doorhanger.png \ $(NULL) @@ -1066,8 +1051,6 @@ RES_DRAWABLE += \ res/drawable/favicon_bg.xml \ res/drawable/handle_end_level.xml \ res/drawable/handle_start_level.xml \ - res/drawable/home_history_tabs_indicator.xml \ - res/drawable/home_page_title_background.xml \ res/drawable/ic_menu_back.xml \ res/drawable/ic_menu_desktop_mode_off.xml \ res/drawable/ic_menu_desktop_mode_on.xml \ diff --git a/mobile/android/base/home/HistoryPage.java b/mobile/android/base/home/HistoryPage.java index 8df09988df1..c53f1a04caa 100644 --- a/mobile/android/base/home/HistoryPage.java +++ b/mobile/android/base/home/HistoryPage.java @@ -6,24 +6,100 @@ package org.mozilla.gecko.home; import org.mozilla.gecko.R; -import org.mozilla.gecko.widget.IconTabWidget; -import android.support.v4.app.Fragment; +import org.mozilla.gecko.db.BrowserDB; +import org.mozilla.gecko.db.BrowserDB.URLColumns; +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.content.res.Resources; +import android.database.Cursor; import android.os.Bundle; -import android.view.LayoutInflater; +import android.support.v4.app.LoaderManager.LoaderCallbacks; +import android.support.v4.content.Loader; +import android.support.v4.widget.SimpleCursorAdapter; +import android.util.SparseArray; import android.view.View; import android.view.ViewGroup; import android.view.LayoutInflater; +import android.widget.AdapterView; +import android.widget.ListView; +import android.widget.TextView; -import android.widget.ImageButton; +import java.util.Date; -public class HistoryPage extends HomeFragment - implements IconTabWidget.OnTabChangedListener { +/** + * Fragment that displays recent history in a ListView. + */ +public class HistoryPage extends HomeFragment { // Logging tag name private static final String LOGTAG = "GeckoHistoryPage"; - private IconTabWidget mTabWidget; - private int mSelectedTab; + + // Cursor loader ID for history query + private static final int HISTORY_LOADER_ID = 0; + + // For the time sections in history + private static final long MS_PER_DAY = 86400000; + private static final long MS_PER_WEEK = MS_PER_DAY * 7; + + // The time ranges for each section + private static enum HistorySection { + TODAY, + YESTERDAY, + WEEK, + OLDER + }; + + // Maps headers in the list with their respective sections + private SparseArray mHistorySections; + + // Adapter for the list of search results + private HistoryAdapter 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 static HistoryPage newInstance() { + return new HistoryPage(); + } + + public HistoryPage() { + 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(); + + mHistorySections = null; + mInflater = null; + mUrlOpenListener = null; + } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -32,68 +108,258 @@ public class HistoryPage extends HomeFragment @Override public void onViewCreated(View view, Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); + final TextView title = (TextView) view.findViewById(R.id.title); + title.setText(R.string.history_title); - mTabWidget = (IconTabWidget) view.findViewById(R.id.tab_icon_widget); + mList = (ListView) view.findViewById(R.id.list); - ImageButton button; - final Resources resources = view.getContext().getResources(); + mList.setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + position -= getHistorySectionsCountBefore(position); - button = mTabWidget.addTab(R.drawable.icon_most_visited); - button.setContentDescription(resources.getString(R.string.home_most_visited_title)); + final Cursor c = mAdapter.getCursor(); + if (c == null || !c.moveToPosition(position)) { + return; + } - button = mTabWidget.addTab(R.drawable.icon_most_recent); - button.setContentDescription(resources.getString(R.string.home_most_recent_title)); + final String url = c.getString(c.getColumnIndexOrThrow(URLColumns.URL)); + mUrlOpenListener.onUrlOpen(url); + } + }); - button = mTabWidget.addTab(R.drawable.icon_last_tabs); - button.setContentDescription(resources.getString(R.string.home_last_tabs_title)); - - //Show most visited page as the initial page - showMostVisitedPage(); - - mTabWidget.setTabSelectionListener(this); - mTabWidget.setCurrentTab(mSelectedTab); + registerForContextMenu(mList); } @Override - public void load() {} + public void onDestroyView() { + super.onDestroyView(); + mList = null; + } @Override - public void onTabChanged(int index) { - if (index == mSelectedTab) { + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + + // Initialize map of history sections + mHistorySections = new SparseArray(); + + // Intialize adapter + mAdapter = new HistoryAdapter(getActivity()); + mList.setAdapter(mAdapter); + + // Create callbacks before the initial loader is started + mCursorLoaderCallbacks = new CursorLoaderCallbacks(); + loadIfVisible(); + } + + @Override + protected void load() { + getLoaderManager().initLoader(HISTORY_LOADER_ID, null, mCursorLoaderCallbacks); + } + + private String getHistorySectionTitle(HistorySection section) { + final Resources resources = getActivity().getResources(); + + switch (section) { + case TODAY: + return resources.getString(R.string.history_today_section); + case YESTERDAY: + return resources.getString(R.string.history_yesterday_section); + case WEEK: + return resources.getString(R.string.history_week_section); + case OLDER: + return resources.getString(R.string.history_older_section); + } + + throw new IllegalStateException("Unrecognized history section"); + } + + private int getHistorySectionsCountBefore(int position) { + // Account for the number headers before the given position + int sectionsBefore = 0; + + final int historySectionsCount = mHistorySections.size(); + for (int i = 0; i < historySectionsCount; i++) { + final int sectionPosition = mHistorySections.keyAt(i); + if (sectionPosition > position) { + break; + } + + sectionsBefore++; + } + + return sectionsBefore; + } + + private HistorySection getHistorySectionForTime(long from, long time) { + long delta = from - time; + + if (delta < 0) { + return HistorySection.TODAY; + } + + if (delta < MS_PER_DAY) { + return HistorySection.YESTERDAY; + } + + if (delta < MS_PER_WEEK) { + return HistorySection.WEEK; + } + + return HistorySection.OLDER; + } + + private void loadHistorySections(Cursor c) { + if (c == null || !c.moveToFirst()) { return; } - if (index == 0) { - showMostVisitedPage(); - } else if (index == 1) { - showMostRecentPage(); - } else if (index == 2) { - showLastTabsPage(); + // Clear any history sections that may have been loaded before. + mHistorySections.clear(); + + final Date now = new Date(); + now.setHours(0); + now.setMinutes(0); + now.setSeconds(0); + + final long today = now.getTime(); + HistorySection section = null; + + do { + final int position = c.getPosition(); + final long time = c.getLong(c.getColumnIndexOrThrow(URLColumns.DATE_LAST_VISITED)); + final HistorySection itemSection = getHistorySectionForTime(today, time); + + if (section != itemSection) { + section = itemSection; + mHistorySections.append(position + mHistorySections.size(), section); + } + + // Reached the last section, no need to continue + if (section == HistorySection.OLDER) { + break; + } + } while (c.moveToNext()); + } + + private static class HistoryCursorLoader extends SimpleCursorLoader { + // Max number of history results + private static final int HISTORY_LIMIT = 100; + + public HistoryCursorLoader(Context context) { + super(context); } - mTabWidget.setCurrentTab(index); - mSelectedTab = index; + @Override + public Cursor loadCursor() { + final ContentResolver cr = getContext().getContentResolver(); + return BrowserDB.getRecentHistory(cr, HISTORY_LIMIT); + } } - private void showSubPage(Fragment subPage) { - getChildFragmentManager().beginTransaction() - .addToBackStack(null).replace(R.id.visited_page_container, subPage) - .commitAllowingStateLoss(); + private class HistoryAdapter extends SimpleCursorAdapter { + private static final int ROW_HEADER = 0; + private static final int ROW_STANDARD = 1; + + private static final int ROW_TYPE_COUNT = 2; + + public HistoryAdapter(Context context) { + super(context, -1, null, new String[] {}, new int[] {}); + } + + @Override + public Object getItem(int position) { + final int type = getItemViewType(position); + + // Header items are not in the cursor + if (type == ROW_HEADER) { + return null; + } + + return super.getItem(position - getHistorySectionsCountBefore(position)); + } + + @Override + public int getItemViewType(int position) { + if (mHistorySections.get(position) != null) { + return ROW_HEADER; + } + + return ROW_STANDARD; + } + + @Override + public int getViewTypeCount() { + // view can be either a standard page row, or a header row + return ROW_TYPE_COUNT; + } + + @Override + public boolean isEnabled(int position) { + return (getItemViewType(position) == ROW_STANDARD); + } + + @Override + public int getCount() { + // Add the history section headers to the number of reported results. + return super.getCount() + mHistorySections.size(); + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + final int type = getItemViewType(position); + + if (type == ROW_HEADER) { + final TextView row; + if (convertView == null) { + row = (TextView) mInflater.inflate(R.layout.home_header_row, mList, false); + } else { + row = (TextView) convertView; + } + + final HistorySection section = mHistorySections.get(position); + row.setText(getHistorySectionTitle(section)); + + return row; + } else { + final TwoLinePageRow row; + if (convertView == null) { + row = (TwoLinePageRow) mInflater.inflate(R.layout.home_item_row, mList, false); + } else { + row = (TwoLinePageRow) convertView; + } + + // Account for the search engines + position -= getHistorySectionsCountBefore(position); + + final Cursor c = getCursor(); + if (!c.moveToPosition(position)) { + throw new IllegalStateException("Couldn't move cursor to position " + position); + } + + row.updateFromCursor(c); + + return row; + } + } } - private void showMostVisitedPage() { - final MostVisitedPage mostVisitedPage = MostVisitedPage.newInstance(); - showSubPage(mostVisitedPage); - } + private class CursorLoaderCallbacks implements LoaderCallbacks { + @Override + public Loader onCreateLoader(int id, Bundle args) { + return new HistoryCursorLoader(getActivity()); + } - private void showMostRecentPage() { - final MostRecentPage mostRecentPage = MostRecentPage.newInstance(); - showSubPage(mostRecentPage); - } + @Override + public void onLoadFinished(Loader loader, Cursor c) { + loadHistorySections(c); + mAdapter.swapCursor(c); + } - private void showLastTabsPage() { - final LastTabsPage lastTabsPage = LastTabsPage.newInstance(); - showSubPage(lastTabsPage); + @Override + public void onLoaderReset(Loader loader) { + mAdapter.swapCursor(null); + } } } diff --git a/mobile/android/base/home/HomeFragment.java b/mobile/android/base/home/HomeFragment.java index 51e37e81f2c..296bab150d3 100644 --- a/mobile/android/base/home/HomeFragment.java +++ b/mobile/android/base/home/HomeFragment.java @@ -46,6 +46,12 @@ abstract class HomeFragment extends Fragment { // URL to Title replacement regex. private static final String REGEX_URL_TO_TITLE = "^([a-z]+://)?(www\\.)?"; + protected void showSubPage(Fragment subPage) { + getActivity().getSupportFragmentManager().beginTransaction() + .addToBackStack(null).replace(R.id.home_pager_container, subPage, HomePager.SUBPAGE_TAG) + .commitAllowingStateLoss(); + } + @Override public void onCreateContextMenu(ContextMenu menu, View view, ContextMenuInfo menuInfo) { if (menuInfo == null || !(menuInfo instanceof HomeContextMenuInfo)) { diff --git a/mobile/android/base/home/HomePager.java b/mobile/android/base/home/HomePager.java index a7f0ee342f7..80f4a674b97 100644 --- a/mobile/android/base/home/HomePager.java +++ b/mobile/android/base/home/HomePager.java @@ -32,7 +32,7 @@ public class HomePager extends ViewPager { // List of pages in order. public enum Page { - HISTORY, + VISITED, BOOKMARKS, READING_LIST } @@ -70,7 +70,7 @@ public class HomePager extends ViewPager { TabsAdapter adapter = new TabsAdapter(fm); // Add the pages to the adapter in order. - adapter.addTab(Page.HISTORY, HistoryPage.class, null, getContext().getString(R.string.home_history_title)); + 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)); adapter.addTab(Page.READING_LIST, ReadingListPage.class, null, getContext().getString(R.string.reading_list)); diff --git a/mobile/android/base/home/MostRecentPage.java b/mobile/android/base/home/MostRecentPage.java deleted file mode 100644 index b709a430b9e..00000000000 --- a/mobile/android/base/home/MostRecentPage.java +++ /dev/null @@ -1,398 +0,0 @@ -/* -*- 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.db.BrowserDB; -import org.mozilla.gecko.db.BrowserDB.URLColumns; -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.content.res.Resources; -import android.database.Cursor; -import android.os.Bundle; -import android.support.v4.app.LoaderManager.LoaderCallbacks; -import android.support.v4.content.Loader; -import android.support.v4.widget.SimpleCursorAdapter; -import android.util.SparseArray; -import android.view.View; -import android.view.ViewGroup; -import android.view.LayoutInflater; -import android.widget.AdapterView; -import android.widget.ListView; -import android.widget.TextView; - -import java.util.Date; - -/** - * Fragment that displays recent history in a ListView. - */ -public class MostRecentPage extends HomeFragment { - // Logging tag name - private static final String LOGTAG = "GeckoMostRecentPage"; - - // Cursor loader ID for history query - private static final int HISTORY_LOADER_ID = 0; - - // Cursor loader ID for favicons query - private static final int FAVICONS_LOADER_ID = 1; - - // For the time sections in history - private static final long MS_PER_DAY = 86400000; - private static final long MS_PER_WEEK = MS_PER_DAY * 7; - - // The time ranges for each section - private static enum MostRecentSection { - TODAY, - YESTERDAY, - WEEK, - OLDER - }; - - // Maps headers in the list with their respective sections - private SparseArray mMostRecentSections; - - // Adapter for the list of search results - private MostRecentAdapter 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 static MostRecentPage newInstance() { - return new MostRecentPage(); - } - - public MostRecentPage() { - 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(); - - mMostRecentSections = null; - mInflater = null; - mUrlOpenListener = null; - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - return inflater.inflate(R.layout.home_most_recent_page, container, false); - } - - @Override - public void onViewCreated(View view, Bundle savedInstanceState) { - final TextView title = (TextView) view.findViewById(R.id.title); - title.setText(R.string.home_most_recent_title); - - mList = (ListView) view.findViewById(R.id.list); - - mList.setOnItemClickListener(new AdapterView.OnItemClickListener() { - @Override - public void onItemClick(AdapterView parent, View view, int position, long id) { - position -= getMostRecentSectionsCountBefore(position); - - 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); - - // Initialize map of history sections - mMostRecentSections = new SparseArray(); - - // Intialize adapter - mAdapter = new MostRecentAdapter(getActivity()); - mList.setAdapter(mAdapter); - - // Create callbacks before the initial loader is started - mCursorLoaderCallbacks = new CursorLoaderCallbacks(); - loadIfVisible(); - } - - @Override - protected void load() { - getLoaderManager().initLoader(HISTORY_LOADER_ID, null, mCursorLoaderCallbacks); - } - - private String getMostRecentSectionTitle(MostRecentSection section) { - final Resources resources = getActivity().getResources(); - - switch (section) { - case TODAY: - return resources.getString(R.string.history_today_section); - case YESTERDAY: - return resources.getString(R.string.history_yesterday_section); - case WEEK: - return resources.getString(R.string.history_week_section); - case OLDER: - return resources.getString(R.string.history_older_section); - } - - throw new IllegalStateException("Unrecognized history section"); - } - - private int getMostRecentSectionsCountBefore(int position) { - // Account for the number headers before the given position - int sectionsBefore = 0; - - final int historySectionsCount = mMostRecentSections.size(); - for (int i = 0; i < historySectionsCount; i++) { - final int sectionPosition = mMostRecentSections.keyAt(i); - if (sectionPosition > position) { - break; - } - - sectionsBefore++; - } - - return sectionsBefore; - } - - private MostRecentSection getMostRecentSectionForTime(long from, long time) { - long delta = from - time; - - if (delta < 0) { - return MostRecentSection.TODAY; - } - - if (delta < MS_PER_DAY) { - return MostRecentSection.YESTERDAY; - } - - if (delta < MS_PER_WEEK) { - return MostRecentSection.WEEK; - } - - return MostRecentSection.OLDER; - } - - private void loadMostRecentSections(Cursor c) { - if (c == null || !c.moveToFirst()) { - return; - } - - // Clear any history sections that may have been loaded before. - mMostRecentSections.clear(); - - final Date now = new Date(); - now.setHours(0); - now.setMinutes(0); - now.setSeconds(0); - - final long today = now.getTime(); - MostRecentSection section = null; - - do { - final int position = c.getPosition(); - final long time = c.getLong(c.getColumnIndexOrThrow(URLColumns.DATE_LAST_VISITED)); - final MostRecentSection itemSection = getMostRecentSectionForTime(today, time); - - if (section != itemSection) { - section = itemSection; - mMostRecentSections.append(position + mMostRecentSections.size(), section); - } - - // Reached the last section, no need to continue - if (section == MostRecentSection.OLDER) { - break; - } - } while (c.moveToNext()); - } - - private static class MostRecentCursorLoader extends SimpleCursorLoader { - // Max number of history results - private static final int HISTORY_LIMIT = 100; - - public MostRecentCursorLoader(Context context) { - super(context); - } - - @Override - public Cursor loadCursor() { - final ContentResolver cr = getContext().getContentResolver(); - return BrowserDB.getRecentHistory(cr, HISTORY_LIMIT); - } - } - - private class MostRecentAdapter extends SimpleCursorAdapter { - private static final int ROW_HEADER = 0; - private static final int ROW_STANDARD = 1; - - private static final int ROW_TYPE_COUNT = 2; - - public MostRecentAdapter(Context context) { - super(context, -1, null, new String[] {}, new int[] {}); - } - - @Override - public Object getItem(int position) { - final int type = getItemViewType(position); - - // Header items are not in the cursor - if (type == ROW_HEADER) { - return null; - } - - return super.getItem(position - getMostRecentSectionsCountBefore(position)); - } - - @Override - public int getItemViewType(int position) { - if (mMostRecentSections.get(position) != null) { - return ROW_HEADER; - } - - return ROW_STANDARD; - } - - @Override - public int getViewTypeCount() { - // view can be either a standard page row, or a header row - return ROW_TYPE_COUNT; - } - - @Override - public boolean isEnabled(int position) { - return (getItemViewType(position) == ROW_STANDARD); - } - - @Override - public int getCount() { - // Add the history section headers to the number of reported results. - return super.getCount() + mMostRecentSections.size(); - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - final int type = getItemViewType(position); - - if (type == ROW_HEADER) { - final TextView row; - if (convertView == null) { - row = (TextView) mInflater.inflate(R.layout.home_header_row, mList, false); - } else { - row = (TextView) convertView; - } - - final MostRecentSection section = mMostRecentSections.get(position); - row.setText(getMostRecentSectionTitle(section)); - - return row; - } else { - final TwoLinePageRow row; - if (convertView == null) { - row = (TwoLinePageRow) mInflater.inflate(R.layout.home_item_row, mList, false); - } else { - row = (TwoLinePageRow) convertView; - } - - // Account for the search engines - position -= getMostRecentSectionsCountBefore(position); - - 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 { - @Override - public Loader onCreateLoader(int id, Bundle args) { - switch(id) { - case HISTORY_LOADER_ID: - return new MostRecentCursorLoader(getActivity()); - - case FAVICONS_LOADER_ID: - return FaviconsLoader.createInstance(getActivity(), args); - } - - return null; - } - - @Override - public void onLoadFinished(Loader loader, Cursor c) { - final int loaderId = loader.getId(); - switch(loaderId) { - case HISTORY_LOADER_ID: - loadMostRecentSections(c); - 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 loader) { - final int loaderId = loader.getId(); - switch(loaderId) { - case HISTORY_LOADER_ID: - mAdapter.swapCursor(null); - break; - - case FAVICONS_LOADER_ID: - // Do nothing - break; - } - } - } -} diff --git a/mobile/android/base/home/MostVisitedPage.java b/mobile/android/base/home/VisitedPage.java similarity index 81% rename from mobile/android/base/home/MostVisitedPage.java rename to mobile/android/base/home/VisitedPage.java index 4f7db5e65a6..691fcb3bd6e 100644 --- a/mobile/android/base/home/MostVisitedPage.java +++ b/mobile/android/base/home/VisitedPage.java @@ -23,14 +23,13 @@ import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.ListView; -import android.widget.TextView; /** * Fragment that displays frecency search results in a ListView. */ -public class MostVisitedPage extends HomeFragment { +public class VisitedPage extends HomeFragment { // Logging tag name - private static final String LOGTAG = "GeckoMostVisitedPage"; + private static final String LOGTAG = "GeckoVisitedPage"; // Cursor loader ID for search query private static final int FRECENCY_LOADER_ID = 0; @@ -47,17 +46,16 @@ public class MostVisitedPage extends HomeFragment { // Empty message view private View mEmptyMessage; + // Buttons container + private View mButtonsContainer; + // Callbacks used for the search and favicon cursor loaders private CursorLoaderCallbacks mCursorLoaderCallbacks; // On URL open listener private OnUrlOpenListener mUrlOpenListener; - public static MostVisitedPage newInstance() { - return new MostVisitedPage(); - } - - public MostVisitedPage() { + public VisitedPage() { mUrlOpenListener = null; } @@ -82,16 +80,14 @@ public class MostVisitedPage extends HomeFragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - return inflater.inflate(R.layout.home_most_visited_page, container, false); + return inflater.inflate(R.layout.home_visited_page, container, false); } @Override public void onViewCreated(View view, Bundle savedInstanceState) { - final TextView title = (TextView) view.findViewById(R.id.title); - title.setText(R.string.home_most_visited_title); + super.onViewCreated(view, savedInstanceState); - mEmptyMessage = view.findViewById(R.id.empty_message); - mList = (HomeListView) view.findViewById(R.id.list); + mList = (HomeListView) view.findViewById(R.id.visited_list); mList.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override @@ -107,12 +103,32 @@ public class MostVisitedPage extends HomeFragment { }); registerForContextMenu(mList); + + mEmptyMessage = view.findViewById(R.id.empty_message); + mButtonsContainer = view.findViewById(R.id.buttons_container); + + final View historyButton = view.findViewById(R.id.history_button); + historyButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + showHistoryPage(); + } + }); + + final View tabsButton = view.findViewById(R.id.tabs_button); + tabsButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + showTabsPage(); + } + }); } @Override public void onDestroyView() { super.onDestroyView(); mList = null; + mButtonsContainer = null; mEmptyMessage = null; } @@ -134,6 +150,16 @@ public class MostVisitedPage extends HomeFragment { getLoaderManager().initLoader(FRECENCY_LOADER_ID, null, mCursorLoaderCallbacks); } + private void showHistoryPage() { + final HistoryPage historyPage = HistoryPage.newInstance(); + showSubPage(historyPage); + } + + private void showTabsPage() { + final LastTabsPage lastTabsPage = LastTabsPage.newInstance(); + showSubPage(lastTabsPage); + } + private static class FrecencyCursorLoader extends SimpleCursorLoader { // Max number of search results private static final int SEARCH_LIMIT = 50; @@ -189,6 +215,9 @@ public class MostVisitedPage extends HomeFragment { // flashing the empty message before loading. mList.setEmptyView(mEmptyMessage); + final int buttonsVisibility = (c.getCount() == 0 ? View.GONE : View.VISIBLE); + mButtonsContainer.setVisibility(buttonsVisibility); + mAdapter.swapCursor(c); FaviconsLoader.restartFromCursor(getLoaderManager(), FAVICONS_LOADER_ID, @@ -217,4 +246,4 @@ public class MostVisitedPage extends HomeFragment { } } } -} +} \ No newline at end of file diff --git a/mobile/android/base/locales/en-US/android_strings.dtd b/mobile/android/base/locales/en-US/android_strings.dtd index 2a9c7fcd5fa..f8cf5a853bd 100644 --- a/mobile/android/base/locales/en-US/android_strings.dtd +++ b/mobile/android/base/locales/en-US/android_strings.dtd @@ -8,7 +8,9 @@ + + @@ -267,11 +269,8 @@ size. --> - - + - - diff --git a/mobile/android/base/resources/drawable-hdpi/history_tabs_indicator_selected.9.png b/mobile/android/base/resources/drawable-hdpi/history_tabs_indicator_selected.9.png deleted file mode 100644 index 03ead6aa8b1..00000000000 Binary files a/mobile/android/base/resources/drawable-hdpi/history_tabs_indicator_selected.9.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-hdpi/icon_last_tabs.png b/mobile/android/base/resources/drawable-hdpi/icon_last_tabs.png deleted file mode 100644 index 8c2b41f9d2f..00000000000 Binary files a/mobile/android/base/resources/drawable-hdpi/icon_last_tabs.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-hdpi/icon_most_recent.png b/mobile/android/base/resources/drawable-hdpi/icon_most_recent.png deleted file mode 100644 index 1924bc4a044..00000000000 Binary files a/mobile/android/base/resources/drawable-hdpi/icon_most_recent.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-hdpi/icon_most_visited.png b/mobile/android/base/resources/drawable-hdpi/icon_most_visited.png deleted file mode 100644 index e7cf2b3b9ce..00000000000 Binary files a/mobile/android/base/resources/drawable-hdpi/icon_most_visited.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-mdpi/history_tabs_indicator_selected.9.png b/mobile/android/base/resources/drawable-mdpi/history_tabs_indicator_selected.9.png deleted file mode 100644 index 5def384c138..00000000000 Binary files a/mobile/android/base/resources/drawable-mdpi/history_tabs_indicator_selected.9.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-mdpi/icon_last_tabs.png b/mobile/android/base/resources/drawable-mdpi/icon_last_tabs.png deleted file mode 100644 index f577fd4c46c..00000000000 Binary files a/mobile/android/base/resources/drawable-mdpi/icon_last_tabs.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-mdpi/icon_most_recent.png b/mobile/android/base/resources/drawable-mdpi/icon_most_recent.png deleted file mode 100644 index e0cfd2ddb78..00000000000 Binary files a/mobile/android/base/resources/drawable-mdpi/icon_most_recent.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-mdpi/icon_most_visited.png b/mobile/android/base/resources/drawable-mdpi/icon_most_visited.png deleted file mode 100644 index e7ef4b91e47..00000000000 Binary files a/mobile/android/base/resources/drawable-mdpi/icon_most_visited.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-xhdpi/history_tabs_indicator_selected.9.png b/mobile/android/base/resources/drawable-xhdpi/history_tabs_indicator_selected.9.png deleted file mode 100644 index 86ba13a5f6f..00000000000 Binary files a/mobile/android/base/resources/drawable-xhdpi/history_tabs_indicator_selected.9.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-xhdpi/icon_last_tabs.png b/mobile/android/base/resources/drawable-xhdpi/icon_last_tabs.png deleted file mode 100644 index c102e8c9e17..00000000000 Binary files a/mobile/android/base/resources/drawable-xhdpi/icon_last_tabs.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-xhdpi/icon_most_recent.png b/mobile/android/base/resources/drawable-xhdpi/icon_most_recent.png deleted file mode 100644 index 7cd12a9abea..00000000000 Binary files a/mobile/android/base/resources/drawable-xhdpi/icon_most_recent.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable-xhdpi/icon_most_visited.png b/mobile/android/base/resources/drawable-xhdpi/icon_most_visited.png deleted file mode 100644 index ccdb7fca621..00000000000 Binary files a/mobile/android/base/resources/drawable-xhdpi/icon_most_visited.png and /dev/null differ diff --git a/mobile/android/base/resources/drawable/home_history_tabs_indicator.xml b/mobile/android/base/resources/drawable/home_history_tabs_indicator.xml deleted file mode 100644 index d0c3e6b75db..00000000000 --- a/mobile/android/base/resources/drawable/home_history_tabs_indicator.xml +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - diff --git a/mobile/android/base/resources/drawable/home_page_title_background.xml b/mobile/android/base/resources/drawable/home_page_title_background.xml deleted file mode 100644 index 1e98bd082ae..00000000000 --- a/mobile/android/base/resources/drawable/home_page_title_background.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - diff --git a/mobile/android/base/resources/layout/home_history_page.xml b/mobile/android/base/resources/layout/home_history_page.xml index 70e0589ad9f..8fb5a82f79c 100644 --- a/mobile/android/base/resources/layout/home_history_page.xml +++ b/mobile/android/base/resources/layout/home_history_page.xml @@ -6,19 +6,9 @@ + android:orientation="vertical" + android:background="@android:color/white"> - + - - - + \ No newline at end of file diff --git a/mobile/android/base/resources/layout/home_history_tabs_indicator.xml b/mobile/android/base/resources/layout/home_history_tabs_indicator.xml deleted file mode 100644 index 5ef9f2765df..00000000000 --- a/mobile/android/base/resources/layout/home_history_tabs_indicator.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - diff --git a/mobile/android/base/resources/layout/home_last_tabs_page.xml b/mobile/android/base/resources/layout/home_last_tabs_page.xml index b8e236839d2..7fd346fc0ce 100644 --- a/mobile/android/base/resources/layout/home_last_tabs_page.xml +++ b/mobile/android/base/resources/layout/home_last_tabs_page.xml @@ -13,7 +13,7 @@ + android:background="@color/background_light">