summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/res/layout/status_bar_expanded.xml2
-rw-r--r--packages/SystemUI/res/values/config.xml3
-rw-r--r--packages/SystemUI/res/values/dimens.xml6
-rw-r--r--packages/SystemUI/res/values/ids.xml1
-rw-r--r--packages/SystemUI/src/com/android/systemui/ExpandHelper.java406
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java20
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java26
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java7
9 files changed, 365 insertions, 107 deletions
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 5841978..17dbcac 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -67,7 +67,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fadingEdge="none"
- android:overScrollMode="always"
+ android:overScrollMode="ifContentScrolls"
>
<com.android.systemui.statusbar.policy.NotificationRowLayout
android:id="@+id/latestItems"
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 26dba67..fd5ef4e 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -65,5 +65,8 @@
<!-- Vibration duration for MultiWaveView used in SearchPanelView -->
<integer translatable="false" name="config_search_panel_view_vibration_duration">20</integer>
+
+ <!-- The length of the vibration when the notificaiotn pops open. -->
+ <integer name="blinds_pop_duration_ms">10</integer>
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 6c40461..c6fd66a 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -150,4 +150,10 @@
<!-- Height of the carrier/wifi name label -->
<dimen name="carrier_label_height">24dp</dimen>
+
+ <!-- The distance you can pull a notificaiton before it pops open -->
+ <dimen name="blinds_pop_threshold">32dp</dimen>
+
+ <!-- The size of the gesture span needed to activate the "pull" notification expansion -->
+ <dimen name="pull_span_min">25dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index 8ebbc52..4a73200 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -18,4 +18,5 @@
<resources>
<item type="id" name="expandable_tag" />
<item type="id" name="user_expanded_tag" />
+ <item type="id" name="user_lock_tag" />
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
index 5dd15c3..dcfd0b3 100644
--- a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
@@ -22,28 +22,35 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.content.Context;
+import android.os.Vibrator;
import android.util.Slog;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
+import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
+import java.util.Stack;
+
public class ExpandHelper implements Gefingerpoken, OnClickListener {
public interface Callback {
View getChildAtRawPosition(float x, float y);
View getChildAtPosition(float x, float y);
boolean canChildBeExpanded(View v);
- boolean setUserExpandedChild(View v, boolean userxpanded);
+ boolean setUserExpandedChild(View v, boolean userExpanded);
+ boolean setUserLockedChild(View v, boolean userLocked);
}
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 (two-finger pull).
+ // Set to false to disable focus-based gestures (spread-finger vertical pull).
private static final boolean USE_DRAG = true;
// Set to false to disable scale-based gestures (both horizontal and vertical).
private static final boolean USE_SPAN = true;
@@ -62,7 +69,14 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
@SuppressWarnings("unused")
private Context mContext;
- private boolean mStretching;
+ private boolean mExpanding;
+ private static final int NONE = 0;
+ private static final int BLINDS = 1<<0;
+ private static final int PULL = 1<<1;
+ private static final int STRETCH = 1<<2;
+ private int mExpansionStyle = NONE;
+ private boolean mWatchingForPull;
+ private boolean mHasPopped;
private View mEventSource;
private View mCurrView;
private View mCurrViewTopGlow;
@@ -70,14 +84,21 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
private float mOldHeight;
private float mNaturalHeight;
private float mInitialTouchFocusY;
+ private float mInitialTouchY;
private float mInitialTouchSpan;
+ private int mTouchSlop;
+ private int mLastMotionY;
+ private float mPopLimit;
+ private int mPopDuration;
+ private float mPullGestureMinXSpan;
private Callback mCallback;
- private ScaleGestureDetector mDetector;
+ private ScaleGestureDetector mSGD;
private ViewScaler mScaler;
private ObjectAnimator mScaleAnimation;
private AnimatorSet mGlowAnimationSet;
private ObjectAnimator mGlowTopAnimation;
private ObjectAnimator mGlowBottomAnimation;
+ private Vibrator mVibrator;
private int mSmallSize;
private int mLargeSize;
@@ -85,6 +106,8 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
private int mGravity;
+ private View mScrollView;
+
private class ViewScaler {
View mView;
@@ -93,7 +116,7 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
mView = v;
}
public void setHeight(float h) {
- if (DEBUG) Slog.v(TAG, "SetHeight: setting to " + h);
+ if (DEBUG_SCALE) Slog.v(TAG, "SetHeight: setting to " + h);
ViewGroup.LayoutParams lp = mView.getLayoutParams();
lp.height = (int)h;
mView.setLayoutParams(lp);
@@ -104,11 +127,12 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
if (height < 0) {
height = mView.getMeasuredHeight();
}
- return (float) height;
+ return height;
}
public int getNaturalHeight(int maximum) {
ViewGroup.LayoutParams lp = mView.getLayoutParams();
- if (DEBUG) Slog.v(TAG, "Inspecting a child of type: " + mView.getClass().getName());
+ if (DEBUG_SCALE) Slog.v(TAG, "Inspecting a child of type: " +
+ mView.getClass().getName());
int oldHeight = lp.height;
lp.height = ViewGroup.LayoutParams.WRAP_CONTENT;
mView.setLayoutParams(lp);
@@ -142,6 +166,9 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
mGravity = Gravity.TOP;
mScaleAnimation = ObjectAnimator.ofFloat(mScaler, "height", 0f);
mScaleAnimation.setDuration(EXPAND_DURATION);
+ mPopLimit = mContext.getResources().getDimension(R.dimen.blinds_pop_threshold);
+ mPopDuration = mContext.getResources().getInteger(R.integer.blinds_pop_duration_ms);
+ mPullGestureMinXSpan = mContext.getResources().getDimension(R.dimen.pull_span_min);
AnimatorListenerAdapter glowVisibilityController = new AnimatorListenerAdapter() {
@Override
@@ -169,74 +196,108 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
mGlowAnimationSet.play(mGlowTopAnimation).with(mGlowBottomAnimation);
mGlowAnimationSet.setDuration(GLOW_DURATION);
- mDetector =
- new ScaleGestureDetector(context,
+ final ViewConfiguration configuration = ViewConfiguration.get(mContext);
+ mTouchSlop = configuration.getScaledTouchSlop();
+
+ mSGD = new ScaleGestureDetector(context,
new ScaleGestureDetector.SimpleOnScaleGestureListener() {
@Override
public boolean onScaleBegin(ScaleGestureDetector detector) {
- if (DEBUG) Slog.v(TAG, "onscalebegin()");
- float x = detector.getFocusX();
- float y = detector.getFocusY();
-
- View v = null;
- if (mEventSource != null) {
- int[] location = new int[2];
- mEventSource.getLocationOnScreen(location);
- x += (float) location[0];
- y += (float) location[1];
- v = mCallback.getChildAtRawPosition(x, y);
- } else {
- v = mCallback.getChildAtPosition(x, y);
- }
+ if (DEBUG_SCALE) Slog.v(TAG, "onscalebegin()");
+ float focusX = detector.getFocusX();
+ float focusY = detector.getFocusY();
// your fingers have to be somewhat close to the bounds of the view in question
- mInitialTouchFocusY = detector.getFocusY();
+ mInitialTouchFocusY = focusY;
mInitialTouchSpan = Math.abs(detector.getCurrentSpan());
- if (DEBUG) Slog.d(TAG, "got mInitialTouchSpan: (" + mInitialTouchSpan + ")");
+ if (DEBUG_SCALE) Slog.d(TAG, "got mInitialTouchSpan: (" + mInitialTouchSpan + ")");
- mStretching = initScale(v);
- return mStretching;
+ final View underFocus = findView(focusX, focusY);
+ if (underFocus != null) {
+ startExpanding(underFocus, STRETCH);
+ }
+ return mExpanding;
}
@Override
public boolean onScale(ScaleGestureDetector detector) {
- if (DEBUG) Slog.v(TAG, "onscale() on " + mCurrView);
-
- // are we scaling or dragging?
- float span = Math.abs(detector.getCurrentSpan()) - mInitialTouchSpan;
- span *= USE_SPAN ? 1f : 0f;
- float drag = detector.getFocusY() - mInitialTouchFocusY;
- drag *= USE_DRAG ? 1f : 0f;
- drag *= mGravity == Gravity.BOTTOM ? -1f : 1f;
- float pull = Math.abs(drag) + Math.abs(span) + 1f;
- float hand = drag * Math.abs(drag) / pull + span * Math.abs(span) / pull;
- if (DEBUG) Slog.d(TAG, "current span handle is: " + hand);
- hand = hand + mOldHeight;
- float target = hand;
- if (DEBUG) Slog.d(TAG, "target is: " + target);
- hand = hand < mSmallSize ? mSmallSize : (hand > mLargeSize ? mLargeSize : hand);
- hand = hand > mNaturalHeight ? mNaturalHeight : hand;
- if (DEBUG) Slog.d(TAG, "scale continues: hand =" + hand);
- mScaler.setHeight(hand);
-
- // glow if overscale
- float stretch = (float) Math.abs((target - hand) / mMaximumStretch);
- float strength = 1f / (1f + (float) Math.pow(Math.E, -1 * ((8f * stretch) - 5f)));
- if (DEBUG) Slog.d(TAG, "stretch: " + stretch + " strength: " + strength);
- setGlow(GLOW_BASE + strength * (1f - GLOW_BASE));
+ if (DEBUG_SCALE) Slog.v(TAG, "onscale() on " + mCurrView);
+ updateExpansion();
return true;
}
@Override
public void onScaleEnd(ScaleGestureDetector detector) {
- if (DEBUG) Slog.v(TAG, "onscaleend()");
+ if (DEBUG_SCALE) Slog.v(TAG, "onscaleend()");
// I guess we're alone now
- if (DEBUG) Slog.d(TAG, "scale end");
- finishScale(false);
+ if (DEBUG_SCALE) Slog.d(TAG, "scale end");
+ finishExpanding(false);
+ clearView();
}
});
}
+ private void updateExpansion() {
+ // are we scaling or dragging?
+ float span = Math.abs(mSGD.getCurrentSpan()) - mInitialTouchSpan;
+ span *= USE_SPAN ? 1f : 0f;
+ float drag = mSGD.getFocusY() - mInitialTouchFocusY;
+ drag *= USE_DRAG ? 1f : 0f;
+ drag *= mGravity == Gravity.BOTTOM ? -1f : 1f;
+ float pull = Math.abs(drag) + Math.abs(span) + 1f;
+ float hand = drag * Math.abs(drag) / pull + span * Math.abs(span) / pull;
+ float target = hand + mOldHeight;
+ float newHeight = clamp(target);
+ mScaler.setHeight(newHeight);
+
+ setGlow(calculateGlow(target, newHeight));
+ }
+
+ private float clamp(float target) {
+ float out = target;
+ out = out < mSmallSize ? mSmallSize : (out > mLargeSize ? mLargeSize : out);
+ out = out > mNaturalHeight ? mNaturalHeight : out;
+ return out;
+ }
+
+ private View findView(float x, float y) {
+ View v = null;
+ if (mEventSource != null) {
+ int[] location = new int[2];
+ mEventSource.getLocationOnScreen(location);
+ x += location[0];
+ y += location[1];
+ v = mCallback.getChildAtRawPosition(x, y);
+ } else {
+ v = mCallback.getChildAtPosition(x, y);
+ }
+ return v;
+ }
+
+ private boolean isInside(View v, float x, float y) {
+ if (DEBUG) Slog.d(TAG, "isinside (" + x + ", " + y + ")");
+
+ if (v == null) {
+ if (DEBUG) Slog.d(TAG, "isinside null subject");
+ return false;
+ }
+ if (mEventSource != null) {
+ int[] location = new int[2];
+ mEventSource.getLocationOnScreen(location);
+ x += location[0];
+ y += location[1];
+ if (DEBUG) Slog.d(TAG, " to global (" + x + ", " + y + ")");
+ }
+ int[] location = new int[2];
+ v.getLocationOnScreen(location);
+ x -= location[0];
+ y -= location[1];
+ if (DEBUG) Slog.d(TAG, " to local (" + x + ", " + y + ")");
+ if (DEBUG) Slog.d(TAG, " inside (" + v.getWidth() + ", " + v.getHeight() + ")");
+ boolean inside = (x > 0f && y > 0f && x < v.getWidth() & y < v.getHeight());
+ return inside;
+ }
+
public void setEventSource(View eventSource) {
mEventSource = eventSource;
}
@@ -245,13 +306,26 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
mGravity = gravity;
}
+ public void setScrollView(View scrollView) {
+ mScrollView = scrollView;
+ }
+
+ private float calculateGlow(float target, float actual) {
+ // glow if overscale
+ if (DEBUG_GLOW) Slog.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) Slog.d(TAG, "stretch: " + stretch + " strength: " + strength);
+ return (GLOW_BASE + strength * (1f - GLOW_BASE));
+ }
+
public void setGlow(float glow) {
if (!mGlowAnimationSet.isRunning() || glow == 0f) {
if (mGlowAnimationSet.isRunning()) {
- mGlowAnimationSet.cancel();
+ mGlowAnimationSet.end();
}
if (mCurrViewTopGlow != null && mCurrViewBottomGlow != null) {
- if (glow == 0f || mCurrViewTopGlow.getAlpha() == 0f) {
+ if (glow == 0f || mCurrViewTopGlow.getAlpha() == 0f) {
// animate glow in and out
mGlowTopAnimation.setTarget(mCurrViewTopGlow);
mGlowBottomAnimation.setTarget(mCurrViewBottomGlow);
@@ -276,72 +350,196 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
View.INVISIBLE : View.VISIBLE);
}
+ @Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
- if (DEBUG) Slog.d(TAG, "interceptTouch: act=" + (ev.getAction()) +
- " stretching=" + mStretching);
- mDetector.onTouchEvent(ev);
- return mStretching;
+ final int action = ev.getAction();
+ if (DEBUG_SCALE) Slog.d(TAG, "intercept: act=" + MotionEvent.actionToString(action) +
+ " expanding=" + mExpanding +
+ (0 != (mExpansionStyle & BLINDS) ? " (blinds)" : "") +
+ (0 != (mExpansionStyle & PULL) ? " (pull)" : "") +
+ (0 != (mExpansionStyle & STRETCH) ? " (stretch)" : ""));
+ // check for a spread-finger vertical pull gesture
+ mSGD.onTouchEvent(ev);
+ final int x = (int) mSGD.getFocusX();
+ final int y = (int) mSGD.getFocusY();
+ if (mExpanding) {
+ return true;
+ } else {
+ if ((action == MotionEvent.ACTION_MOVE) && 0 != (mExpansionStyle & BLINDS)) {
+ // we've begun Venetian blinds style expansion
+ return true;
+ }
+ final float xspan = mSGD.getCurrentSpanX();
+ if ((action == MotionEvent.ACTION_MOVE &&
+ xspan > mPullGestureMinXSpan &&
+ xspan > mSGD.getCurrentSpanY())) {
+ // detect a vertical pulling gesture with fingers somewhat separated
+ if (DEBUG_SCALE) Slog.v(TAG, "got pull gesture (xspan=" + xspan + "px)");
+
+ mInitialTouchFocusY = y;
+
+ final View underFocus = findView(x, y);
+ if (underFocus != null) {
+ startExpanding(underFocus, PULL);
+ }
+ return true;
+ }
+ if (mScrollView != null && mScrollView.getScrollY() > 0) {
+ return false;
+ }
+ // Now look for other gestures
+ switch (action & MotionEvent.ACTION_MASK) {
+ case MotionEvent.ACTION_MOVE: {
+ if (mWatchingForPull) {
+ final int yDiff = y - mLastMotionY;
+ if (yDiff > mTouchSlop) {
+ if (DEBUG) Slog.v(TAG, "got venetian gesture (dy=" + yDiff + "px)");
+ mLastMotionY = y;
+ final View underFocus = findView(x, y);
+ if (underFocus != null) {
+ startExpanding(underFocus, BLINDS);
+ mInitialTouchY = mLastMotionY;
+ mHasPopped = false;
+ }
+ }
+ }
+ break;
+ }
+
+ case MotionEvent.ACTION_DOWN:
+ mWatchingForPull = isInside(mScrollView, x, y);
+ mLastMotionY = y;
+ break;
+
+ case MotionEvent.ACTION_CANCEL:
+ case MotionEvent.ACTION_UP:
+ if (DEBUG) Slog.d(TAG, "up/cancel");
+ finishExpanding(false);
+ clearView();
+ break;
+ }
+ return mExpanding;
+ }
}
+ @Override
public boolean onTouchEvent(MotionEvent ev) {
final int action = ev.getAction();
- if (DEBUG) Slog.d(TAG, "touch: act=" + (action) + " stretching=" + mStretching);
- if (mStretching) {
- if (DEBUG) Slog.d(TAG, "detector ontouch");
- mDetector.onTouchEvent(ev);
- }
+ if (DEBUG_SCALE) Slog.d(TAG, "touch: act=" + MotionEvent.actionToString(action) +
+ " expanding=" + mExpanding +
+ (0 != (mExpansionStyle & BLINDS) ? " (blinds)" : "") +
+ (0 != (mExpansionStyle & PULL) ? " (pull)" : "") +
+ (0 != (mExpansionStyle & STRETCH) ? " (stretch)" : ""));
+
+ mSGD.onTouchEvent(ev);
+
switch (action) {
+ case MotionEvent.ACTION_MOVE: {
+ if (0 != (mExpansionStyle & BLINDS)) {
+ final float rawHeight = ev.getY() - mInitialTouchY + mOldHeight;
+ final float newHeight = clamp(rawHeight);
+ final boolean wasClosed = (mOldHeight == mSmallSize);
+ boolean isFinished = false;
+ if (rawHeight > mNaturalHeight) {
+ isFinished = true;
+ }
+ if (rawHeight < mSmallSize) {
+ isFinished = true;
+ }
+
+ final float pull = Math.abs(ev.getY() - mInitialTouchY);
+ if (mHasPopped || pull > mPopLimit) {
+ if (!mHasPopped) {
+ vibrate(mPopDuration);
+ mHasPopped = true;
+ }
+ }
+
+ if (mHasPopped) {
+ mScaler.setHeight(newHeight);
+ setGlow(GLOW_BASE);
+ } else {
+ setGlow(calculateGlow(4f * pull, 0f));
+ }
+
+ final int x = (int) mSGD.getFocusX();
+ final int y = (int) mSGD.getFocusY();
+ View underFocus = findView(x, y);
+ if (isFinished && underFocus != null && underFocus != mCurrView) {
+ finishExpanding(false); // @@@ needed?
+ startExpanding(underFocus, BLINDS);
+ mInitialTouchY = y;
+ mHasPopped = false;
+ }
+ return true;
+ }
+
+ if (mExpanding) {
+ updateExpansion();
+ return true;
+ }
+
+ break;
+ }
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
- if (DEBUG) Slog.d(TAG, "cancel");
- mStretching = false;
+ if (DEBUG) Slog.d(TAG, "up/cancel");
+ finishExpanding(false);
clearView();
break;
}
return true;
}
- private boolean initScale(View v) {
- if (v != null) {
- if (DEBUG) Slog.d(TAG, "scale begins on view: " + v);
- mStretching = true;
- setView(v);
- setGlow(GLOW_BASE);
- mScaler.setView(v);
- mOldHeight = mScaler.getHeight();
- if (mCallback.canChildBeExpanded(v)) {
- if (DEBUG) Slog.d(TAG, "working on an expandable child");
- mNaturalHeight = mScaler.getNaturalHeight(mLargeSize);
- } else {
- if (DEBUG) Slog.d(TAG, "working on a non-expandable child");
- mNaturalHeight = mOldHeight;
- }
- if (DEBUG) Slog.d(TAG, "got mOldHeight: " + mOldHeight +
- " mNaturalHeight: " + mNaturalHeight);
- v.getParent().requestDisallowInterceptTouchEvent(true);
+
+ private void startExpanding(View v, int expandType) {
+ mExpanding = true;
+ mExpansionStyle = expandType;
+ if (DEBUG) Slog.d(TAG, "scale type " + expandType + " beginning on view: " + v);
+ mCallback.setUserLockedChild(v, true);
+ setView(v);
+ setGlow(GLOW_BASE);
+ mScaler.setView(v);
+ mOldHeight = mScaler.getHeight();
+ if (mCallback.canChildBeExpanded(v)) {
+ if (DEBUG) Slog.d(TAG, "working on an expandable child");
+ mNaturalHeight = mScaler.getNaturalHeight(mLargeSize);
+ } else {
+ if (DEBUG) Slog.d(TAG, "working on a non-expandable child");
+ mNaturalHeight = mOldHeight;
}
- return mStretching;
+ if (DEBUG) Slog.d(TAG, "got mOldHeight: " + mOldHeight +
+ " mNaturalHeight: " + mNaturalHeight);
+ v.getParent().requestDisallowInterceptTouchEvent(true);
}
- private void finishScale(boolean force) {
+ private void finishExpanding(boolean force) {
+ if (!mExpanding) return;
+
+ float currentHeight = mScaler.getHeight();
+ float targetHeight = mSmallSize;
float h = mScaler.getHeight();
final boolean wasClosed = (mOldHeight == mSmallSize);
if (wasClosed) {
- h = (force || h > mSmallSize) ? mNaturalHeight : mSmallSize;
+ targetHeight = (force || currentHeight > mSmallSize) ? mNaturalHeight : mSmallSize;
} else {
- h = (force || h < mNaturalHeight) ? mSmallSize : mNaturalHeight;
+ targetHeight = (force || currentHeight < mNaturalHeight) ? mSmallSize : mNaturalHeight;
}
- if (DEBUG && mCurrView != null) mCurrView.setBackgroundColor(0);
if (mScaleAnimation.isRunning()) {
mScaleAnimation.cancel();
}
- mScaleAnimation.setFloatValues(h);
- mScaleAnimation.setupStartValues();
- mScaleAnimation.start();
- mStretching = false;
setGlow(0f);
mCallback.setUserExpandedChild(mCurrView, h == mNaturalHeight);
+ if (targetHeight != currentHeight) {
+ mScaleAnimation.setFloatValues(targetHeight);
+ mScaleAnimation.setupStartValues();
+ mScaleAnimation.start();
+ }
+ mCallback.setUserLockedChild(mCurrView, false);
+
+ mExpanding = false;
+ mExpansionStyle = NONE;
+
if (DEBUG) Slog.d(TAG, "scale was finished on view: " + mCurrView);
- clearView();
}
private void clearView() {
@@ -357,7 +555,7 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
mCurrViewTopGlow = g.findViewById(R.id.top_glow);
mCurrViewBottomGlow = g.findViewById(R.id.bottom_glow);
if (DEBUG) {
- String debugLog = "Looking for glows: " +
+ String debugLog = "Looking for glows: " +
(mCurrViewTopGlow != null ? "found top " : "didn't find top") +
(mCurrViewBottomGlow != null ? "found bottom " : "didn't find bottom");
Slog.v(TAG, debugLog);
@@ -367,8 +565,20 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
@Override
public void onClick(View v) {
- initScale(v);
- finishScale(true);
+ startExpanding(v, STRETCH);
+ finishExpanding(true);
+ clearView();
+ }
+ /**
+ * Triggers haptic feedback.
+ */
+ private synchronized void vibrate(long duration) {
+ if (mVibrator == null) {
+ mVibrator = (android.os.Vibrator)
+ mContext.getSystemService(Context.VIBRATOR_SERVICE);
+ }
+ mVibrator.vibrate(duration);
}
}
+
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 1204a89..8d7734e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -783,16 +783,20 @@ public abstract class BaseStatusBar extends SystemUI implements
int N = mNotificationData.size();
for (int i = 0; i < N; i++) {
NotificationData.Entry entry = mNotificationData.get(i);
- if (i == (N-1)) {
- if (DEBUG) Slog.d(TAG, "expanding top notification at " + i);
- expandView(entry, true);
- } else {
- if (!entry.userExpanded()) {
- if (DEBUG) Slog.d(TAG, "collapsing notification at " + i);
- expandView(entry, false);
+ if (!entry.userLocked()) {
+ if (i == (N-1)) {
+ if (DEBUG) Slog.d(TAG, "expanding top notification at " + i);
+ expandView(entry, true);
} else {
- if (DEBUG) Slog.d(TAG, "ignoring user-modified notification at " + i);
+ if (!entry.userExpanded()) {
+ if (DEBUG) Slog.d(TAG, "collapsing notification at " + i);
+ expandView(entry, false);
+ } else {
+ if (DEBUG) Slog.d(TAG, "ignoring user-modified notification at " + i);
+ }
}
+ } else {
+ if (DEBUG) Slog.d(TAG, "ignoring notification being held by user at " + i);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index dfd8cf8..c82f250 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -71,6 +71,18 @@ public class NotificationData {
public boolean setUserExpanded(boolean userExpanded) {
return NotificationData.setUserExpanded(row, userExpanded);
}
+ /**
+ * Return whether the entry is being touched by the user.
+ */
+ public boolean userLocked() {
+ return NotificationData.getUserLocked(row);
+ }
+ /**
+ * Set the flag indicating that this is being touched by the user.
+ */
+ public boolean setUserLocked(boolean userLocked) {
+ return NotificationData.setUserLocked(row, userLocked);
+ }
}
private final ArrayList<Entry> mEntries = new ArrayList<Entry>();
private final Comparator<Entry> mEntryCmp = new Comparator<Entry>() {
@@ -197,4 +209,18 @@ public class NotificationData {
public static boolean setUserExpanded(View row, boolean userExpanded) {
return writeBooleanTag(row, R.id.user_expanded_tag, userExpanded);
}
+
+ /**
+ * Return whether the entry is being touched by the user.
+ */
+ public static boolean getUserLocked(View row) {
+ return readBooleanTag(row, R.id.user_lock_tag);
+ }
+
+ /**
+ * Set whether the entry is being touched by the user.
+ */
+ public static boolean setUserLocked(View row, boolean userLocked) {
+ return writeBooleanTag(row, R.id.user_lock_tag, userLocked);
+ }
}
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 9317561..2628631 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -53,6 +53,7 @@ public class StatusBarWindowView extends FrameLayout
int maxHeight = getResources().getDimensionPixelSize(R.dimen.notification_row_max_height);
mExpandHelper = new ExpandHelper(mContext, latestItems, minHeight, maxHeight);
mExpandHelper.setEventSource(this);
+ mExpandHelper.setScrollView(scroller);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java
index 61e5ab6..89eed1b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NotificationRowLayout.java
@@ -78,6 +78,7 @@ public class NotificationRowLayout
super(context, attrs, defStyle);
mRealLayoutTransition = new LayoutTransition();
+ mRealLayoutTransition.setAnimateParentHierarchy(true);
setLayoutTransitionsEnabled(true);
setOrientation(LinearLayout.VERTICAL);
@@ -161,7 +162,12 @@ public class NotificationRowLayout
return NotificationData.setUserExpanded(v, userExpanded);
}
+ public boolean setUserLockedChild(View v, boolean userLocked) {
+ return NotificationData.setUserLocked(v, userLocked);
+ }
+
public void onChildDismissed(View v) {
+ if (DEBUG) Slog.v(TAG, "onChildDismissed: " + v + " mRemoveViews=" + mRemoveViews);
final View veto = v.findViewById(R.id.veto);
if (veto != null && veto.getVisibility() != View.GONE && mRemoveViews) {
veto.performClick();
@@ -225,6 +231,7 @@ public class NotificationRowLayout
* get removed properly.
*/
public void setViewRemoval(boolean removeViews) {
+ if (DEBUG) Slog.v(TAG, "setViewRemoval: " + removeViews);
mRemoveViews = removeViews;
}