am a5e042f9: Merge "Single finger notification expansion." into jb-dev
* commit 'a5e042f9232c26505968d8add60f3f84c6a87dae': Single finger notification expansion.
This commit is contained in:
@@ -67,7 +67,7 @@
|
|||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:fadingEdge="none"
|
android:fadingEdge="none"
|
||||||
android:overScrollMode="always"
|
android:overScrollMode="ifContentScrolls"
|
||||||
>
|
>
|
||||||
<com.android.systemui.statusbar.policy.NotificationRowLayout
|
<com.android.systemui.statusbar.policy.NotificationRowLayout
|
||||||
android:id="@+id/latestItems"
|
android:id="@+id/latestItems"
|
||||||
|
|||||||
@@ -65,5 +65,8 @@
|
|||||||
|
|
||||||
<!-- Vibration duration for MultiWaveView used in SearchPanelView -->
|
<!-- Vibration duration for MultiWaveView used in SearchPanelView -->
|
||||||
<integer translatable="false" name="config_search_panel_view_vibration_duration">20</integer>
|
<integer translatable="false" name="config_search_panel_view_vibration_duration">20</integer>
|
||||||
|
|
||||||
|
<!-- The length of the vibration when the notificaiotn pops open. -->
|
||||||
|
<integer name="one_finger_pop_duration_ms">10</integer>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
||||||
|
|||||||
@@ -150,4 +150,7 @@
|
|||||||
|
|
||||||
<!-- Height of the carrier/wifi name label -->
|
<!-- Height of the carrier/wifi name label -->
|
||||||
<dimen name="carrier_label_height">24dp</dimen>
|
<dimen name="carrier_label_height">24dp</dimen>
|
||||||
|
|
||||||
|
<!-- The distance you can pull a notificaiton before it pops open -->
|
||||||
|
<dimen name="one_finger_pop_limit">32dp</dimen>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -18,4 +18,5 @@
|
|||||||
<resources>
|
<resources>
|
||||||
<item type="id" name="expandable_tag" />
|
<item type="id" name="expandable_tag" />
|
||||||
<item type="id" name="user_expanded_tag" />
|
<item type="id" name="user_expanded_tag" />
|
||||||
|
<item type="id" name="user_lock_tag" />
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -22,24 +22,31 @@ import android.animation.AnimatorListenerAdapter;
|
|||||||
import android.animation.AnimatorSet;
|
import android.animation.AnimatorSet;
|
||||||
import android.animation.ObjectAnimator;
|
import android.animation.ObjectAnimator;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.os.Vibrator;
|
||||||
import android.util.Slog;
|
import android.util.Slog;
|
||||||
import android.view.Gravity;
|
import android.view.Gravity;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.ScaleGestureDetector;
|
import android.view.ScaleGestureDetector;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
import android.view.ViewConfiguration;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.view.View.OnClickListener;
|
import android.view.View.OnClickListener;
|
||||||
|
|
||||||
|
import java.util.Stack;
|
||||||
|
|
||||||
public class ExpandHelper implements Gefingerpoken, OnClickListener {
|
public class ExpandHelper implements Gefingerpoken, OnClickListener {
|
||||||
public interface Callback {
|
public interface Callback {
|
||||||
View getChildAtRawPosition(float x, float y);
|
View getChildAtRawPosition(float x, float y);
|
||||||
View getChildAtPosition(float x, float y);
|
View getChildAtPosition(float x, float y);
|
||||||
boolean canChildBeExpanded(View v);
|
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";
|
private static final String TAG = "ExpandHelper";
|
||||||
protected static final boolean DEBUG = false;
|
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 EXPAND_DURATION = 250;
|
||||||
private static final long GLOW_DURATION = 150;
|
private static final long GLOW_DURATION = 150;
|
||||||
|
|
||||||
@@ -63,6 +70,9 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
|
|||||||
private Context mContext;
|
private Context mContext;
|
||||||
|
|
||||||
private boolean mStretching;
|
private boolean mStretching;
|
||||||
|
private boolean mPullingWithOneFinger;
|
||||||
|
private boolean mWatchingForPull;
|
||||||
|
private boolean mHasPopped;
|
||||||
private View mEventSource;
|
private View mEventSource;
|
||||||
private View mCurrView;
|
private View mCurrView;
|
||||||
private View mCurrViewTopGlow;
|
private View mCurrViewTopGlow;
|
||||||
@@ -70,7 +80,12 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
|
|||||||
private float mOldHeight;
|
private float mOldHeight;
|
||||||
private float mNaturalHeight;
|
private float mNaturalHeight;
|
||||||
private float mInitialTouchFocusY;
|
private float mInitialTouchFocusY;
|
||||||
|
private float mInitialTouchY;
|
||||||
private float mInitialTouchSpan;
|
private float mInitialTouchSpan;
|
||||||
|
private int mTouchSlop;
|
||||||
|
private int mLastMotionY;
|
||||||
|
private float mPopLimit;
|
||||||
|
private int mPopDuration;
|
||||||
private Callback mCallback;
|
private Callback mCallback;
|
||||||
private ScaleGestureDetector mDetector;
|
private ScaleGestureDetector mDetector;
|
||||||
private ViewScaler mScaler;
|
private ViewScaler mScaler;
|
||||||
@@ -78,6 +93,7 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
|
|||||||
private AnimatorSet mGlowAnimationSet;
|
private AnimatorSet mGlowAnimationSet;
|
||||||
private ObjectAnimator mGlowTopAnimation;
|
private ObjectAnimator mGlowTopAnimation;
|
||||||
private ObjectAnimator mGlowBottomAnimation;
|
private ObjectAnimator mGlowBottomAnimation;
|
||||||
|
private Vibrator mVibrator;
|
||||||
|
|
||||||
private int mSmallSize;
|
private int mSmallSize;
|
||||||
private int mLargeSize;
|
private int mLargeSize;
|
||||||
@@ -85,6 +101,8 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
|
|||||||
|
|
||||||
private int mGravity;
|
private int mGravity;
|
||||||
|
|
||||||
|
private View mScrollView;
|
||||||
|
|
||||||
private class ViewScaler {
|
private class ViewScaler {
|
||||||
View mView;
|
View mView;
|
||||||
|
|
||||||
@@ -93,7 +111,7 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
|
|||||||
mView = v;
|
mView = v;
|
||||||
}
|
}
|
||||||
public void setHeight(float h) {
|
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();
|
ViewGroup.LayoutParams lp = mView.getLayoutParams();
|
||||||
lp.height = (int)h;
|
lp.height = (int)h;
|
||||||
mView.setLayoutParams(lp);
|
mView.setLayoutParams(lp);
|
||||||
@@ -108,7 +126,8 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
|
|||||||
}
|
}
|
||||||
public int getNaturalHeight(int maximum) {
|
public int getNaturalHeight(int maximum) {
|
||||||
ViewGroup.LayoutParams lp = mView.getLayoutParams();
|
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;
|
int oldHeight = lp.height;
|
||||||
lp.height = ViewGroup.LayoutParams.WRAP_CONTENT;
|
lp.height = ViewGroup.LayoutParams.WRAP_CONTENT;
|
||||||
mView.setLayoutParams(lp);
|
mView.setLayoutParams(lp);
|
||||||
@@ -142,6 +161,8 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
|
|||||||
mGravity = Gravity.TOP;
|
mGravity = Gravity.TOP;
|
||||||
mScaleAnimation = ObjectAnimator.ofFloat(mScaler, "height", 0f);
|
mScaleAnimation = ObjectAnimator.ofFloat(mScaler, "height", 0f);
|
||||||
mScaleAnimation.setDuration(EXPAND_DURATION);
|
mScaleAnimation.setDuration(EXPAND_DURATION);
|
||||||
|
mPopLimit = mContext.getResources().getDimension(R.dimen.one_finger_pop_limit);
|
||||||
|
mPopDuration = mContext.getResources().getInteger(R.integer.one_finger_pop_duration_ms);
|
||||||
|
|
||||||
AnimatorListenerAdapter glowVisibilityController = new AnimatorListenerAdapter() {
|
AnimatorListenerAdapter glowVisibilityController = new AnimatorListenerAdapter() {
|
||||||
@Override
|
@Override
|
||||||
@@ -169,38 +190,30 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
|
|||||||
mGlowAnimationSet.play(mGlowTopAnimation).with(mGlowBottomAnimation);
|
mGlowAnimationSet.play(mGlowTopAnimation).with(mGlowBottomAnimation);
|
||||||
mGlowAnimationSet.setDuration(GLOW_DURATION);
|
mGlowAnimationSet.setDuration(GLOW_DURATION);
|
||||||
|
|
||||||
|
final ViewConfiguration configuration = ViewConfiguration.get(mContext);
|
||||||
|
mTouchSlop = configuration.getScaledTouchSlop();
|
||||||
|
|
||||||
mDetector =
|
mDetector =
|
||||||
new ScaleGestureDetector(context,
|
new ScaleGestureDetector(context,
|
||||||
new ScaleGestureDetector.SimpleOnScaleGestureListener() {
|
new ScaleGestureDetector.SimpleOnScaleGestureListener() {
|
||||||
@Override
|
@Override
|
||||||
public boolean onScaleBegin(ScaleGestureDetector detector) {
|
public boolean onScaleBegin(ScaleGestureDetector detector) {
|
||||||
if (DEBUG) Slog.v(TAG, "onscalebegin()");
|
if (DEBUG_SCALE) Slog.v(TAG, "onscalebegin()");
|
||||||
float x = detector.getFocusX();
|
float x = detector.getFocusX();
|
||||||
float y = detector.getFocusY();
|
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// your fingers have to be somewhat close to the bounds of the view in question
|
// your fingers have to be somewhat close to the bounds of the view in question
|
||||||
mInitialTouchFocusY = detector.getFocusY();
|
mInitialTouchFocusY = detector.getFocusY();
|
||||||
mInitialTouchSpan = Math.abs(detector.getCurrentSpan());
|
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);
|
mStretching = initScale(findView(x, y));
|
||||||
return mStretching;
|
return mStretching;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onScale(ScaleGestureDetector detector) {
|
public boolean onScale(ScaleGestureDetector detector) {
|
||||||
if (DEBUG) Slog.v(TAG, "onscale() on " + mCurrView);
|
if (DEBUG_SCALE) Slog.v(TAG, "onscale() on " + mCurrView);
|
||||||
|
|
||||||
// are we scaling or dragging?
|
// are we scaling or dragging?
|
||||||
float span = Math.abs(detector.getCurrentSpan()) - mInitialTouchSpan;
|
float span = Math.abs(detector.getCurrentSpan()) - mInitialTouchSpan;
|
||||||
@@ -210,33 +223,71 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
|
|||||||
drag *= mGravity == Gravity.BOTTOM ? -1f : 1f;
|
drag *= mGravity == Gravity.BOTTOM ? -1f : 1f;
|
||||||
float pull = Math.abs(drag) + Math.abs(span) + 1f;
|
float pull = Math.abs(drag) + Math.abs(span) + 1f;
|
||||||
float hand = drag * Math.abs(drag) / pull + span * Math.abs(span) / pull;
|
float hand = drag * Math.abs(drag) / pull + span * Math.abs(span) / pull;
|
||||||
if (DEBUG) Slog.d(TAG, "current span handle is: " + hand);
|
float target = hand + mOldHeight;
|
||||||
hand = hand + mOldHeight;
|
float newHeight = clamp(target);
|
||||||
float target = hand;
|
mScaler.setHeight(newHeight);
|
||||||
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
|
setGlow(calculateGlow(target, newHeight));
|
||||||
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));
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onScaleEnd(ScaleGestureDetector detector) {
|
public void onScaleEnd(ScaleGestureDetector detector) {
|
||||||
if (DEBUG) Slog.v(TAG, "onscaleend()");
|
if (DEBUG_SCALE) Slog.v(TAG, "onscaleend()");
|
||||||
// I guess we're alone now
|
// I guess we're alone now
|
||||||
if (DEBUG) Slog.d(TAG, "scale end");
|
if (DEBUG_SCALE) Slog.d(TAG, "scale end");
|
||||||
finishScale(false);
|
finishScale(false);
|
||||||
|
clearView();
|
||||||
|
mStretching = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 += (float) location[0];
|
||||||
|
y += (float) 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 += (float) location[0];
|
||||||
|
y += (float) location[1];
|
||||||
|
if (DEBUG) Slog.d(TAG, " to global (" + x + ", " + y + ")");
|
||||||
|
}
|
||||||
|
int[] location = new int[2];
|
||||||
|
v.getLocationOnScreen(location);
|
||||||
|
x -= (float) location[0];
|
||||||
|
y -= (float) 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) {
|
public void setEventSource(View eventSource) {
|
||||||
mEventSource = eventSource;
|
mEventSource = eventSource;
|
||||||
}
|
}
|
||||||
@@ -245,13 +296,26 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
|
|||||||
mGravity = gravity;
|
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 = (float) 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) {
|
public void setGlow(float glow) {
|
||||||
if (!mGlowAnimationSet.isRunning() || glow == 0f) {
|
if (!mGlowAnimationSet.isRunning() || glow == 0f) {
|
||||||
if (mGlowAnimationSet.isRunning()) {
|
if (mGlowAnimationSet.isRunning()) {
|
||||||
mGlowAnimationSet.cancel();
|
mGlowAnimationSet.end();
|
||||||
}
|
}
|
||||||
if (mCurrViewTopGlow != null && mCurrViewBottomGlow != null) {
|
if (mCurrViewTopGlow != null && mCurrViewBottomGlow != null) {
|
||||||
if (glow == 0f || mCurrViewTopGlow.getAlpha() == 0f) {
|
if (glow == 0f || mCurrViewTopGlow.getAlpha() == 0f) {
|
||||||
// animate glow in and out
|
// animate glow in and out
|
||||||
mGlowTopAnimation.setTarget(mCurrViewTopGlow);
|
mGlowTopAnimation.setTarget(mCurrViewTopGlow);
|
||||||
mGlowBottomAnimation.setTarget(mCurrViewBottomGlow);
|
mGlowBottomAnimation.setTarget(mCurrViewBottomGlow);
|
||||||
@@ -278,23 +342,115 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
|
|||||||
|
|
||||||
public boolean onInterceptTouchEvent(MotionEvent ev) {
|
public boolean onInterceptTouchEvent(MotionEvent ev) {
|
||||||
if (DEBUG) Slog.d(TAG, "interceptTouch: act=" + (ev.getAction()) +
|
if (DEBUG) Slog.d(TAG, "interceptTouch: act=" + (ev.getAction()) +
|
||||||
" stretching=" + mStretching);
|
" stretching=" + mStretching +
|
||||||
|
" onefinger=" + mPullingWithOneFinger);
|
||||||
|
// check for a two-finger gesture
|
||||||
mDetector.onTouchEvent(ev);
|
mDetector.onTouchEvent(ev);
|
||||||
return mStretching;
|
if (mStretching) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
final int action = ev.getAction();
|
||||||
|
if ((action == MotionEvent.ACTION_MOVE) && mPullingWithOneFinger) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (mScrollView != null && mScrollView.getScrollY() > 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
switch (action & MotionEvent.ACTION_MASK) {
|
||||||
|
case MotionEvent.ACTION_MOVE: {
|
||||||
|
if (mWatchingForPull) {
|
||||||
|
final int x = (int) ev.getX();
|
||||||
|
final int y = (int) ev.getY();
|
||||||
|
final int yDiff = y - mLastMotionY;
|
||||||
|
if (yDiff > mTouchSlop) {
|
||||||
|
mLastMotionY = y;
|
||||||
|
mPullingWithOneFinger = initScale(findView(x, y));
|
||||||
|
if (mPullingWithOneFinger) {
|
||||||
|
mInitialTouchY = mLastMotionY;
|
||||||
|
mHasPopped = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case MotionEvent.ACTION_DOWN:
|
||||||
|
mWatchingForPull = isInside(mScrollView, ev.getX(), ev.getY());
|
||||||
|
mLastMotionY = (int) ev.getY();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MotionEvent.ACTION_CANCEL:
|
||||||
|
case MotionEvent.ACTION_UP:
|
||||||
|
if (mPullingWithOneFinger) {
|
||||||
|
finishScale(false);
|
||||||
|
clearView();
|
||||||
|
}
|
||||||
|
mPullingWithOneFinger = false;
|
||||||
|
mWatchingForPull = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return mPullingWithOneFinger;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean onTouchEvent(MotionEvent ev) {
|
public boolean onTouchEvent(MotionEvent ev) {
|
||||||
final int action = ev.getAction();
|
final int action = ev.getAction();
|
||||||
if (DEBUG) Slog.d(TAG, "touch: act=" + (action) + " stretching=" + mStretching);
|
if (DEBUG_SCALE) Slog.d(TAG, "touch: act=" + (action) +
|
||||||
|
" stretching=" + mStretching +
|
||||||
|
" onefinger=" + mPullingWithOneFinger);
|
||||||
if (mStretching) {
|
if (mStretching) {
|
||||||
if (DEBUG) Slog.d(TAG, "detector ontouch");
|
|
||||||
mDetector.onTouchEvent(ev);
|
mDetector.onTouchEvent(ev);
|
||||||
}
|
}
|
||||||
switch (action) {
|
switch (action) {
|
||||||
|
case MotionEvent.ACTION_MOVE: {
|
||||||
|
if (mPullingWithOneFinger) {
|
||||||
|
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) ev.getX();
|
||||||
|
final int y = (int) ev.getY();
|
||||||
|
View underPointer = findView(x, y);
|
||||||
|
if (isFinished && underPointer != null && underPointer != mCurrView) {
|
||||||
|
finishScale(false);
|
||||||
|
initScale(underPointer);
|
||||||
|
mInitialTouchY = ev.getY();
|
||||||
|
mHasPopped = false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
case MotionEvent.ACTION_UP:
|
case MotionEvent.ACTION_UP:
|
||||||
case MotionEvent.ACTION_CANCEL:
|
case MotionEvent.ACTION_CANCEL:
|
||||||
if (DEBUG) Slog.d(TAG, "cancel");
|
if (DEBUG) Slog.d(TAG, "cancel");
|
||||||
mStretching = false;
|
mStretching = false;
|
||||||
|
if (mPullingWithOneFinger) {
|
||||||
|
finishScale(false);
|
||||||
|
mPullingWithOneFinger = false;
|
||||||
|
}
|
||||||
clearView();
|
clearView();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -303,7 +459,7 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
|
|||||||
private boolean initScale(View v) {
|
private boolean initScale(View v) {
|
||||||
if (v != null) {
|
if (v != null) {
|
||||||
if (DEBUG) Slog.d(TAG, "scale begins on view: " + v);
|
if (DEBUG) Slog.d(TAG, "scale begins on view: " + v);
|
||||||
mStretching = true;
|
mCallback.setUserLockedChild(v, true);
|
||||||
setView(v);
|
setView(v);
|
||||||
setGlow(GLOW_BASE);
|
setGlow(GLOW_BASE);
|
||||||
mScaler.setView(v);
|
mScaler.setView(v);
|
||||||
@@ -318,30 +474,34 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
|
|||||||
if (DEBUG) Slog.d(TAG, "got mOldHeight: " + mOldHeight +
|
if (DEBUG) Slog.d(TAG, "got mOldHeight: " + mOldHeight +
|
||||||
" mNaturalHeight: " + mNaturalHeight);
|
" mNaturalHeight: " + mNaturalHeight);
|
||||||
v.getParent().requestDisallowInterceptTouchEvent(true);
|
v.getParent().requestDisallowInterceptTouchEvent(true);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return mStretching;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void finishScale(boolean force) {
|
private void finishScale(boolean force) {
|
||||||
|
float currentHeight = mScaler.getHeight();
|
||||||
|
float targetHeight = mSmallSize;
|
||||||
float h = mScaler.getHeight();
|
float h = mScaler.getHeight();
|
||||||
final boolean wasClosed = (mOldHeight == mSmallSize);
|
final boolean wasClosed = (mOldHeight == mSmallSize);
|
||||||
if (wasClosed) {
|
if (wasClosed) {
|
||||||
h = (force || h > mSmallSize) ? mNaturalHeight : mSmallSize;
|
targetHeight = (force || currentHeight > mSmallSize) ? mNaturalHeight : mSmallSize;
|
||||||
} else {
|
} else {
|
||||||
h = (force || h < mNaturalHeight) ? mSmallSize : mNaturalHeight;
|
targetHeight = (force || currentHeight < mNaturalHeight) ? mSmallSize : mNaturalHeight;
|
||||||
}
|
}
|
||||||
if (DEBUG && mCurrView != null) mCurrView.setBackgroundColor(0);
|
|
||||||
if (mScaleAnimation.isRunning()) {
|
if (mScaleAnimation.isRunning()) {
|
||||||
mScaleAnimation.cancel();
|
mScaleAnimation.cancel();
|
||||||
}
|
}
|
||||||
mScaleAnimation.setFloatValues(h);
|
|
||||||
mScaleAnimation.setupStartValues();
|
|
||||||
mScaleAnimation.start();
|
|
||||||
mStretching = false;
|
|
||||||
setGlow(0f);
|
setGlow(0f);
|
||||||
mCallback.setUserExpandedChild(mCurrView, h == mNaturalHeight);
|
mCallback.setUserExpandedChild(mCurrView, h == mNaturalHeight);
|
||||||
|
if (targetHeight != currentHeight) {
|
||||||
|
mScaleAnimation.setFloatValues(targetHeight);
|
||||||
|
mScaleAnimation.setupStartValues();
|
||||||
|
mScaleAnimation.start();
|
||||||
|
}
|
||||||
|
mCallback.setUserLockedChild(mCurrView, false);
|
||||||
if (DEBUG) Slog.d(TAG, "scale was finished on view: " + mCurrView);
|
if (DEBUG) Slog.d(TAG, "scale was finished on view: " + mCurrView);
|
||||||
clearView();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void clearView() {
|
private void clearView() {
|
||||||
@@ -357,7 +517,7 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
|
|||||||
mCurrViewTopGlow = g.findViewById(R.id.top_glow);
|
mCurrViewTopGlow = g.findViewById(R.id.top_glow);
|
||||||
mCurrViewBottomGlow = g.findViewById(R.id.bottom_glow);
|
mCurrViewBottomGlow = g.findViewById(R.id.bottom_glow);
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
String debugLog = "Looking for glows: " +
|
String debugLog = "Looking for glows: " +
|
||||||
(mCurrViewTopGlow != null ? "found top " : "didn't find top") +
|
(mCurrViewTopGlow != null ? "found top " : "didn't find top") +
|
||||||
(mCurrViewBottomGlow != null ? "found bottom " : "didn't find bottom");
|
(mCurrViewBottomGlow != null ? "found bottom " : "didn't find bottom");
|
||||||
Slog.v(TAG, debugLog);
|
Slog.v(TAG, debugLog);
|
||||||
@@ -369,6 +529,18 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
|
|||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
initScale(v);
|
initScale(v);
|
||||||
finishScale(true);
|
finishScale(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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -783,16 +783,20 @@ public abstract class BaseStatusBar extends SystemUI implements
|
|||||||
int N = mNotificationData.size();
|
int N = mNotificationData.size();
|
||||||
for (int i = 0; i < N; i++) {
|
for (int i = 0; i < N; i++) {
|
||||||
NotificationData.Entry entry = mNotificationData.get(i);
|
NotificationData.Entry entry = mNotificationData.get(i);
|
||||||
if (i == (N-1)) {
|
if (!entry.userLocked()) {
|
||||||
if (DEBUG) Slog.d(TAG, "expanding top notification at " + i);
|
if (i == (N-1)) {
|
||||||
expandView(entry, true);
|
if (DEBUG) Slog.d(TAG, "expanding top notification at " + i);
|
||||||
} else {
|
expandView(entry, true);
|
||||||
if (!entry.userExpanded()) {
|
|
||||||
if (DEBUG) Slog.d(TAG, "collapsing notification at " + i);
|
|
||||||
expandView(entry, false);
|
|
||||||
} else {
|
} 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,6 +71,18 @@ public class NotificationData {
|
|||||||
public boolean setUserExpanded(boolean userExpanded) {
|
public boolean setUserExpanded(boolean userExpanded) {
|
||||||
return NotificationData.setUserExpanded(row, 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 ArrayList<Entry> mEntries = new ArrayList<Entry>();
|
||||||
private final Comparator<Entry> mEntryCmp = new Comparator<Entry>() {
|
private final Comparator<Entry> mEntryCmp = new Comparator<Entry>() {
|
||||||
@@ -197,4 +209,18 @@ public class NotificationData {
|
|||||||
public static boolean setUserExpanded(View row, boolean userExpanded) {
|
public static boolean setUserExpanded(View row, boolean userExpanded) {
|
||||||
return writeBooleanTag(row, R.id.user_expanded_tag, 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ public class StatusBarWindowView extends FrameLayout
|
|||||||
int maxHeight = getResources().getDimensionPixelSize(R.dimen.notification_row_max_height);
|
int maxHeight = getResources().getDimensionPixelSize(R.dimen.notification_row_max_height);
|
||||||
mExpandHelper = new ExpandHelper(mContext, latestItems, minHeight, maxHeight);
|
mExpandHelper = new ExpandHelper(mContext, latestItems, minHeight, maxHeight);
|
||||||
mExpandHelper.setEventSource(this);
|
mExpandHelper.setEventSource(this);
|
||||||
|
mExpandHelper.setScrollView(scroller);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -78,6 +78,7 @@ public class NotificationRowLayout
|
|||||||
super(context, attrs, defStyle);
|
super(context, attrs, defStyle);
|
||||||
|
|
||||||
mRealLayoutTransition = new LayoutTransition();
|
mRealLayoutTransition = new LayoutTransition();
|
||||||
|
mRealLayoutTransition.setAnimateParentHierarchy(true);
|
||||||
setLayoutTransitionsEnabled(true);
|
setLayoutTransitionsEnabled(true);
|
||||||
|
|
||||||
setOrientation(LinearLayout.VERTICAL);
|
setOrientation(LinearLayout.VERTICAL);
|
||||||
@@ -161,7 +162,12 @@ public class NotificationRowLayout
|
|||||||
return NotificationData.setUserExpanded(v, userExpanded);
|
return NotificationData.setUserExpanded(v, userExpanded);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean setUserLockedChild(View v, boolean userLocked) {
|
||||||
|
return NotificationData.setUserLocked(v, userLocked);
|
||||||
|
}
|
||||||
|
|
||||||
public void onChildDismissed(View v) {
|
public void onChildDismissed(View v) {
|
||||||
|
if (DEBUG) Slog.v(TAG, "onChildDismissed: " + v + " mRemoveViews=" + mRemoveViews);
|
||||||
final View veto = v.findViewById(R.id.veto);
|
final View veto = v.findViewById(R.id.veto);
|
||||||
if (veto != null && veto.getVisibility() != View.GONE && mRemoveViews) {
|
if (veto != null && veto.getVisibility() != View.GONE && mRemoveViews) {
|
||||||
veto.performClick();
|
veto.performClick();
|
||||||
@@ -225,6 +231,7 @@ public class NotificationRowLayout
|
|||||||
* get removed properly.
|
* get removed properly.
|
||||||
*/
|
*/
|
||||||
public void setViewRemoval(boolean removeViews) {
|
public void setViewRemoval(boolean removeViews) {
|
||||||
|
if (DEBUG) Slog.v(TAG, "setViewRemoval: " + removeViews);
|
||||||
mRemoveViews = removeViews;
|
mRemoveViews = removeViews;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user