summaryrefslogtreecommitdiffstats
path: root/packages/SystemUI/src/com/android/systemui/statusbar
diff options
context:
space:
mode:
authorSelim Cinek <cinek@google.com>2015-04-07 10:51:49 -0700
committerSelim Cinek <cinek@google.com>2015-04-15 12:50:12 -0700
commita59ecc3401de0c4bf1e13665158f54669f22d06c (patch)
tree0fd807011aa1fb73ea7c0ea5c408623c1817a533 /packages/SystemUI/src/com/android/systemui/statusbar
parentb8f09cf5533d458868a335ce334e4880b2b0788d (diff)
downloadframeworks_base-a59ecc3401de0c4bf1e13665158f54669f22d06c.zip
frameworks_base-a59ecc3401de0c4bf1e13665158f54669f22d06c.tar.gz
frameworks_base-a59ecc3401de0c4bf1e13665158f54669f22d06c.tar.bz2
Handling a few more border cases with HUNs
Also does sorting correctly now. The status bar now allows touches below when a heads-up is on. Also fixes a few flashes when a heads up was dismissed or appeared. Change-Id: I4d90a07333ad2e5ea2a13704cdc9d9184716681a
Diffstat (limited to 'packages/SystemUI/src/com/android/systemui/statusbar')
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java6
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java17
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java5
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java11
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java9
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java92
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java33
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java113
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java86
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java67
10 files changed, 304 insertions, 135 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index b9b3388..dc0b0e4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -1880,7 +1880,7 @@ public abstract class BaseStatusBar extends SystemUI implements
}
boolean applyInPlace = shouldApplyInPlace(entry, n);
final boolean shouldInterrupt = shouldInterrupt(notification);
- final boolean alertAgain = shouldInterrupt && alertAgain(entry, n);
+ final boolean alertAgain = alertAgain(entry, n);
boolean isHeadsUp = shouldInterrupt && alertAgain;
entry.notification = notification;
@@ -1947,8 +1947,12 @@ public abstract class BaseStatusBar extends SystemUI implements
if (wasHeadsUp) {
mHeadsUpManager.updateNotification(entry, alertAgain);
if (!shouldInterrupt) {
+ // We don't want this to be interrupting anymore, lets remove it
mHeadsUpManager.removeNotification(key);
}
+ } else if (shouldInterrupt && alertAgain) {
+ // This notification was updated to be a heads-up, show it!
+ mHeadsUpManager.showNotification(entry);
}
}
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 6fe609e..eacc436 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -510,9 +510,6 @@ public class NotificationPanelView extends PanelView implements
@Override
protected void flingToHeight(float vel, boolean expand, float target) {
- if (!expand && mHeadsUpManager.hasPinnedHeadsUp()) {
- target = mHeadsUpManager.getHighestPinnedHeadsUp();
- }
mHeadsUpTouchHelper.notifyFling(!expand);
super.flingToHeight(vel, expand, target);
}
@@ -722,7 +719,7 @@ public class NotificationPanelView extends PanelView implements
|| event.getActionMasked() == MotionEvent.ACTION_UP) {
mConflictingQsExpansionGesture = false;
}
- if (event.getActionMasked() == MotionEvent.ACTION_DOWN && mExpandedHeight == 0
+ if (event.getActionMasked() == MotionEvent.ACTION_DOWN && isShadeCollapsed()
&& mQsExpansionEnabled) {
mTwoFingerQsExpandPossible = true;
}
@@ -1774,7 +1771,7 @@ public class NotificationPanelView extends PanelView implements
}
private void updateMaxHeadsUpTranslation() {
- mNotificationStackScroller.setMaxHeadsUpTranslation(getHeight() - mBottomBarHeight);
+ mNotificationStackScroller.setHeadsUpBoundaries(getHeight(), mBottomBarHeight);
}
@Override
@@ -2151,16 +2148,12 @@ public class NotificationPanelView extends PanelView implements
@Override
public void OnHeadsUpStateChanged(NotificationData.Entry entry, boolean isHeadsUp) {
- // TODO: figure out the conditions when not to generate an animation
mNotificationStackScroller.generateHeadsUpAnimation(entry.row, isHeadsUp);
- if (isShadeCollapsed()) {
- setExpandedHeight(mHeadsUpManager.getHighestPinnedHeadsUp());
- }
}
- private boolean isShadeCollapsed() {
- // TODO: handle this cleaner
- return mHeader.getTranslationY() + mHeader.getCollapsedHeight() <= 0;
+ @Override
+ protected boolean isShadeCollapsed() {
+ return mExpandedHeight == 0 || mHeadsUpManager.hasPinnedHeadsUp();
}
@Override
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 1b89b3f..b19535b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -659,7 +659,7 @@ public abstract class PanelView extends FrameLayout {
// If the user isn't actively poking us, let's update the height
if ((!mTracking || isTrackingBlocked())
&& mHeightAnimator == null
- && mExpandedHeight > 0
+ && !isShadeCollapsed()
&& currentMaxPanelHeight != mExpandedHeight
&& !mPeekPending
&& mPeekAnimator == null
@@ -730,6 +730,7 @@ public abstract class PanelView extends FrameLayout {
}
public boolean isFullyCollapsed() {
+ // TODO: look into whether this is still correct with HUN's
return mExpandedHeight <= 0;
}
@@ -1019,6 +1020,8 @@ public abstract class PanelView extends FrameLayout {
*/
protected abstract int getClearAllHeight();
+ protected abstract boolean isShadeCollapsed();
+
public void setHeadsUpManager(HeadsUpManager headsUpManager) {
mHeadsUpManager = headsUpManager;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 74a26a8..ab4ac8b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -160,7 +160,7 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
-import java.util.TreeMap;
+import java.util.TreeSet;
import static android.app.StatusBarManager.NAVIGATION_HINT_BACK_ALT;
import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SHOWN;
@@ -615,7 +615,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
R.color.notification_panel_solid_background)));
}
- mHeadsUpManager = new HeadsUpManager(context);
+ mHeadsUpManager = new HeadsUpManager(context, mNotificationPanel.getViewTreeObserver());
mHeadsUpManager.setBar(this);
mHeadsUpManager.addListener(this);
mHeadsUpManager.addListener(mNotificationPanel);
@@ -1880,10 +1880,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
@Override
public void escalateHeadsUp() {
- TreeMap<String, HeadsUpManager.HeadsUpEntry> entries = mHeadsUpManager.getEntries();
- for (String key : entries.keySet()) {
- Entry entry = entries.get(key).entry;
- final StatusBarNotification sbn = entry.notification;
+ TreeSet<HeadsUpManager.HeadsUpEntry> entries = mHeadsUpManager.getSortedEntries();
+ for (HeadsUpManager.HeadsUpEntry entry : entries) {
+ final StatusBarNotification sbn = entry.entry.notification;
final Notification notification = sbn.getNotification();
if (notification.fullScreenIntent != null) {
if (DEBUG) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
index 6e0bf8f..84a9f64 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
@@ -172,11 +172,20 @@ public class StatusBarWindowManager {
applyUserActivityTimeout(state);
applyInputFeatures(state);
applyFitsSystemWindows(state);
+ applyModalFlag(state);
if (mLp.copyFrom(mLpChanged) != 0) {
mWindowManager.updateViewLayout(mStatusBarView, mLp);
}
}
+ private void applyModalFlag(State state) {
+ if (state.headsUpShowing) {
+ mLpChanged.flags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
+ } else {
+ mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
+ }
+ }
+
public void setKeyguardShowing(boolean showing) {
mCurrentState.keyguardShowing = showing;
apply(mCurrentState);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
index d43af59..85ff59a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
@@ -30,16 +30,18 @@ import android.view.ViewTreeObserver;
import android.view.accessibility.AccessibilityEvent;
import com.android.systemui.R;
+import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.NotificationData;
import com.android.systemui.statusbar.phone.PhoneStatusBar;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.Stack;
-import java.util.TreeMap;
+import java.util.TreeSet;
-public class HeadsUpManager {
+public class HeadsUpManager implements ViewTreeObserver.OnComputeInternalInsetsListener {
private static final String TAG = "HeadsUpManager";
private static final boolean DEBUG = false;
private static final String SETTING_HEADS_UP_SNOOZE_LENGTH_MS = "heads_up_snooze_length_ms";
@@ -76,8 +78,8 @@ public class HeadsUpManager {
private PhoneStatusBar mBar;
private int mSnoozeLengthMs;
private ContentObserver mSettingsObserver;
-
- private TreeMap<String ,HeadsUpEntry> mHeadsUpEntries = new TreeMap<>();
+ private HashMap<String, HeadsUpEntry> mHeadsUpEntries = new HashMap<>();
+ private TreeSet<HeadsUpEntry> mSortedEntries = new TreeSet<>();
private HashSet<String> mSwipedOutKeys = new HashSet<>();
private int mUser;
private Clock mClock;
@@ -86,8 +88,9 @@ public class HeadsUpManager {
private HashSet<NotificationData.Entry> mEntriesToRemoveAfterExpand = new HashSet<>();
private boolean mIsExpanded;
private boolean mHasPinnedHeadsUp;
+ private int[] mTmpTwoArray = new int[2];
- public HeadsUpManager(final Context context) {
+ public HeadsUpManager(final Context context, ViewTreeObserver observer) {
Resources resources = context.getResources();
mTouchSensitivityDelay = resources.getInteger(R.integer.heads_up_sensitivity_delay);
if (DEBUG) Log.v(TAG, "create() " + mTouchSensitivityDelay);
@@ -95,7 +98,7 @@ public class HeadsUpManager {
mDefaultSnoozeLengthMs = resources.getInteger(R.integer.heads_up_default_snooze_length_ms);
mSnoozeLengthMs = mDefaultSnoozeLengthMs;
mMinimumDisplayTime = resources.getInteger(R.integer.heads_up_notification_minimum_time);
- mHeadsUpNotificationDecay = 2000000;
+ mHeadsUpNotificationDecay = 200000000/*resources.getInteger(R.integer.heads_up_notification_decay)*/;;
mClock = new Clock();
// TODO: shadow mSwipeHelper.setMaxSwipeProgress(mMaxAlpha);
@@ -116,12 +119,7 @@ public class HeadsUpManager {
Settings.Global.getUriFor(SETTING_HEADS_UP_SNOOZE_LENGTH_MS), false,
mSettingsObserver);
if (DEBUG) Log.v(TAG, "mSnoozeLengthMs = " + mSnoozeLengthMs);
-
- // TODO: investigate whether this is still needed
-// if (!mHeadsUpEntries.isEmpty()) {
-// whoops, we're on already!
-// showNotification(mHeadsUpEntries);
-// }
+ observer.addOnComputeInternalInsetsListener(this);
}
public void setBar(PhoneStatusBar bar) {
@@ -144,7 +142,6 @@ public class HeadsUpManager {
addHeadsUpEntry(headsUp);
updateNotification(headsUp, true);
headsUp.setInterruption();
- updatePinnedHeadsUpState(false);
}
/**
@@ -164,26 +161,32 @@ public class HeadsUpManager {
}
private void addHeadsUpEntry(NotificationData.Entry entry) {
- boolean wasEmpty = mHeadsUpEntries.isEmpty();
HeadsUpEntry headsUpEntry = mEntryPool.acquire();
+
+ // This will also add the entry to the sortedList
headsUpEntry.setEntry(entry);
mHeadsUpEntries.put(entry.key, headsUpEntry);
+ entry.row.setHeadsUp(true);
+ if (!entry.row.isInShade() && mIsExpanded) {
+ headsUpEntry.entry.row.setInShade(true);
+ }
+ updatePinnedHeadsUpState(false);
for (OnHeadsUpChangedListener listener : mListeners) {
listener.OnHeadsUpStateChanged(entry, true);
}
entry.row.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
- entry.row.setHeadsUp(true);
}
private void removeHeadsUpEntry(NotificationData.Entry entry) {
HeadsUpEntry remove = mHeadsUpEntries.remove(entry.key);
+ mSortedEntries.remove(remove);
mEntryPool.release(remove);
entry.row.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
entry.row.setHeadsUp(false);
+ updatePinnedHeadsUpState(false);
for (OnHeadsUpChangedListener listener : mListeners) {
listener.OnHeadsUpStateChanged(entry, false);
}
- updatePinnedHeadsUpState(false);
}
private void updatePinnedHeadsUpState(boolean forceImmediate) {
@@ -238,7 +241,8 @@ public class HeadsUpManager {
*/
public void releaseAllImmediately() {
if (DEBUG) Log.v(TAG, "releaseAllImmediately");
- for (String key: mHeadsUpEntries.keySet()) {
+ HashSet<String> keys = new HashSet<>(mHeadsUpEntries.keySet());
+ for (String key: keys) {
releaseImmediately(key);
}
}
@@ -287,12 +291,12 @@ public class HeadsUpManager {
return mHeadsUpEntries.get(key).entry;
}
- public TreeMap<String, HeadsUpEntry> getEntries() {
- return mHeadsUpEntries;
+ public TreeSet<HeadsUpEntry> getSortedEntries() {
+ return mSortedEntries;
}
public HeadsUpEntry getTopEntry() {
- return mHeadsUpEntries.isEmpty() ? null : mHeadsUpEntries.lastEntry().getValue();
+ return mSortedEntries.isEmpty() ? null : mSortedEntries.first();
}
/**
@@ -313,13 +317,25 @@ public class HeadsUpManager {
}
public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo info) {
- // TODO: Look into touchable region
-// mContentHolder.getLocationOnScreen(mTmpTwoArray);
-//
-// info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
-// info.touchableRegion.set(mTmpTwoArray[0], mTmpTwoArray[1],
-// mTmpTwoArray[0] + mContentHolder.getWidth(),
-// mTmpTwoArray[1] + mContentHolder.getHeight());
+ if (!mIsExpanded && mHasPinnedHeadsUp) {
+ int minX = Integer.MAX_VALUE;
+ int maxX = 0;
+ int minY = Integer.MAX_VALUE;
+ int maxY = 0;
+ for (HeadsUpEntry entry: mSortedEntries) {
+ ExpandableNotificationRow row = entry.entry.row;
+ if (!row.isInShade()) {
+ row.getLocationOnScreen(mTmpTwoArray);
+ minX = Math.min(minX, mTmpTwoArray[0]);
+ minY = Math.min(minY, 0);
+ maxX = Math.max(maxX, mTmpTwoArray[0] + row.getWidth());
+ maxY = Math.max(maxY, row.getHeadsUpHeight());
+ }
+ }
+
+ info.setTouchableInsets(ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
+ info.touchableRegion.set(minX, minY, maxX, maxY);
+ }
}
public void setUser(int user) {
@@ -332,8 +348,8 @@ public class HeadsUpManager {
pw.print(" mSnoozeLengthMs="); pw.println(mSnoozeLengthMs);
pw.print(" now="); pw.println(SystemClock.elapsedRealtime());
pw.print(" mUser="); pw.println(mUser);
- for (String key: mHeadsUpEntries.keySet()) {
- pw.print(" HeadsUpEntry="); pw.println(mHeadsUpEntries.get(key));
+ for (HeadsUpEntry entry: mSortedEntries) {
+ pw.print(" HeadsUpEntry="); pw.println(entry.entry);
}
int N = mSnoozedPackages.size();
pw.println(" snoozed packages: " + N);
@@ -363,8 +379,7 @@ public class HeadsUpManager {
public float getHighestPinnedHeadsUp() {
float max = 0;
- for (String key: mHeadsUpEntries.keySet()) {
- HeadsUpEntry entry = mHeadsUpEntries.get(key);
+ for (HeadsUpEntry entry: mSortedEntries) {
if (!entry.entry.row.isInShade()) {
max = Math.max(max, entry.entry.row.getActualHeight());
}
@@ -437,13 +452,14 @@ public class HeadsUpManager {
earliestRemovaltime = currentTime + mMinimumDisplayTime;
removeAutoCancelCallbacks();
mHandler.postDelayed(mRemoveHeadsUpRunnable, removeDelay);
+ updateSortOrder(HeadsUpEntry.this);
}
@Override
public int compareTo(HeadsUpEntry o) {
- return postTime < o.postTime ? -1
+ return postTime < o.postTime ? 1
: postTime == o.postTime ? 0
- : 1;
+ : -1;
}
public void removeAutoCancelCallbacks() {
@@ -461,6 +477,16 @@ public class HeadsUpManager {
}
}
+ /**
+ * Update the sorted heads up order.
+ *
+ * @param headsUpEntry the headsUp that changed
+ */
+ private void updateSortOrder(HeadsUpEntry headsUpEntry) {
+ mSortedEntries.remove(headsUpEntry);
+ mSortedEntries.add(headsUpEntry);
+ }
+
public static class Clock {
public long currentTimeMillis() {
return SystemClock.elapsedRealtime();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
index 824ba94..f2b971f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
@@ -17,11 +17,13 @@
package com.android.systemui.statusbar.stack;
import android.view.View;
+
import com.android.systemui.statusbar.ActivatableNotificationView;
+import com.android.systemui.statusbar.ExpandableNotificationRow;
import com.android.systemui.statusbar.policy.HeadsUpManager;
import java.util.ArrayList;
-import java.util.TreeMap;
+import java.util.TreeSet;
/**
* A global state to track all input states for the algorithm.
@@ -37,7 +39,7 @@ public class AmbientState {
private boolean mDark;
private boolean mHideSensitive;
private HeadsUpManager mHeadsUpManager;
- private float mPaddingOffset;
+ private float mStackTranslation;
private int mLayoutHeight;
private int mTopPadding;
private boolean mShadeExpanded;
@@ -128,16 +130,16 @@ public class AmbientState {
mHeadsUpManager = headsUpManager;
}
- public TreeMap<String, HeadsUpManager.HeadsUpEntry> getHeadsUpEntries() {
- return mHeadsUpManager.getEntries();
+ public TreeSet<HeadsUpManager.HeadsUpEntry> getSortedHeadsUpEntries() {
+ return mHeadsUpManager.getSortedEntries();
}
- public float getPaddingOffset() {
- return mPaddingOffset;
+ public float getStackTranslation() {
+ return mStackTranslation;
}
- public void setPaddingOffset(float paddingOffset) {
- mPaddingOffset = paddingOffset;
+ public void setStackTranslation(float stackTranslation) {
+ mStackTranslation = stackTranslation;
}
public int getLayoutHeight() {
@@ -148,7 +150,7 @@ public class AmbientState {
mLayoutHeight = layoutHeight;
}
- public int getTopPadding() {
+ public float getTopPadding() {
return mTopPadding;
}
@@ -157,7 +159,13 @@ public class AmbientState {
}
public int getInnerHeight() {
- return mLayoutHeight - mTopPadding;
+ return mLayoutHeight - mTopPadding - getTopHeadsUpPushIn();
+ }
+
+ private int getTopHeadsUpPushIn() {
+ ExpandableNotificationRow topHeadsUpEntry = getTopHeadsUpEntry();
+ return topHeadsUpEntry != null ? topHeadsUpEntry.getHeadsUpHeight()
+ - topHeadsUpEntry.getMinHeight(): 0;
}
public boolean isShadeExpanded() {
@@ -175,4 +183,9 @@ public class AmbientState {
public float getMaxHeadsUpTranslation() {
return mMaxHeadsUpTranslation;
}
+
+ public ExpandableNotificationRow getTopHeadsUpEntry() {
+ HeadsUpManager.HeadsUpEntry topEntry = mHeadsUpManager.getTopEntry();
+ return topEntry == null ? null : topEntry.entry.row;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index cac1b8a..656f23a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -123,15 +123,15 @@ public class NotificationStackScrollLayout extends ViewGroup
private StackScrollState mCurrentStackScrollState = new StackScrollState(this);
private AmbientState mAmbientState = new AmbientState();
private NotificationGroupManager mGroupManager;
- private ArrayList<View> mChildrenToAddAnimated = new ArrayList<View>();
- private ArrayList<View> mChildrenToRemoveAnimated = new ArrayList<View>();
- private ArrayList<View> mSnappedBackChildren = new ArrayList<View>();
- private ArrayList<View> mDragAnimPendingChildren = new ArrayList<View>();
- private ArrayList<View> mChildrenChangingPositions = new ArrayList<View>();
+ private ArrayList<View> mChildrenToAddAnimated = new ArrayList<>();
+ private ArrayList<View> mAddedHeadsUpChildren = new ArrayList<>();
+ private ArrayList<View> mChildrenToRemoveAnimated = new ArrayList<>();
+ private ArrayList<View> mSnappedBackChildren = new ArrayList<>();
+ private ArrayList<View> mDragAnimPendingChildren = new ArrayList<>();
+ private ArrayList<View> mChildrenChangingPositions = new ArrayList<>();
private HashSet<View> mFromMoreCardAdditions = new HashSet<>();
- private ArrayList<AnimationEvent> mAnimationEvents
- = new ArrayList<AnimationEvent>();
- private ArrayList<View> mSwipedOutViews = new ArrayList<View>();
+ private ArrayList<AnimationEvent> mAnimationEvents = new ArrayList<>();
+ private ArrayList<View> mSwipedOutViews = new ArrayList<>();
private final StackStateAnimator mStateAnimator = new StackStateAnimator(this);
private boolean mAnimationsEnabled;
private boolean mChangePositionInProgress;
@@ -145,7 +145,6 @@ public class NotificationStackScrollLayout extends ViewGroup
* The raw amount of the overScroll on the bottom, which is not rubber-banded.
*/
private float mOverScrolledBottomPixels;
-
private OnChildLocationsChangedListener mListener;
private OnOverscrollTopChangedListener mOverscrollTopChangedListener;
private ExpandableView.OnHeightChangedListener mOnHeightChangedListener;
@@ -173,7 +172,6 @@ public class NotificationStackScrollLayout extends ViewGroup
* Was the scroller scrolled to the top when the down motion was observed?
*/
private boolean mScrolledToTopOnFirstDown;
-
/**
* The minimal amount of over scroll which is needed in order to switch to the quick settings
* when over scrolling on a expanded card.
@@ -187,15 +185,14 @@ public class NotificationStackScrollLayout extends ViewGroup
private boolean mRequestViewResizeAnimationOnLayout;
private boolean mNeedViewResizeAnimation;
private View mExpandedGroupView;
-
private boolean mEverythingNeedsAnimation;
+
/**
* The maximum scrollPosition which we are allowed to reach when a notification was expanded.
* This is needed to avoid scrolling too far after the notification was collapsed in the same
* motion.
*/
private int mMaxScrollAfterExpand;
-
private SwipeHelper.LongPressListener mLongPressListener;
/**
@@ -206,8 +203,8 @@ public class NotificationStackScrollLayout extends ViewGroup
private ViewGroup mScrollView;
private boolean mInterceptDelegateEnabled;
private boolean mDelegateToScrollView;
- private boolean mDisallowScrollingInThisMotion;
+ private boolean mDisallowScrollingInThisMotion;
private long mGoToFullShadeDelay;
private ViewTreeObserver.OnPreDrawListener mChildrenUpdater
= new ViewTreeObserver.OnPreDrawListener() {
@@ -529,7 +526,7 @@ public class NotificationStackScrollLayout extends ViewGroup
private void setPaddingOffset(float paddingOffset) {
if (paddingOffset != mPaddingOffset) {
mPaddingOffset = paddingOffset;
- mAmbientState.setPaddingOffset(paddingOffset);
+ mAmbientState.setStackTranslation(paddingOffset);
requestChildrenUpdate();
}
}
@@ -617,13 +614,29 @@ public class NotificationStackScrollLayout extends ViewGroup
public void onBeginDrag(View v) {
setSwipingInProgress(true);
mAmbientState.onBeginDrag(v);
- if (mAnimationsEnabled) {
+ if (mAnimationsEnabled && !isPinnedHeadsUp(v)) {
mDragAnimPendingChildren.add(v);
mNeedsAnimation = true;
}
requestChildrenUpdate();
}
+ private boolean isPinnedHeadsUp(View v) {
+ if (v instanceof ExpandableNotificationRow) {
+ ExpandableNotificationRow row = (ExpandableNotificationRow) v;
+ return row.isHeadsUp() && !row.isInShade();
+ }
+ return false;
+ }
+
+ private boolean isHeadsUp(View v) {
+ if (v instanceof ExpandableNotificationRow) {
+ ExpandableNotificationRow row = (ExpandableNotificationRow) v;
+ return row.isHeadsUp();
+ }
+ return false;
+ }
+
public void onDragCancelled(View v) {
setSwipingInProgress(false);
}
@@ -693,6 +706,10 @@ public class NotificationStackScrollLayout extends ViewGroup
if (touchY >= top && touchY <= bottom && touchX >= left && touchX <= right) {
if (slidingChild instanceof ExpandableNotificationRow) {
ExpandableNotificationRow row = (ExpandableNotificationRow) slidingChild;
+ if (row.isHeadsUp() && !row.isInShade()
+ && mHeadsUpManager.getTopEntry().entry.row != row) {
+ continue;
+ }
return row.getViewAtPosition(touchY - childTop);
}
return slidingChild;
@@ -1788,6 +1805,10 @@ public class NotificationStackScrollLayout extends ViewGroup
}
mNeedsAnimation = true;
}
+ if (isHeadsUp(child)) {
+ mAddedHeadsUpChildren.add(child);
+ mChildrenToAddAnimated.remove(child);
+ }
}
/**
@@ -1826,6 +1847,7 @@ public class NotificationStackScrollLayout extends ViewGroup
}
private void generateChildHierarchyEvents() {
+ generateHeadsUpAnimationEvents();
generateChildRemovalEvents();
generateChildAdditionEvents();
generatePositionChangeEvents();
@@ -1839,19 +1861,42 @@ public class NotificationStackScrollLayout extends ViewGroup
generateGoToFullShadeEvent();
generateViewResizeEvent();
generateGroupExpansionEvent();
- generateHeadsUpAnimationEvents();
generateAnimateEverythingEvent();
mNeedsAnimation = false;
}
private void generateHeadsUpAnimationEvents() {
for (Pair<ExpandableNotificationRow, Boolean> eventPair : mHeadsUpChangeAnimations) {
- int type = eventPair.second ? AnimationEvent.ANIMATION_TYPE_HEADS_UP_APPEAR
- : AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR;
- mAnimationEvents.add(new AnimationEvent(eventPair.first,
- type));
+ ExpandableNotificationRow row = eventPair.first;
+ boolean isHeadsUp = eventPair.second;
+ int type = AnimationEvent.ANIMATION_TYPE_HEADS_UP_OTHER;
+ boolean onBottom = false;
+ if (!row.isInShade() && !isHeadsUp) {
+ type = AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR;
+ } else if (mAddedHeadsUpChildren.contains(row)) {
+ if (!row.isInShade() || shouldHunAppearFromBottom(row)) {
+ // Our custom add animation
+ type = AnimationEvent.ANIMATION_TYPE_HEADS_UP_APPEAR;
+ } else {
+ // Normal add animation
+ type = AnimationEvent.ANIMATION_TYPE_ADD;
+ }
+ onBottom = row.isInShade();
+ }
+ AnimationEvent event = new AnimationEvent(row, type);
+ event.headsUpFromBottom = onBottom;
+ mAnimationEvents.add(event);
}
mHeadsUpChangeAnimations.clear();
+ mAddedHeadsUpChildren.clear();
+ }
+
+ private boolean shouldHunAppearFromBottom(ExpandableNotificationRow row) {
+ StackViewState viewState = mCurrentStackScrollState.getViewStateForView(row);
+ if (viewState.yTranslation + viewState.height < mAmbientState.getMaxHeadsUpTranslation()) {
+ return false;
+ }
+ return true;
}
private void generateGroupExpansionEvent() {
@@ -2649,10 +2694,19 @@ public class NotificationStackScrollLayout extends ViewGroup
public void setShadeExpanded(boolean shadeExpanded) {
mAmbientState.setShadeExpanded(shadeExpanded);
+ mStateAnimator.setShadeExpanded(shadeExpanded);
}
- public void setMaxHeadsUpTranslation(int maxTranslation) {
- mAmbientState.setMaxHeadsUpTranslation(maxTranslation);
+ /**
+ * Set the boundary for the bottom heads up position. The heads up will always be above this
+ * position.
+ *
+ * @param height the height of the screen
+ * @param bottomBarHeight the height of the bar on the bottom
+ */
+ public void setHeadsUpBoundaries(int height, int bottomBarHeight) {
+ mAmbientState.setMaxHeadsUpTranslation(height - bottomBarHeight);
+ mStateAnimator.setHeadsUpAppearHeightBottom(height);
requestChildrenUpdate();
}
@@ -2820,6 +2874,14 @@ public class NotificationStackScrollLayout extends ViewGroup
.animateY()
.animateZ(),
+ // ANIMATION_TYPE_HEADS_UP_OTHER
+ new AnimationFilter()
+ .animateAlpha()
+ .animateHeight()
+ .animateTopInset()
+ .animateY()
+ .animateZ(),
+
// ANIMATION_TYPE_EVERYTHING
new AnimationFilter()
.animateAlpha()
@@ -2883,6 +2945,9 @@ public class NotificationStackScrollLayout extends ViewGroup
// ANIMATION_TYPE_HEADS_UP_DISAPPEAR
StackStateAnimator.ANIMATION_DURATION_HEADS_UP_DISAPPEAR,
+ // ANIMATION_TYPE_HEADS_UP_OTHER
+ StackStateAnimator.ANIMATION_DURATION_STANDARD,
+
// ANIMATION_TYPE_EVERYTHING
StackStateAnimator.ANIMATION_DURATION_STANDARD,
};
@@ -2903,7 +2968,8 @@ public class NotificationStackScrollLayout extends ViewGroup
static final int ANIMATION_TYPE_GROUP_EXPANSION_CHANGED = 13;
static final int ANIMATION_TYPE_HEADS_UP_APPEAR = 14;
static final int ANIMATION_TYPE_HEADS_UP_DISAPPEAR = 15;
- static final int ANIMATION_TYPE_EVERYTHING = 16;
+ static final int ANIMATION_TYPE_HEADS_UP_OTHER = 16;
+ static final int ANIMATION_TYPE_EVERYTHING = 17;
static final int DARK_ANIMATION_ORIGIN_INDEX_ABOVE = -1;
static final int DARK_ANIMATION_ORIGIN_INDEX_BELOW = -2;
@@ -2915,6 +2981,7 @@ public class NotificationStackScrollLayout extends ViewGroup
final long length;
View viewAfterChangingView;
int darkAnimationOriginIndex;
+ boolean headsUpFromBottom;
AnimationEvent(View view, int type) {
this(view, type, LENGTHS[type]);
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 b0f287f..1a42f45 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -29,7 +29,7 @@ import com.android.systemui.statusbar.policy.HeadsUpManager;
import java.util.ArrayList;
import java.util.List;
-import java.util.TreeMap;
+import java.util.TreeSet;
/**
* The Algorithm of the {@link com.android.systemui.statusbar.stack
@@ -167,7 +167,7 @@ public class StackScrollAlgorithm {
handleDraggedViews(ambientState, resultState, algorithmState);
updateDimmedActivatedHideSensitive(ambientState, resultState, algorithmState);
- updateClipping(resultState, algorithmState);
+ updateClipping(resultState, algorithmState, ambientState);
updateSpeedBumpState(resultState, algorithmState, ambientState.getSpeedBumpIndex());
getNotificationChildrenStates(resultState, algorithmState);
}
@@ -198,7 +198,7 @@ public class StackScrollAlgorithm {
}
private void updateClipping(StackScrollState resultState,
- StackScrollAlgorithmState algorithmState) {
+ StackScrollAlgorithmState algorithmState, AmbientState ambientState) {
float previousNotificationEnd = 0;
float previousNotificationStart = 0;
boolean previousNotificationIsSwiped = false;
@@ -239,7 +239,7 @@ public class StackScrollAlgorithm {
// otherwise we would clip to a transparent view.
previousNotificationStart = newYTranslation + state.clipTopAmount * state.scale;
previousNotificationEnd = newNotificationEnd;
- previousNotificationIsSwiped = child.getTranslationX() != 0;
+ previousNotificationIsSwiped = ambientState.getDraggedViews().contains(child);
}
}
}
@@ -311,7 +311,9 @@ public class StackScrollAlgorithm {
StackViewState viewState = resultState.getViewStateForView(
nextChild);
// The child below the dragged one must be fully visible
- viewState.alpha = 1;
+ if (!isPinnedHeadsUpView(draggedView) || isPinnedHeadsUpView(nextChild)) {
+ viewState.alpha = 1;
+ }
}
// Lets set the alpha to the one it currently has, as its currently being dragged
@@ -322,6 +324,14 @@ public class StackScrollAlgorithm {
}
}
+ private boolean isPinnedHeadsUpView(View view) {
+ if (view instanceof ExpandableNotificationRow) {
+ ExpandableNotificationRow row = (ExpandableNotificationRow) view;
+ return row.isHeadsUp() && !row.isInShade();
+ }
+ return false;
+ }
+
/**
* Update the visible children on the state.
*/
@@ -332,16 +342,15 @@ public class StackScrollAlgorithm {
state.visibleChildren.clear();
state.visibleChildren.ensureCapacity(childCount);
int notGoneIndex = 0;
- TreeMap<String, HeadsUpManager.HeadsUpEntry> headsUpEntries =
- ambientState.getHeadsUpEntries();
- for (String key: headsUpEntries.keySet()) {
- ExpandableView v = headsUpEntries.get(key).entry.row;
+ TreeSet<HeadsUpManager.HeadsUpEntry> headsUpEntries
+ = ambientState.getSortedHeadsUpEntries();
+ for (HeadsUpManager.HeadsUpEntry entry: headsUpEntries) {
+ ExpandableView v = entry.entry.row;
notGoneIndex = updateNotGoneIndex(resultState, state, notGoneIndex, v);
}
for (int i = 0; i < childCount; i++) {
ExpandableView v = (ExpandableView) hostView.getChildAt(i);
if (v.getVisibility() != View.GONE) {
-
if (v instanceof ExpandableNotificationRow) {
ExpandableNotificationRow row = (ExpandableNotificationRow) v;
if (row.isHeadsUp()) {
@@ -401,13 +410,17 @@ public class StackScrollAlgorithm {
// How far in is the element currently transitioning into the bottom stack.
float yPositionInScrollView = 0.0f;
+ // If we have a heads-up higher than the collapsed height we need to add the difference to
+ // the padding of all other elements, i.e push in the top stack slightly.
+ ExpandableNotificationRow topHeadsUpEntry = ambientState.getTopHeadsUpEntry();
+
int childCount = algorithmState.visibleChildren.size();
int numberOfElementsCompletelyIn = (int) algorithmState.itemsInTopStack;
for (int i = 0; i < childCount; i++) {
ExpandableView child = algorithmState.visibleChildren.get(i);
StackViewState childViewState = resultState.getViewStateForView(child);
childViewState.location = StackViewState.LOCATION_UNKNOWN;
- int childHeight = getMaxAllowedChildHeight(child);
+ int childHeight = getMaxAllowedChildHeight(child, ambientState);
float yPositionInScrollViewAfterElement = yPositionInScrollView
+ childHeight
+ mPaddingBetweenElements;
@@ -486,45 +499,31 @@ public class StackScrollAlgorithm {
currentYPosition = childViewState.yTranslation + childHeight + mPaddingBetweenElements;
yPositionInScrollView = yPositionInScrollViewAfterElement;
+ if (ambientState.isShadeExpanded() && topHeadsUpEntry != null
+ && child != topHeadsUpEntry) {
+ childViewState.yTranslation += topHeadsUpEntry.getHeadsUpHeight() - mCollapsedSize;
+ }
childViewState.yTranslation += ambientState.getTopPadding()
- + ambientState.getPaddingOffset();
-
- updateHeadsUpStates(resultState, algorithmState, ambientState);
+ + ambientState.getStackTranslation();
}
+ updateHeadsUpStates(resultState, algorithmState, ambientState);
}
private void updateHeadsUpStates(StackScrollState resultState,
StackScrollAlgorithmState algorithmState, AmbientState ambientState) {
- TreeMap<String, HeadsUpManager.HeadsUpEntry> headsUpEntries =
- ambientState.getHeadsUpEntries();
- boolean hasPinnedHeadsUp = false;
- for (String key: headsUpEntries.keySet()) {
- ExpandableNotificationRow row = headsUpEntries.get(key).entry.row;
+ TreeSet<HeadsUpManager.HeadsUpEntry> headsUpEntries = ambientState.getSortedHeadsUpEntries();
+ for (HeadsUpManager.HeadsUpEntry entry: headsUpEntries) {
+ ExpandableNotificationRow row = entry.entry.row;
StackViewState childState = resultState.getViewStateForView(row);
if (!row.isInShade()) {
- childState.yTranslation = Math.max(childState.yTranslation, 0);
- hasPinnedHeadsUp = true;
+ childState.yTranslation = 0;
}
childState.height = Math.max(childState.height, row.getHeadsUpHeight());
+
+ // Ensure that the heads up is always visible even when scrolled of from the bottom
childState.yTranslation = Math.min(childState.yTranslation,
ambientState.getMaxHeadsUpTranslation() - childState.height);
}
- if (hasPinnedHeadsUp && !ambientState.isShadeExpanded()) {
- // Let's hide all normal views
- int childCount = algorithmState.visibleChildren.size();
- for (int i = 0; i < childCount; i++) {
- ExpandableView child = algorithmState.visibleChildren.get(i);
- StackViewState state = resultState.getViewStateForView(child);
- boolean hideView = true;
- if (child instanceof ExpandableNotificationRow) {
- ExpandableNotificationRow row = (ExpandableNotificationRow) child;
- hideView = !row.isHeadsUp();
- }
- if (hideView) {
- state.alpha = 0.0f;
- }
- }
- }
}
/**
@@ -555,7 +554,7 @@ public class StackScrollAlgorithm {
/**
* Clamp the yTranslation of the child up such that its end is at lest on the end of the top
- * stack.get
+ * stack.
*
* @param childViewState the view state of the child
* @param childHeight the height of this child
@@ -566,9 +565,12 @@ public class StackScrollAlgorithm {
mCollapsedSize - childHeight);
}
- private int getMaxAllowedChildHeight(View child) {
+ private int getMaxAllowedChildHeight(View child, AmbientState ambientState) {
if (child instanceof ExpandableNotificationRow) {
ExpandableNotificationRow row = (ExpandableNotificationRow) child;
+ if (ambientState != null && ambientState.getTopHeadsUpEntry() == child) {
+ return mCollapsedSize;
+ }
return row.getIntrinsicHeight();
} else if (child instanceof ExpandableView) {
ExpandableView expandableView = (ExpandableView) child;
@@ -695,7 +697,7 @@ public class StackScrollAlgorithm {
for (int i = 0; i < childCount; i++) {
ExpandableView child = algorithmState.visibleChildren.get(i);
StackViewState childViewState = resultState.getViewStateForView(child);
- int childHeight = getMaxAllowedChildHeight(child);
+ int childHeight = getMaxAllowedChildHeight(child, ambientState);
float yPositionInScrollViewAfterElement = yPositionInScrollView
+ childHeight
+ mPaddingBetweenElements;
@@ -850,7 +852,7 @@ public class StackScrollAlgorithm {
int oldBottom) {
if (mFirstChildWhileExpanding != null) {
mFirstChildMaxHeight = getMaxAllowedChildHeight(
- mFirstChildWhileExpanding);
+ mFirstChildWhileExpanding, null);
} else {
mFirstChildMaxHeight = 0;
}
@@ -858,7 +860,7 @@ public class StackScrollAlgorithm {
}
});
} else {
- mFirstChildMaxHeight = getMaxAllowedChildHeight(mFirstChildWhileExpanding);
+ mFirstChildMaxHeight = getMaxAllowedChildHeight(mFirstChildWhileExpanding, null);
}
}
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 9640b84..b869c27 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
@@ -21,9 +21,11 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
+import android.graphics.Path;
import android.view.View;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
+import android.view.animation.PathInterpolator;
import com.android.systemui.R;
import com.android.systemui.statusbar.ExpandableNotificationRow;
@@ -32,7 +34,6 @@ import com.android.systemui.statusbar.SpeedBumpView;
import java.util.ArrayList;
import java.util.HashSet;
-import java.util.Set;
import java.util.Stack;
/**
@@ -46,7 +47,7 @@ public class StackStateAnimator {
public static final int ANIMATION_DURATION_EXPAND_CLICKED = 360;
public static final int ANIMATION_DURATION_DIMMED_ACTIVATED = 220;
public static final int ANIMATION_DURATION_HEADS_UP_APPEAR = 280;
- public static final int ANIMATION_DURATION_HEADS_UP_DISAPPEAR = 220;
+ public static final int ANIMATION_DURATION_HEADS_UP_DISAPPEAR = 230;
public static final int ANIMATION_DELAY_PER_ELEMENT_INTERRUPTING = 80;
public static final int ANIMATION_DELAY_PER_ELEMENT_EXPAND_CHILDREN = 54;
public static final int ANIMATION_DELAY_PER_ELEMENT_MANUAL = 32;
@@ -75,12 +76,15 @@ public class StackStateAnimator {
private static final int TAG_START_TOP_INSET = R.id.top_inset_animator_start_value_tag;
private final Interpolator mFastOutSlowInInterpolator;
+ private final Interpolator mHeadsUpAppearInterpolator;
private final int mGoToFullShadeAppearingTranslation;
public NotificationStackScrollLayout mHostLayout;
private ArrayList<NotificationStackScrollLayout.AnimationEvent> mNewEvents =
new ArrayList<>();
private ArrayList<View> mNewAddChildren = new ArrayList<>();
- private Set<Animator> mAnimatorSet = new HashSet<>();
+ private HashSet<View> mHeadsUpAppearChildren = new HashSet<>();
+ private HashSet<View> mHeadsUpDisappearChildren = new HashSet<>();
+ private HashSet<Animator> mAnimatorSet = new HashSet<>();
private Stack<AnimatorListenerAdapter> mAnimationListenerPool = new Stack<>();
private AnimationFilter mAnimationFilter = new AnimationFilter();
private long mCurrentLength;
@@ -88,11 +92,12 @@ public class StackStateAnimator {
/** The current index for the last child which was not added in this event set. */
private int mCurrentLastNotAddedIndex;
-
private ValueAnimator mTopOverScrollAnimator;
private ValueAnimator mBottomOverScrollAnimator;
private ExpandableNotificationRow mChildExpandingView;
private StackViewState mTmpState = new StackViewState();
+ private int mHeadsUpAppearHeightBottom;
+ private boolean mShadeExpanded;
public StackStateAnimator(NotificationStackScrollLayout hostLayout) {
mHostLayout = hostLayout;
@@ -101,6 +106,10 @@ public class StackStateAnimator {
mGoToFullShadeAppearingTranslation =
hostLayout.getContext().getResources().getDimensionPixelSize(
R.dimen.go_to_full_shade_appearing_translation);
+ Path path = new Path();
+ path.moveTo(0, 0);
+ path.cubicTo(0.8f, 0, 0.8f, 1.2f, 1f, 1f);
+ mHeadsUpAppearInterpolator = new PathInterpolator(path);
}
public boolean isRunning() {
@@ -122,7 +131,8 @@ public class StackStateAnimator {
final ExpandableView child = (ExpandableView) mHostLayout.getChildAt(i);
StackViewState viewState = finalState.getViewStateForView(child);
- if (viewState == null || child.getVisibility() == View.GONE) {
+ if (viewState == null || child.getVisibility() == View.GONE
+ || applyWithoutAnimation(child, viewState, finalState)) {
continue;
}
@@ -133,11 +143,35 @@ public class StackStateAnimator {
// no child has preformed any animation, lets finish
onAnimationFinished();
}
+ mHeadsUpAppearChildren.clear();
+ mHeadsUpDisappearChildren.clear();
mNewEvents.clear();
mNewAddChildren.clear();
mChildExpandingView = null;
}
+ /**
+ * Determines if a view should not perform an animation and applies it directly.
+ *
+ * @return true if no animation should be performed
+ */
+ private boolean applyWithoutAnimation(ExpandableView child, StackViewState viewState,
+ StackScrollState finalState) {
+ if (mShadeExpanded) {
+ return false;
+ }
+ if (getChildTag(child, TAG_ANIMATOR_TRANSLATION_Y) != null) {
+ // A Y translation animation is running
+ return false;
+ }
+ if (mHeadsUpDisappearChildren.contains(child) || mHeadsUpAppearChildren.contains(child)) {
+ // This is a heads up animation
+ return false;
+ }
+ finalState.applyState(child, viewState);
+ return true;
+ }
+
private int findLastNotAddedIndex(StackScrollState finalState) {
int childCount = mHostLayout.getChildCount();
for (int i = childCount - 1; i >= 0; i--) {
@@ -619,7 +653,9 @@ public class StackStateAnimator {
ObjectAnimator animator = ObjectAnimator.ofFloat(child, View.TRANSLATION_Y,
child.getTranslationY(), newEndValue);
- animator.setInterpolator(mFastOutSlowInInterpolator);
+ Interpolator interpolator = mHeadsUpAppearChildren.contains(child) ?
+ mHeadsUpAppearInterpolator :mFastOutSlowInInterpolator;
+ animator.setInterpolator(interpolator);
long newDuration = cancelAnimatorAndGetNewDuration(duration, previousAnimator);
animator.setDuration(newDuration);
if (delay > 0 && (previousAnimator == null || !previousAnimator.isRunning())) {
@@ -836,8 +872,17 @@ public class StackStateAnimator {
// This item is added, initialize it's properties.
StackViewState viewState = finalState.getViewStateForView(changingView);
mTmpState.copyFrom(viewState);
- mTmpState.yTranslation = -mTmpState.height;
+ if (event.headsUpFromBottom) {
+ mTmpState.yTranslation = mHeadsUpAppearHeightBottom;
+ } else {
+ mTmpState.yTranslation = -mTmpState.height;
+ }
+ mHeadsUpAppearChildren.add(changingView);
finalState.applyState(changingView, mTmpState);
+ } else if (event.animationType == NotificationStackScrollLayout
+ .AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR) {
+ // This item is added, initialize it's properties.
+ mHeadsUpDisappearChildren.add(changingView);
}
mNewEvents.add(event);
}
@@ -903,4 +948,12 @@ public class StackStateAnimator {
return getChildTag(view, TAG_END_HEIGHT);
}
}
+
+ public void setHeadsUpAppearHeightBottom(int headsUpAppearHeightBottom) {
+ mHeadsUpAppearHeightBottom = headsUpAppearHeightBottom;
+ }
+
+ public void setShadeExpanded(boolean shadeExpanded) {
+ mShadeExpanded = shadeExpanded;
+ }
}