зеркало из https://github.com/mozilla/pjs.git
Bug 763049: Tablet animation should slide on phones, slide and shrink on tablets. [r=mfinkle]
This commit is contained in:
Родитель
f3e8977860
Коммит
d489fabf91
|
@ -61,12 +61,16 @@ import android.content.pm.*;
|
|||
import android.content.pm.PackageManager.*;
|
||||
import dalvik.system.*;
|
||||
|
||||
abstract public class BrowserApp extends GeckoApp {
|
||||
abstract public class BrowserApp extends GeckoApp
|
||||
implements TabsPanel.TabsLayoutChangeListener,
|
||||
PropertyAnimator.PropertyAnimationListener {
|
||||
private static final String LOGTAG = "GeckoBrowserApp";
|
||||
|
||||
public static BrowserToolbar mBrowserToolbar;
|
||||
private AboutHomeContent mAboutHomeContent;
|
||||
|
||||
private PropertyAnimator mMainLayoutAnimator;
|
||||
|
||||
@Override
|
||||
public void onTabChanged(Tab tab, Tabs.TabEvents msg, Object data) {
|
||||
switch(msg) {
|
||||
|
@ -198,6 +202,9 @@ abstract public class BrowserApp extends GeckoApp {
|
|||
mBrowserToolbar = new BrowserToolbar(mAppContext);
|
||||
mBrowserToolbar.from(actionBar);
|
||||
|
||||
if (mTabsPanel != null)
|
||||
mTabsPanel.setTabsLayoutChangeListener(this);
|
||||
|
||||
if (savedInstanceState != null) {
|
||||
mBrowserToolbar.setTitle(savedInstanceState.getString(SAVED_STATE_TITLE));
|
||||
}
|
||||
|
@ -322,6 +329,57 @@ abstract public class BrowserApp extends GeckoApp {
|
|||
return mTabsPanel.isShown();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTabsLayoutChange(int width, int height) {
|
||||
if (mMainLayoutAnimator != null)
|
||||
mMainLayoutAnimator.stop();
|
||||
|
||||
mMainLayoutAnimator = new PropertyAnimator(150);
|
||||
mMainLayoutAnimator.setPropertyAnimationListener(this);
|
||||
|
||||
if (isTablet()) {
|
||||
mMainLayoutAnimator.attach(mBrowserToolbar.getLayout(),
|
||||
PropertyAnimator.Property.SHRINK_LEFT,
|
||||
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);
|
||||
mGeckoLayout.requestLayout();
|
||||
}
|
||||
|
||||
mMainLayoutAnimator.attach(mGeckoLayout,
|
||||
PropertyAnimator.Property.SLIDE_LEFT,
|
||||
width);
|
||||
|
||||
} else {
|
||||
mMainLayoutAnimator.attach(mMainLayout,
|
||||
PropertyAnimator.Property.SLIDE_TOP,
|
||||
height);
|
||||
}
|
||||
|
||||
mMainLayoutAnimator.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPropertyAnimationStart() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPropertyAnimationEnd() {
|
||||
mMainHandler.post(new Runnable() {
|
||||
public void run() {
|
||||
if (isTablet() && 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();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/* Doorhanger notification methods */
|
||||
@Override
|
||||
void updatePopups(final Tab tab) {
|
||||
|
|
|
@ -264,6 +264,10 @@ public class BrowserToolbar implements ViewSwitcher.ViewFactory,
|
|||
}
|
||||
}
|
||||
|
||||
public View getLayout() {
|
||||
return mLayout;
|
||||
}
|
||||
|
||||
public void requestLayout() {
|
||||
mLayout.invalidate();
|
||||
}
|
||||
|
|
|
@ -65,8 +65,7 @@ abstract public class GeckoApp
|
|||
extends GeckoActivity
|
||||
implements GeckoEventListener, SensorEventListener, LocationListener,
|
||||
GeckoApplication.ApplicationLifecycleCallbacks,
|
||||
Tabs.OnTabsChangedListener,
|
||||
TabsPanel.TabsLayoutChangeListener
|
||||
Tabs.OnTabsChangedListener
|
||||
{
|
||||
private static final String LOGTAG = "GeckoApp";
|
||||
|
||||
|
@ -87,8 +86,8 @@ abstract public class GeckoApp
|
|||
public static final String SAVED_STATE_TITLE = "title";
|
||||
|
||||
StartupMode mStartupMode = null;
|
||||
private LinearLayout mMainLayout;
|
||||
private RelativeLayout mGeckoLayout;
|
||||
protected LinearLayout mMainLayout;
|
||||
protected RelativeLayout mGeckoLayout;
|
||||
public View getView() { return mGeckoLayout; }
|
||||
public static SurfaceView cameraView;
|
||||
public static GeckoApp mAppContext;
|
||||
|
@ -114,8 +113,6 @@ abstract public class GeckoApp
|
|||
private static AbsoluteLayout mPluginContainer;
|
||||
private static FindInPageBar mFindInPageBar;
|
||||
|
||||
private PropertyAnimator mMainLayoutAnimator;
|
||||
|
||||
private FullScreenHolder mFullScreenPluginContainer;
|
||||
private View mFullScreenPluginView;
|
||||
|
||||
|
@ -923,28 +920,6 @@ abstract public class GeckoApp
|
|||
|
||||
public boolean areTabsShown() { return false; }
|
||||
|
||||
@Override
|
||||
public void onTabsLayoutChange(int width, int height) {
|
||||
if (mMainLayoutAnimator != null)
|
||||
mMainLayoutAnimator.stop();
|
||||
|
||||
RelativeLayout.LayoutParams params = (RelativeLayout.LayoutParams) mMainLayout.getLayoutParams();
|
||||
|
||||
if (isTablet())
|
||||
mMainLayoutAnimator = new PropertyAnimator(mMainLayout,
|
||||
PropertyAnimator.Property.MARGIN_LEFT,
|
||||
params.leftMargin,
|
||||
width,
|
||||
200);
|
||||
else
|
||||
mMainLayoutAnimator = new PropertyAnimator(mMainLayout,
|
||||
PropertyAnimator.Property.MARGIN_TOP,
|
||||
params.topMargin,
|
||||
height,
|
||||
200);
|
||||
mMainLayoutAnimator.start();
|
||||
}
|
||||
|
||||
public void handleMessage(String event, JSONObject message) {
|
||||
Log.i(LOGTAG, "Got message: " + event);
|
||||
try {
|
||||
|
@ -1704,8 +1679,6 @@ abstract public class GeckoApp
|
|||
|
||||
// setup tabs panel
|
||||
mTabsPanel = (TabsPanel) findViewById(R.id.tabs_panel);
|
||||
if (mTabsPanel != null)
|
||||
mTabsPanel.setTabsLayoutChangeListener(this);
|
||||
|
||||
if (savedInstanceState != null) {
|
||||
mRestoreMode = GeckoAppShell.RESTORE_OOM;
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
|
||||
package org.mozilla.gecko;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
|
@ -12,64 +14,105 @@ import android.os.Handler;
|
|||
import android.view.animation.Interpolator;
|
||||
import android.view.animation.DecelerateInterpolator;
|
||||
import android.view.View;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
public class PropertyAnimator extends TimerTask {
|
||||
private static final String LOGTAG = "GeckoPropertyAnimator";
|
||||
|
||||
private Timer mTimer;
|
||||
private TimerTask mShowTask;
|
||||
private Interpolator mInterpolator;
|
||||
|
||||
public static enum Property {
|
||||
MARGIN_LEFT,
|
||||
MARGIN_RIGHT,
|
||||
MARGIN_TOP,
|
||||
MARGIN_BOTTOM
|
||||
SHRINK_LEFT,
|
||||
SHRINK_TOP,
|
||||
SLIDE_TOP,
|
||||
SLIDE_LEFT
|
||||
}
|
||||
|
||||
private View mView;
|
||||
private Property mProperty;
|
||||
private int mDuration;
|
||||
private int mFrom;
|
||||
private int mTo;
|
||||
private class ElementHolder {
|
||||
View view;
|
||||
Property property;
|
||||
int from;
|
||||
int to;
|
||||
}
|
||||
|
||||
public static interface PropertyAnimationListener {
|
||||
public void onPropertyAnimationStart();
|
||||
public void onPropertyAnimationEnd();
|
||||
}
|
||||
|
||||
private int mCount;
|
||||
private int mDuration;
|
||||
private List<ElementHolder> mElementsList;
|
||||
private PropertyAnimationListener mListener;
|
||||
|
||||
// Default refresh rate in ms.
|
||||
private static final int sInterval = 10;
|
||||
private static final int INTERVAL = 10;
|
||||
|
||||
public PropertyAnimator(View view, Property property, int from, int to, int duration) {
|
||||
mView = view;
|
||||
mProperty = property;
|
||||
public PropertyAnimator(int duration) {
|
||||
mDuration = duration;
|
||||
mFrom = from;
|
||||
mTo = to;
|
||||
|
||||
mTimer = new Timer();
|
||||
mInterpolator = new DecelerateInterpolator();
|
||||
mElementsList = new ArrayList<ElementHolder>();
|
||||
}
|
||||
|
||||
public void attach(View view, Property property, int to) {
|
||||
ElementHolder element = new ElementHolder();
|
||||
|
||||
element.view = 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;
|
||||
|
||||
mElementsList.add(element);
|
||||
}
|
||||
|
||||
public void setPropertyAnimationListener(PropertyAnimationListener listener) {
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
float interpolation = mInterpolator.getInterpolation((float) (mCount * sInterval) / (float) mDuration);
|
||||
int delta;
|
||||
if (mFrom < mTo)
|
||||
delta = mFrom + (int) ((mTo - mFrom) * interpolation);
|
||||
else
|
||||
delta = mFrom - (int) ((mFrom - mTo) * interpolation);
|
||||
float interpolation = mInterpolator.getInterpolation((float) (mCount * INTERVAL) / (float) mDuration);
|
||||
|
||||
invalidate(delta);
|
||||
for (ElementHolder element : mElementsList) {
|
||||
int delta = element.from + (int) ((element.to - element.from) * interpolation);
|
||||
invalidate(element, delta);
|
||||
}
|
||||
|
||||
mCount++;
|
||||
|
||||
if (mCount * sInterval >= mDuration)
|
||||
if (mCount * INTERVAL >= mDuration)
|
||||
stop();
|
||||
}
|
||||
|
||||
public void start() {
|
||||
mCount = 0;
|
||||
mTimer.scheduleAtFixedRate(this, 0, sInterval);
|
||||
|
||||
// Fix the from value based on current position and property
|
||||
for (ElementHolder element : mElementsList) {
|
||||
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;
|
||||
else if (element.property == Property.SLIDE_TOP)
|
||||
element.from = element.view.getScrollY();
|
||||
else if (element.property == Property.SLIDE_LEFT)
|
||||
element.from = element.view.getScrollX();
|
||||
}
|
||||
|
||||
if (mDuration != 0) {
|
||||
mTimer.scheduleAtFixedRate(this, 0, INTERVAL);
|
||||
|
||||
if (mListener != null)
|
||||
mListener.onPropertyAnimationStart();
|
||||
}
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
|
@ -78,35 +121,35 @@ public class PropertyAnimator extends TimerTask {
|
|||
mTimer.purge();
|
||||
|
||||
// Make sure to snap to the end position.
|
||||
invalidate(mTo);
|
||||
for (ElementHolder element : mElementsList) {
|
||||
invalidate(element, element.to);
|
||||
}
|
||||
|
||||
mElementsList.clear();
|
||||
|
||||
if (mListener != null) {
|
||||
mListener.onPropertyAnimationEnd();
|
||||
mListener = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void invalidate(final int delta) {
|
||||
private void invalidate(final ElementHolder element, final int delta) {
|
||||
// Post the layout changes on the view's UI thread.
|
||||
mView.getHandler().post(new Runnable() {
|
||||
element.view.getHandler().post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(mView.getLayoutParams());
|
||||
switch(mProperty) {
|
||||
case MARGIN_TOP:
|
||||
params.setMargins(0, delta, 0, 0);
|
||||
break;
|
||||
|
||||
case MARGIN_BOTTOM:
|
||||
params.setMargins(0, 0, 0, delta);
|
||||
break;
|
||||
|
||||
case MARGIN_LEFT:
|
||||
params.setMargins(delta, 0, 0, 0);
|
||||
break;
|
||||
|
||||
case MARGIN_RIGHT:
|
||||
params.setMargins(0, 0, delta, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
mView.setLayoutParams(params);
|
||||
mView.requestLayout();
|
||||
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) element.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);
|
||||
else if (element.property == Property.SLIDE_TOP)
|
||||
element.view.scrollTo(element.view.getScrollX(), delta);
|
||||
else if (element.property == Property.SLIDE_LEFT)
|
||||
element.view.scrollTo(delta, element.view.getScrollY());
|
||||
|
||||
element.view.requestLayout();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -157,8 +157,10 @@ public class TabsPanel extends LinearLayout {
|
|||
}
|
||||
|
||||
public void hide() {
|
||||
mVisible = false;
|
||||
dispatchLayoutChange(0, 0);
|
||||
if (mVisible) {
|
||||
mVisible = false;
|
||||
dispatchLayoutChange(0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public void refresh() {
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
android:background="@drawable/tabs_tray_bg_repeat"/>
|
||||
|
||||
<LinearLayout android:id="@+id/main_layout"
|
||||
style="@style/Screen">
|
||||
style="@style/Screen.Transparent">
|
||||
|
||||
<include layout="@layout/browser_toolbar"/>
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
android:background="@drawable/tabs_tray_bg_repeat"/>
|
||||
|
||||
<LinearLayout android:id="@+id/main_layout"
|
||||
style="@style/Screen">
|
||||
style="@style/Screen.Transparent">
|
||||
|
||||
<include layout="@layout/browser_toolbar"/>
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
android:background="@drawable/tabs_tray_bg_repeat"/>
|
||||
|
||||
<LinearLayout android:id="@+id/main_layout"
|
||||
style="@style/Screen">
|
||||
style="@style/Screen.Transparent">
|
||||
|
||||
<include layout="@layout/browser_toolbar"/>
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче