Merge "Fading away notification panel individually" into qt-r1-dev

am: b26223d9c1

Change-Id: I546633a9516a8d65fd17534e4f008042e5e2c78a
This commit is contained in:
Selim Cinek 2019-07-05 13:47:49 -07:00 committed by android-build-merger
commit 798c910075
7 changed files with 220 additions and 14 deletions

View File

@ -23,9 +23,11 @@
android:fromAlpha="0.0" android:toAlpha="1.0"
android:fillEnabled="true" android:fillBefore="true"
android:interpolator="@interpolator/linear"
android:startOffset="80"
android:duration="233"/>
<translate android:fromYDelta="5%p" android:toYDelta="0"
android:fillEnabled="true" android:fillBefore="true" android:fillAfter="true"
android:interpolator="@interpolator/fast_out_slow_in"
android:startOffset="80"
android:duration="233" />
</set>

View File

@ -98,6 +98,12 @@
<item type="id" name="keyguard_hun_animator_start_tag"/>
<item type="id" name="keyguard_hun_animator_end_tag"/>
<item type="id" name="view_group_fade_helper_modified_views"/>
<item type="id" name="view_group_fade_helper_animator"/>
<item type="id" name="view_group_fade_helper_previous_value_tag"/>
<item type="id" name="view_group_fade_helper_restore_tag"/>
<item type="id" name="view_group_fade_helper_hardware_layer"/>
<!-- Accessibility actions for the notification menu -->
<item type="id" name="action_snooze_undo"/>
<item type="id" name="action_snooze_shorter"/>

View File

@ -61,6 +61,7 @@ import android.util.EventLog;
import android.util.Log;
import android.util.Slog;
import android.util.SparseArray;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManagerPolicyConstants;
import android.view.animation.Animation;
@ -85,6 +86,7 @@ import com.android.systemui.SystemUIFactory;
import com.android.systemui.UiOffloadThread;
import com.android.systemui.classifier.FalsingManagerFactory;
import com.android.systemui.statusbar.phone.BiometricUnlockController;
import com.android.systemui.statusbar.phone.KeyguardBypassController;
import com.android.systemui.statusbar.phone.NotificationPanelView;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
@ -2060,9 +2062,11 @@ public class KeyguardViewMediator extends SystemUI {
public StatusBarKeyguardViewManager registerStatusBar(StatusBar statusBar,
ViewGroup container, NotificationPanelView panelView,
BiometricUnlockController biometricUnlockController, ViewGroup lockIconContainer) {
BiometricUnlockController biometricUnlockController, ViewGroup lockIconContainer,
View notificationContainer, KeyguardBypassController bypassController) {
mStatusBarKeyguardViewManager.registerStatusBar(statusBar, container, panelView,
biometricUnlockController, mDismissCallbackRegistry, lockIconContainer);
biometricUnlockController, mDismissCallbackRegistry, lockIconContainer,
notificationContainer, bypassController);
return mStatusBarKeyguardViewManager;
}

View File

