Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 06c12d64 authored by Selim Cinek's avatar Selim Cinek
Browse files

Fading away notification panel individually

Previously the notification panel was fading away all together,
which doesn't work when the notifications need to stay around.
We're now fading the whole panel away.

Bug: 134952761
Test: pick up phone and unlock, observe normal behavior
Change-Id: I48d12776dc8b4bd51c1a35c2b822caeef38eb850
parent 9917209b
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -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>
 No newline at end of file
+6 −0
Original line number Diff line number Diff line
@@ -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"/>
+6 −2
Original line number Diff line number Diff line
@@ -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;
    }

+147 −0
Original line number Diff line number Diff line
/*
 * 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)
        }
    }
}
+4 −1
Original line number Diff line number Diff line
@@ -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;
@@ -1232,7 +1233,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);
@@ -3169,6 +3171,7 @@ public class StatusBar extends SystemUI implements DemoMode,
        mNotificationPanel.onAffordanceLaunchEnded();
        mNotificationPanel.animate().cancel();
        mNotificationPanel.setAlpha(1f);
        ViewGroupFadeHelper.reset(mNotificationPanel);
        updateScrimController();
        Trace.endSection();
        return staying;
Loading