Change interaction for dragging down to full shade.
Starts expanding the card if it is expandable. If it's not, we
rubberband the expansion a lot. After the threshold has been reached,
we scale all the notifications up and make it fully white and opaque.
Change-Id: I9ecd020ca263b0f84e87fd6ab2332519ac5e9984
diff --git a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
index 61c268e..4d6d815 100644
--- a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
@@ -29,17 +29,16 @@
import android.view.ScaleGestureDetector;
import android.view.ScaleGestureDetector.OnScaleGestureListener;
import android.view.View;
-import android.view.View.OnClickListener;
import android.view.ViewConfiguration;
-import com.android.systemui.statusbar.ExpandableView;
import com.android.systemui.statusbar.ExpandableNotificationRow;
+import com.android.systemui.statusbar.ExpandableView;
import com.android.systemui.statusbar.policy.ScrollAdapter;
-public class ExpandHelper implements Gefingerpoken, OnClickListener {
+public class ExpandHelper implements Gefingerpoken {
public interface Callback {
- View getChildAtRawPosition(float x, float y);
- View getChildAtPosition(float x, float y);
+ ExpandableView getChildAtRawPosition(float x, float y);
+ ExpandableView getChildAtPosition(float x, float y);
boolean canChildBeExpanded(View v);
void setUserExpandedChild(View v, boolean userExpanded);
void setUserLockedChild(View v, boolean userLocked);
@@ -48,9 +47,7 @@
private static final String TAG = "ExpandHelper";
protected static final boolean DEBUG = false;
protected static final boolean DEBUG_SCALE = false;
- protected static final boolean DEBUG_GLOW = false;
private static final long EXPAND_DURATION = 250;
- private static final long GLOW_DURATION = 150;
// Set to false to disable focus-based gestures (spread-finger vertical pull).
private static final boolean USE_DRAG = true;
@@ -115,7 +112,7 @@
float focusX = detector.getFocusX();
float focusY = detector.getFocusY();
- final View underFocus = findView(focusX, focusY);
+ final ExpandableView underFocus = findView(focusX, focusY);
startExpanding(underFocus, STRETCH);
return mExpanding;
}
@@ -172,24 +169,6 @@
mPopDuration = mContext.getResources().getInteger(R.integer.blinds_pop_duration_ms);
mPullGestureMinXSpan = mContext.getResources().getDimension(R.dimen.pull_span_min);
- AnimatorListenerAdapter glowVisibilityController = new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- View target = (View) ((ObjectAnimator) animation).getTarget();
- if (target.getAlpha() <= 0.0f) {
- target.setVisibility(View.VISIBLE);
- }
- }
-
- @Override
- public void onAnimationEnd(Animator animation) {
- View target = (View) ((ObjectAnimator) animation).getTarget();
- if (target.getAlpha() <= 0.0f) {
- target.setVisibility(View.INVISIBLE);
- }
- }
- };
-
final ViewConfiguration configuration = ViewConfiguration.get(mContext);
mTouchSlop = configuration.getScaledTouchSlop();
@@ -221,8 +200,8 @@
return out;
}
- private View findView(float x, float y) {
- View v = null;
+ private ExpandableView findView(float x, float y) {
+ ExpandableView v;
if (mEventSource != null) {
int[] location = new int[2];
mEventSource.getLocationOnScreen(location);
@@ -271,15 +250,6 @@
mScrollAdapter = adapter;
}
- private float calculateGlow(float target, float actual) {
- // glow if overscale
- if (DEBUG_GLOW) Log.d(TAG, "target: " + target + " actual: " + actual);
- float stretch = Math.abs((target - actual) / mMaximumStretch);
- float strength = 1f / (1f + (float) Math.pow(Math.E, -1 * ((8f * stretch) - 5f)));
- if (DEBUG_GLOW) Log.d(TAG, "stretch: " + stretch + " strength: " + strength);
- return (GLOW_BASE + strength * (1f - GLOW_BASE));
- }
-
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
final int action = ev.getAction();
@@ -313,7 +283,7 @@
// detect a vertical pulling gesture with fingers somewhat separated
if (DEBUG_SCALE) Log.v(TAG, "got pull gesture (xspan=" + xspan + "px)");
- final View underFocus = findView(x, y);
+ final ExpandableView underFocus = findView(x, y);
startExpanding(underFocus, PULL);
return true;
}
@@ -328,7 +298,7 @@
if (yDiff > mTouchSlop) {
if (DEBUG) Log.v(TAG, "got venetian gesture (dy=" + yDiff + "px)");
mLastMotionY = y;
- final View underFocus = findView(x, y);
+ final ExpandableView underFocus = findView(x, y);
if (startExpanding(underFocus, BLINDS)) {
mInitialTouchY = mLastMotionY;
mHasPopped = false;
@@ -394,7 +364,7 @@
final int x = (int) mSGD.getFocusX();
final int y = (int) mSGD.getFocusY();
- View underFocus = findView(x, y);
+ ExpandableView underFocus = findView(x, y);
if (isFinished && underFocus != null && underFocus != mCurrView) {
finishExpanding(false); // @@@ needed?
startExpanding(underFocus, BLINDS);
@@ -432,7 +402,7 @@
/**
* @return True if the view is expandable, false otherwise.
*/
- private boolean startExpanding(View v, int expandType) {
+ private boolean startExpanding(ExpandableView v, int expandType) {
if (!(v instanceof ExpandableNotificationRow)) {
return false;
}
@@ -512,13 +482,6 @@
mCurrView = v;
}
- @Override
- public void onClick(View v) {
- startExpanding(v, STRETCH);
- finishExpanding(true);
- clearView();
- }
-
/**
* Use this to abort any pending expansions in progress.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index 5a55292..f5f2eb79 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -16,12 +16,18 @@
package com.android.systemui.statusbar;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
-import android.widget.FrameLayout;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
import com.android.internal.R;
@@ -34,7 +40,6 @@
private static final long DOUBLETAP_TIMEOUT_MS = 1000;
private boolean mDimmed;
- private boolean mLocked;
private int mBgResId = R.drawable.notification_quantum_bg;
private int mDimmedBgResId = R.drawable.notification_quantum_bg_dim;
@@ -51,13 +56,20 @@
private OnActivatedListener mOnActivatedListener;
+ protected Drawable mBackgroundNormal;
+ protected Drawable mBackgroundDimmed;
+ private ObjectAnimator mBackgroundAnimator;
+ private Interpolator mFastOutSlowInInterpolator;
+
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);
}
-
private final Runnable mTapTimeoutRunnable = new Runnable() {
@Override
public void run() {
@@ -66,20 +78,51 @@
};
@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 (mLocked) {
- return handleTouchEventLocked(event);
+ if (mDimmed) {
+ return handleTouchEventDimmed(event);
} else {
return super.onTouchEvent(event);
}
}
- private boolean handleTouchEventLocked(MotionEvent event) {
+ private boolean handleTouchEventDimmed(MotionEvent event) {
int action = event.getActionMasked();
switch (action) {
case MotionEvent.ACTION_DOWN:
@@ -118,7 +161,7 @@
}
private void makeActive(float x, float y) {
- mCustomBackground.setHotspot(0, x, y);
+ mBackgroundDimmed.setHotspot(0, x, y);
mActivated = true;
if (mOnActivatedListener != null) {
mOnActivatedListener.onActivated(this);
@@ -131,8 +174,8 @@
private void makeInactive() {
if (mActivated) {
// Make sure that we clear the hotspot from the center.
- mCustomBackground.setHotspot(0, getWidth() / 2, getActualHeight() / 2);
- mCustomBackground.removeHotspot(0);
+ mBackgroundDimmed.setHotspot(0, getWidth() / 2, getActualHeight() / 2);
+ mBackgroundDimmed.removeHotspot(0);
mActivated = false;
}
if (mOnActivatedListener != null) {
@@ -148,23 +191,22 @@
/**
* Sets the notification as dimmed, meaning that it will appear in a more gray variant.
+ *
+ * @param dimmed Whether the notification should be dimmed.
+ * @param fade Whether an animation should be played to change the state.
*/
- public void setDimmed(boolean dimmed) {
+ public void setDimmed(boolean dimmed, boolean fade) {
if (mDimmed != dimmed) {
mDimmed = dimmed;
- updateBackgroundResource();
+ if (fade) {
+ fadeBackgroundResource();
+ } else {
+ updateBackgroundResource();
+ }
}
}
/**
- * Sets the notification as locked. In the locked state, the first tap will produce a quantum
- * ripple to make the notification brighter and only the second tap will cause a click.
- */
- public void setLocked(boolean locked) {
- mLocked = locked;
- }
-
- /**
* Sets the resource id for the background of this notification.
*
* @param bgResId The background resource to use in normal state.
@@ -176,20 +218,106 @@
updateBackgroundResource();
}
+ private void fadeBackgroundResource() {
+ if (mDimmed) {
+ setBackgroundDimmed(mDimmedBgResId);
+ } else {
+ setBackgroundNormal(mBgResId);
+ }
+ int startAlpha = mDimmed ? 255 : 0;
+ int endAlpha = mDimmed ? 0 : 255;
+ int duration = NotificationActivator.ANIMATION_LENGTH_MS;
+ // Check whether there is already a background animation running.
+ if (mBackgroundAnimator != null) {
+ startAlpha = (Integer) mBackgroundAnimator.getAnimatedValue();
+ duration = (int) (NotificationActivator.ANIMATION_LENGTH_MS
+ - mBackgroundAnimator.getCurrentPlayTime());
+ mBackgroundAnimator.removeAllListeners();
+ mBackgroundAnimator.cancel();
+ }
+ mBackgroundNormal.setAlpha(startAlpha);
+ mBackgroundAnimator =
+ ObjectAnimator.ofInt(mBackgroundNormal, "alpha", startAlpha, endAlpha);
+ mBackgroundAnimator.setInterpolator(mFastOutSlowInInterpolator);
+ mBackgroundAnimator.setDuration(duration);
+ mBackgroundAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (mDimmed) {
+ setBackgroundNormal(null);
+ } else {
+ setBackgroundDimmed(null);
+ }
+ mBackgroundAnimator = null;
+ }
+ });
+ mBackgroundAnimator.start();
+ }
+
private void updateBackgroundResource() {
- setCustomBackgroundResource(mDimmed ? mDimmedBgResId : mBgResId);
+ if (mDimmed) {
+ setBackgroundDimmed(mDimmedBgResId);
+ setBackgroundNormal(null);
+ } else {
+ setBackgroundDimmed(null);
+ setBackgroundNormal(mBgResId);
+ }
+ }
+
+ /**
+ * 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) {
+ setBackgroundNormal(getResources().getDrawable(drawableResId));
+ }
+
+ private void setBackgroundDimmed(int drawableResId) {
+ setBackgroundDimmed(getResources().getDrawable(drawableResId));
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
- setPivotX(getWidth()/2);
+ setPivotX(getWidth() / 2);
}
@Override
public void setActualHeight(int actualHeight) {
super.setActualHeight(actualHeight);
- setPivotY(actualHeight/2);
+ invalidate();
+ setPivotY(actualHeight / 2);
+ }
+
+ @Override
+ public void setClipTopAmount(int clipTopAmount) {
+ super.setClipTopAmount(clipTopAmount);
+ invalidate();
}
public void setOnActivatedListener(OnActivatedListener onActivatedListener) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 829cee4..236e0e9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -171,6 +171,7 @@
* The {@link StatusBarState} of the status bar.
*/
protected int mState;
+ protected boolean mBouncerShowing;
protected NotificationOverflowContainer mKeyguardIconOverflowContainer;
@@ -1073,8 +1074,7 @@
entry.row.setSystemExpanded(top);
}
}
- entry.row.setDimmed(onKeyguard);
- entry.row.setLocked(onKeyguard);
+ entry.row.setDimmed(onKeyguard, false /* fade */);
boolean showOnKeyguard = shouldShowOnKeyguard(entry.notification);
if (onKeyguard && (visibleNotifications >= maxKeyguardNotifications
|| !showOnKeyguard)) {
@@ -1094,6 +1094,7 @@
if (onKeyguard && mKeyguardIconOverflowContainer.getIconsView().getChildCount() > 0) {
mKeyguardIconOverflowContainer.setVisibility(View.VISIBLE);
+ mKeyguardIconOverflowContainer.setDimmed(true /* dimmed */, false /* fade */);
} else {
mKeyguardIconOverflowContainer.setVisibility(View.GONE);
}
@@ -1403,6 +1404,17 @@
// hook for subclasses
}
+ public void setBouncerShowing(boolean bouncerShowing) {
+ mBouncerShowing = bouncerShowing;
+ }
+
+ /**
+ * @return Whether the security bouncer from Keyguard is showing.
+ */
+ public boolean isBouncerShowing() {
+ return mBouncerShowing;
+ }
+
public void destroy() {
if (mSearchPanelView != null) {
mWindowManager.removeViewImmediate(mSearchPanelView);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
index af4c8b8..699c83f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
@@ -16,24 +16,31 @@
package com.android.systemui.statusbar;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
import android.content.Context;
-import android.util.ArraySet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
import com.android.systemui.ExpandHelper;
import com.android.systemui.Gefingerpoken;
import com.android.systemui.R;
-import java.util.HashSet;
-
/**
* A utility class to enable the downward swipe on the lockscreen to go to the full shade and expand
* the notification where the drag started.
*/
public class DragDownHelper implements Gefingerpoken {
+ private static final float RUBBERBAND_FACTOR_EXPANDABLE = 0.5f;
+ private static final float RUBBERBAND_FACTOR_STATIC = 0.15f;
+
+ private static final int SPRING_BACK_ANIMATION_LENGTH_MS = 375;
+
private int mMinDragDistance;
private ExpandHelper.Callback mCallback;
private float mInitialTouchX;
@@ -43,14 +50,16 @@
private OnDragDownListener mOnDragDownListener;
private View mHost;
private final int[] mTemp2 = new int[2];
- private final ArraySet<View> mHoveredChildren = new ArraySet<View>();
private boolean mDraggedFarEnough;
- private View mStartingChild;
+ private ExpandableView mStartingChild;
+ private Interpolator mInterpolator;
public DragDownHelper(Context context, View host, ExpandHelper.Callback callback,
OnDragDownListener onDragDownListener) {
mMinDragDistance = context.getResources().getDimensionPixelSize(
R.dimen.keyguard_drag_down_min_distance);
+ mInterpolator =
+ AnimationUtils.loadInterpolator(context, android.R.interpolator.fast_out_slow_in);
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
mCallback = callback;
mOnDragDownListener = onDragDownListener;
@@ -64,7 +73,6 @@
switch (event.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
- mHoveredChildren.clear();
mDraggedFarEnough = false;
mDraggingDown = false;
mStartingChild = null;
@@ -76,6 +84,7 @@
final float h = y - mInitialTouchY;
if (h > mTouchSlop && h > Math.abs(x - mInitialTouchX)) {
mDraggingDown = true;
+ captureStartingChild(mInitialTouchX, mInitialTouchY);
mInitialTouchY = y;
mInitialTouchX = x;
return true;
@@ -96,9 +105,9 @@
switch (event.getActionMasked()) {
case MotionEvent.ACTION_MOVE:
final float h = y - mInitialTouchY;
- View child = findView(x, y);
- if (child != null) {
- hoverChild(findView(x, y));
+ captureStartingChild(mInitialTouchX, mInitialTouchY);
+ if (mStartingChild != null) {
+ handleExpansion(h, mStartingChild);
}
if (h > mMinDragDistance) {
if (!mDraggedFarEnough) {
@@ -114,6 +123,9 @@
return true;
case MotionEvent.ACTION_UP:
if (mDraggedFarEnough) {
+ if (mStartingChild != null) {
+ mCallback.setUserLockedChild(mStartingChild, false);
+ }
mOnDragDownListener.onDraggedDown(mStartingChild);
} else {
stopDragging();
@@ -127,22 +139,58 @@
return false;
}
+ private void captureStartingChild(float x, float y) {
+ if (mStartingChild == null) {
+ mStartingChild = findView(x, y);
+ if (mStartingChild != null) {
+ mCallback.setUserLockedChild(mStartingChild, true);
+ }
+ }
+ }
+
+ private void handleExpansion(float heightDelta, ExpandableView child) {
+ if (heightDelta < 0) {
+ heightDelta = 0;
+ }
+ boolean expandable = child.isContentExpandable();
+ float rubberbandFactor = expandable
+ ? RUBBERBAND_FACTOR_EXPANDABLE
+ : RUBBERBAND_FACTOR_STATIC;
+ float rubberband = heightDelta * rubberbandFactor;
+ if (expandable && (rubberband + child.getMinHeight()) > child.getMaxHeight()) {
+ float overshoot = (rubberband + child.getMinHeight()) - child.getMaxHeight();
+ overshoot *= (1 - RUBBERBAND_FACTOR_STATIC);
+ rubberband -= overshoot;
+ }
+ child.setActualHeight((int) (child.getMinHeight() + rubberband));
+ }
+
+ private void cancelExpansion(final ExpandableView child) {
+ if (child.getActualHeight() == child.getMinHeight()) {
+ return;
+ }
+ ObjectAnimator anim = ObjectAnimator.ofInt(child, "actualHeight",
+ child.getActualHeight(), child.getMinHeight());
+ anim.setInterpolator(mInterpolator);
+ anim.setDuration(SPRING_BACK_ANIMATION_LENGTH_MS);
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mCallback.setUserLockedChild(child, false);
+ }
+ });
+ anim.start();
+ }
+
private void stopDragging() {
+ if (mStartingChild != null) {
+ cancelExpansion(mStartingChild);
+ }
mDraggingDown = false;
mOnDragDownListener.onReset();
}
- private void hoverChild(View child) {
- if (mHoveredChildren.isEmpty()) {
- mStartingChild = child;
- }
- if (!mHoveredChildren.contains(child)) {
- mOnDragDownListener.onHover(child);
- mHoveredChildren.add(child);
- }
- }
-
- private View findView(float x, float y) {
+ private ExpandableView findView(float x, float y) {
mHost.getLocationOnScreen(mTemp2);
x += mTemp2[0];
y += mTemp2[1];
@@ -150,7 +198,6 @@
}
public interface OnDragDownListener {
- void onHover(View child);
void onDraggedDown(View startingChild);
void onReset();
void onThresholdReached();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 5b70cd3..a6dcbeb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -23,8 +23,7 @@
import com.android.systemui.R;
-public class ExpandableNotificationRow extends ActivatableNotificationView implements
- NotificationActivatable {
+public class ExpandableNotificationRow extends ActivatableNotificationView {
private int mRowMinHeight;
private int mRowMaxHeight;
@@ -114,7 +113,6 @@
public void setUserExpanded(boolean userExpanded) {
mHasUserChangedExpansion = true;
mUserExpanded = userExpanded;
- applyExpansionToLayout();
}
public boolean isUserLocked() {
@@ -218,16 +216,16 @@
/**
* Sets the notification as dimmed, meaning that it will appear in a more gray variant.
*/
- public void setDimmed(boolean dimmed) {
- super.setDimmed(dimmed);
- mActivator.setDimmed(dimmed);
+ @Override
+ public void setDimmed(boolean dimmed, boolean fade) {
+ super.setDimmed(dimmed, fade);
+ mActivator.setDimmed(dimmed, fade);
}
public int getMaxExpandHeight() {
return mMaxExpandHeight;
}
- @Override
public NotificationActivator getActivator() {
return mActivator;
}
@@ -240,6 +238,11 @@
}
@Override
+ public boolean isContentExpandable() {
+ return mPrivateLayout.isContentExpandable();
+ }
+
+ @Override
public void setActualHeight(int height) {
mPrivateLayout.setActualHeight(height);
invalidate();
@@ -252,6 +255,11 @@
}
@Override
+ public int getMinHeight() {
+ return mPrivateLayout.getMinHeight();
+ }
+
+ @Override
public void setClipTopAmount(int clipTopAmount) {
super.setClipTopAmount(clipTopAmount);
mPrivateLayout.setClipTopAmount(clipTopAmount);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
index 35913fa..871c84b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
@@ -34,7 +34,6 @@
private OnHeightChangedListener mOnHeightChangedListener;
protected int mActualHeight;
protected int mClipTopAmount;
- protected Drawable mCustomBackground;
private boolean mActualHeightInitialized;
public ExpandableView(Context context, AttributeSet attrs) {
@@ -42,27 +41,6 @@
}
@Override
- protected void onDraw(Canvas canvas) {
- if (mCustomBackground != null) {
- mCustomBackground.setBounds(0, mClipTopAmount, getWidth(), mActualHeight);
- mCustomBackground.draw(canvas);
- }
- }
-
- @Override
- protected boolean verifyDrawable(Drawable who) {
- return super.verifyDrawable(who) || who == mCustomBackground;
- }
-
- @Override
- protected void drawableStateChanged() {
- final Drawable d = mCustomBackground;
- if (d != null && d.isStateful()) {
- d.setState(getDrawableState());
- }
- }
-
- @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) {
@@ -77,7 +55,6 @@
*/
public void setActualHeight(int actualHeight) {
mActualHeight = actualHeight;
- invalidate();
if (mOnHeightChangedListener != null) {
mOnHeightChangedListener.onHeightChanged(this);
}
@@ -95,7 +72,16 @@
/**
* @return The maximum height of this notification.
*/
- public abstract int getMaxHeight();
+ public int getMaxHeight() {
+ return getHeight();
+ }
+
+ /**
+ * @return The minimum height of this notification.
+ */
+ public int getMinHeight() {
+ return getHeight();
+ }
/**
* Sets the amount this view should be clipped from the top. This is used when an expanded
@@ -105,7 +91,6 @@
*/
public void setClipTopAmount(int clipTopAmount) {
mClipTopAmount = clipTopAmount;
- invalidate();
}
public void setOnHeightChangedListener(OnHeightChangedListener listener) {
@@ -113,22 +98,10 @@
}
/**
- * Sets a custom background drawable. As we need to change our bounds independently of layout,
- * we need the notition of a custom background.
+ * @return Whether we can expand this views content.
*/
- public void setCustomBackground(Drawable customBackground) {
- if (mCustomBackground != null) {
- mCustomBackground.setCallback(null);
- unscheduleDrawable(mCustomBackground);
- }
- mCustomBackground = customBackground;
- mCustomBackground.setCallback(this);
- setWillNotDraw(customBackground == null);
- invalidate();
- }
-
- public void setCustomBackgroundResource(int drawableResId) {
- setCustomBackground(getResources().getDrawable(drawableResId));
+ public boolean isContentExpandable() {
+ return false;
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationActivatable.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationActivatable.java
deleted file mode 100644
index 410a3aa..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationActivatable.java
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * 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;
-
-/**
- * An interface which defines a view to be activatable in the meaning of
- * {@link NotificationActivator}.
- */
-public interface NotificationActivatable {
- NotificationActivator getActivator();
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationActivator.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationActivator.java
index 097857c..a03aeec 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationActivator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationActivator.java
@@ -30,7 +30,7 @@
*/
public class NotificationActivator {
- private static final int ANIMATION_LENGTH_MS = 220;
+ public static final int ANIMATION_LENGTH_MS = 220;
private static final float INVERSE_ALPHA = 0.9f;
private static final float DIMMED_SCALE = 0.95f;
@@ -118,20 +118,34 @@
if (mTargetView.getAlpha() != 1.0f) {
mTargetView.animate().withLayer().alpha(1);
}
- mHotspotView.getBackground().removeHotspot(0);
mState = STATE_DIMMED;
}
- public void setDimmed(boolean dimmed) {
+ public void setDimmed(boolean dimmed, boolean fade) {
if (dimmed) {
mTargetView.animate().cancel();
- mTargetView.setScaleX(DIMMED_SCALE);
- mTargetView.setScaleY(DIMMED_SCALE);
+ if (fade) {
+ mTargetView.animate()
+ .setInterpolator(mFastOutSlowInInterpolator)
+ .scaleX(DIMMED_SCALE)
+ .scaleY(DIMMED_SCALE);
+ } else {
+ mTargetView.setScaleX(DIMMED_SCALE);
+ mTargetView.setScaleY(DIMMED_SCALE);
+ }
mState = STATE_DIMMED;
} else {
mTargetView.animate().cancel();
- mTargetView.setScaleX(1);
- mTargetView.setScaleY(1);
+ if (fade) {
+ mTargetView.animate()
+ .setInterpolator(mFastOutSlowInInterpolator)
+ .scaleX(1)
+ .scaleY(1);
+ } else {
+ mTargetView.animate().cancel();
+ mTargetView.setScaleX(1);
+ mTargetView.setScaleY(1);
+ }
mState = STATE_NORMAL;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index fd0cb08..1f15eaf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -84,6 +84,11 @@
}
@Override
+ public int getMinHeight() {
+ return mSmallHeight;
+ }
+
+ @Override
public void setClipTopAmount(int clipTopAmount) {
super.setClipTopAmount(clipTopAmount);
updateClipping();
@@ -125,4 +130,9 @@
public void notifyContentUpdated() {
selectLayout();
}
+
+ @Override
+ public boolean isContentExpandable() {
+ return mExpandedChild != null;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java
index 6f9cbf8..e6b5600 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationOverflowContainer.java
@@ -25,8 +25,7 @@
/**
* Container view for overflowing notification icons on Keyguard.
*/
-public class NotificationOverflowContainer extends ActivatableNotificationView implements
- NotificationActivatable {
+public class NotificationOverflowContainer extends ActivatableNotificationView {
private NotificationOverflowIconsView mIconsView;
private NotificationActivator mActivator;
@@ -46,11 +45,6 @@
}
@Override
- public int getMaxHeight() {
- return getHeight();
- }
-
- @Override
public void setClipTopAmount(int clipTopAmount) {
// noop
}
@@ -62,16 +56,19 @@
mIconsView.setMoreText((TextView) findViewById(R.id.more_text));
mActivator = new NotificationActivator(this, this);
- mActivator.setDimmed(true);
- setLocked(true);
- setDimmed(true);
+ setDimmed(true, false);
+ }
+
+ @Override
+ public void setDimmed(boolean dimmed, boolean fade) {
+ super.setDimmed(dimmed, fade);
+ mActivator.setDimmed(dimmed, fade);
}
public NotificationOverflowIconsView getIconsView() {
return mIconsView;
}
- @Override
public NotificationActivator getActivator() {
return mActivator;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 7d8f3ef..890d1bd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -100,7 +100,6 @@
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.GestureRecorder;
import com.android.systemui.statusbar.InterceptedNotifications;
-import com.android.systemui.statusbar.NotificationActivatable;
import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.NotificationData.Entry;
import com.android.systemui.statusbar.NotificationOverflowContainer;
@@ -3134,19 +3133,29 @@
@Override
public void onReset() {
- onReset(null);
- }
-
- public void onHover(View child) {
- if (child instanceof NotificationActivatable) {
- NotificationActivatable activatable = (NotificationActivatable) child;
- activatable.getActivator().activate();
- activatable.getActivator().addHotspot();
+ int n = mNotificationData.size();
+ for (int i = 0; i < n; i++) {
+ NotificationData.Entry entry = mNotificationData.get(i);
+ if (entry.row.getVisibility() != View.GONE) {
+ entry.row.setDimmed(true /* dimmed */, true /* fade */);
+ }
+ }
+ if (mKeyguardIconOverflowContainer.getVisibility() != View.GONE) {
+ mKeyguardIconOverflowContainer.setDimmed(true /* dimmed */, true /* fade */);
}
}
public void onThresholdReached() {
- // TODO: Add visual hint that threshold is reached.
+ int n = mNotificationData.size();
+ for (int i = 0; i < n; i++) {
+ NotificationData.Entry entry = mNotificationData.get(i);
+ if (entry.row.getVisibility() != View.GONE) {
+ entry.row.setDimmed(false /* dimmed */, true /* fade */);
+ }
+ }
+ if (mKeyguardIconOverflowContainer.getVisibility() != View.GONE) {
+ mKeyguardIconOverflowContainer.setDimmed(false /* dimmed */, true /* fade */);
+ }
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index c9c2867..10c1625 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -19,7 +19,6 @@
import android.app.ActivityManager;
import android.content.Context;
import android.content.res.Resources;
-import android.content.res.Resources.NotFoundException;
import android.util.AttributeSet;
import android.util.EventLog;
import android.util.Log;
@@ -188,7 +187,8 @@
if (panel == mFadingPanel && mScrimColor != 0 && ActivityManager.isHighEndGfx()
&& mBar.mStatusBarWindow != null) {
if (mShouldFade) {
- int scrimColor = mBar.getBarState() == StatusBarState.KEYGUARD
+ int scrimColor = (mBar.getBarState() == StatusBarState.KEYGUARD
+ || mBar.getBarState() == StatusBarState.SHADE_LOCKED)
? mScrimColorKeyguard
: mScrimColor;
frac = mPanelExpandedFractionSum; // don't judge me
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index c2595cf..554892c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -18,22 +18,14 @@
import android.content.Context;
import android.os.Bundle;
-import android.os.IBinder;
import android.os.RemoteException;
-import android.util.Log;
import android.util.Slog;
-import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.view.ViewTreeObserver;
import com.android.internal.policy.IKeyguardShowCallback;
import com.android.internal.widget.LockPatternUtils;
-import com.android.keyguard.KeyguardHostView;
-import com.android.keyguard.KeyguardSimpleHostView;
-import com.android.keyguard.R;
import com.android.keyguard.ViewMediatorCallback;
-import com.android.systemui.keyguard.KeyguardViewMediator;
/**
* Manages creating, showing, hiding and resetting the keyguard within the status bar. Calls back
@@ -82,7 +74,7 @@
mShowing = true;
mStatusBarWindowManager.setKeyguardShowing(true);
showBouncerOrKeyguard();
- updateBackButtonState();
+ updateStates();
}
/**
@@ -102,9 +94,9 @@
}
}
- public void showBouncer() {
+ private void showBouncer() {
mBouncer.show();
- updateBackButtonState();
+ updateStates();
}
/**
@@ -112,7 +104,7 @@
*/
public void reset() {
showBouncerOrKeyguard();
- updateBackButtonState();
+ updateStates();
}
public void onScreenTurnedOff() {
@@ -155,7 +147,7 @@
public void setOccluded(boolean occluded) {
mOccluded = occluded;
mStatusBarWindowManager.setKeyguardOccluded(occluded);
- updateBackButtonState();
+ updateStates();
}
/**
@@ -167,7 +159,7 @@
mStatusBarWindowManager.setKeyguardShowing(false);
mBouncer.hide();
mViewMediatorCallback.keyguardGone();
- updateBackButtonState();
+ updateStates();
}
/**
@@ -199,13 +191,13 @@
if (mBouncer.isShowing()) {
mBouncer.hide();
mPhoneStatusBar.showKeyguard();
- updateBackButtonState();
+ updateStates();
return true;
}
return false;
}
- private void updateBackButtonState() {
+ private void updateStates() {
int vis = mContainer.getSystemUiVisibility();
boolean bouncerDismissable = mBouncer.isShowing() && !mBouncer.needsFullscreenBouncer();
if (bouncerDismissable || !mShowing) {
@@ -218,6 +210,7 @@
} else {
mPhoneStatusBar.getNavigationBarView().setVisibility(View.GONE);
}
+ mPhoneStatusBar.setBouncerShowing(mBouncer.isShowing());
}
public boolean onMenuPressed() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
index a04baea..a4c9df5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
@@ -147,7 +147,8 @@
}
private void applyInputFeatures(State state) {
- if (state.isKeyguardShowingAndNotOccluded()) {
+ if (state.isKeyguardShowingAndNotOccluded()
+ && state.statusBarState == StatusBarState.KEYGUARD) {
mLp.inputFeatures |= WindowManager.LayoutParams.INPUT_FEATURE_DISABLE_USER_ACTIVITY;
} else {
mLp.inputFeatures &= ~WindowManager.LayoutParams.INPUT_FEATURE_DISABLE_USER_ACTIVITY;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index 3e5ba16..acc3a0b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -112,7 +112,8 @@
intercept = mExpandHelper.onInterceptTouchEvent(ev);
} else if (mNotificationPanel.isFullyExpanded()
&& mStackScrollLayout.getVisibility() == View.VISIBLE
- && mService.getBarState() == StatusBarState.KEYGUARD) {
+ && mService.getBarState() == StatusBarState.KEYGUARD
+ && !mService.isBouncerShowing()) {
intercept = mDragDownHelper.onInterceptTouchEvent(ev);
}
if (!intercept) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
index c94c65f..72e22e9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
@@ -32,6 +32,7 @@
import com.android.systemui.R;
import com.android.systemui.SwipeHelper;
import com.android.systemui.statusbar.BaseStatusBar;
+import com.android.systemui.statusbar.ExpandableView;
import com.android.systemui.statusbar.NotificationData;
public class HeadsUpNotificationView extends FrameLayout implements SwipeHelper.Callback, ExpandHelper.Callback {
@@ -185,12 +186,12 @@
// ExpandHelper.Callback methods
@Override
- public View getChildAtRawPosition(float x, float y) {
+ public ExpandableView getChildAtRawPosition(float x, float y) {
return getChildAtPosition(x, y);
}
@Override
- public View getChildAtPosition(float x, float y) {
+ public ExpandableView getChildAtPosition(float x, float y) {
return mHeadsUp == null ? null : mHeadsUp.row;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 0114f3c..8a49ded 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -159,6 +159,7 @@
mScroller = new OverScroller(getContext());
setFocusable(true);
setDescendantFocusability(FOCUS_AFTER_DESCENDANTS);
+ setClipChildren(false);
final ViewConfiguration configuration = ViewConfiguration.get(context);
mTouchSlop = configuration.getScaledTouchSlop();
mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();
@@ -383,13 +384,13 @@
return getChildAtPosition(ev.getX(), ev.getY());
}
- public View getChildAtRawPosition(float touchX, float touchY) {
+ public ExpandableView getChildAtRawPosition(float touchX, float touchY) {
int[] location = new int[2];
getLocationOnScreen(location);
return getChildAtPosition(touchX - location[0], touchY - location[1]);
}
- public View getChildAtPosition(float touchX, float touchY) {
+ public ExpandableView getChildAtPosition(float touchX, float touchY) {
// find the view under the pointer, accounting for GONE views
final int count = getChildCount();
for (int childIdx = 0; childIdx < count; childIdx++) {