Merge "Simplify panel animations with an eye to performance." into honeycomb

This commit is contained in:
Daniel Sandler
2011-01-11 11:51:59 -08:00
committed by Android (Google) Code Review
7 changed files with 131 additions and 210 deletions

View File

@@ -12,6 +12,7 @@
<application
android:persistent="true"
android:allowClearUserData="false"
android:hardwareAccelerated="true"
android:label="@string/app_label"
android:icon="@drawable/ic_launcher_settings">

Binary file not shown.

Before

Width:  |  Height:  |  Size: 152 B

After

Width:  |  Height:  |  Size: 243 B

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2011 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<bitmap
xmlns:android="http://schemas.android.com/apk/res/android"
android:src="@drawable/panel_notification"
android:tileMode="repeat"
/>

View File

@@ -20,27 +20,35 @@
xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
android:layout_height="match_parent"
android:layout_width="match_parent"
android:orientation="vertical"
android:gravity="right"
android:paddingTop="32dp"
>
<LinearLayout
<View
android:id="@+id/scrim"
android:background="@drawable/notify_panel_bg_protect"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
/>
<RelativeLayout
android:id="@+id/content_parent"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:animateLayoutChanges="true"
android:orientation="vertical"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
>
<com.android.systemui.statusbar.tablet.NotificationTitleArea
<RelativeLayout
android:id="@+id/title_area"
android:layout_height="160dp"
android:layout_width="384dp"
android:layout_marginLeft="24dp"
android:paddingTop="20dp"
android:orientation="vertical"
android:animateLayoutChanges="true"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
android:background="@drawable/panel_notification_tiled"
>
<com.android.systemui.statusbar.tablet.HoloClock
@@ -154,13 +162,15 @@
android:src="@drawable/status_bar_veto"
android:baseline="21dp"
/>
</com.android.systemui.statusbar.tablet.NotificationTitleArea>
</RelativeLayout>
<LinearLayout
android:id="@+id/content_frame"
android:layout_height="wrap_content"
android:layout_width="408dp"
android:orientation="vertical"
android:layout_below="@id/title_area"
android:layout_alignParentRight="true"
>
<ScrollView
android:id="@+id/notification_scroller"
@@ -191,5 +201,17 @@
android:src="@drawable/notify_item_glow_bottom"
/>
</LinearLayout>
</LinearLayout>
</RelativeLayout>
<View
android:id="@+id/glow"
android:background="@drawable/notify_glow_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignTop="@id/content_parent"
android:layout_alignLeft="@id/content_parent"
android:layout_marginLeft="100dip"
android:layout_marginTop="-100dip"
/>
</com.android.systemui.statusbar.tablet.NotificationPanel>

View File

