Merge "Move background from notification into a view."
diff --git a/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml b/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml
index 8348e9b..f867068 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_keyguard_overflow.xml
@@ -22,6 +22,14 @@
android:focusable="true"
android:clickable="true"
>
+ <com.android.systemui.statusbar.NotificationBackgroundView android:id="@+id/backgroundNormal"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ />
+ <com.android.systemui.statusbar.NotificationBackgroundView android:id="@+id/backgroundDimmed"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ />
<TextView
android:id="@+id/more_text"
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/status_bar_notification_row.xml b/packages/SystemUI/res/layout/status_bar_notification_row.xml
index 8959a5b..2837cd6 100644
--- a/packages/SystemUI/res/layout/status_bar_notification_row.xml
+++ b/packages/SystemUI/res/layout/status_bar_notification_row.xml
@@ -6,6 +6,16 @@
android:clickable="true"
>
+ <com.android.systemui.statusbar.NotificationBackgroundView
+ android:id="@+id/backgroundNormal"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
+ <com.android.systemui.statusbar.NotificationBackgroundView
+ android:id="@+id/backgroundDimmed"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+
<com.android.systemui.statusbar.NotificationContentView android:id="@+id/expanded"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index 5e8c769..724b6a4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -19,18 +19,17 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.PorterDuff;
-import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
+import android.view.animation.PathInterpolator;
-import com.android.internal.R;
+import com.android.systemui.R;
/**
* Base class for both {@link ExpandableNotificationRow} and {@link NotificationOverflowContainer}
@@ -38,13 +37,19 @@
*/
public abstract class ActivatableNotificationView extends ExpandableOutlineView {
- private static final long DOUBLETAP_TIMEOUT_MS = 1000;
+ private static final long DOUBLETAP_TIMEOUT_MS = 1200;
private static final int BACKGROUND_ANIMATION_LENGTH_MS = 220;
+ private static final int ACTIVATE_ANIMATION_LENGTH = 220;
+
+ private static final Interpolator ACTIVATE_INVERSE_INTERPOLATOR
+ = new PathInterpolator(0.6f, 0, 0.5f, 1);
+ private static final Interpolator ACTIVATE_INVERSE_ALPHA_INTERPOLATOR
+ = new PathInterpolator(0, 0, 0.5f, 1);
private boolean mDimmed;
- private int mBgResId = R.drawable.notification_quantum_bg;
- private int mDimmedBgResId = R.drawable.notification_quantum_bg_dim;
+ private int mBgResId = com.android.internal.R.drawable.notification_quantum_bg;
+ private int mDimmedBgResId = com.android.internal.R.drawable.notification_quantum_bg_dim;
private int mBgTint = 0;
private int mDimmedBgTint = 0;
@@ -61,18 +66,30 @@
private OnActivatedListener mOnActivatedListener;
- protected Drawable mBackgroundNormal;
- protected Drawable mBackgroundDimmed;
- private ObjectAnimator mBackgroundAnimator;
+ private Interpolator mLinearOutSlowInInterpolator;
private Interpolator mFastOutSlowInInterpolator;
+ private NotificationBackgroundView mBackgroundNormal;
+ private NotificationBackgroundView mBackgroundDimmed;
+ private ObjectAnimator mBackgroundAnimator;
+
public ActivatableNotificationView(Context context, AttributeSet attrs) {
super(context, attrs);
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
- updateBackgroundResource();
- setWillNotDraw(false);
mFastOutSlowInInterpolator =
AnimationUtils.loadInterpolator(context, android.R.interpolator.fast_out_slow_in);
+ mLinearOutSlowInInterpolator =
+ AnimationUtils.loadInterpolator(context, android.R.interpolator.linear_out_slow_in);
+ setClipChildren(false);
+ setClipToPadding(false);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mBackgroundNormal = (NotificationBackgroundView) findViewById(R.id.backgroundNormal);
+ mBackgroundDimmed = (NotificationBackgroundView) findViewById(R.id.backgroundDimmed);
+ updateBackgroundResource();
}
private final Runnable mTapTimeoutRunnable = new Runnable() {
@@ -83,42 +100,6 @@
};
@Override
- protected void onDraw(Canvas canvas) {
- draw(canvas, mBackgroundNormal);
- draw(canvas, mBackgroundDimmed);
- }
-
- private void draw(Canvas canvas, Drawable drawable) {
- if (drawable != null) {
- drawable.setBounds(0, mClipTopAmount, getWidth(), mActualHeight);
- drawable.draw(canvas);
- }
- }
-
- @Override
- protected boolean verifyDrawable(Drawable who) {
- return super.verifyDrawable(who) || who == mBackgroundNormal
- || who == mBackgroundDimmed;
- }
-
- @Override
- protected void drawableStateChanged() {
- drawableStateChanged(mBackgroundNormal);
- drawableStateChanged(mBackgroundDimmed);
- }
-
- private void drawableStateChanged(Drawable d) {
- if (d != null && d.isStateful()) {
- d.setState(getDrawableState());
- }
- }
-
- @Override
- public void setOnClickListener(OnClickListener l) {
- super.setOnClickListener(l);
- }
-
- @Override
public boolean onTouchEvent(MotionEvent event) {
if (mDimmed) {
return handleTouchEventDimmed(event);
@@ -146,10 +127,9 @@
case MotionEvent.ACTION_UP:
if (isWithinTouchSlop(event)) {
if (!mActivated) {
- makeActive(event.getX(), event.getY());
+ makeActive();
postDelayed(mTapTimeoutRunnable, DOUBLETAP_TIMEOUT_MS);
} else {
- makeInactive();
performClick();
}
} else {
@@ -165,23 +145,58 @@
return true;
}
- private void makeActive(float x, float y) {
- mBackgroundDimmed.setHotspot(0, x, y);
+ private void makeActive() {
+ startActivateAnimation(false /* reverse */);
mActivated = true;
if (mOnActivatedListener != null) {
mOnActivatedListener.onActivated(this);
}
}
+ private void startActivateAnimation(boolean reverse) {
+ int widthHalf = mBackgroundNormal.getWidth()/2;
+ int heightHalf = mBackgroundNormal.getActualHeight()/2;
+ float radius = (float) Math.sqrt(widthHalf*widthHalf + heightHalf*heightHalf);
+ ValueAnimator animator =
+ mBackgroundNormal.createRevealAnimator(widthHalf, heightHalf, 0, radius);
+ mBackgroundNormal.setVisibility(View.VISIBLE);
+ Interpolator interpolator;
+ Interpolator alphaInterpolator;
+ if (!reverse) {
+ interpolator = mLinearOutSlowInInterpolator;
+ alphaInterpolator = mLinearOutSlowInInterpolator;
+ } else {
+ interpolator = ACTIVATE_INVERSE_INTERPOLATOR;
+ alphaInterpolator = ACTIVATE_INVERSE_ALPHA_INTERPOLATOR;
+ }
+ animator.setInterpolator(interpolator);
+ animator.setDuration(ACTIVATE_ANIMATION_LENGTH);
+ if (reverse) {
+ mBackgroundNormal.setAlpha(1f);
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mBackgroundNormal.setVisibility(View.INVISIBLE);
+ }
+ });
+ animator.reverse();
+ } else {
+ mBackgroundNormal.setAlpha(0.4f);
+ animator.start();
+ }
+ mBackgroundNormal.animate()
+ .alpha(reverse ? 0f : 1f)
+ .setInterpolator(alphaInterpolator)
+ .setDuration(ACTIVATE_ANIMATION_LENGTH);
+ }
+
/**
* Cancels the hotspot and makes the notification inactive.
*/
private void makeInactive() {
if (mActivated) {
- // Make sure that we clear the hotspot from the center.
- if (mBackgroundDimmed != null) {
- mBackgroundDimmed.setHotspot(0, getWidth() / 2, getActualHeight() / 2);
- mBackgroundDimmed.removeHotspot(0);
+ if (mDimmed) {
+ startActivateAnimation(true /* reverse */);
}
mActivated = false;
}
@@ -227,16 +242,16 @@
private void fadeBackgroundResource() {
if (mDimmed) {
- setBackgroundDimmed(mDimmedBgResId, mDimmedBgTint);
+ mBackgroundDimmed.setVisibility(View.VISIBLE);
} else {
- setBackgroundNormal(mBgResId, mBgTint);
+ mBackgroundNormal.setVisibility(View.VISIBLE);
}
- int startAlpha = mDimmed ? 255 : 0;
- int endAlpha = mDimmed ? 0 : 255;
+ float startAlpha = mDimmed ? 1f : 0;
+ float endAlpha = mDimmed ? 0 : 1f;
int duration = BACKGROUND_ANIMATION_LENGTH_MS;
// Check whether there is already a background animation running.
if (mBackgroundAnimator != null) {
- startAlpha = (Integer) mBackgroundAnimator.getAnimatedValue();
+ startAlpha = (Float) mBackgroundAnimator.getAnimatedValue();
duration = (int) mBackgroundAnimator.getCurrentPlayTime();
mBackgroundAnimator.removeAllListeners();
mBackgroundAnimator.cancel();
@@ -247,16 +262,16 @@
}
mBackgroundNormal.setAlpha(startAlpha);
mBackgroundAnimator =
- ObjectAnimator.ofInt(mBackgroundNormal, "alpha", startAlpha, endAlpha);
+ ObjectAnimator.ofFloat(mBackgroundNormal, View.ALPHA, startAlpha, endAlpha);
mBackgroundAnimator.setInterpolator(mFastOutSlowInInterpolator);
mBackgroundAnimator.setDuration(duration);
mBackgroundAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
if (mDimmed) {
- setBackgroundNormal(null);
+ mBackgroundNormal.setVisibility(View.INVISIBLE);
} else {
- setBackgroundDimmed(null);
+ mBackgroundDimmed.setVisibility(View.INVISIBLE);
}
mBackgroundAnimator = null;
}
@@ -266,61 +281,17 @@
private void updateBackgroundResource() {
if (mDimmed) {
- setBackgroundDimmed(mDimmedBgResId, mDimmedBgTint);
- mBackgroundDimmed.setAlpha(255);
- setBackgroundNormal(null);
+ mBackgroundDimmed.setVisibility(View.VISIBLE);
+ mBackgroundDimmed.setCustomBackground(mDimmedBgResId, mDimmedBgTint);
+ mBackgroundNormal.setVisibility(View.INVISIBLE);
} else {
- setBackgroundDimmed(null);
- setBackgroundNormal(mBgResId, mBgTint);
- mBackgroundNormal.setAlpha(255);
+ mBackgroundDimmed.setVisibility(View.INVISIBLE);
+ mBackgroundNormal.setVisibility(View.VISIBLE);
+ mBackgroundNormal.setCustomBackground(mBgResId, mBgTint);
+ mBackgroundNormal.setAlpha(1f);
}
}
- /**
- * Sets a background drawable for the normal state. As we need to change our bounds
- * independently of layout, we need the notion of a background independently of the regular View
- * background..
- */
- private void setBackgroundNormal(Drawable backgroundNormal) {
- if (mBackgroundNormal != null) {
- mBackgroundNormal.setCallback(null);
- unscheduleDrawable(mBackgroundNormal);
- }
- mBackgroundNormal = backgroundNormal;
- if (mBackgroundNormal != null) {
- mBackgroundNormal.setCallback(this);
- }
- invalidate();
- }
-
- private void setBackgroundDimmed(Drawable overlay) {
- if (mBackgroundDimmed != null) {
- mBackgroundDimmed.setCallback(null);
- unscheduleDrawable(mBackgroundDimmed);
- }
- mBackgroundDimmed = overlay;
- if (mBackgroundDimmed != null) {
- mBackgroundDimmed.setCallback(this);
- }
- invalidate();
- }
-
- private void setBackgroundNormal(int drawableResId, int tintColor) {
- final Drawable d = getResources().getDrawable(drawableResId);
- if (tintColor != 0) {
- d.setColorFilter(tintColor, PorterDuff.Mode.SRC_ATOP);
- }
- setBackgroundNormal(d);
- }
-
- private void setBackgroundDimmed(int drawableResId, int tintColor) {
- final Drawable d = getResources().getDrawable(drawableResId);
- if (tintColor != 0) {
- d.setColorFilter(tintColor, PorterDuff.Mode.SRC_ATOP);
- }
- setBackgroundDimmed(d);
- }
-
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
@@ -330,14 +301,16 @@
@Override
public void setActualHeight(int actualHeight, boolean notifyListeners) {
super.setActualHeight(actualHeight, notifyListeners);
- invalidate();
setPivotY(actualHeight / 2);
+ mBackgroundNormal.setActualHeight(actualHeight);
+ mBackgroundDimmed.setActualHeight(actualHeight);
}
@Override
public void setClipTopAmount(int clipTopAmount) {
super.setClipTopAmount(clipTopAmount);
- invalidate();
+ mBackgroundNormal.setClipTopAmount(clipTopAmount);
+ mBackgroundDimmed.setClipTopAmount(clipTopAmount);
}
public void setOnActivatedListener(OnActivatedListener onActivatedListener) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java
new file mode 100644
index 0000000..e49ec64
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2014 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;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.PorterDuff;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.View;
+
+/**
+ * A view that can be used for both the dimmed and normal background of an notification.
+ */
+public class NotificationBackgroundView extends View {
+
+ private Drawable mBackground;
+ private int mClipTopAmount;
+ private int mActualHeight;
+ private boolean mActualHeightInitialized;
+
+ public NotificationBackgroundView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ setWillNotDraw(false);
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
+ if (!mActualHeightInitialized && mActualHeight == 0) {
+ mActualHeight = getHeight();
+ }
+ mActualHeightInitialized = true;
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ draw(canvas, mBackground);
+ }
+
+ private void draw(Canvas canvas, Drawable drawable) {
+ if (drawable != null) {
+ drawable.setBounds(0, mClipTopAmount, getWidth(), mActualHeight);
+ drawable.draw(canvas);
+ }
+ }
+
+ @Override
+ protected boolean verifyDrawable(Drawable who) {
+ return super.verifyDrawable(who) || who == mBackground;
+ }
+
+ @Override
+ protected void drawableStateChanged() {
+ drawableStateChanged(mBackground);
+ }
+
+ private void drawableStateChanged(Drawable d) {
+ if (d != null && d.isStateful()) {
+ d.setState(getDrawableState());
+ }
+ }
+
+ /**
+ * Sets a background drawable. As we need to change our bounds independently of layout, we need
+ * the notion of a background independently of the regular View background..
+ */
+ public void setCustomBackground(Drawable background) {
+ if (mBackground != null) {
+ mBackground.setCallback(null);
+ unscheduleDrawable(mBackground);
+ }
+ mBackground = background;
+ if (mBackground != null) {
+ mBackground.setCallback(this);
+ }
+ invalidate();
+ }
+
+ public void setCustomBackground(int drawableResId, int tintColor) {
+ final Drawable d = getResources().getDrawable(drawableResId);
+ if (tintColor != 0) {
+ d.setColorFilter(tintColor, PorterDuff.Mode.SRC_ATOP);
+ }
+ setCustomBackground(d);
+ }
+
+ public void setActualHeight(int actualHeight) {
+ mActualHeight = actualHeight;
+ invalidate();
+ }
+
+ public int getActualHeight() {
+ return mActualHeight;
+ }
+
+ public void setClipTopAmount(int clipTopAmount) {
+ mClipTopAmount = clipTopAmount;
+ invalidate();
+ }
+
+ @Override
+ public boolean hasOverlappingRendering() {
+
+ // Prevents this view from creating a layer when alpha is animating.
+ return false;
+ }
+}