Merge changes I089fa8ff,I8db745c1,I6fa83189 into qt-r1-dev
* changes:
Showing heads up for music when bypassing
Not rendering background when bypassing
Made sure the lock icon is invisible while hunned
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index e95e6e0..6f0669b 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -8276,6 +8276,16 @@
BOOLEAN_VALIDATOR;
/**
+ * Whether or not media is shown automatically when bypassing as a heads up.
+ * @hide
+ */
+ public static final String SHOW_MEDIA_WHEN_BYPASSING =
+ "show_media_when_bypassing";
+
+ private static final Validator SHOW_MEDIA_WHEN_BYPASSING_VALIDATOR =
+ BOOLEAN_VALIDATOR;
+
+ /**
* Whether or not face unlock requires attention. This is a cached value, the source of
* truth is obtained through the HAL.
* @hide
@@ -8979,6 +8989,7 @@
NFC_PAYMENT_DEFAULT_COMPONENT,
AUTOMATIC_STORAGE_MANAGER_DAYS_TO_RETAIN,
FACE_UNLOCK_KEYGUARD_ENABLED,
+ SHOW_MEDIA_WHEN_BYPASSING,
FACE_UNLOCK_DISMISSES_KEYGUARD,
FACE_UNLOCK_APP_ENABLED,
FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION,
@@ -9155,6 +9166,7 @@
VALIDATORS.put(FACE_UNLOCK_KEYGUARD_ENABLED, FACE_UNLOCK_KEYGUARD_ENABLED_VALIDATOR);
VALIDATORS.put(FACE_UNLOCK_DISMISSES_KEYGUARD,
FACE_UNLOCK_DISMISSES_KEYGUARD_VALIDATOR);
+ VALIDATORS.put(SHOW_MEDIA_WHEN_BYPASSING, SHOW_MEDIA_WHEN_BYPASSING_VALIDATOR);
VALIDATORS.put(FACE_UNLOCK_APP_ENABLED, FACE_UNLOCK_APP_ENABLED_VALIDATOR);
VALIDATORS.put(FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION,
FACE_UNLOCK_ALWAYS_REQUIRE_CONFIRMATION_VALIDATOR);
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 122bcea..4df824e 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -138,6 +138,9 @@
<!-- The number of milliseconds before the heads up notification auto-dismisses. -->
<integer name="heads_up_notification_decay">5000</integer>
+ <!-- The number of milliseconds before the heads up notification sent automatically by the system auto-dismisses. -->
+ <integer name="auto_heads_up_notification_decay">3000</integer>
+
<!-- The number of milliseconds after a heads up notification is pushed back
before the app can interrupt again. -->
<integer name="heads_up_default_snooze_length_ms">60000</integer>
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
index 0635231..5136682 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
@@ -52,6 +52,7 @@
import com.android.systemui.R;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.NotificationMediaManager;
+import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.policy.NextAlarmController;
import com.android.systemui.statusbar.policy.NextAlarmControllerImpl;
@@ -103,8 +104,8 @@
private final Date mCurrentTime = new Date();
private final Handler mHandler;
private final AlarmManager.OnAlarmListener mUpdateNextAlarm = this::updateNextAlarm;
- private final HashSet<Integer> mMediaInvisibleStates;
private final Object mMediaToken = new Object();
+ private DozeParameters mDozeParameters;
@VisibleForTesting
protected SettableWakeLock mMediaWakeLock;
@VisibleForTesting
@@ -184,11 +185,6 @@
mAlarmUri = Uri.parse(KEYGUARD_NEXT_ALARM_URI);
mDndUri = Uri.parse(KEYGUARD_DND_URI);
mMediaUri = Uri.parse(KEYGUARD_MEDIA_URI);
-
- mMediaInvisibleStates = new HashSet<>();
- mMediaInvisibleStates.add(PlaybackState.STATE_NONE);
- mMediaInvisibleStates.add(PlaybackState.STATE_STOPPED);
- mMediaInvisibleStates.add(PlaybackState.STATE_PAUSED);
}
/**
@@ -201,12 +197,14 @@
public void initDependencies(
NotificationMediaManager mediaManager,
StatusBarStateController statusBarStateController,
- KeyguardBypassController keyguardBypassController) {
+ KeyguardBypassController keyguardBypassController,
+ DozeParameters dozeParameters) {
mMediaManager = mediaManager;
mMediaManager.addCallback(this);
mStatusBarStateController = statusBarStateController;
mStatusBarStateController.addCallback(this);
mKeyguardBypassController = keyguardBypassController;
+ mDozeParameters = dozeParameters;
}
@AnyThread
@@ -231,9 +229,9 @@
}
protected boolean needsMediaLocked() {
- boolean isBypass = mKeyguardBypassController != null
- && mKeyguardBypassController.getBypassEnabled();
- return !TextUtils.isEmpty(mMediaTitle) && mMediaIsVisible && (mDozing || isBypass);
+ boolean keepWhenAwake = mKeyguardBypassController != null
+ && mKeyguardBypassController.getBypassEnabled() && mDozeParameters.getAlwaysOn();
+ return !TextUtils.isEmpty(mMediaTitle) && mMediaIsVisible && (mDozing || keepWhenAwake);
}
protected void addMediaLocked(ListBuilder listBuilder) {
@@ -458,7 +456,7 @@
@Override
public void onMetadataOrStateChanged(MediaMetadata metadata, @PlaybackState.State int state) {
synchronized (this) {
- boolean nextVisible = !mMediaInvisibleStates.contains(state);
+ boolean nextVisible = NotificationMediaManager.isPlayingState(state);
mHandler.removeCallbacksAndMessages(mMediaToken);
if (mMediaIsVisible && !nextVisible) {
// We need to delay this event for a few millis when stopping to avoid jank in the
@@ -477,7 +475,7 @@
}
private void updateMediaStateLocked(MediaMetadata metadata, @PlaybackState.State int state) {
- boolean nextVisible = !mMediaInvisibleStates.contains(state);
+ boolean nextVisible = NotificationMediaManager.isPlayingState(state);
CharSequence title = null;
if (metadata != null) {
title = metadata.getText(MediaMetadata.METADATA_KEY_TITLE);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index a59d590..f001561 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -69,6 +69,7 @@
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
import java.util.Set;
@@ -91,6 +92,14 @@
private final SysuiColorExtractor mColorExtractor = Dependency.get(SysuiColorExtractor.class);
private final KeyguardMonitor mKeyguardMonitor = Dependency.get(KeyguardMonitor.class);
private final KeyguardBypassController mKeyguardBypassController;
+ private static final HashSet<Integer> PAUSED_MEDIA_STATES = new HashSet<>();
+ static {
+ PAUSED_MEDIA_STATES.add(PlaybackState.STATE_NONE);
+ PAUSED_MEDIA_STATES.add(PlaybackState.STATE_STOPPED);
+ PAUSED_MEDIA_STATES.add(PlaybackState.STATE_PAUSED);
+ PAUSED_MEDIA_STATES.add(PlaybackState.STATE_ERROR);
+ }
+
// Late binding
private NotificationEntryManager mEntryManager;
@@ -207,6 +216,10 @@
mPropertiesChangedListener);
}
+ public static boolean isPlayingState(int state) {
+ return !PAUSED_MEDIA_STATES.contains(state);
+ }
+
public void setUpWithPresenter(NotificationPresenter presenter) {
mPresenter = presenter;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 0a8b7f8..4ccd0cd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -18,6 +18,7 @@
import static com.android.systemui.Interpolators.FAST_OUT_SLOW_IN_REVERSE;
import static com.android.systemui.statusbar.phone.NotificationIconContainer.IconState.NO_VALUE;
+import static com.android.systemui.util.InjectionInflationController.VIEW_CONTEXT;
import android.content.Context;
import android.content.res.Configuration;
@@ -48,8 +49,12 @@
import com.android.systemui.statusbar.notification.stack.ExpandableViewState;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.notification.stack.ViewState;
+import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.NotificationIconContainer;
+import javax.inject.Inject;
+import javax.inject.Named;
+
/**
* A notification shelf view that is placed inside the notification scroller. It manages the
* overflow icons that don't fit into the regular list anymore.
@@ -63,6 +68,7 @@
= SystemProperties.getBoolean("debug.icon_scroll_animations", true);
private static final int TAG_CONTINUOUS_CLIPPING = R.id.continuous_clipping_tag;
private static final String TAG = "NotificationShelf";
+ private final KeyguardBypassController mBypassController;
private NotificationIconContainer mShelfIcons;
private int[] mTmp = new int[2];
@@ -93,8 +99,12 @@
private int mCutoutHeight;
private int mGapHeight;
- public NotificationShelf(Context context, AttributeSet attrs) {
+ @Inject
+ public NotificationShelf(@Named(VIEW_CONTEXT) Context context,
+ AttributeSet attrs,
+ KeyguardBypassController keyguardBypassController) {
super(context, attrs);
+ mBypassController = keyguardBypassController;
}
@Override
@@ -309,7 +319,10 @@
colorTwoBefore = previousColor;
transitionAmount = inShelfAmount;
}
- if (isLastChild) {
+ // We don't want to modify the color if the notification is hun'd
+ boolean canModifyColor = mAmbientState.isShadeExpanded()
+ && !(mAmbientState.isOnKeyguard() && mBypassController.getBypassEnabled());
+ if (isLastChild && canModifyColor) {
if (colorOfViewBeforeLast == NO_COLOR) {
colorOfViewBeforeLast = ownColorUntinted;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/BypassHeadsUpNotifier.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/BypassHeadsUpNotifier.kt
new file mode 100644
index 0000000..ea474ce
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/BypassHeadsUpNotifier.kt
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.notification
+
+import android.content.Context
+import android.media.MediaMetadata
+import android.provider.Settings
+import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.statusbar.NotificationMediaManager
+import com.android.systemui.statusbar.StatusBarState
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.phone.HeadsUpManagerPhone
+import com.android.systemui.statusbar.phone.KeyguardBypassController
+import com.android.systemui.tuner.TunerService
+import javax.inject.Inject
+import javax.inject.Singleton
+
+/**
+ * A class that automatically creates heads up for important notification when bypassing the
+ * lockscreen
+ */
+@Singleton
+class BypassHeadsUpNotifier @Inject constructor(
+ private val context: Context,
+ private val bypassController: KeyguardBypassController,
+ private val statusBarStateController: StatusBarStateController,
+ private val headsUpManager: HeadsUpManagerPhone,
+ private val mediaManager: NotificationMediaManager,
+ tunerService: TunerService) : StatusBarStateController.StateListener,
+ NotificationMediaManager.MediaListener {
+
+ private lateinit var entryManager: NotificationEntryManager
+ private var currentMediaEntry: NotificationEntry? = null
+ private var enabled = true
+
+ var fullyAwake = false
+ set(value) {
+ field = value
+ if (value) {
+ updateAutoHeadsUp(currentMediaEntry)
+ }
+ }
+
+ init {
+ statusBarStateController.addCallback(this)
+ tunerService.addTunable(
+ TunerService.Tunable { _, _ ->
+ enabled = Settings.Secure.getIntForUser(
+ context.contentResolver,
+ Settings.Secure.SHOW_MEDIA_WHEN_BYPASSING,
+ 1 /* default */,
+ KeyguardUpdateMonitor.getCurrentUser()) != 0
+ }, Settings.Secure.SHOW_MEDIA_WHEN_BYPASSING)
+ }
+
+ fun setUp(entryManager: NotificationEntryManager) {
+ this.entryManager = entryManager
+ mediaManager.addCallback(this)
+ }
+
+ override fun onMetadataOrStateChanged(metadata: MediaMetadata?, state: Int) {
+ val previous = currentMediaEntry
+ var newEntry = entryManager.notificationData.get(mediaManager.mediaNotificationKey)
+ if (!NotificationMediaManager.isPlayingState(state)) {
+ newEntry = null
+ }
+ if (newEntry?.isSensitive == true) {
+ newEntry = null
+ }
+ currentMediaEntry = newEntry
+ updateAutoHeadsUp(previous)
+ updateAutoHeadsUp(currentMediaEntry)
+ }
+
+ private fun updateAutoHeadsUp(entry: NotificationEntry?) {
+ entry?.let {
+ val autoHeadsUp = it == currentMediaEntry && canAutoHeadsUp()
+ it.isAutoHeadsUp = autoHeadsUp
+ if (autoHeadsUp) {
+ headsUpManager.showNotification(it)
+ }
+ }
+ }
+
+ override fun onStatePostChange() {
+ updateAutoHeadsUp(currentMediaEntry)
+ }
+
+ private fun canAutoHeadsUp() : Boolean {
+ if (!enabled) {
+ return false
+ }
+ if (!bypassController.bypassEnabled) {
+ return false
+ }
+ if (statusBarStateController.state != StatusBarState.KEYGUARD) {
+ return false
+ }
+ if (!fullyAwake) {
+ return false
+ }
+ return true
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java
index 8a23f71..d71d407 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationAlertingManager.java
@@ -24,7 +24,6 @@
import android.util.Log;
import com.android.internal.statusbar.NotificationVisibility;
-import com.android.systemui.statusbar.AlertingNotificationManager;
import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -119,12 +118,11 @@
shouldAlert = mNotificationInterruptionStateProvider.shouldHeadsUp(entry);
final boolean wasAlerting = mHeadsUpManager.isAlerting(entry.key);
if (wasAlerting) {
- if (!shouldAlert) {
- // We don't want this to be interrupting anymore, let's remove it
- mHeadsUpManager.removeNotification(entry.key,
- false /* ignoreEarliestRemovalTime */);
- } else {
+ if (shouldAlert) {
mHeadsUpManager.updateNotification(entry.key, alertAgain);
+ } else if (!mHeadsUpManager.isEntryAutoHeadsUpped(entry.key)) {
+ // We don't want this to be interrupting anymore, let's remove it
+ mHeadsUpManager.removeNotification(entry.key, false /* removeImmediately */);
}
} else if (shouldAlert && alertAgain) {
// This notification was updated to be alerting, show it!
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java
index 1aa6bc9..dfc6450 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationEntryListener.java
@@ -24,6 +24,8 @@
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.NotificationContentInflater.InflationFlag;
+import androidx.annotation.NonNull;
+
/**
* Listener interface for changes sent by NotificationEntryManager.
*/
@@ -45,7 +47,7 @@
/**
* Called when a new entry is created.
*/
- default void onNotificationAdded(NotificationEntry entry) {
+ default void onNotificationAdded(@NonNull NotificationEntry entry) {
}
/**
@@ -61,7 +63,7 @@
/**
* Called when a notification was updated, after any filtering of notifications have occurred.
*/
- default void onPostEntryUpdated(NotificationEntry entry) {
+ default void onPostEntryUpdated(@NonNull NotificationEntry entry) {
}
/**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
index 9db715d..b19d2ca 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
@@ -175,6 +175,7 @@
private boolean mHighPriority;
private boolean mSensitive = true;
private Runnable mOnSensitiveChangedListener;
+ private boolean mAutoHeadsUp;
public NotificationEntry(StatusBarNotification n) {
this(n, null);
@@ -670,11 +671,25 @@
if (row != null) row.setHeadsUp(shouldHeadsUp);
}
-
public void setHeadsUpAnimatingAway(boolean animatingAway) {
if (row != null) row.setHeadsUpAnimatingAway(animatingAway);
}
+ /**
+ * Set that this notification was automatically heads upped. This happens for example when
+ * the user bypasses the lockscreen and media is playing.
+ */
+ public void setAutoHeadsUp(boolean autoHeadsUp) {
+ mAutoHeadsUp = autoHeadsUp;
+ }
+
+ /**
+ * @return if this notification was automatically heads upped. This happens for example when
+ * * the user bypasses the lockscreen and media is playing.
+ */
+ public boolean isAutoHeadsUp() {
+ return mAutoHeadsUp;
+ }
public boolean mustStayOnScreen() {
return row != null && row.mustStayOnScreen();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index ae534d2..a8327f6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -2698,6 +2698,8 @@
l.setAlpha(1.0f);
l.setLayerType(LAYER_TYPE_NONE, null);
}
+ } else {
+ setHeadsUpAnimatingAway(false);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index e2cb8d4..58e6399 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -837,7 +837,13 @@
break;
}
}
- if (!mAmbientState.isDozing() || anySectionHasVisibleChild) {
+ boolean shouldDrawBackground;
+ if (mKeyguardBypassController.getBypassEnabled() && onKeyguard()) {
+ shouldDrawBackground = isPulseExpanding();
+ } else {
+ shouldDrawBackground = !mAmbientState.isDozing() || anySectionHasVisibleChild;
+ }
+ if (shouldDrawBackground) {
drawBackgroundRects(canvas, left, right, top, backgroundTopAnimationOffset);
}
@@ -3396,10 +3402,20 @@
for (Pair<ExpandableNotificationRow, Boolean> eventPair : mHeadsUpChangeAnimations) {
ExpandableNotificationRow row = eventPair.first;
boolean isHeadsUp = eventPair.second;
+ if (isHeadsUp != row.isHeadsUp()) {
+ // For cases where we have a heads up showing and appearing again we shouldn't
+ // do the animations at all.
+ continue;
+ }
int type = AnimationEvent.ANIMATION_TYPE_HEADS_UP_OTHER;
boolean onBottom = false;
boolean pinnedAndClosed = row.isPinned() && !mIsExpanded;
- if (!mIsExpanded && !isHeadsUp) {
+ boolean performDisappearAnimation = !mIsExpanded
+ // Only animate if we still have pinned heads up, otherwise we just have the
+ // regular collapse animation of the lock screen
+ || (mKeyguardBypassController.getBypassEnabled() && onKeyguard()
+ && mHeadsUpManager.hasPinnedHeadsUp());
+ if (performDisappearAnimation && !isHeadsUp) {
type = row.wasJustClicked()
? AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR_CLICK
: AnimationEvent.ANIMATION_TYPE_HEADS_UP_DISAPPEAR;
@@ -6246,6 +6262,15 @@
mAmbientState.onDragFinished(animView);
updateContinuousShadowDrawing();
updateContinuousBackgroundDrawing();
+ if (animView instanceof ExpandableNotificationRow) {
+ ExpandableNotificationRow row = (ExpandableNotificationRow) animView;
+ if (row.isPinned() && !canChildBeDismissed(row)
+ && row.getStatusBarNotification().getNotification().fullScreenIntent
+ == null) {
+ mHeadsUpManager.removeNotification(row.getStatusBarNotification().getKey(),
+ true /* removeImmediately */);
+ }
+ }
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
index 09c6968..35ba801 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
@@ -546,12 +546,12 @@
ExpandableViewState topState =
topHeadsUpEntry == null ? null : topHeadsUpEntry.getViewState();
if (topState != null && !isTopEntry && (!mIsExpanded
- || unmodifiedEndLocation < topState.yTranslation + topState.height)) {
+ || unmodifiedEndLocation > topState.yTranslation + topState.height)) {
// Ensure that a headsUp doesn't vertically extend further than the heads-up at
// the top most z-position
childState.height = row.getIntrinsicHeight();
- childState.yTranslation = topState.yTranslation + topState.height
- - childState.height;
+ childState.yTranslation = Math.min(topState.yTranslation + topState.height
+ - childState.height, childState.yTranslation);
}
// heads up notification show and this row is the top entry of heads up
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
index 4f169eb..0996ff2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
@@ -28,6 +28,7 @@
import com.android.systemui.R;
import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.StatusBarIconView;
+import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.ExpandableView;
@@ -451,7 +452,11 @@
if (row.isDismissed()) {
needsAnimation = false;
}
- StatusBarIconView icon = row.getEntry().icon;
+ NotificationEntry entry = row.getEntry();
+ StatusBarIconView icon = entry.icon;
+ if (entry.centeredIcon != null && entry.centeredIcon.getParent() != null) {
+ icon = entry.centeredIcon;
+ }
if (icon.getParent() != null) {
icon.getLocationOnScreen(mTmpLocation);
float iconPosition = mTmpLocation[0] - icon.getTranslationX()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
index ade855e..c44f953 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
@@ -32,7 +32,6 @@
import androidx.collection.ArraySet;
import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.Dependency;
import com.android.systemui.Dumpable;
import com.android.systemui.R;
import com.android.systemui.ScreenDecorations;
@@ -67,6 +66,7 @@
final int mExtensionTime;
private final StatusBarStateController mStatusBarStateController;
private final KeyguardBypassController mBypassController;
+ private final int mAutoHeadsUpNotificationDecay;
private View mStatusBarWindowView;
private NotificationGroupManager mGroupManager;
private VisualStabilityManager mVisualStabilityManager;
@@ -81,6 +81,7 @@
private boolean mTrackingHeadsUp;
private HashSet<String> mSwipedOutKeys = new HashSet<>();
private HashSet<NotificationEntry> mEntriesToRemoveAfterExpand = new HashSet<>();
+ private HashSet<String> mKeysToRemoveWhenLeavingKeyguard = new HashSet<>();
private ArraySet<NotificationEntry> mEntriesToRemoveWhenReorderingAllowed
= new ArraySet<>();
private boolean mIsExpanded;
@@ -121,6 +122,8 @@
mAutoDismissNotificationDecayDozing = resources.getInteger(
R.integer.heads_up_notification_decay_dozing);
mExtensionTime = resources.getInteger(R.integer.ambient_notification_extension_time);
+ mAutoHeadsUpNotificationDecay = resources.getInteger(
+ R.integer.auto_heads_up_notification_decay);
mStatusBarStateController = statusBarStateController;
mStatusBarStateController.addCallback(this);
mBypassController = bypassController;
@@ -231,7 +234,16 @@
@Override
public void onStateChanged(int newState) {
+ boolean wasKeyguard = mStatusBarState == StatusBarState.KEYGUARD;
+ boolean isKeyguard = newState == StatusBarState.KEYGUARD;
mStatusBarState = newState;
+ if (wasKeyguard && !isKeyguard && mKeysToRemoveWhenLeavingKeyguard.size() != 0) {
+ String[] keys = mKeysToRemoveWhenLeavingKeyguard.toArray(new String[0]);
+ for (String key : keys) {
+ removeAlertEntry(key);
+ }
+ mKeysToRemoveWhenLeavingKeyguard.clear();
+ }
}
@Override
@@ -245,6 +257,15 @@
}
}
+ @Override
+ public boolean isEntryAutoHeadsUpped(String key) {
+ HeadsUpEntryPhone headsUpEntryPhone = getHeadsUpEntryPhone(key);
+ if (headsUpEntryPhone == null) {
+ return false;
+ }
+ return headsUpEntryPhone.isAutoHeadsUp();
+ }
+
/**
* Set that we are exiting the headsUp pinned mode, but some notifications might still be
* animating out. This is used to keep the touchable regions in a sane state.
@@ -420,6 +441,7 @@
@Override
protected void onAlertEntryRemoved(AlertEntry alertEntry) {
+ mKeysToRemoveWhenLeavingKeyguard.remove(alertEntry.mEntry.key);
super.onAlertEntryRemoved(alertEntry);
mEntryPool.release((HeadsUpEntryPhone) alertEntry);
}
@@ -479,6 +501,11 @@
*/
private boolean extended;
+ /**
+ * Was this entry received while on keyguard
+ */
+ private boolean mIsAutoHeadsUp;
+
@Override
protected boolean isSticky() {
@@ -494,10 +521,12 @@
mEntriesToRemoveWhenReorderingAllowed.add(entry);
mVisualStabilityManager.addReorderingAllowedCallback(
HeadsUpManagerPhone.this);
- } else if (!mTrackingHeadsUp) {
- removeAlertEntry(entry.key);
- } else {
+ } else if (mTrackingHeadsUp) {
mEntriesToRemoveAfterExpand.add(entry);
+ } else if (mIsAutoHeadsUp && mStatusBarState == StatusBarState.KEYGUARD) {
+ mKeysToRemoveWhenLeavingKeyguard.add(entry.key);
+ } else {
+ removeAlertEntry(entry.key);
}
};
@@ -506,6 +535,7 @@
@Override
public void updateEntry(boolean updatePostTime) {
+ mIsAutoHeadsUp = mEntry.isAutoHeadsUp();
super.updateEntry(updatePostTime);
if (mEntriesToRemoveAfterExpand.contains(mEntry)) {
@@ -514,6 +544,7 @@
if (mEntriesToRemoveWhenReorderingAllowed.contains(mEntry)) {
mEntriesToRemoveWhenReorderingAllowed.remove(mEntry);
}
+ mKeysToRemoveWhenLeavingKeyguard.remove(mEntry.key);
}
@Override
@@ -548,6 +579,7 @@
super.reset();
mMenuShownPinned = false;
extended = false;
+ mIsAutoHeadsUp = false;
}
private void extendPulse() {
@@ -558,13 +590,35 @@
}
@Override
+ public int compareTo(AlertEntry alertEntry) {
+ HeadsUpEntryPhone headsUpEntry = (HeadsUpEntryPhone) alertEntry;
+ boolean autoShown = isAutoHeadsUp();
+ boolean otherAutoShown = headsUpEntry.isAutoHeadsUp();
+ if (autoShown && !otherAutoShown) {
+ return 1;
+ } else if (!autoShown && otherAutoShown) {
+ return -1;
+ }
+ return super.compareTo(alertEntry);
+ }
+
+ @Override
protected long calculateFinishTime() {
return mPostTime + getDecayDuration() + (extended ? mExtensionTime : 0);
}
private int getDecayDuration() {
- return mStatusBarStateController.isDozing() ? mAutoDismissNotificationDecayDozing
- : getRecommendedHeadsUpTimeoutMs();
+ if (mStatusBarStateController.isDozing()) {
+ return mAutoDismissNotificationDecayDozing;
+ } else if (isAutoHeadsUp()) {
+ return getRecommendedHeadsUpTimeoutMs(mAutoHeadsUpNotificationDecay);
+ } else {
+ return getRecommendedHeadsUpTimeoutMs(mAutoDismissNotificationDecay);
+ }
+ }
+
+ private boolean isAutoHeadsUp() {
+ return mIsAutoHeadsUp;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
index 1e7c44c..ea434fc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
@@ -53,6 +53,7 @@
import com.android.systemui.statusbar.policy.AccessibilityController;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardMonitor;
+import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
import com.android.systemui.statusbar.policy.UserInfoController.OnUserInfoChangedListener;
import java.lang.annotation.Retention;
@@ -67,7 +68,8 @@
public class LockIcon extends KeyguardAffordanceView implements OnUserInfoChangedListener,
StatusBarStateController.StateListener, ConfigurationController.ConfigurationListener,
UnlockMethodCache.OnUnlockMethodChangedListener,
- NotificationWakeUpCoordinator.WakeUpListener, ViewTreeObserver.OnPreDrawListener {
+ NotificationWakeUpCoordinator.WakeUpListener, ViewTreeObserver.OnPreDrawListener,
+ OnHeadsUpChangedListener {
private static final int STATE_LOCKED = 0;
private static final int STATE_LOCK_OPEN = 1;
@@ -82,6 +84,7 @@
private final KeyguardMonitor mKeyguardMonitor;
private final KeyguardBypassController mBypassController;
private final NotificationWakeUpCoordinator mWakeUpCoordinator;
+ private final HeadsUpManagerPhone mHeadsUpManager;
private int mLastState = 0;
private boolean mForceUpdate;
@@ -94,7 +97,7 @@
private boolean mDocked;
private int mIconColor;
private float mDozeAmount;
- private boolean mBouncerShowing;
+ private boolean mBouncerShowingScrimmed;
private boolean mWakeAndUnlockRunning;
private boolean mKeyguardShowing;
private boolean mShowingLaunchAffordance;
@@ -155,7 +158,8 @@
KeyguardBypassController bypassController,
NotificationWakeUpCoordinator wakeUpCoordinator,
KeyguardMonitor keyguardMonitor,
- @Nullable DockManager dockManager) {
+ @Nullable DockManager dockManager,
+ HeadsUpManagerPhone headsUpManager) {
super(context, attrs);
mContext = context;
mUnlockMethodCache = UnlockMethodCache.getInstance(context);
@@ -167,6 +171,7 @@
mWakeUpCoordinator = wakeUpCoordinator;
mKeyguardMonitor = keyguardMonitor;
mDockManager = dockManager;
+ mHeadsUpManager = headsUpManager;
}
@Override
@@ -296,11 +301,13 @@
boolean onAodNotPulsingOrDocked = mDozing && (!mPulsing || mDocked);
boolean invisible = onAodNotPulsingOrDocked || mWakeAndUnlockRunning
|| mShowingLaunchAffordance;
- if (mBypassController.getBypassEnabled()
- && mStatusBarStateController.getState() == StatusBarState.KEYGUARD
- && !mWakeUpCoordinator.getNotificationsFullyHidden()
- && !mBouncerShowing) {
- invisible = true;
+ if (mBypassController.getBypassEnabled() && !mBouncerShowingScrimmed) {
+ if (mHeadsUpManager.isHeadsUpGoingAway()
+ || mHeadsUpManager.hasPinnedHeadsUp()
+ || (mStatusBarStateController.getState() == StatusBarState.KEYGUARD
+ && !mWakeUpCoordinator.getNotificationsFullyHidden())) {
+ invisible = true;
+ }
}
boolean wasInvisible = getVisibility() == INVISIBLE;
if (invisible != wasInvisible) {
@@ -408,8 +415,8 @@
}
}
- public void setBouncerShowing(boolean bouncerShowing) {
- mBouncerShowing = bouncerShowing;
+ public void setBouncerShowingScrimmed(boolean bouncerShowing) {
+ mBouncerShowingScrimmed = bouncerShowing;
if (mBypassController.getBypassEnabled()) {
update();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index cd97722..d2159ca 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -248,7 +248,7 @@
if (onlyShowCenteredIcon) {
return isCenteredNotificationIcon;
}
- if (hideCenteredIcon && isCenteredNotificationIcon) {
+ if (hideCenteredIcon && isCenteredNotificationIcon && !entry.isRowHeadsUp()) {
return false;
}
if (mEntryManager.getNotificationData().isAmbient(entry.key) && !showAmbient) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 9d10438..e756d3a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -80,6 +80,7 @@
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
+import android.os.Debug;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
@@ -193,6 +194,7 @@
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.VibratorHelper;
import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
+import com.android.systemui.statusbar.notification.BypassHeadsUpNotifier;
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
import com.android.systemui.statusbar.notification.NotificationAlertingManager;
import com.android.systemui.statusbar.notification.NotificationClicker;
@@ -373,6 +375,8 @@
KeyguardBypassController mKeyguardBypassController;
@Inject
protected HeadsUpManagerPhone mHeadsUpManager;
+ @Inject
+ BypassHeadsUpNotifier mBypassHeadsUpNotifier;
@Nullable
@Inject
protected KeyguardLiftController mKeyguardLiftController;
@@ -633,6 +637,7 @@
mGutsManager = Dependency.get(NotificationGutsManager.class);
mMediaManager = Dependency.get(NotificationMediaManager.class);
mEntryManager = Dependency.get(NotificationEntryManager.class);
+ mBypassHeadsUpNotifier.setUp(mEntryManager);
mNotificationInterruptionStateProvider =
Dependency.get(NotificationInterruptionStateProvider.class);
mViewHierarchyManager = Dependency.get(NotificationViewHierarchyManager.class);
@@ -649,7 +654,7 @@
KeyguardSliceProvider sliceProvider = KeyguardSliceProvider.getAttachedInstance();
if (sliceProvider != null) {
sliceProvider.initDependencies(mMediaManager, mStatusBarStateController,
- mKeyguardBypassController);
+ mKeyguardBypassController, DozeParameters.getInstance(mContext));
} else {
Log.w(TAG, "Cannot init KeyguardSliceProvider dependencies");
}
@@ -1154,8 +1159,9 @@
private void inflateShelf() {
mNotificationShelf =
- (NotificationShelf) LayoutInflater.from(mContext).inflate(
- R.layout.status_bar_notification_shelf, mStackScroller, false);
+ (NotificationShelf) mInjectionInflater.injectable(
+ LayoutInflater.from(mContext)).inflate(
+ R.layout.status_bar_notification_shelf, mStackScroller, false);
mNotificationShelf.setOnClickListener(mGoToLockedShadeListener);
}
@@ -3576,7 +3582,7 @@
mBouncerShowing = bouncerShowing;
mKeyguardBypassController.setBouncerShowing(bouncerShowing);
mPulseExpansionHandler.setBouncerShowing(bouncerShowing);
- mStatusBarWindow.setBouncerShowing(bouncerShowing);
+ mStatusBarWindow.setBouncerShowingScrimmed(isBouncerShowingScrimmed());
if (mStatusBarView != null) mStatusBarView.setBouncerShowing(bouncerShowing);
updateHideIconsForBouncer(true /* animate */);
mCommandQueue.recomputeDisableFlags(mDisplayId, true /* animate */);
@@ -3629,6 +3635,7 @@
notifyHeadsUpGoingToSleep();
dismissVolumeDialog();
mWakeUpCoordinator.setFullyAwake(false);
+ mBypassHeadsUpNotifier.setFullyAwake(false);
mKeyguardBypassController.onStartedGoingToSleep();
}
@@ -3653,6 +3660,7 @@
@Override
public void onFinishedWakingUp() {
mWakeUpCoordinator.setFullyAwake(true);
+ mBypassHeadsUpNotifier.setFullyAwake(true);
mWakeUpCoordinator.setWakingUp(false);
if (mLaunchCameraWhenFinishedWaking) {
mNotificationPanel.launchCamera(false /* animate */, mLastCameraLaunchSource);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index a82e14e..667521b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -525,9 +525,9 @@
mBypassController = bypassController;
}
- public void setBouncerShowing(boolean bouncerShowing) {
+ public void setBouncerShowingScrimmed(boolean bouncerShowing) {
if (mLockIcon != null) {
- mLockIcon.setBouncerShowing(bouncerShowing);
+ mLockIcon.setBouncerShowingScrimmed(bouncerShowing);
}
}
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 40d5e4d..b84dc47 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
@@ -356,6 +356,10 @@
public void onDensityOrFontScaleChanged() {
}
+ public boolean isEntryAutoHeadsUpped(String key) {
+ return false;
+ }
+
/**
* This represents a notification and how long it is in a heads up mode. It also manages its
* lifecycle automatically when created.
@@ -416,16 +420,17 @@
@Override
protected long calculateFinishTime() {
- return mPostTime + getRecommendedHeadsUpTimeoutMs();
+ return mPostTime + getRecommendedHeadsUpTimeoutMs(mAutoDismissNotificationDecay);
}
/**
* Get user-preferred or default timeout duration. The larger one will be returned.
* @return milliseconds before auto-dismiss
+ * @param requestedTimeout
*/
- protected int getRecommendedHeadsUpTimeoutMs() {
+ protected int getRecommendedHeadsUpTimeoutMs(int requestedTimeout) {
return mAccessibilityMgr.getRecommendedTimeoutMillis(
- mAutoDismissNotificationDecay,
+ requestedTimeout,
AccessibilityManager.FLAG_CONTENT_CONTROLS
| AccessibilityManager.FLAG_CONTENT_ICONS
| AccessibilityManager.FLAG_CONTENT_TEXT);
diff --git a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java b/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
index d521e55..ede3004 100644
--- a/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
+++ b/packages/SystemUI/src/com/android/systemui/util/InjectionInflationController.java
@@ -32,6 +32,7 @@
import com.android.systemui.qs.QSPanel;
import com.android.systemui.qs.QuickQSPanel;
import com.android.systemui.qs.QuickStatusBarHeader;
+import com.android.systemui.statusbar.NotificationShelf;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
import com.android.systemui.statusbar.phone.LockIcon;
import com.android.systemui.statusbar.phone.NotificationPanelView;
@@ -138,6 +139,11 @@
QSCarrierGroup createQSCarrierGroup();
/**
+ * Creates the Shelf.
+ */
+ NotificationShelf creatNotificationShelf();
+
+ /**
* Creates the KeyguardClockSwitch.
*/
KeyguardClockSwitch createKeyguardClockSwitch();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
index bf06794..893f3d1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
@@ -48,6 +48,7 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.NotificationMediaManager;
+import com.android.systemui.statusbar.phone.DozeParameters;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.util.wakelock.SettableWakeLock;
@@ -84,6 +85,8 @@
private SettableWakeLock mMediaWakeLock;
@Mock
private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ @Mock
+ private DozeParameters mDozeParameters;
private TestableKeyguardSliceProvider mProvider;
private boolean mIsZenMode;
@@ -94,7 +97,7 @@
mProvider = new TestableKeyguardSliceProvider();
mProvider.attachInfo(getContext(), null);
mProvider.initDependencies(mNotificationMediaManager, mStatusBarStateController,
- mKeyguardBypassController);
+ mKeyguardBypassController, mDozeParameters);
SliceProvider.setSpecs(new HashSet<>(Arrays.asList(SliceSpecs.LIST)));
}
@@ -130,6 +133,7 @@
MediaMetadata metadata = mock(MediaMetadata.class);
when(metadata.getText(any())).thenReturn("metadata");
when(mKeyguardBypassController.getBypassEnabled()).thenReturn(true);
+ when(mDozeParameters.getAlwaysOn()).thenReturn(true);
mProvider.onMetadataOrStateChanged(metadata, PlaybackState.STATE_PLAYING);
mProvider.onBindSlice(mProvider.getUri());
verify(metadata).getText(eq(MediaMetadata.METADATA_KEY_TITLE));