@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.tablet;
import android.animation.Animator;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
@@ -33,11 +34,13 @@ import android.view.animation.AccelerateInterpolator;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.FrameLayout;
import android.widget.TextView;
import com.android.systemui.R;
public class NotificationPanel extends LinearLayout implements StatusBarPanel,
public class NotificationPanel extends RelativeLayout implements StatusBarPanel,
View.OnClickListener {
static final String TAG = "Tablet/NotificationPanel";
static final boolean DEBUG = false;
@@ -51,12 +54,11 @@ public class NotificationPanel extends LinearLayout implements StatusBarPanel,
ViewGroup mContentFrame;
Rect mContentArea;
View mSettingsView;
View mScrim, mGlow;
ViewGroup mContentParent;
Choreographer mChoreo = new Choreographer();
int mStatusBarHeight;
Drawable mBgDrawable;
Drawable mGlowDrawable;
public NotificationPanel(Context context, AttributeSet attrs) {
this(context, attrs, 0);
@@ -69,8 +71,6 @@ public class NotificationPanel extends LinearLayout implements StatusBarPanel,
mStatusBarHeight = res.getDimensionPixelSize(
com.android.internal.R.dimen.status_bar_height);
mBgDrawable = res.getDrawable(R.drawable.notify_panel_bg_protect);
mGlowDrawable = res.getDrawable(R.drawable.notify_glow_back);
}
@Override
@@ -80,9 +80,13 @@ public class NotificationPanel extends LinearLayout implements StatusBarPanel,
setWillNotDraw(false);
mContentParent = (ViewGroup)findViewById(R.id.content_parent);
mContentParent.bringToFront();
mTitleArea = findViewById(R.id.title_area);
mTitleArea.setOnClickListener(this);
mScrim = findViewById(R.id.scrim);
mGlow = findViewById(R.id.glow);
mSettingsButton = (ImageView)findViewById(R.id.settings_button);
mNotificationButton = (ImageView)findViewById(R.id.notification_button);
@@ -132,21 +136,6 @@ public class NotificationPanel extends LinearLayout implements StatusBarPanel,
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
// We know that none of our children are GONE, so don't worry about skipping GONE views.
final int N = getChildCount();
if (N == 0) {
return;
}
final int allocatedBottom = getChildAt(N-1).getBottom();
final int shift = b - allocatedBottom - getPaddingBottom();
if (shift <= 0) {
return;
}
for (int i=0; i<N; i++) {
final View c = getChildAt(i);
c.layout(c.getLeft(), c.getTop() + shift, c.getRight(), c.getBottom() + shift);
}
mChoreo.setPanelHeight(mContentParent.getHeight());
}
@@ -154,26 +143,6 @@ public class NotificationPanel extends LinearLayout implements StatusBarPanel,
public void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
mContentArea = null;
mBgDrawable.setBounds(0, 0, w, h-mStatusBarHeight);
}
@Override
public void onDraw(Canvas canvas) {
int saveCount;
final int w = getWidth();
final int h = getHeight();
super.onDraw(canvas);
// Background protection
mBgDrawable.draw(canvas);
// The panel glow (behind status bar)
saveCount = canvas.save();
canvas.clipRect(0, 0, w, h-mStatusBarHeight);
mGlowDrawable.draw(canvas);
canvas.restoreToCount(saveCount);
}
public void onClick(View v) {
@@ -227,82 +196,82 @@ public class NotificationPanel extends LinearLayout implements StatusBarPanel,
private class Choreographer implements Animator.AnimatorListener {
boolean mVisible;
int mBgAlpha;
ValueAnimator mBgAnim;
int mPanelHeight;
int mPanelBottom;
ValueAnimator mPositionAnim;
AnimatorSet mContentAnim;
// should group this into a multi-property animation
final int OPEN_DURATION = 200;
final int OPEN_DURATION = 250;
// the panel will start to appear this many px from the end
final int HYPERSPACE_OFFRAMP = 120;
Choreographer() {
}
void createAnimation(boolean visible) {
mBgAnim = ObjectAnimator.ofInt(this, "bgAlpha", mBgAlpha, visible ? 255 : 0)
.setDuration(OPEN_DURATION);
mBgAnim.addListener(this);
void createAnimation(boolean appearing) {
Animator bgAnim = ObjectAnimator.ofFloat(mScrim,
"alpha", mScrim.getAlpha(), appearing ? 1 : 0);
mPositionAnim = ObjectAnimator.ofInt(this, "panelBottom", mPanelBottom,
visible ? mPanelHeight : 0)
.setDuration(OPEN_DURATION);
}
float start, end;
void startAnimation(boolean visible) {
if (DEBUG) Slog.d(TAG, "startAnimation(visible=" + visible + ")");
createAnimation(visible);
mBgAnim.start();
mPositionAnim.start();
mVisible = visible;
}
void jumpTo(boolean visible) {
setBgAlpha(visible ? 255 : 0);
setPanelBottom(visible ? mPanelHeight : 0);
}
public void setBgAlpha(int alpha) {
mBgAlpha = alpha;
mBgDrawable.setAlpha((int)(alpha));
invalidate();
}
// 0 is closed, the height of the panel is open
public void setPanelBottom(int y) {
mPanelBottom = y;
int translationY = mPanelHeight - y;
mContentParent.setTranslationY(translationY);
final int glowXOffset = 100;
final int glowYOffset = 100;
int glowX = mContentParent.getLeft() - glowXOffset;
int glowY = mContentParent.getTop() - glowYOffset + translationY;
mGlowDrawable.setBounds(glowX, glowY, glowX + mGlowDrawable.getIntrinsicWidth(),
glowY + mGlowDrawable.getIntrinsicHeight());
float alpha;
if (mPanelBottom > glowYOffset) {
alpha = 1;
// 0: on-screen
// height: off-screen
float y = mContentParent.getTranslationY();
if (appearing) {
// we want to go from near-the-top to the top, unless we're half-open in the right
// general vicinity
start = (y < HYPERSPACE_OFFRAMP)
? y
: HYPERSPACE_OFFRAMP;
end = 0;
} else {
alpha = ((float)mPanelBottom) / glowYOffset;
start = y;
end = y + HYPERSPACE_OFFRAMP;
}
mContentParent.setAlpha(alpha);
mGlowDrawable.setAlpha((int)(255 * alpha));
Animator posAnim = ObjectAnimator.ofFloat(mContentParent, "translationY", start, end);
posAnim.setInterpolator(appearing
? new android.view.animation.DecelerateInterpolator(2.0f)
: new android.view.animation.AccelerateInterpolator(2.0f));
if (false) {
Slog.d(TAG, "mPanelBottom=" + mPanelBottom + " translationY=" + translationY
+ " alpha=" + alpha + " glowY=" + glowY);
}
Animator glowAnim = ObjectAnimator.ofFloat(mGlow, "alpha",
mGlow.getAlpha(), appearing ? 1.0f : 0.0f);
glowAnim.setInterpolator(appearing
? new android.view.animation.AccelerateInterpolator(1.0f)
: new android.view.animation.DecelerateInterpolator(1.0f));
mContentAnim = new AnimatorSet();
mContentAnim
.play(ObjectAnimator.ofFloat(mContentParent, "alpha", mContentParent.getAlpha(),
appearing ? 1.0f : 0.0f))
.with(glowAnim)
.with(bgAnim)
.with(posAnim)
;
mContentAnim.setDuration(OPEN_DURATION);
mContentAnim.addListener(this);
}
void startAnimation(boolean appearing) {
if (DEBUG) Slog.d(TAG, "startAnimation(appearing=" + appearing + ")");
createAnimation(appearing);
mContentParent.setLayerType(View.LAYER_TYPE_HARDWARE, null);
mContentAnim.start();
mVisible = appearing;
}
void jumpTo(boolean appearing) {
// setBgAlpha(appearing ? 255 : 0);
mContentParent.setTranslationY(appearing ? 0 : mPanelHeight);
}
public void setPanelHeight(int h) {
if (DEBUG) Slog.d(TAG, "panelHeight=" + h);
mPanelHeight = h;
if (mPanelBottom == 0) {
if (mPanelHeight == 0) {
// fully closed, no animation necessary
setPanelBottom(0);
} else if (mVisible) {
if (DEBUG) {
Slog.d(TAG, "panelHeight not zero but trying to open; scheduling an anim to open fully");
@@ -312,17 +281,18 @@ public class NotificationPanel extends LinearLayout implements StatusBarPanel,
}
public void onAnimationCancel(Animator animation) {
if (DEBUG) Slog.d(TAG, "onAnimationCancel mBgAlpha=" + mBgAlpha);
if (DEBUG) Slog.d(TAG, "onAnimationCancel");
// force this to zero so we close the window
mBgAlpha = 0;
mVisible = false;
}
public void onAnimationEnd(Animator animation) {
if (DEBUG) Slog.d(TAG, "onAnimationEnd mBgAlpha=" + mBgAlpha);
if (mBgAlpha == 0) {
if (DEBUG) Slog.d(TAG, "onAnimationEnd");
if (! mVisible) {
setVisibility(View.GONE);
}
mBgAnim = null;
mContentParent.setLayerType(View.LAYER_TYPE_NONE, null);
mContentAnim = null;
}
public void onAnimationRepeat(Animator animation) {

View File

@@ -1,95 +0,0 @@
/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.statusbar.tablet;
import android.content.Context;
import android.graphics.BitmapFactory;
import android.graphics.Bitmap;
import android.graphics.Paint;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.util.Slog;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.view.View;
import android.widget.FrameLayout;
import com.android.systemui.R;
public class NotificationTitleArea extends RelativeLayout {
static final String TAG = "NotificationTitleArea";
View mSettingsButton;
View mNotificationButton;
View mNotificationScroller;
FrameLayout mSettingsFrame;
View mSettingsPanel;
// for drawing the background
Bitmap mTexture;
Paint mPaint;
int mTextureWidth;
int mTextureHeight;
public NotificationTitleArea(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public NotificationTitleArea(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// for drawing the background
mTexture = BitmapFactory.decodeResource(getResources(), R.drawable.panel_notification);
mTextureWidth = mTexture.getWidth();
mTextureHeight = mTexture.getHeight();
mPaint = new Paint();
mPaint.setDither(false);
}
public void onFinishInflate() {
super.onFinishInflate();
setWillNotDraw(false);
}
@Override
public void onDraw(Canvas canvas) {
final Bitmap texture = mTexture;
final Paint paint = mPaint;
final int width = getWidth();
final int height = getHeight();
final int textureWidth = mTextureWidth;
final int textureHeight = mTextureHeight;
int x = 0;
int y;
while (x < width) {
y = 0;
while (y < height) {
canvas.drawBitmap(texture, x, y, paint);
y += textureHeight;
}
x += textureWidth;
}
}
}

View File

@@ -183,7 +183,7 @@ public class TabletStatusBar extends StatusBar {
mStatusBarView.setIgnoreChildren(0, mNotificationTrigger, mNotificationPanel);
WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
720, // ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL,
WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN
@@ -196,6 +196,7 @@ public class TabletStatusBar extends StatusBar {
lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED
| WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
lp.windowAnimations = com.android.internal.R.style.Animation; // == no animation
// lp.windowAnimations = com.android.internal.R.style.Animation_ZoomButtons; // simple fade
WindowManagerImpl.getDefault().addView(mNotificationPanel, lp);