summaryrefslogtreecommitdiffstats
path: root/packages/SystemUI/src
diff options
context:
space:
mode:
Diffstat (limited to 'packages/SystemUI/src')
-rw-r--r--packages/SystemUI/src/com/android/systemui/ExpandHelper.java3
-rw-r--r--packages/SystemUI/src/com/android/systemui/SwipeHelper.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/QSPanel.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java10
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/DismissView.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java7
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java42
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java2
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java92
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java15
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java99
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java34
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java7
20 files changed, 285 insertions, 72 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
index 0f8fe1c..d42ac61 100644
--- a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
@@ -351,6 +351,9 @@ public class ExpandHelper implements Gefingerpoken {
mVelocityTracker.addMovement(event);
break;
case MotionEvent.ACTION_MOVE:
+ if (mVelocityTracker == null) {
+ mVelocityTracker = VelocityTracker.obtain();
+ }
mVelocityTracker.addMovement(event);
break;
default:
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index 0d393bf..f206e56 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -311,11 +311,14 @@ public class SwipeHelper implements Gefingerpoken {
final View animView = mCallback.getChildContentView(view);
final boolean canAnimViewBeDismissed = mCallback.canChildBeDismissed(view);
float newPos;
+ boolean isLayoutRtl = view.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
if (velocity < 0
|| (velocity == 0 && getTranslation(animView) < 0)
// if we use the Menu to dismiss an item in landscape, animate up
- || (velocity == 0 && getTranslation(animView) == 0 && mSwipeDirection == Y)) {
+ || (velocity == 0 && getTranslation(animView) == 0 && mSwipeDirection == Y)
+ // if the language is rtl we prefer swiping to the left
+ || (velocity == 0 && getTranslation(animView) == 0 && isLayoutRtl)) {
newPos = -getSize(animView);
} else {
newPos = getSize(animView);
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
index f5df1a9..4391bfc 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
@@ -66,6 +66,7 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI {
private static final String ACTION_SHOW_BATTERY_SETTINGS = "PNW.batterySettings";
private static final String ACTION_START_SAVER = "PNW.startSaver";
private static final String ACTION_STOP_SAVER = "PNW.stopSaver";
+ private static final String ACTION_DISMISSED_WARNING = "PNW.dismissedWarning";
private static final AudioAttributes AUDIO_ATTRIBUTES = new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
@@ -180,6 +181,7 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI {
.setContentTitle(mContext.getString(R.string.battery_low_title))
.setContentText(mContext.getString(textRes, percentage))
.setOnlyAlertOnce(true)
+ .setDeleteIntent(pendingBroadcast(ACTION_DISMISSED_WARNING))
.setPriority(Notification.PRIORITY_MAX)
.setVisibility(Notification.VISIBILITY_PUBLIC)
.setColor(mContext.getResources().getColor(
@@ -374,6 +376,7 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI {
filter.addAction(ACTION_SHOW_BATTERY_SETTINGS);
filter.addAction(ACTION_START_SAVER);
filter.addAction(ACTION_STOP_SAVER);
+ filter.addAction(ACTION_DISMISSED_WARNING);
mContext.registerReceiverAsUser(this, UserHandle.ALL, filter, null, mHandler);
}
@@ -391,6 +394,8 @@ public class PowerNotificationWarnings implements PowerUI.WarningsUI {
dismissSaverNotification();
dismissLowBatteryNotification();
setSaverMode(false);
+ } else if (action.equals(ACTION_DISMISSED_WARNING)) {
+ dismissLowBatteryWarning();
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index fdebdd3..54a8414 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -542,7 +542,10 @@ public class QSPanel extends ViewGroup {
@Override
public void onAnimationEnd(Animator animation) {
- setGridContentVisibility(false);
+ // Only hide content if still in detail state.
+ if (mDetailRecord != null) {
+ setGridContentVisibility(false);
+ }
}
};
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index e4faa6a..02b9378 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -508,7 +508,7 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
if (mAppearAnimator != null) {
mAppearAnimator.cancel();
}
- mAnimationTranslationY = translationDirection * mActualHeight;
+ mAnimationTranslationY = translationDirection * getActualHeight();
if (mAppearAnimationFraction == -1.0f) {
// not initialized yet, we start anew
if (isAppearing) {
@@ -601,14 +601,15 @@ public abstract class ActivatableNotificationView extends ExpandableOutlineView
float top;
float bottom;
+ final int actualHeight = getActualHeight();
if (mAnimationTranslationY > 0.0f) {
- bottom = mActualHeight - heightFraction * mAnimationTranslationY * 0.1f
+ bottom = actualHeight - heightFraction * mAnimationTranslationY * 0.1f
- translateYTotalAmount;
top = bottom * heightFraction;
} else {
- top = heightFraction * (mActualHeight + mAnimationTranslationY) * 0.1f -
+ top = heightFraction * (actualHeight + mAnimationTranslationY) * 0.1f -
translateYTotalAmount;
- bottom = mActualHeight * (1 - heightFraction) + top * heightFraction;
+ bottom = actualHeight * (1 - heightFraction) + top * heightFraction;
}
mAppearAnimationRect.set(left, top, right, bottom);
setOutlineRect(left, top + mAppearAnimationTranslation, right,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 1b4bdf8..09d0b5d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -59,6 +59,7 @@ import android.service.notification.NotificationListenerService.RankingMap;
import android.service.notification.StatusBarNotification;
import android.text.TextUtils;
import android.util.Log;
+import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.view.Display;
@@ -113,6 +114,9 @@ public abstract class BaseStatusBar extends SystemUI implements
public static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
public static final boolean MULTIUSER_DEBUG = false;
+ // STOPSHIP disable once we resolve b/18102199
+ private static final boolean NOTIFICATION_CLICK_DEBUG = true;
+
protected static final int MSG_SHOW_RECENT_APPS = 1019;
protected static final int MSG_HIDE_RECENT_APPS = 1020;
protected static final int MSG_TOGGLE_RECENTS_APPS = 1021;
@@ -325,6 +329,9 @@ public abstract class BaseStatusBar extends SystemUI implements
ViewGroup actionGroup = (ViewGroup) parent;
index = actionGroup.indexOfChild(view);
}
+ if (NOTIFICATION_CLICK_DEBUG) {
+ Log.d(TAG, "Clicked on button " + index + " for " + key);
+ }
try {
mBarService.onNotificationActionClick(key, index);
} catch (RemoteException e) {
@@ -1515,6 +1522,9 @@ public abstract class BaseStatusBar extends SystemUI implements
}
public void onClick(final View v) {
+ if (NOTIFICATION_CLICK_DEBUG) {
+ Log.d(TAG, "Clicked on content of " + mNotificationKey);
+ }
final boolean keyguardShowing = mStatusBarKeyguardViewManager.isShowing();
final boolean afterKeyguardGone = mIntent.isActivity()
&& PreviewInflater.wouldLaunchResolverActivity(mContext, mIntent.getIntent(),
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DismissView.java b/packages/SystemUI/src/com/android/systemui/statusbar/DismissView.java
index 897dbf2..479c2fb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/DismissView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DismissView.java
@@ -36,4 +36,11 @@ public class DismissView extends StackScrollerDecorView {
public void setOnButtonClickListener(OnClickListener listener) {
mContent.setOnClickListener(listener);
}
+
+ public boolean isOnEmptySpace(float touchX, float touchY) {
+ return touchX < mContent.getX()
+ || touchX > mContent.getX() + mContent.getWidth()
+ || touchY < mContent.getY()
+ || touchY > mContent.getY() + mContent.getHeight();
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 556c423..a4e5e74 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -23,10 +23,8 @@ import android.graphics.drawable.Drawable;
import android.service.notification.StatusBarNotification;
import android.util.AttributeSet;
import android.view.View;
-import android.view.ViewGroup;
import android.view.ViewStub;
import android.view.accessibility.AccessibilityEvent;
-
import android.widget.ImageView;
import com.android.systemui.R;
@@ -156,9 +154,9 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
}
public void resetHeight() {
+ super.resetHeight();
mMaxExpandHeight = 0;
mWasReset = true;
- mActualHeight = 0;
onHeightReset();
requestLayout();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
index f85d32b..a18fff2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
@@ -41,7 +41,7 @@ public abstract class ExpandableOutlineView extends ExpandableView {
outline.setRect(0,
mClipTopAmount,
getWidth(),
- Math.max(mActualHeight, mClipTopAmount));
+ Math.max(getActualHeight(), mClipTopAmount));
} else {
outline.setRect(mOutlineRect);
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
index c8f756e..edfbe86 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
@@ -36,7 +36,7 @@ public abstract class ExpandableView extends FrameLayout {
private final int mMaxNotificationHeight;
private OnHeightChangedListener mOnHeightChangedListener;
- protected int mActualHeight;
+ private int mActualHeight;
protected int mClipTopAmount;
private boolean mActualHeightInitialized;
private ArrayList<View> mMatchParentViews = new ArrayList<View>();
@@ -103,6 +103,11 @@ public abstract class ExpandableView extends FrameLayout {
}
}
+ protected void resetHeight() {
+ mActualHeight = 0;
+ mActualHeightInitialized = false;
+ }
+
protected int getInitialHeight() {
return getHeight();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java
index 5db680a..0fc46e9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java
@@ -23,9 +23,7 @@ import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.RippleDrawable;
import android.util.AttributeSet;
-import android.view.MotionEvent;
import android.view.View;
-import com.android.systemui.R;
/**
* A view that can be used for both the dimmed and normal background of an notification.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index 502490f..9b11f9b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -27,11 +27,11 @@ import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
+import android.view.ViewTreeObserver;
import android.view.animation.Interpolator;
import android.view.animation.LinearInterpolator;
import android.widget.FrameLayout;
import android.widget.ImageView;
-
import com.android.systemui.R;
/**
@@ -60,6 +60,16 @@ public class NotificationContentView extends FrameLayout {
private boolean mDark;
private final Paint mFadePaint = new Paint();
+ private boolean mAnimate;
+ private ViewTreeObserver.OnPreDrawListener mEnableAnimationPredrawListener
+ = new ViewTreeObserver.OnPreDrawListener() {
+ @Override
+ public boolean onPreDraw() {
+ mAnimate = true;
+ getViewTreeObserver().removeOnPreDrawListener(this);
+ return true;
+ }
+ };
public NotificationContentView(Context context, AttributeSet attrs) {
super(context, attrs);
@@ -73,6 +83,12 @@ public class NotificationContentView extends FrameLayout {
updateClipping();
}
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ updateVisibility();
+ }
+
public void reset() {
if (mContractedChild != null) {
mContractedChild.animate().cancel();
@@ -117,9 +133,31 @@ public class NotificationContentView extends FrameLayout {
selectLayout(false /* animate */, true /* force */);
}
+ @Override
+ protected void onVisibilityChanged(View changedView, int visibility) {
+ super.onVisibilityChanged(changedView, visibility);
+ updateVisibility();
+ }
+
+ private void updateVisibility() {
+ setVisible(isShown());
+ }
+
+ private void setVisible(final boolean isVisible) {
+ if (isVisible) {
+
+ // We only animate if we are drawn at least once, otherwise the view might animate when
+ // it's shown the first time
+ getViewTreeObserver().addOnPreDrawListener(mEnableAnimationPredrawListener);
+ } else {
+ getViewTreeObserver().removeOnPreDrawListener(mEnableAnimationPredrawListener);
+ mAnimate = false;
+ }
+ }
+
public void setActualHeight(int actualHeight) {
mActualHeight = actualHeight;
- selectLayout(true /* animate */, false /* force */);
+ selectLayout(mAnimate /* animate */, false /* force */);
updateClipping();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
index 682c01c..6cb5bcc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
@@ -159,7 +159,7 @@ public class DemoStatusIcons extends LinearLayout implements DemoMode {
}
}
StatusBarIcon icon = new StatusBarIcon(iconPkg, UserHandle.CURRENT, iconId, 0, 0, "Demo");
- StatusBarIconView v = new StatusBarIconView(getContext(), null);
+ StatusBarIconView v = new StatusBarIconView(getContext(), null, null);
v.setTag(slot);
v.set(icon);
addView(v, 0, new LinearLayout.LayoutParams(mIconSize, mIconSize));
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
index a956151..6fd6758 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeParameters.java
@@ -48,6 +48,7 @@ public class DozeParameters {
pw.print(" getDisplayStateSupported(): "); pw.println(getDisplayStateSupported());
pw.print(" getPulseDuration(): "); pw.println(getPulseDuration());
pw.print(" getPulseInDuration(): "); pw.println(getPulseInDuration());
+ pw.print(" getPulseInDelay(): "); pw.println(getPulseInDelay());
pw.print(" getPulseInVisibleDuration(): "); pw.println(getPulseVisibleDuration());
pw.print(" getPulseOutDuration(): "); pw.println(getPulseOutDuration());
pw.print(" getPulseOnSigMotion(): "); pw.println(getPulseOnSigMotion());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 0bde7ef..d9e44c3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -52,7 +52,7 @@ import com.android.systemui.statusbar.stack.StackStateAnimator;
public class NotificationPanelView extends PanelView implements
ExpandableView.OnHeightChangedListener, ObservableScrollView.Listener,
View.OnClickListener, NotificationStackScrollLayout.OnOverscrollTopChangedListener,
- KeyguardAffordanceHelper.Callback {
+ KeyguardAffordanceHelper.Callback, NotificationStackScrollLayout.OnEmptySpaceClickListener {
// Cap and total height of Roboto font. Needs to be adjusted when font for the big clock is
// changed.
@@ -197,6 +197,7 @@ public class NotificationPanelView extends PanelView implements
findViewById(R.id.notification_stack_scroller);
mNotificationStackScroller.setOnHeightChangedListener(this);
mNotificationStackScroller.setOverscrollTopChangedListener(this);
+ mNotificationStackScroller.setOnEmptySpaceClickListener(this);
mNotificationStackScroller.setScrollView(mScrollView);
mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(getContext(),
android.R.interpolator.fast_out_slow_in);
@@ -526,13 +527,15 @@ public class NotificationPanelView extends PanelView implements
mIntercepting = false;
break;
}
+ return super.onInterceptTouchEvent(event);
+ }
- // Allow closing the whole panel when in SHADE state.
- if (mStatusBarState == StatusBarState.SHADE) {
- return super.onInterceptTouchEvent(event);
- } else {
- return !mQsExpanded && super.onInterceptTouchEvent(event);
- }
+ @Override
+ protected boolean isInContentBounds(float x, float y) {
+ float yTransformed = y - mNotificationStackScroller.getY();
+ float stackScrollerX = mNotificationStackScroller.getX();
+ return mNotificationStackScroller.isInContentBounds(yTransformed) && stackScrollerX < x
+ && x < stackScrollerX + mNotificationStackScroller.getWidth();
}
private void resetDownStates(MotionEvent event) {
@@ -636,10 +639,9 @@ public class NotificationPanelView extends PanelView implements
}
private boolean isInQsArea(float x, float y) {
- return mStatusBarState != StatusBarState.SHADE ||
- (x >= mScrollView.getLeft() && x <= mScrollView.getRight()) &&
- (y <= mNotificationStackScroller.getBottomMostNotificationBottom()
- || y <= mQsContainer.getY() + mQsContainer.getHeight());
+ return (x >= mScrollView.getLeft() && x <= mScrollView.getRight()) &&
+ (y <= mNotificationStackScroller.getBottomMostNotificationBottom()
+ || y <= mQsContainer.getY() + mQsContainer.getHeight());
}
private void handleQsDown(MotionEvent event) {
@@ -1110,9 +1112,26 @@ public class NotificationPanelView extends PanelView implements
}
private float calculateQsTopPadding() {
- // We can only do the smoother transition on Keyguard when we also are not collapsing from a
- // scrolled quick settings.
- if (mKeyguardShowing && mScrollYOverride == -1) {
+ if (mKeyguardShowing
+ && (mTwoFingerQsExpand || mIsExpanding && mQsExpandedWhenExpandingStarted)) {
+
+ // Either QS pushes the notifications down when fully expanded, or QS is fully above the
+ // notifications (mostly on tablets). maxNotifications denotes the normal top padding
+ // on Keyguard, maxQs denotes the top padding from the quick settings panel. We need to
+ // take the maximum and linearly interpolate with the panel expansion for a nice motion.
+ int maxNotifications = mClockPositionResult.stackScrollerPadding
+ - mClockPositionResult.stackScrollerPaddingAdjustment
+ - mNotificationTopPadding;
+ int maxQs = getTempQsMaxExpansion();
+ int max = mStatusBarState == StatusBarState.KEYGUARD
+ ? Math.max(maxNotifications, maxQs)
+ : maxQs;
+ return (int) interpolate(getExpandedFraction(),
+ mQsMinExpansionHeight, max);
+ } else if (mKeyguardShowing && mScrollYOverride == -1) {
+
+ // We can only do the smoother transition on Keyguard when we also are not collapsing
+ // from a scrolled quick settings.
return interpolate(getQsExpansionFraction(),
mNotificationStackScroller.getIntrinsicPadding() - mNotificationTopPadding,
mQsMaxExpansionHeight);
@@ -1124,7 +1143,9 @@ public class NotificationPanelView extends PanelView implements
private void requestScrollerTopPaddingUpdate(boolean animate) {
mNotificationStackScroller.updateTopPadding(calculateQsTopPadding(),
mScrollView.getScrollY(),
- mAnimateNextTopPaddingChange || animate);
+ mAnimateNextTopPaddingChange || animate,
+ mKeyguardShowing
+ && (mTwoFingerQsExpand || mIsExpanding && mQsExpandedWhenExpandingStarted));
mAnimateNextTopPaddingChange = false;
}
@@ -1254,18 +1275,27 @@ public class NotificationPanelView extends PanelView implements
@Override
protected void onHeightUpdated(float expandedHeight) {
- if (!mQsExpanded) {
+ if (!mQsExpanded || mTwoFingerQsExpand || mIsExpanding && mQsExpandedWhenExpandingStarted) {
positionClockAndNotifications();
}
if (mTwoFingerQsExpand || mQsExpanded && !mQsTracking && mQsExpansionAnimator == null
&& !mQsExpansionFromOverscroll) {
- float panelHeightQsCollapsed = mNotificationStackScroller.getIntrinsicPadding()
- + mNotificationStackScroller.getMinStackHeight()
- + mNotificationStackScroller.getNotificationTopPadding();
- float panelHeightQsExpanded = calculatePanelHeightQsExpanded();
- float t = (expandedHeight - panelHeightQsCollapsed)
- / (panelHeightQsExpanded - panelHeightQsCollapsed);
+ float t;
+ if (mKeyguardShowing) {
+
+ // On Keyguard, interpolate the QS expansion linearly to the panel expansion
+ t = expandedHeight / getMaxPanelHeight();
+ } else {
+ // In Shade, interpolate linearly such that QS is closed whenever panel height is
+ // minimum QS expansion + minStackHeight
+ float panelHeightQsCollapsed = mNotificationStackScroller.getIntrinsicPadding()
+ + mNotificationStackScroller.getMinStackHeight()
+ + mNotificationStackScroller.getNotificationTopPadding();
+ float panelHeightQsExpanded = calculatePanelHeightQsExpanded();
+ t = (expandedHeight - panelHeightQsCollapsed)
+ / (panelHeightQsExpanded - panelHeightQsCollapsed);
+ }
setQsExpansion(mQsMinExpansionHeight
+ t * (getTempQsMaxExpansion() - mQsMinExpansionHeight));
}
@@ -1299,8 +1329,10 @@ public class NotificationPanelView extends PanelView implements
float notificationHeight = mNotificationStackScroller.getHeight()
- mNotificationStackScroller.getEmptyBottomMargin()
- mNotificationStackScroller.getTopPadding();
- float totalHeight = mQsMaxExpansionHeight + notificationHeight
- + mNotificationStackScroller.getNotificationTopPadding();
+ float totalHeight = Math.max(
+ mQsMaxExpansionHeight + mNotificationStackScroller.getNotificationTopPadding(),
+ mClockPositionResult.stackScrollerPadding - mTopPaddingAdjustment)
+ + notificationHeight;
if (totalHeight > mNotificationStackScroller.getHeight()) {
float fullyCollapsedHeight = mQsMaxExpansionHeight
+ mNotificationStackScroller.getMinStackHeight()
@@ -1433,7 +1465,7 @@ public class NotificationPanelView extends PanelView implements
super.onExpandingStarted();
mNotificationStackScroller.onExpansionStarted();
mIsExpanding = true;
- mQsExpandedWhenExpandingStarted = mQsExpanded;
+ mQsExpandedWhenExpandingStarted = mQsFullyExpanded;
if (mQsExpanded) {
onQsExpansionStarted();
}
@@ -1487,11 +1519,12 @@ public class NotificationPanelView extends PanelView implements
@Override
protected void onTrackingStarted() {
super.onTrackingStarted();
+ if (mQsFullyExpanded) {
+ mTwoFingerQsExpand = true;
+ }
if (mStatusBar.getBarState() == StatusBarState.KEYGUARD
|| mStatusBar.getBarState() == StatusBarState.SHADE_LOCKED) {
mAfforanceHelper.animateHideLeftRightIcon();
- } else if (mQsExpanded) {
- mTwoFingerQsExpand = true;
}
}
@@ -1867,4 +1900,9 @@ public class NotificationPanelView extends PanelView implements
public void onScreenTurnedOn() {
mKeyguardStatusView.refreshTime();
}
+
+ @Override
+ public void onEmptySpaceClicked(float x, float y) {
+ onEmptySpaceClick(x);
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 0ddda8a..c706ef0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -70,6 +70,7 @@ public abstract class PanelView extends FrameLayout {
private boolean mOverExpandedBeforeFling;
private boolean mTouchAboveFalsingThreshold;
private int mUnlockFalsingThreshold;
+ private boolean mTouchStartedInEmptyArea;
private ValueAnimator mHeightAnimator;
private ObjectAnimator mPeekAnimator;
@@ -284,7 +285,7 @@ public abstract class PanelView extends FrameLayout {
|| mInitialOffsetOnTouch == 0f)) {
mTouchSlopExceeded = true;
if (waitForTouchSlop && !mTracking) {
- if (!mJustPeeked) {
+ if (!mJustPeeked && mInitialOffsetOnTouch != 0f) {
mInitialOffsetOnTouch = mExpandedHeight;
mInitialTouchX = x;
mInitialTouchY = y;
@@ -409,6 +410,7 @@ public abstract class PanelView extends FrameLayout {
}
mInitialTouchY = y;
mInitialTouchX = x;
+ mTouchStartedInEmptyArea = !isInContentBounds(x, y);
mTouchSlopExceeded = false;
mJustPeeked = false;
mPanelClosedOnDown = mExpandedHeight == 0.0f;
@@ -432,7 +434,7 @@ public abstract class PanelView extends FrameLayout {
case MotionEvent.ACTION_MOVE:
final float h = y - mInitialTouchY;
trackMovement(event);
- if (scrolledToBottom) {
+ if (scrolledToBottom || mTouchStartedInEmptyArea) {
if (h < -mTouchSlop && h < -Math.abs(x - mInitialTouchX)) {
cancelHeightAnimator();
mInitialOffsetOnTouch = mExpandedHeight;
@@ -452,6 +454,11 @@ public abstract class PanelView extends FrameLayout {
return false;
}
+ /**
+ * @return Whether a pair of coordinates are inside the visible view content bounds.
+ */
+ protected abstract boolean isInContentBounds(float x, float y);
+
private void cancelHeightAnimator() {
if (mHeightAnimator != null) {
mHeightAnimator.cancel();
@@ -632,10 +639,10 @@ public abstract class PanelView extends FrameLayout {
}
mExpandedHeight = Math.max(0, mExpandedHeight);
- onHeightUpdated(mExpandedHeight);
mExpandedFraction = Math.min(1f, fhWithoutOverExpansion == 0
? 0
: mExpandedHeight / fhWithoutOverExpansion);
+ onHeightUpdated(mExpandedHeight);
notifyBarPanelExpansionChanged();
}
@@ -903,7 +910,7 @@ public abstract class PanelView extends FrameLayout {
*
* @return whether the panel will be expanded after the action performed by this method
*/
- private boolean onEmptySpaceClick(float x) {
+ protected boolean onEmptySpaceClick(float x) {
if (mHintAnimationRunning) {
return true;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 4a20406..87ce565 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -40,6 +40,7 @@ import com.android.systemui.statusbar.EmptyShadeView;
import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.ExpandableView;
import com.android.systemui.statusbar.SpeedBumpView;
+import com.android.systemui.statusbar.StackScrollerDecorView;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.phone.PhoneStatusBar;
import com.android.systemui.statusbar.policy.ScrollAdapter;
@@ -70,6 +71,12 @@ public class NotificationStackScrollLayout extends ViewGroup
private SwipeHelper mSwipeHelper;
private boolean mSwipingInProgress;
private int mCurrentStackHeight = Integer.MAX_VALUE;
+
+ /**
+ * mCurrentStackHeight is the actual stack height, mLastSetStackHeight is the stack height set
+ * externally from {@link #setStackHeight}
+ */
+ private float mLastSetStackHeight;
private int mOwnScrollY;
private int mMaxLayoutHeight;
@@ -84,6 +91,9 @@ public class NotificationStackScrollLayout extends ViewGroup
private int mLastMotionY;
private int mDownX;
private int mActivePointerId;
+ private boolean mTouchIsClick;
+ private float mInitialTouchX;
+ private float mInitialTouchY;
private int mSidePaddings;
private Paint mDebugPaint;
@@ -133,6 +143,7 @@ public class NotificationStackScrollLayout extends ViewGroup
private OnChildLocationsChangedListener mListener;
private OnOverscrollTopChangedListener mOverscrollTopChangedListener;
private ExpandableView.OnHeightChangedListener mOnHeightChangedListener;
+ private OnEmptySpaceClickListener mOnEmptySpaceClickListener;
private boolean mNeedsAnimation;
private boolean mTopPaddingNeedsAnimation;
private boolean mDimmedNeedsAnimation;
@@ -367,6 +378,9 @@ public class NotificationStackScrollLayout extends ViewGroup
if (childViewState == null) {
return ViewState.LOCATION_UNKNOWN;
}
+ if (childViewState.gone) {
+ return ViewState.LOCATION_GONE;
+ }
return childViewState.location;
}
@@ -445,6 +459,7 @@ public class NotificationStackScrollLayout extends ViewGroup
* @param height the new height of the stack
*/
public void setStackHeight(float height) {
+ mLastSetStackHeight = height;
setIsExpanded(height > 0.0f);
int newStackHeight = (int) height;
int minStackHeight = getMinStackHeight();
@@ -581,7 +596,9 @@ public class NotificationStackScrollLayout extends ViewGroup
final int count = getChildCount();
for (int childIdx = 0; childIdx < count; childIdx++) {
ExpandableView slidingChild = (ExpandableView) getChildAt(childIdx);
- if (slidingChild.getVisibility() == GONE) {
+ if (slidingChild.getVisibility() == GONE
+ || slidingChild instanceof StackScrollerDecorView
+ || slidingChild == mSpeedBumpView) {
continue;
}
float childTop = slidingChild.getTranslationY();
@@ -687,6 +704,7 @@ public class NotificationStackScrollLayout extends ViewGroup
transformTouchEvent(ev, this, mScrollView);
return mScrollView.onTouchEvent(ev);
}
+ handleEmptySpaceClick(ev);
boolean expandWantsIt = false;
if (!mSwipingInProgress && !mOnlyScrollingInThisMotion && isScrollingEnabled()) {
if (isCancelOrUp) {
@@ -1338,7 +1356,19 @@ public class NotificationStackScrollLayout extends ViewGroup
&& initialVelocity > 0;
}
- public void updateTopPadding(float qsHeight, int scrollY, boolean animate) {
+ /**
+ * Updates the top padding of the notifications, taking {@link #getIntrinsicPadding()} into
+ * account.
+ *
+ * @param qsHeight the top padding imposed by the quick settings panel
+ * @param scrollY how much the notifications are scrolled inside the QS/notifications scroll
+ * container
+ * @param animate whether to animate the change
+ * @param ignoreIntrinsicPadding if true, {@link #getIntrinsicPadding()} is ignored and
+ * {@code qsHeight} is the final top padding
+ */
+ public void updateTopPadding(float qsHeight, int scrollY, boolean animate,
+ boolean ignoreIntrinsicPadding) {
float start = qsHeight - scrollY + mNotificationTopPadding;
float stackHeight = getHeight() - start;
int minStackHeight = getMinStackHeight();
@@ -1346,13 +1376,13 @@ public class NotificationStackScrollLayout extends ViewGroup
float overflow = minStackHeight - stackHeight;
stackHeight = minStackHeight;
start = getHeight() - stackHeight;
- setTranslationY(overflow);
mTopPaddingOverflow = overflow;
} else {
- setTranslationY(0);
mTopPaddingOverflow = 0;
}
- setTopPadding(clampPadding((int) start), animate);
+ setTopPadding(ignoreIntrinsicPadding ? (int) start : clampPadding((int) start),
+ animate);
+ setStackHeight(mLastSetStackHeight);
}
public int getNotificationTopPadding() {
@@ -1430,6 +1460,7 @@ public class NotificationStackScrollLayout extends ViewGroup
transformTouchEvent(ev, mScrollView, this);
}
initDownStates(ev);
+ handleEmptySpaceClick(ev);
boolean expandWantsIt = false;
if (!mSwipingInProgress && !mOnlyScrollingInThisMotion && isScrollingEnabled()) {
expandWantsIt = mExpandHelper.onInterceptTouchEvent(ev);
@@ -1448,11 +1479,31 @@ public class NotificationStackScrollLayout extends ViewGroup
return swipeWantsIt || scrollWantsIt || expandWantsIt || super.onInterceptTouchEvent(ev);
}
+ private void handleEmptySpaceClick(MotionEvent ev) {
+ switch (ev.getActionMasked()) {
+ case MotionEvent.ACTION_MOVE:
+ if (mTouchIsClick && (Math.abs(ev.getY() - mInitialTouchY) > mTouchSlop
+ || Math.abs(ev.getX() - mInitialTouchX) > mTouchSlop )) {
+ mTouchIsClick = false;
+ }
+ break;
+ case MotionEvent.ACTION_UP:
+ if (mPhoneStatusBar.getBarState() != StatusBarState.KEYGUARD && mTouchIsClick &&
+ isBelowLastNotification(mInitialTouchX, mInitialTouchY)) {
+ mOnEmptySpaceClickListener.onEmptySpaceClicked(mInitialTouchX, mInitialTouchY);
+ }
+ break;
+ }
+ }
+
private void initDownStates(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
mExpandedInThisMotion = false;
mOnlyScrollingInThisMotion = !mScroller.isFinished();
mDisallowScrollingInThisMotion = false;
+ mTouchIsClick = true;
+ mInitialTouchX = ev.getX();
+ mInitialTouchY = ev.getY();
}
}
@@ -1886,7 +1937,14 @@ public class NotificationStackScrollLayout extends ViewGroup
* @return Whether the specified motion event is actually happening over the content.
*/
private boolean isInContentBounds(MotionEvent event) {
- return event.getY() < getHeight() - getEmptyBottomMargin();
+ return isInContentBounds(event.getY());
+ }
+
+ /**
+ * @return Whether a y coordinate is inside the content.
+ */
+ public boolean isInContentBounds(float y) {
+ return y < getHeight() - getEmptyBottomMargin();
}
private void setIsBeingDragged(boolean isDragged) {
@@ -1995,6 +2053,10 @@ public class NotificationStackScrollLayout extends ViewGroup
this.mOnHeightChangedListener = mOnHeightChangedListener;
}
+ public void setOnEmptySpaceClickListener(OnEmptySpaceClickListener listener) {
+ mOnEmptySpaceClickListener = listener;
+ }
+
public void onChildAnimationFinished() {
requestChildrenUpdate();
}
@@ -2245,6 +2307,24 @@ public class NotificationStackScrollLayout extends ViewGroup
}
}
+ private boolean isBelowLastNotification(float touchX, float touchY) {
+ ExpandableView lastChildNotGone = (ExpandableView) getLastChildNotGone();
+ if (lastChildNotGone == null) {
+ return touchY > mIntrinsicPadding;
+ }
+ if (lastChildNotGone != mDismissView && lastChildNotGone != mEmptyShadeView) {
+ return touchY > lastChildNotGone.getY() + lastChildNotGone.getActualHeight();
+ } else if (lastChildNotGone == mEmptyShadeView) {
+ return touchY > mEmptyShadeView.getY();
+ } else {
+ float dismissY = mDismissView.getY();
+ boolean belowDismissView = touchY > dismissY + mDismissView.getActualHeight();
+ return belowDismissView || (touchY > dismissY
+ && mDismissView.isOnEmptySpace(touchX - mDismissView.getX(),
+ touchY - dismissY));
+ }
+ }
+
/**
* A listener that is notified when some child locations might have changed.
*/
@@ -2253,6 +2333,13 @@ public class NotificationStackScrollLayout extends ViewGroup
}
/**
+ * A listener that is notified when the empty space below the notifications is clicked on
+ */
+ public interface OnEmptySpaceClickListener {
+ public void onEmptySpaceClicked(float x, float y);
+ }
+
+ /**
* A listener that gets notified when the overscroll at the top has changed.
*/
public interface OnOverscrollTopChangedListener {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
index 853628e..ddc4251 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -200,15 +200,25 @@ public class StackScrollAlgorithm {
// apply clipping and shadow
float newNotificationEnd = newYTranslation + newHeight;
- // In the unlocked shade we have to clip a little bit higher because of the rounded
- // corners of the notifications.
- float clippingCorrection = state.dimmed ? 0 : mRoundedRectCornerRadius * state.scale;
-
- // When the previous notification is swiped, we don't clip the content to the
- // bottom of it.
- float clipHeight = previousNotificationIsSwiped
- ? newHeight
- : newNotificationEnd - (previousNotificationEnd - clippingCorrection);
+ float clipHeight;
+ if (previousNotificationIsSwiped) {
+ // When the previous notification is swiped, we don't clip the content to the
+ // bottom of it.
+ clipHeight = newHeight;
+ } else {
+ clipHeight = newNotificationEnd - previousNotificationEnd;
+ clipHeight = Math.max(0.0f, clipHeight);
+ if (clipHeight != 0.0f) {
+
+ // In the unlocked shade we have to clip a little bit higher because of the rounded
+ // corners of the notifications, but only if we are not fully overlapped by
+ // the top card.
+ float clippingCorrection = state.dimmed
+ ? 0
+ : mRoundedRectCornerRadius * state.scale;
+ clipHeight += clippingCorrection;
+ }
+ }
updateChildClippingAndBackground(state, newHeight, clipHeight,
newHeight - (previousNotificationStart - newYTranslation));
@@ -669,7 +679,11 @@ public class StackScrollAlgorithm {
StackScrollState.ViewState childViewState = resultState.getViewStateForView(child);
if (i < algorithmState.itemsInTopStack) {
float stackIndex = algorithmState.itemsInTopStack - i;
- stackIndex = Math.min(stackIndex, MAX_ITEMS_IN_TOP_STACK + 2);
+
+ // Ensure that the topmost item is a little bit higher than the rest when fully
+ // scrolled, to avoid drawing errors when swiping it out
+ float max = MAX_ITEMS_IN_TOP_STACK + (i == 0 ? 2.5f : 2);
+ stackIndex = Math.min(stackIndex, max);
if (i == 0 && algorithmState.itemsInTopStack < 2.0f) {
// We only have the top item and an additional item in the top stack,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
index 0967ecd..4611370 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
@@ -119,9 +119,7 @@ public class StackScrollState {
}
// apply alpha
- if (!becomesInvisible) {
- child.setAlpha(newAlpha);
- }
+ child.setAlpha(newAlpha);
}
// apply visibility
@@ -236,6 +234,8 @@ public class StackScrollState {
public static final int LOCATION_MAIN_AREA = 0x08;
public static final int LOCATION_BOTTOM_STACK_PEEKING = 0x10;
public static final int LOCATION_BOTTOM_STACK_HIDDEN = 0x20;
+ /** The view isn't layouted at all. */
+ public static final int LOCATION_GONE = 0x40;
float alpha;
float yTranslation;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
index 433357e..674642b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
@@ -477,6 +477,7 @@ public class StackStateAnimator {
if (newEndValue == 0 && !mWasCancelled) {
child.setVisibility(View.INVISIBLE);
}
+ // remove the tag when the animation is finished
child.setTag(TAG_ANIMATOR_ALPHA, null);
child.setTag(TAG_START_ALPHA, null);
child.setTag(TAG_END_ALPHA, null);
@@ -498,13 +499,7 @@ public class StackStateAnimator {
animator.setStartDelay(delay);
}
animator.addListener(getGlobalAnimationFinishedListener());
- // remove the tag when the animation is finished
- animator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- }
- });
startAnimator(animator);
child.setTag(TAG_ANIMATOR_ALPHA, animator);
child.setTag(TAG_START_ALPHA, child.getAlpha());