Bug 895837: Implemented tabs on the bottom for history page [r=lucasr]

--HG--
rename : mobile/android/base/home/HistoryPage.java => mobile/android/base/home/MostRecentPage.java
rename : mobile/android/base/home/VisitedPage.java => mobile/android/base/home/MostVisitedPage.java
This commit is contained in:
Shilpan Bhagat 2013-07-26 09:29:05 -07:00
parent bfccff861e
commit c78a1abd53
36 changed files with 601 additions and 437 deletions

View File

@ -1317,7 +1317,7 @@ abstract public class BrowserApp extends GeckoApp
animator.setUseHardwareLayer(false);
mBrowserToolbar.startEditing(url, animator);
showHomePagerWithAnimator(HomePager.Page.VISITED, animator);
showHomePagerWithAnimator(HomePager.Page.HISTORY, animator);
animator.start();
}
@ -1396,14 +1396,6 @@ 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();

View File

@ -229,6 +229,8 @@ 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 \
@ -240,7 +242,6 @@ FENNEC_JAVA_FILES = \
home/TopBookmarksAdapter.java \
home/TopBookmarksView.java \
home/TwoLinePageRow.java \
home/VisitedPage.java \
menu/GeckoMenu.java \
menu/GeckoMenuInflater.java \
menu/GeckoMenuItem.java \
@ -465,11 +466,13 @@ 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 \
@ -632,6 +635,9 @@ 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 \
@ -704,6 +710,7 @@ 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)
@ -744,6 +751,9 @@ 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 \
@ -794,6 +804,7 @@ 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)
@ -832,6 +843,9 @@ 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 \
@ -877,6 +891,7 @@ 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)
@ -1051,6 +1066,8 @@ 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 \

View File

@ -6,100 +6,24 @@
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 org.mozilla.gecko.widget.IconTabWidget;
import android.support.v4.app.Fragment;
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.LayoutInflater;
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;
import android.widget.ImageButton;
/**
* Fragment that displays recent history in a ListView.
*/
public class HistoryPage extends HomeFragment {
public class HistoryPage extends HomeFragment
implements IconTabWidget.OnTabChangedListener {
// Logging tag name
private static final String LOGTAG = "GeckoHistoryPage";
// 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<HistorySection> 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;
}
private IconTabWidget mTabWidget;
private int mSelectedTab;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
@ -108,258 +32,68 @@ public class HistoryPage extends HomeFragment {
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
final TextView title = (TextView) view.findViewById(R.id.title);
title.setText(R.string.history_title);
super.onViewCreated(view, savedInstanceState);
mList = (ListView) view.findViewById(R.id.list);
mTabWidget = (IconTabWidget) view.findViewById(R.id.tab_icon_widget);
mList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
position -= getHistorySectionsCountBefore(position);
ImageButton button;
final Resources resources = view.getContext().getResources();
final Cursor c = mAdapter.getCursor();
if (c == null || !c.moveToPosition(position)) {
return;
}
button = mTabWidget.addTab(R.drawable.icon_most_visited);
button.setContentDescription(resources.getString(R.string.home_most_visited_title));
final String url = c.getString(c.getColumnIndexOrThrow(URLColumns.URL));
mUrlOpenListener.onUrlOpen(url);
}
});
button = mTabWidget.addTab(R.drawable.icon_most_recent);
button.setContentDescription(resources.getString(R.string.home_most_recent_title));
registerForContextMenu(mList);
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);
}
@Override
public void onDestroyView() {
super.onDestroyView();
mList = null;
}
public void load() {}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// Initialize map of history sections
mHistorySections = new SparseArray<HistorySection>();
// 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()) {
public void onTabChanged(int index) {
if (index == mSelectedTab) {
return;
}
// Clear any history sections that may have been loaded before.
mHistorySections.clear();
if (index == 0) {
showMostVisitedPage();
} else if (index == 1) {
showMostRecentPage();
} else if (index == 2) {
showLastTabsPage();
}
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());
mTabWidget.setCurrentTab(index);
mSelectedTab = index;
}
private static class HistoryCursorLoader extends SimpleCursorLoader {
// Max number of history results
private static final int HISTORY_LIMIT = 100;
public HistoryCursorLoader(Context context) {
super(context);
}
@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<Cursor> {
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
return new HistoryCursorLoader(getActivity());
}
private void showMostRecentPage() {
final MostRecentPage mostRecentPage = MostRecentPage.newInstance();
showSubPage(mostRecentPage);
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor c) {
loadHistorySections(c);
mAdapter.swapCursor(c);
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
mAdapter.swapCursor(null);
}
private void showLastTabsPage() {
final LastTabsPage lastTabsPage = LastTabsPage.newInstance();
showSubPage(lastTabsPage);
}
}

View File

