diff options
| author | 2023-10-30 20:32:28 +0000 | |
|---|---|---|
| committer | 2024-02-29 18:41:46 +0000 | |
| commit | 4ebf7432155bc8d704486a8e90ff9ea6b15b61a9 (patch) | |
| tree | 648e4f18ec4ab5a5bd8b7dd9228598442d64c341 | |
| parent | e437c58869fffd9a192184a2d036ab42bbb372a5 (diff) | |
Move group notification summary header view inflation to the background thread
Move the group notification summary header view inflation to the background thread
to reduce janks and improve the performance of System UI.
Bug: 217799515
Test: atest NotificationChildrenContainerTest
Flag: ACONFIG notification_async_group_header_inflation DEVELOPMENT
Change-Id: I7124e909add1efa964f6b4d6f0effdc309fc1d1d
15 files changed, 545 insertions, 39 deletions
diff --git a/core/java/android/service/notification/StatusBarNotification.java b/core/java/android/service/notification/StatusBarNotification.java index 264b53c6ee40..d8210742e331 100644 --- a/core/java/android/service/notification/StatusBarNotification.java +++ b/core/java/android/service/notification/StatusBarNotification.java @@ -174,6 +174,23 @@ public class StatusBarNotification implements Parcelable { return sbnKey; } + /** + * @return Whether the Entry is a group child by the app or system + * @hide + */ + public boolean isAppOrSystemGroupChild() { + return isGroup() && !getNotification().isGroupSummary(); + } + + + /** + * @return Whether the Entry is a group summary by the app or system + * @hide + */ + public boolean isAppOrSystemGroupSummary() { + return isGroup() && getNotification().isGroupSummary(); + } + private String groupKey() { if (overrideGroupKey != null) { return user.getIdentifier() + "|" + pkg + "|" + "g:" + overrideGroupKey; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGroupingUtil.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGroupingUtil.java index 143fc324f8c7..3cf61e211e42 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGroupingUtil.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationGroupingUtil.java @@ -34,6 +34,8 @@ import com.android.internal.widget.ConversationLayout; import com.android.internal.widget.ImageFloatingTextView; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.NotificationContentView; +import com.android.systemui.statusbar.notification.row.shared.AsyncGroupHeaderViewInflation; +import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper; import java.util.ArrayList; import java.util.HashSet; @@ -253,7 +255,8 @@ public class NotificationGroupingUtil { } public void init() { - View header = mParentRow.getNotificationViewWrapper().getNotificationHeader(); + NotificationViewWrapper wrapper = mParentRow.getNotificationViewWrapper(); + View header = wrapper == null ? null : wrapper.getNotificationHeader(); mParentView = header == null ? null : header.findViewById(mId); mParentData = mExtractor == null ? null : mExtractor.extractData(mParentRow); mApply = !mComparator.isEmpty(mParentView); @@ -326,6 +329,9 @@ public class NotificationGroupingUtil { @Override public boolean isEmpty(View view) { + if (AsyncGroupHeaderViewInflation.isEnabled() && view == null) { + return true; + } if (view instanceof ImageView) { return ((ImageView) view).getDrawable() == null; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java index 639e23ae0765..deaf1d1bc764 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/PreparationCoordinator.java @@ -363,10 +363,11 @@ public class PreparationCoordinator implements Coordinator { NotifInflater.Params getInflaterParams(NotifUiAdjustment adjustment, String reason) { return new NotifInflater.Params( - adjustment.isMinimized(), - reason, - adjustment.isSnoozeEnabled(), - adjustment.isChildInGroup() + /* isLowPriority = */ adjustment.isMinimized(), + /* reason = */ reason, + /* showSnooze = */ adjustment.isSnoozeEnabled(), + /* isChildInGroup = */ adjustment.isChildInGroup(), + /* isGroupSummary = */ adjustment.isGroupSummary() ); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifInflater.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifInflater.kt index c0b187be42f3..18460c3e3766 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifInflater.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifInflater.kt @@ -60,5 +60,6 @@ interface NotifInflater { val reason: String, val showSnooze: Boolean, val isChildInGroup: Boolean = false, + val isGroupSummary: Boolean = false, ) } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustment.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustment.kt index e1d2cdc65d5a..bab94b50018e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustment.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustment.kt @@ -20,6 +20,7 @@ import android.app.Notification import android.app.RemoteInput import android.graphics.drawable.Icon import android.text.TextUtils +import com.android.systemui.statusbar.notification.row.shared.AsyncGroupHeaderViewInflation import com.android.systemui.statusbar.notification.row.shared.AsyncHybridViewInflation /** @@ -36,6 +37,7 @@ class NotifUiAdjustment internal constructor( val isMinimized: Boolean, val needsRedaction: Boolean, val isChildInGroup: Boolean, + val isGroupSummary: Boolean, ) { companion object { @JvmStatic @@ -55,6 +57,8 @@ class NotifUiAdjustment internal constructor( // !oldAdjustment.isChildInGroup && newAdjustment.isChildInGroup -> true AsyncHybridViewInflation.isEnabled && oldAdjustment.isChildInGroup != newAdjustment.isChildInGroup -> true + AsyncGroupHeaderViewInflation.isEnabled && + !oldAdjustment.isGroupSummary && newAdjustment.isGroupSummary -> true else -> false } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProvider.kt index 6f44c13a3e71..0b9d19df3a75 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProvider.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProvider.kt @@ -123,6 +123,7 @@ class NotifUiAdjustmentProvider @Inject constructor( isSnoozeEnabled = isSnoozeSettingsEnabled && !entry.isCanceled, isMinimized = isEntryMinimized(entry), needsRedaction = lockscreenUserManager.needsRedaction(entry), - isChildInGroup = groupMembershipManager.isChildInGroup(entry), + isChildInGroup = entry.sbn.isAppOrSystemGroupChild, + isGroupSummary = entry.sbn.isAppOrSystemGroupSummary, ) } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java index 954e80505cbe..c5b55c7b1d9b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/inflation/NotificationRowBinderImpl.java @@ -21,6 +21,8 @@ import static com.android.systemui.statusbar.notification.row.NotificationRowCon import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_EXPANDED; import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_PUBLIC; import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_SINGLE_LINE; +import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_GROUP_SUMMARY_HEADER; +import static com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_LOW_PRIORITY_GROUP_SUMMARY_HEADER; import static java.util.Objects.requireNonNull; @@ -50,6 +52,7 @@ import com.android.systemui.statusbar.notification.row.RowContentBindParams; import com.android.systemui.statusbar.notification.row.RowContentBindStage; import com.android.systemui.statusbar.notification.row.RowInflaterTask; import com.android.systemui.statusbar.notification.row.dagger.ExpandableNotificationRowComponent; +import com.android.systemui.statusbar.notification.row.shared.AsyncGroupHeaderViewInflation; import com.android.systemui.statusbar.notification.row.shared.AsyncHybridViewInflation; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; @@ -271,6 +274,17 @@ public class NotificationRowBinderImpl implements NotificationRowBinder { } } + if (AsyncGroupHeaderViewInflation.isEnabled()) { + if (inflaterParams.isGroupSummary()) { + params.requireContentViews(FLAG_GROUP_SUMMARY_HEADER); + if (isLowPriority) { + params.requireContentViews(FLAG_LOW_PRIORITY_GROUP_SUMMARY_HEADER); + } + } else { + params.markContentViewsFreeable(FLAG_GROUP_SUMMARY_HEADER); + params.markContentViewsFreeable(FLAG_LOW_PRIORITY_GROUP_SUMMARY_HEADER); + } + } params.rebindAllContentViews(); mLogger.logRequestingRebind(entry, inflaterParams); mRowContentBindStage.requestRebind(entry, en -> { 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 decb244947ff..d987a278fc71 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 @@ -100,6 +100,7 @@ import com.android.systemui.statusbar.notification.collection.render.GroupMember import com.android.systemui.statusbar.notification.logging.NotificationCounters; import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier; import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag; +import com.android.systemui.statusbar.notification.row.shared.AsyncGroupHeaderViewInflation; import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper; import com.android.systemui.statusbar.notification.stack.AmbientState; import com.android.systemui.statusbar.notification.stack.AnimationProperties; @@ -586,7 +587,11 @@ public class ExpandableNotificationRow extends ActivatableNotificationView mMenuRow.setAppName(mAppName); } if (mIsSummaryWithChildren) { - mChildrenContainer.recreateNotificationHeader(mExpandClickListener, isConversation()); + if (!AsyncGroupHeaderViewInflation.isEnabled()) { + // We create the header from the background thread instead + mChildrenContainer.recreateNotificationHeader(mExpandClickListener, + isConversation()); + } mChildrenContainer.onNotificationUpdated(); } if (mAnimationRunning) { @@ -668,7 +673,9 @@ public class ExpandableNotificationRow extends ActivatableNotificationView public int getOriginalIconColor() { if (mIsSummaryWithChildren && !shouldShowPublic()) { - return mChildrenContainer.getVisibleWrapper().getOriginalIconColor(); + if (!AsyncGroupHeaderViewInflation.isEnabled()) { + return mChildrenContainer.getVisibleWrapper().getOriginalIconColor(); + } } int color = getShowingLayout().getOriginalIconColor(); if (color != Notification.COLOR_INVALID) { @@ -1513,6 +1520,40 @@ public class ExpandableNotificationRow extends ActivatableNotificationView return mChildrenContainer; } + /** + * @return An non-null instance of mChildrenContainer, inflate it if not yet. + */ + public @NonNull NotificationChildrenContainer getChildrenContainerNonNull() { + if (mChildrenContainer == null) { + mChildrenContainerStub.inflate(); + } + return mChildrenContainer; + } + + /** + * Set the group notification header view + * @param headerView header view to set + */ + public void setGroupHeader(NotificationHeaderView headerView) { + NotificationChildrenContainer childrenContainer = getChildrenContainerNonNull(); + childrenContainer.setGroupHeader( + /* headerView= */ headerView, + /* onClickListener= */ mExpandClickListener + ); + } + + /** + * Set the low-priority group notification header view + * @param headerView header view to set + */ + public void setLowPriorityGroupHeader(NotificationHeaderView headerView) { + NotificationChildrenContainer childrenContainer = getChildrenContainerNonNull(); + childrenContainer.setLowPriorityGroupHeader( + /* headerViewLowPriority= */ headerView, + /* onClickListener= */ mExpandClickListener + ); + } + public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) { boolean wasAboveShelf = isAboveShelf(); boolean changed = headsUpAnimatingAway != mHeadsupDisappearRunning; @@ -1565,7 +1606,11 @@ public class ExpandableNotificationRow extends ActivatableNotificationView @Override public View getShelfTransformationTarget() { if (mIsSummaryWithChildren && !shouldShowPublic()) { - return mChildrenContainer.getVisibleWrapper().getShelfTransformationTarget(); + NotificationViewWrapper viewWrapper = mChildrenContainer.getVisibleWrapper(); + if (AsyncGroupHeaderViewInflation.isEnabled() && viewWrapper == null) { + return null; + } + return viewWrapper.getShelfTransformationTarget(); } return getShowingLayout().getShelfTransformationTarget(); } @@ -2710,10 +2755,12 @@ public class ExpandableNotificationRow extends ActivatableNotificationView && mChildrenContainer.getNotificationChildCount() > 0; if (mIsSummaryWithChildren) { Trace.beginSection("ExpNotRow#onChildCountChanged (summary)"); - NotificationViewWrapper wrapper = mChildrenContainer.getNotificationViewWrapper(); - if (wrapper == null || wrapper.getNotificationHeader() == null) { - mChildrenContainer.recreateNotificationHeader(mExpandClickListener, - isConversation()); + if (!AsyncGroupHeaderViewInflation.isEnabled()) { + NotificationViewWrapper wrapper = mChildrenContainer.getNotificationViewWrapper(); + if (wrapper == null || wrapper.getNotificationHeader() == null) { + mChildrenContainer.recreateNotificationHeader(mExpandClickListener, + isConversation()); + } } } if (!mIsSummaryWithChildren && wasSummary) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java index e288e857bf4a..d308fa583f71 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java @@ -37,7 +37,9 @@ import android.os.Trace; import android.os.UserHandle; import android.service.notification.StatusBarNotification; import android.util.Log; +import android.view.NotificationHeaderView; import android.view.View; +import android.view.ViewGroup; import android.widget.RemoteViews; import com.android.internal.annotations.VisibleForTesting; @@ -51,11 +53,13 @@ import com.android.systemui.statusbar.NotificationRemoteInputManager; import com.android.systemui.statusbar.notification.ConversationNotificationProcessor; import com.android.systemui.statusbar.notification.InflationException; import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.notification.row.shared.AsyncGroupHeaderViewInflation; import com.android.systemui.statusbar.notification.row.shared.AsyncHybridViewInflation; import com.android.systemui.statusbar.notification.row.ui.viewbinder.SingleLineConversationViewBinder; import com.android.systemui.statusbar.notification.row.ui.viewbinder.SingleLineViewBinder; import com.android.systemui.statusbar.notification.row.ui.viewmodel.SingleLineViewModel; import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper; +import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainer; import com.android.systemui.statusbar.phone.CentralSurfaces; import com.android.systemui.statusbar.policy.InflatedSmartReplyState; import com.android.systemui.statusbar.policy.InflatedSmartReplyViewHolder; @@ -387,6 +391,21 @@ public class NotificationContentInflater implements NotificationRowContentBinder logger.logAsyncTaskProgress(entryForLogging, "creating public remote view"); result.newPublicView = builder.makePublicContentView(isLowPriority); } + + if (AsyncGroupHeaderViewInflation.isEnabled()) { + if ((reInflateFlags & FLAG_GROUP_SUMMARY_HEADER) != 0) { + logger.logAsyncTaskProgress(entryForLogging, + "creating group summary remote view"); + result.mNewGroupHeaderView = builder.makeNotificationGroupHeader(); + } + + if ((reInflateFlags & FLAG_LOW_PRIORITY_GROUP_SUMMARY_HEADER) != 0) { + logger.logAsyncTaskProgress(entryForLogging, + "creating low-priority group summary remote view"); + result.mNewLowPriorityGroupHeaderView = + builder.makeLowPriorityContentView(true /* useRegularSubtext */); + } + } setNotifsViewsInflaterFactory(result, row, notifLayoutInflaterFactoryProvider); result.packageContext = packageContext; result.headsUpStatusBarText = builder.getHeadsUpStatusBarText(false /* showingPublic */); @@ -534,6 +553,67 @@ public class NotificationContentInflater implements NotificationRowContentBinder runningInflations, applyCallback, logger); } + if (AsyncGroupHeaderViewInflation.isEnabled()) { + NotificationChildrenContainer childrenContainer = row.getChildrenContainerNonNull(); + if ((reInflateFlags & FLAG_GROUP_SUMMARY_HEADER) != 0) { + boolean isNewView = + !canReapplyRemoteView( + /* newView = */ result.mNewGroupHeaderView, + /* oldView = */ remoteViewCache + .getCachedView(entry, FLAG_GROUP_SUMMARY_HEADER)); + ApplyCallback applyCallback = new ApplyCallback() { + @Override + public void setResultView(View v) { + logger.logAsyncTaskProgress(entry, "group header view applied"); + result.mInflatedGroupHeaderView = (NotificationHeaderView) v; + } + + @Override + public RemoteViews getRemoteView() { + return result.mNewGroupHeaderView; + } + }; + logger.logAsyncTaskProgress(entry, "applying group header view"); + applyRemoteView(inflationExecutor, inflateSynchronously, result, reInflateFlags, + /* inflationId = */ FLAG_GROUP_SUMMARY_HEADER, + remoteViewCache, entry, row, isNewView, remoteViewClickHandler, callback, + /* parentLayout = */ childrenContainer, + /* existingView = */ childrenContainer.getNotificationHeader(), + /* existingWrapper = */ childrenContainer.getNotificationHeaderWrapper(), + runningInflations, applyCallback, logger); + } + + if ((reInflateFlags & FLAG_LOW_PRIORITY_GROUP_SUMMARY_HEADER) != 0) { + boolean isNewView = + !canReapplyRemoteView( + /* newView = */ result.mNewLowPriorityGroupHeaderView, + /* oldView = */ remoteViewCache.getCachedView( + entry, FLAG_LOW_PRIORITY_GROUP_SUMMARY_HEADER)); + ApplyCallback applyCallback = new ApplyCallback() { + @Override + public void setResultView(View v) { + logger.logAsyncTaskProgress(entry, + "low-priority group header view applied"); + result.mInflatedLowPriorityGroupHeaderView = (NotificationHeaderView) v; + } + + @Override + public RemoteViews getRemoteView() { + return result.mNewLowPriorityGroupHeaderView; + } + }; + logger.logAsyncTaskProgress(entry, "applying low priority group header view"); + applyRemoteView(inflationExecutor, inflateSynchronously, result, reInflateFlags, + /* inflationId = */ FLAG_LOW_PRIORITY_GROUP_SUMMARY_HEADER, + remoteViewCache, entry, row, isNewView, remoteViewClickHandler, callback, + /* parentLayout = */ childrenContainer, + /* existingView = */ childrenContainer.getNotificationHeaderLowPriority(), + /* existingWrapper = */ childrenContainer + .getLowPriorityViewWrapper(), + runningInflations, applyCallback, logger); + } + } + // Let's try to finish, maybe nobody is even inflating anything finishIfDone(result, reInflateFlags, remoteViewCache, runningInflations, callback, entry, row, logger); @@ -560,7 +640,7 @@ public class NotificationContentInflater implements NotificationRowContentBinder boolean isNewView, RemoteViews.InteractionHandler remoteViewClickHandler, @Nullable final InflationCallback callback, - NotificationContentView parentLayout, + ViewGroup parentLayout, View existingView, NotificationViewWrapper existingWrapper, final HashMap<Integer, CancellationSignal> runningInflations, @@ -702,6 +782,10 @@ public class NotificationContentInflater implements NotificationRowContentBinder return result; } + /** + * Notifications with undecorated custom views need to satisfy a minimum height to avoid visual + * issues. + */ private static boolean requiresHeightCheck(NotificationEntry entry) { // Undecorated custom views are disallowed from S onwards if (entry.targetSdk >= Build.VERSION_CODES.S) { @@ -845,6 +929,39 @@ public class NotificationContentInflater implements NotificationRowContentBinder } } + if (AsyncGroupHeaderViewInflation.isEnabled()) { + if ((reInflateFlags & FLAG_GROUP_SUMMARY_HEADER) != 0) { + if (result.mInflatedGroupHeaderView != null) { + row.setIsLowPriority(false); + row.setGroupHeader(/* headerView= */ result.mInflatedGroupHeaderView); + remoteViewCache.putCachedView(entry, FLAG_GROUP_SUMMARY_HEADER, + result.mNewGroupHeaderView); + } else if (remoteViewCache.hasCachedView(entry, FLAG_GROUP_SUMMARY_HEADER)) { + // Re-inflation case. Only update if it's still cached (i.e. view has not + // been freed while inflating). + remoteViewCache.putCachedView(entry, FLAG_GROUP_SUMMARY_HEADER, + result.mNewGroupHeaderView); + } + } + + if ((reInflateFlags & FLAG_LOW_PRIORITY_GROUP_SUMMARY_HEADER) != 0) { + if (result.mInflatedLowPriorityGroupHeaderView != null) { + // New view case, set row to low priority + row.setIsLowPriority(true); + row.setLowPriorityGroupHeader( + /* headerView= */ result.mInflatedLowPriorityGroupHeaderView); + remoteViewCache.putCachedView(entry, FLAG_LOW_PRIORITY_GROUP_SUMMARY_HEADER, + result.mNewLowPriorityGroupHeaderView); + } else if (remoteViewCache.hasCachedView(entry, + FLAG_LOW_PRIORITY_GROUP_SUMMARY_HEADER)) { + // Re-inflation case. Only update if it's still cached (i.e. view has not + // been freed while inflating). + remoteViewCache.putCachedView(entry, FLAG_LOW_PRIORITY_GROUP_SUMMARY_HEADER, + result.mNewGroupHeaderView); + } + } + } + entry.headsUpStatusBarText = result.headsUpStatusBarText; entry.headsUpStatusBarTextPublic = result.headsUpStatusBarTextPublic; if (endListener != null) { @@ -1147,6 +1264,8 @@ public class NotificationContentInflater implements NotificationRowContentBinder private RemoteViews newHeadsUpView; private RemoteViews newExpandedView; private RemoteViews newPublicView; + private RemoteViews mNewGroupHeaderView; + private RemoteViews mNewLowPriorityGroupHeaderView; @VisibleForTesting Context packageContext; @@ -1155,6 +1274,8 @@ public class NotificationContentInflater implements NotificationRowContentBinder private View inflatedHeadsUpView; private View inflatedExpandedView; private View inflatedPublicView; + private NotificationHeaderView mInflatedGroupHeaderView; + private NotificationHeaderView mInflatedLowPriorityGroupHeaderView; private CharSequence headsUpStatusBarText; private CharSequence headsUpStatusBarTextPublic; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterLogger.kt index ee9462c60674..15c705579bf7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterLogger.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflaterLogger.kt @@ -27,6 +27,8 @@ import com.android.systemui.statusbar.notification.row.NotificationRowContentBin import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_HEADS_UP import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_PUBLIC import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_SINGLE_LINE +import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_GROUP_SUMMARY_HEADER +import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_LOW_PRIORITY_GROUP_SUMMARY_HEADER import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag import javax.inject.Inject @@ -145,6 +147,12 @@ constructor(@NotifInflationLog private val buffer: LogBuffer) { if (flag and FLAG_CONTENT_VIEW_SINGLE_LINE != 0) { l.add("SINGLE_LINE") } + if (flag and FLAG_GROUP_SUMMARY_HEADER != 0) { + l.add("GROUP_SUMMARY_HEADER") + } + if (flag and FLAG_LOW_PRIORITY_GROUP_SUMMARY_HEADER != 0) { + l.add("LOW_PRIORITY_GROUP_SUMMARY_HEADER") + } return l.joinToString("|") } } 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 374248252d1f..50bc3d31aa42 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 @@ -238,7 +238,10 @@ public class NotificationContentView extends FrameLayout implements Notification mMinContractedHeight = getResources().getDimensionPixelSize( R.dimen.min_notification_layout_height); if (AsyncHybridViewInflation.isEnabled()) { - //TODO: set the height with a more reasonable min single-line height + //TODO (b/217799515): single-line view height is the greater of two heights: text view + // height and icon height (when there's an icon). icon height is fixed to be + // conversation_single_line_face_pile_size (24dp), the text view's height is 16sp, + // its pixel height changes with the system's font scaling factor. mMinSingleLineHeight = getResources().getDimensionPixelSize( R.dimen.conversation_single_line_face_pile_size); } @@ -843,7 +846,7 @@ public class NotificationContentView extends FrameLayout implements Notification if (mSingleLineView != null) { return getViewHeight(VISIBLE_TYPE_SINGLELINE); } else { - Log.wtf(TAG, "getMinHeight: mSingleLineView == null"); + //TODO(b/217799515): investigate the impact of min-height value return mMinSingleLineHeight; } } else { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinder.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinder.java index 736140c44dfd..b0fd47587782 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinder.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinder.java @@ -81,6 +81,8 @@ public interface NotificationRowContentBinder { FLAG_CONTENT_VIEW_HEADS_UP, FLAG_CONTENT_VIEW_PUBLIC, FLAG_CONTENT_VIEW_SINGLE_LINE, + FLAG_GROUP_SUMMARY_HEADER, + FLAG_LOW_PRIORITY_GROUP_SUMMARY_HEADER, FLAG_CONTENT_VIEW_ALL}) @interface InflationFlag {} /** @@ -108,7 +110,17 @@ public interface NotificationRowContentBinder { */ int FLAG_CONTENT_VIEW_SINGLE_LINE = 1 << 4; - int FLAG_CONTENT_VIEW_ALL = (1 << 5) - 1; + /** + * The notification group summary header view + */ + int FLAG_GROUP_SUMMARY_HEADER = 1 << 5; + + /** + * The notification low-priority group summary header view + */ + int FLAG_LOW_PRIORITY_GROUP_SUMMARY_HEADER = 1 << 6; + + int FLAG_CONTENT_VIEW_ALL = (1 << 7) - 1; /** * Parameters for content view binding @@ -129,6 +141,11 @@ public interface NotificationRowContentBinder { * Use increased height when binding heads up views. */ public boolean usesIncreasedHeadsUpHeight; + + /** + * Is group summary notification + */ + public boolean mIsGroupSummary; } /** 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 abf6c27c68ac..fa973001cec7 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 @@ -55,6 +55,7 @@ import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow import com.android.systemui.statusbar.notification.row.ExpandableView; import com.android.systemui.statusbar.notification.row.HybridGroupManager; import com.android.systemui.statusbar.notification.row.HybridNotificationView; +import com.android.systemui.statusbar.notification.row.shared.AsyncGroupHeaderViewInflation; import com.android.systemui.statusbar.notification.row.wrapper.NotificationHeaderViewWrapper; import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper; @@ -131,6 +132,7 @@ public class NotificationChildrenContainer extends ViewGroup private int mUntruncatedChildCount; private boolean mContainingNotificationIsFaded = false; private RoundableState mRoundableState; + private int mMinSingleLineHeight; private NotificationChildrenContainerLogger mLogger; @@ -183,6 +185,8 @@ public class NotificationChildrenContainer extends ViewGroup com.android.internal.R.dimen.notification_content_margin) - mNotificationHeaderMargin; mHybridGroupManager.initDimens(); + mMinSingleLineHeight = getResources().getDimensionPixelSize( + R.dimen.conversation_single_line_face_pile_size); } @NonNull @@ -385,16 +389,31 @@ public class NotificationChildrenContainer extends ViewGroup return mAttachedChildren.size(); } - public void recreateNotificationHeader(OnClickListener listener, boolean isConversation) { + /** + * Re-create the Notification header view + * @param listener OnClickListener of the header view + * @param isConversation if the notification group is a conversation group + */ + public void recreateNotificationHeader( + OnClickListener listener, + boolean isConversation + ) { + // We don't want to inflate headers from the main thread when async inflation enabled + AsyncGroupHeaderViewInflation.assertInLegacyMode(); + // TODO(b/217799515): remove traces from this function in a follow-up change Trace.beginSection("NotifChildCont#recreateHeader"); mHeaderClickListener = listener; mIsConversation = isConversation; StatusBarNotification notification = mContainingNotification.getEntry().getSbn(); final Notification.Builder builder = Notification.Builder.recoverBuilder(getContext(), notification.getNotification()); + Trace.beginSection("recreateHeader#makeNotificationGroupHeader"); RemoteViews header = builder.makeNotificationGroupHeader(); + Trace.endSection(); if (mNotificationHeader == null) { + Trace.beginSection("recreateHeader#apply"); mNotificationHeader = (NotificationHeaderView) header.apply(getContext(), this); + Trace.endSection(); mNotificationHeader.findViewById(com.android.internal.R.id.expand_button) .setVisibility(VISIBLE); mNotificationHeader.setOnClickListener(mHeaderClickListener); @@ -407,7 +426,9 @@ public class NotificationChildrenContainer extends ViewGroup addView(mNotificationHeader, 0); invalidate(); } else { + Trace.beginSection("recreateHeader#reapply"); header.reapply(getContext(), mNotificationHeader); + Trace.endSection(); } mNotificationHeaderWrapper.setExpanded(mChildrenExpanded); mNotificationHeaderWrapper.onContentUpdated(mContainingNotification); @@ -417,12 +438,105 @@ public class NotificationChildrenContainer extends ViewGroup Trace.endSection(); } + private void removeGroupHeader() { + if (mNotificationHeader == null) { + return; + } + removeView(mNotificationHeader); + mNotificationHeader = null; + mNotificationHeaderWrapper = null; + } + + private void removeLowPriorityGroupHeader() { + if (mNotificationHeaderLowPriority == null) { + return; + } + removeView(mNotificationHeaderLowPriority); + mNotificationHeaderLowPriority = null; + mNotificationHeaderWrapperLowPriority = null; + } + + /** + * Set the group header view + * @param headerView view to set + * @param onClickListener OnClickListener of the header view + */ + public void setGroupHeader( + NotificationHeaderView headerView, + OnClickListener onClickListener + ) { + if (AsyncGroupHeaderViewInflation.isUnexpectedlyInLegacyMode()) return; + mHeaderClickListener = onClickListener; + + removeGroupHeader(); + + if (headerView == null) { + return; + } + + mNotificationHeader = headerView; + mNotificationHeader.findViewById(com.android.internal.R.id.expand_button) + .setVisibility(VISIBLE); + mNotificationHeader.setOnClickListener(mHeaderClickListener); + mNotificationHeaderWrapper = + (NotificationHeaderViewWrapper) NotificationViewWrapper.wrap( + getContext(), + mNotificationHeader, + mContainingNotification); + mNotificationHeaderWrapper.setOnRoundnessChangedListener(this::invalidate); + addView(mNotificationHeader, 0); + invalidate(); + + mNotificationHeaderWrapper.setExpanded(mChildrenExpanded); + mNotificationHeaderWrapper.onContentUpdated(mContainingNotification); + + updateHeaderVisibility(false /* animate */); + updateChildrenAppearance(); + + Trace.endSection(); + } + + /** + * Set the low-priority group header view + * @param headerViewLowPriority header view to set + * @param onClickListener OnClickListener of the header view + */ + public void setLowPriorityGroupHeader( + NotificationHeaderView headerViewLowPriority, + OnClickListener onClickListener + ) { + if (AsyncGroupHeaderViewInflation.isUnexpectedlyInLegacyMode()) return; + removeLowPriorityGroupHeader(); + if (headerViewLowPriority == null) { + return; + } + + mNotificationHeaderLowPriority = headerViewLowPriority; + mNotificationHeaderLowPriority.findViewById(com.android.internal.R.id.expand_button) + .setVisibility(VISIBLE); + mNotificationHeaderLowPriority.setOnClickListener(onClickListener); + mNotificationHeaderWrapperLowPriority = + (NotificationHeaderViewWrapper) NotificationViewWrapper.wrap( + getContext(), + mNotificationHeaderLowPriority, + mContainingNotification); + mNotificationHeaderWrapperLowPriority.setOnRoundnessChangedListener(this::invalidate); + addView(mNotificationHeaderLowPriority, 0); + invalidate(); + + mNotificationHeaderWrapperLowPriority.onContentUpdated(mContainingNotification); + updateHeaderVisibility(false /* animate */); + updateChildrenAppearance(); + } + /** * Recreate the low-priority header. * * @param builder a builder to reuse. Otherwise the builder will be recovered. */ - private void recreateLowPriorityHeader(Notification.Builder builder, boolean isConversation) { + @VisibleForTesting + void recreateLowPriorityHeader(Notification.Builder builder, boolean isConversation) { + AsyncGroupHeaderViewInflation.assertInLegacyMode(); RemoteViews header; StatusBarNotification notification = mContainingNotification.getEntry().getSbn(); if (mIsLowPriority) { @@ -527,8 +641,10 @@ public class NotificationChildrenContainer extends ViewGroup * @param alpha alpha value to apply to the content */ public void setContentAlpha(float alpha) { - for (int i = 0; i < mNotificationHeader.getChildCount(); i++) { - mNotificationHeader.getChildAt(i).setAlpha(alpha); + if (mNotificationHeader != null) { + for (int i = 0; i < mNotificationHeader.getChildCount(); i++) { + mNotificationHeader.getChildAt(i).setAlpha(alpha); + } } for (ExpandableNotificationRow child : getAttachedChildren()) { child.setContentAlpha(alpha); @@ -564,7 +680,11 @@ public class NotificationChildrenContainer extends ViewGroup */ private int getIntrinsicHeight(float maxAllowedVisibleChildren) { if (showingAsLowPriority()) { - return mNotificationHeaderLowPriority.getHeight(); + if (AsyncGroupHeaderViewInflation.isEnabled()) { + return mHeaderHeight; + } else { + return mNotificationHeaderLowPriority.getHeight(); + } } int intrinsicHeight = mNotificationHeaderMargin + mCurrentHeaderTranslation; int visibleChildren = 0; @@ -1023,6 +1143,14 @@ public class NotificationChildrenContainer extends ViewGroup return mCurrentHeader; } + public NotificationHeaderView getNotificationHeader() { + return mNotificationHeader; + } + + public NotificationHeaderView getNotificationHeaderLowPriority() { + return mNotificationHeaderLowPriority; + } + private void updateHeaderVisibility(boolean animate) { ViewGroup desiredHeader; ViewGroup currentHeader = mCurrentHeader; @@ -1032,6 +1160,10 @@ public class NotificationChildrenContainer extends ViewGroup return; } + if (AsyncGroupHeaderViewInflation.isEnabled() && desiredHeader == null) { + return; + } + if (animate) { if (desiredHeader != null && currentHeader != null) { currentHeader.setVisibility(VISIBLE); @@ -1271,6 +1403,9 @@ public class NotificationChildrenContainer extends ViewGroup boolean likeHighPriority, int headerTranslation) { if (!likeHighPriority && showingAsLowPriority()) { + if (AsyncGroupHeaderViewInflation.isEnabled()) { + return mHeaderHeight; + } if (mNotificationHeaderLowPriority == null) { Log.e(TAG, "getMinHeight: low priority header is null", new Exception()); return 0; @@ -1295,8 +1430,12 @@ public class NotificationChildrenContainer extends ViewGroup if (singleLineView != null) { minExpandHeight += singleLineView.getHeight(); } else { - Log.e(TAG, "getMinHeight: child " + child.getEntry().getKey() - + " single line view is null", new Exception()); + if (AsyncGroupHeaderViewInflation.isEnabled()) { + minExpandHeight += mMinSingleLineHeight; + } else { + Log.e(TAG, "getMinHeight: child " + child.getEntry().getKey() + + " single line view is null", new Exception()); + } } visibleChildren++; } @@ -1309,15 +1448,19 @@ public class NotificationChildrenContainer extends ViewGroup } public void reInflateViews(OnClickListener listener, StatusBarNotification notification) { - if (mNotificationHeader != null) { - removeView(mNotificationHeader); - mNotificationHeader = null; - } - if (mNotificationHeaderLowPriority != null) { - removeView(mNotificationHeaderLowPriority); - mNotificationHeaderLowPriority = null; + if (!AsyncGroupHeaderViewInflation.isEnabled()) { + // When Async header inflation is enabled, we do not reinflate headers because they are + // inflated from the background thread + if (mNotificationHeader != null) { + removeView(mNotificationHeader); + mNotificationHeader = null; + } + if (mNotificationHeaderLowPriority != null) { + removeView(mNotificationHeaderLowPriority); + mNotificationHeaderLowPriority = null; + } + recreateNotificationHeader(listener, mIsConversation); } - recreateNotificationHeader(listener, mIsConversation); initDimens(); for (int i = 0; i < mDividers.size(); i++) { View prevDivider = mDividers.get(i); @@ -1395,7 +1538,9 @@ public class NotificationChildrenContainer extends ViewGroup public void setIsLowPriority(boolean isLowPriority) { mIsLowPriority = isLowPriority; if (mContainingNotification != null) { /* we're not yet set up yet otherwise */ - recreateLowPriorityHeader(null /* existingBuilder */, mIsConversation); + if (!AsyncGroupHeaderViewInflation.isEnabled()) { + recreateLowPriorityHeader(null /* existingBuilder */, mIsConversation); + } updateHeaderVisibility(false /* animate */); } if (mUserLocked) { diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProviderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProviderTest.kt index 73c49c023dd5..115a0d367e87 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProviderTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/inflation/NotifUiAdjustmentProviderTest.kt @@ -31,6 +31,7 @@ import com.android.systemui.statusbar.notification.collection.NotificationEntryB import com.android.systemui.statusbar.notification.collection.listbuilder.NotifSection import com.android.systemui.statusbar.notification.collection.provider.SectionStyleProvider import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager +import com.android.systemui.statusbar.notification.row.shared.AsyncGroupHeaderViewInflation import com.android.systemui.statusbar.notification.row.shared.AsyncHybridViewInflation import com.android.systemui.util.mockito.any import com.android.systemui.util.mockito.eq @@ -46,6 +47,7 @@ import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mockito.clearInvocations import org.mockito.Mockito.inOrder +import org.mockito.Mockito.spy import org.mockito.Mockito.verify import org.mockito.Mockito.verifyNoMoreInteractions import org.mockito.Mockito.`when` as whenever @@ -141,12 +143,14 @@ class NotifUiAdjustmentProviderTest : SysuiTestCase() { fun changeIsChildInGroup_asyncHybirdFlagEnabled_needReInflation() { // Given: an Entry that is not child in group // AsyncHybridViewInflation flag is enabled - whenever(groupMembershipManager.isChildInGroup(entry)).thenReturn(false) + val spySbn = spy(entry.sbn) + entry.sbn = spySbn + whenever(spySbn.isAppOrSystemGroupChild).thenReturn(false) val oldAdjustment = adjustmentProvider.calculateAdjustment(entry) assertThat(oldAdjustment.isChildInGroup).isFalse() // When: the Entry becomes a group child - whenever(groupMembershipManager.isChildInGroup(entry)).thenReturn(true) + whenever(spySbn.isAppOrSystemGroupChild).thenReturn(true) val newAdjustment = adjustmentProvider.calculateAdjustment(entry) assertThat(newAdjustment.isChildInGroup).isTrue() assertThat(newAdjustment).isNotEqualTo(oldAdjustment) @@ -160,12 +164,14 @@ class NotifUiAdjustmentProviderTest : SysuiTestCase() { fun changeIsChildInGroup_asyncHybirdFlagDisabled_noNeedForReInflation() { // Given: an Entry that is not child in group // AsyncHybridViewInflation flag is disabled - whenever(groupMembershipManager.isChildInGroup(entry)).thenReturn(false) + val spySbn = spy(entry.sbn) + entry.sbn = spySbn + whenever(spySbn.isAppOrSystemGroupChild).thenReturn(false) val oldAdjustment = adjustmentProvider.calculateAdjustment(entry) assertThat(oldAdjustment.isChildInGroup).isFalse() // When: the Entry becomes a group child - whenever(groupMembershipManager.isChildInGroup(entry)).thenReturn(true) + whenever(spySbn.isAppOrSystemGroupChild).thenReturn(true) val newAdjustment = adjustmentProvider.calculateAdjustment(entry) assertThat(newAdjustment.isChildInGroup).isTrue() assertThat(newAdjustment).isNotEqualTo(oldAdjustment) @@ -173,4 +179,24 @@ class NotifUiAdjustmentProviderTest : SysuiTestCase() { // Then: need no re-inflation assertFalse(NotifUiAdjustment.needReinflate(oldAdjustment, newAdjustment)) } + + @Test + @EnableFlags(AsyncGroupHeaderViewInflation.FLAG_NAME) + fun changeIsGroupSummary_needReInflation() { + // Given: an Entry that is not a group summary + val spySbn = spy(entry.sbn) + entry.sbn = spySbn + whenever(spySbn.isAppOrSystemGroupSummary).thenReturn(false) + val oldAdjustment = adjustmentProvider.calculateAdjustment(entry) + assertThat(oldAdjustment.isGroupSummary).isFalse() + + // When: the Entry becomes a group summary + whenever(spySbn.isAppOrSystemGroupSummary).thenReturn(true) + val newAdjustment = adjustmentProvider.calculateAdjustment(entry) + assertThat(newAdjustment.isGroupSummary).isTrue() + assertThat(newAdjustment).isNotEqualTo(oldAdjustment) + + // Then: Need re-inflation + assertTrue(NotifUiAdjustment.needReinflate(oldAdjustment, newAdjustment)) + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerTest.java index be976a1c9eaf..1f38a73020b2 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerTest.java @@ -16,11 +16,17 @@ package com.android.systemui.statusbar.notification.stack; +import static org.junit.Assert.assertNull; + +import android.app.Notification; +import android.platform.test.annotations.DisableFlags; +import android.platform.test.annotations.EnableFlags; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.testing.TestableLooper.RunWithLooper; import android.view.NotificationHeaderView; import android.view.View; +import android.widget.RemoteViews; import androidx.test.filters.SmallTest; @@ -28,6 +34,7 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.statusbar.notification.SourceType; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.NotificationTestHelper; +import com.android.systemui.statusbar.notification.row.shared.AsyncGroupHeaderViewInflation; import com.android.systemui.statusbar.notification.row.wrapper.NotificationHeaderViewWrapper; import org.junit.Assert; @@ -40,6 +47,7 @@ import java.util.List; @SmallTest @RunWith(AndroidTestingRunner.class) @RunWithLooper +//@DisableFlags(AsyncGroupHeaderViewInflation.FLAG_NAME) public class NotificationChildrenContainerTest extends SysuiTestCase { private ExpandableNotificationRow mGroup; @@ -138,6 +146,7 @@ public class NotificationChildrenContainerTest extends SysuiTestCase { } @Test + @DisableFlags(AsyncGroupHeaderViewInflation.FLAG_NAME) public void testLowPriorityHeaderCleared() { mGroup.setIsLowPriority(true); NotificationHeaderView lowPriorityHeaderView = @@ -145,11 +154,12 @@ public class NotificationChildrenContainerTest extends SysuiTestCase { Assert.assertEquals(View.VISIBLE, lowPriorityHeaderView.getVisibility()); Assert.assertSame(mChildrenContainer, lowPriorityHeaderView.getParent()); mGroup.setIsLowPriority(false); - Assert.assertNull(lowPriorityHeaderView.getParent()); - Assert.assertNull(mChildrenContainer.getLowPriorityViewWrapper()); + assertNull(lowPriorityHeaderView.getParent()); + assertNull(mChildrenContainer.getLowPriorityViewWrapper()); } @Test + @DisableFlags(AsyncGroupHeaderViewInflation.FLAG_NAME) public void testRecreateNotificationHeader_hasHeader() { mChildrenContainer.recreateNotificationHeader(null, false); Assert.assertNotNull("Children container must have a header after recreation", @@ -157,6 +167,76 @@ public class NotificationChildrenContainerTest extends SysuiTestCase { } @Test + @EnableFlags(AsyncGroupHeaderViewInflation.FLAG_NAME) + public void testSetLowPriorityWithAsyncInflation_noHeaderReInflation() { + mChildrenContainer.setIsLowPriority(true); + assertNull("We don't inflate header from the main thread with Async " + + "Inflation enabled", mChildrenContainer.getCurrentHeaderView()); + } + + @Test + @EnableFlags(AsyncGroupHeaderViewInflation.FLAG_NAME) + public void setLowPriorityBeforeLowPriorityHeaderSet() { + + //Given: the children container does not have a low-priority header, and is not low-priority + assertNull(mChildrenContainer.getLowPriorityViewWrapper()); + mGroup.setIsLowPriority(false); + + //When: set the children container to be low-priority and set the low-priority header + mGroup.setIsLowPriority(true); + mGroup.setLowPriorityGroupHeader(createHeaderView(/* lowPriorityHeader= */ true)); + + //Then: the low-priority group header should be visible + NotificationHeaderView lowPriorityHeaderView = + mChildrenContainer.getLowPriorityViewWrapper().getNotificationHeader(); + Assert.assertEquals(View.VISIBLE, lowPriorityHeaderView.getVisibility()); + Assert.assertSame(mChildrenContainer, lowPriorityHeaderView.getParent()); + + //When: set the children container to be not low-priority and set the normal header + mGroup.setIsLowPriority(false); + mGroup.setGroupHeader(createHeaderView(/* lowPriorityHeader= */ false)); + + //Then: the low-priority group header should not be visible , normal header should be + // visible + Assert.assertEquals(View.INVISIBLE, lowPriorityHeaderView.getVisibility()); + Assert.assertEquals( + View.VISIBLE, + mChildrenContainer.getNotificationHeaderWrapper().getNotificationHeader() + .getVisibility() + ); + } + + @Test + @EnableFlags(AsyncGroupHeaderViewInflation.FLAG_NAME) + public void changeLowPriorityAfterHeaderSet() { + + //Given: the children container does not have headers, and is not low-priority + assertNull(mChildrenContainer.getLowPriorityViewWrapper()); + assertNull(mChildrenContainer.getNotificationHeaderWrapper()); + mGroup.setIsLowPriority(false); + + //When: set the set the normal header + mGroup.setGroupHeader(createHeaderView(/* lowPriorityHeader= */ false)); + + //Then: the group header should be visible + NotificationHeaderView headerView = + mChildrenContainer.getNotificationHeaderWrapper().getNotificationHeader(); + Assert.assertEquals(View.VISIBLE, headerView.getVisibility()); + Assert.assertSame(mChildrenContainer, headerView.getParent()); + + //When: set the set the row to be low priority, and set the low-priority header + mGroup.setIsLowPriority(true); + mGroup.setLowPriorityGroupHeader(createHeaderView(/* lowPriorityHeader= */ true)); + + //Then: the header view should not be visible, the low-priority group header should be + // visible + Assert.assertEquals(View.INVISIBLE, headerView.getVisibility()); + NotificationHeaderView lowPriorityHeaderView = + mChildrenContainer.getLowPriorityViewWrapper().getNotificationHeader(); + Assert.assertEquals(View.VISIBLE, lowPriorityHeaderView.getVisibility()); + } + + @Test public void applyRoundnessAndInvalidate_should_be_immediately_applied_on_last_child() { List<ExpandableNotificationRow> children = mChildrenContainer.getAttachedChildren(); ExpandableNotificationRow notificationRow = children.get(children.size() - 1); @@ -170,6 +250,7 @@ public class NotificationChildrenContainerTest extends SysuiTestCase { } @Test + @DisableFlags(AsyncGroupHeaderViewInflation.FLAG_NAME) public void applyRoundnessAndInvalidate_should_be_immediately_applied_on_header() { NotificationHeaderViewWrapper header = mChildrenContainer.getNotificationHeaderWrapper(); Assert.assertEquals(0f, header.getTopRoundness(), 0.001f); @@ -180,6 +261,7 @@ public class NotificationChildrenContainerTest extends SysuiTestCase { } @Test + @DisableFlags(AsyncGroupHeaderViewInflation.FLAG_NAME) public void applyRoundnessAndInvalidate_should_be_immediately_applied_on_headerLowPriority() { mChildrenContainer.setIsLowPriority(true); @@ -190,4 +272,17 @@ public class NotificationChildrenContainerTest extends SysuiTestCase { Assert.assertEquals(1f, header.getTopRoundness(), 0.001f); } + + private NotificationHeaderView createHeaderView(boolean lowPriority) { + Notification notification = mNotificationTestHelper.createNotification(); + final Notification.Builder builder = Notification.Builder.recoverBuilder(getContext(), + notification); + RemoteViews headerRemoteViews; + if (lowPriority) { + headerRemoteViews = builder.makeLowPriorityContentView(true); + } else { + headerRemoteViews = builder.makeNotificationGroupHeader(); + } + return (NotificationHeaderView) headerRemoteViews.apply(getContext(), mChildrenContainer); + } } |