diff options
author | Joe Onorato <joeo@google.com> | 2010-12-14 01:22:23 -0800 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2010-12-14 01:22:23 -0800 |
commit | 4738da2e30272ceeec7e065be3ce4b2838a22d07 (patch) | |
tree | 3f517f14411baa9ca3e3274d49d123c19f05424e /packages/SystemUI/src/com/android/systemui/statusbar | |
parent | f2e69a911aa4d8ebaa3ffb6bc025a5ea5fea4bac (diff) | |
parent | 7c270fab75c2f4529e45ea80b31d4017ab516482 (diff) | |
download | frameworks_base-4738da2e30272ceeec7e065be3ce4b2838a22d07.zip frameworks_base-4738da2e30272ceeec7e065be3ce4b2838a22d07.tar.gz frameworks_base-4738da2e30272ceeec7e065be3ce4b2838a22d07.tar.bz2 |
Merge "notification panel animations"
Diffstat (limited to 'packages/SystemUI/src/com/android/systemui/statusbar')
3 files changed, 293 insertions, 19 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationLinearLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationLinearLayout.java new file mode 100644 index 0000000..9ecb2e4 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationLinearLayout.java @@ -0,0 +1,92 @@ +/* + * 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.animation.Animator; +import android.animation.ObjectAnimator; +import android.animation.ValueAnimator; +import android.content.Context; +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.graphics.Canvas; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.util.AttributeSet; +import android.util.Slog; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.AccelerateInterpolator; +import android.widget.FrameLayout; +import android.widget.ImageView; +import android.widget.LinearLayout; +import android.widget.TextView; + +import com.android.systemui.R; + +public class NotificationLinearLayout extends LinearLayout { + private static final String TAG = "NotificationLinearLayout"; + + Drawable mItemGlow; + int mInsetLeft; + Rect mTmp = new Rect(); + + public NotificationLinearLayout(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public NotificationLinearLayout(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + + final Resources res = context.getResources(); + + mItemGlow = res.getDrawable(R.drawable.notify_item_glow_bottom); + + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.NotificationLinearLayout, + defStyle, 0); + mInsetLeft = a.getDimensionPixelSize(R.styleable.NotificationLinearLayout_insetLeft, 0); + a.recycle(); + } + + @Override + public void onFinishInflate() { + super.onFinishInflate(); + setWillNotDraw(false); + } + + @Override + public void onDraw(Canvas canvas) { + super.onDraw(canvas); + + final Rect padding = mTmp; + final Drawable glow = mItemGlow; + glow.getPadding(padding); + final int glowHeight = glow.getIntrinsicHeight(); + final int insetLeft = mInsetLeft; + + final int N = getChildCount(); + for (int i=0; i<N; i++) { + final View child = getChildAt(i); + + final int childBottom = child.getBottom(); + + glow.setBounds(child.getLeft() - padding.left + insetLeft, childBottom, + child.getRight() - padding.right, childBottom + glowHeight); + glow.draw(canvas); + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java index baf4a0f..82c1d17 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/NotificationPanel.java @@ -16,11 +16,20 @@ package com.android.systemui.statusbar.tablet; +import android.animation.Animator; +import android.animation.ObjectAnimator; +import android.animation.ValueAnimator; import android.content.Context; +import android.content.res.Resources; +import android.graphics.Canvas; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; import android.util.AttributeSet; import android.util.Slog; import android.view.LayoutInflater; import android.view.View; +import android.view.ViewGroup; +import android.view.animation.AccelerateInterpolator; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.LinearLayout; @@ -32,12 +41,20 @@ public class NotificationPanel extends LinearLayout implements StatusBarPanel, View.OnClickListener { static final String TAG = "NotificationPanel"; + boolean mShowing; View mTitleArea; View mSettingsButton; View mNotificationButton; View mNotificationScroller; - FrameLayout mContentFrame; + ViewGroup mContentFrame; + Rect mContentArea; View mSettingsView; + ViewGroup mContentParent; + + Choreographer mChoreo = new Choreographer(); + int mStatusBarHeight; + Drawable mBgDrawable; + Drawable mGlowDrawable; public NotificationPanel(Context context, AttributeSet attrs) { this(context, attrs, 0); @@ -45,12 +62,22 @@ public class NotificationPanel extends LinearLayout implements StatusBarPanel, public NotificationPanel(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); + + final Resources res = context.getResources(); + + 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 public void onFinishInflate() { super.onFinishInflate(); + setWillNotDraw(false); + + mContentParent = (ViewGroup)findViewById(R.id.content_parent); mTitleArea = findViewById(R.id.title_area); mSettingsButton = (ImageView)findViewById(R.id.settings_button); @@ -59,7 +86,31 @@ public class NotificationPanel extends LinearLayout implements StatusBarPanel, mNotificationButton.setOnClickListener(this); mNotificationScroller = findViewById(R.id.notificationScroller); - mContentFrame = (FrameLayout)findViewById(R.id.content_frame); + mContentFrame = (ViewGroup)findViewById(R.id.content_frame); + } + + public void show(boolean show, boolean animate) { + if (animate) { + if (mShowing != show) { + mShowing = show; + if (show) { + setVisibility(View.VISIBLE); + } + mChoreo.startAnimation(show); + } + } else { + mShowing = show; + setVisibility(show ? View.VISIBLE : View.GONE); + mChoreo.jumpTo(show); + } + } + + /** + * Whether the panel is showing, or, if it's animating, whether it will be + * when the animation is done. + */ + public boolean isShowing() { + return mShowing; } @Override @@ -93,6 +144,34 @@ public class NotificationPanel extends LinearLayout implements StatusBarPanel, final View c = getChildAt(i); c.layout(c.getLeft(), c.getTop() + shift, c.getRight(), c.getBottom() + shift); } + + mChoreo.setPanelHeight(mContentParent.getHeight()); + } + + @Override + 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) { @@ -119,11 +198,14 @@ public class NotificationPanel extends LinearLayout implements StatusBarPanel, } public boolean isInContentArea(int x, int y) { - final int l = mContentFrame.getLeft(); - final int r = mContentFrame.getRight(); - final int t = mTitleArea.getTop(); - final int b = mContentFrame.getBottom(); - return x >= l && x < r && y >= t && y < b; + if (mContentArea == null) { + mContentArea = new Rect(mContentFrame.getLeft(), + mTitleArea.getTop(), + mContentFrame.getRight(), + mContentFrame.getBottom()); + offsetDescendantRectToMyCoords(mContentParent, mContentArea); + } + return mContentArea.contains(x, y); } void removeSettingsView() { @@ -138,5 +220,102 @@ public class NotificationPanel extends LinearLayout implements StatusBarPanel, mSettingsView = infl.inflate(R.layout.status_bar_settings_view, mContentFrame, false); mContentFrame.addView(mSettingsView); } + + private class Choreographer implements Animator.AnimatorListener { + int mBgAlpha; + ValueAnimator mBgAnim; + int mPanelHeight; + int mPanelBottom; + ValueAnimator mPositionAnim; + + // should group this into a multi-property animation + final int OPEN_DURATION = 200; + + Choreographer() { + } + + void createAnimation(boolean visible) { + mBgAnim = ObjectAnimator.ofInt(this, "bgAlpha", mBgAlpha, visible ? 255 : 0) + .setDuration(OPEN_DURATION); + mBgAnim.addListener(this); + + mPositionAnim = ObjectAnimator.ofInt(this, "panelBottom", mPanelBottom, + visible ? mPanelHeight : 0) + .setDuration(OPEN_DURATION); + } + + void startAnimation(boolean visible) { + if (mBgAnim == null) { + createAnimation(visible); + mBgAnim.start(); + mPositionAnim.start(); + } else { + mBgAnim.reverse(); + mPositionAnim.reverse(); + } + } + + 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; + } else { + alpha = ((float)mPanelBottom) / glowYOffset; + } + mContentParent.setAlpha(alpha); + mGlowDrawable.setAlpha((int)(255 * alpha)); + + if (false) { + Slog.d(TAG, "mPanelBottom=" + mPanelBottom + "translationY=" + translationY + + " alpha=" + alpha + " glowY=" + glowY); + } + } + + public void setPanelHeight(int h) { + mPanelHeight = h; + setPanelBottom(mPanelBottom); + } + + public void onAnimationCancel(Animator animation) { + //Slog.d(TAG, "onAnimationCancel mBgAlpha=" + mBgAlpha); + } + + public void onAnimationEnd(Animator animation) { + //Slog.d(TAG, "onAnimationEnd mBgAlpha=" + mBgAlpha); + if (mBgAlpha == 0) { + setVisibility(View.GONE); + } + mBgAnim = null; + } + + public void onAnimationRepeat(Animator animation) { + } + + public void onAnimationStart(Animator animation) { + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java index 8b80e50..7a7976a 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java @@ -161,7 +161,7 @@ public class TabletStatusBar extends StatusBar { // Notification Panel mNotificationPanel = (NotificationPanel)View.inflate(context, R.layout.status_bar_notification_panel, null); - mNotificationPanel.setVisibility(View.GONE); + mNotificationPanel.show(false, false); mNotificationPanel.setOnTouchListener( new TouchOutsideListener(MSG_CLOSE_NOTIFICATION_PANEL, mNotificationPanel)); @@ -186,10 +186,14 @@ public class TabletStatusBar extends StatusBar { WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL, WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN | WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM - | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH, + | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH + | WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED, PixelFormat.TRANSLUCENT); lp.gravity = Gravity.BOTTOM | Gravity.RIGHT; lp.setTitle("NotificationPanel"); + lp.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED + | WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING; + lp.windowAnimations = com.android.internal.R.style.Animation; // == no animation WindowManagerImpl.getDefault().addView(mNotificationPanel, lp); @@ -391,7 +395,7 @@ public class TabletStatusBar extends StatusBar { mNotificationPeekRow.addView(copy.row); mNotificationPeekWindow.setVisibility(View.VISIBLE); - mNotificationPanel.setVisibility(View.GONE); + mNotificationPanel.show(false, true); mNotificationPeekIndex = peekIndex; mNotificationPeekKey = entry.key; @@ -413,9 +417,9 @@ public class TabletStatusBar extends StatusBar { break; case MSG_OPEN_NOTIFICATION_PANEL: if (DEBUG) Slog.d(TAG, "opening notifications panel"); - if (mNotificationPanel.getVisibility() == View.GONE) { + if (!mNotificationPanel.isShowing()) { mNotificationPeekWindow.setVisibility(View.GONE); - mNotificationPanel.setVisibility(View.VISIBLE); + mNotificationPanel.show(true, true); // synchronize with current shadow state mShadowController.hideElement(mNotificationArea); mTicker.halt(); @@ -423,8 +427,8 @@ public class TabletStatusBar extends StatusBar { break; case MSG_CLOSE_NOTIFICATION_PANEL: if (DEBUG) Slog.d(TAG, "closing notifications panel"); - if (mNotificationPanel.getVisibility() == View.VISIBLE) { - mNotificationPanel.setVisibility(View.GONE); + if (mNotificationPanel.isShowing()) { + mNotificationPanel.show(false, true); // synchronize with current shadow state mShadowController.showElement(mNotificationArea); } @@ -459,8 +463,7 @@ public class TabletStatusBar extends StatusBar { if (mNotificationTrigger == null) return; int resId; - boolean panel = (mNotificationPanel != null - && mNotificationPanel.getVisibility() == View.VISIBLE); + boolean panel = (mNotificationPanel != null && mNotificationPanel.isShowing(); if (!mNotificationsOn) { resId = R.drawable.ic_sysbar_noti_dnd; } else if (mNotns.size() > 0) { @@ -658,7 +661,7 @@ public class TabletStatusBar extends StatusBar { private void tick(IBinder key, StatusBarNotification n) { // Don't show the ticker when the windowshade is open. - if (mNotificationPanel.getVisibility() == View.VISIBLE) { + if (mNotificationPanel.isShowing()) { return; } // Show the ticker if one is requested. Also don't do this @@ -786,7 +789,7 @@ public class TabletStatusBar extends StatusBar { mIconLayout.setVisibility(View.VISIBLE); // TODO: animation refreshNotificationTrigger(); } else { - int msg = (mNotificationPanel.getVisibility() == View.GONE) + int msg = !mNotificationPanel.isShowing() ? MSG_OPEN_NOTIFICATION_PANEL : MSG_CLOSE_NOTIFICATION_PANEL; mHandler.removeMessages(msg); @@ -895,7 +898,7 @@ public class TabletStatusBar extends StatusBar { public boolean onTouch(View v, MotionEvent event) { boolean peeking = mNotificationPeekWindow.getVisibility() != View.GONE; - boolean panelShowing = mNotificationPanel.getVisibility() != View.GONE; + boolean panelShowing = mNotificationPanel.isShowing(); if (panelShowing) return false; switch (event.getAction()) { |