Bug 868553 - Implement HomePager for about:home views. r=lucasr

This commit is contained in:
Brian Nicholson 2013-05-13 14:06:34 -07:00
parent 8eb39acda3
commit 620941472f
6 changed files with 182 additions and 85 deletions

View File

@ -13,6 +13,7 @@ import org.mozilla.gecko.gfx.GeckoLayerClient;
import org.mozilla.gecko.gfx.ImmutableViewportMetrics;
import org.mozilla.gecko.gfx.LayerView;
import org.mozilla.gecko.gfx.PanZoomController;
import org.mozilla.gecko.home.HomePager;
import org.mozilla.gecko.util.FloatUtils;
import org.mozilla.gecko.util.GamepadUtils;
import org.mozilla.gecko.util.HardwareUtils;
@ -82,7 +83,7 @@ abstract public class BrowserApp extends GeckoApp
private static final int READER_ADD_DUPLICATE = 2;
public static BrowserToolbar mBrowserToolbar;
private AboutHome mAboutHome;
private HomePager mHomePager;
protected Telemetry.Timer mAboutHomeStartupTimer = null;
private static final int ADDON_MENU_OFFSET = 1000;
@ -124,10 +125,6 @@ abstract public class BrowserApp extends GeckoApp
private Integer mPrefObserverId;
// Tag for the AboutHome fragment. The fragment is automatically attached
// after restoring from a saved state, so we use this tag to identify it.
private static final String ABOUTHOME_TAG = "abouthome";
private SharedPreferencesHelper mSharedPreferencesHelper;
private OrderedBroadcastHelper mOrderedBroadcastHelper;
@ -143,14 +140,14 @@ abstract public class BrowserApp extends GeckoApp
case SELECTED:
if (Tabs.getInstance().isSelectedTab(tab)) {
if ("about:home".equals(tab.getURL())) {
showAboutHome();
showHomePager();
if (isDynamicToolbarEnabled()) {
// Show the toolbar.
mLayerView.getLayerMarginsAnimator().showMargins(false);
}
} else {
hideAboutHome();
hideHomePager();
}
// Dismiss any SiteIdentity Popup
@ -224,7 +221,7 @@ abstract public class BrowserApp extends GeckoApp
case KeyEvent.KEYCODE_BUTTON_Y:
// Toggle/focus the address bar on gamepad-y button.
if (mBrowserToolbar.isVisible()) {
if (isDynamicToolbarEnabled() && !mAboutHome.getUserVisibleHint()) {
if (isDynamicToolbarEnabled() && !mHomePager.isVisible()) {
if (mLayerView != null) {
mLayerView.getLayerMarginsAnimator().hideMargins(false);
mLayerView.requestFocus();
@ -333,8 +330,7 @@ abstract public class BrowserApp extends GeckoApp
ThreadUtils.postToUiThread(new Runnable() {
@Override
public void run() {
if (mAboutHome != null)
mAboutHome.setLastTabsVisibility(false);
mHomePager.setAboutHomeLastTabsVisibility(false);
}
});
@ -357,28 +353,17 @@ abstract public class BrowserApp extends GeckoApp
// If we get a gamepad panning MotionEvent while the focus is not on the layerview,
// put the focus on the layerview and carry on
if (mLayerView != null && !mLayerView.hasFocus() && GamepadUtils.isPanningControl(event)) {
if (mAboutHome.getUserVisibleHint()) {
if (mHomePager.isVisible()) {
mLayerView.requestFocus();
} else {
mAboutHome.requestFocus();
mHomePager.requestFocus();
}
}
return false;
}
});
// Find the Fragment if it was already added from a restored instance state.
mAboutHome = (AboutHome) getSupportFragmentManager().findFragmentByTag(ABOUTHOME_TAG);
if (mAboutHome == null) {
// AboutHome will be dynamically attached and detached as
// about:home is shown. Adding/removing the fragment is not synchronous,
// so we can't use Fragment#isVisible() to determine whether the
// about:home is shown. Instead, we use Fragment#getUserVisibleHint()
// with the hint we set ourselves.
mAboutHome = AboutHome.newInstance();
mAboutHome.setUserVisibleHint(false);
}
mHomePager = (HomePager) findViewById(R.id.abouthome_pager);
mBrowserToolbar = new BrowserToolbar(this);
mBrowserToolbar.from(actionBar);
@ -463,7 +448,7 @@ abstract public class BrowserApp extends GeckoApp
if (mLayerView != null) {
mLayerView.getLayerClient().setOnMetricsChangedListener(null);
}
mAboutHome.setPadding(0, 0, 0, 0);
mHomePager.setPadding(0, 0, 0, 0);
if (mBrowserToolbar != null) {
mBrowserToolbar.getLayout().scrollTo(0, 0);
}
@ -580,7 +565,7 @@ abstract public class BrowserApp extends GeckoApp
@Override
public void onMetricsChanged(ImmutableViewportMetrics aMetrics) {
if (mAboutHome.getUserVisibleHint() || mBrowserToolbar == null) {
if (mHomePager.isVisible() || mBrowserToolbar == null) {
return;
}
@ -595,7 +580,7 @@ abstract public class BrowserApp extends GeckoApp
@Override
public void onPanZoomStopped() {
if (!isDynamicToolbarEnabled() || mAboutHome.getUserVisibleHint()) {
if (!isDynamicToolbarEnabled() || mHomePager.isVisible()) {
return;
}
@ -613,7 +598,7 @@ abstract public class BrowserApp extends GeckoApp
height = mBrowserToolbar.getLayout().getHeight();
}
if (!isDynamicToolbarEnabled() || mAboutHome.getUserVisibleHint()) {
if (!isDynamicToolbarEnabled() || mHomePager.isVisible()) {
// Use aVisibleHeight here so that when the dynamic toolbar is
// enabled, the padding will animate with the toolbar becoming
// visible.
@ -621,7 +606,7 @@ abstract public class BrowserApp extends GeckoApp
// When the dynamic toolbar is enabled, set the padding on the
// about:home widget directly - this is to avoid resizing the
// LayerView, which can cause visible artifacts.
mAboutHome.setPadding(0, height, 0, 0);
mHomePager.setPadding(0, height, 0, 0);
} else {
setToolbarMargin(height);
height = 0;
@ -1028,11 +1013,11 @@ abstract public class BrowserApp extends GeckoApp
/* About:home UI */
void updateAboutHomeTopSites() {
mAboutHome.update(EnumSet.of(AboutHome.UpdateFlags.TOP_SITES));
mHomePager.updateAboutHome(EnumSet.of(AboutHome.UpdateFlags.TOP_SITES));
}
private void showAboutHome() {
if (mAboutHome.getUserVisibleHint()) {
private void showHomePager() {
if (mHomePager.isVisible()) {
return;
}
@ -1045,29 +1030,17 @@ abstract public class BrowserApp extends GeckoApp
mLayerView.getLayerMarginsAnimator().showMargins(true);
}
// We use commitAllowingStateLoss() instead of commit() here to avoid an
// IllegalStateException. showAboutHome() and hideAboutHome() are
// executed inside of tab's onChange() callback. Since that callback can
// be triggered asynchronously from Gecko, it's possible that this
// method can be called while Fennec is in the background. If that
// happens, using commit() would throw an IllegalStateException since
// it can't be used between the Activity's onSaveInstanceState() and
// onResume().
getSupportFragmentManager().beginTransaction()
.add(R.id.gecko_layout, mAboutHome, ABOUTHOME_TAG).commitAllowingStateLoss();
mAboutHome.setUserVisibleHint(true);
mHomePager.show(getSupportFragmentManager());
mBrowserToolbar.setNextFocusDownId(R.id.abouthome_content);
}
private void hideAboutHome() {
if (!mAboutHome.getUserVisibleHint()) {
private void hideHomePager() {
if (!mHomePager.isVisible()) {
return;
}
getSupportFragmentManager().beginTransaction()
.remove(mAboutHome).commitAllowingStateLoss();
mAboutHome.setUserVisibleHint(false);
mHomePager.hide();
mBrowserToolbar.setShadowVisibility(true);
mBrowserToolbar.setNextFocusDownId(R.id.layer_view);

View File

@ -220,6 +220,7 @@ FENNEC_JAVA_FILES = \
gfx/TouchEventHandler.java \
gfx/ViewTransform.java \
gfx/VirtualLayer.java \
home/HomePager.java \
widget/AboutHome.java \
widget/AboutHomeView.java \
widget/AboutHomeSection.java \

View File

@ -0,0 +1,149 @@
/* -*- 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 java.util.ArrayList;
import java.util.EnumMap;
import java.util.EnumSet;
import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentStatePagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.ViewGroup;
import org.mozilla.gecko.widget.AboutHome;
public class HomePager extends ViewPager {
private final Context mContext;
private volatile boolean mLoaded;
private enum Page {
ABOUT_HOME
}
private EnumMap<Page, Fragment> mPages = new EnumMap<Page, Fragment>(Page.class);
public HomePager(Context context) {
super(context);
mContext = context;
}
public HomePager(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
}
/**
* Loads and initializes the pager.
*
* @param fm FragmentManager for the adapter
*/
public void show(FragmentManager fm) {
mLoaded = true;
TabsAdapter adapter = new TabsAdapter(fm);
adapter.addTab(Page.ABOUT_HOME, AboutHome.class, null);
setAdapter(adapter);
setVisibility(VISIBLE);
}
/**
* Hides the pager and removes all child fragments.
*/
public void hide() {
mLoaded = false;
setVisibility(GONE);
setAdapter(null);
}
/**
* Determines whether the pager is visible.
*
* Unlike getVisibility(), this method does not need to be called on the UI
* thread.
*
* @return Whether the pager and its fragments are being displayed
*/
public boolean isVisible() {
return mLoaded;
}
/**
* @see AboutHome#update(EnumSet)
*/
public void updateAboutHome(final EnumSet<AboutHome.UpdateFlags> flags) {
AboutHome aboutHome = (AboutHome) mPages.get(Page.ABOUT_HOME);
if (aboutHome != null) {
aboutHome.update(flags);
}
}
/**
* @see AboutHome#setLastTabsVisibility(boolean)
*/
public void setAboutHomeLastTabsVisibility(boolean visible) {
AboutHome aboutHome = (AboutHome) mPages.get(Page.ABOUT_HOME);
if (aboutHome != null) {
aboutHome.setLastTabsVisibility(visible);
}
}
class TabsAdapter extends FragmentStatePagerAdapter {
private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
final class TabInfo {
private final Page page;
private final Class<?> clss;
private final Bundle args;
TabInfo(Page page, Class<?> clss, Bundle args) {
this.page = page;
this.clss = clss;
this.args = args;
}
}
public TabsAdapter(FragmentManager fm) {
super(fm);
}
public void addTab(Page page, Class<?> clss, Bundle args) {
TabInfo info = new TabInfo(page, clss, args);
mTabs.add(info);
notifyDataSetChanged();
}
@Override
public int getCount() {
return mTabs.size();
}
@Override
public Fragment getItem(int position) {
TabInfo info = mTabs.get(position);
return Fragment.instantiate(mContext, info.clss.getName(), info.args);
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
Fragment fragment = (Fragment) super.instantiateItem(container, position);
mPages.put(mTabs.get(position).page, fragment);
return fragment;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
super.destroyItem(container, position, object);
mPages.remove(mTabs.get(position).page);
}
}
}

View File

@ -4,12 +4,11 @@
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<org.mozilla.gecko.widget.AboutHomeView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:gecko="http://schemas.android.com/apk/res-auto"
android:id="@+id/abouthome_content"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@color/background_normal">
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:gecko="http://schemas.android.com/apk/res-auto"
android:id="@+id/abouthome_content"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<RelativeLayout android:layout_width="fill_parent"
android:layout_height="fill_parent"

View File

@ -28,6 +28,12 @@
<include layout="@layout/shared_ui_components"/>
<org.mozilla.gecko.home.HomePager android:id="@+id/abouthome_pager"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="@color/background_normal"
android:visibility="gone"/>
</RelativeLayout>
<org.mozilla.gecko.FindInPageBar android:id="@+id/find_in_page"

View File

@ -37,10 +37,6 @@ public class AboutHome extends Fragment {
private LoadCompleteListener mLoadCompleteListener;
private LightweightTheme mLightweightTheme;
private ContentObserver mTabsContentObserver;
private int mPaddingLeft;
private int mPaddingRight;
private int mPaddingTop;
private int mPaddingBottom;
private AboutHomeView mAboutHomeView;
private AddonsSection mAddonsSection;
private LastTabsSection mLastTabsSection;
@ -55,10 +51,6 @@ public class AboutHome extends Fragment {
public void onAboutHomeLoadComplete();
}
public static AboutHome newInstance() {
return new AboutHome();
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@ -113,7 +105,6 @@ public class AboutHome extends Fragment {
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
view.setPadding(mPaddingLeft, mPaddingTop, mPaddingRight, mPaddingBottom);
((PromoBox) view.findViewById(R.id.promo_box)).showRandomPromo();
update(AboutHome.UpdateFlags.ALL);
@ -234,26 +225,4 @@ public class AboutHome extends Fragment {
else
mLastTabsSection.hide();
}
public void requestFocus() {
View view = getView();
if (view != null) {
view.requestFocus();
}
}
public void setPadding(int left, int top, int right, int bottom) {
View view = getView();
if (view != null) {
view.setPadding(left, top, right, bottom);
}
// If the padding has changed but the view hasn't been created yet,
// store the padding values here; they will be used later in
// onViewCreated().
mPaddingLeft = left;
mPaddingRight = right;
mPaddingTop = top;
mPaddingBottom = bottom;
}
}