mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-24 00:24:14 +00:00
Bug 767980 - Reimplement PropertyAnimator in terms of view proxies (r=mfinkle)
This commit is contained in:
parent
14c4c78adc
commit
60fcbd1dd8
303
mobile/android/base/AnimatorProxy.java
Normal file
303
mobile/android/base/AnimatorProxy.java
Normal file
@ -0,0 +1,303 @@
|
||||
/* -*- 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;
|
||||
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.RectF;
|
||||
import android.os.Build;
|
||||
import android.view.View;
|
||||
import android.view.animation.Animation;
|
||||
import android.view.animation.AnimationUtils;
|
||||
import android.view.animation.Transformation;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
public class AnimatorProxy {
|
||||
private static final WeakHashMap<View, AnimatorProxy> PROXIES =
|
||||
new WeakHashMap<View, AnimatorProxy>();
|
||||
|
||||
private static interface AnimatorProxyImpl {
|
||||
public int getScrollX();
|
||||
public int getScrollY();
|
||||
public void scrollTo(int scrollX, int scrollY);
|
||||
|
||||
public float getTranslationX();
|
||||
public void setTranslationX(float translationX);
|
||||
|
||||
public float getTranslationY();
|
||||
public void setTranslationY(float translationY);
|
||||
}
|
||||
|
||||
private AnimatorProxyImpl mImpl;
|
||||
|
||||
private AnimatorProxy(AnimatorProxyImpl impl) {
|
||||
mImpl = impl;
|
||||
}
|
||||
|
||||
public static AnimatorProxy create(View view) {
|
||||
AnimatorProxy proxy = PROXIES.get(view);
|
||||
boolean needsAnimationProxy = (Build.VERSION.SDK_INT < 11);
|
||||
|
||||
// If the view's animation proxy has been overridden from somewhere else, we need to
|
||||
// create a new AnimatorProxy for the view.
|
||||
if (proxy == null || (needsAnimationProxy && proxy.mImpl != view.getAnimation())) {
|
||||
AnimatorProxyImpl impl = (needsAnimationProxy ? new AnimatorProxyPreHC(view) :
|
||||
new AnimatorProxyPostHC(view));
|
||||
|
||||
proxy = new AnimatorProxy(impl);
|
||||
PROXIES.put(view, proxy);
|
||||
}
|
||||
|
||||
return proxy;
|
||||
}
|
||||
|
||||
public int getScrollX() {
|
||||
return mImpl.getScrollX();
|
||||
}
|
||||
|
||||
public int getScrollY() {
|
||||
return mImpl.getScrollY();
|
||||
}
|
||||
|
||||
public void scrollTo(int scrollX, int scrollY) {
|
||||
mImpl.scrollTo(scrollX, scrollY);
|
||||
}
|
||||
|
||||
public float getTranslationX() {
|
||||
return mImpl.getTranslationX();
|
||||
}
|
||||
|
||||
public void setTranslationX(float translationX) {
|
||||
mImpl.setTranslationX(translationX);
|
||||
}
|
||||
|
||||
public float getTranslationY() {
|
||||
return mImpl.getTranslationY();
|
||||
}
|
||||
|
||||
public void setTranslationY(float translationY) {
|
||||
mImpl.setTranslationY(translationY);
|
||||
}
|
||||
|
||||
/*
|
||||
* AnimatorProxyPreHC uses the technique used by the NineOldAndroids described here:
|
||||
* http://jakewharton.com/advanced-pre-honeycomb-animation/
|
||||
*
|
||||
* Some of this code is based on Jake Wharton's AnimatorProxy released as part of
|
||||
* the NineOldAndroids library under the Apache License 2.0.
|
||||
*/
|
||||
private static class AnimatorProxyPreHC extends Animation implements AnimatorProxyImpl {
|
||||
private WeakReference<View> mViewRef;
|
||||
|
||||
private final RectF mBefore;
|
||||
private final RectF mAfter;
|
||||
private final Matrix mTempMatrix;
|
||||
|
||||
private float mTranslationX;
|
||||
private float mTranslationY;
|
||||
|
||||
public AnimatorProxyPreHC(View view) {
|
||||
mBefore = new RectF();
|
||||
mAfter = new RectF();
|
||||
mTempMatrix = new Matrix();
|
||||
|
||||
mTranslationX = 0;
|
||||
mTranslationY = 0;
|
||||
|
||||
loadCurrentTransformation(view);
|
||||
|
||||
setDuration(0);
|
||||
setFillAfter(true);
|
||||
view.setAnimation(this);
|
||||
|
||||
mViewRef = new WeakReference<View>(view);
|
||||
}
|
||||
|
||||
private void loadCurrentTransformation(View view) {
|
||||
Animation animation = view.getAnimation();
|
||||
if (animation == null)
|
||||
return;
|
||||
|
||||
Transformation transformation = new Transformation();
|
||||
float[] matrix = new float[9];
|
||||
|
||||
animation.getTransformation(AnimationUtils.currentAnimationTimeMillis(), transformation);
|
||||
transformation.getMatrix().getValues(matrix);
|
||||
|
||||
mTranslationX = matrix[Matrix.MTRANS_X];
|
||||
mTranslationY = matrix[Matrix.MTRANS_Y];
|
||||
}
|
||||
|
||||
private void prepareForUpdate() {
|
||||
View view = mViewRef.get();
|
||||
if (view != null)
|
||||
computeRect(mBefore, view);
|
||||
}
|
||||
|
||||
private void computeRect(final RectF r, View view) {
|
||||
final float w = view.getWidth();
|
||||
final float h = view.getHeight();
|
||||
|
||||
r.set(0, 0, w, h);
|
||||
|
||||
final Matrix m = mTempMatrix;
|
||||
m.reset();
|
||||
transformMatrix(m, view);
|
||||
mTempMatrix.mapRect(r);
|
||||
|
||||
r.offset(view.getLeft(), view.getTop());
|
||||
}
|
||||
|
||||
private void transformMatrix(Matrix m, View view) {
|
||||
m.postTranslate(mTranslationX, mTranslationY);
|
||||
}
|
||||
|
||||
private void invalidateAfterUpdate() {
|
||||
View view = mViewRef.get();
|
||||
if (view == null || view.getParent() == null)
|
||||
return;
|
||||
|
||||
final RectF after = mAfter;
|
||||
computeRect(after, view);
|
||||
after.union(mBefore);
|
||||
|
||||
((View)view.getParent()).invalidate(
|
||||
(int) Math.floor(after.left),
|
||||
(int) Math.floor(after.top),
|
||||
(int) Math.ceil(after.right),
|
||||
(int) Math.ceil(after.bottom));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getScrollX() {
|
||||
View view = mViewRef.get();
|
||||
if (view != null)
|
||||
return view.getScrollX();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getScrollY() {
|
||||
View view = mViewRef.get();
|
||||
if (view != null)
|
||||
return view.getScrollY();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scrollTo(int scrollX, int scrollY) {
|
||||
View view = mViewRef.get();
|
||||
if (view != null)
|
||||
view.scrollTo(scrollX, scrollY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getTranslationX() {
|
||||
return mTranslationX;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTranslationX(float translationX) {
|
||||
if (mTranslationX == translationX)
|
||||
return;
|
||||
|
||||
prepareForUpdate();
|
||||
mTranslationX = translationX;
|
||||
invalidateAfterUpdate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getTranslationY() {
|
||||
return mTranslationY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTranslationY(float translationY) {
|
||||
if (mTranslationY == translationY)
|
||||
return;
|
||||
|
||||
prepareForUpdate();
|
||||
mTranslationY = translationY;
|
||||
invalidateAfterUpdate();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyTransformation(float interpolatedTime, Transformation t) {
|
||||
View view = mViewRef.get();
|
||||
if (view != null)
|
||||
transformMatrix(t.getMatrix(), view);
|
||||
}
|
||||
}
|
||||
|
||||
private static class AnimatorProxyPostHC implements AnimatorProxyImpl {
|
||||
private WeakReference<View> mViewRef;
|
||||
|
||||
public AnimatorProxyPostHC(View view) {
|
||||
mViewRef = new WeakReference<View>(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getScrollX() {
|
||||
View view = mViewRef.get();
|
||||
if (view != null)
|
||||
return view.getScrollX();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getScrollY() {
|
||||
View view = mViewRef.get();
|
||||
if (view != null)
|
||||
return view.getScrollY();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void scrollTo(int scrollX, int scrollY) {
|
||||
View view = mViewRef.get();
|
||||
if (view != null)
|
||||
view.scrollTo(scrollX, scrollY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getTranslationX() {
|
||||
View view = mViewRef.get();
|
||||
if (view != null)
|
||||
return view.getTranslationX();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTranslationX(float translationX) {
|
||||
View view = mViewRef.get();
|
||||
if (view != null)
|
||||
view.setTranslationX(translationX);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getTranslationY() {
|
||||
View view = mViewRef.get();
|
||||
if (view != null)
|
||||
return view.getTranslationY();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTranslationY(float translationY) {
|
||||
View view = mViewRef.get();
|
||||
if (view != null)
|
||||
view.setTranslationY(translationY);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -511,26 +511,29 @@ abstract public class BrowserApp extends GeckoApp
|
||||
mMainLayoutAnimator = new PropertyAnimator(450, sTabsInterpolator);
|
||||
mMainLayoutAnimator.setPropertyAnimationListener(this);
|
||||
|
||||
boolean usingTextureView = mLayerView.shouldUseTextureView();
|
||||
mMainLayoutAnimator.setUseHardwareLayer(usingTextureView);
|
||||
|
||||
if (hasTabsSideBar()) {
|
||||
mMainLayoutAnimator.attach(mBrowserToolbar.getLayout(),
|
||||
PropertyAnimator.Property.SHRINK_LEFT,
|
||||
width);
|
||||
mBrowserToolbar.prepareTabsAnimation(mMainLayoutAnimator, width);
|
||||
|
||||
// Set the gecko layout for sliding.
|
||||
if (!mTabsPanel.isShown()) {
|
||||
((LinearLayout.LayoutParams) mGeckoLayout.getLayoutParams()).setMargins(0, 0, 0, 0);
|
||||
mGeckoLayout.scrollTo(mTabsPanel.getWidth() * -1, 0);
|
||||
if (!usingTextureView)
|
||||
mGeckoLayout.scrollTo(mTabsPanel.getWidth() * -1, 0);
|
||||
mGeckoLayout.requestLayout();
|
||||
}
|
||||
|
||||
mMainLayoutAnimator.attach(mGeckoLayout,
|
||||
PropertyAnimator.Property.SLIDE_LEFT,
|
||||
width);
|
||||
|
||||
usingTextureView ? PropertyAnimator.Property.TRANSLATION_X :
|
||||
PropertyAnimator.Property.SCROLL_X,
|
||||
usingTextureView ? width : -width);
|
||||
} else {
|
||||
mMainLayoutAnimator.attach(mMainLayout,
|
||||
PropertyAnimator.Property.SLIDE_TOP,
|
||||
height);
|
||||
usingTextureView ? PropertyAnimator.Property.TRANSLATION_Y :
|
||||
PropertyAnimator.Property.SCROLL_Y,
|
||||
usingTextureView ? height : -height);
|
||||
}
|
||||
|
||||
mMainLayoutAnimator.start();
|
||||
@ -538,30 +541,39 @@ abstract public class BrowserApp extends GeckoApp
|
||||
|
||||
@Override
|
||||
public void onPropertyAnimationStart() {
|
||||
mMainHandler.post(new Runnable() {
|
||||
public void run() {
|
||||
mBrowserToolbar.updateTabs(true);
|
||||
}
|
||||
});
|
||||
mBrowserToolbar.updateTabs(true);
|
||||
|
||||
// Although the tabs panel is not animating per se, it will be re-drawn several
|
||||
// times while the main/gecko layout slides to left/top. Adding a hardware layer
|
||||
// here considerably improves the frame rate of the animation.
|
||||
if (Build.VERSION.SDK_INT >= 11)
|
||||
mTabsPanel.setLayerType(View.LAYER_TYPE_HARDWARE, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPropertyAnimationEnd() {
|
||||
mMainHandler.post(new Runnable() {
|
||||
public void run() {
|
||||
if (hasTabsSideBar() && mTabsPanel.isShown()) {
|
||||
// Fake the gecko layout to have been shrunk, instead of sliding.
|
||||
((LinearLayout.LayoutParams) mGeckoLayout.getLayoutParams()).setMargins(mTabsPanel.getWidth(), 0, 0, 0);
|
||||
mGeckoLayout.scrollTo(0, 0);
|
||||
mGeckoLayout.requestLayout();
|
||||
}
|
||||
// Destroy the hardware layer used during the animation
|
||||
if (Build.VERSION.SDK_INT >= 11)
|
||||
mTabsPanel.setLayerType(View.LAYER_TYPE_NONE, null);
|
||||
|
||||
if (!mTabsPanel.isShown()) {
|
||||
mBrowserToolbar.updateTabs(false);
|
||||
mTabsPanel.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
|
||||
}
|
||||
}
|
||||
});
|
||||
if (hasTabsSideBar() && mTabsPanel.isShown()) {
|
||||
boolean usingTextureView = mLayerView.shouldUseTextureView();
|
||||
|
||||
int leftMargin = (usingTextureView ? 0 : mTabsPanel.getWidth());
|
||||
int rightMargin = (usingTextureView ? mTabsPanel.getWidth() : 0);
|
||||
((LinearLayout.LayoutParams) mGeckoLayout.getLayoutParams()).setMargins(leftMargin, 0, rightMargin, 0);
|
||||
|
||||
if (!usingTextureView)
|
||||
mGeckoLayout.scrollTo(0, 0);
|
||||
|
||||
mGeckoLayout.requestLayout();
|
||||
}
|
||||
|
||||
if (!mTabsPanel.isShown()) {
|
||||
mBrowserToolbar.updateTabs(false);
|
||||
mBrowserToolbar.finishTabsAnimation();
|
||||
mTabsPanel.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
|
||||
}
|
||||
}
|
||||
|
||||
/* Favicon methods */
|
||||
|
@ -51,12 +51,15 @@ public class BrowserToolbar implements ViewSwitcher.ViewFactory,
|
||||
Animation.AnimationListener {
|
||||
private static final String LOGTAG = "GeckoToolbar";
|
||||
private LinearLayout mLayout;
|
||||
private Button mAwesomeBar;
|
||||
private View mAwesomeBar;
|
||||
private View mAwesomeBarRightEdge;
|
||||
private View mAddressBarBg;
|
||||
private TextView mTitle;
|
||||
private int mTitlePadding;
|
||||
private boolean mSiteSecurityVisible;
|
||||
private boolean mAnimateSiteSecurity;
|
||||
private ImageButton mTabs;
|
||||
private int mTabsPaneWidth;
|
||||
private ImageView mBack;
|
||||
private ImageView mForward;
|
||||
public ImageButton mFavicon;
|
||||
@ -112,12 +115,29 @@ public class BrowserToolbar implements ViewSwitcher.ViewFactory,
|
||||
mShowSiteSecurity = false;
|
||||
mShowReader = false;
|
||||
|
||||
// Only used on tablet layout. We need a separate view for the background
|
||||
// because we need to slide it left/right for hiding/shoing the tabs sidebar
|
||||
// See prepareTabsAnimation().
|
||||
mAddressBarBg = mLayout.findViewById(R.id.address_bar_bg);
|
||||
|
||||
// Only used on tablet layout. The tabs sidebar slide animation is implemented
|
||||
// in terms of translating the inner elements of the tablet toolbar to give the
|
||||
// impression of resizing. In order to do this, This "fake" right edge is kept
|
||||
// in the same position during the animation while the elements on the left
|
||||
// (favicon, back, forware, lock icon, title, ...) slide behind it.
|
||||
// See prepareTabsAnimation().
|
||||
mAwesomeBarRightEdge = mLayout.findViewById(R.id.awesome_bar_right_edge);
|
||||
|
||||
// This will hold the translation width inside the toolbar when the tabs
|
||||
// pane is visible. It will affect the padding applied to the title TextView.
|
||||
mTabsPaneWidth = 0;
|
||||
|
||||
mTitle = (TextView) mLayout.findViewById(R.id.awesome_bar_title);
|
||||
mTitlePadding = mTitle.getPaddingRight();
|
||||
if (Build.VERSION.SDK_INT >= 16)
|
||||
mTitle.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
|
||||
|
||||
mAwesomeBar = (Button) mLayout.findViewById(R.id.awesome_bar);
|
||||
mAwesomeBar = mLayout.findViewById(R.id.awesome_bar);
|
||||
mAwesomeBar.setOnClickListener(new Button.OnClickListener() {
|
||||
public void onClick(View v) {
|
||||
mActivity.autoHideTabs();
|
||||
@ -460,6 +480,54 @@ public class BrowserToolbar implements ViewSwitcher.ViewFactory,
|
||||
updateTabs(mActivity.areTabsShown());
|
||||
}
|
||||
|
||||
public void prepareTabsAnimation(PropertyAnimator animator, int width) {
|
||||
// This is negative before we want to keep the right edge in the same
|
||||
// position while animating the left-most elements below.
|
||||
animator.attach(mAwesomeBarRightEdge,
|
||||
PropertyAnimator.Property.TRANSLATION_X,
|
||||
-width);
|
||||
|
||||
animator.attach(mAwesomeBar,
|
||||
PropertyAnimator.Property.TRANSLATION_X,
|
||||
width);
|
||||
animator.attach(mAddressBarBg,
|
||||
PropertyAnimator.Property.TRANSLATION_X,
|
||||
width);
|
||||
animator.attach(mTabs,
|
||||
PropertyAnimator.Property.TRANSLATION_X,
|
||||
width);
|
||||
animator.attach(mTabsCount,
|
||||
PropertyAnimator.Property.TRANSLATION_X,
|
||||
width);
|
||||
animator.attach(mBack,
|
||||
PropertyAnimator.Property.TRANSLATION_X,
|
||||
width);
|
||||
animator.attach(mForward,
|
||||
PropertyAnimator.Property.TRANSLATION_X,
|
||||
width);
|
||||
animator.attach(mTitle,
|
||||
PropertyAnimator.Property.TRANSLATION_X,
|
||||
width);
|
||||
animator.attach(mFavicon,
|
||||
PropertyAnimator.Property.TRANSLATION_X,
|
||||
width);
|
||||
animator.attach(mSiteSecurity,
|
||||
PropertyAnimator.Property.TRANSLATION_X,
|
||||
width);
|
||||
|
||||
mTabsPaneWidth = width;
|
||||
|
||||
// Only update title padding immediatelly when shrinking the browser
|
||||
// toolbar. Leave the padding update to the end of the animation when
|
||||
// expanding (see finishTabsAnimation()).
|
||||
if (mTabsPaneWidth > 0)
|
||||
setPageActionVisibility(mStop.getVisibility() == View.VISIBLE);
|
||||
}
|
||||
|
||||
public void finishTabsAnimation() {
|
||||
setPageActionVisibility(mStop.getVisibility() == View.VISIBLE);
|
||||
}
|
||||
|
||||
public void updateTabs(boolean areTabsShown) {
|
||||
if (areTabsShown) {
|
||||
mTabs.getBackground().setLevel(TABS_EXPANDED);
|
||||
@ -511,7 +579,7 @@ public class BrowserToolbar implements ViewSwitcher.ViewFactory,
|
||||
// We want title to fill the whole space available for it when there are icons
|
||||
// being shown on the right side of the toolbar as the icons already have some
|
||||
// padding in them. This is just to avoid wasting space when icons are shown.
|
||||
mTitle.setPadding(0, 0, (!mShowReader && !isLoading ? mTitlePadding : 0), 0);
|
||||
mTitle.setPadding(0, 0, (!mShowReader && !isLoading ? mTitlePadding : 0) + mTabsPaneWidth, 0);
|
||||
|
||||
updateFocusOrder();
|
||||
}
|
||||
|
@ -175,7 +175,7 @@ abstract public class GeckoApp
|
||||
protected FormAssistPopup mFormAssistPopup;
|
||||
protected TabsPanel mTabsPanel;
|
||||
|
||||
private LayerView mLayerView;
|
||||
protected LayerView mLayerView;
|
||||
private AbsoluteLayout mPluginContainer;
|
||||
|
||||
private FullScreenHolder mFullScreenPluginContainer;
|
||||
|
@ -40,6 +40,7 @@ FENNEC_JAVA_FILES = \
|
||||
ActivityHandlerHelper.java \
|
||||
AndroidImport.java \
|
||||
AndroidImportPreference.java \
|
||||
AnimatorProxy.java \
|
||||
AlertNotification.java \
|
||||
AnimatedHeightLayout.java \
|
||||
AwesomeBar.java \
|
||||
|
@ -17,24 +17,23 @@ import android.view.animation.Interpolator;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
public class PropertyAnimator implements Runnable {
|
||||
private static final String LOGTAG = "GeckoPropertyAnimator";
|
||||
|
||||
public static enum Property {
|
||||
SHRINK_LEFT,
|
||||
SHRINK_TOP,
|
||||
SLIDE_TOP,
|
||||
SLIDE_LEFT
|
||||
TRANSLATION_X,
|
||||
TRANSLATION_Y,
|
||||
SCROLL_X,
|
||||
SCROLL_Y
|
||||
}
|
||||
|
||||
private class ElementHolder {
|
||||
View view;
|
||||
AnimatorProxy proxy;
|
||||
Property property;
|
||||
int from;
|
||||
int to;
|
||||
float from;
|
||||
float to;
|
||||
}
|
||||
|
||||
public static interface PropertyAnimationListener {
|
||||
@ -49,6 +48,7 @@ public class PropertyAnimator implements Runnable {
|
||||
private List<ElementHolder> mElementsList;
|
||||
private PropertyAnimationListener mListener;
|
||||
private FramePoster mFramePoster;
|
||||
private boolean mUseHardwareLayer;
|
||||
|
||||
public PropertyAnimator(int duration) {
|
||||
this(duration, new DecelerateInterpolator());
|
||||
@ -60,25 +60,20 @@ public class PropertyAnimator implements Runnable {
|
||||
mInterpolator = interpolator;
|
||||
mElementsList = new ArrayList<ElementHolder>();
|
||||
mFramePoster = FramePoster.create(this);
|
||||
mUseHardwareLayer = true;
|
||||
}
|
||||
|
||||
public void setUseHardwareLayer(boolean useHardwareLayer) {
|
||||
mUseHardwareLayer = useHardwareLayer;
|
||||
}
|
||||
|
||||
public void attach(View view, Property property, int to) {
|
||||
if (!(view instanceof ViewGroup) && (property == Property.SHRINK_LEFT ||
|
||||
property == Property.SHRINK_TOP)) {
|
||||
Log.i(LOGTAG, "Margin can only be animated on Viewgroups");
|
||||
return;
|
||||
}
|
||||
|
||||
ElementHolder element = new ElementHolder();
|
||||
|
||||
element.view = view;
|
||||
element.proxy = AnimatorProxy.create(view);
|
||||
element.property = property;
|
||||
|
||||
// Sliding should happen in the negative.
|
||||
if (property == Property.SLIDE_TOP || property == Property.SLIDE_LEFT)
|
||||
element.to = to * -1;
|
||||
else
|
||||
element.to = to;
|
||||
element.to = to;
|
||||
|
||||
mElementsList.add(element);
|
||||
}
|
||||
@ -98,7 +93,7 @@ public class PropertyAnimator implements Runnable {
|
||||
float interpolation = mInterpolator.getInterpolation(timePassed * mDurationReciprocal);
|
||||
|
||||
for (ElementHolder element : mElementsList) {
|
||||
int delta = element.from + (int) ((element.to - element.from) * interpolation);
|
||||
float delta = element.from + ((element.to - element.from) * interpolation);
|
||||
invalidate(element, delta);
|
||||
}
|
||||
|
||||
@ -110,17 +105,17 @@ public class PropertyAnimator implements Runnable {
|
||||
|
||||
// Fix the from value based on current position and property
|
||||
for (ElementHolder element : mElementsList) {
|
||||
if (element.property == Property.SLIDE_TOP)
|
||||
element.from = element.view.getScrollY();
|
||||
else if (element.property == Property.SLIDE_LEFT)
|
||||
element.from = element.view.getScrollX();
|
||||
else {
|
||||
ViewGroup.MarginLayoutParams params = ((ViewGroup.MarginLayoutParams) element.view.getLayoutParams());
|
||||
if (element.property == Property.SHRINK_TOP)
|
||||
element.from = params.topMargin;
|
||||
else if (element.property == Property.SHRINK_LEFT)
|
||||
element.from = params.leftMargin;
|
||||
}
|
||||
if (element.property == Property.TRANSLATION_Y)
|
||||
element.from = element.proxy.getTranslationY();
|
||||
else if (element.property == Property.TRANSLATION_X)
|
||||
element.from = element.proxy.getTranslationX();
|
||||
else if (element.property == Property.SCROLL_Y)
|
||||
element.from = element.proxy.getScrollY();
|
||||
else if (element.property == Property.SCROLL_X)
|
||||
element.from = element.proxy.getScrollX();
|
||||
|
||||
if (shouldEnableHardwareLayer(element))
|
||||
element.view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
|
||||
}
|
||||
|
||||
if (mDuration != 0) {
|
||||
@ -137,6 +132,8 @@ public class PropertyAnimator implements Runnable {
|
||||
// Make sure to snap to the end position.
|
||||
for (ElementHolder element : mElementsList) {
|
||||
invalidate(element, element.to);
|
||||
if (shouldEnableHardwareLayer(element))
|
||||
element.view.setLayerType(View.LAYER_TYPE_NONE, null);
|
||||
}
|
||||
|
||||
mElementsList.clear();
|
||||
@ -147,7 +144,23 @@ public class PropertyAnimator implements Runnable {
|
||||
}
|
||||
}
|
||||
|
||||
private void invalidate(final ElementHolder element, final int delta) {
|
||||
private boolean shouldEnableHardwareLayer(ElementHolder element) {
|
||||
if (!mUseHardwareLayer)
|
||||
return false;
|
||||
|
||||
if (Build.VERSION.SDK_INT < 11)
|
||||
return false;
|
||||
|
||||
if (!(element.view instanceof ViewGroup))
|
||||
return false;
|
||||
|
||||
if (element.property == Property.TRANSLATION_Y || element.property == Property.TRANSLATION_X)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void invalidate(final ElementHolder element, final float delta) {
|
||||
final View view = element.view;
|
||||
|
||||
// check to see if the view was detached between the check above and this code
|
||||
@ -155,22 +168,14 @@ public class PropertyAnimator implements Runnable {
|
||||
if (view.getHandler() == null)
|
||||
return;
|
||||
|
||||
if (element.property == Property.SLIDE_TOP) {
|
||||
view.scrollTo(view.getScrollX(), delta);
|
||||
return;
|
||||
} else if (element.property == Property.SLIDE_LEFT) {
|
||||
view.scrollTo(delta, view.getScrollY());
|
||||
return;
|
||||
}
|
||||
|
||||
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) view.getLayoutParams();
|
||||
|
||||
if (element.property == Property.SHRINK_TOP)
|
||||
params.setMargins(params.leftMargin, delta, params.rightMargin, params.bottomMargin);
|
||||
else if (element.property == Property.SHRINK_LEFT)
|
||||
params.setMargins(delta, params.topMargin, params.rightMargin, params.bottomMargin);
|
||||
|
||||
view.requestLayout();
|
||||
if (element.property == Property.TRANSLATION_Y)
|
||||
element.proxy.setTranslationY(delta);
|
||||
else if (element.property == Property.TRANSLATION_X)
|
||||
element.proxy.setTranslationX(delta);
|
||||
else if (element.property == Property.SCROLL_Y)
|
||||
element.proxy.scrollTo(element.proxy.getScrollX(), (int) delta);
|
||||
else if (element.property == Property.SCROLL_X)
|
||||
element.proxy.scrollTo((int) delta, element.proxy.getScrollY());
|
||||
}
|
||||
|
||||
private static abstract class FramePoster {
|
||||
|
@ -297,7 +297,7 @@ public class TabsTray extends LinearLayout
|
||||
|
||||
private void animateTo(final View view, int x, int duration) {
|
||||
PropertyAnimator pa = new PropertyAnimator(duration);
|
||||
pa.attach(view, Property.SLIDE_LEFT, x);
|
||||
pa.attach(view, Property.SCROLL_X, -x);
|
||||
if (x != 0 && !mWaitingForClose) {
|
||||
mWaitingForClose = true;
|
||||
|
||||
|
@ -63,7 +63,7 @@ public class LayerView extends FrameLayout {
|
||||
public static final int PAINT_BEFORE_FIRST = 0;
|
||||
public static final int PAINT_AFTER_FIRST = 1;
|
||||
|
||||
boolean shouldUseTextureView() {
|
||||
public boolean shouldUseTextureView() {
|
||||
// Disable TextureView support for now as it causes panning/zooming
|
||||
// performance regressions (see bug 792259). Uncomment the code below
|
||||
// once this bug is fixed.
|
||||
|
@ -10,8 +10,12 @@
|
||||
style="@style/BrowserToolbar">
|
||||
|
||||
<RelativeLayout android:id="@+id/address_bar"
|
||||
style="@style/AddressBar"
|
||||
android:background="@drawable/address_bar_bg">
|
||||
style="@style/AddressBar">
|
||||
|
||||
<ImageView android:id="@+id/address_bar_bg"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:background="@drawable/address_bar_bg"/>
|
||||
|
||||
<org.mozilla.gecko.TabsButton android:id="@+id/tabs"
|
||||
style="@style/AddressBar.ImageButton"
|
||||
@ -33,18 +37,17 @@
|
||||
android:layout_alignLeft="@id/tabs"
|
||||
android:gravity="center_horizontal"/>
|
||||
|
||||
<org.mozilla.gecko.MenuButton android:id="@+id/menu"
|
||||
style="@style/AddressBar.ImageButton"
|
||||
android:layout_width="56dip"
|
||||
android:layout_alignParentRight="true"
|
||||
gecko:curveTowards="none"
|
||||
android:gravity="center_vertical"
|
||||
android:src="@drawable/menu"
|
||||
android:contentDescription="@string/menu"
|
||||
android:background="@drawable/action_bar_button"
|
||||
android:paddingLeft="14dip"
|
||||
android:paddingRight="14dip"
|
||||
android:visibility="gone"/>
|
||||
<ImageButton android:id="@+id/menu"
|
||||
style="@style/AddressBar.ImageButton"
|
||||
android:layout_width="56dip"
|
||||
android:layout_alignParentRight="true"
|
||||
android:gravity="center_vertical"
|
||||
android:src="@drawable/menu"
|
||||
android:contentDescription="@string/menu"
|
||||
android:background="@drawable/action_bar_button"
|
||||
android:paddingLeft="14dip"
|
||||
android:paddingRight="14dip"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<LinearLayout android:id="@+id/menu_items"
|
||||
android:layout_width="wrap_content"
|
||||
@ -52,20 +55,52 @@
|
||||
android:orientation="horizontal"
|
||||
android:layout_toLeftOf="@id/menu"/>
|
||||
|
||||
<FrameLayout style="@style/AddressBar.Button"
|
||||
android:layout_toRightOf="@id/tabs"
|
||||
android:layout_toLeftOf="@id/menu_items"
|
||||
android:layout_marginLeft="-28dp"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_centerVertical="true">
|
||||
<RelativeLayout style="@style/AddressBar.Button"
|
||||
android:layout_toRightOf="@id/tabs"
|
||||
android:layout_toLeftOf="@id/menu_items"
|
||||
android:layout_marginLeft="-28dp"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_centerVertical="true">
|
||||
|
||||
<Button android:id="@+id/awesome_bar"
|
||||
style="@style/AddressBar.Button"
|
||||
android:layout_marginLeft="20dp"
|
||||
android:layout_marginTop="6dp"
|
||||
android:layout_marginBottom="6dp"
|
||||
android:layout_marginRight="0dp"
|
||||
android:background="@drawable/address_bar_url_level"/>
|
||||
<RelativeLayout android:id="@+id/awesome_bar"
|
||||
style="@style/AddressBar.Button"
|
||||
android:layout_centerVertical="true"
|
||||
android:clickable="true"
|
||||
android:focusable="true">
|
||||
|
||||
<ImageView style="@style/AddressBar.Button"
|
||||
android:layout_marginLeft="20dp"
|
||||
android:layout_marginRight="0dp"
|
||||
android:layout_marginTop="6dp"
|
||||
android:layout_marginBottom="6dp"
|
||||
android:duplicateParentState="true"
|
||||
android:clickable="false"
|
||||
android:focusable="false"
|
||||
android:background="@drawable/address_bar_url"/>
|
||||
|
||||
<FrameLayout android:id="@+id/awesome_bar_right_edge"
|
||||
style="@style/AddressBar.ImageButton"
|
||||
android:layout_width="25dp"
|
||||
android:layout_height="fill_parent"
|
||||
android:paddingTop="6dp"
|
||||
android:paddingBottom="6dp"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_alignParentRight="true"
|
||||
android:duplicateParentState="true"
|
||||
android:background="@drawable/address_bar_bg">
|
||||
|
||||
<ImageView android:layout_width="50dp"
|
||||
android:layout_height="fill_parent"
|
||||
android:scaleType="fitXY"
|
||||
android:layout_marginLeft="-26dp"
|
||||
android:duplicateParentState="true"
|
||||
android:clickable="false"
|
||||
android:focusable="false"
|
||||
android:src="@drawable/address_bar_url"/>
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<ImageButton android:id="@+id/forward"
|
||||
style="@style/AddressBar.ImageButton"
|
||||
@ -73,7 +108,7 @@
|
||||
android:layout_height="40dip"
|
||||
android:layout_marginLeft="22dp"
|
||||
android:paddingLeft="22dp"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_centerVertical="true"
|
||||
android:src="@drawable/ic_menu_forward"
|
||||
android:contentDescription="@string/forward"
|
||||
android:background="@drawable/address_bar_forward_button"/>
|
||||
@ -82,7 +117,7 @@
|
||||
style="@style/AddressBar.ImageButton"
|
||||
android:layout_width="50dip"
|
||||
android:layout_height="50dip"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:layout_centerVertical="true"
|
||||
android:src="@drawable/ic_menu_back"
|
||||
android:contentDescription="@string/back"
|
||||
android:background="@drawable/address_bar_back_button"/>
|
||||
@ -139,7 +174,7 @@
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</FrameLayout>
|
||||
</RelativeLayout>
|
||||
|
||||
<ImageView android:id="@+id/shadow"
|
||||
android:layout_width="fill_parent"
|
||||
|
Loading…
Reference in New Issue
Block a user