diff options
| author | 2021-11-24 14:24:18 +0000 | |
|---|---|---|
| committer | 2021-11-24 14:24:18 +0000 | |
| commit | cb9390f8726b049b99b21e124a8bcc1f52941e0f (patch) | |
| tree | 2dc0e6713f82815aa2f520115735ab08557ed4b1 | |
| parent | b06ff485a597b4d22cc783162f1c8f6fe9d73f4c (diff) | |
| parent | 8639dd9756cddaac29c61d83dcdc666c7fea6a8c (diff) | |
Merge "Reduce hardware render sizes for ExpandableNotificationRow."
12 files changed, 321 insertions, 14 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFadeAware.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFadeAware.java new file mode 100644 index 000000000000..8d2e3c92c92a --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationFadeAware.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2021 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.view.View; + +import androidx.annotation.Nullable; + +/** + * Used to let views that have an alpha not apply the HARDWARE layer type directly, and instead + * delegate that to specific children. This is useful if we want to fake not having overlapping + * rendering to avoid layer trashing, when fading out a view that is also changing. + */ +public interface NotificationFadeAware { + /** + * Calls {@link View#setLayerType} with {@link View#LAYER_TYPE_HARDWARE} if faded and + * {@link View#LAYER_TYPE_NONE} otherwise. + */ + static void setLayerTypeForFaded(@Nullable View view, boolean faded) { + if (view != null) { + int newLayerType = faded ? View.LAYER_TYPE_HARDWARE : View.LAYER_TYPE_NONE; + view.setLayerType(newLayerType, null); + } + } + + /** + * Used like {@link View#setLayerType} with {@link View#LAYER_TYPE_HARDWARE} or + * {@link View#LAYER_TYPE_NONE} except that instead of necessarily affecting this view + * specifically, this may delegate the call to child views. + * + * When set to <code>true</code>, the view has two possible paths: + * 1. If a hardware layer is required to ensure correct appearance of this view, then + * set that layer type. + * 2. Otherwise, delegate this call to children, who might make that call for themselves. + * + * When set to <code>false</code>, the view should undo the above, typically by calling + * {@link View#setLayerType} with {@link View#LAYER_TYPE_NONE} on itself and children, and + * delegating to this method on children where implemented. + * + * When this delegates to {@link View#setLayerType} on this view or a subview, `null` will be + * passed for the `paint` argument of that call. + */ + void setNotificationFaded(boolean faded); + + /** + * Interface for the top level notification view that fades and optimizes that through deep + * awareness of individual components. + */ + interface FadeOptimizedNotification extends NotificationFadeAware { + /** Top-level feature switch */ + boolean FADE_LAYER_OPTIMIZATION_ENABLED = true; + + /** Determine if the notification is currently faded. */ + boolean isNotificationFaded(); + } +} 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 9f10322b5fa3..4a8a4fe25eb1 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 @@ -92,6 +92,7 @@ import com.android.systemui.statusbar.RemoteInputController; import com.android.systemui.statusbar.StatusBarIconView; import com.android.systemui.statusbar.notification.AboveShelfChangedListener; import com.android.systemui.statusbar.notification.ExpandAnimationParameters; +import com.android.systemui.statusbar.notification.NotificationFadeAware; import com.android.systemui.statusbar.notification.NotificationLaunchAnimatorController; import com.android.systemui.statusbar.notification.NotificationUtils; import com.android.systemui.statusbar.notification.collection.NotificationEntry; @@ -131,7 +132,8 @@ import java.util.function.Consumer; * the group summary (which contains 1 or more child notifications). */ public class ExpandableNotificationRow extends ActivatableNotificationView - implements PluginListener<NotificationMenuRowPlugin>, SwipeableView { + implements PluginListener<NotificationMenuRowPlugin>, SwipeableView, + NotificationFadeAware.FadeOptimizedNotification { private static final boolean DEBUG = false; private static final int DEFAULT_DIVIDER_ALPHA = 0x29; @@ -144,6 +146,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView private boolean mUpdateBackgroundOnUpdate; private boolean mNotificationTranslationFinished = false; private boolean mIsSnoozed; + private boolean mIsFaded; /** * Listener for when {@link ExpandableNotificationRow} is laid out. @@ -2774,17 +2777,112 @@ public class ExpandableNotificationRow extends ActivatableNotificationView // alphas are reset if (mChildrenContainer != null) { mChildrenContainer.setAlpha(1.0f); - mChildrenContainer.setLayerType(LAYER_TYPE_NONE, null); } for (NotificationContentView l : mLayouts) { l.setAlpha(1.0f); - l.setLayerType(LAYER_TYPE_NONE, null); + } + if (FADE_LAYER_OPTIMIZATION_ENABLED) { + setNotificationFaded(false); + } else { + setNotificationFadedOnChildren(false); } } else { setHeadsUpAnimatingAway(false); } } + /** Gets the last value set with {@link #setNotificationFaded(boolean)} */ + @Override + public boolean isNotificationFaded() { + return mIsFaded; + } + + /** + * This class needs to delegate the faded state set on it by + * {@link com.android.systemui.statusbar.notification.stack.ViewState} to its children. + * Having each notification use layerType of HARDWARE anytime it fades in/out can result in + * extremely large layers (in the case of groups, it can even exceed the device height). + * Because these large renders can cause serious jank when rendering, we instead have + * notifications return false from {@link #hasOverlappingRendering()} and delegate the + * layerType to child views which really need it in order to render correctly, such as icon + * views or the conversation face pile. + * + * Another compounding factor for notifications is that we change clipping on each frame of the + * animation, so the hardware layer isn't able to do any caching at the top level, but the + * individual elements we render with hardware layers (e.g. icons) cache wonderfully because we + * never invalidate them. + */ + @Override + public void setNotificationFaded(boolean faded) { + mIsFaded = faded; + if (childrenRequireOverlappingRendering()) { + // == Simple Scenario == + // If a child (like remote input) needs this to have overlapping rendering, then set + // the layerType of this view and reset the children to render as if the notification is + // not fading. + NotificationFadeAware.setLayerTypeForFaded(this, faded); + setNotificationFadedOnChildren(false); + } else { + // == Delegating Scenario == + // This is the new normal for alpha: Explicitly reset this view's layer type to NONE, + // and require that all children use their own hardware layer if they have bad + // overlapping rendering. + NotificationFadeAware.setLayerTypeForFaded(this, false); + setNotificationFadedOnChildren(faded); + } + } + + /** Private helper for iterating over the layouts and children containers to set faded state */ + private void setNotificationFadedOnChildren(boolean faded) { + delegateNotificationFaded(mChildrenContainer, faded); + for (NotificationContentView layout : mLayouts) { + delegateNotificationFaded(layout, faded); + } + } + + private static void delegateNotificationFaded(@Nullable View view, boolean faded) { + if (FADE_LAYER_OPTIMIZATION_ENABLED && view instanceof NotificationFadeAware) { + ((NotificationFadeAware) view).setNotificationFaded(faded); + } else { + NotificationFadeAware.setLayerTypeForFaded(view, faded); + } + } + + /** + * Only declare overlapping rendering if independent children of the view require it. + */ + @Override + public boolean hasOverlappingRendering() { + return super.hasOverlappingRendering() && childrenRequireOverlappingRendering(); + } + + /** + * Because RemoteInputView is designed to be an opaque view that overlaps the Actions row, the + * row should require overlapping rendering to ensure that the overlapped view doesn't bleed + * through when alpha fading. + * + * Note that this currently works for top-level notifications which squish their height down + * while collapsing the shade, but does not work for children inside groups, because the + * accordion affect does not apply to those views, so super.hasOverlappingRendering() will + * always return false to avoid the clipping caused when the view's measured height is less than + * the 'actual height'. + */ + private boolean childrenRequireOverlappingRendering() { + if (!FADE_LAYER_OPTIMIZATION_ENABLED) { + return true; + } + // The colorized background is another layer with which all other elements overlap + if (getEntry().getSbn().getNotification().isColorized()) { + return true; + } + // Check if the showing layout has a need for overlapping rendering. + // NOTE: We could check both public and private layouts here, but becuause these states + // don't animate well, there are bigger visual artifacts if we start changing the shown + // layout during shade expansion. + NotificationContentView showingLayout = getShowingLayout(); + return showingLayout != null && showingLayout.requireRowToHaveOverlappingRendering(); + } + @Override public int getExtraBottomPadding() { if (mIsSummaryWithChildren && isGroupExpanded()) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridConversationNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridConversationNotificationView.java index caba3ac7e17b..c66140822d92 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridConversationNotificationView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridConversationNotificationView.java @@ -28,6 +28,7 @@ import android.widget.TextView; import com.android.internal.widget.ConversationLayout; import com.android.systemui.R; +import com.android.systemui.statusbar.notification.NotificationFadeAware; /** * A hybrid view which may contain information about one ore more conversations. @@ -138,4 +139,14 @@ public class HybridConversationNotificationView extends HybridNotificationView { lp.height = size; view.setLayoutParams(lp); } + + /** + * Apply the faded state as a layer type change to the face pile view which needs to have + * overlapping contents render precisely. + */ + @Override + public void setNotificationFaded(boolean faded) { + super.setNotificationFaded(faded); + NotificationFadeAware.setLayerTypeForFaded(mConversationFacePile, faded); + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridNotificationView.java index bc2adac31d07..c0d85a6a16ef 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridNotificationView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/HybridNotificationView.java @@ -28,13 +28,14 @@ import com.android.systemui.R; import com.android.systemui.statusbar.CrossFadeHelper; import com.android.systemui.statusbar.TransformableView; import com.android.systemui.statusbar.ViewTransformationHelper; +import com.android.systemui.statusbar.notification.NotificationFadeAware; import com.android.systemui.statusbar.notification.TransformState; /** * A hybrid view which may contain information about one ore more notifications. */ public class HybridNotificationView extends AlphaOptimizedLinearLayout - implements TransformableView { + implements TransformableView, NotificationFadeAware { protected final ViewTransformationHelper mTransformationHelper = new ViewTransformationHelper(); protected TextView mTitleView; @@ -148,4 +149,7 @@ public class HybridNotificationView extends AlphaOptimizedLinearLayout setVisibility(visible ? View.VISIBLE : View.INVISIBLE); mTransformationHelper.setVisible(visible); } + + @Override + public void setNotificationFaded(boolean faded) {} } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java index 727f0e55f58f..438992e22577 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java @@ -46,6 +46,7 @@ import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; import com.android.systemui.statusbar.RemoteInputController; import com.android.systemui.statusbar.SmartReplyController; import com.android.systemui.statusbar.TransformableView; +import com.android.systemui.statusbar.notification.NotificationFadeAware; import com.android.systemui.statusbar.notification.NotificationUtils; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager; @@ -73,7 +74,7 @@ import java.util.List; * expanded and heads up layout. This class is responsible for clipping the content and and * switching between the expanded, contracted and the heads up view depending on its clipped size. */ -public class NotificationContentView extends FrameLayout { +public class NotificationContentView extends FrameLayout implements NotificationFadeAware { private static final String TAG = "NotificationContentView"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); @@ -2045,6 +2046,41 @@ public class NotificationContentView extends FrameLayout { return Notification.COLOR_INVALID; } + /** + * Delegate the faded state to the notification content views which actually + * need to have overlapping contents render precisely. + */ + @Override + public void setNotificationFaded(boolean faded) { + if (mContractedWrapper != null) { + mContractedWrapper.setNotificationFaded(faded); + } + if (mHeadsUpWrapper != null) { + mHeadsUpWrapper.setNotificationFaded(faded); + } + if (mExpandedWrapper != null) { + mExpandedWrapper.setNotificationFaded(faded); + } + if (mSingleLineView != null) { + mSingleLineView.setNotificationFaded(faded); + } + } + + /** + * @return true if a visible view has a remote input active, as this requires that the entire + * row report that it has overlapping rendering. + */ + public boolean requireRowToHaveOverlappingRendering() { + // This inexpensive check is done on both states to avoid state invalidating the result. + if (mHeadsUpRemoteInput != null && mHeadsUpRemoteInput.isActive()) { + return true; + } + if (mExpandedRemoteInput != null && mExpandedRemoteInput.isActive()) { + return true; + } + return false; + } + public void setRemoteInputViewSubcomponentFactory(RemoteInputViewSubcomponent.Factory factory) { mRemoteInputSubcomponentFactory = factory; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCallTemplateViewWrapper.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCallTemplateViewWrapper.kt index 12e94cbc1ab9..bb43b95357db 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCallTemplateViewWrapper.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCallTemplateViewWrapper.kt @@ -21,6 +21,7 @@ import android.view.View import com.android.internal.widget.CachingIconView import com.android.internal.widget.CallLayout import com.android.systemui.R +import com.android.systemui.statusbar.notification.NotificationFadeAware import com.android.systemui.statusbar.notification.NotificationUtils import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow @@ -37,6 +38,7 @@ class NotificationCallTemplateViewWrapper constructor( NotificationUtils.getFontScaledHeight(ctx, R.dimen.notification_max_height) private val callLayout: CallLayout = view as CallLayout + private lateinit var conversationIconContainer: View private lateinit var conversationIconView: CachingIconView private lateinit var conversationBadgeBg: View private lateinit var expandBtn: View @@ -45,6 +47,8 @@ class NotificationCallTemplateViewWrapper constructor( private fun resolveViews() { with(callLayout) { + conversationIconContainer = + requireViewById(com.android.internal.R.id.conversation_icon_container) conversationIconView = requireViewById(com.android.internal.R.id.conversation_icon) conversationBadgeBg = requireViewById(com.android.internal.R.id.conversation_icon_badge_bg) @@ -82,4 +86,14 @@ class NotificationCallTemplateViewWrapper constructor( } override fun getMinLayoutHeight(): Int = minHeightWithActions + + /** + * Apply the faded state as a layer type change to the face pile view which needs to have + * overlapping contents render precisely. + */ + override fun setNotificationFaded(faded: Boolean) { + // Do not call super + NotificationFadeAware.setLayerTypeForFaded(expandBtn, faded) + NotificationFadeAware.setLayerTypeForFaded(conversationIconContainer, faded) + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt index 3ef5b665d778..e136055b80b3 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationConversationTemplateViewWrapper.kt @@ -23,6 +23,7 @@ import com.android.internal.widget.CachingIconView import com.android.internal.widget.ConversationLayout import com.android.internal.widget.MessagingLinearLayout import com.android.systemui.R +import com.android.systemui.statusbar.notification.NotificationFadeAware import com.android.systemui.statusbar.notification.NotificationUtils import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow import com.android.systemui.statusbar.notification.row.wrapper.NotificationMessagingTemplateViewWrapper.setCustomImageMessageTransform @@ -42,6 +43,7 @@ class NotificationConversationTemplateViewWrapper constructor( ) private val conversationLayout: ConversationLayout = view as ConversationLayout + private lateinit var conversationIconContainer: View private lateinit var conversationIconView: CachingIconView private lateinit var conversationBadgeBg: View private lateinit var expandBtn: View @@ -59,6 +61,8 @@ class NotificationConversationTemplateViewWrapper constructor( messagingLinearLayout = conversationLayout.messagingLinearLayout imageMessageContainer = conversationLayout.imageMessageContainer with(conversationLayout) { + conversationIconContainer = + requireViewById(com.android.internal.R.id.conversation_icon_container) conversationIconView = requireViewById(com.android.internal.R.id.conversation_icon) conversationBadgeBg = requireViewById(com.android.internal.R.id.conversation_icon_badge_bg) @@ -136,4 +140,10 @@ class NotificationConversationTemplateViewWrapper constructor( minHeightWithActions else super.getMinLayoutHeight() + + override fun setNotificationFaded(faded: Boolean) { + // Do not call super + NotificationFadeAware.setLayerTypeForFaded(expandBtn, faded) + NotificationFadeAware.setLayerTypeForFaded(conversationIconContainer, faded) + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapper.java index 4c9c2f95b35c..fdff12d22354 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapper.java @@ -22,6 +22,7 @@ import android.view.View; import com.android.internal.graphics.ColorUtils; import com.android.systemui.R; +import com.android.systemui.statusbar.notification.NotificationFadeAware; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; /** @@ -86,4 +87,14 @@ public class NotificationCustomViewWrapper extends NotificationViewWrapper { public boolean shouldClipToRounding(boolean topRounded, boolean bottomRounded) { return true; } + + /** + * Apply the faded state as a layer type change to the custom view which needs to have + * overlapping contents render precisely. + */ + @Override + public void setNotificationFaded(boolean faded) { + super.setNotificationFaded(faded); + NotificationFadeAware.setLayerTypeForFaded(mView, faded); + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationDecoratedCustomViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationDecoratedCustomViewWrapper.java index 8c6fa023d92b..31595397b9b0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationDecoratedCustomViewWrapper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationDecoratedCustomViewWrapper.java @@ -20,6 +20,7 @@ import android.content.Context; import android.view.View; import android.view.ViewGroup; +import com.android.systemui.statusbar.notification.NotificationFadeAware; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; /** @@ -67,4 +68,14 @@ public class NotificationDecoratedCustomViewWrapper extends NotificationTemplate } super.onContentUpdated(row); } + + /** + * Apply the faded state as a layer type change to the custom view which needs to have + * overlapping contents render precisely. + */ + @Override + public void setNotificationFaded(boolean faded) { + super.setNotificationFaded(faded); + NotificationFadeAware.setLayerTypeForFaded(mWrappedView, faded); + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java index 76301917b458..6c3e0d2f798b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java @@ -42,6 +42,7 @@ import com.android.internal.widget.CachingIconView; import com.android.settingslib.Utils; import com.android.systemui.statusbar.CrossFadeHelper; import com.android.systemui.statusbar.TransformableView; +import com.android.systemui.statusbar.notification.NotificationFadeAware; import com.android.systemui.statusbar.notification.TransformState; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; @@ -395,4 +396,13 @@ public abstract class NotificationViewWrapper implements TransformableView { */ public void setRecentlyAudiblyAlerted(boolean audiblyAlerted) { } + + /** + * Apply the faded state as a layer type change to the views which need to have overlapping + * contents render precisely. + */ + public void setNotificationFaded(boolean faded) { + NotificationFadeAware.setLayerTypeForFaded(getIcon(), faded); + NotificationFadeAware.setLayerTypeForFaded(getExpandButton(), faded); + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java index a4727106c5fa..a1aed46ca8a6 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainer.java @@ -38,6 +38,7 @@ import com.android.internal.widget.NotificationExpandButton; import com.android.systemui.R; import com.android.systemui.statusbar.CrossFadeHelper; import com.android.systemui.statusbar.NotificationGroupingUtil; +import com.android.systemui.statusbar.notification.NotificationFadeAware; import com.android.systemui.statusbar.notification.NotificationUtils; import com.android.systemui.statusbar.notification.collection.legacy.VisualStabilityManager; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; @@ -51,7 +52,8 @@ import java.util.List; /** * A container containing child notifications */ -public class NotificationChildrenContainer extends ViewGroup { +public class NotificationChildrenContainer extends ViewGroup + implements NotificationFadeAware { @VisibleForTesting static final int NUMBER_OF_CHILDREN_WHEN_COLLAPSED = 2; @@ -111,6 +113,7 @@ public class NotificationChildrenContainer extends ViewGroup { private int mCurrentHeaderTranslation = 0; private float mHeaderVisibleAmount = 1.0f; private int mUntruncatedChildCount; + private boolean mContainingNotificationIsFaded = false; public NotificationChildrenContainer(Context context) { this(context, null); @@ -277,6 +280,7 @@ public class NotificationChildrenContainer extends ViewGroup { mDividers.add(newIndex, divider); row.setContentTransformationAmount(0, false /* isLastChild */); + row.setNotificationFaded(mContainingNotificationIsFaded); // It doesn't make sense to keep old animations around, lets cancel them! ExpandableViewState viewState = row.getViewState(); if (viewState != null) { @@ -301,6 +305,7 @@ public class NotificationChildrenContainer extends ViewGroup { }); row.setSystemChildExpanded(false); + row.setNotificationFaded(false); row.setUserLocked(false); if (!row.isRemoved()) { mGroupingUtil.restoreChildNotification(row); @@ -1308,4 +1313,18 @@ public class NotificationChildrenContainer extends ViewGroup { mNotificationHeaderWrapperLowPriority.setRecentlyAudiblyAlerted(audiblyAlertedRecently); } } + + @Override + public void setNotificationFaded(boolean faded) { + mContainingNotificationIsFaded = faded; + if (mNotificationHeaderWrapper != null) { + mNotificationHeaderWrapper.setNotificationFaded(faded); + } + if (mNotificationHeaderWrapperLowPriority != null) { + mNotificationHeaderWrapperLowPriority.setNotificationFaded(faded); + } + for (ExpandableNotificationRow child : mAttachedChildren) { + child.setNotificationFaded(faded); + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ViewState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ViewState.java index 6d82a45313d1..83bea84c8d33 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ViewState.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ViewState.java @@ -29,6 +29,7 @@ import com.android.systemui.Dumpable; import com.android.systemui.R; import com.android.systemui.animation.Interpolators; import com.android.systemui.statusbar.notification.AnimatableProperty; +import com.android.systemui.statusbar.notification.NotificationFadeAware.FadeOptimizedNotification; import com.android.systemui.statusbar.notification.PropertyAnimator; import com.android.systemui.statusbar.notification.row.ExpandableView; import com.android.systemui.statusbar.policy.HeadsUpUtil; @@ -206,14 +207,26 @@ public class ViewState implements Dumpable { } else if (view.getAlpha() != this.alpha) { // apply layer type boolean becomesFullyVisible = this.alpha == 1.0f; - boolean newLayerTypeIsHardware = !becomesInvisible && !becomesFullyVisible - && view.hasOverlappingRendering(); - int layerType = view.getLayerType(); - int newLayerType = newLayerTypeIsHardware - ? View.LAYER_TYPE_HARDWARE - : View.LAYER_TYPE_NONE; - if (layerType != newLayerType) { - view.setLayerType(newLayerType, null); + boolean becomesFaded = !becomesInvisible && !becomesFullyVisible; + if (FadeOptimizedNotification.FADE_LAYER_OPTIMIZATION_ENABLED + && view instanceof FadeOptimizedNotification) { + // NOTE: A view that's going to utilize this interface to avoid having a hardware + // layer will have to return false from hasOverlappingRendering(), so we + // intentionally do not check that value in this if, even though we do in the else. + FadeOptimizedNotification fadeOptimizedView = (FadeOptimizedNotification) view; + boolean isFaded = fadeOptimizedView.isNotificationFaded(); + if (isFaded != becomesFaded) { + fadeOptimizedView.setNotificationFaded(becomesFaded); + } + } else { + boolean newLayerTypeIsHardware = becomesFaded && view.hasOverlappingRendering(); + int layerType = view.getLayerType(); + int newLayerType = newLayerTypeIsHardware + ? View.LAYER_TYPE_HARDWARE + : View.LAYER_TYPE_NONE; + if (layerType != newLayerType) { + view.setLayerType(newLayerType, null); + } } // apply alpha |