diff options
| author | 2023-10-24 16:18:13 +0000 | |
|---|---|---|
| committer | 2023-10-24 16:18:13 +0000 | |
| commit | ddedd72a9920d3cffddf5e3da87f6ba41513d52d (patch) | |
| tree | e4252f2ee06c6fef46d1545322f4790158f1bf6b | |
| parent | 7f68fdfe9d7ce53fff583f57c8ab672dfd005110 (diff) | |
| parent | e0520b0874af4b3dae89b4c7edbf5cdf55343c01 (diff) | |
Merge "Introduce new FooterView stack." into main
11 files changed, 382 insertions, 34 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java index e74b3fcdf050..ba916542fa67 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterView.java @@ -19,6 +19,9 @@ package com.android.systemui.statusbar.notification.footer.ui.view; import static android.graphics.PorterDuff.Mode.SRC_ATOP; import android.annotation.ColorInt; +import android.annotation.DrawableRes; +import android.annotation.StringRes; +import android.annotation.SuppressLint; import android.content.Context; import android.content.res.ColorStateList; import android.content.res.Configuration; @@ -35,6 +38,7 @@ import androidx.annotation.NonNull; import com.android.settingslib.Utils; import com.android.systemui.res.R; +import com.android.systemui.statusbar.notification.footer.shared.FooterViewRefactor; import com.android.systemui.statusbar.notification.row.FooterViewButton; import com.android.systemui.statusbar.notification.row.StackScrollerDecorView; import com.android.systemui.statusbar.notification.stack.ExpandableViewState; @@ -44,6 +48,8 @@ import com.android.systemui.util.DumpUtilsKt; import java.io.PrintWriter; public class FooterView extends StackScrollerDecorView { + private static final String TAG = "FooterView"; + private FooterViewButton mClearAllButton; private FooterViewButton mManageButton; private boolean mShowHistory; @@ -57,6 +63,9 @@ public class FooterView extends StackScrollerDecorView { private String mSeenNotifsFilteredText; private Drawable mSeenNotifsFilteredIcon; + private @StringRes int mMessageStringId; + private @DrawableRes int mMessageIconId; + public FooterView(Context context, AttributeSet attrs) { super(context, attrs); } @@ -84,6 +93,50 @@ public class FooterView extends StackScrollerDecorView { }); } + /** Set the string for a message to be shown instead of the buttons. */ + public void setMessageString(@StringRes int messageId) { + if (FooterViewRefactor.isUnexpectedlyInLegacyMode()) return; + if (mMessageStringId == messageId) { + return; // nothing changed + } + mMessageStringId = messageId; + updateMessageString(); + } + + private void updateMessageString() { + if (mMessageStringId == 0) { + return; // not initialized yet + } + String messageString = getContext().getString(mMessageStringId); + mSeenNotifsFooterTextView.setText(messageString); + } + + + /** Set the icon to be shown before the message (see {@link #setMessageString(int)}). */ + public void setMessageIcon(@DrawableRes int iconId) { + if (FooterViewRefactor.isUnexpectedlyInLegacyMode()) return; + if (mMessageIconId == iconId) { + return; // nothing changed + } + mMessageIconId = iconId; + updateMessageIcon(); + } + + private void updateMessageIcon() { + if (mMessageIconId == 0) { + return; // not initialized yet + } + int unlockIconSize = getResources() + .getDimensionPixelSize(R.dimen.notifications_unseen_footer_icon_size); + @SuppressLint("UseCompatLoadingForDrawables") + Drawable messageIcon = getContext().getDrawable(mMessageIconId); + if (messageIcon != null) { + messageIcon.setBounds(0, 0, unlockIconSize, unlockIconSize); + mSeenNotifsFooterTextView + .setCompoundDrawablesRelative(messageIcon, null, null, null); + } + } + @Override protected void onFinishInflate() { super.onFinishInflate(); @@ -148,9 +201,11 @@ public class FooterView extends StackScrollerDecorView { mManageButton.setText(mManageNotificationText); mManageButton.setContentDescription(mManageNotificationText); } - mSeenNotifsFooterTextView.setText(mSeenNotifsFilteredText); - mSeenNotifsFooterTextView - .setCompoundDrawablesRelative(mSeenNotifsFilteredIcon, null, null, null); + if (!FooterViewRefactor.isEnabled()) { + mSeenNotifsFooterTextView.setText(mSeenNotifsFilteredText); + mSeenNotifsFooterTextView + .setCompoundDrawablesRelative(mSeenNotifsFilteredIcon, null, null, null); + } } /** Whether the start button shows "History" (true) or "Manage" (false). */ @@ -167,6 +222,11 @@ public class FooterView extends StackScrollerDecorView { mContext.getString(R.string.accessibility_clear_all)); updateResources(); updateContent(); + + if (FooterViewRefactor.isEnabled()) { + updateMessageString(); + updateMessageIcon(); + } } /** @@ -200,11 +260,13 @@ public class FooterView extends StackScrollerDecorView { mManageNotificationText = getContext().getString(R.string.manage_notifications_text); mManageNotificationHistoryText = getContext() .getString(R.string.manage_notifications_history_text); - int unlockIconSize = getResources() - .getDimensionPixelSize(R.dimen.notifications_unseen_footer_icon_size); - mSeenNotifsFilteredText = getContext().getString(R.string.unlock_to_see_notif_text); - mSeenNotifsFilteredIcon = getContext().getDrawable(R.drawable.ic_friction_lock_closed); - mSeenNotifsFilteredIcon.setBounds(0, 0, unlockIconSize, unlockIconSize); + if (!FooterViewRefactor.isEnabled()) { + int unlockIconSize = getResources() + .getDimensionPixelSize(R.dimen.notifications_unseen_footer_icon_size); + mSeenNotifsFilteredText = getContext().getString(R.string.unlock_to_see_notif_text); + mSeenNotifsFilteredIcon = getContext().getDrawable(R.drawable.ic_friction_lock_closed); + mSeenNotifsFilteredIcon.setBounds(0, 0, unlockIconSize, unlockIconSize); + } } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewbinder/FooterViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewbinder/FooterViewBinder.kt new file mode 100644 index 000000000000..6d8234371b65 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewbinder/FooterViewBinder.kt @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification.footer.ui.viewbinder + +import androidx.lifecycle.lifecycleScope +import com.android.systemui.lifecycle.repeatWhenAttached +import com.android.systemui.statusbar.notification.footer.ui.view.FooterView +import com.android.systemui.statusbar.notification.footer.ui.viewmodel.FooterViewModel +import kotlinx.coroutines.DisposableHandle +import kotlinx.coroutines.launch + +/** Binds a [FooterView] to its [view model][FooterViewModel]. */ +object FooterViewBinder { + fun bind( + footer: FooterView, + viewModel: FooterViewModel, + ): DisposableHandle { + return footer.repeatWhenAttached { + // Listen for changes when the view is attached. + lifecycleScope.launch { + viewModel.message.collect { message -> + footer.setFooterLabelVisible(message.visible) + footer.setMessageString(message.messageId) + footer.setMessageIcon(message.iconId) + } + } + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterMessageViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterMessageViewModel.kt new file mode 100644 index 000000000000..bc912fb106f0 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterMessageViewModel.kt @@ -0,0 +1,27 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification.footer.ui.viewmodel + +import android.annotation.DrawableRes +import android.annotation.StringRes + +/** A ViewModel for the string message that can be shown in the footer. */ +data class FooterMessageViewModel( + @StringRes val messageId: Int, + @DrawableRes val iconId: Int, + val visible: Boolean, +) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModel.kt new file mode 100644 index 000000000000..ffa5ff052454 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModel.kt @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification.footer.ui.viewmodel + +import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.res.R +import com.android.systemui.statusbar.notification.domain.interactor.SeenNotificationsInteractor +import com.android.systemui.statusbar.notification.footer.shared.FooterViewRefactor +import com.android.systemui.statusbar.notification.footer.ui.view.FooterView +import javax.inject.Inject +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map + +/** ViewModel for [FooterView]. */ +@SysUISingleton +class FooterViewModel +@Inject +constructor(seenNotificationsInteractor: SeenNotificationsInteractor) { + init { + /* Check if */ FooterViewRefactor.isUnexpectedlyInLegacyMode() + } + + val message: Flow<FooterMessageViewModel> = + seenNotificationsInteractor.hasFilteredOutSeenNotifications.map { hasFilteredOutNotifs -> + FooterMessageViewModel( + messageId = R.string.unlock_to_see_notif_text, + iconId = R.drawable.ic_friction_lock_closed, + visible = hasFilteredOutNotifs, + ) + } +} 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 77d5a2d70d43..1e9cfa8d1d3a 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 @@ -107,6 +107,7 @@ import com.android.systemui.statusbar.notification.NotificationUtils; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager; import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager; +import com.android.systemui.statusbar.notification.footer.shared.FooterViewRefactor; import com.android.systemui.statusbar.notification.footer.ui.view.FooterView; import com.android.systemui.statusbar.notification.init.NotificationsController; import com.android.systemui.statusbar.notification.logging.NotificationLogger; @@ -694,7 +695,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable super.onFinishInflate(); inflateEmptyShadeView(); - inflateFooterView(); + if (!FooterViewRefactor.isEnabled()) { + inflateFooterView(); + } } /** @@ -729,9 +732,11 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable } void reinflateViews() { - inflateFooterView(); + if (!FooterViewRefactor.isEnabled()) { + inflateFooterView(); + updateFooter(); + } inflateEmptyShadeView(); - updateFooter(); mSectionsManager.reinflateViews(); } @@ -746,7 +751,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable @VisibleForTesting public void updateFooter() { - if (mFooterView == null) { + if (mFooterView == null || mController == null) { return; } // TODO: move this logic to controller, which will invoke updateFooterView directly @@ -4546,7 +4551,8 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable return mFooterView != null && mFooterView.isHistoryShown(); } - void setFooterView(@NonNull FooterView footerView) { + /** Bind the {@link FooterView} to the NSSL. */ + public void setFooterView(@NonNull FooterView footerView) { int index = -1; if (mFooterView != null) { index = indexOfChild(mFooterView); @@ -4557,6 +4563,16 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable if (mManageButtonClickListener != null) { mFooterView.setManageButtonClickListener(mManageButtonClickListener); } + mFooterView.setClearAllButtonClickListener(v -> { + if (mFooterClearAllListener != null) { + mFooterClearAllListener.onClearAll(); + } + clearNotifications(ROWS_ALL, true /* closeShade */); + footerView.setSecondaryVisible(false /* visible */, true /* animate */); + }); + if (FooterViewRefactor.isEnabled()) { + updateFooter(); + } } public void setEmptyShadeView(EmptyShadeView emptyShadeView) { @@ -4619,7 +4635,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable mFooterView.setVisible(visible, animate); mFooterView.setSecondaryVisible(showDismissView, animate); mFooterView.showHistory(showHistory); - mFooterView.setFooterLabelVisible(mHasFilteredOutSeenNotifications); + if (!FooterViewRefactor.isEnabled()) { + mFooterView.setFooterLabelVisible(mHasFilteredOutSeenNotifications); + } } @VisibleForTesting @@ -5370,15 +5388,9 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable @VisibleForTesting protected void inflateFooterView() { + FooterViewRefactor.assertInLegacyMode(); FooterView footerView = (FooterView) LayoutInflater.from(mContext).inflate( R.layout.status_bar_notification_footer, this, false); - footerView.setClearAllButtonClickListener(v -> { - if (mFooterClearAllListener != null) { - mFooterClearAllListener.onClearAll(); - } - clearNotifications(ROWS_ALL, true /* closeShade */); - footerView.setSecondaryVisible(false /* visible */, true /* animate */); - }); setFooterView(footerView); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java index 8e88a91b5cd9..79448b46fa06 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java @@ -62,7 +62,7 @@ import com.android.systemui.classifier.FalsingCollector; import com.android.systemui.dagger.SysUISingleton; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dump.DumpManager; -import com.android.systemui.flags.FeatureFlags; +import com.android.systemui.flags.FeatureFlagsClassic; import com.android.systemui.flags.Flags; import com.android.systemui.flags.RefactorFlag; import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository; @@ -206,7 +206,7 @@ public class NotificationStackScrollLayoutController { private HeadsUpAppearanceController mHeadsUpAppearanceController; private boolean mIsInTransitionToAod = false; - private final FeatureFlags mFeatureFlags; + private final FeatureFlagsClassic mFeatureFlags; private final RefactorFlag mShelfRefactor; private final NotificationTargetsHelper mNotificationTargetsHelper; private final SecureSettings mSecureSettings; @@ -669,7 +669,7 @@ public class NotificationStackScrollLayoutController { NotificationStackScrollLogger logger, NotificationStackSizeCalculator notificationStackSizeCalculator, NotificationIconAreaController notifIconAreaController, - FeatureFlags featureFlags, + FeatureFlagsClassic featureFlags, NotificationTargetsHelper notificationTargetsHelper, SecureSettings secureSettings, NotificationDismissibilityProvider dismissibilityProvider, @@ -832,7 +832,8 @@ public class NotificationStackScrollLayoutController { mViewModel.ifPresent( vm -> NotificationListViewBinder - .bind(mView, vm, mFalsingManager, mFeatureFlags, mNotifIconAreaController)); + .bind(mView, vm, mFalsingManager, mFeatureFlags, mNotifIconAreaController, + mConfigurationController)); collectFlow(mView, mKeyguardTransitionRepo.getTransitions(), this::onKeyguardTransitionChanged); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt index dee3973edb55..a3792cf6a0f0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt @@ -17,14 +17,23 @@ package com.android.systemui.statusbar.notification.stack.ui.viewbinder import android.view.LayoutInflater -import com.android.systemui.res.R -import com.android.systemui.flags.FeatureFlags +import com.android.systemui.flags.FeatureFlagsClassic +import com.android.systemui.lifecycle.repeatWhenAttached import com.android.systemui.plugins.FalsingManager +import com.android.systemui.res.R import com.android.systemui.statusbar.NotificationShelf +import com.android.systemui.statusbar.notification.footer.ui.view.FooterView +import com.android.systemui.statusbar.notification.footer.ui.viewbinder.FooterViewBinder import com.android.systemui.statusbar.notification.shelf.ui.viewbinder.NotificationShelfViewBinder import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationListViewModel import com.android.systemui.statusbar.phone.NotificationIconAreaController +import com.android.systemui.statusbar.policy.ConfigurationController +import com.android.systemui.statusbar.policy.onDensityOrFontScaleChanged +import com.android.systemui.statusbar.policy.onThemeChanged +import com.android.systemui.util.traceSection +import com.android.systemui.util.view.reinflateAndBindLatest +import kotlinx.coroutines.flow.merge /** Binds a [NotificationStackScrollLayout] to its [view model][NotificationListViewModel]. */ object NotificationListViewBinder { @@ -33,8 +42,9 @@ object NotificationListViewBinder { view: NotificationStackScrollLayout, viewModel: NotificationListViewModel, falsingManager: FalsingManager, - featureFlags: FeatureFlags, + featureFlags: FeatureFlagsClassic, iconAreaController: NotificationIconAreaController, + configurationController: ConfigurationController, ) { val shelf = LayoutInflater.from(view.context) @@ -47,5 +57,26 @@ object NotificationListViewBinder { iconAreaController ) view.setShelf(shelf) + + viewModel.footer.ifPresent { footerViewModel -> + // The footer needs to be re-inflated every time the theme or the font size changes. + view.repeatWhenAttached { + LayoutInflater.from(view.context).reinflateAndBindLatest( + R.layout.status_bar_notification_footer, + view, + attachToRoot = false, + // TODO(b/305930747): This may lead to duplicate invocations if both flows emit, + // find a solution to only emit one event. + merge( + configurationController.onThemeChanged, + configurationController.onDensityOrFontScaleChanged, + ), + ) { view -> + traceSection("bind FooterView") { + FooterViewBinder.bind(view as FooterView, footerViewModel) + } + } + } + } } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModel.kt index 11f68e0f663b..261371d59a3d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModel.kt @@ -17,8 +17,9 @@ package com.android.systemui.statusbar.notification.stack.ui.viewmodel import com.android.systemui.dagger.SysUISingleton -import com.android.systemui.flags.FeatureFlags +import com.android.systemui.flags.FeatureFlagsClassic import com.android.systemui.flags.Flags +import com.android.systemui.statusbar.notification.footer.ui.viewmodel.FooterViewModel import com.android.systemui.statusbar.notification.shelf.ui.viewmodel.NotificationShelfViewModel import dagger.Module import dagger.Provides @@ -28,6 +29,7 @@ import javax.inject.Provider /** ViewModel for the list of notifications. */ class NotificationListViewModel( val shelf: NotificationShelfViewModel, + val footer: Optional<FooterViewModel>, ) @Module @@ -36,12 +38,33 @@ object NotificationListViewModelModule { @Provides @SysUISingleton fun maybeProvideViewModel( - featureFlags: FeatureFlags, + featureFlags: FeatureFlagsClassic, shelfViewModel: Provider<NotificationShelfViewModel>, - ): Optional<NotificationListViewModel> = - if (featureFlags.isEnabled(Flags.NOTIFICATION_SHELF_REFACTOR)) { - Optional.of(NotificationListViewModel(shelfViewModel.get())) + footerViewModel: Provider<FooterViewModel>, + ): Optional<NotificationListViewModel> { + return if (featureFlags.isEnabled(Flags.NOTIFICATION_SHELF_REFACTOR)) { + if (com.android.systemui.Flags.notificationsFooterViewRefactor()) { + Optional.of( + NotificationListViewModel( + shelfViewModel.get(), + Optional.of(footerViewModel.get()) + ) + ) + } else { + Optional.of(NotificationListViewModel(shelfViewModel.get(), Optional.empty())) + } } else { + if (com.android.systemui.Flags.notificationsFooterViewRefactor()) { + throw IllegalStateException( + "The com.android.systemui.notifications_footer_view_refactor flag requires " + + "the notification_shelf_refactor flag to be enabled. First disable the " + + "footer flag using `adb shell device_config put systemui " + + "com.android.systemui.notifications_footer_view_refactor false`, then " + + "enable the notification_shelf_refactor flag in Flag Flipper. " + + "Afterwards, you can try re-enabling the footer refactor flag via adb." + ) + } Optional.empty() } + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterViewTest.java index f72142ffc6d7..cc87d7ce377b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/footer/ui/view/FooterViewTest.java @@ -22,8 +22,15 @@ import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertNotNull; import static junit.framework.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; +import android.content.Context; import android.testing.AndroidTestingRunner; import android.view.LayoutInflater; import android.view.View; @@ -31,6 +38,7 @@ import android.widget.TextView; import androidx.test.filters.SmallTest; +import com.android.systemui.Flags; import com.android.systemui.SysuiTestCase; import com.android.systemui.res.R; @@ -44,9 +52,13 @@ public class FooterViewTest extends SysuiTestCase { FooterView mView; + Context mSpyContext = spy(mContext); + @Before public void setUp() { - mView = (FooterView) LayoutInflater.from(mContext).inflate( + mSetFlagsRule.enableFlags(Flags.FLAG_NOTIFICATIONS_FOOTER_VIEW_REFACTOR); + + mView = (FooterView) LayoutInflater.from(mSpyContext).inflate( R.layout.status_bar_notification_footer, null, false); mView.setDuration(0); } @@ -102,6 +114,37 @@ public class FooterViewTest extends SysuiTestCase { } @Test + public void testSetMessageString_resourceOnlyFetchedOnce() { + mView.setMessageString(R.string.unlock_to_see_notif_text); + verify(mSpyContext).getString(eq(R.string.unlock_to_see_notif_text)); + + clearInvocations(mSpyContext); + + assertThat(((TextView) mView.findViewById(R.id.unlock_prompt_footer)) + .getText().toString()).contains("Unlock"); + + // Set it a few more times, it shouldn't lead to the resource being fetched again + mView.setMessageString(R.string.unlock_to_see_notif_text); + mView.setMessageString(R.string.unlock_to_see_notif_text); + + verify(mSpyContext, never()).getString(anyInt()); + } + + @Test + public void testSetMessageIcon_resourceOnlyFetchedOnce() { + mView.setMessageIcon(R.drawable.ic_friction_lock_closed); + verify(mSpyContext).getDrawable(eq(R.drawable.ic_friction_lock_closed)); + + clearInvocations(mSpyContext); + + // Set it a few more times, it shouldn't lead to the resource being fetched again + mView.setMessageIcon(R.drawable.ic_friction_lock_closed); + mView.setMessageIcon(R.drawable.ic_friction_lock_closed); + + verify(mSpyContext, never()).getDrawable(anyInt()); + } + + @Test public void testSetFooterLabelVisible() { mView.setFooterLabelVisible(true); assertThat(mView.findViewById(R.id.manage_text).getVisibility()).isEqualTo(View.GONE); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModelTest.kt new file mode 100644 index 000000000000..57a7c3c7e2bf --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/footer/ui/viewmodel/FooterViewModelTest.kt @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2023 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.statusbar.notification.footer.ui.viewmodel + +import android.testing.AndroidTestingRunner +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.coroutines.collectLastValue +import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationListRepository +import com.android.systemui.statusbar.notification.domain.interactor.SeenNotificationsInteractor +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.test.runTest +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(AndroidTestingRunner::class) +@SmallTest +class FooterViewModelTest : SysuiTestCase() { + private val repository = ActiveNotificationListRepository() + private val interactor = SeenNotificationsInteractor(repository) + private val underTest = FooterViewModel(interactor) + + @Test + fun testMessageVisible_whenFilteredNotifications() = runTest { + val message by collectLastValue(underTest.message) + + repository.hasFilteredOutSeenNotifications.value = true + + assertThat(message?.visible).isTrue() + } + + @Test + fun testMessageVisible_whenNoFilteredNotifications() = runTest { + val message by collectLastValue(underTest.message) + + repository.hasFilteredOutSeenNotifications.value = false + + assertThat(message?.visible).isFalse() + } +} 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 033c96ae84b0..8f36d4f5bf6c 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 @@ -19,6 +19,8 @@ package com.android.systemui.statusbar.notification.stack; import static android.view.View.GONE; import static android.view.WindowInsets.Type.ime; +import static com.android.systemui.Flags.FLAG_NOTIFICATIONS_FOOTER_VIEW_REFACTOR; +import static com.android.systemui.flags.SetFlagsRuleExtensionsKt.setFlagDefault; import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_ALL; import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.ROWS_GENTLE; import static com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.RUBBER_BAND_FACTOR_NORMAL; @@ -165,6 +167,11 @@ public class NotificationStackScrollLayoutTest extends SysuiTestCase { mFeatureFlags.setDefault(Flags.NOTIFICATION_SHELF_REFACTOR); mFeatureFlags.setDefault(Flags.NEW_AOD_TRANSITION); mFeatureFlags.setDefault(Flags.UNCLEARED_TRANSIENT_HUN_FIX); + // Some tests in this file test the FooterView. Since we're refactoring the FooterView + // business logic out of the NSSL, the behavior tested in this file will eventually be + // tested directly in the new FooterView stack. For now, we just want to make sure that the + // old behavior is preserved when the flag is off. + setFlagDefault(mSetFlagsRule, FLAG_NOTIFICATIONS_FOOTER_VIEW_REFACTOR); // Inject dependencies before initializing the layout mDependency.injectTestDependency(FeatureFlags.class, mFeatureFlags); |