diff options
7 files changed, 118 insertions, 35 deletions
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 eabc5c5f254e..508619a27e81 100644 --- a/packages/SystemUI/res/layout/status_bar_notification_section_header.xml +++ b/packages/SystemUI/res/layout/status_bar_notification_section_header.xml @@ -22,6 +22,7 @@ android:focusable="true" android:clickable="true" > + <com.android.systemui.statusbar.notification.row.NotificationBackgroundView android:id="@+id/backgroundNormal" android:layout_width="match_parent" @@ -38,28 +39,7 @@ android:gravity="center_vertical" android:orientation="horizontal" > - <TextView - android:id="@+id/header_label" - 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" - /> - <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:src="@drawable/status_bar_notification_section_header_clear_btn" - android:contentDescription="@string/accessibility_notification_section_header_gentle_clear_all" - android:scaleType="center" - /> + <include layout="@layout/status_bar_notification_section_header_contents"/> </LinearLayout> <com.android.systemui.statusbar.notification.FakeShadowView 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 new file mode 100644 index 000000000000..feabd1c72a65 --- /dev/null +++ b/packages/SystemUI/res/layout/status_bar_notification_section_header_contents.xml @@ -0,0 +1,41 @@ +<!-- + ~ Copyright (C) 2019 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License + --> + +<!-- 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" + 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" + /> + <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:src="@drawable/status_bar_notification_section_header_clear_btn" + android:contentDescription="@string/accessibility_notification_section_header_gentle_clear_all" + android:scaleType="center" + /> +</merge> 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 5747bb122fc4..170a4d570688 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 @@ -19,7 +19,6 @@ package com.android.systemui.statusbar.notification.stack; import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_GENTLE; import android.annotation.Nullable; -import android.content.Context; import android.content.Intent; import android.provider.Settings; import android.view.LayoutInflater; @@ -32,6 +31,8 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.notification.row.ActivatableNotificationView; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; +import com.android.systemui.statusbar.policy.ConfigurationController; +import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener; /** * Manages the boundaries of the two notification sections (high priority and low priority). Also @@ -43,8 +44,10 @@ class NotificationSectionsManager implements StackScrollAlgorithm.SectionProvide private final NotificationStackScrollLayout mParent; private final ActivityStarter mActivityStarter; private final StatusBarStateController mStatusBarStateController; + private final ConfigurationController mConfigurationController; private final boolean mUseMultipleSections; + private boolean mInitialized = false; private SectionHeaderView mGentleHeader; private boolean mGentleHeaderVisible = false; @Nullable private ExpandableNotificationRow mFirstGentleNotif; @@ -54,18 +57,29 @@ class NotificationSectionsManager implements StackScrollAlgorithm.SectionProvide NotificationStackScrollLayout parent, ActivityStarter activityStarter, StatusBarStateController statusBarStateController, + ConfigurationController configurationController, boolean useMultipleSections) { mParent = parent; mActivityStarter = activityStarter; mStatusBarStateController = statusBarStateController; + mConfigurationController = configurationController; mUseMultipleSections = useMultipleSections; } + /** Must be called before use. */ + void initialize(LayoutInflater layoutInflater) { + if (mInitialized) { + throw new IllegalStateException("NotificationSectionsManager already initialized"); + } + mInitialized = true; + reinflateViews(layoutInflater); + mConfigurationController.addCallback(mConfigurationListener); + } + /** - * Must be called before use. Should be called again whenever inflation-related things change, - * such as density or theme changes. + * Reinflates the entire notification header, including all decoration views. */ - void inflateViews(Context context) { + void reinflateViews(LayoutInflater layoutInflater) { int oldPos = -1; if (mGentleHeader != null) { if (mGentleHeader.getTransientContainer() != null) { @@ -76,7 +90,7 @@ class NotificationSectionsManager implements StackScrollAlgorithm.SectionProvide } } - mGentleHeader = (SectionHeaderView) LayoutInflater.from(context).inflate( + mGentleHeader = (SectionHeaderView) layoutInflater.inflate( R.layout.status_bar_notification_section_header, mParent, false); mGentleHeader.setOnHeaderClickListener(this::onGentleHeaderClick); mGentleHeader.setOnClearAllClickListener(this::onClearGentleNotifsClick); @@ -244,6 +258,13 @@ class NotificationSectionsManager implements StackScrollAlgorithm.SectionProvide return lastChildBeforeGap; } + private final ConfigurationListener mConfigurationListener = new ConfigurationListener() { + @Override + public void onLocaleListChanged() { + mGentleHeader.reinflateContents(); + } + }; + private void onGentleHeaderClick(View v) { Intent intent = new Intent(Settings.ACTION_NOTIFICATION_SETTINGS); mActivityStarter.startActivity( 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 cd2a65461903..aad35b246178 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 @@ -32,7 +32,6 @@ import android.animation.ValueAnimator; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; -import android.app.WallpaperManager; import android.content.Context; import android.content.Intent; import android.content.res.Configuration; @@ -508,6 +507,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd @Named(ALLOW_NOTIFICATION_LONG_PRESS_NAME) boolean allowLongPress, NotificationRoundnessManager notificationRoundnessManager, DynamicPrivacyController dynamicPrivacyController, + ConfigurationController configurationController, ActivityStarter activityStarter, StatusBarStateController statusBarStateController, HeadsUpManagerPhone headsUpManager, @@ -532,8 +532,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd this, activityStarter, statusBarStateController, + configurationController, NotificationUtils.useNewInterruptionModel(context)); - mSectionsManager.inflateViews(context); + mSectionsManager.initialize(LayoutInflater.from(context)); mSectionsManager.setOnClearGentleNotifsClickListener(v -> { // Leave the shade open if there will be other notifs left over to clear final boolean closeShade = !hasActiveClearableNotifications(ROWS_HIGH_PRIORITY); @@ -647,7 +648,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd inflateFooterView(); inflateEmptyShadeView(); updateFooter(); - mSectionsManager.inflateViews(mContext); + mSectionsManager.reinflateViews(LayoutInflater.from(mContext)); } @Override 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 e2f702dcb732..cc1170f7409b 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 @@ -16,11 +16,16 @@ package com.android.systemui.statusbar.notification.stack; +import static com.android.internal.util.Preconditions.checkNotNull; + +import android.annotation.Nullable; import android.content.Context; import android.graphics.RectF; import android.util.AttributeSet; +import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; +import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; @@ -32,9 +37,10 @@ import com.android.systemui.statusbar.notification.row.ActivatableNotificationVi * notification sections. Currently only used for gentle notifications. */ public class SectionHeaderView extends ActivatableNotificationView { - private View mContents; + private ViewGroup mContents; private TextView mLabelView; private ImageView mClearAllButton; + @Nullable private View.OnClickListener mOnClearClickListener = null; private final RectF mTmpRect = new RectF(); @@ -45,9 +51,16 @@ public class SectionHeaderView extends ActivatableNotificationView { @Override protected void onFinishInflate() { super.onFinishInflate(); - mContents = findViewById(R.id.content); - mLabelView = findViewById(R.id.header_label); - mClearAllButton = findViewById(R.id.btn_clear_all); + mContents = checkNotNull(findViewById(R.id.content)); + bindContents(); + } + + private void bindContents() { + mLabelView = checkNotNull(findViewById(R.id.header_label)); + mClearAllButton = checkNotNull(findViewById(R.id.btn_clear_all)); + if (mOnClearClickListener != null) { + mClearAllButton.setOnClickListener(mOnClearClickListener); + } } @Override @@ -55,6 +68,21 @@ public class SectionHeaderView extends ActivatableNotificationView { return mContents; } + /** + * 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 + * decorator views, such as the background view or shadow view. + */ + void reinflateContents() { + mContents.removeAllViews(); + LayoutInflater.from(getContext()).inflate( + R.layout.status_bar_notification_section_header_contents, + mContents); + bindContents(); + } + /** Must be called whenever the UI mode changes (i.e. when we enter night mode). */ void onUiModeChanged() { updateBackgroundColors(); @@ -88,6 +116,7 @@ public class SectionHeaderView extends ActivatableNotificationView { /** Fired when the user clicks on the "X" button on the far right of the header. */ void setOnClearAllClickListener(View.OnClickListener listener) { + mOnClearClickListener = listener; mClearAllButton.setOnClickListener(listener); } } 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 b99958a07ced..73abda9a5da7 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 @@ -31,6 +31,7 @@ import static org.mockito.Mockito.when; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.util.AttributeSet; +import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -41,6 +42,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.row.ExpandableNotificationRow; +import com.android.systemui.statusbar.policy.ConfigurationController; import org.junit.Before; import org.junit.Rule; @@ -60,6 +62,7 @@ public class NotificationSectionsManagerTest extends SysuiTestCase { @Mock private NotificationStackScrollLayout mNssl; @Mock private ActivityStarterDelegate mActivityStarterDelegate; @Mock private StatusBarStateController mStatusBarStateController; + @Mock private ConfigurationController mConfigurationController; private NotificationSectionsManager mSectionsManager; @@ -70,15 +73,21 @@ public class NotificationSectionsManagerTest extends SysuiTestCase { mNssl, mActivityStarterDelegate, mStatusBarStateController, + mConfigurationController, true); // Required in order for the header inflation to work properly when(mNssl.generateLayoutParams(any(AttributeSet.class))) .thenReturn(new ViewGroup.LayoutParams(WRAP_CONTENT, WRAP_CONTENT)); - mSectionsManager.inflateViews(mContext); + mSectionsManager.initialize(LayoutInflater.from(mContext)); when(mNssl.indexOfChild(any(View.class))).thenReturn(-1); when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE); } + @Test(expected = IllegalStateException.class) + public void testDuplicateInitializeThrows() { + mSectionsManager.initialize(LayoutInflater.from(mContext)); + } + @Test public void testInsertHeader() { // GIVEN a stack with HI and LO rows but no section headers diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java index f337b69ff347..95cf90b96644 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java @@ -75,6 +75,7 @@ import com.android.systemui.statusbar.phone.ScrimController; import com.android.systemui.statusbar.phone.ShadeController; import com.android.systemui.statusbar.phone.StatusBar; import com.android.systemui.statusbar.phone.StatusBarTest.TestableNotificationEntryManager; +import com.android.systemui.statusbar.policy.ConfigurationController; import org.junit.After; import org.junit.Assert; @@ -155,6 +156,7 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { mStackScrollerInternal = new NotificationStackScrollLayout(getContext(), null, true /* allowLongPress */, mNotificationRoundnessManager, mock(DynamicPrivacyController.class), + mock(ConfigurationController.class), mock(ActivityStarterDelegate.class), mock(StatusBarStateController.class), mHeadsUpManager, |