Bug 942231 - Change HomePager to be backed by HomeConfig (r=margaret)

This commit is contained in:
Lucas Rocha 2013-12-12 12:04:31 +00:00
parent c5f8fff541
commit c1e1d38335
10 changed files with 790 additions and 87 deletions

View File

@ -18,4 +18,4 @@
# Modifying this file will now automatically clobber the buildbot machines \o/
#
Bug 946067 required a clobber on Windows because bug 928195
Bug 942231 needs a clobber -- JNI wrappers need to be re-generated.

View File

@ -1467,7 +1467,7 @@ abstract public class BrowserApp extends GeckoApp
animator.setUseHardwareLayer(false);
mBrowserToolbar.startEditing(url, animator);
showHomePagerWithAnimator(HomePager.Page.TOP_SITES, animator);
showHomePagerWithAnimator(animator);
animator.start();
}
@ -1623,7 +1623,7 @@ abstract public class BrowserApp extends GeckoApp
super.onLocaleReady(locale);
if (mHomePager != null) {
// Blow it away and rebuild it with the right strings.
mHomePager.redisplay(getSupportFragmentManager());
mHomePager.redisplay(getSupportLoaderManager(), getSupportFragmentManager());
}
if (mMenu != null) {
@ -1636,6 +1636,12 @@ abstract public class BrowserApp extends GeckoApp
showHomePagerWithAnimator(page, null);
}
private void showHomePagerWithAnimator(PropertyAnimator animator) {
// Passing null here means the default page will be defined
// by the HomePager's configuration.
showHomePagerWithAnimator(null, animator);
}
private void showHomePagerWithAnimator(HomePager.Page page, PropertyAnimator animator) {
if (isHomePagerVisible()) {
return;
@ -1655,7 +1661,9 @@ abstract public class BrowserApp extends GeckoApp
mHomePager = (HomePager) homePagerStub.inflate();
}
mHomePager.show(getSupportFragmentManager(), page, animator);
mHomePager.show(getSupportLoaderManager(),
getSupportFragmentManager(),
page, animator);
// Hide the web content so it cannot be focused by screen readers.
hideWebContentOnPropertyAnimationEnd(animator);

View File

@ -95,7 +95,7 @@ public class Tab {
mUserSearch = "";
mExternal = external;
mParentId = parentId;
mAboutHomePage = HomePager.Page.TOP_SITES;
mAboutHomePage = null;
mTitle = title == null ? "" : title;
mFavicon = null;
mFaviconUrl = null;
@ -155,7 +155,6 @@ public class Tab {
mAboutHomePage = page;
}
// may be null if user-entered query hasn't yet been resolved to a URI
public synchronized String getURL() {
return mUrl;
@ -660,6 +659,8 @@ public class Tab {
final String homePage = message.getString("aboutHomePage");
if (!TextUtils.isEmpty(homePage)) {
setAboutHomePage(HomePager.Page.valueOf(homePage));
} else {
setAboutHomePage(null);
}
Tabs.getInstance().notifyListeners(this, Tabs.TabEvents.LOCATION_CHANGE, oldUrl);

View File

@ -5,6 +5,8 @@
package org.mozilla.gecko.home;
import org.mozilla.gecko.home.HomeConfig.PageEntry;
import org.mozilla.gecko.home.HomeConfig.PageType;
import org.mozilla.gecko.home.HomePager;
import org.mozilla.gecko.home.HomePager.Page;
@ -16,13 +18,16 @@ import android.support.v4.app.FragmentStatePagerAdapter;
import android.view.ViewGroup;
import java.util.ArrayList;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.List;
class HomeAdapter extends FragmentStatePagerAdapter {
private final Context mContext;
private final ArrayList<PageInfo> mPageInfos;
private final EnumMap<Page, Fragment> mPages;
private final HashMap<String, Fragment> mPages;
private boolean mCanLoadHint;
private OnAddPageListener mAddPageListener;
@ -30,27 +35,14 @@ class HomeAdapter extends FragmentStatePagerAdapter {
public void onAddPage(String title);
}
final class PageInfo {
private final Page page;
private final Class<?> clss;
private final Bundle args;
private final String title;
PageInfo(Page page, Class<?> clss, Bundle args, String title) {
this.page = page;
this.clss = clss;
this.args = args;
this.title = title;
}
}
public HomeAdapter(Context context, FragmentManager fm) {
super(fm);
mContext = context;
mCanLoadHint = HomeFragment.DEFAULT_CAN_LOAD_HINT;
mPageInfos = new ArrayList<PageInfo>();
mPages = new EnumMap<Page, Fragment>(Page.class);
mPages = new HashMap<String, Fragment>();
}
@Override
@ -61,19 +53,23 @@ class HomeAdapter extends FragmentStatePagerAdapter {
@Override
public Fragment getItem(int position) {
PageInfo info = mPageInfos.get(position);
return Fragment.instantiate(mContext, info.clss.getName(), info.args);
return Fragment.instantiate(mContext, info.getClassName(), info.getArgs());
}
@Override
public CharSequence getPageTitle(int position) {
PageInfo info = mPageInfos.get(position);
return info.title.toUpperCase();
if (mPageInfos.size() > 0) {
PageInfo info = mPageInfos.get(position);
return info.getTitle().toUpperCase();
}
return null;
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment fragment = (Fragment) super.instantiateItem(container, position);
mPages.put(mPageInfos.get(position).page, fragment);
mPages.put(mPageInfos.get(position).getId(), fragment);
return fragment;
}
@ -81,37 +77,17 @@ class HomeAdapter extends FragmentStatePagerAdapter {
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
super.destroyItem(container, position, object);
mPages.remove(mPageInfos.get(position).page);
mPages.remove(mPageInfos.get(position).getId());
}
public void setOnAddPageListener(OnAddPageListener listener) {
mAddPageListener = listener;
}
public void addPage(Page page, Class<?> clss, Bundle args, String title) {
addPage(-1, page, clss, args, title);
}
public void addPage(int index, Page page, Class<?> clss, Bundle args, String title) {
PageInfo info = new PageInfo(page, clss, args, title);
if (index >= 0) {
mPageInfos.add(index, info);
} else {
mPageInfos.add(info);
}
notifyDataSetChanged();
if (mAddPageListener != null) {
mAddPageListener.onAddPage(title);
}
}
public int getItemPosition(Page page) {
for (int i = 0; i < mPageInfos.size(); i++) {
PageInfo info = mPageInfos.get(i);
if (info.page == page) {
final Page infoPage = mPageInfos.get(i).toPage();
if (infoPage == page) {
return i;
}
}
@ -121,14 +97,39 @@ class HomeAdapter extends FragmentStatePagerAdapter {
public Page getPageAtPosition(int position) {
PageInfo info = mPageInfos.get(position);
return info.page;
return info.toPage();
}
private void addPage(PageInfo info) {
mPageInfos.add(info);
if (mAddPageListener != null) {
mAddPageListener.onAddPage(info.getTitle());
}
}
public void update(List<PageEntry> pageEntries) {
mPages.clear();
mPageInfos.clear();
if (pageEntries != null) {
for (PageEntry pageEntry : pageEntries) {
final PageInfo info = new PageInfo(pageEntry);
addPage(info);
}
}
notifyDataSetChanged();
}
public boolean getCanLoadHint() {
return mCanLoadHint;
}
public void setCanLoadHint(boolean canLoadHint) {
// Update fragment arguments for future instances
for (PageInfo info : mPageInfos) {
info.args.putBoolean(HomePager.CAN_LOAD_ARG, canLoadHint);
}
// We cache the last hint value so that we can use it when
// creating new pages. See PageInfo.getArgs().
mCanLoadHint = canLoadHint;
// Enable/disable loading on all existing pages
for (Fragment page : mPages.values()) {
@ -136,4 +137,49 @@ class HomeAdapter extends FragmentStatePagerAdapter {
homePage.setCanLoadHint(canLoadHint);
}
}
private final class PageInfo {
private final String mId;
private final PageEntry mPageEntry;
PageInfo(PageEntry pageEntry) {
mId = pageEntry.getType() + "-" + pageEntry.getId();
mPageEntry = pageEntry;
}
public String getId() {
return mId;
}
public String getTitle() {
return mPageEntry.getTitle();
}
public String getClassName() {
final PageType type = mPageEntry.getType();
return type.getPageClass().getName();
}
public Bundle getArgs() {
final Bundle args = new Bundle();
args.putBoolean(HomePager.CAN_LOAD_ARG, mCanLoadHint);
// Only list pages need the page entry
if (mPageEntry.getType() == PageType.LIST) {
args.putParcelable(HomePager.PAGE_ENTRY_ARG, mPageEntry);
}
return args;
}
public Page toPage() {
final PageType type = mPageEntry.getType();
if (type == PageType.LIST) {
return null;
}
return Page.valueOf(type);
}
}
}

View File

@ -0,0 +1,224 @@
/* -*- 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.home.HomePager.Page;
import android.content.Context;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
import java.util.EnumSet;
import java.util.List;
final class HomeConfig {
public static enum PageType implements Parcelable {
TOP_SITES("top_sites", TopSitesPage.class),
BOOKMARKS("bookmarks", BookmarksPage.class),
HISTORY("history", HistoryPage.class),
READING_LIST("reading_list", ReadingListPage.class),
LIST("list", ListPage.class);
private final String mId;
private final Class<?> mPageClass;
PageType(String id, Class<?> pageClass) {
mId = id;
mPageClass = pageClass;
}
public static PageType valueOf(Page page) {
switch(page) {
case TOP_SITES:
return PageType.TOP_SITES;
case BOOKMARKS:
return PageType.BOOKMARKS;
case HISTORY:
return PageType.HISTORY;
case READING_LIST:
return PageType.READING_LIST;
default:
throw new IllegalArgumentException("Could not convert unrecognized Page");
}
}
public static PageType fromId(String id) {
if (id == null) {
throw new IllegalArgumentException("Could not convert null String to PageType");
}
for (PageType page : PageType.values()) {
if (TextUtils.equals(page.mId, id.toLowerCase())) {
return page;
}
}
throw new IllegalArgumentException("Could not convert String id to PageType");
}
@Override
public String toString() {
return mId;
}
public Class<?> getPageClass() {
return mPageClass;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(ordinal());
}
public static final Creator<PageType> CREATOR = new Creator<PageType>() {
@Override
public PageType createFromParcel(final Parcel source) {
return PageType.values()[source.readInt()];
}
@Override
public PageType[] newArray(final int size) {
return new PageType[size];
}
};
}
public static class PageEntry implements Parcelable {
private final PageType mType;
private final String mTitle;
private final String mId;
private final EnumSet<Flags> mFlags;
public enum Flags {
DEFAULT_PAGE
}
@SuppressWarnings("unchecked")
public PageEntry(Parcel in) {
mType = (PageType) in.readParcelable(getClass().getClassLoader());
mTitle = in.readString();
mId = in.readString();
mFlags = (EnumSet<Flags>) in.readSerializable();
}
public PageEntry(PageType type, String title) {
this(type, title, EnumSet.noneOf(Flags.class));
}
public PageEntry(PageType type, String title, EnumSet<Flags> flags) {
this(type, title, type.toString(), flags);
}
public PageEntry(PageType type, String title, String id) {
this(type, title, id, EnumSet.noneOf(Flags.class));
}
public PageEntry(PageType type, String title, String id, EnumSet<Flags> flags) {
if (type == null) {
throw new IllegalArgumentException("Can't create PageEntry with null type");
}
mType = type;
if (title == null) {
throw new IllegalArgumentException("Can't create PageEntry with null title");
}
mTitle = title;
if (id == null) {
throw new IllegalArgumentException("Can't create PageEntry with null id");
}
mId = id;
if (flags == null) {
throw new IllegalArgumentException("Can't create PageEntry with null flags");
}
mFlags = flags;
}
public PageType getType() {
return mType;
}
public String getTitle() {
return mTitle;
}
public String getId() {
return mId;
}
public boolean isDefault() {
return mFlags.contains(Flags.DEFAULT_PAGE);
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeParcelable(mType, 0);
dest.writeString(mTitle);
dest.writeString(mId);
dest.writeSerializable(mFlags);
}
public static final Creator<PageEntry> CREATOR = new Creator<PageEntry>() {
@Override
public PageEntry createFromParcel(final Parcel in) {
return new PageEntry(in);
}
@Override
public PageEntry[] newArray(final int size) {
return new PageEntry[size];
}
};
}
public interface OnChangeListener {
public void onChange();
}
public interface HomeConfigBackend {
public List<PageEntry> load();
public void save(List<PageEntry> entries);
public void setOnChangeListener(OnChangeListener listener);
}
private final HomeConfigBackend mBackend;
public HomeConfig(HomeConfigBackend backend) {
mBackend = backend;
}
public List<PageEntry> load() {
return mBackend.load();
}
public void save(List<PageEntry> entries) {
mBackend.save(entries);
}
public void setOnChangeListener(OnChangeListener listener) {
mBackend.setOnChangeListener(listener);
}
public static HomeConfig getDefault(Context context) {
return new HomeConfig(new HomeConfigMemBackend(context));
}
}

View File

@ -0,0 +1,83 @@
/* -*- 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.home.HomeConfig.PageEntry;
import org.mozilla.gecko.home.HomeConfig.OnChangeListener;
import android.content.Context;
import android.support.v4.content.AsyncTaskLoader;
import java.util.List;
public class HomeConfigLoader extends AsyncTaskLoader<List<PageEntry>> {
private final HomeConfig mConfig;
private List<PageEntry> mPageEntries;
public HomeConfigLoader(Context context, HomeConfig homeConfig) {
super(context);
mConfig = homeConfig;
}
@Override
public List<PageEntry> loadInBackground() {
return mConfig.load();
}
@Override
public void deliverResult(List<PageEntry> pageEntries) {
if (isReset()) {
mPageEntries = null;
return;
}
mPageEntries = pageEntries;
mConfig.setOnChangeListener(new ForceLoadChangeListener());
if (isStarted()) {
super.deliverResult(pageEntries);
}
}
@Override
protected void onStartLoading() {
if (mPageEntries != null) {
deliverResult(mPageEntries);
}
if (takeContentChanged() || mPageEntries == null) {
forceLoad();
}
}
@Override
protected void onStopLoading() {
cancelLoad();
}
@Override
public void onCanceled(List<PageEntry> pageEntries) {
mPageEntries = null;
}
@Override
protected void onReset() {
super.onReset();
// Ensure the loader is stopped.
onStopLoading();
mPageEntries = null;
mConfig.setOnChangeListener(null);
}
private class ForceLoadChangeListener implements OnChangeListener {
@Override
public void onChange() {
onContentChanged();
}
}
}

View File

@ -0,0 +1,67 @@
/* -*- 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.home.HomeConfig.HomeConfigBackend;
import org.mozilla.gecko.home.HomeConfig.OnChangeListener;
import org.mozilla.gecko.home.HomeConfig.PageEntry;
import org.mozilla.gecko.home.HomeConfig.PageType;
import org.mozilla.gecko.util.HardwareUtils;
import android.content.Context;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
class HomeConfigMemBackend implements HomeConfigBackend {
private final Context mContext;
public HomeConfigMemBackend(Context context) {
mContext = context;
}
public List<PageEntry> load() {
final ArrayList<PageEntry> pageEntries = new ArrayList<PageEntry>();
pageEntries.add(new PageEntry(PageType.TOP_SITES,
mContext.getString(R.string.home_top_sites_title),
EnumSet.of(PageEntry.Flags.DEFAULT_PAGE)));
pageEntries.add(new PageEntry(PageType.BOOKMARKS,
mContext.getString(R.string.bookmarks_title)));
// We disable reader mode support on low memory devices. Hence the
// reading list page should not show up on such devices.
if (!HardwareUtils.isLowMemoryPlatform()) {
pageEntries.add(new PageEntry(PageType.READING_LIST,
mContext.getString(R.string.reading_list_title)));
}
final PageEntry historyEntry = new PageEntry(PageType.HISTORY,
mContext.getString(R.string.home_history_title));
// On tablets, the history page is the last.
// On phones, the history page is the first one.
if (HardwareUtils.isTablet()) {
pageEntries.add(historyEntry);
} else {
pageEntries.add(0, historyEntry);
}
return Collections.unmodifiableList(pageEntries);
}
public void save(List<PageEntry> entries) {
// This is a static backend, do nothing.
}
public void setOnChangeListener(OnChangeListener listener) {
// This is a static backend, do nothing.
}
}

View File

@ -9,6 +9,8 @@ import org.mozilla.gecko.R;
import org.mozilla.gecko.animation.PropertyAnimator;
import org.mozilla.gecko.animation.ViewHelper;
import org.mozilla.gecko.home.HomeAdapter.OnAddPageListener;
import org.mozilla.gecko.home.HomeConfig.PageEntry;
import org.mozilla.gecko.home.HomeConfig.PageType;
import org.mozilla.gecko.mozglue.RobocopTarget;
import org.mozilla.gecko.util.HardwareUtils;
@ -17,6 +19,9 @@ import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.LoaderManager;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.Loader;
import android.support.v4.view.ViewPager;
import android.view.ViewGroup.LayoutParams;
import android.util.AttributeSet;
@ -25,22 +30,50 @@ import android.view.ViewGroup;
import android.view.View;
import java.util.EnumSet;
import java.util.List;
public class HomePager extends ViewPager {
private static final int LOADER_ID_CONFIG = 0;
private final Context mContext;
private volatile boolean mLoaded;
private Decor mDecor;
private View mTabStrip;
private final OnAddPageListener mAddPageListener;
private final HomeConfig mConfig;
private ConfigLoaderCallbacks mConfigLoaderCallbacks;
private Page mInitialPage;
// List of pages in order.
@RobocopTarget
public enum Page {
HISTORY,
TOP_SITES,
BOOKMARKS,
READING_LIST
READING_LIST;
static Page valueOf(PageType page) {
switch(page) {
case TOP_SITES:
return Page.TOP_SITES;
case BOOKMARKS:
return Page.BOOKMARKS;
case HISTORY:
return Page.HISTORY;
case READING_LIST:
return Page.READING_LIST;
default:
throw new IllegalArgumentException("Could not convert unrecognized PageType");
}
}
}
// This is mostly used by UI tests to easily fetch
@ -81,6 +114,7 @@ public class HomePager extends ViewPager {
}
static final String CAN_LOAD_ARG = "canLoad";
static final String PAGE_ENTRY_ARG = "pageEntry";
public HomePager(Context context) {
this(context, null);
@ -90,6 +124,9 @@ public class HomePager extends ViewPager {
super(context, attrs);
mContext = context;
mConfig = HomeConfig.getDefault(mContext);
mConfigLoaderCallbacks = new ConfigLoaderCallbacks();
mAddPageListener = new OnAddPageListener() {
@Override
public void onAddPage(String title) {
@ -116,6 +153,7 @@ public class HomePager extends ViewPager {
if (child instanceof Decor) {
((ViewPager.LayoutParams) params).isDecor = true;
mDecor = (Decor) child;
mTabStrip = child;
mDecor.setOnTitleClickListener(new OnTitleClickListener() {
@Override
@ -138,16 +176,18 @@ public class HomePager extends ViewPager {
@Override
public void onPageScrollStateChanged(int state) { }
});
} else if (child instanceof HomePagerTabStrip) {
mTabStrip = child;
}
super.addView(child, index, params);
}
public void redisplay(FragmentManager fm) {
public void redisplay(LoaderManager lm, FragmentManager fm) {
final HomeAdapter adapter = (HomeAdapter) getAdapter();
final Page currentPage = adapter.getPageAtPosition(getCurrentItem());
show(fm, currentPage, null);
Page currentPage = adapter.getPageAtPosition(getCurrentItem());
show(lm, fm, currentPage, null);
}
/**
@ -155,44 +195,27 @@ public class HomePager extends ViewPager {
*
* @param fm FragmentManager for the adapter
*/
public void show(FragmentManager fm, Page page, PropertyAnimator animator) {
public void show(LoaderManager lm, FragmentManager fm, Page page, PropertyAnimator animator) {
mLoaded = true;
if (mDecor != null) {
mDecor.removeAllPagerViews();
}
final HomeAdapter adapter = new HomeAdapter(mContext, fm);
adapter.setOnAddPageListener(mAddPageListener);
mInitialPage = page;
// Only animate on post-HC devices, when a non-null animator is given
final boolean shouldAnimate = (animator != null && Build.VERSION.SDK_INT >= 11);
adapter.addPage(Page.TOP_SITES, TopSitesPage.class, new Bundle(),
getContext().getString(R.string.home_top_sites_title));
adapter.addPage(Page.BOOKMARKS, BookmarksPage.class, new Bundle(),
getContext().getString(R.string.bookmarks_title));
// We disable reader mode support on low memory devices. Hence the
// reading list page should not show up on such devices.
if (!HardwareUtils.isLowMemoryPlatform()) {
adapter.addPage(Page.READING_LIST, ReadingListPage.class, new Bundle(),
getContext().getString(R.string.reading_list_title));
}
// On phones, the history page is the first one. On tablets, the
// history page is the last.
adapter.addPage(HardwareUtils.isTablet() ? -1 : 0,
Page.HISTORY, HistoryPage.class, new Bundle(),
getContext().getString(R.string.home_history_title));
final HomeAdapter adapter = new HomeAdapter(mContext, fm);
adapter.setOnAddPageListener(mAddPageListener);
adapter.setCanLoadHint(!shouldAnimate);
setAdapter(adapter);
setCurrentItem(adapter.getItemPosition(page), false);
setVisibility(VISIBLE);
// Don't show the tabs strip until we have the
// list of pages in place.
mTabStrip.setVisibility(View.INVISIBLE);
// Load list of pages from configuration
lm.initLoader(LOADER_ID_CONFIG, null, mConfigLoaderCallbacks);
if (shouldAnimate) {
animator.addPropertyAnimationListener(new PropertyAnimator.PropertyAnimationListener() {
@Override
@ -254,4 +277,66 @@ public class HomePager extends ViewPager {
return super.onInterceptTouchEvent(event);
}
private void updateUiFromPageEntries(List<PageEntry> pageEntries) {
// We only care about the adapter if HomePager is currently
// loaded, which means it's visible in the activity.
if (!mLoaded) {
return;
}
if (mDecor != null) {
mDecor.removeAllPagerViews();
}
final HomeAdapter adapter = (HomeAdapter) getAdapter();
// Disable loading until the final current item is defined
// after loading the page entries. This is to stop any temporary
// active item from loading.
boolean originalCanLoadHint = adapter.getCanLoadHint();
adapter.setCanLoadHint(false);
// Update the adapter with the new page entries
adapter.update(pageEntries);
final int count = (pageEntries != null ? pageEntries.size() : 0);
mTabStrip.setVisibility(count > 0 ? View.VISIBLE : View.INVISIBLE);
// Use the default page as defined in the HomePager's configuration
// if the initial page wasn't explicitly set by the show() caller.
if (mInitialPage != null) {
setCurrentItem(adapter.getItemPosition(mInitialPage), false);
mInitialPage = null;
} else {
for (int i = 0; i < count; i++) {
final PageEntry pageEntry = pageEntries.get(i);
if (pageEntry.isDefault()) {
setCurrentItem(i, false);
break;
}
}
}
// Restore canLoadHint now that we have the final
// state in HomePager.
adapter.setCanLoadHint(originalCanLoadHint);
}
private class ConfigLoaderCallbacks implements LoaderCallbacks<List<PageEntry>> {
@Override
public Loader<List<PageEntry>> onCreateLoader(int id, Bundle args) {
return new HomeConfigLoader(mContext, mConfig);
}
@Override
public void onLoadFinished(Loader<List<PageEntry>> loader, List<PageEntry> pageEntries) {
updateUiFromPageEntries(pageEntries);
}
@Override
public void onLoaderReset(Loader<List<PageEntry>> loader) {
updateUiFromPageEntries(null);
}
}
}

View File

@ -0,0 +1,185 @@
/* -*- 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.home.HomePager.OnUrlOpenListener;
import org.mozilla.gecko.home.HomeConfig.PageEntry;
import android.app.Activity;
import android.content.Context;
import android.content.res.Configuration;
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.CursorAdapter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;
import java.util.EnumSet;
/**
* Fragment that displays custom lists.
*/
public class ListPage extends HomeFragment {
// Cursor loader ID for the lists
private static final int LOADER_ID_LIST = 0;
// The page entry associated with this page
private PageEntry mPageEntry;
// Adapter for the list
private HomeListAdapter mAdapter;
// The view shown by the fragment
private ListView mList;
// Callbacks used for the list loader
private CursorLoaderCallbacks mCursorLoaderCallbacks;
// On URL open listener
private OnUrlOpenListener mUrlOpenListener;
@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");
}
}
@Override
public void onDetach() {
super.onDetach();
mUrlOpenListener = null;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
final Bundle args = getArguments();
if (args != null) {
mPageEntry = (PageEntry) args.getParcelable(HomePager.PAGE_ENTRY_ARG);
}
if (mPageEntry == null) {
throw new IllegalStateException("Can't create a ListPage without a PageEntry");
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
mList = new HomeListView(getActivity());
return mList;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
registerForContextMenu(mList);
}
@Override
public void onDestroyView() {
super.onDestroyView();
mList = null;
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Detach and reattach the fragment as the layout changes.
if (isVisible()) {
getFragmentManager().beginTransaction()
.detach(this)
.attach(this)
.commitAllowingStateLoss();
}
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mAdapter = new HomeListAdapter(getActivity(), null);
mList.setAdapter(mAdapter);
// Create callbacks before the initial loader is started.
mCursorLoaderCallbacks = new CursorLoaderCallbacks();
loadIfVisible();
}
@Override
protected void load() {
getLoaderManager().initLoader(LOADER_ID_LIST, null, mCursorLoaderCallbacks);
}
/**
* Cursor loader for the lists.
*/
private static class HomeListLoader extends SimpleCursorLoader {
public HomeListLoader(Context context) {
super(context);
}
@Override
public Cursor loadCursor() {
// Do nothing
return null;
}
}
/**
* Cursor adapter for the list.
*/
private class HomeListAdapter extends CursorAdapter {
public HomeListAdapter(Context context, Cursor cursor) {
super(context, cursor, 0);
}
@Override
public void bindView(View view, Context context, Cursor cursor) {
final TwoLinePageRow row = (TwoLinePageRow) view;
row.updateFromCursor(cursor);
}
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
return LayoutInflater.from(parent.getContext()).inflate(R.layout.bookmark_item_row, parent, false);
}
}
/**
* LoaderCallbacks implementation that interacts with the LoaderManager.
*/
private class CursorLoaderCallbacks implements LoaderCallbacks<Cursor> {
@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
return new HomeListLoader(getActivity());
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor c) {
mAdapter.swapCursor(c);
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
mAdapter.swapCursor(null);
}
}
}

View File

@ -210,11 +210,15 @@ gbjar.sources += [
'home/HistoryPage.java',
'home/HomeAdapter.java',
'home/HomeBanner.java',
'home/HomeConfig.java',
'home/HomeConfigLoader.java',
'home/HomeConfigMemBackend.java',
'home/HomeFragment.java',
'home/HomeListView.java',
'home/HomePager.java',
'home/HomePagerTabStrip.java',
'home/LastTabsPage.java',
'home/ListPage.java',
'home/MostRecentPage.java',
'home/MultiTypeCursorAdapter.java',
'home/PinSiteDialog.java',