@ -0,0 +1,147 @@
/*
* 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.animation.Animator
import android.animation.AnimatorListenerAdapter
import android.animation.ValueAnimator
import android.view.View
import android.view.ViewGroup
import com.android.systemui.Interpolators
import com.android.systemui.R
/**
* Class to help with fading of view groups without fading one subview
*/
class ViewGroupFadeHelper {
companion object {
private val visibilityIncluder = {
view: View -> view.visibility == View.VISIBLE
}
/**
* Fade out all views of a root except a single child. This will iterate over all children
* of the view and make sure that the animation works smoothly.
* @param root the view root to fade the children away
* @param excludedView which view should remain
* @param duration the duration of the animation
*/
@JvmStatic
fun fadeOutAllChildrenExcept(root: ViewGroup, excludedView: View, duration: Long,
endRunnable: Runnable?) {
// starting from the view going up, we are adding the siblings of the child to the set
// of views that need to be faded.
val viewsToFadeOut = gatherViews(root, excludedView, visibilityIncluder)
// Applying the right layertypes for the animation
for (viewToFade in viewsToFadeOut) {
if (viewToFade.hasOverlappingRendering
&& viewToFade.layerType == View.LAYER_TYPE_NONE) {
viewToFade.setLayerType(View.LAYER_TYPE_HARDWARE, null)
viewToFade.setTag(R.id.view_group_fade_helper_hardware_layer, true)
}
}
val animator = ValueAnimator.ofFloat(1.0f, 0.0f).apply {
this.duration = duration
interpolator = Interpolators.ALPHA_OUT
addUpdateListener { animation ->
val previousSetAlpha = root.getTag(
R.id.view_group_fade_helper_previous_value_tag) as Float?
val newAlpha = animation.animatedValue as Float
for (viewToFade in viewsToFadeOut) {
if (viewToFade.alpha != previousSetAlpha) {
// A value was set that wasn't set from our view, let's store it and restore
// it at the end
viewToFade.setTag(R.id.view_group_fade_helper_restore_tag, viewToFade.alpha)
}
viewToFade.alpha = newAlpha
}
root.setTag(R.id.view_group_fade_helper_previous_value_tag, newAlpha)
}
addListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator?) {
endRunnable?.run()
}
})
start()
}
root.setTag(R.id.view_group_fade_helper_modified_views, viewsToFadeOut)
root.setTag(R.id.view_group_fade_helper_animator, animator)
}
private fun gatherViews(root: ViewGroup, excludedView: View,
shouldInclude: (View) -> Boolean): MutableSet<View> {
val viewsToFadeOut = mutableSetOf<View>()
var parent = excludedView.parent as ViewGroup?
var viewContainingExcludedView = excludedView;
while (parent != null) {
for (i in 0 until parent.childCount) {
val child = parent.getChildAt(i)
if (shouldInclude.invoke(child) && viewContainingExcludedView != child) {
viewsToFadeOut.add(child)
}
}
if (parent == root) {
break;
}
viewContainingExcludedView = parent
parent = parent.parent as ViewGroup?
}
return viewsToFadeOut
}
/**
* Reset all view alphas for views previously transformed away.
*/
@JvmStatic
fun reset(root: ViewGroup) {
@Suppress("UNCHECKED_CAST")
val modifiedViews = root.getTag(R.id.view_group_fade_helper_modified_views)
as MutableSet<View>?
val animator = root.getTag(R.id.view_group_fade_helper_animator) as Animator?
if (modifiedViews == null || animator == null) {
// nothing to restore
return
}
animator.cancel()
val lastSetValue = root.getTag(
R.id.view_group_fade_helper_previous_value_tag) as Float?
for (viewToFade in modifiedViews) {
val restoreAlpha = viewToFade.getTag(
R.id.view_group_fade_helper_restore_tag) as Float?
if (restoreAlpha == null) {
continue
}
if (lastSetValue == viewToFade.alpha) {
// it was modified after the transition!
viewToFade.alpha = restoreAlpha
}
val needsLayerReset = viewToFade.getTag(
R.id.view_group_fade_helper_hardware_layer) as Boolean?
if (needsLayerReset == true) {
viewToFade.setLayerType(View.LAYER_TYPE_NONE, null)
viewToFade.setTag(R.id.view_group_fade_helper_hardware_layer, null)
}
viewToFade.setTag(R.id.view_group_fade_helper_restore_tag, null)
}
root.setTag(R.id.view_group_fade_helper_modified_views, null)
root.setTag(R.id.view_group_fade_helper_previous_value_tag, null)
root.setTag(R.id.view_group_fade_helper_animator, null)
}
}
}

View File

@ -202,6 +202,7 @@ import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.NotificationListController;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
import com.android.systemui.statusbar.notification.ViewGroupFadeHelper;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationRowBinderImpl;
@ -1235,7 +1236,8 @@ public class StatusBar extends SystemUI implements DemoMode,
new Handler(), mKeyguardUpdateMonitor, mKeyguardBypassController);
mStatusBarKeyguardViewManager = keyguardViewMediator.registerStatusBar(this,
getBouncerContainer(), mNotificationPanel, mBiometricUnlockController,
mStatusBarWindow.findViewById(R.id.lock_icon_container));
mStatusBarWindow.findViewById(R.id.lock_icon_container), mStackScroller,
mKeyguardBypassController);
mKeyguardIndicationController
.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
mBiometricUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
@ -3172,6 +3174,7 @@ public class StatusBar extends SystemUI implements DemoMode,
mNotificationPanel.onAffordanceLaunchEnded();
mNotificationPanel.animate().cancel();
mNotificationPanel.setAlpha(1f);
ViewGroupFadeHelper.reset(mNotificationPanel);
updateScrimController();
Trace.endSection();
return staying;

