mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-30 13:45:27 +00:00
Bug 942231 - Change HomePager to be backed by HomeConfig (r=margaret)
This commit is contained in:
parent
c5f8fff541
commit
c1e1d38335
2
CLOBBER
2
CLOBBER
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
224
mobile/android/base/home/HomeConfig.java
Normal file
224
mobile/android/base/home/HomeConfig.java
Normal 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));
|
||||
}
|
||||
}
|
83
mobile/android/base/home/HomeConfigLoader.java
Normal file
83
mobile/android/base/home/HomeConfigLoader.java
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
67
mobile/android/base/home/HomeConfigMemBackend.java
Normal file
67
mobile/android/base/home/HomeConfigMemBackend.java
Normal 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.
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
185
mobile/android/base/home/ListPage.java
Normal file
185
mobile/android/base/home/ListPage.java
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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',
|
||||
|
Loading…
Reference in New Issue
Block a user