Merge "Enabled the new notification shade and improved expanding logic"
This commit is contained in:
@@ -24,19 +24,10 @@
|
||||
android:id="@+id/notification_panel"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/notification_panel_bg"
|
||||
android:paddingTop="@dimen/notification_panel_padding_top"
|
||||
android:layout_marginStart="@dimen/notification_panel_margin_left"
|
||||
>
|
||||
|
||||
<View
|
||||
android:id="@+id/handle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/close_handle_height"
|
||||
android:background="@drawable/status_bar_close"
|
||||
android:visibility="invisible"
|
||||
/>
|
||||
|
||||
<include
|
||||
layout="@layout/carrier_label"
|
||||
android:layout_height="@dimen/carrier_label_height"
|
||||
@@ -69,6 +60,7 @@
|
||||
/>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/notification_container_parent"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
>
|
||||
@@ -77,21 +69,6 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
/>
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/scroll"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:fadingEdge="none"
|
||||
android:overScrollMode="ifContentScrolls"
|
||||
>
|
||||
<com.android.systemui.statusbar.policy.NotificationRowLayout
|
||||
android:id="@+id/latestItems"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
systemui:rowHeight="@dimen/notification_row_min_height"
|
||||
/>
|
||||
</ScrollView>
|
||||
|
||||
<com.android.systemui.statusbar.stack.NotificationStackScrollLayout
|
||||
android:id="@+id/notification_stack_scroller"
|
||||
|
||||
@@ -34,6 +34,8 @@ import android.view.View.OnClickListener;
|
||||
import android.view.ViewConfiguration;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.android.systemui.statusbar.policy.ScrollAdapter;
|
||||
|
||||
public class ExpandHelper implements Gefingerpoken, OnClickListener {
|
||||
public interface Callback {
|
||||
View getChildAtRawPosition(float x, float y);
|
||||
@@ -609,19 +611,5 @@ public class ExpandHelper implements Gefingerpoken, OnClickListener {
|
||||
}
|
||||
mVibrator.vibrate(duration, AudioManager.STREAM_SYSTEM);
|
||||
}
|
||||
|
||||
public interface ScrollAdapter {
|
||||
|
||||
/**
|
||||
* @return Whether the view returned by {@link #getHostView()} is scrolled to the top
|
||||
* and can therefore be expanded by a single finger drag
|
||||
*/
|
||||
public boolean isScrolledToTop();
|
||||
|
||||
/**
|
||||
* @return The view in which the scrolling is performed
|
||||
*/
|
||||
public View getHostView();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,6 @@ import android.os.Message;
|
||||
import android.os.PowerManager;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.SystemProperties;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.provider.Settings;
|
||||
@@ -78,6 +77,7 @@ import com.android.systemui.RecentsComponent;
|
||||
import com.android.systemui.SearchPanelView;
|
||||
import com.android.systemui.SystemUI;
|
||||
import com.android.systemui.statusbar.phone.KeyguardTouchDelegate;
|
||||
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Locale;
|
||||
@@ -98,8 +98,6 @@ public abstract class BaseStatusBar extends SystemUI implements
|
||||
protected static final int MSG_HIDE_HEADS_UP = 1027;
|
||||
protected static final int MSG_ESCALATE_HEADS_UP = 1028;
|
||||
|
||||
public static final boolean ENABLE_NOTIFICATION_STACK = SystemProperties
|
||||
.getBoolean("persist.notifications.use_stack", false);
|
||||
protected static final boolean ENABLE_HEADS_UP = true;
|
||||
// scores above this threshold should be displayed in heads up mode.
|
||||
protected static final int INTERRUPTION_THRESHOLD = 10;
|
||||
@@ -120,7 +118,7 @@ public abstract class BaseStatusBar extends SystemUI implements
|
||||
|
||||
// all notifications
|
||||
protected NotificationData mNotificationData = new NotificationData();
|
||||
protected ViewGroup mPile;
|
||||
protected NotificationStackScrollLayout mStackScroller;
|
||||
|
||||
protected NotificationData.Entry mInterruptingNotificationEntry;
|
||||
protected long mInterruptingNotificationTime;
|
||||
@@ -1033,7 +1031,7 @@ public abstract class BaseStatusBar extends SystemUI implements
|
||||
}
|
||||
// Construct the expanded view.
|
||||
NotificationData.Entry entry = new NotificationData.Entry(key, notification, iconView);
|
||||
if (!inflateViews(entry, mPile)) {
|
||||
if (!inflateViews(entry, mStackScroller)) {
|
||||
handleNotificationError(key, notification, "Couldn't expand RemoteViews for: "
|
||||
+ notification);
|
||||
return null;
|
||||
|
||||
@@ -17,45 +17,51 @@
|
||||
package com.android.systemui.statusbar.phone;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.EventLog;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
|
||||
import com.android.systemui.EventLogTags;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.statusbar.GestureRecorder;
|
||||
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
|
||||
|
||||
public class NotificationPanelView extends PanelView {
|
||||
public static final boolean DEBUG_GESTURES = true;
|
||||
|
||||
Drawable mHandleBar;
|
||||
int mHandleBarHeight;
|
||||
View mHandleView;
|
||||
int mFingers;
|
||||
PhoneStatusBar mStatusBar;
|
||||
boolean mOkToFlip;
|
||||
private NotificationStackScrollLayout mNotificationStackScroller;
|
||||
private int[] mTempLocation = new int[2];
|
||||
private int[] mTempChildLocation = new int[2];
|
||||
private View mNotificationParent;
|
||||
|
||||
|
||||
public NotificationPanelView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public void setStatusBar(PhoneStatusBar bar) {
|
||||
if (mStatusBar != null) {
|
||||
mStatusBar.setOnFlipRunnable(null);
|
||||
}
|
||||
mStatusBar = bar;
|
||||
if (bar != null) {
|
||||
mStatusBar.setOnFlipRunnable(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
requestPanelHeightUpdate();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
|
||||
Resources resources = getContext().getResources();
|
||||
mHandleBar = resources.getDrawable(R.drawable.status_bar_close);
|
||||
mHandleBarHeight = resources.getDimensionPixelSize(R.dimen.close_handle_height);
|
||||
mHandleView = findViewById(R.id.handle);
|
||||
mNotificationStackScroller = (NotificationStackScrollLayout)
|
||||
findViewById(R.id.notification_stack_scroller);
|
||||
mNotificationParent = findViewById(R.id.notification_container_parent);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -80,61 +86,86 @@ public class NotificationPanelView extends PanelView {
|
||||
return super.dispatchPopulateAccessibilityEvent(event);
|
||||
}
|
||||
|
||||
// We draw the handle ourselves so that it's always glued to the bottom of the window.
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||
super.onLayout(changed, left, top, right, bottom);
|
||||
if (changed) {
|
||||
final int pl = getPaddingLeft();
|
||||
final int pr = getPaddingRight();
|
||||
mHandleBar.setBounds(pl, 0, getWidth() - pr, (int) mHandleBarHeight);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(Canvas canvas) {
|
||||
super.draw(canvas);
|
||||
final int off = (int) (getHeight() - mHandleBarHeight - getPaddingBottom());
|
||||
canvas.translate(0, off);
|
||||
mHandleBar.setState(mHandleView.getDrawableState());
|
||||
mHandleBar.draw(canvas);
|
||||
canvas.translate(0, -off);
|
||||
/**
|
||||
* Gets the relative position of a view on the screen in regard to this view.
|
||||
*
|
||||
* @param requestedView the view we want to find the relative position for
|
||||
* @return
|
||||
*/
|
||||
private int getRelativeTop(View requestedView) {
|
||||
getLocationOnScreen(mTempLocation);
|
||||
requestedView.getLocationOnScreen(mTempChildLocation);
|
||||
return mTempChildLocation[1] - mTempLocation[1];
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
if (DEBUG_GESTURES) {
|
||||
if (event.getActionMasked() != MotionEvent.ACTION_MOVE) {
|
||||
EventLog.writeEvent(EventLogTags.SYSUI_NOTIFICATIONPANEL_TOUCH,
|
||||
event.getActionMasked(), (int) event.getX(), (int) event.getY());
|
||||
}
|
||||
// TODO: Handle doublefinger swipe to notifications again. Look at history for a reference
|
||||
// implementation.
|
||||
return super.onTouchEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isScrolledToBottom() {
|
||||
if (!isInSettings()) {
|
||||
return mNotificationStackScroller.isScrolledToBottom();
|
||||
}
|
||||
if (PhoneStatusBar.SETTINGS_DRAG_SHORTCUT && mStatusBar.mHasFlipSettings) {
|
||||
switch (event.getActionMasked()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
mOkToFlip = getExpandedHeight() == 0;
|
||||
break;
|
||||
case MotionEvent.ACTION_POINTER_DOWN:
|
||||
if (mOkToFlip) {
|
||||
float miny = event.getY(0);
|
||||
float maxy = miny;
|
||||
for (int i=1; i<event.getPointerCount(); i++) {
|
||||
final float y = event.getY(i);
|
||||
if (y < miny) miny = y;
|
||||
if (y > maxy) maxy = y;
|
||||
}
|
||||
if (maxy - miny < mHandleBarHeight) {
|
||||
if (getMeasuredHeight() < mHandleBarHeight) {
|
||||
mStatusBar.switchToSettings();
|
||||
} else {
|
||||
mStatusBar.flipToSettings();
|
||||
}
|
||||
mOkToFlip = false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return super.isScrolledToBottom();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getMaxPanelHeight() {
|
||||
if (!isInSettings()) {
|
||||
int maxPanelHeight = super.getMaxPanelHeight();
|
||||
int emptyBottomMargin = mNotificationStackScroller.getEmptyBottomMargin();
|
||||
return maxPanelHeight - emptyBottomMargin;
|
||||
}
|
||||
return mHandleView.dispatchTouchEvent(event);
|
||||
return super.getMaxPanelHeight();
|
||||
}
|
||||
|
||||
private boolean isInSettings() {
|
||||
return mStatusBar != null && mStatusBar.isFlippedToSettings();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onHeightUpdated(float expandedHeight) {
|
||||
updateNotificationStackHeight(expandedHeight);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the height of the {@link #mNotificationStackScroller} to the new expanded height.
|
||||
* This is much more efficient than doing it over the layout pass.
|
||||
*
|
||||
* @param expandedHeight the new expanded height
|
||||
*/
|
||||
private void updateNotificationStackHeight(float expandedHeight) {
|
||||
float childOffset = getRelativeTop(mNotificationStackScroller)
|
||||
- mNotificationParent.getTranslationY();
|
||||
int newStackHeight = (int) (expandedHeight - childOffset);
|
||||
int itemHeight = mNotificationStackScroller.getItemHeight();
|
||||
int bottomStackPeekSize = mNotificationStackScroller.getBottomStackPeekSize();
|
||||
int minStackHeight = itemHeight + bottomStackPeekSize;
|
||||
if (newStackHeight >= minStackHeight) {
|
||||
mNotificationParent.setTranslationY(0);
|
||||
mNotificationStackScroller.setCurrentStackHeight(newStackHeight);
|
||||
} else {
|
||||
|
||||
// We did not reach the position yet where we actually start growing,
|
||||
// so we translate the stack upwards.
|
||||
int translationY = (newStackHeight - minStackHeight);
|
||||
// A slight parallax effect is introduced in order for the stack to catch up with
|
||||
// the top card.
|
||||
float partiallyThere = (float) newStackHeight / minStackHeight;
|
||||
partiallyThere = Math.max(0, partiallyThere);
|
||||
translationY += (1 - partiallyThere) * bottomStackPeekSize;
|
||||
mNotificationParent.setTranslationY(translationY);
|
||||
mNotificationStackScroller.setCurrentStackHeight(
|
||||
(int) (expandedHeight - (childOffset + translationY)));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getDesiredMeasureHeight() {
|
||||
return mMaxPanelHeight;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewConfiguration;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import com.android.systemui.R;
|
||||
@@ -69,7 +70,7 @@ public class PanelView extends FrameLayout {
|
||||
|
||||
private View mHandleView;
|
||||
private float mPeekHeight;
|
||||
private float mTouchOffset;
|
||||
private float mInitialOffsetOnTouch;
|
||||
private float mExpandedFraction = 0;
|
||||
private float mExpandedHeight = 0;
|
||||
private boolean mJustPeeked;
|
||||
@@ -77,6 +78,7 @@ public class PanelView extends FrameLayout {
|
||||
private boolean mRubberbanding;
|
||||
private boolean mTracking;
|
||||
private int mTrackingPointer;
|
||||
private int mTouchSlop;
|
||||
|
||||
private TimeAnimator mTimeAnimator;
|
||||
private ObjectAnimator mPeekAnimator;
|
||||
@@ -198,7 +200,6 @@ public class PanelView extends FrameLayout {
|
||||
}
|
||||
}
|
||||
|
||||
private int[] mAbsPos = new int[2];
|
||||
PanelBar mBar;
|
||||
|
||||
private final TimeListener mAnimationCallback = new TimeListener() {
|
||||
@@ -220,7 +221,7 @@ public class PanelView extends FrameLayout {
|
||||
};
|
||||
|
||||
private float mVel, mAccel;
|
||||
private int mFullHeight = 0;
|
||||
protected int mMaxPanelHeight = 0;
|
||||
private String mViewName;
|
||||
protected float mInitialTouchY;
|
||||
protected float mFinalTouchY;
|
||||
@@ -253,13 +254,13 @@ public class PanelView extends FrameLayout {
|
||||
mTimeAnimator.start();
|
||||
|
||||
mRubberbanding = mRubberbandingEnabled // is it enabled at all?
|
||||
&& mExpandedHeight > getFullHeight() // are we past the end?
|
||||
&& mExpandedHeight > getMaxPanelHeight() // are we past the end?
|
||||
&& mVel >= -mFlingGestureMinDistPx; // was this not possibly a "close" gesture?
|
||||
if (mRubberbanding) {
|
||||
mClosing = true;
|
||||
} else if (mVel == 0) {
|
||||
// if the panel is less than halfway open, close it
|
||||
mClosing = (mFinalTouchY / getFullHeight()) < 0.5f;
|
||||
mClosing = (mFinalTouchY / getMaxPanelHeight()) < 0.5f;
|
||||
} else {
|
||||
mClosing = mExpandedHeight > 0 && mVel < 0;
|
||||
}
|
||||
@@ -268,7 +269,7 @@ public class PanelView extends FrameLayout {
|
||||
if (DEBUG) logf("tick: v=%.2fpx/s dt=%.4fs", mVel, dt);
|
||||
if (DEBUG) logf("tick: before: h=%d", (int) mExpandedHeight);
|
||||
|
||||
final float fh = getFullHeight();
|
||||
final float fh = getMaxPanelHeight();
|
||||
boolean braking = false;
|
||||
if (BRAKES) {
|
||||
if (mClosing) {
|
||||
@@ -351,6 +352,9 @@ public class PanelView extends FrameLayout {
|
||||
mPeekHeight = res.getDimension(R.dimen.peek_height)
|
||||
+ getPaddingBottom() // our window might have a dropshadow
|
||||
- (mHandleView == null ? 0 : mHandleView.getPaddingTop()); // the handle might have a topshadow
|
||||
|
||||
final ViewConfiguration configuration = ViewConfiguration.get(getContext());
|
||||
mTouchSlop = configuration.getScaledTouchSlop();
|
||||
}
|
||||
|
||||
private void trackMovement(MotionEvent event) {
|
||||
@@ -363,10 +367,221 @@ public class PanelView extends FrameLayout {
|
||||
event.offsetLocation(-deltaX, -deltaY);
|
||||
}
|
||||
|
||||
// Pass all touches along to the handle, allowing the user to drag the panel closed from its interior
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
return mHandleView.dispatchTouchEvent(event);
|
||||
|
||||
/*
|
||||
* We capture touch events here and update the expand height here in case according to
|
||||
* the users fingers. This also handles multi-touch.
|
||||
*
|
||||
* If the user just clicks shortly, we give him a quick peek of the shade.
|
||||
*
|
||||
* Flinging is also enabled in order to open or close the shade.
|
||||
*/
|
||||
|
||||
int pointerIndex = event.findPointerIndex(mTrackingPointer);
|
||||
if (pointerIndex < 0) {
|
||||
pointerIndex = 0;
|
||||
mTrackingPointer = event.getPointerId(pointerIndex);
|
||||
}
|
||||
final float y = event.getY(pointerIndex);
|
||||
|
||||
switch (event.getActionMasked()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
mTracking = true;
|
||||
if (mHandleView != null) {
|
||||
mHandleView.setPressed(true);
|
||||
postInvalidate(); // catch the press state change
|
||||
}
|
||||
|
||||
mInitialTouchY = y;
|
||||
initVelocityTracker();
|
||||
trackMovement(event);
|
||||
mTimeAnimator.cancel(); // end any outstanding animations
|
||||
mBar.onTrackingStarted(PanelView.this);
|
||||
mInitialOffsetOnTouch = mExpandedHeight;
|
||||
if (mExpandedHeight == 0) {
|
||||
mJustPeeked = true;
|
||||
runPeekAnimation();
|
||||
}
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_POINTER_UP:
|
||||
final int upPointer = event.getPointerId(event.getActionIndex());
|
||||
if (mTrackingPointer == upPointer) {
|
||||
// gesture is ongoing, find a new pointer to track
|
||||
final int newIndex = event.getPointerId(0) != upPointer ? 0 : 1;
|
||||
final float newY = event.getY(newIndex);
|
||||
mTrackingPointer = event.getPointerId(newIndex);
|
||||
mInitialOffsetOnTouch = mExpandedHeight;
|
||||
mInitialTouchY = newY;
|
||||
}
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
final float h = y - mInitialTouchY + mInitialOffsetOnTouch;
|
||||
if (h > mPeekHeight) {
|
||||
if (mPeekAnimator != null && mPeekAnimator.isStarted()) {
|
||||
mPeekAnimator.cancel();
|
||||
}
|
||||
mJustPeeked = false;
|
||||
}
|
||||
if (!mJustPeeked) {
|
||||
setExpandedHeightInternal(h);
|
||||
mBar.panelExpansionChanged(PanelView.this, mExpandedFraction);
|
||||
}
|
||||
|
||||
trackMovement(event);
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_UP:
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
mFinalTouchY = y;
|
||||
mTracking = false;
|
||||
mTrackingPointer = -1;
|
||||
if (mHandleView != null) {
|
||||
mHandleView.setPressed(false);
|
||||
postInvalidate(); // catch the press state change
|
||||
}
|
||||
mBar.onTrackingStopped(PanelView.this);
|
||||
trackMovement(event);
|
||||
|
||||
float vel = getCurrentVelocity();
|
||||
fling(vel, true);
|
||||
|
||||
if (mVelocityTracker != null) {
|
||||
mVelocityTracker.recycle();
|
||||
mVelocityTracker = null;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private float getCurrentVelocity() {
|
||||
float vel = 0;
|
||||
float yVel = 0, xVel = 0;
|
||||
boolean negative = false;
|
||||
|
||||
// the velocitytracker might be null if we got a bad input stream
|
||||
if (mVelocityTracker == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
mVelocityTracker.computeCurrentVelocity(1000);
|
||||
|
||||
yVel = mVelocityTracker.getYVelocity();
|
||||
negative = yVel < 0;
|
||||
|
||||
xVel = mVelocityTracker.getXVelocity();
|
||||
if (xVel < 0) {
|
||||
xVel = -xVel;
|
||||
}
|
||||
if (xVel > mFlingGestureMaxXVelocityPx) {
|
||||
xVel = mFlingGestureMaxXVelocityPx; // limit how much we care about the x axis
|
||||
}
|
||||
|
||||
vel = (float) Math.hypot(yVel, xVel);
|
||||
if (vel > mFlingGestureMaxOutputVelocityPx) {
|
||||
vel = mFlingGestureMaxOutputVelocityPx;
|
||||
}
|
||||
|
||||
// if you've barely moved your finger, we treat the velocity as 0
|
||||
// preventing spurious flings due to touch screen jitter
|
||||
final float deltaY = Math.abs(mFinalTouchY - mInitialTouchY);
|
||||
if (deltaY < mFlingGestureMinDistPx
|
||||
|| vel < mFlingExpandMinVelocityPx
|
||||
) {
|
||||
vel = 0;
|
||||
}
|
||||
|
||||
if (negative) {
|
||||
vel = -vel;
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
logf("gesture: dy=%f vel=(%f,%f) vlinear=%f",
|
||||
deltaY,
|
||||
xVel, yVel,
|
||||
vel);
|
||||
}
|
||||
return vel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onInterceptTouchEvent(MotionEvent event) {
|
||||
|
||||
/*
|
||||
* If the user drags anywhere inside the panel we intercept it if he moves his finger
|
||||
* upwards. This allows closing the shade from anywhere inside the panel.
|
||||
*
|
||||
* We only do this if the current content is scrolled to the bottom,
|
||||
* i.e isScrolledToBottom() is true and therefore there is no conflicting scrolling gesture
|
||||
* possible.
|
||||
*/
|
||||
int pointerIndex = event.findPointerIndex(mTrackingPointer);
|
||||
if (pointerIndex < 0) {
|
||||
pointerIndex = 0;
|
||||
mTrackingPointer = event.getPointerId(pointerIndex);
|
||||
}
|
||||
final float y = event.getY(pointerIndex);
|
||||
boolean scrolledToBottom = isScrolledToBottom();
|
||||
|
||||
switch (event.getActionMasked()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
mTracking = true;
|
||||
if (mHandleView != null) {
|
||||
mHandleView.setPressed(true);
|
||||
// catch the press state change
|
||||
postInvalidate();
|
||||
}
|
||||
mInitialTouchY = y;
|
||||
initVelocityTracker();
|
||||
trackMovement(event);
|
||||
mTimeAnimator.cancel(); // end any outstanding animations
|
||||
if (mExpandedHeight == 0 || y > getContentHeight()) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case MotionEvent.ACTION_POINTER_UP:
|
||||
final int upPointer = event.getPointerId(event.getActionIndex());
|
||||
if (mTrackingPointer == upPointer) {
|
||||
// gesture is ongoing, find a new pointer to track
|
||||
final int newIndex = event.getPointerId(0) != upPointer ? 0 : 1;
|
||||
mTrackingPointer = event.getPointerId(newIndex);
|
||||
final float newY = event.getY(newIndex);
|
||||
mInitialTouchY = newY;
|
||||
}
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
final float h = y - mInitialTouchY;
|
||||
trackMovement(event);
|
||||
if (scrolledToBottom) {
|
||||
if (h < -mTouchSlop) {
|
||||
mInitialOffsetOnTouch = mExpandedHeight;
|
||||
mInitialTouchY = y;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void initVelocityTracker() {
|
||||
if (mVelocityTracker != null) {
|
||||
mVelocityTracker.recycle();
|
||||
}
|
||||
mVelocityTracker = FlingTracker.obtain();
|
||||
}
|
||||
|
||||
protected boolean isScrolledToBottom() {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected float getContentHeight() {
|
||||
return mExpandedHeight;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -375,134 +590,6 @@ public class PanelView extends FrameLayout {
|
||||
mHandleView = findViewById(R.id.handle);
|
||||
|
||||
loadDimens();
|
||||
|
||||
if (DEBUG) logf("handle view: " + mHandleView);
|
||||
if (mHandleView != null) {
|
||||
mHandleView.setOnTouchListener(new View.OnTouchListener() {
|
||||
@Override
|
||||
public boolean onTouch(View v, MotionEvent event) {
|
||||
int pointerIndex = event.findPointerIndex(mTrackingPointer);
|
||||
if (pointerIndex < 0) {
|
||||
pointerIndex = 0;
|
||||
mTrackingPointer = event.getPointerId(pointerIndex);
|
||||
}
|
||||
final float y = event.getY(pointerIndex);
|
||||
final float rawDelta = event.getRawY() - event.getY();
|
||||
final float rawY = y + rawDelta;
|
||||
if (DEBUG) logf("handle.onTouch: a=%s p=[%d,%d] y=%.1f rawY=%.1f off=%.1f",
|
||||
MotionEvent.actionToString(event.getAction()),
|
||||
mTrackingPointer, pointerIndex,
|
||||
y, rawY, mTouchOffset);
|
||||
PanelView.this.getLocationOnScreen(mAbsPos);
|
||||
|
||||
switch (event.getActionMasked()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
mTracking = true;
|
||||
mHandleView.setPressed(true);
|
||||
postInvalidate(); // catch the press state change
|
||||
mInitialTouchY = y;
|
||||
mVelocityTracker = FlingTracker.obtain();
|
||||
trackMovement(event);
|
||||
mTimeAnimator.cancel(); // end any outstanding animations
|
||||
mBar.onTrackingStarted(PanelView.this);
|
||||
mTouchOffset = (rawY - mAbsPos[1]) - mExpandedHeight;
|
||||
if (mExpandedHeight == 0) {
|
||||
mJustPeeked = true;
|
||||
runPeekAnimation();
|
||||
}
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_POINTER_UP:
|
||||
final int upPointer = event.getPointerId(event.getActionIndex());
|
||||
if (mTrackingPointer == upPointer) {
|
||||
// gesture is ongoing, find a new pointer to track
|
||||
final int newIndex = event.getPointerId(0) != upPointer ? 0 : 1;
|
||||
final float newY = event.getY(newIndex);
|
||||
final float newRawY = newY + rawDelta;
|
||||
mTrackingPointer = event.getPointerId(newIndex);
|
||||
mTouchOffset = (newRawY - mAbsPos[1]) - mExpandedHeight;
|
||||
mInitialTouchY = newY;
|
||||
}
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
final float h = rawY - mAbsPos[1] - mTouchOffset;
|
||||
if (h > mPeekHeight) {
|
||||
if (mPeekAnimator != null && mPeekAnimator.isStarted()) {
|
||||
mPeekAnimator.cancel();
|
||||
}
|
||||
mJustPeeked = false;
|
||||
}
|
||||
if (!mJustPeeked) {
|
||||
PanelView.this.setExpandedHeightInternal(h);
|
||||
mBar.panelExpansionChanged(PanelView.this, mExpandedFraction);
|
||||
}
|
||||
|
||||
trackMovement(event);
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_UP:
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
mFinalTouchY = y;
|
||||
mTracking = false;
|
||||
mTrackingPointer = -1;
|
||||
mHandleView.setPressed(false);
|
||||
postInvalidate(); // catch the press state change
|
||||
mBar.onTrackingStopped(PanelView.this);
|
||||
trackMovement(event);
|
||||
|
||||
float vel = 0, yVel = 0, xVel = 0;
|
||||
boolean negative = false;
|
||||
|
||||
if (mVelocityTracker != null) {
|
||||
// the velocitytracker might be null if we got a bad input stream
|
||||
mVelocityTracker.computeCurrentVelocity(1000);
|
||||
|
||||
yVel = mVelocityTracker.getYVelocity();
|
||||
negative = yVel < 0;
|
||||
|
||||
xVel = mVelocityTracker.getXVelocity();
|
||||
if (xVel < 0) {
|
||||
xVel = -xVel;
|
||||
}
|
||||
if (xVel > mFlingGestureMaxXVelocityPx) {
|
||||
xVel = mFlingGestureMaxXVelocityPx; // limit how much we care about the x axis
|
||||
}
|
||||
|
||||
vel = (float)Math.hypot(yVel, xVel);
|
||||
if (vel > mFlingGestureMaxOutputVelocityPx) {
|
||||
vel = mFlingGestureMaxOutputVelocityPx;
|
||||
}
|
||||
|
||||
mVelocityTracker.recycle();
|
||||
mVelocityTracker = null;
|
||||
}
|
||||
|
||||
// if you've barely moved your finger, we treat the velocity as 0
|
||||
// preventing spurious flings due to touch screen jitter
|
||||
final float deltaY = Math.abs(mFinalTouchY - mInitialTouchY);
|
||||
if (deltaY < mFlingGestureMinDistPx
|
||||
|| vel < mFlingExpandMinVelocityPx
|
||||
) {
|
||||
vel = 0;
|
||||
}
|
||||
|
||||
if (negative) {
|
||||
vel = -vel;
|
||||
}
|
||||
|
||||
if (DEBUG) logf("gesture: dy=%f vel=(%f,%f) vlinear=%f",
|
||||
deltaY,
|
||||
xVel, yVel,
|
||||
vel);
|
||||
|
||||
fling(vel, true);
|
||||
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}});
|
||||
}
|
||||
}
|
||||
|
||||
public void fling(float vel, boolean always) {
|
||||
@@ -543,19 +630,18 @@ public class PanelView extends FrameLayout {
|
||||
|
||||
// Did one of our children change size?
|
||||
int newHeight = getMeasuredHeight();
|
||||
if (newHeight != mFullHeight) {
|
||||
mFullHeight = newHeight;
|
||||
// If the user isn't actively poking us, let's rubberband to the content
|
||||
if (!mTracking && !mRubberbanding && !mTimeAnimator.isStarted()
|
||||
&& mExpandedHeight > 0 && mExpandedHeight != mFullHeight) {
|
||||
mExpandedHeight = mFullHeight;
|
||||
}
|
||||
if (newHeight != mMaxPanelHeight) {
|
||||
mMaxPanelHeight = newHeight;
|
||||
}
|
||||
heightMeasureSpec = MeasureSpec.makeMeasureSpec(
|
||||
(int) mExpandedHeight, MeasureSpec.AT_MOST); // MeasureSpec.getMode(heightMeasureSpec));
|
||||
getDesiredMeasureHeight(), MeasureSpec.AT_MOST);
|
||||
setMeasuredDimension(widthMeasureSpec, heightMeasureSpec);
|
||||
}
|
||||
|
||||
protected int getDesiredMeasureHeight() {
|
||||
return (int) mExpandedHeight;
|
||||
}
|
||||
|
||||
|
||||
public void setExpandedHeight(float height) {
|
||||
if (DEBUG) logf("setExpandedHeight(%.1f)", height);
|
||||
@@ -569,8 +655,20 @@ public class PanelView extends FrameLayout {
|
||||
|
||||
@Override
|
||||
protected void onLayout (boolean changed, int left, int top, int right, int bottom) {
|
||||
if (DEBUG) logf("onLayout: changed=%s, bottom=%d eh=%d fh=%d", changed?"T":"f", bottom, (int)mExpandedHeight, mFullHeight);
|
||||
if (DEBUG) logf("onLayout: changed=%s, bottom=%d eh=%d fh=%d", changed?"T":"f", bottom,
|
||||
(int)mExpandedHeight, mMaxPanelHeight);
|
||||
super.onLayout(changed, left, top, right, bottom);
|
||||
requestPanelHeightUpdate();
|
||||
}
|
||||
|
||||
protected void requestPanelHeightUpdate() {
|
||||
float currentMaxPanelHeight = getMaxPanelHeight();
|
||||
|
||||
// If the user isn't actively poking us, let's update the height
|
||||
if (!mTracking && !mRubberbanding && !mTimeAnimator.isStarted()
|
||||
&& mExpandedHeight > 0 && currentMaxPanelHeight != mExpandedHeight) {
|
||||
setExpandedHeightInternal(currentMaxPanelHeight);
|
||||
}
|
||||
}
|
||||
|
||||
public void setExpandedHeightInternal(float h) {
|
||||
@@ -583,7 +681,7 @@ public class PanelView extends FrameLayout {
|
||||
h = 0;
|
||||
}
|
||||
|
||||
float fh = getFullHeight();
|
||||
float fh = getMaxPanelHeight();
|
||||
if (fh == 0) {
|
||||
// Hmm, full height hasn't been computed yet
|
||||
}
|
||||
@@ -593,9 +691,13 @@ public class PanelView extends FrameLayout {
|
||||
|
||||
mExpandedHeight = h;
|
||||
|
||||
if (DEBUG) logf("setExpansion: height=%.1f fh=%.1f tracking=%s rubber=%s", h, fh, mTracking?"T":"f", mRubberbanding?"T":"f");
|
||||
if (DEBUG) {
|
||||
logf("setExpansion: height=%.1f fh=%.1f tracking=%s rubber=%s", h, fh,
|
||||
mTracking ? "T" : "f", mRubberbanding ? "T" : "f");
|
||||
}
|
||||
|
||||
onHeightUpdated(mExpandedHeight);
|
||||
|
||||
requestLayout();
|
||||
// FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
|
||||
// lp.height = (int) mExpandedHeight;
|
||||
// setLayoutParams(lp);
|
||||
@@ -603,13 +705,23 @@ public class PanelView extends FrameLayout {
|
||||
mExpandedFraction = Math.min(1f, (fh == 0) ? 0 : h / fh);
|
||||
}
|
||||
|
||||
private float getFullHeight() {
|
||||
if (mFullHeight <= 0) {
|
||||
if (DEBUG) logf("Forcing measure() since fullHeight=" + mFullHeight);
|
||||
protected void onHeightUpdated(float expandedHeight) {
|
||||
requestLayout();
|
||||
}
|
||||
|
||||
/**
|
||||
* This returns the maximum height of the panel. Children should override this if their
|
||||
* desired height is not the full height.
|
||||
*
|
||||
* @return the default implementation simply returns the maximum height.
|
||||
*/
|
||||
protected int getMaxPanelHeight() {
|
||||
if (mMaxPanelHeight <= 0) {
|
||||
if (DEBUG) logf("Forcing measure() since mMaxPanelHeight=" + mMaxPanelHeight);
|
||||
measure(MeasureSpec.makeMeasureSpec(android.view.ViewGroup.LayoutParams.WRAP_CONTENT, MeasureSpec.EXACTLY),
|
||||
MeasureSpec.makeMeasureSpec(android.view.ViewGroup.LayoutParams.WRAP_CONTENT, MeasureSpec.EXACTLY));
|
||||
}
|
||||
return mFullHeight;
|
||||
return mMaxPanelHeight;
|
||||
}
|
||||
|
||||
public void setExpandedFraction(float frac) {
|
||||
@@ -621,7 +733,7 @@ public class PanelView extends FrameLayout {
|
||||
}
|
||||
frac = 0;
|
||||
}
|
||||
setExpandedHeight(getFullHeight() * frac);
|
||||
setExpandedHeight(getMaxPanelHeight() * frac);
|
||||
}
|
||||
|
||||
public float getExpandedHeight() {
|
||||
@@ -633,7 +745,7 @@ public class PanelView extends FrameLayout {
|
||||
}
|
||||
|
||||
public boolean isFullyExpanded() {
|
||||
return mExpandedHeight >= getFullHeight();
|
||||
return mExpandedHeight >= getMaxPanelHeight();
|
||||
}
|
||||
|
||||
public boolean isFullyCollapsed() {
|
||||
@@ -681,12 +793,12 @@ public class PanelView extends FrameLayout {
|
||||
}
|
||||
|
||||
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
|
||||
pw.println(String.format("[PanelView(%s): expandedHeight=%f fullHeight=%f closing=%s"
|
||||
pw.println(String.format("[PanelView(%s): expandedHeight=%f maxPanelHeight=%f closing=%s"
|
||||
+ " tracking=%s rubberbanding=%s justPeeked=%s peekAnim=%s%s timeAnim=%s%s"
|
||||
+ "]",
|
||||
this.getClass().getSimpleName(),
|
||||
getExpandedHeight(),
|
||||
getFullHeight(),
|
||||
getMaxPanelHeight(),
|
||||
mClosing?"T":"f",
|
||||
mTracking?"T":"f",
|
||||
mRubberbanding?"T":"f",
|
||||
|
||||
@@ -86,7 +86,6 @@ import com.android.internal.statusbar.StatusBarIcon;
|
||||
import com.android.systemui.DemoMode;
|
||||
import com.android.systemui.EventLogTags;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.SwipeHelper;
|
||||
import com.android.systemui.statusbar.BaseStatusBar;
|
||||
import com.android.systemui.statusbar.CommandQueue;
|
||||
import com.android.systemui.statusbar.GestureRecorder;
|
||||
@@ -101,8 +100,6 @@ import com.android.systemui.statusbar.policy.DateView;
|
||||
import com.android.systemui.statusbar.policy.HeadsUpNotificationView;
|
||||
import com.android.systemui.statusbar.policy.LocationController;
|
||||
import com.android.systemui.statusbar.policy.NetworkController;
|
||||
import com.android.systemui.statusbar.policy.NotificationRowLayout;
|
||||
import com.android.systemui.statusbar.policy.OnSizeChangedListener;
|
||||
import com.android.systemui.statusbar.policy.RotationLockController;
|
||||
|
||||
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
|
||||
@@ -172,7 +169,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
|
||||
Display mDisplay;
|
||||
Point mCurrentDisplaySize = new Point();
|
||||
private float mHeadsUpVerticalOffset;
|
||||
private int[] mPilePosition = new int[2];
|
||||
private int[] mStackScrollerPosition = new int[2];
|
||||
|
||||
StatusBarWindowView mStatusBarWindow;
|
||||
PhoneStatusBarView mStatusBarView;
|
||||
@@ -198,7 +195,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
|
||||
|
||||
// expanded notifications
|
||||
NotificationPanelView mNotificationPanel; // the sliding/resizing panel within the notification window
|
||||
View mNotificationScroller;
|
||||
View mExpandedContents;
|
||||
int mNotificationPanelGravity;
|
||||
int mNotificationPanelMarginBottomPx, mNotificationPanelMarginPx;
|
||||
@@ -350,6 +346,12 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
|
||||
}
|
||||
}};
|
||||
|
||||
private Runnable mOnFlipRunnable;
|
||||
|
||||
public void setOnFlipRunnable(Runnable onFlipRunnable) {
|
||||
mOnFlipRunnable = onFlipRunnable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setZenMode(int mode) {
|
||||
super.setZenMode(mode);
|
||||
@@ -417,7 +419,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
|
||||
PanelHolder holder = (PanelHolder) mStatusBarWindow.findViewById(R.id.panel_holder);
|
||||
mStatusBarView.setPanelHolder(holder);
|
||||
|
||||
mNotificationPanel = (NotificationPanelView) mStatusBarWindow.findViewById(R.id.notification_panel);
|
||||
mNotificationPanel = (NotificationPanelView) mStatusBarWindow.findViewById(
|
||||
R.id.notification_panel);
|
||||
mNotificationPanel.setStatusBar(this);
|
||||
mNotificationPanelIsFullScreenWidth =
|
||||
(mNotificationPanel.getLayoutParams().width == ViewGroup.LayoutParams.MATCH_PARENT);
|
||||
@@ -443,7 +446,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
|
||||
mHeadsUpNotificationView.setBar(this);
|
||||
}
|
||||
if (MULTIUSER_DEBUG) {
|
||||
mNotificationPanelDebugText = (TextView) mNotificationPanel.findViewById(R.id.header_debug_info);
|
||||
mNotificationPanelDebugText = (TextView) mNotificationPanel.findViewById(
|
||||
R.id.header_debug_info);
|
||||
mNotificationPanelDebugText.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
@@ -482,33 +486,11 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
|
||||
mStatusBarContents = (LinearLayout)mStatusBarView.findViewById(R.id.status_bar_contents);
|
||||
mTickerView = mStatusBarView.findViewById(R.id.ticker);
|
||||
|
||||
View legacyScrollView = mStatusBarWindow.findViewById(R.id.scroll);
|
||||
NotificationStackScrollLayout notificationStack
|
||||
= (NotificationStackScrollLayout) mStatusBarWindow
|
||||
.findViewById(R.id.notification_stack_scroller);
|
||||
if (ENABLE_NOTIFICATION_STACK) {
|
||||
notificationStack.setLongPressListener(getNotificationLongClicker());
|
||||
mPile = notificationStack;
|
||||
legacyScrollView.setVisibility(View.GONE);
|
||||
|
||||
// The scrollview and the notification container are unified now!
|
||||
// TODO: remove mNotificationScroller entirely once we fully switch to the new Layout
|
||||
mNotificationScroller = notificationStack;
|
||||
} else {
|
||||
mNotificationScroller = legacyScrollView;
|
||||
// less drawing during pulldowns
|
||||
mNotificationScroller.setVerticalScrollBarEnabled(false);
|
||||
NotificationRowLayout rowLayout
|
||||
= (NotificationRowLayout) mStatusBarWindow.findViewById(R.id.latestItems);
|
||||
rowLayout.setLayoutTransitionsEnabled(false);
|
||||
rowLayout.setLongPressListener(getNotificationLongClicker());
|
||||
mPile = rowLayout;
|
||||
notificationStack.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
mExpandedContents = mPile; // was: expanded.findViewById(R.id.notificationLinearLayout);
|
||||
|
||||
mStackScroller = (NotificationStackScrollLayout) mStatusBarWindow.findViewById(
|
||||
R.id.notification_stack_scroller);
|
||||
mStackScroller.setLongPressListener(getNotificationLongClicker());
|
||||
|
||||
mExpandedContents = mStackScroller;
|
||||
|
||||
mNotificationPanelHeader = mStatusBarWindow.findViewById(R.id.header);
|
||||
|
||||
@@ -551,7 +533,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
|
||||
}
|
||||
}
|
||||
if (mHasFlipSettings) {
|
||||
mNotificationButton = (ImageView) mStatusBarWindow.findViewById(R.id.notification_button);
|
||||
mNotificationButton = (ImageView) mStatusBarWindow.findViewById(
|
||||
R.id.notification_button);
|
||||
if (mNotificationButton != null) {
|
||||
mNotificationButton.setOnClickListener(mNotificationButtonListener);
|
||||
}
|
||||
@@ -593,17 +576,18 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
|
||||
if (isAPhone) {
|
||||
mEmergencyCallLabel =
|
||||
(TextView) mStatusBarWindow.findViewById(R.id.emergency_calls_only);
|
||||
if (mEmergencyCallLabel != null) {
|
||||
mNetworkController.addEmergencyLabelView(mEmergencyCallLabel);
|
||||
mEmergencyCallLabel.setOnClickListener(new View.OnClickListener() {
|
||||
public void onClick(View v) { }});
|
||||
mEmergencyCallLabel.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
|
||||
@Override
|
||||
public void onLayoutChange(View v, int left, int top, int right, int bottom,
|
||||
int oldLeft, int oldTop, int oldRight, int oldBottom) {
|
||||
updateCarrierLabelVisibility(false);
|
||||
}});
|
||||
}
|
||||
// TODO: Uncomment when correctly positioned
|
||||
// if (mEmergencyCallLabel != null) {
|
||||
// mNetworkController.addEmergencyLabelView(mEmergencyCallLabel);
|
||||
// mEmergencyCallLabel.setOnClickListener(new View.OnClickListener() {
|
||||
// public void onClick(View v) { }});
|
||||
// mEmergencyCallLabel.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
|
||||
// @Override
|
||||
// public void onLayoutChange(View v, int left, int top, int right, int bottom,
|
||||
// int oldLeft, int oldTop, int oldRight, int oldBottom) {
|
||||
// updateCarrierLabelVisibility(false);
|
||||
// }});
|
||||
// }
|
||||
}
|
||||
|
||||
mCarrierLabel = (TextView)mStatusBarWindow.findViewById(R.id.carrier_label);
|
||||
@@ -621,13 +605,12 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
|
||||
}
|
||||
|
||||
// set up the dynamic hide/show of the label
|
||||
if (!ENABLE_NOTIFICATION_STACK)
|
||||
((NotificationRowLayout) mPile).setOnSizeChangedListener(new OnSizeChangedListener() {
|
||||
@Override
|
||||
public void onSizeChanged(View view, int w, int h, int oldw, int oldh) {
|
||||
updateCarrierLabelVisibility(false);
|
||||
}
|
||||
});
|
||||
// TODO: uncomment, handle this for the Stack scroller aswell
|
||||
// ((NotificationRowLayout) mStackScroller)
|
||||
// .setOnSizeChangedListener(new OnSizeChangedListener() {
|
||||
// @Override
|
||||
// public void onSizeChanged(View view, int w, int h, int oldw, int oldh) {
|
||||
// updateCarrierLabelVisibility(false);
|
||||
}
|
||||
|
||||
// Quick Settings (where available, some restrictions apply)
|
||||
@@ -1066,7 +1049,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
|
||||
}
|
||||
|
||||
private void loadNotificationShade() {
|
||||
if (mPile == null) return;
|
||||
if (mStackScroller == null) return;
|
||||
|
||||
int N = mNotificationData.size();
|
||||
|
||||
@@ -1092,21 +1075,21 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
|
||||
}
|
||||
|
||||
ArrayList<View> toRemove = new ArrayList<View>();
|
||||
for (int i=0; i<mPile.getChildCount(); i++) {
|
||||
View child = mPile.getChildAt(i);
|
||||
for (int i=0; i< mStackScroller.getChildCount(); i++) {
|
||||
View child = mStackScroller.getChildAt(i);
|
||||
if (!toShow.contains(child)) {
|
||||
toRemove.add(child);
|
||||
}
|
||||
}
|
||||
|
||||
for (View remove : toRemove) {
|
||||
mPile.removeView(remove);
|
||||
mStackScroller.removeView(remove);
|
||||
}
|
||||
|
||||
for (int i=0; i<toShow.size(); i++) {
|
||||
View v = toShow.get(i);
|
||||
if (v.getParent() == null) {
|
||||
mPile.addView(v, i);
|
||||
mStackScroller.addView(v, i);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1178,15 +1161,17 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
|
||||
// The idea here is to only show the carrier label when there is enough room to see it,
|
||||
// i.e. when there aren't enough notifications to fill the panel.
|
||||
if (SPEW) {
|
||||
Log.d(TAG, String.format("pileh=%d scrollh=%d carrierh=%d",
|
||||
mPile.getHeight(), mNotificationScroller.getHeight(), mCarrierLabelHeight));
|
||||
Log.d(TAG, String.format("stackScrollerh=%d scrollh=%d carrierh=%d",
|
||||
mStackScroller.getHeight(), mStackScroller.getHeight(),
|
||||
mCarrierLabelHeight));
|
||||
}
|
||||
|
||||
final boolean emergencyCallsShownElsewhere = mEmergencyCallLabel != null;
|
||||
final boolean makeVisible =
|
||||
!(emergencyCallsShownElsewhere && mNetworkController.isEmergencyOnly())
|
||||
&& mPile.getHeight() < (mNotificationPanel.getHeight() - mCarrierLabelHeight - mNotificationHeaderHeight)
|
||||
&& mNotificationScroller.getVisibility() == View.VISIBLE;
|
||||
&& mStackScroller.getHeight() < (mNotificationPanel.getHeight()
|
||||
- mCarrierLabelHeight - mNotificationHeaderHeight)
|
||||
&& mStackScroller.getVisibility() == View.VISIBLE;
|
||||
|
||||
if (force || mCarrierLabelVisible != makeVisible) {
|
||||
mCarrierLabelVisible = makeVisible;
|
||||
@@ -1229,7 +1214,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
|
||||
if (mHasFlipSettings
|
||||
&& mFlipSettingsView != null
|
||||
&& mFlipSettingsView.getVisibility() == View.VISIBLE
|
||||
&& mNotificationScroller.getVisibility() != View.VISIBLE) {
|
||||
&& mStackScroller.getVisibility() != View.VISIBLE) {
|
||||
// the flip settings panel is unequivocally showing; we should not be shown
|
||||
mClearButton.setVisibility(View.INVISIBLE);
|
||||
} else if (mClearButton.isShown()) {
|
||||
@@ -1483,9 +1468,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
|
||||
}
|
||||
|
||||
mExpandedVisible = true;
|
||||
if (!ENABLE_NOTIFICATION_STACK) {
|
||||
((NotificationRowLayout) mPile).setLayoutTransitionsEnabled(true);
|
||||
}
|
||||
if (mNavigationBarView != null)
|
||||
mNavigationBarView.setSlippery(true);
|
||||
|
||||
@@ -1600,7 +1582,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
|
||||
}
|
||||
|
||||
mNotificationPanel.expand();
|
||||
if (mHasFlipSettings && mNotificationScroller.getVisibility() != View.VISIBLE) {
|
||||
if (mHasFlipSettings && mStackScroller.getVisibility() != View.VISIBLE) {
|
||||
flipToNotifications();
|
||||
}
|
||||
|
||||
@@ -1614,11 +1596,11 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
|
||||
if (mNotificationButtonAnim != null) mNotificationButtonAnim.cancel();
|
||||
if (mClearButtonAnim != null) mClearButtonAnim.cancel();
|
||||
|
||||
mNotificationScroller.setVisibility(View.VISIBLE);
|
||||
mStackScroller.setVisibility(View.VISIBLE);
|
||||
mScrollViewAnim = start(
|
||||
startDelay(FLIP_DURATION_OUT,
|
||||
interpolator(mDecelerateInterpolator,
|
||||
ObjectAnimator.ofFloat(mNotificationScroller, View.SCALE_X, 0f, 1f)
|
||||
ObjectAnimator.ofFloat(mStackScroller, View.SCALE_X, 0f, 1f)
|
||||
.setDuration(FLIP_DURATION_IN)
|
||||
)));
|
||||
mFlipSettingsViewAnim = start(
|
||||
@@ -1645,6 +1627,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
|
||||
updateCarrierLabelVisibility(false);
|
||||
}
|
||||
}, FLIP_DURATION - 150);
|
||||
if (mOnFlipRunnable != null) {
|
||||
mOnFlipRunnable.run();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1676,11 +1661,21 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
|
||||
mFlipSettingsView.setScaleX(1f);
|
||||
mFlipSettingsView.setVisibility(View.VISIBLE);
|
||||
mSettingsButton.setVisibility(View.GONE);
|
||||
mNotificationScroller.setVisibility(View.GONE);
|
||||
mNotificationScroller.setScaleX(0f);
|
||||
mStackScroller.setVisibility(View.GONE);
|
||||
mStackScroller.setScaleX(0f);
|
||||
mNotificationButton.setVisibility(View.VISIBLE);
|
||||
mNotificationButton.setAlpha(1f);
|
||||
mClearButton.setVisibility(View.GONE);
|
||||
if (mOnFlipRunnable != null) {
|
||||
mOnFlipRunnable.run();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isFlippedToSettings() {
|
||||
if (mFlipSettingsView != null) {
|
||||
return mFlipSettingsView.getVisibility() == View.VISIBLE;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void flipToSettings() {
|
||||
@@ -1704,15 +1699,15 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
|
||||
mScrollViewAnim = start(
|
||||
setVisibilityWhenDone(
|
||||
interpolator(mAccelerateInterpolator,
|
||||
ObjectAnimator.ofFloat(mNotificationScroller, View.SCALE_X, 1f, 0f)
|
||||
ObjectAnimator.ofFloat(mStackScroller, View.SCALE_X, 1f, 0f)
|
||||
)
|
||||
.setDuration(FLIP_DURATION_OUT),
|
||||
mNotificationScroller, View.INVISIBLE));
|
||||
mStackScroller, View.INVISIBLE));
|
||||
mSettingsButtonAnim = start(
|
||||
setVisibilityWhenDone(
|
||||
ObjectAnimator.ofFloat(mSettingsButton, View.ALPHA, 0f)
|
||||
.setDuration(FLIP_DURATION),
|
||||
mNotificationScroller, View.INVISIBLE));
|
||||
mStackScroller, View.INVISIBLE));
|
||||
mNotificationButton.setVisibility(View.VISIBLE);
|
||||
mNotificationButtonAnim = start(
|
||||
ObjectAnimator.ofFloat(mNotificationButton, View.ALPHA, 1f)
|
||||
@@ -1727,6 +1722,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
|
||||
updateCarrierLabelVisibility(false);
|
||||
}
|
||||
}, FLIP_DURATION - 150);
|
||||
if (mOnFlipRunnable != null) {
|
||||
mOnFlipRunnable.run();
|
||||
}
|
||||
}
|
||||
|
||||
public void flipPanels() {
|
||||
@@ -1766,8 +1764,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
|
||||
if (mNotificationButtonAnim != null) mNotificationButtonAnim.cancel();
|
||||
if (mClearButtonAnim != null) mClearButtonAnim.cancel();
|
||||
|
||||
mNotificationScroller.setScaleX(1f);
|
||||
mNotificationScroller.setVisibility(View.VISIBLE);
|
||||
mStackScroller.setScaleX(1f);
|
||||
mStackScroller.setVisibility(View.VISIBLE);
|
||||
mSettingsButton.setAlpha(1f);
|
||||
mSettingsButton.setVisibility(View.VISIBLE);
|
||||
mNotificationPanel.setVisibility(View.GONE);
|
||||
@@ -1777,9 +1775,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
|
||||
}
|
||||
|
||||
mExpandedVisible = false;
|
||||
if (!ENABLE_NOTIFICATION_STACK) {
|
||||
((NotificationRowLayout) mPile).setLayoutTransitionsEnabled(false);
|
||||
}
|
||||
if (mNavigationBarView != null)
|
||||
mNavigationBarView.setSlippery(false);
|
||||
visibilityChanged(false);
|
||||
@@ -1806,53 +1801,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
|
||||
setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables or disables layers on the children of the notifications pile.
|
||||
*
|
||||
* When layers are enabled, this method attempts to enable layers for the minimal
|
||||
* number of children. Only children visible when the notification area is fully
|
||||
* expanded will receive a layer. The technique used in this method might cause
|
||||
* more children than necessary to get a layer (at most one extra child with the
|
||||
* current UI.)
|
||||
*
|
||||
* @param layerType {@link View#LAYER_TYPE_NONE} or {@link View#LAYER_TYPE_HARDWARE}
|
||||
*/
|
||||
private void setPileLayers(int layerType) {
|
||||
final int count = mPile.getChildCount();
|
||||
|
||||
switch (layerType) {
|
||||
case View.LAYER_TYPE_NONE:
|
||||
for (int i = 0; i < count; i++) {
|
||||
mPile.getChildAt(i).setLayerType(layerType, null);
|
||||
}
|
||||
break;
|
||||
case View.LAYER_TYPE_HARDWARE:
|
||||
final int[] location = new int[2];
|
||||
mNotificationPanel.getLocationInWindow(location);
|
||||
|
||||
final int left = location[0];
|
||||
final int top = location[1];
|
||||
final int right = left + mNotificationPanel.getWidth();
|
||||
final int bottom = top + getExpandedViewMaxHeight();
|
||||
|
||||
final Rect childBounds = new Rect();
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
final View view = mPile.getChildAt(i);
|
||||
view.getLocationInWindow(location);
|
||||
|
||||
childBounds.set(location[0], location[1],
|
||||
location[0] + view.getWidth(), location[1] + view.getHeight());
|
||||
|
||||
if (childBounds.intersects(left, top, right, bottom)) {
|
||||
view.setLayerType(layerType, null);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean interceptTouchEvent(MotionEvent event) {
|
||||
if (DEBUG_GESTURES) {
|
||||
if (event.getActionMasked() != MotionEvent.ACTION_MOVE) {
|
||||
@@ -2230,11 +2178,11 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
|
||||
pw.println(" mTicking=" + mTicking);
|
||||
pw.println(" mTracking=" + mTracking);
|
||||
pw.println(" mDisplayMetrics=" + mDisplayMetrics);
|
||||
pw.println(" mPile: " + viewInfo(mPile));
|
||||
pw.println(" mStackScroller: " + viewInfo(mStackScroller));
|
||||
pw.println(" mTickerView: " + viewInfo(mTickerView));
|
||||
pw.println(" mNotificationScroller: " + viewInfo(mNotificationScroller)
|
||||
+ " scroll " + mNotificationScroller.getScrollX()
|
||||
+ "," + mNotificationScroller.getScrollY());
|
||||
pw.println(" mStackScroller: " + viewInfo(mStackScroller)
|
||||
+ " scroll " + mStackScroller.getScrollX()
|
||||
+ "," + mStackScroller.getScrollY());
|
||||
}
|
||||
|
||||
pw.print(" mInteractingWindows="); pw.println(mInteractingWindows);
|
||||
@@ -2409,8 +2357,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
|
||||
|
||||
if (ENABLE_HEADS_UP && mHeadsUpNotificationView != null) {
|
||||
mHeadsUpNotificationView.setMargin(mNotificationPanelMarginPx);
|
||||
mPile.getLocationOnScreen(mPilePosition);
|
||||
mHeadsUpVerticalOffset = mPilePosition[1] - mNaturalBarHeight;
|
||||
mStackScroller.getLocationOnScreen(mStackScrollerPosition);
|
||||
mHeadsUpVerticalOffset = mStackScrollerPosition[1] - mNaturalBarHeight;
|
||||
}
|
||||
|
||||
updateCarrierLabelVisibility(false);
|
||||
@@ -2428,7 +2376,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
|
||||
|
||||
private View.OnClickListener mClearButtonListener = new View.OnClickListener() {
|
||||
public void onClick(View v) {
|
||||
// TODO: Handle this better with notification stack scroller
|
||||
synchronized (mNotificationData) {
|
||||
mPostCollapseCleanup = new Runnable() {
|
||||
@Override
|
||||
@@ -2437,86 +2384,14 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode {
|
||||
Log.v(TAG, "running post-collapse cleanup");
|
||||
}
|
||||
try {
|
||||
if (!ENABLE_NOTIFICATION_STACK) {
|
||||
((NotificationRowLayout) mPile).setViewRemoval(true);
|
||||
}
|
||||
mBarService.onClearAllNotifications(mCurrentUserId);
|
||||
} catch (Exception ex) { }
|
||||
}
|
||||
};
|
||||
|
||||
if(ENABLE_NOTIFICATION_STACK) {
|
||||
animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
|
||||
return;
|
||||
}
|
||||
|
||||
// animate-swipe all dismissable notifications, then animate the shade closed
|
||||
int numChildren = mPile.getChildCount();
|
||||
|
||||
int scrollTop = mNotificationScroller.getScrollY();
|
||||
int scrollBottom = scrollTop + mNotificationScroller.getHeight();
|
||||
final ArrayList<View> snapshot = new ArrayList<View>(numChildren);
|
||||
for (int i=0; i<numChildren; i++) {
|
||||
final View child = mPile.getChildAt(i);
|
||||
if (((SwipeHelper.Callback) mPile).canChildBeDismissed(child)
|
||||
&& child.getBottom() > scrollTop && child.getTop() < scrollBottom) {
|
||||
snapshot.add(child);
|
||||
}
|
||||
}
|
||||
if (snapshot.isEmpty()) {
|
||||
animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
|
||||
return;
|
||||
}
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
// Decrease the delay for every row we animate to give the sense of
|
||||
// accelerating the swipes
|
||||
final int ROW_DELAY_DECREMENT = 10;
|
||||
int currentDelay = 140;
|
||||
int totalDelay = 0;
|
||||
|
||||
|
||||
if (!ENABLE_NOTIFICATION_STACK) {
|
||||
// Set the shade-animating state to avoid doing other work during
|
||||
// all of these animations. In particular, avoid layout and
|
||||
// redrawing when collapsing the shade.
|
||||
((NotificationRowLayout) mPile).setViewRemoval(false);
|
||||
}
|
||||
|
||||
View sampleView = snapshot.get(0);
|
||||
int width = sampleView.getWidth();
|
||||
final int dir = sampleView.isLayoutRtl() ? -1 : +1;
|
||||
final int velocity = dir * width * 8; // 1000/8 = 125 ms duration
|
||||
for (final View _v : snapshot) {
|
||||
mHandler.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (!ENABLE_NOTIFICATION_STACK) {
|
||||
((NotificationRowLayout) mPile).dismissRowAnimated(
|
||||
_v, velocity);
|
||||
} else {
|
||||
((NotificationStackScrollLayout) mPile).dismissRowAnimated(
|
||||
_v, velocity);
|
||||
}
|
||||
}
|
||||
}, totalDelay);
|
||||
currentDelay = Math.max(50, currentDelay - ROW_DELAY_DECREMENT);
|
||||
totalDelay += currentDelay;
|
||||
}
|
||||
// Delay the collapse animation until after all swipe animations have
|
||||
// finished. Provide some buffer because there may be some extra delay
|
||||
// before actually starting each swipe animation. Ideally, we'd
|
||||
// synchronize the end of those animations with the start of the collaps
|
||||
// exactly.
|
||||
mHandler.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
|
||||
}
|
||||
}, totalDelay + 225);
|
||||
}
|
||||
}).start();
|
||||
animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE);
|
||||
return;
|
||||
// TODO: Handle this better with notification stack scroller
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -24,13 +24,13 @@ import android.util.AttributeSet;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewRootImpl;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import com.android.systemui.ExpandHelper;
|
||||
import com.android.systemui.R;
|
||||
import com.android.systemui.statusbar.BaseStatusBar;
|
||||
import com.android.systemui.statusbar.policy.ScrollAdapter;
|
||||
import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
|
||||
|
||||
|
||||
@@ -40,9 +40,8 @@ public class StatusBarWindowView extends FrameLayout
|
||||
public static final boolean DEBUG = BaseStatusBar.DEBUG;
|
||||
|
||||
private ExpandHelper mExpandHelper;
|
||||
private ViewGroup latestItems;
|
||||
private NotificationStackScrollLayout mStackScrollLayout;
|
||||
private NotificationPanelView mNotificationPanel;
|
||||
private View mNotificationScroller;
|
||||
|
||||
PhoneStatusBar mService;
|
||||
|
||||
@@ -56,37 +55,15 @@ public class StatusBarWindowView extends FrameLayout
|
||||
protected void onAttachedToWindow () {
|
||||
super.onAttachedToWindow();
|
||||
|
||||
ExpandHelper.ScrollAdapter scrollAdapter;
|
||||
if (BaseStatusBar.ENABLE_NOTIFICATION_STACK) {
|
||||
NotificationStackScrollLayout stackScrollLayout =
|
||||
(NotificationStackScrollLayout) findViewById(R.id.notification_stack_scroller);
|
||||
|
||||
// ScrollView and notification container are unified in a single view now.
|
||||
latestItems = stackScrollLayout;
|
||||
scrollAdapter = stackScrollLayout;
|
||||
mNotificationScroller = stackScrollLayout;
|
||||
} else {
|
||||
latestItems = (ViewGroup) findViewById(R.id.latestItems);
|
||||
mNotificationScroller = findViewById(R.id.scroll);
|
||||
scrollAdapter = new ExpandHelper.ScrollAdapter() {
|
||||
@Override
|
||||
public boolean isScrolledToTop() {
|
||||
return mNotificationScroller.getScrollY() == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getHostView() {
|
||||
return mNotificationScroller;
|
||||
}
|
||||
};
|
||||
}
|
||||
mStackScrollLayout = (NotificationStackScrollLayout) findViewById(
|
||||
R.id.notification_stack_scroller);
|
||||
mNotificationPanel = (NotificationPanelView) findViewById(R.id.notification_panel);
|
||||
int minHeight = getResources().getDimensionPixelSize(R.dimen.notification_row_min_height);
|
||||
int maxHeight = getResources().getDimensionPixelSize(R.dimen.notification_row_max_height);
|
||||
mExpandHelper = new ExpandHelper(getContext(), (ExpandHelper.Callback) latestItems,
|
||||
mExpandHelper = new ExpandHelper(getContext(), mStackScrollLayout,
|
||||
minHeight, maxHeight);
|
||||
mExpandHelper.setEventSource(this);
|
||||
mExpandHelper.setScrollAdapter(scrollAdapter);
|
||||
mExpandHelper.setScrollAdapter(mStackScrollLayout);
|
||||
|
||||
// We really need to be able to animate while window animations are going on
|
||||
// so that activities may be started asynchronously from panel animations
|
||||
@@ -113,7 +90,7 @@ public class StatusBarWindowView extends FrameLayout
|
||||
public boolean onInterceptTouchEvent(MotionEvent ev) {
|
||||
boolean intercept = false;
|
||||
if (mNotificationPanel.isFullyExpanded()
|
||||
&& mNotificationScroller.getVisibility() == View.VISIBLE) {
|
||||
&& mStackScrollLayout.getVisibility() == View.VISIBLE) {
|
||||
intercept = mExpandHelper.onInterceptTouchEvent(ev);
|
||||
}
|
||||
if (!intercept) {
|
||||
@@ -122,7 +99,7 @@ public class StatusBarWindowView extends FrameLayout
|
||||
if (intercept) {
|
||||
MotionEvent cancellation = MotionEvent.obtain(ev);
|
||||
cancellation.setAction(MotionEvent.ACTION_CANCEL);
|
||||
latestItems.onInterceptTouchEvent(cancellation);
|
||||
mStackScrollLayout.onInterceptTouchEvent(cancellation);
|
||||
cancellation.recycle();
|
||||
}
|
||||
return intercept;
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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.policy;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
/**
|
||||
* A scroll adapter which can be queried for meta information about the scroll state
|
||||
*/
|
||||
public interface ScrollAdapter {
|
||||
|
||||
/**
|
||||
* @return Whether the view returned by {@link #getHostView()} is scrolled to the top
|
||||
*/
|
||||
public boolean isScrolledToTop();
|
||||
|
||||
/**
|
||||
* @return Whether the view returned by {@link #getHostView()} is scrolled to the bottom
|
||||
*/
|
||||
public boolean isScrolledToBottom();
|
||||
|
||||
/**
|
||||
* @return The view in which the scrolling is performed
|
||||
*/
|
||||
public View getHostView();
|
||||
}
|
||||
@@ -39,12 +39,13 @@ import com.android.systemui.R;
|
||||
import com.android.systemui.SwipeHelper;
|
||||
import com.android.systemui.statusbar.ExpandableNotificationRow;
|
||||
import com.android.systemui.statusbar.stack.StackScrollState.ViewState;
|
||||
import com.android.systemui.statusbar.policy.ScrollAdapter;
|
||||
|
||||
/**
|
||||
* A layout which handles a dynamic amount of notifications and presents them in a scrollable stack.
|
||||
*/
|
||||
public class NotificationStackScrollLayout extends ViewGroup
|
||||
implements SwipeHelper.Callback, ExpandHelper.Callback, ExpandHelper.ScrollAdapter {
|
||||
implements SwipeHelper.Callback, ExpandHelper.Callback, ScrollAdapter {
|
||||
|
||||
private static final String TAG = "NotificationStackScrollLayout";
|
||||
private static final boolean DEBUG = false;
|
||||
@@ -55,7 +56,7 @@ public class NotificationStackScrollLayout extends ViewGroup
|
||||
private static final int INVALID_POINTER = -1;
|
||||
|
||||
private SwipeHelper mSwipeHelper;
|
||||
private boolean mAllowScrolling = true;
|
||||
private boolean mSwipingInProgress = true;
|
||||
private int mCurrentStackHeight = Integer.MAX_VALUE;
|
||||
private int mOwnScrollY;
|
||||
private int mMaxLayoutHeight;
|
||||
@@ -89,7 +90,7 @@ public class NotificationStackScrollLayout extends ViewGroup
|
||||
* The current State this Layout is in
|
||||
*/
|
||||
private final StackScrollState mCurrentStackScrollState = new StackScrollState(this);
|
||||
|
||||
|
||||
private OnChildLocationsChangedListener mListener;
|
||||
|
||||
public NotificationStackScrollLayout(Context context) {
|
||||
@@ -279,7 +280,7 @@ public class NotificationStackScrollLayout extends ViewGroup
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current height of the view. This is at most the size of the view given by a the
|
||||
* Get the current height of the view. This is at most the msize of the view given by a the
|
||||
* layout but it can also be made smaller by setting {@link #mCurrentStackHeight}
|
||||
*
|
||||
* @return either the layout height or the externally defined height, whichever is smaller
|
||||
@@ -288,6 +289,14 @@ public class NotificationStackScrollLayout extends ViewGroup
|
||||
return Math.min(mMaxLayoutHeight, mCurrentStackHeight);
|
||||
}
|
||||
|
||||
public int getItemHeight() {
|
||||
return mCollapsedSize;
|
||||
}
|
||||
|
||||
public int getBottomStackPeekSize() {
|
||||
return mBottomStackPeekSize;
|
||||
}
|
||||
|
||||
public void setLongPressListener(View.OnLongClickListener listener) {
|
||||
mSwipeHelper.setLongPressListener(listener);
|
||||
}
|
||||
@@ -298,15 +307,15 @@ public class NotificationStackScrollLayout extends ViewGroup
|
||||
if (veto != null && veto.getVisibility() != View.GONE) {
|
||||
veto.performClick();
|
||||
}
|
||||
allowScrolling(true);
|
||||
setSwipingInProgress(false);
|
||||
}
|
||||
|
||||
public void onBeginDrag(View v) {
|
||||
allowScrolling(false);
|
||||
setSwipingInProgress(true);
|
||||
}
|
||||
|
||||
public void onDragCancelled(View v) {
|
||||
allowScrolling(true);
|
||||
setSwipingInProgress(false);
|
||||
}
|
||||
|
||||
public View getChildAtPosition(MotionEvent ev) {
|
||||
@@ -365,8 +374,11 @@ public class NotificationStackScrollLayout extends ViewGroup
|
||||
return (veto != null && veto.getVisibility() != View.GONE);
|
||||
}
|
||||
|
||||
private void allowScrolling(boolean allow) {
|
||||
mAllowScrolling = allow;
|
||||
private void setSwipingInProgress(boolean isSwiped) {
|
||||
mSwipingInProgress = isSwiped;
|
||||
if(isSwiped) {
|
||||
requestDisallowInterceptTouchEvent(true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -386,7 +398,7 @@ public class NotificationStackScrollLayout extends ViewGroup
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent ev) {
|
||||
boolean scrollerWantsIt = false;
|
||||
if (mAllowScrolling) {
|
||||
if (!mSwipingInProgress) {
|
||||
scrollerWantsIt = onScrollTouch(ev);
|
||||
}
|
||||
boolean horizontalSwipeWantsIt = false;
|
||||
@@ -409,12 +421,6 @@ public class NotificationStackScrollLayout extends ViewGroup
|
||||
}
|
||||
boolean isBeingDragged = !mScroller.isFinished();
|
||||
setIsBeingDragged(isBeingDragged);
|
||||
if (isBeingDragged) {
|
||||
final ViewParent parent = getParent();
|
||||
if (parent != null) {
|
||||
parent.requestDisallowInterceptTouchEvent(true);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If being flinged and user touches, stop the fling. isFinished
|
||||
@@ -439,10 +445,6 @@ public class NotificationStackScrollLayout extends ViewGroup
|
||||
final int y = (int) ev.getY(activePointerIndex);
|
||||
int deltaY = mLastMotionY - y;
|
||||
if (!mIsBeingDragged && Math.abs(deltaY) > mTouchSlop) {
|
||||
final ViewParent parent = getParent();
|
||||
if (parent != null) {
|
||||
parent.requestDisallowInterceptTouchEvent(true);
|
||||
}
|
||||
setIsBeingDragged(true);
|
||||
if (deltaY > 0) {
|
||||
deltaY -= mTouchSlop;
|
||||
@@ -642,7 +644,7 @@ public class NotificationStackScrollLayout extends ViewGroup
|
||||
if (getChildCount() > 0) {
|
||||
int contentHeight = getContentHeight();
|
||||
scrollRange = Math.max(0,
|
||||
contentHeight - mMaxLayoutHeight + mCollapsedSize);
|
||||
contentHeight - mMaxLayoutHeight + mBottomStackPeekSize);
|
||||
}
|
||||
return scrollRange;
|
||||
}
|
||||
@@ -697,7 +699,7 @@ public class NotificationStackScrollLayout extends ViewGroup
|
||||
@Override
|
||||
public boolean onInterceptTouchEvent(MotionEvent ev) {
|
||||
boolean scrollWantsIt = false;
|
||||
if (mAllowScrolling) {
|
||||
if (!mSwipingInProgress) {
|
||||
scrollWantsIt = onInterceptTouchEventScroll(ev);
|
||||
}
|
||||
boolean swipeWantsIt = false;
|
||||
@@ -763,10 +765,6 @@ public class NotificationStackScrollLayout extends ViewGroup
|
||||
mLastMotionY = y;
|
||||
initVelocityTrackerIfNotExists();
|
||||
mVelocityTracker.addMovement(ev);
|
||||
final ViewParent parent = getParent();
|
||||
if (parent != null) {
|
||||
parent.requestDisallowInterceptTouchEvent(true);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -823,6 +821,7 @@ public class NotificationStackScrollLayout extends ViewGroup
|
||||
private void setIsBeingDragged(boolean isDragged) {
|
||||
mIsBeingDragged = isDragged;
|
||||
if (isDragged) {
|
||||
requestDisallowInterceptTouchEvent(true);
|
||||
mSwipeHelper.removeLongPressCallback();
|
||||
}
|
||||
}
|
||||
@@ -840,11 +839,20 @@ public class NotificationStackScrollLayout extends ViewGroup
|
||||
return mOwnScrollY == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isScrolledToBottom() {
|
||||
return mOwnScrollY >= getScrollRange();
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getHostView() {
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getEmptyBottomMargin() {
|
||||
return Math.max(getHeight() - mContentHeight, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* A listener that is notified when some child locations might have changed.
|
||||
*/
|
||||
|
||||
@@ -86,7 +86,7 @@ public class StackScrollAlgorithm {
|
||||
// First we reset the view states to their default values.
|
||||
resultState.resetViewStates();
|
||||
|
||||
// The first element is always in there so it's initialized with 1.0f.
|
||||
// The first element is always in there so it's initialized with 1.0f;
|
||||
algorithmState.itemsInTopStack = 1.0f;
|
||||
algorithmState.partialInTop = 0.0f;
|
||||
algorithmState.lastTopStackIndex = 0;
|
||||
@@ -102,7 +102,7 @@ public class StackScrollAlgorithm {
|
||||
// Phase 3:
|
||||
updateZValuesForState(resultState, algorithmState);
|
||||
|
||||
// Write the algorithm state to the result.
|
||||
// write the algorithm state to the result
|
||||
resultState.setScrollY(algorithmState.scrollY);
|
||||
}
|
||||
|
||||
@@ -151,7 +151,7 @@ public class StackScrollAlgorithm {
|
||||
// Case 2:
|
||||
// First element of regular scrollview comes next, so the position is just the
|
||||
// scrolling position
|
||||
nextYPosition = scrollOffset;
|
||||
nextYPosition = Math.min(scrollOffset, transitioningPositionStart);
|
||||
childViewState.location = StackScrollState.ViewState.LOCATION_TOP_STACK_PEEKING;
|
||||
} else if (nextYPosition >= transitioningPositionStart) {
|
||||
if (currentYPosition >= transitioningPositionStart) {
|
||||
@@ -180,6 +180,7 @@ public class StackScrollAlgorithm {
|
||||
if (childViewState.location == StackScrollState.ViewState.LOCATION_UNKNOWN) {
|
||||
Log.wtf(LOG_TAG, "Failed to assign location for child " + i);
|
||||
}
|
||||
nextYPosition = Math.max(0, nextYPosition);
|
||||
currentYPosition = nextYPosition;
|
||||
yPositionInScrollView = yPositionInScrollViewAfterElement;
|
||||
}
|
||||
@@ -253,6 +254,8 @@ public class StackScrollAlgorithm {
|
||||
nextYPosition = mCollapsedSize + mPaddingBetweenElements -
|
||||
mTopStackIndentationFunctor.getValue(
|
||||
algorithmState.itemsInTopStack - i - 1);
|
||||
nextYPosition = Math.min(nextYPosition, mLayoutHeight - mCollapsedSize
|
||||
- mBottomStackPeekSize);
|
||||
if (paddedIndex == 0) {
|
||||
childViewState.alpha = 1.0f - algorithmState.partialInTop;
|
||||
childViewState.location = StackScrollState.ViewState.LOCATION_TOP_STACK_HIDDEN;
|
||||
|
||||
Reference in New Issue
Block a user