diff options
22 files changed, 379 insertions, 378 deletions
diff --git a/packages/SystemUI/res/layout/people_strip.xml b/packages/SystemUI/res/layout/people_strip.xml index 982aa8ef6d16..c2dbacaa64f7 100644 --- a/packages/SystemUI/res/layout/people_strip.xml +++ b/packages/SystemUI/res/layout/people_strip.xml @@ -19,39 +19,34 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="@dimen/notification_section_header_height" + android:paddingStart="4dp" + android:paddingEnd="4dp" android:focusable="true" android:clickable="true" > - <com.android.systemui.statusbar.notification.row.NotificationBackgroundView - android:id="@+id/backgroundNormal" - android:layout_width="match_parent" - android:layout_height="match_parent" /> - - <com.android.systemui.statusbar.notification.row.NotificationBackgroundView - android:id="@+id/backgroundDimmed" - android:layout_width="match_parent" - android:layout_height="match_parent" /> - <LinearLayout android:id="@+id/people_list" android:layout_width="match_parent" android:layout_height="match_parent" - android:gravity="center" + android:layout_marginEnd="8dp" + android:gravity="bottom" android:orientation="horizontal"> - <TextView + <FrameLayout android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_weight="1" - android:layout_marginStart="@dimen/notification_section_header_padding_left" - android:gravity="start" - android:textAlignment="gravity" - android:text="@string/notification_section_header_conversations" - android:textSize="12sp" - android:textColor="@color/notification_section_header_label_color" - android:fontFamily="@*android:string/config_headlineFontFamilyMedium" - /> + android:gravity="start|center_vertical" + android:layout_weight="1"> + + <TextView + style="@style/TextAppearance.NotificationSectionHeaderButton" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/notification_section_header_conversations" + /> + + </FrameLayout> <ImageView android:layout_width="48dp" @@ -84,16 +79,10 @@ <ImageView android:layout_width="48dp" android:layout_height="48dp" - android:layout_marginEnd="8dp" android:padding="8dp" android:scaleType="fitCenter" /> </LinearLayout> - <com.android.systemui.statusbar.notification.FakeShadowView - android:id="@+id/fake_shadow" - android:layout_width="match_parent" - android:layout_height="match_parent" /> - </com.android.systemui.statusbar.notification.stack.PeopleHubView> diff --git a/packages/SystemUI/res/layout/status_bar_notification_footer.xml b/packages/SystemUI/res/layout/status_bar_notification_footer.xml index 174a3b8e004b..36ba66af5729 100644 --- a/packages/SystemUI/res/layout/status_bar_notification_footer.xml +++ b/packages/SystemUI/res/layout/status_bar_notification_footer.xml @@ -25,9 +25,9 @@ <com.android.systemui.statusbar.AlphaOptimizedFrameLayout android:id="@+id/content" android:layout_width="match_parent" - android:layout_height="wrap_content" > + android:layout_height="wrap_content"> <com.android.systemui.statusbar.notification.row.FooterViewButton - style="@android:style/Widget.Material.Button.Borderless" + style="@style/TextAppearance.NotificationSectionHeaderButton" android:id="@+id/manage_text" android:layout_width="wrap_content" android:layout_height="wrap_content" @@ -35,10 +35,9 @@ android:focusable="true" android:contentDescription="@string/accessibility_manage_notification" android:text="@string/manage_notifications_text" - android:textColor="?attr/wallpaperTextColor" - android:textAllCaps="false"/> + /> <com.android.systemui.statusbar.notification.row.FooterViewButton - style="@android:style/Widget.Material.Button.Borderless" + style="@style/TextAppearance.NotificationSectionHeaderButton" android:id="@+id/dismiss_text" android:layout_width="wrap_content" android:layout_height="wrap_content" @@ -46,6 +45,6 @@ android:focusable="true" android:contentDescription="@string/accessibility_clear_all" android:text="@string/clear_all_notifications_text" - android:textColor="?attr/wallpaperTextColor"/> + /> </com.android.systemui.statusbar.AlphaOptimizedFrameLayout> </com.android.systemui.statusbar.notification.row.FooterView> diff --git a/packages/SystemUI/res/layout/status_bar_notification_section_header.xml b/packages/SystemUI/res/layout/status_bar_notification_section_header.xml index 508619a27e81..0043d7a7bdad 100644 --- a/packages/SystemUI/res/layout/status_bar_notification_section_header.xml +++ b/packages/SystemUI/res/layout/status_bar_notification_section_header.xml @@ -19,32 +19,21 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="@dimen/notification_section_header_height" + android:paddingStart="4dp" + android:paddingEnd="4dp" android:focusable="true" android:clickable="true" > - <com.android.systemui.statusbar.notification.row.NotificationBackgroundView - android:id="@+id/backgroundNormal" - android:layout_width="match_parent" - android:layout_height="match_parent" /> - <com.android.systemui.statusbar.notification.row.NotificationBackgroundView - android:id="@+id/backgroundDimmed" - android:layout_width="match_parent" - android:layout_height="match_parent" /> - <LinearLayout android:id="@+id/content" android:layout_width="match_parent" - android:layout_height="match_parent" + android:layout_height="wrap_content" + android:layout_gravity="bottom" android:gravity="center_vertical" android:orientation="horizontal" > <include layout="@layout/status_bar_notification_section_header_contents"/> </LinearLayout> - <com.android.systemui.statusbar.notification.FakeShadowView - android:id="@+id/fake_shadow" - android:layout_width="match_parent" - android:layout_height="match_parent" /> - </com.android.systemui.statusbar.notification.stack.SectionHeaderView> diff --git a/packages/SystemUI/res/layout/status_bar_notification_section_header_contents.xml b/packages/SystemUI/res/layout/status_bar_notification_section_header_contents.xml index feabd1c72a65..df4b0471c78b 100644 --- a/packages/SystemUI/res/layout/status_bar_notification_section_header_contents.xml +++ b/packages/SystemUI/res/layout/status_bar_notification_section_header_contents.xml @@ -16,26 +16,30 @@ <!-- Used by both status_bar_notification_header and SectionHeaderView --> <merge xmlns:android="http://schemas.android.com/apk/res/android" > - <TextView - android:id="@+id/header_label" + <FrameLayout android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_weight="1" - android:layout_marginStart="@dimen/notification_section_header_padding_left" - android:gravity="start" - android:textAlignment="gravity" - android:text="@string/notification_section_header_gentle" - android:textSize="12sp" - android:textColor="@color/notification_section_header_label_color" - android:fontFamily="@*android:string/config_headlineFontFamilyMedium" - /> + android:gravity="start|center_vertical" + android:layout_weight="1"> + + <TextView + style="@style/TextAppearance.NotificationSectionHeaderButton" + android:id="@+id/header_label" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:text="@string/notification_section_header_gentle" + /> + + </FrameLayout> <ImageView android:id="@+id/btn_clear_all" - android:layout_width="@dimen/notification_section_header_height" - android:layout_height="@dimen/notification_section_header_height" - android:layout_marginEnd="4dp" + android:layout_width="48dp" + android:layout_height="48dp" android:src="@drawable/status_bar_notification_section_header_clear_btn" android:contentDescription="@string/accessibility_notification_section_header_gentle_clear_all" android:scaleType="center" + android:tint="?attr/wallpaperTextColor" + android:tintMode="src_in" + android:visibility="gone" /> </merge> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 15575a49bb5e..f9b0666c695f 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -744,7 +744,7 @@ <!-- The top padding of the clear all button --> <dimen name="clear_all_padding_top">12dp</dimen> - <dimen name="notification_section_header_height">48dp</dimen> + <dimen name="notification_section_header_height">56dp</dimen> <dimen name="notification_section_header_padding_left">16dp</dimen> <!-- Largest size an avatar might need to be drawn in the user picker, status bar, or diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 5e9feff566e5..89d500281e90 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -1204,6 +1204,9 @@ <!-- Section title for notifications that do not vibrate or make noise. [CHAR LIMIT=40] --> <string name="notification_section_header_gentle">Silent notifications</string> + <!-- Section title for notifications that vibrate or make noise. [CHAR LIMIT=40] --> + <string name="notification_section_header_alerting">Alerting notifications</string> + <!-- Section title for conversational notifications. [CHAR LIMIT=40] --> <string name="notification_section_header_conversations">Conversations</string> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index 557e2d65202b..36c4526fb521 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -554,6 +554,14 @@ <item name="android:gravity">center</item> </style> + <style + name="TextAppearance.NotificationSectionHeaderButton" + parent="@android:style/Widget.Material.Button.Borderless"> + <item name="android:textColor">?attr/wallpaperTextColor</item> + <item name="android:textAllCaps">false</item> + <item name="android:textSize">16sp</item> + </style> + <style name="TextAppearance.HeadsUpStatusBarText" parent="@*android:style/TextAppearance.DeviceDefault.Notification.Info"> </style> @@ -661,5 +669,5 @@ <item name="android:textSize">12sp</item> <item name="android:textColor">@color/control_secondary_text</item> </style> - + </resources> diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManager.kt index 009551168010..48386dce5d3f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManager.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManager.kt @@ -22,6 +22,7 @@ import android.provider.DeviceConfig import com.android.internal.annotations.VisibleForTesting import com.android.internal.config.sysui.SystemUiDeviceConfigFlags.NOTIFICATIONS_USE_PEOPLE_FILTERING import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING +import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_HEADS_UP import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_PEOPLE import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_SILENT import com.android.systemui.util.DeviceConfigProxy @@ -45,7 +46,7 @@ class NotificationSectionsFeatureManager @Inject constructor( fun getNotificationBuckets(): IntArray { return when { isFilteringEnabled() -> - intArrayOf(BUCKET_PEOPLE, BUCKET_ALERTING, BUCKET_SILENT) + intArrayOf(BUCKET_HEADS_UP, BUCKET_PEOPLE, BUCKET_ALERTING, BUCKET_SILENT) NotificationUtils.useNewInterruptionModel(context) -> intArrayOf(BUCKET_ALERTING, BUCKET_SILENT) else -> diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt index e612c07ac18a..9c942a52b966 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManager.kt @@ -28,6 +28,7 @@ import com.android.systemui.statusbar.notification.NotificationSectionsFeatureMa import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING +import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_HEADS_UP import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_PEOPLE import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_SILENT import com.android.systemui.statusbar.phone.NotificationGroupManager @@ -90,12 +91,12 @@ open class NotificationRankingManager @Inject constructor( val bIsHighPriority = b.isHighPriority() when { - usePeopleFiltering && aIsPeople != bIsPeople -> if (aIsPeople) -1 else 1 - usePeopleFiltering && aIsImportantPeople != bIsImportantPeople -> - if (aIsImportantPeople) -1 else 1 aHeadsUp != bHeadsUp -> if (aHeadsUp) -1 else 1 // Provide consistent ranking with headsUpManager aHeadsUp -> headsUpManager.compare(a, b) + usePeopleFiltering && aIsPeople != bIsPeople -> if (aIsPeople) -1 else 1 + usePeopleFiltering && aIsImportantPeople != bIsImportantPeople -> + if (aIsImportantPeople) -1 else 1 // Upsort current media notification. aMedia != bMedia -> if (aMedia) -1 else 1 // Upsort PRIORITY_MAX system notifications @@ -162,7 +163,9 @@ open class NotificationRankingManager @Inject constructor( isMedia: Boolean, isSystemMax: Boolean ) { - if (usePeopleFiltering && entry.isPeopleNotification()) { + if (usePeopleFiltering && isHeadsUp) { + entry.bucket = BUCKET_HEADS_UP + } else if (usePeopleFiltering && entry.isPeopleNotification()) { entry.bucket = BUCKET_PEOPLE } else if (isHeadsUp || isMedia || isSystemMax || entry.isHighPriority()) { entry.bucket = BUCKET_ALERTING diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubModule.kt index efcef7124035..16574abab7aa 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubModule.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubModule.kt @@ -24,8 +24,8 @@ abstract class PeopleHubModule { @Binds abstract fun peopleHubSectionFooterViewAdapter( - impl: PeopleHubSectionFooterViewAdapterImpl - ): PeopleHubSectionFooterViewAdapter + impl: PeopleHubViewAdapterImpl + ): PeopleHubViewAdapter @Binds abstract fun peopleHubDataSource(impl: PeopleHubDataSourceImpl): DataSource<PeopleHubModel> diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubViewController.kt index ec1d6deb1b8f..e28d03fc8b42 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubViewController.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/people/PeopleHubViewController.kt @@ -25,17 +25,16 @@ import android.provider.Settings import android.view.View import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.plugins.ActivityStarter -import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager import javax.inject.Inject import javax.inject.Singleton /** Boundary between the View and PeopleHub, as seen by the View. */ -interface PeopleHubSectionFooterViewAdapter { - fun bindView(viewBoundary: PeopleHubSectionFooterViewBoundary) +interface PeopleHubViewAdapter { + fun bindView(viewBoundary: PeopleHubViewBoundary): Subscription } -/** Abstract `View` representation of PeopleHub footer in [NotificationSectionsManager]. */ -interface PeopleHubSectionFooterViewBoundary { +/** Abstract `View` representation of PeopleHub. */ +interface PeopleHubViewBoundary { /** View used for animating the activity launch caused by clicking a person in the hub. */ val associatedViewForClickAnimation: View @@ -57,23 +56,22 @@ interface PeopleHubViewModelFactory { } /** - * Wraps a [PeopleHubSectionFooterViewBoundary] in a [DataListener], and connects it to the data + * Wraps a [PeopleHubViewBoundary] in a [DataListener], and connects it to the data * pipeline. * * @param dataSource PeopleHub data pipeline. */ @Singleton -class PeopleHubSectionFooterViewAdapterImpl @Inject constructor( +class PeopleHubViewAdapterImpl @Inject constructor( private val dataSource: DataSource<@JvmSuppressWildcards PeopleHubViewModelFactory> -) : PeopleHubSectionFooterViewAdapter { +) : PeopleHubViewAdapter { - override fun bindView(viewBoundary: PeopleHubSectionFooterViewBoundary) { - dataSource.registerListener(PeopleHubDataListenerImpl(viewBoundary)) - } + override fun bindView(viewBoundary: PeopleHubViewBoundary): Subscription = + dataSource.registerListener(PeopleHubDataListenerImpl(viewBoundary)) } private class PeopleHubDataListenerImpl( - private val viewBoundary: PeopleHubSectionFooterViewBoundary + private val viewBoundary: PeopleHubViewBoundary ) : DataListener<PeopleHubViewModelFactory> { override fun onDataChanged(data: PeopleHubViewModelFactory) { @@ -92,7 +90,7 @@ private class PeopleHubDataListenerImpl( * Converts [PeopleHubModel]s into [PeopleHubViewModelFactory]s. * * This class serves as the glue between the View layer (which depends on - * [PeopleHubSectionFooterViewBoundary]) and the Data layer (which produces [PeopleHubModel]s). + * [PeopleHubViewBoundary]) and the Data layer (which produces [PeopleHubModel]s). */ @Singleton class PeopleHubViewModelFactoryDataSourceImpl @Inject constructor( diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java index a0fef0068b05..e79d89f3a45c 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableView.java @@ -67,29 +67,34 @@ public abstract class ExpandableView extends FrameLayout implements Dumpable { @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - final int givenSize = MeasureSpec.getSize(heightMeasureSpec); + final int givenHeight = MeasureSpec.getSize(heightMeasureSpec); final int viewHorizontalPadding = getPaddingStart() + getPaddingEnd(); + + // Max height is as large as possible, unless otherwise requested int ownMaxHeight = Integer.MAX_VALUE; int heightMode = MeasureSpec.getMode(heightMeasureSpec); - if (heightMode != MeasureSpec.UNSPECIFIED && givenSize != 0) { - ownMaxHeight = Math.min(givenSize, ownMaxHeight); + if (heightMode != MeasureSpec.UNSPECIFIED && givenHeight != 0) { + // Set our max height to what was requested from the parent + ownMaxHeight = Math.min(givenHeight, ownMaxHeight); } - int newHeightSpec = MeasureSpec.makeMeasureSpec(ownMaxHeight, MeasureSpec.AT_MOST); + + // height of the largest child int maxChildHeight = 0; + int atMostOwnMaxHeightSpec = MeasureSpec.makeMeasureSpec(ownMaxHeight, MeasureSpec.AT_MOST); int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { View child = getChildAt(i); if (child.getVisibility() == GONE) { continue; } - int childHeightSpec = newHeightSpec; + int childHeightSpec = atMostOwnMaxHeightSpec; ViewGroup.LayoutParams layoutParams = child.getLayoutParams(); if (layoutParams.height != ViewGroup.LayoutParams.MATCH_PARENT) { if (layoutParams.height >= 0) { - // An actual height is set - childHeightSpec = layoutParams.height > ownMaxHeight - ? MeasureSpec.makeMeasureSpec(ownMaxHeight, MeasureSpec.EXACTLY) - : MeasureSpec.makeMeasureSpec(layoutParams.height, MeasureSpec.EXACTLY); + // If an actual height is set, cap it to the max height + childHeightSpec = MeasureSpec.makeMeasureSpec( + Math.min(layoutParams.height, ownMaxHeight), + MeasureSpec.EXACTLY); } child.measure(getChildMeasureSpec( widthMeasureSpec, viewHorizontalPadding, layoutParams.width), @@ -100,15 +105,22 @@ public abstract class ExpandableView extends FrameLayout implements Dumpable { mMatchParentViews.add(child); } } + + // Set our own height to the given height, or the height of the largest child int ownHeight = heightMode == MeasureSpec.EXACTLY - ? givenSize : Math.min(ownMaxHeight, maxChildHeight); - newHeightSpec = MeasureSpec.makeMeasureSpec(ownHeight, MeasureSpec.EXACTLY); + ? givenHeight + : Math.min(ownMaxHeight, maxChildHeight); + int exactlyOwnHeightSpec = MeasureSpec.makeMeasureSpec(ownHeight, MeasureSpec.EXACTLY); + + // Now that we know our own height, measure the children that are MATCH_PARENT for (View child : mMatchParentViews) { child.measure(getChildMeasureSpec( widthMeasureSpec, viewHorizontalPadding, child.getLayoutParams().width), - newHeightSpec); + exactlyOwnHeightSpec); } mMatchParentViews.clear(); + + // Finish up int width = MeasureSpec.getSize(widthMeasureSpec); setMeasuredDimension(width, ownHeight); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java index 23433cb1682d..b3561c2deda7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManager.java @@ -16,11 +16,10 @@ package com.android.systemui.statusbar.notification.stack; -import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_GENTLE; - import static java.lang.annotation.RetentionPolicy.SOURCE; import android.annotation.IntDef; +import android.annotation.LayoutRes; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Intent; @@ -35,18 +34,21 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager; import com.android.systemui.statusbar.notification.people.DataListener; -import com.android.systemui.statusbar.notification.people.PeopleHubSectionFooterViewAdapter; -import com.android.systemui.statusbar.notification.people.PeopleHubSectionFooterViewBoundary; +import com.android.systemui.statusbar.notification.people.PeopleHubViewAdapter; +import com.android.systemui.statusbar.notification.people.PeopleHubViewBoundary; import com.android.systemui.statusbar.notification.people.PersonViewModel; +import com.android.systemui.statusbar.notification.people.Subscription; import com.android.systemui.statusbar.notification.row.ActivatableNotificationView; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; -import com.android.systemui.statusbar.notification.row.dagger.NotificationRowComponent; +import com.android.systemui.statusbar.notification.row.ExpandableView; +import com.android.systemui.statusbar.notification.row.StackScrollerDecorView; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener; import java.lang.annotation.Retention; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import javax.inject.Inject; @@ -63,63 +65,65 @@ public class NotificationSectionsManager implements StackScrollAlgorithm.Section private static final String TAG = "NotifSectionsManager"; private static final boolean DEBUG = false; - private NotificationStackScrollLayout mParent; private final ActivityStarter mActivityStarter; private final StatusBarStateController mStatusBarStateController; private final ConfigurationController mConfigurationController; - private final int mNumberOfSections; + private final PeopleHubViewAdapter mPeopleHubViewAdapter; private final NotificationSectionsFeatureManager mSectionsFeatureManager; - private final NotificationRowComponent.Builder mNotificationRowComponentBuilder; - private boolean mInitialized = false; - - private SectionHeaderView mGentleHeader; - private boolean mGentleHeaderVisible = false; + private final int mNumberOfSections; - private boolean mPeopleHubVisible = false; - private PeopleHubView mPeopleHubView; - private final PeopleHubSectionFooterViewAdapter mPeopleHubViewAdapter; - private final PeopleHubSectionFooterViewBoundary mPeopleHubViewBoundary = - new PeopleHubSectionFooterViewBoundary() { - @Override - public void setVisible(boolean isVisible) { - if (mPeopleHubVisible != isVisible) { - mPeopleHubVisible = isVisible; - if (mInitialized) { - updateSectionBoundaries(); - } - } + private final PeopleHubViewBoundary mPeopleHubViewBoundary = new PeopleHubViewBoundary() { + @Override + public void setVisible(boolean isVisible) { + if (mPeopleHubVisible != isVisible) { + mPeopleHubVisible = isVisible; + if (mInitialized) { + updateSectionBoundaries(); } + } + } - @NonNull - @Override - public View getAssociatedViewForClickAnimation() { - return mPeopleHubView; - } + @NonNull + @Override + public View getAssociatedViewForClickAnimation() { + return mPeopleHubView; + } - @NonNull - @Override - public Sequence<DataListener<PersonViewModel>> getPersonViewAdapters() { - return mPeopleHubView.getPersonViewAdapters(); - } - }; + @NonNull + @Override + public Sequence<DataListener<PersonViewModel>> getPersonViewAdapters() { + return mPeopleHubView.getPersonViewAdapters(); + } + }; + + private NotificationStackScrollLayout mParent; + private boolean mInitialized = false; + private SectionHeaderView mGentleHeader; + private boolean mGentleHeaderVisible; @Nullable private View.OnClickListener mOnClearGentleNotifsClickListener; + private SectionHeaderView mAlertingHeader; + private boolean mAlertingHeaderVisible; + + private PeopleHubView mPeopleHubView; + private boolean mPeopleHeaderVisible; + private boolean mPeopleHubVisible = false; + @Nullable private Subscription mPeopleHubSubscription; + @Inject NotificationSectionsManager( ActivityStarter activityStarter, StatusBarStateController statusBarStateController, ConfigurationController configurationController, - PeopleHubSectionFooterViewAdapter peopleHubViewAdapter, - NotificationSectionsFeatureManager sectionsFeatureManager, - NotificationRowComponent.Builder notificationRowComponentBuilder) { + PeopleHubViewAdapter peopleHubViewAdapter, + NotificationSectionsFeatureManager sectionsFeatureManager) { mActivityStarter = activityStarter; mStatusBarStateController = statusBarStateController; mConfigurationController = configurationController; mPeopleHubViewAdapter = peopleHubViewAdapter; mSectionsFeatureManager = sectionsFeatureManager; mNumberOfSections = mSectionsFeatureManager.getNumberOfBuckets(); - mNotificationRowComponentBuilder = notificationRowComponentBuilder; } NotificationSection[] createSectionsForBuckets() { @@ -141,105 +145,81 @@ public class NotificationSectionsManager implements StackScrollAlgorithm.Section mInitialized = true; mParent = parent; reinflateViews(layoutInflater); - mPeopleHubViewAdapter.bindView(mPeopleHubViewBoundary); mConfigurationController.addCallback(mConfigurationListener); } - /** - * Reinflates the entire notification header, including all decoration views. - */ - void reinflateViews(LayoutInflater layoutInflater) { - int oldGentleHeaderPos = -1; - int oldPeopleHubPos = -1; - if (mGentleHeader != null) { - if (mGentleHeader.getTransientContainer() != null) { - mGentleHeader.getTransientContainer().removeView(mGentleHeader); - } else if (mGentleHeader.getParent() != null) { - oldGentleHeaderPos = mParent.indexOfChild(mGentleHeader); - mParent.removeView(mGentleHeader); + private <T extends ExpandableView> T reinflateView( + T view, LayoutInflater layoutInflater, @LayoutRes int layoutResId) { + int oldPos = -1; + if (view != null) { + if (view.getTransientContainer() != null) { + view.getTransientContainer().removeView(mGentleHeader); + } else if (view.getParent() != null) { + oldPos = mParent.indexOfChild(view); + mParent.removeView(view); } } - if (mPeopleHubView != null) { - if (mPeopleHubView.getTransientContainer() != null) { - mPeopleHubView.getTransientContainer().removeView(mPeopleHubView); - } else if (mPeopleHubView.getParent() != null) { - oldPeopleHubPos = mParent.indexOfChild(mPeopleHubView); - mParent.removeView(mPeopleHubView); - } + + view = (T) layoutInflater.inflate(layoutResId, mParent, false); + + if (oldPos != -1) { + mParent.addView(view, oldPos); } - mGentleHeader = (SectionHeaderView) layoutInflater.inflate( - R.layout.status_bar_notification_section_header, mParent, false); - NotificationRowComponent sectionHeaderComponent = mNotificationRowComponentBuilder - .activatableNotificationView(mGentleHeader) - .build(); - sectionHeaderComponent.getActivatableNotificationViewController().init(); + return view; + } + /** + * Reinflates the entire notification header, including all decoration views. + */ + void reinflateViews(LayoutInflater layoutInflater) { + mGentleHeader = reinflateView( + mGentleHeader, layoutInflater, R.layout.status_bar_notification_section_header); + mGentleHeader.setHeaderText(R.string.notification_section_header_gentle); mGentleHeader.setOnHeaderClickListener(this::onGentleHeaderClick); mGentleHeader.setOnClearAllClickListener(this::onClearGentleNotifsClick); - if (oldGentleHeaderPos != -1) { - mParent.addView(mGentleHeader, oldGentleHeaderPos); - } - - mPeopleHubView = (PeopleHubView) layoutInflater.inflate( - R.layout.people_strip, mParent, false); + mAlertingHeader = reinflateView( + mAlertingHeader, layoutInflater, R.layout.status_bar_notification_section_header); + mAlertingHeader.setHeaderText(R.string.notification_section_header_alerting); + mAlertingHeader.setOnHeaderClickListener(this::onGentleHeaderClick); - NotificationRowComponent notificationRowComponent = mNotificationRowComponentBuilder - .activatableNotificationView(mPeopleHubView) - .build(); - notificationRowComponent.getActivatableNotificationViewController().init(); - - if (oldPeopleHubPos != -1) { - mParent.addView(mPeopleHubView, oldPeopleHubPos); + if (mPeopleHubSubscription != null) { + mPeopleHubSubscription.unsubscribe(); } + mPeopleHubView = reinflateView(mPeopleHubView, layoutInflater, R.layout.people_strip); + mPeopleHubSubscription = mPeopleHubViewAdapter.bindView(mPeopleHubViewBoundary); } - /** Listener for when the "clear all" buttton is clciked on the gentle notification header. */ + /** Listener for when the "clear all" button is clicked on the gentle notification header. */ void setOnClearGentleNotifsClickListener(View.OnClickListener listener) { mOnClearGentleNotifsClickListener = listener; } - /** Must be called whenever the UI mode changes (i.e. when we enter night mode). */ - void onUiModeChanged() { - mGentleHeader.onUiModeChanged(); - } - @Override public boolean beginsSection(@NonNull View view, @Nullable View previous) { - boolean begin = false; - if (view instanceof ActivatableNotificationView) { - if (previous instanceof ActivatableNotificationView) { - // If we're drawing the first non-person notification, break out a section - ActivatableNotificationView curr = (ActivatableNotificationView) view; - ActivatableNotificationView prev = (ActivatableNotificationView) previous; - - begin = getBucket(curr) != getBucket(prev); - } - } - - if (!begin) { - begin = view == mGentleHeader || view == mPeopleHubView; - } - - return begin; + return view == mGentleHeader + || view == mPeopleHubView + || view == mAlertingHeader + || !Objects.equals(getBucket(view), getBucket(previous)); } private boolean isUsingMultipleSections() { return mNumberOfSections > 1; } - private @PriorityBucket int getBucket(ActivatableNotificationView view) - throws IllegalArgumentException { - if (view instanceof ExpandableNotificationRow) { - return ((ExpandableNotificationRow) view).getEntry().getBucket(); - } else if (view == mGentleHeader) { + @Nullable + private Integer getBucket(View view) { + if (view == mGentleHeader) { return BUCKET_SILENT; } else if (view == mPeopleHubView) { return BUCKET_PEOPLE; + } else if (view == mAlertingHeader) { + return BUCKET_ALERTING; + } else if (view instanceof ExpandableNotificationRow) { + return ((ExpandableNotificationRow) view).getEntry().getBucket(); } - - throw new IllegalArgumentException("I don't know how to find a bucket for this view :("); + return null; } /** @@ -251,118 +231,104 @@ public class NotificationSectionsManager implements StackScrollAlgorithm.Section return; } - boolean peopleNotificationsPresent = false; - int firstNonHeadsUpIndex = -1; - int firstGentleIndex = -1; - int notifCount = 0; + final boolean showHeaders = mStatusBarStateController.getState() != StatusBarState.KEYGUARD; + final boolean usingPeopleFiltering = mSectionsFeatureManager.isFilteringEnabled(); - final int n = mParent.getChildCount(); - for (int i = 0; i < n; i++) { - View child = mParent.getChildAt(i); - if (child instanceof ExpandableNotificationRow && child.getVisibility() != View.GONE) { - notifCount++; - ExpandableNotificationRow row = (ExpandableNotificationRow) child; - if (firstNonHeadsUpIndex == -1 && !row.isHeadsUp()) { - firstNonHeadsUpIndex = i; + boolean peopleNotifsPresent = false; + int peopleHeaderTarget = -1; + int alertingHeaderTarget = -1; + int gentleHeaderTarget = -1; + + int viewCount = 0; + + if (showHeaders) { + final int childCount = mParent.getChildCount(); + for (int i = 0; i < childCount; i++) { + View child = mParent.getChildAt(i); + if (child.getVisibility() == View.GONE + || !(child instanceof ExpandableNotificationRow)) { + continue; } - if (row.getEntry().getBucket() == BUCKET_PEOPLE) { - peopleNotificationsPresent = true; + ExpandableNotificationRow row = (ExpandableNotificationRow) child; + switch (row.getEntry().getBucket()) { + case BUCKET_PEOPLE: + if (peopleHeaderTarget == -1) { + peopleNotifsPresent = true; + peopleHeaderTarget = viewCount; + viewCount++; + } + break; + case BUCKET_ALERTING: + if (usingPeopleFiltering && alertingHeaderTarget == -1) { + alertingHeaderTarget = viewCount; + viewCount++; + } + break; + case BUCKET_SILENT: + if (gentleHeaderTarget == -1) { + gentleHeaderTarget = viewCount; + viewCount++; + } + break; } - if (row.getEntry().getBucket() == BUCKET_SILENT) { - firstGentleIndex = i; - break; + viewCount++; + } + if (usingPeopleFiltering && mPeopleHubVisible && peopleHeaderTarget == -1) { + // Insert the people header even if there are no people visible, in order to show + // the hub. Put it directly above the next header. + if (alertingHeaderTarget != -1) { + peopleHeaderTarget = alertingHeaderTarget; + alertingHeaderTarget++; + gentleHeaderTarget++; + } else if (gentleHeaderTarget != -1) { + peopleHeaderTarget = gentleHeaderTarget; + gentleHeaderTarget++; + } else { + // Put it at the end of the list. + peopleHeaderTarget = viewCount; } } } - if (firstNonHeadsUpIndex == -1) { - firstNonHeadsUpIndex = firstGentleIndex != -1 ? firstGentleIndex : notifCount; - } - - // make room for peopleHub - int offset = adjustPeopleHubVisibilityAndPosition( - firstNonHeadsUpIndex, peopleNotificationsPresent); - if (firstGentleIndex != -1) { - firstGentleIndex += offset; - } - - adjustGentleHeaderVisibilityAndPosition(firstGentleIndex); + // Allow swiping the people header if the section is empty + mPeopleHubView.setCanSwipe(mPeopleHubVisible && !peopleNotifsPresent); - mGentleHeader.setAreThereDismissableGentleNotifs( - mParent.hasActiveClearableNotifications(ROWS_GENTLE)); + mPeopleHeaderVisible = adjustHeaderVisibilityAndPosition( + peopleHeaderTarget, mPeopleHubView, mPeopleHeaderVisible); + mAlertingHeaderVisible = adjustHeaderVisibilityAndPosition( + alertingHeaderTarget, mAlertingHeader, mAlertingHeaderVisible); + mGentleHeaderVisible = adjustHeaderVisibilityAndPosition( + gentleHeaderTarget, mGentleHeader, mGentleHeaderVisible); } - private void adjustGentleHeaderVisibilityAndPosition(int firstGentleNotifIndex) { - final boolean showGentleHeader = - firstGentleNotifIndex != -1 - && mStatusBarStateController.getState() != StatusBarState.KEYGUARD; - final int currentHeaderIndex = mParent.indexOfChild(mGentleHeader); - - if (!showGentleHeader) { - if (mGentleHeaderVisible) { - mGentleHeaderVisible = false; - mParent.removeView(mGentleHeader); + private boolean adjustHeaderVisibilityAndPosition( + int targetIndex, StackScrollerDecorView header, boolean isCurrentlyVisible) { + if (targetIndex == -1) { + if (isCurrentlyVisible) { + mParent.removeView(header); } + return false; } else { - if (!mGentleHeaderVisible) { - mGentleHeaderVisible = true; + if (header instanceof SwipeableView) { + ((SwipeableView) header).resetTranslation(); + } + if (!isCurrentlyVisible) { // If the header is animating away, it will still have a parent, so detach it first // TODO: We should really cancel the active animations here. This will happen // automatically when the view's intro animation starts, but it's a fragile link. - if (mGentleHeader.getTransientContainer() != null) { - mGentleHeader.getTransientContainer().removeTransientView(mGentleHeader); - mGentleHeader.setTransientContainer(null); + if (header.getTransientContainer() != null) { + header.getTransientContainer().removeTransientView(header); + header.setTransientContainer(null); } - mParent.addView(mGentleHeader, firstGentleNotifIndex); - } else if (currentHeaderIndex != firstGentleNotifIndex - 1) { - // Relocate the header to be immediately before the first child in the section - int targetIndex = firstGentleNotifIndex; - if (currentHeaderIndex < firstGentleNotifIndex) { - // Adjust the target index to account for the header itself being temporarily - // removed during the position change. - targetIndex--; - } - - mParent.changeViewPosition(mGentleHeader, targetIndex); + header.setContentVisible(true); + mParent.addView(header, targetIndex); + } else if (mParent.indexOfChild(header) != targetIndex) { + mParent.changeViewPosition(header, targetIndex); } + return true; } } - private int adjustPeopleHubVisibilityAndPosition( - int targetIndex, boolean peopleNotificationsPresent) { - final boolean showPeopleHeader = mNumberOfSections > 2 - && mStatusBarStateController.getState() != StatusBarState.KEYGUARD - && (peopleNotificationsPresent || mPeopleHubVisible); - final int currentHubIndex = mParent.indexOfChild(mPeopleHubView); - final boolean currentlyVisible = currentHubIndex >= 0; - - mPeopleHubView.setCanSwipe(showPeopleHeader && !peopleNotificationsPresent); - - if (!showPeopleHeader) { - if (currentlyVisible) { - mParent.removeView(mPeopleHubView); - return -1; - } - } else { - mPeopleHubView.unDismiss(); - mPeopleHubView.resetTranslation(); - if (!currentlyVisible) { - if (mPeopleHubView.getTransientContainer() != null) { - mPeopleHubView.getTransientContainer().removeTransientView(mPeopleHubView); - mPeopleHubView.setTransientContainer(null); - } - mParent.addView(mPeopleHubView, targetIndex); - return 1; - } else if (currentHubIndex != targetIndex) { - if (currentHubIndex < targetIndex) { - targetIndex--; - } - mParent.changeViewPosition(mPeopleHubView, targetIndex); - } - } - return 0; - } - /** * Updates the boundaries (as tracked by their first and last views) of the priority sections. * @@ -388,7 +354,12 @@ public class NotificationSectionsManager implements StackScrollAlgorithm.Section //TODO: do this in a single pass, and more better for (ActivatableNotificationView v : children) { - if (getBucket(v) == filter) { + Integer bucket = getBucket(v); + if (bucket == null) { + throw new IllegalArgumentException("Cannot find section bucket for view"); + } + + if (bucket == filter) { viewsInBucket.add(v); } @@ -463,16 +434,17 @@ public class NotificationSectionsManager implements StackScrollAlgorithm.Section /** * For now, declare the available notification buckets (sections) here so that other * presentation code can decide what to do based on an entry's buckets - * */ @Retention(SOURCE) @IntDef(prefix = { "BUCKET_" }, value = { + BUCKET_HEADS_UP, BUCKET_PEOPLE, BUCKET_ALERTING, BUCKET_SILENT }) public @interface PriorityBucket {} - public static final int BUCKET_PEOPLE = 0; - public static final int BUCKET_ALERTING = 1; - public static final int BUCKET_SILENT = 2; + public static final int BUCKET_HEADS_UP = 0; + public static final int BUCKET_PEOPLE = 1; + public static final int BUCKET_ALERTING = 2; + public static final int BUCKET_SILENT = 3; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index 2eeda1f48df3..1bd9bbecc26e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java @@ -815,7 +815,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd mBgColor = mContext.getColor(R.color.notification_shade_background_color); updateBackgroundDimming(); mShelf.onUiModeChanged(); - mSectionsManager.onUiModeChanged(); } @ShadeViewRefactor(RefactorComponent.DECORATOR) @@ -1632,8 +1631,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd @ShadeViewRefactor(RefactorComponent.COORDINATOR) private ExpandableView getChildAtPosition(float touchX, float touchY) { - return getChildAtPosition(touchX, touchY, true /* requireMinHeight */); - + return getChildAtPosition( + touchX, touchY, true /* requireMinHeight */, true /* ignoreDecors */); } /** @@ -1642,17 +1641,18 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd * @param touchX the x coordinate * @param touchY the y coordinate * @param requireMinHeight Whether a minimum height is required for a child to be returned. + * @param ignoreDecors Whether decors can be returned * @return the child at the given location. */ @ShadeViewRefactor(RefactorComponent.COORDINATOR) private ExpandableView getChildAtPosition(float touchX, float touchY, - boolean requireMinHeight) { + boolean requireMinHeight, boolean ignoreDecors) { // find the view under the pointer, accounting for GONE views final int count = getChildCount(); for (int childIdx = 0; childIdx < count; childIdx++) { ExpandableView slidingChild = (ExpandableView) getChildAt(childIdx); if (slidingChild.getVisibility() != VISIBLE - || slidingChild instanceof StackScrollerDecorView) { + || (ignoreDecors && slidingChild instanceof StackScrollerDecorView)) { continue; } float childTop = slidingChild.getTranslationY(); @@ -4166,7 +4166,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd case MotionEvent.ACTION_DOWN: { final int y = (int) ev.getY(); mScrolledToTopOnFirstDown = isScrolledToTop(); - if (getChildAtPosition(ev.getX(), y, false /* requireMinHeight */) == null) { + final ExpandableView childAtTouchPos = getChildAtPosition( + ev.getX(), y, false /* requireMinHeight */, false /* ignoreDecors */); + if (childAtTouchPos == null) { setIsBeingDragged(false); recycleVelocityTracker(); break; @@ -6299,8 +6301,6 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd } if (view instanceof PeopleHubView) { - PeopleHubView row = (PeopleHubView) view; - row.dismiss(false); mSectionsManager.hidePeopleRow(); } @@ -6325,8 +6325,11 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd @Override public View getChildAtPosition(MotionEvent ev) { - View child = NotificationStackScrollLayout.this.getChildAtPosition(ev.getX(), - ev.getY()); + View child = NotificationStackScrollLayout.this.getChildAtPosition( + ev.getX(), + ev.getY(), + true /* requireMinHeight */, + false /* ignoreDecors */); if (child instanceof ExpandableNotificationRow) { ExpandableNotificationRow row = (ExpandableNotificationRow) child; ExpandableNotificationRow parent = row.getNotificationParent(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt index e5717aeefdcb..151c6b272a3e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/PeopleHubView.kt @@ -25,30 +25,32 @@ import com.android.systemui.R import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin import com.android.systemui.statusbar.notification.people.DataListener import com.android.systemui.statusbar.notification.people.PersonViewModel -import com.android.systemui.statusbar.notification.row.ActivatableNotificationView +import com.android.systemui.statusbar.notification.row.StackScrollerDecorView class PeopleHubView(context: Context, attrs: AttributeSet) : - ActivatableNotificationView(context, attrs), SwipeableView { + StackScrollerDecorView(context, attrs), SwipeableView { private lateinit var contents: ViewGroup - private lateinit var personControllers: List<PersonDataListenerImpl> - val personViewAdapters: Sequence<DataListener<PersonViewModel?>> - get() = personControllers.asSequence() + lateinit var personViewAdapters: Sequence<DataListener<PersonViewModel?>> + private set override fun onFinishInflate() { - super.onFinishInflate() contents = requireViewById(R.id.people_list) - personControllers = (0 until contents.childCount) + personViewAdapters = (0 until contents.childCount) .reversed() .asSequence() .mapNotNull { idx -> (contents.getChildAt(idx) as? ImageView)?.let(::PersonDataListenerImpl) } .toList() + .asSequence() + super.onFinishInflate() + setVisible(true /* nowVisible */, false /* animate */) } - override fun getContentView(): View = contents + override fun findContentView(): View = contents + override fun findSecondaryView(): View? = null override fun hasFinishedInitialization(): Boolean = true diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SectionHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SectionHeaderView.java index add982dabf02..ad3ff69eb5c8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SectionHeaderView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/SectionHeaderView.java @@ -17,8 +17,8 @@ package com.android.systemui.statusbar.notification.stack; import android.annotation.Nullable; +import android.annotation.StringRes; import android.content.Context; -import android.graphics.RectF; import android.util.AttributeSet; import android.view.LayoutInflater; import android.view.MotionEvent; @@ -28,7 +28,7 @@ import android.widget.ImageView; import android.widget.TextView; import com.android.systemui.R; -import com.android.systemui.statusbar.notification.row.ActivatableNotificationView; +import com.android.systemui.statusbar.notification.row.StackScrollerDecorView; import java.util.Objects; @@ -36,23 +36,22 @@ import java.util.Objects; * Similar in size and appearance to the NotificationShelf, appears at the beginning of some * notification sections. Currently only used for gentle notifications. */ -public class SectionHeaderView extends ActivatableNotificationView { +public class SectionHeaderView extends StackScrollerDecorView { private ViewGroup mContents; private TextView mLabelView; private ImageView mClearAllButton; @Nullable private View.OnClickListener mOnClearClickListener = null; - private final RectF mTmpRect = new RectF(); - public SectionHeaderView(Context context, AttributeSet attrs) { super(context, attrs); } @Override protected void onFinishInflate() { - super.onFinishInflate(); mContents = Objects.requireNonNull(findViewById(R.id.content)); bindContents(); + super.onFinishInflate(); + setVisible(true /* nowVisible */, false /* animate */); } private void bindContents() { @@ -64,15 +63,20 @@ public class SectionHeaderView extends ActivatableNotificationView { } @Override - protected View getContentView() { + protected View findContentView() { return mContents; } + @Override + protected View findSecondaryView() { + return null; + } + /** * Destroys and reinflates the visible contents of the section header. For use on configuration * changes or any other time that layout values might need to be re-evaluated. * - * Does not reinflate the base content view itself ({@link #getContentView()} or any of the + * Does not reinflate the base content view itself ({@link #findContentView()} or any of the * decorator views, such as the background view or shadow view. */ void reinflateContents() { @@ -88,35 +92,20 @@ public class SectionHeaderView extends ActivatableNotificationView { return true; } - /** Must be called whenever the UI mode changes (i.e. when we enter night mode). */ - void onUiModeChanged() { - updateBackgroundColors(); - mLabelView.setTextColor( - getContext().getColor(R.color.notification_section_header_label_color)); - mClearAllButton.setImageResource( - R.drawable.status_bar_notification_section_header_clear_btn); - } - void setAreThereDismissableGentleNotifs(boolean areThereDismissableGentleNotifs) { mClearAllButton.setVisibility(areThereDismissableGentleNotifs ? View.VISIBLE : View.GONE); } @Override - protected boolean disallowSingleClick(MotionEvent event) { - // Disallow single click on lockscreen if user is tapping on clear all button - mTmpRect.set( - mClearAllButton.getLeft(), - mClearAllButton.getTop(), - mClearAllButton.getLeft() + mClearAllButton.getWidth(), - mClearAllButton.getTop() + mClearAllButton.getHeight()); - return mTmpRect.contains(event.getX(), event.getY()); + public boolean onInterceptTouchEvent(MotionEvent ev) { + return super.onInterceptTouchEvent(ev); } /** * Fired whenever the user clicks on the body of the header (e.g. no sub-buttons or anything). */ void setOnHeaderClickListener(View.OnClickListener listener) { - mContents.setOnClickListener(listener); + mLabelView.setOnClickListener(listener); } /** Fired when the user clicks on the "X" button on the far right of the header. */ @@ -124,4 +113,8 @@ public class SectionHeaderView extends ActivatableNotificationView { mOnClearClickListener = listener; mClearAllButton.setOnClickListener(listener); } + + void setHeaderText(@StringRes int resId) { + mLabelView.setText(resId); + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java index 10821d63d4cc..945a9db7c836 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java @@ -21,7 +21,6 @@ import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.annotation.IntDef; import android.app.AlarmManager; -import android.content.res.Resources; import android.graphics.Color; import android.graphics.drawable.Drawable; import android.os.Handler; @@ -45,7 +44,6 @@ import com.android.systemui.DejankUtils; import com.android.systemui.Dumpable; import com.android.systemui.R; import com.android.systemui.colorextraction.SysuiColorExtractor; -import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dock.DockManager; import com.android.systemui.statusbar.ScrimView; import com.android.systemui.statusbar.notification.stack.ViewState; @@ -116,7 +114,7 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo * A scrim varies its opacity based on a busyness factor, for example * how many notifications are currently visible. */ - public static final float BUSY_SCRIM_ALPHA = 0.54f; + public static final float BUSY_SCRIM_ALPHA = 0.75f; /** * The most common scrim, the one under the keyguard. @@ -146,8 +144,6 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo private GradientColors mColors; private boolean mNeedsDrawableColorUpdate; - private float mScrimBehindAlpha; - private float mScrimBehindAlphaResValue; private float mScrimBehindAlphaKeyguard = SCRIM_BEHIND_ALPHA_KEYGUARD; // Assuming the shade is expanded during initialization @@ -192,7 +188,6 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo @Inject public ScrimController(LightBarController lightBarController, DozeParameters dozeParameters, AlarmManager alarmManager, KeyguardStateController keyguardStateController, - @Main Resources resources, DelayedWakeLock.Builder delayedWakeLockBuilder, Handler handler, KeyguardUpdateMonitor keyguardUpdateMonitor, SysuiColorExtractor sysuiColorExtractor, DockManager dockManager) { @@ -203,14 +198,12 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo mDarkenWhileDragging = !mKeyguardStateController.canDismissLockScreen(); mKeyguardUpdateMonitor = keyguardUpdateMonitor; mKeyguardVisibilityCallback = new KeyguardVisibilityCallback(); - mScrimBehindAlphaResValue = resources.getFloat(R.dimen.scrim_behind_alpha); mHandler = handler; mTimeTicker = new AlarmTimeout(alarmManager, this::onHideWallpaperTimeout, "hide_aod_wallpaper", mHandler); mWakeLock = delayedWakeLockBuilder.setHandler(mHandler).setTag("Scrims").build(); // Scrim alpha is initially set to the value on the resource but might be changed // to make sure that text on top of it is legible. - mScrimBehindAlpha = mScrimBehindAlphaResValue; mDozeParameters = dozeParameters; mDockManager = dockManager; keyguardStateController.addCallback(new KeyguardStateController.Callback() { @@ -587,7 +580,6 @@ public class ScrimController implements ViewTreeObserver.OnPreDrawListener, OnCo int mainColor = mColors.getMainColor(); float minOpacity = ColorUtils.calculateMinimumBackgroundAlpha(textColor, mainColor, 4.5f /* minimumContrast */) / 255f; - mScrimBehindAlpha = Math.max(mScrimBehindAlphaResValue, minOpacity); dispatchScrimState(mScrimBehind.getViewAlpha()); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManagerTest.kt index b3d0d22445b6..6388fe1a69c1 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManagerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationSectionsFeatureManagerTest.kt @@ -63,7 +63,7 @@ class NotificationSectionsFeatureManagerTest : SysuiTestCase() { DeviceConfig.NAMESPACE_SYSTEMUI, NOTIFICATIONS_USE_PEOPLE_FILTERING, "true", false) assertTrue("People filtering should be enabled", manager!!.isFilteringEnabled()) - assertTrue("Expecting 3 buckets when people filtering is enabled", - manager!!.getNumberOfBuckets() == 3) + assertTrue("Expecting 4 buckets when people filtering is enabled", + manager!!.getNumberOfBuckets() == 4) } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt index 45c51d42c250..f11c42bda6cc 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt @@ -32,6 +32,7 @@ import com.android.systemui.statusbar.notification.NotificationFilter import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier +import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_ALERTING import com.android.systemui.statusbar.notification.stack.NotificationSectionsManager.BUCKET_SILENT import com.android.systemui.statusbar.phone.NotificationGroupManager @@ -148,6 +149,53 @@ class NotificationRankingManagerTest : SysuiTestCase() { } @Test + fun testSort_headsUp_trumpsPeople() { + whenever(sectionsManager.isFilteringEnabled()).thenReturn(true) + val aN = Notification.Builder(mContext, "test") + .setStyle(Notification.MessagingStyle("")) + .build() + val a = NotificationEntryBuilder() + .setImportance(IMPORTANCE_HIGH) + .setPkg("pkg") + .setOpPkg("pkg") + .setTag("tag") + .setNotification(aN) + .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT)) + .setUser(mContext.getUser()) + .setOverrideGroupKey("") + .build() + + whenever(personNotificationIdentifier.isImportantPeopleNotification(a.sbn, a.ranking)) + .thenReturn(true) + whenever(personNotificationIdentifier.isPeopleNotification(a.sbn, a.ranking)) + .thenReturn(true) + + val bN = Notification.Builder(mContext, "test") + .setStyle(Notification.MessagingStyle("")) + .build() + val b = NotificationEntryBuilder() + .setImportance(IMPORTANCE_HIGH) + .setPkg("pkg2") + .setOpPkg("pkg2") + .setTag("tag") + .setNotification(bN) + .setChannel(NotificationChannel("test", "", IMPORTANCE_DEFAULT)) + .setUser(mContext.getUser()) + .setOverrideGroupKey("") + .build() + b.row = mock(ExpandableNotificationRow::class.java).also { + whenever(it.isHeadsUp).thenReturn(true) + } + + whenever(personNotificationIdentifier.isImportantPeopleNotification(a.sbn, a.ranking)) + .thenReturn(false) + whenever(personNotificationIdentifier.isPeopleNotification(a.sbn, a.ranking)) + .thenReturn(false) + + assertEquals(listOf(b, a), rankingManager.updateRanking(null, listOf(a, b), "test")) + } + + @Test fun testSort_importantPeople() { whenever(sectionsManager.isFilteringEnabled()).thenReturn(true) val aN = Notification.Builder(mContext, "test") diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt index 867a9b97d622..abce8b517dfb 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/people/PeopleHubViewControllerTest.kt @@ -43,7 +43,7 @@ class PeopleHubViewControllerTest : SysuiTestCase() { @JvmField @Rule val mockito: MockitoRule = MockitoJUnit.rule() - @Mock private lateinit var mockViewBoundary: PeopleHubSectionFooterViewBoundary + @Mock private lateinit var mockViewBoundary: PeopleHubViewBoundary @Mock private lateinit var mockActivityStarter: ActivityStarter @Test @@ -67,7 +67,7 @@ class PeopleHubViewControllerTest : SysuiTestCase() { return mockSubscription } } - val adapter = PeopleHubSectionFooterViewAdapterImpl(fakeFactoryDataSource) + val adapter = PeopleHubViewAdapterImpl(fakeFactoryDataSource) adapter.bindView(mockViewBoundary) diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java index 51f214d8cda2..abfbcd99167b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSectionsManagerTest.java @@ -45,8 +45,7 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.notification.NotificationSectionsFeatureManager; -import com.android.systemui.statusbar.notification.people.PeopleHubSectionFooterViewAdapter; -import com.android.systemui.statusbar.notification.row.ActivatableNotificationView; +import com.android.systemui.statusbar.notification.people.PeopleHubViewAdapter; import com.android.systemui.statusbar.notification.row.ActivatableNotificationViewController; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.dagger.NotificationRowComponent; @@ -71,7 +70,7 @@ public class NotificationSectionsManagerTest extends SysuiTestCase { @Mock private ActivityStarterDelegate mActivityStarterDelegate; @Mock private StatusBarStateController mStatusBarStateController; @Mock private ConfigurationController mConfigurationController; - @Mock private PeopleHubSectionFooterViewAdapter mPeopleHubAdapter; + @Mock private PeopleHubViewAdapter mPeopleHubAdapter; @Mock private NotificationSectionsFeatureManager mSectionsFeatureManager; @Mock private NotificationRowComponent mNotificationRowComponent; @Mock private ActivatableNotificationViewController mActivatableNotificationViewController; @@ -90,18 +89,8 @@ public class NotificationSectionsManagerTest extends SysuiTestCase { mStatusBarStateController, mConfigurationController, mPeopleHubAdapter, - mSectionsFeatureManager, - new NotificationRowComponent.Builder() { - @Override - public NotificationRowComponent.Builder activatableNotificationView( - ActivatableNotificationView view) { - return this; - } - - @Override - public NotificationRowComponent build() { - return mNotificationRowComponent; - }}); + mSectionsFeatureManager + ); // Required in order for the header inflation to work properly when(mNssl.generateLayoutParams(any(AttributeSet.class))) .thenReturn(new ViewGroup.LayoutParams(WRAP_CONTENT, WRAP_CONTENT)); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java index 2e6fbe7d1ddb..408dfc0e1dee 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java @@ -36,7 +36,6 @@ import static org.mockito.Mockito.when; import android.animation.Animator; import android.app.AlarmManager; -import android.content.res.Resources; import android.graphics.Color; import android.os.Handler; import android.testing.AndroidTestingRunner; @@ -91,8 +90,6 @@ public class ScrimControllerTest extends SysuiTestCase { @Mock LightBarController mLightBarController; @Mock - Resources mResources; - @Mock DelayedWakeLock.Builder mDelayedWakeLockBuilder; @Mock private DelayedWakeLock mWakeLock; @@ -216,8 +213,7 @@ public class ScrimControllerTest extends SysuiTestCase { when(mDockManager.isDocked()).thenReturn(false); mScrimController = new ScrimController(mLightBarController, - mDozeParamenters, mAlarmManager, mKeyguardStateController, - mResources, mDelayedWakeLockBuilder, + mDozeParamenters, mAlarmManager, mKeyguardStateController, mDelayedWakeLockBuilder, new FakeHandler(mLooper.getLooper()), mKeyguardUpdateMonitor, mSysuiColorExtractor, mDockManager); mScrimController.setScrimVisibleListener(visible -> mScrimVisibility = visible); |