View File

@ -17,6 +17,7 @@
package com.android.systemui.statusbar.phone;
import static com.android.systemui.plugins.ActivityStarter.OnDismissAction;
import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_UNLOCK_FADING;
import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK;
import static com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING;
@ -51,6 +52,7 @@ import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.RemoteInputController;
import com.android.systemui.statusbar.StatusBarState;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.notification.ViewGroupFadeHelper;
import com.android.systemui.statusbar.phone.KeyguardBouncer.BouncerExpansionCallback;
import com.android.systemui.statusbar.policy.ConfigurationController;
import com.android.systemui.statusbar.policy.KeyguardMonitor;
@ -82,6 +84,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
// make everything a bit slower to bridge a gap until the user is unlocked and home screen has
// dranw its first frame.
private static final long KEYGUARD_DISMISS_DURATION_LOCKED = 2000;
private static final long BYPASS_PANEL_FADE_DURATION = 67;
private static String TAG = "StatusBarKeyguardViewManager";
@ -132,6 +135,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
private ViewGroup mContainer;
private ViewGroup mLockIconContainer;
private View mNotificationContainer;
protected KeyguardBouncer mBouncer;
protected boolean mShowing;
@ -165,9 +169,10 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
(KeyguardMonitorImpl) Dependency.get(KeyguardMonitor.class);
private final NotificationMediaManager mMediaManager =
Dependency.get(NotificationMediaManager.class);
private final StatusBarStateController mStatusBarStateController =
Dependency.get(StatusBarStateController.class);
private final SysuiStatusBarStateController mStatusBarStateController =
(SysuiStatusBarStateController) Dependency.get(StatusBarStateController.class);
private final DockManager mDockManager;
private KeyguardBypassController mBypassController;
private final KeyguardUpdateMonitorCallback mUpdateMonitorCallback =
new KeyguardUpdateMonitorCallback() {
@ -205,7 +210,8 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
NotificationPanelView notificationPanelView,
BiometricUnlockController biometricUnlockController,
DismissCallbackRegistry dismissCallbackRegistry,
ViewGroup lockIconContainer) {
ViewGroup lockIconContainer, View notificationContainer,
KeyguardBypassController bypassController) {
mStatusBar = statusBar;
mContainer = container;
mLockIconContainer = lockIconContainer;
@ -218,6 +224,8 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
mExpansionCallback);
mNotificationPanelView = notificationPanelView;
notificationPanelView.setExpansionListener(this);
mBypassController = bypassController;
mNotificationContainer = notificationContainer;
}
@Override
@ -555,12 +563,32 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
mBiometricUnlockController.startKeyguardFadingAway();
hideBouncer(true /* destroyView */);
if (wakeUnlockPulsing) {
mStatusBar.fadeKeyguardWhilePulsing();
if (needsBypassFading()) {
ViewGroupFadeHelper.fadeOutAllChildrenExcept(mNotificationPanelView,
mNotificationContainer,
BYPASS_PANEL_FADE_DURATION,
() -> {
mStatusBar.hideKeyguard();
onKeyguardFadedAway();
});
} else {
mStatusBar.fadeKeyguardWhilePulsing();
}
wakeAndUnlockDejank();
} else {
boolean staying = mStatusBar.hideKeyguard();
boolean staying = mStatusBarStateController.leaveOpenOnKeyguardHide();
if (!staying) {
mStatusBarWindowController.setKeyguardFadingAway(true);
if (needsBypassFading()) {
ViewGroupFadeHelper.fadeOutAllChildrenExcept(mNotificationPanelView,
mNotificationContainer,
BYPASS_PANEL_FADE_DURATION,
() -> {
mStatusBar.hideKeyguard();
});
} else {
mStatusBar.hideKeyguard();
}
// hide() will happen asynchronously and might arrive after the scrims
// were already hidden, this means that the transition callback won't
// be triggered anymore and StatusBarWindowController will be forever in
@ -568,6 +596,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
mStatusBar.updateScrimController();
wakeAndUnlockDejank();
} else {
mStatusBar.hideKeyguard();
mStatusBar.finishKeyguardFadingAway();
mBiometricUnlockController.finishKeyguardFadingAway();
}
@ -580,6 +609,13 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
StatsLog.KEYGUARD_STATE_CHANGED__STATE__HIDDEN);
}
private boolean needsBypassFading() {
return (mBiometricUnlockController.getMode() == MODE_UNLOCK_FADING
|| mBiometricUnlockController.getMode() == MODE_WAKE_AND_UNLOCK_PULSING
|| mBiometricUnlockController.getMode() == MODE_WAKE_AND_UNLOCK)
&& mBypassController.getBypassEnabled();
}
@Override
public void onDensityOrFontScaleChanged() {
hideBouncer(true /* destroyView */);
@ -602,6 +638,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
public void onKeyguardFadedAway() {
mContainer.postDelayed(() -> mStatusBarWindowController.setKeyguardFadingAway(false),
100);
ViewGroupFadeHelper.reset(mNotificationPanelView);
mStatusBar.finishKeyguardFadingAway();
mBiometricUnlockController.finishKeyguardFadingAway();
WindowManagerGlobal.getInstance().trimMemory(
@ -821,8 +858,7 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb
* @return Whether subtle animation should be used for unlocking the device.
*/
public boolean shouldSubtleWindowAnimationsForUnlock() {
return mStatusBar.mKeyguardBypassController.getBypassEnabled()
&& mStatusBar.mState == StatusBarState.KEYGUARD && !mBouncer.isAnimatingAway();
return needsBypassFading();
}
public boolean isGoingToNotificationShade() {

View File

@ -29,6 +29,7 @@ import static org.mockito.Mockito.when;
import android.content.Context;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.view.View;
import android.view.ViewGroup;
import androidx.test.filters.SmallTest;
@ -39,6 +40,7 @@ import com.android.systemui.SysuiTestCase;
import com.android.systemui.keyguard.DismissCallbackRegistry;
import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
import com.android.systemui.plugins.statusbar.StatusBarStateController;
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import org.junit.Before;
import org.junit.Test;
@ -70,7 +72,11 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
@Mock
private ViewGroup mLockIconContainer;
@Mock
private StatusBarStateController mStatusBarStateController;
private SysuiStatusBarStateController mStatusBarStateController;
@Mock
private View mNotificationContainer;
@Mock
private KeyguardBypassController mBypassController;
private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
@Before
@ -83,7 +89,7 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
mViewMediatorCallback, mLockPatternUtils);
mStatusBarKeyguardViewManager.registerStatusBar(mStatusBar, mContainer,
mNotificationPanelView, mBiometrucUnlockController, mDismissCallbackRegistry,
mLockIconContainer);
mLockIconContainer, mNotificationContainer, mBypassController);
mStatusBarKeyguardViewManager.show(null);
}
@ -221,9 +227,11 @@ public class StatusBarKeyguardViewManagerTest extends SysuiTestCase {
NotificationPanelView notificationPanelView,
BiometricUnlockController fingerprintUnlockController,
DismissCallbackRegistry dismissCallbackRegistry,
ViewGroup lockIconContainer) {
ViewGroup lockIconContainer, View notificationContainer,
KeyguardBypassController bypassController) {
super.registerStatusBar(statusBar, container, notificationPanelView,
fingerprintUnlockController, dismissCallbackRegistry, lockIconContainer);
fingerprintUnlockController, dismissCallbackRegistry, lockIconContainer,
notificationContainer, bypassController);
mBouncer = StatusBarKeyguardViewManagerTest.this.mBouncer;
}
}