Bug 960359: (3/4) Display HomeBanner on default page and animate. r=margaret

This commit is contained in:
Josh Dover 2014-02-13 15:47:17 -08:00
parent 2c1e3e5ab9
commit 47251984bd
4 changed files with 174 additions and 20 deletions

View File

@ -24,6 +24,7 @@ import org.mozilla.gecko.health.BrowserHealthReporter;
import org.mozilla.gecko.health.HealthRecorder;
import org.mozilla.gecko.health.SessionInformation;
import org.mozilla.gecko.home.BrowserSearch;
import org.mozilla.gecko.home.HomeBanner;
import org.mozilla.gecko.home.HomeConfigInvalidator;
import org.mozilla.gecko.home.HomePager;
import org.mozilla.gecko.home.HomePager.OnUrlOpenListener;
@ -1678,6 +1679,9 @@ abstract public class BrowserApp extends GeckoApp
if (mHomePager == null) {
final ViewStub homePagerStub = (ViewStub) findViewById(R.id.home_pager_stub);
mHomePager = (HomePager) homePagerStub.inflate();
HomeBanner homeBanner = (HomeBanner) findViewById(R.id.home_banner);
mHomePager.setBanner(homeBanner);
}
mHomePagerContainer.setVisibility(View.VISIBLE);

View File

@ -5,6 +5,10 @@
package org.mozilla.gecko.home;
import org.mozilla.gecko.animation.PropertyAnimator;
import org.mozilla.gecko.animation.PropertyAnimator.Property;
import org.mozilla.gecko.animation.PropertyAnimator.PropertyAnimationListener;
import org.mozilla.gecko.animation.ViewHelper;
import org.mozilla.gecko.GeckoAppShell;
import org.mozilla.gecko.GeckoEvent;
import org.mozilla.gecko.R;
@ -23,6 +27,7 @@ import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.widget.ImageButton;
import android.widget.ImageView;
@ -33,6 +38,22 @@ public class HomeBanner extends LinearLayout
implements GeckoEventListener {
private static final String LOGTAG = "GeckoHomeBanner";
// Used for tracking scroll length
private float mTouchY = -1;
// Used to detect for upwards scroll to push banner all the way up
private boolean mSnapBannerToTop;
// Tracks if the banner has been enabled by HomePager to avoid race conditions.
private boolean mEnabled = false;
// The user is currently swiping between HomePager pages
private boolean mScrollingPages = false;
// Tracks whether the user swiped the banner down, preventing us from autoshowing when the user
// switches back to the default page.
private boolean mUserSwipedDown = false;
public HomeBanner(Context context) {
this(context, null);
}
@ -82,9 +103,9 @@ public class HomeBanner extends LinearLayout
GeckoAppShell.getEventDispatcher().unregisterEventListener("HomeBanner:Data", this);
}
public boolean isDismissed() {
return (getVisibility() == View.GONE);
}
public void setScrollingPages(boolean scrollingPages) {
mScrollingPages = scrollingPages;
}
@Override
public void handleMessage(String event, JSONObject message) {
@ -101,7 +122,8 @@ public class HomeBanner extends LinearLayout
@Override
public void run() {
textView.setText(text);
setVisibility(View.VISIBLE);
setVisibility(VISIBLE);
animateUp();
}
});
} catch (JSONException e) {
@ -137,4 +159,102 @@ public class HomeBanner extends LinearLayout
}
});
}
public void setEnabled(boolean enabled) {
// No need to animate if not changing
if (mEnabled == enabled) {
return;
}
mEnabled = enabled;
if (enabled) {
animateUp();
} else {
animateDown();
}
}
private void animateUp() {
// Check to make sure that message has been received and the banner has been enabled.
// Necessary to avoid race conditions between show() and handleMessage() calls.
TextView textView = (TextView) findViewById(R.id.text);
if (!mEnabled || TextUtils.isEmpty(textView.getText()) || mUserSwipedDown) {
return;
}
// No need to animate if already translated.
if (ViewHelper.getTranslationY(this) == 0) {
return;
}
final PropertyAnimator animator = new PropertyAnimator(100);
animator.attach(this, Property.TRANSLATION_Y, 0);
animator.start();
}
private void animateDown() {
// No need to animate if already translated or gone.
if (ViewHelper.getTranslationY(this) == getHeight()) {
return;
}
final PropertyAnimator animator = new PropertyAnimator(100);
animator.attach(this, Property.TRANSLATION_Y, getHeight());
animator.start();
}
public void handleHomeTouch(MotionEvent event) {
if (!mEnabled || getVisibility() == GONE || mScrollingPages) {
return;
}
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN: {
// Track the beginning of the touch
mTouchY = event.getRawY();
break;
}
case MotionEvent.ACTION_MOVE: {
final float curY = event.getRawY();
final float delta = mTouchY - curY;
mSnapBannerToTop = delta <= 0.0f;
final float height = getHeight();
float newTranslationY = ViewHelper.getTranslationY(this) + delta;
// Clamp the values to be between 0 and height.
if (newTranslationY < 0.0f) {
newTranslationY = 0.0f;
} else if (newTranslationY > height) {
newTranslationY = height;
}
// Don't change this value if it wasn't a significant movement
if (delta >= 10 || delta <= -10) {
mUserSwipedDown = newTranslationY == height;
}
ViewHelper.setTranslationY(this, newTranslationY);
mTouchY = curY;
break;
}
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL: {
mTouchY = -1;
final float y = ViewHelper.getTranslationY(this);
final float height = getHeight();
if (y > 0.0f && y < height) {
if (mSnapBannerToTop) {
animateUp();
} else {
animateDown();
mUserSwipedDown = true;
}
}
break;
}
}
}
}

