Animate public/private notification layouts
This change move the boolean whether we hide sensitive contents into
AmbientState, which makes it consistent with the other stack states
and allows for a orchestrated transition between public/private
layouts. We need this transition when going into the full shade.
Bug: 16291973
Change-Id: I379a6119b5b73eca900a4a2ba9d5ec95b293e487
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 4b0af11..0960c00 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -37,6 +37,9 @@
private boolean mUserLocked;
/** Are we showing the "public" version */
private boolean mShowingPublic;
+ private boolean mSensitive;
+ private boolean mShowingPublicInitialized;
+ private boolean mShowingPublicForIntrinsicHeight;
/**
* Is this notification expanded by the system. The expansion state can be overridden by the
@@ -78,6 +81,8 @@
mHasUserChangedExpansion = false;
mUserLocked = false;
mShowingPublic = false;
+ mSensitive = false;
+ mShowingPublicInitialized = false;
mIsSystemExpanded = false;
mExpansionDisabled = false;
mPublicLayout.reset();
@@ -222,7 +227,7 @@
return mRowMinHeight;
}
- return mShowingPublic ? mRowMinHeight : getMaxExpandHeight();
+ return mShowingPublicForIntrinsicHeight ? mRowMinHeight : getMaxExpandHeight();
}
/**
@@ -248,17 +253,64 @@
}
}
- public void setShowingPublic(boolean show) {
- mShowingPublic = show;
+ public void setSensitive(boolean sensitive) {
+ mSensitive = sensitive;
+ }
+
+ public void setHideSensitiveForIntrinsicHeight(boolean hideSensitive) {
+ mShowingPublicForIntrinsicHeight = mSensitive && hideSensitive;
+ }
+
+ public void setHideSensitive(boolean hideSensitive, boolean animated, long delay,
+ long duration) {
+ boolean oldShowingPublic = mShowingPublic;
+ mShowingPublic = mSensitive && hideSensitive;
+ if (mShowingPublicInitialized && mShowingPublic == oldShowingPublic) {
+ return;
+ }
// bail out if no public version
if (mPublicLayout.getChildCount() == 0) return;
- // TODO: animation?
- mPublicLayout.setVisibility(show ? View.VISIBLE : View.GONE);
- mPrivateLayout.setVisibility(show ? View.GONE : View.VISIBLE);
+ if (!animated) {
+ mPublicLayout.animate().cancel();
+ mPrivateLayout.animate().cancel();
+ mPublicLayout.setAlpha(1f);
+ mPrivateLayout.setAlpha(1f);
+ mPublicLayout.setVisibility(mShowingPublic ? View.VISIBLE : View.INVISIBLE);
+ mPrivateLayout.setVisibility(mShowingPublic ? View.INVISIBLE : View.VISIBLE);
+ } else {
+ animateShowingPublic(delay, duration);
+ }
updateVetoButton();
+ mShowingPublicInitialized = true;
+ }
+
+ private void animateShowingPublic(long delay, long duration) {
+ final View source = mShowingPublic ? mPrivateLayout : mPublicLayout;
+ View target = mShowingPublic ? mPublicLayout : mPrivateLayout;
+ source.setVisibility(View.VISIBLE);
+ target.setVisibility(View.VISIBLE);
+ target.setAlpha(0f);
+ source.animate().cancel();
+ target.animate().cancel();
+ source.animate()
+ .alpha(0f)
+ .withLayer()
+ .setStartDelay(delay)
+ .setDuration(duration)
+ .withEndAction(new Runnable() {
+ @Override
+ public void run() {
+ source.setVisibility(View.INVISIBLE);
+ }
+ });
+ target.animate()
+ .alpha(1f)
+ .withLayer()
+ .setStartDelay(delay)
+ .setDuration(duration);
}
private void updateVetoButton() {
@@ -267,7 +319,7 @@
}
public int getMaxExpandHeight() {
- return mShowingPublic ? mRowMinHeight : mMaxExpandHeight;
+ return mShowingPublicForIntrinsicHeight ? mRowMinHeight : mMaxExpandHeight;
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
index 5cadd1e..46d4a9a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
@@ -176,6 +176,23 @@
}
/**
+ * See {@link #setHideSensitive}. This is a variant which notifies this view in advance about
+ * the upcoming state of hiding sensitive notifications. It gets called at the very beginning
+ * of a stack scroller update such that the updated intrinsic height (which is dependent on
+ * whether private or public layout is showing) gets taken into account into all layout
+ * calculations.
+ */
+ public void setHideSensitiveForIntrinsicHeight(boolean hideSensitive) {
+ }
+
+ /**
+ * Sets whether the notification should hide its private contents if it is sensitive.
+ */
+ public void setHideSensitive(boolean hideSensitive, boolean animated, long delay,
+ long duration) {
+ }
+
+ /**
* @return The desired notification height.
*/
public int getIntrinsicHeight() {
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 61b0eaa..7d4f90e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -1362,10 +1362,15 @@
int vis = ent.notification.getNotification().visibility;
// Display public version of the notification if we need to redact.
- final boolean hideSensitive = shouldHideSensitiveContents(ent.notification.getUserId());
- boolean showingPublic = vis == Notification.VISIBILITY_PRIVATE && hideSensitive;
- ent.row.setShowingPublic(showingPublic);
+ final boolean hideSensitive =
+ !userAllowsPrivateNotificationsInPublic(ent.notification.getUserId());
+ boolean sensitive = vis == Notification.VISIBILITY_PRIVATE;
+ boolean showingPublic = sensitive && hideSensitive && isLockscreenPublicMode();
+ ent.row.setSensitive(sensitive && hideSensitive);
if (ent.autoRedacted && ent.legacy) {
+
+ // TODO: Also fade this? Or, maybe easier (and better), provide a dark redacted form
+ // for legacy auto redacted notifications.
if (showingPublic) {
ent.row.setShowingLegacyBackground(false);
} else {
@@ -3415,8 +3420,8 @@
}
mNotificationPanel.setBarState(mState, mKeyguardFadingAway, goingToFullShade);
updateDozingState();
- updateStackScrollerState();
updatePublicMode();
+ updateStackScrollerState(goingToFullShade);
updateNotifications();
checkBarModes();
updateCarrierLabelVisibility(false);
@@ -3443,9 +3448,10 @@
mScrimController.setDozing(mDozing);
}
- public void updateStackScrollerState() {
+ public void updateStackScrollerState(boolean goingToFullShade) {
if (mStackScroller == null) return;
boolean onKeyguard = mState == StatusBarState.KEYGUARD;
+ mStackScroller.setHideSensitive(isLockscreenPublicMode(), goingToFullShade);
mStackScroller.setDimmed(onKeyguard, false /* animate */);
mStackScroller.setExpandingEnabled(!onKeyguard);
ActivatableNotificationView activatedChild = mStackScroller.getActivatedChild();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
index c2fa68f..2aceb95 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpNotificationView.java
@@ -91,7 +91,9 @@
if (mHeadsUp != null) {
mHeadsUp.row.setSystemExpanded(true);
- mHeadsUp.row.setShowingPublic(false);
+ mHeadsUp.row.setSensitive(false);
+ mHeadsUp.row.setHideSensitive(
+ false, false /* animated */, 0 /* delay */, 0 /* duration */);
if (mContentHolder == null) {
// too soon!
return false;
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 0582140..ddb5cb8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
@@ -34,6 +34,7 @@
private int mSpeedBumpIndex = -1;
private float mScrimAmount;
private boolean mDark;
+ private boolean mHideSensitive;
public int getScrollY() {
return mScrollY;
@@ -68,6 +69,10 @@
mDark = dark;
}
+ public void setHideSensitive(boolean hideSensitive) {
+ mHideSensitive = hideSensitive;
+ }
+
/**
* In dimmed mode, a child can be activated, which happens on the first tap of the double-tap
* interaction. This child is then scaled normally and its background is fully opaque.
@@ -84,6 +89,10 @@
return mDark;
}
+ public boolean isHideSensitive() {
+ return mHideSensitive;
+ }
+
public ActivatableNotificationView getActivatedChild() {
return mActivatedChild;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java
index 2709384..3c93b19 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AnimationFilter.java
@@ -30,6 +30,7 @@
boolean animateTopInset;
boolean animateDimmed;
boolean animateDark;
+ boolean animateHideSensitive;
boolean hasDelays;
boolean hasGoToFullShadeEvent;
@@ -78,6 +79,11 @@
return this;
}
+ public AnimationFilter animateHideSensitive() {
+ animateHideSensitive = true;
+ return this;
+ }
+
/**
* Combines multiple filters into {@code this} filter, using or as the operand .
*
@@ -104,6 +110,7 @@
animateTopInset |= filter.animateTopInset;
animateDimmed |= filter.animateDimmed;
animateDark |= filter.animateDark;
+ animateHideSensitive |= filter.animateHideSensitive;
hasDelays |= filter.hasDelays;
}
@@ -116,6 +123,7 @@
animateTopInset = false;
animateDimmed = false;
animateDark = false;
+ animateHideSensitive = false;
hasDelays = false;
hasGoToFullShadeEvent = false;
}
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 c9bfc4e..a4d2021 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -131,6 +131,7 @@
private boolean mNeedsAnimation;
private boolean mTopPaddingNeedsAnimation;
private boolean mDimmedNeedsAnimation;
+ private boolean mHideSensitiveNeedsAnimation;
private boolean mDarkNeedsAnimation;
private boolean mActivateNeedsAnimation;
private boolean mGoToFullShadeNeedsAnimation;
@@ -1579,6 +1580,7 @@
generateTopPaddingEvent();
generateActivateEvent();
generateDimmedEvent();
+ generateHideSensitiveEvent();
generateDarkEvent();
generateGoToFullShadeEvent();
mNeedsAnimation = false;
@@ -1656,6 +1658,14 @@
mDimmedNeedsAnimation = false;
}
+ private void generateHideSensitiveEvent() {
+ if (mHideSensitiveNeedsAnimation) {
+ mAnimationEvents.add(
+ new AnimationEvent(null, AnimationEvent.ANIMATION_TYPE_HIDE_SENSITIVE));
+ }
+ mHideSensitiveNeedsAnimation = false;
+ }
+
private void generateDarkEvent() {
if (mDarkNeedsAnimation) {
mAnimationEvents.add(
@@ -1899,6 +1909,22 @@
requestChildrenUpdate();
}
+ public void setHideSensitive(boolean hideSensitive, boolean animate) {
+ if (hideSensitive != mAmbientState.isHideSensitive()) {
+ int childCount = getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ ExpandableView v = (ExpandableView) getChildAt(i);
+ v.setHideSensitiveForIntrinsicHeight(hideSensitive);
+ }
+ mAmbientState.setHideSensitive(hideSensitive);
+ if (animate && mAnimationsEnabled) {
+ mHideSensitiveNeedsAnimation = true;
+ mNeedsAnimation = true;
+ }
+ requestChildrenUpdate();
+ }
+ }
+
/**
* See {@link AmbientState#setActivatedChild}.
*/
@@ -2155,7 +2181,12 @@
.animateY()
.animateDimmed()
.animateScale()
- .animateZ(),
+ .animateZ()
+ .hasDelays(),
+
+ // ANIMATION_TYPE_HIDE_SENSITIVE
+ new AnimationFilter()
+ .animateHideSensitive(),
};
static int[] LENGTHS = new int[] {
@@ -2192,6 +2223,9 @@
// ANIMATION_TYPE_GO_TO_FULL_SHADE
StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE,
+
+ // ANIMATION_TYPE_HIDE_SENSITIVE
+ StackStateAnimator.ANIMATION_DURATION_STANDARD,
};
static final int ANIMATION_TYPE_ADD = 0;
@@ -2205,6 +2239,7 @@
static final int ANIMATION_TYPE_CHANGE_POSITION = 8;
static final int ANIMATION_TYPE_DARK = 9;
static final int ANIMATION_TYPE_GO_TO_FULL_SHADE = 10;
+ static final int ANIMATION_TYPE_HIDE_SENSITIVE = 11;
final long eventStartTime;
final View changingView;
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 fe2733b..ba3f339 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -159,7 +159,7 @@
updateZValuesForState(resultState, algorithmState);
handleDraggedViews(ambientState, resultState, algorithmState);
- updateDimmedActivated(ambientState, resultState, algorithmState);
+ updateDimmedActivatedHideSensitive(ambientState, resultState, algorithmState);
updateClipping(resultState, algorithmState);
updateScrimAmount(resultState, algorithmState, ambientState.getScrimAmount());
updateSpeedBumpState(resultState, algorithmState, ambientState.getSpeedBumpIndex());
@@ -251,12 +251,13 @@
}
/**
- * Updates the dimmed and activated states of the children.
+ * Updates the dimmed, activated and hiding sensitive states of the children.
*/
- private void updateDimmedActivated(AmbientState ambientState, StackScrollState resultState,
- StackScrollAlgorithmState algorithmState) {
+ private void updateDimmedActivatedHideSensitive(AmbientState ambientState,
+ StackScrollState resultState, StackScrollAlgorithmState algorithmState) {
boolean dimmed = ambientState.isDimmed();
boolean dark = ambientState.isDark();
+ boolean hideSensitive = ambientState.isHideSensitive();
View activatedChild = ambientState.getActivatedChild();
int childCount = algorithmState.visibleChildren.size();
for (int i = 0; i < childCount; i++) {
@@ -264,6 +265,7 @@
StackScrollState.ViewState childViewState = resultState.getViewStateForView(child);
childViewState.dimmed = dimmed;
childViewState.dark = dark;
+ childViewState.hideSensitive = hideSensitive;
boolean isActivatedChild = activatedChild == child;
childViewState.scale = !dimmed || isActivatedChild
? 1.0f
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 d0064c8..a174952 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollState.java
@@ -157,6 +157,10 @@
// apply dark
child.setDark(state.dark, false /* animate */);
+ // apply hiding sensitive
+ child.setHideSensitive(
+ state.hideSensitive, false /* animated */, 0 /* delay */, 0 /* duration */);
+
// apply speed bump state
child.setBelowSpeedBump(state.belowSpeedBump);
@@ -238,6 +242,7 @@
float scale;
boolean dimmed;
boolean dark;
+ boolean hideSensitive;
boolean belowSpeedBump;
/**
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 e21d52d..afd7216 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackStateAnimator.java
@@ -220,6 +220,10 @@
// apply speed bump state
child.setBelowSpeedBump(viewState.belowSpeedBump);
+ // start hiding sensitive animation
+ child.setHideSensitive(viewState.hideSensitive,
+ mAnimationFilter.animateHideSensitive && !wasAdded, delay, duration);
+
// apply scrimming
child.setScrimAmount(viewState.scrimAmount);