Bug 763049: Tablet animation should slide on phones, slide and shrink on tablets. [r=mfinkle]

This commit is contained in:
Sriram Ramasubramanian 2012-06-12 22:47:52 -07:00
Родитель f3e8977860
Коммит d489fabf91
8 изменённых файлов: 167 добавлений и 87 удалений

Просмотреть файл

@ -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"/>