View File

@ -41,6 +41,8 @@ public class HomePager extends ViewPager {
private volatile boolean mLoaded;
private Decor mDecor;
private View mTabStrip;
private HomeBanner mHomeBanner;
private int mDefaultPageIndex = -1;
private final OnAddPanelListener mAddPanelListener;
@ -125,6 +127,7 @@ public class HomePager extends ViewPager {
setFocusableInTouchMode(true);
mOriginalBackground = getBackground();
setOnPageChangeListener(new PageChangeListener());
}
@Override
@ -140,21 +143,6 @@ public class HomePager extends ViewPager {
setCurrentItem(index, true);
}
});
setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageSelected(int position) {
mDecor.onPageSelected(position);
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
mDecor.onPageScrolled(position, positionOffset, positionOffsetPixels);
}
@Override
public void onPageScrollStateChanged(int state) { }
});
} else if (child instanceof HomePagerTabStrip) {
mTabStrip = child;
}
@ -247,6 +235,19 @@ public class HomePager extends ViewPager {
return super.onInterceptTouchEvent(event);
}
public void setBanner(HomeBanner banner) {
mHomeBanner = banner;
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
if (mHomeBanner != null) {
mHomeBanner.handleHomeTouch(event);
}
return super.dispatchTouchEvent(event);
}
private void updateUiFromPanelConfigs(List<PanelConfig> panelConfigs) {
// We only care about the adapter if HomePager is currently
// loaded, which means it's visible in the activity.
@ -303,6 +304,7 @@ public class HomePager extends ViewPager {
for (int i = 0; i < count; i++) {
final PanelConfig panelConfig = enabledPanels.get(i);
if (panelConfig.isDefault()) {
mDefaultPageIndex = i;
setCurrentItem(i, false);
break;
}
@ -325,4 +327,31 @@ public class HomePager extends ViewPager {
public void onLoaderReset(Loader<List<PanelConfig>> loader) {
}
}
private class PageChangeListener implements ViewPager.OnPageChangeListener {
@Override
public void onPageSelected(int position) {
if (mDecor != null) {
mDecor.onPageSelected(position);
}
if (mHomeBanner != null) {
mHomeBanner.setEnabled(position == mDefaultPageIndex);
}
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
if (mDecor != null) {
mDecor.onPageScrolled(position, positionOffset, positionOffsetPixels);
}
if (mHomeBanner != null) {
mHomeBanner.setScrollingPages(positionOffsetPixels != 0);
}
}
@Override
public void onPageScrollStateChanged(int state) { }
}
}

View File

@ -44,7 +44,8 @@
android:gravity="center_vertical"
android:visibility="gone"
android:clickable="true"
android:focusable="true"/>
android:focusable="true"
android:translationY="@dimen/home_banner_height"/>
</FrameLayout>