@ -46,12 +46,6 @@ 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)) {

View File

@ -32,7 +32,7 @@ public class HomePager extends ViewPager {
// List of pages in order.
public enum Page {
VISITED,
HISTORY,
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.VISITED, VisitedPage.class, null, getContext().getString(R.string.visited_title));
adapter.addTab(Page.HISTORY, HistoryPage.class, null, getContext().getString(R.string.home_history_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));

View File

@ -0,0 +1,365 @@
/* -*- 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;
// 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<MostRecentSection> 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<MostRecentSection>();
// 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<Cursor> {
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
return new MostRecentCursorLoader(getActivity());
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor c) {
loadMostRecentSections(c);
mAdapter.swapCursor(c);
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
mAdapter.swapCursor(null);
}
}
}

View File

@ -23,13 +23,14 @@ 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 VisitedPage extends HomeFragment {
public class MostVisitedPage extends HomeFragment {
// Logging tag name
private static final String LOGTAG = "GeckoVisitedPage";
private static final String LOGTAG = "GeckoMostVisitedPage";
// Cursor loader ID for search query
private static final int FRECENCY_LOADER_ID = 0;
@ -46,16 +47,17 @@ public class VisitedPage 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 VisitedPage() {
public static MostVisitedPage newInstance() {
return new MostVisitedPage();
}
public MostVisitedPage() {
mUrlOpenListener = null;
}
@ -80,14 +82,16 @@ public class VisitedPage extends HomeFragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.home_visited_page, container, false);
return inflater.inflate(R.layout.home_most_visited_page, container, false);
}
@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.home_most_visited_title);
mList = (HomeListView) view.findViewById(R.id.visited_list);
mEmptyMessage = view.findViewById(R.id.empty_message);
mList = (HomeListView) view.findViewById(R.id.list);
mList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
@ -103,32 +107,12 @@ public class VisitedPage 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;
}
@ -150,16 +134,6 @@ public class VisitedPage 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;
@ -215,9 +189,6 @@ public class VisitedPage 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,
@ -246,4 +217,4 @@ public class VisitedPage extends HomeFragment {
}
}
}
}
}

View File

@ -8,9 +8,7 @@
<!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.">
@ -269,8 +267,11 @@ size. -->
<!ENTITY button_set "Set">
<!ENTITY button_clear "Clear">
<!ENTITY home_last_tabs_title "Your tabs from last time">
<!ENTITY home_history_title "History">
<!ENTITY home_last_tabs_title "Tabs from last time">
<!ENTITY home_last_tabs_open "Open all tabs from last time">
<!ENTITY home_most_recent_title "Most recent">
<!ENTITY home_most_visited_title "Most visited">
<!ENTITY home_visited_empty "Websites you visited go here">
<!ENTITY pin_bookmark_dialog_hint "Enter a search keyword">

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 446 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 841 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 421 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 361 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 599 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 312 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 597 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 555 B

View File

@ -0,0 +1,48 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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/. -->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_focused="false"
android:state_selected="false"
android:state_pressed="false"
android:drawable="@android:color/transparent"/>
<item android:state_focused="false"
android:state_selected="true"
android:state_pressed="false"
android:drawable="@drawable/history_tabs_indicator_selected"/>
<item android:state_focused="true"
android:state_selected="false"
android:state_pressed="false"
android:drawable="@color/highlight_dark_focused"/>
<item android:state_focused="true"
android:state_selected="true"
android:state_pressed="false"
android:drawable="@drawable/history_tabs_indicator_selected"/>
<item android:state_focused="false"
android:state_selected="false"
android:state_pressed="true"
android:drawable="@color/highlight_dark"/>
<item android:state_focused="false"
android:state_selected="true"
android:state_pressed="true"
android:drawable="@color/highlight_dark"/>
<item android:state_focused="true"
android:state_selected="false"
android:state_pressed="true"
android:drawable="@color/highlight_dark"/>
<item android:state_focused="true"
android:state_selected="true"
android:state_pressed="true"
android:drawable="@color/highlight_dark"/>
</selector>

View File

@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:left="-1dp"
android:right="-1dp"
android:top="-1dp">
<shape android:shape="rectangle" >
<stroke android:width="1px"
android:color="@color/doorhanger_divider_dark" />
<solid android:color="#00000000" />
</shape>
</item>
</layer-list>

View File

@ -6,9 +6,19 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:background="@android:color/white">
android:orientation="vertical">
<include layout="@layout/home_list_with_title"/>
<FrameLayout android:id="@+id/visited_page_container"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1" />
</LinearLayout>
<org.mozilla.gecko.widget.IconTabWidget android:id="@+id/tab_icon_widget"
android:layout_width="fill_parent"
android:layout_height="@dimen/browser_toolbar_height"
android:tabStripEnabled="false"
android:showDividers="none"
android:background="@color/background_light"
android:layout="@layout/home_history_tabs_indicator"/>
</LinearLayout>

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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/. -->
<ImageButton xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@drawable/home_history_tabs_indicator"/>

View File

@ -13,7 +13,7 @@
<LinearLayout android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@color/background_light">
android:background="@color/home_last_tab_bar_bg">
<Button android:id="@+id/open_all_tabs_button"
style="@style/Widget.Home.ActionButton"

View File

@ -5,6 +5,13 @@
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<TextView android:id="@+id/empty_message"
style="@style/Widget.Home.EmptyMessage"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:text="@string/home_visited_empty"
android:visibility="gone"/>
<TextView android:id="@+id/title"
style="@style/Widget.Home.PageTitle"/>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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/. -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:background="@android:color/white">
<include layout="@layout/home_list_with_title"/>
</LinearLayout>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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/. -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:background="@android:color/white">
<include layout="@layout/home_list_with_title"/>
</LinearLayout>

View File

@ -1,45 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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/. -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">
<TextView android:id="@+id/empty_message"
style="@style/Widget.Home.EmptyMessage"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:text="@string/home_visited_empty"
android:visibility="gone"/>
<org.mozilla.gecko.home.HomeListView
android:id="@+id/visited_list"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"/>
<LinearLayout android:id="@+id/buttons_container"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:background="@color/background_light"
android:visibility="gone">
<Button android:id="@+id/history_button"
style="@style/Widget.Home.PageButton"
android:text="@string/history_title"/>
<View android:layout_width="fill_parent"
android:layout_height="1dip"
android:background="#FFD1D5DA"/>
<Button android:id="@+id/tabs_button"
style="@style/Widget.Home.PageButton"
android:text="@string/home_last_tabs_title"/>
</LinearLayout>
</LinearLayout>

View File

@ -9,7 +9,8 @@
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:tabStripEnabled="false"
android:divider="@drawable/tab_indicator_divider"/>
android:divider="@drawable/tab_indicator_divider"
android:layout="@layout/tabs_panel_indicator"/>
<View android:layout_width="0dip"
android:layout_height="fill_parent"

View File

@ -59,7 +59,7 @@
</string-array>
<string-array name="pref_import_android_entries">
<item>@string/bookmarks_title</item>
<item>@string/history_title</item>
<item>@string/home_most_recent_title</item>
</string-array>
<string-array name="pref_import_android_values">
<item>true</item>

View File

@ -193,5 +193,9 @@
<attr name="url" format="string"/>
</declare-styleable>
<declare-styleable name="IconTabWidget">
<attr name="android:layout"/>
</declare-styleable>
</resources>

View File

@ -87,5 +87,7 @@
<color name="url_bar_domaintext">#000</color>
<color name="url_bar_domaintext_private">#FFF</color>
<color name="home_last_tab_bar_bg">#FFF5F7F9</color>
</resources>

View File

@ -192,7 +192,7 @@
<item name="android:layout_width">fill_parent</item>
<item name="android:layout_height">32dp</item>
<item name="android:textAppearance">@style/TextAppearance.Widget.Home.PageTitle</item>
<item name="android:background">@color/background_light</item>
<item name="android:background">@drawable/home_page_title_background</item>
<item name="android:focusable">false</item>
<item name="android:gravity">center|left</item>
<item name="android:paddingLeft">10dip</item>

View File

@ -23,9 +23,7 @@
<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>
@ -237,8 +235,11 @@
<string name="button_yes">&button_yes;</string>
<string name="button_no">&button_no;</string>
<string name="home_history_title">&home_history_title;</string>
<string name="home_last_tabs_title">&home_last_tabs_title;</string>
<string name="home_last_tabs_open">&home_last_tabs_open;</string>
<string name="home_most_recent_title">&home_most_recent_title;</string>
<string name="home_most_visited_title">&home_most_visited_title;</string>
<string name="home_visited_empty">&home_visited_empty;</string>
<string name="pin_bookmark_dialog_hint">&pin_bookmark_dialog_hint;</string>

View File

@ -7,6 +7,7 @@ package org.mozilla.gecko.widget;
import org.mozilla.gecko.R;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
@ -15,6 +16,7 @@ import android.widget.TabWidget;
public class IconTabWidget extends TabWidget {
private OnTabChangedListener mListener;
private final int mButtonLayoutId;
public static interface OnTabChangedListener {
public void onTabChanged(int tabIndex);
@ -22,10 +24,18 @@ public class IconTabWidget extends TabWidget {
public IconTabWidget(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.IconTabWidget);
mButtonLayoutId = a.getResourceId(R.styleable.IconTabWidget_android_layout, 0);
a.recycle();
if (mButtonLayoutId == 0) {
throw new RuntimeException("You must supply layout attribute");
}
}
public ImageButton addTab(int resId) {
ImageButton button = (ImageButton) LayoutInflater.from(getContext()).inflate(R.layout.tabs_panel_indicator, null);
ImageButton button = (ImageButton) LayoutInflater.from(getContext()).inflate(mButtonLayoutId, null);
button.setImageResource(resId);
addView(button);