Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9441b51f authored by Ioana Alexandru's avatar Ioana Alexandru Committed by Android (Google) Code Review
Browse files

Merge changes I087ba490,Ic4b8a879 into main

* changes:
  Notif redesign: Hide footer buttons when message is visible
  Add refactor checks for footer redesign.
parents 5cd16a26 8af56443
Loading
Loading
Loading
Loading
+36 −2
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@

package com.android.systemui.statusbar.notification.footer.ui.viewmodel

import android.platform.test.annotations.DisableFlags
import android.platform.test.annotations.EnableFlags
import android.platform.test.flag.junit.FlagsParameterization
import android.provider.Settings
@@ -40,6 +41,7 @@ import com.android.systemui.statusbar.notification.collection.render.NotifStats
import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository
import com.android.systemui.statusbar.notification.emptyshade.shared.ModesEmptyShadeFix
import com.android.systemui.statusbar.notification.footer.shared.FooterViewRefactor
import com.android.systemui.statusbar.notification.footer.shared.NotifRedesignFooter
import com.android.systemui.testKosmos
import com.android.systemui.util.ui.isAnimating
import com.android.systemui.util.ui.value
@@ -230,6 +232,7 @@ class FooterViewModelTest(flags: FlagsParameterization) : SysuiTestCase() {
        }

    @Test
    @DisableFlags(NotifRedesignFooter.FLAG_NAME)
    fun manageButton_whenHistoryDisabled() =
        testScope.runTest {
            val buttonLabel by collectLastValue(underTest.manageOrHistoryButton.labelId)
@@ -243,6 +246,7 @@ class FooterViewModelTest(flags: FlagsParameterization) : SysuiTestCase() {
        }

    @Test
    @DisableFlags(NotifRedesignFooter.FLAG_NAME)
    fun historyButton_whenHistoryEnabled() =
        testScope.runTest {
            val buttonLabel by collectLastValue(underTest.manageOrHistoryButton.labelId)
@@ -255,8 +259,9 @@ class FooterViewModelTest(flags: FlagsParameterization) : SysuiTestCase() {
            assertThat(buttonLabel).isEqualTo(R.string.manage_notifications_history_text)
        }

    @EnableFlags(ModesEmptyShadeFix.FLAG_NAME)
    @Test
    @EnableFlags(ModesEmptyShadeFix.FLAG_NAME)
    @DisableFlags(NotifRedesignFooter.FLAG_NAME)
    fun manageButtonOnClick_whenHistoryDisabled() =
        testScope.runTest {
            val onClick by collectLastValue(underTest.manageOrHistoryButtonClick)
@@ -271,8 +276,9 @@ class FooterViewModelTest(flags: FlagsParameterization) : SysuiTestCase() {
            assertThat(onClick?.backStack).isEmpty()
        }

    @EnableFlags(ModesEmptyShadeFix.FLAG_NAME)
    @Test
    @EnableFlags(ModesEmptyShadeFix.FLAG_NAME)
    @DisableFlags(NotifRedesignFooter.FLAG_NAME)
    fun historyButtonOnClick_whenHistoryEnabled() =
        testScope.runTest {
            val onClick by collectLastValue(underTest.manageOrHistoryButtonClick)
@@ -289,6 +295,7 @@ class FooterViewModelTest(flags: FlagsParameterization) : SysuiTestCase() {
        }

    @Test
    @DisableFlags(NotifRedesignFooter.FLAG_NAME)
    fun manageButtonVisible_whenMessageVisible() =
        testScope.runTest {
            val visible by collectLastValue(underTest.manageOrHistoryButton.isVisible)
@@ -299,6 +306,7 @@ class FooterViewModelTest(flags: FlagsParameterization) : SysuiTestCase() {
        }

    @Test
    @DisableFlags(NotifRedesignFooter.FLAG_NAME)
    fun manageButtonVisible_whenMessageNotVisible() =
        testScope.runTest {
            val visible by collectLastValue(underTest.manageOrHistoryButton.isVisible)
@@ -307,4 +315,30 @@ class FooterViewModelTest(flags: FlagsParameterization) : SysuiTestCase() {

            assertThat(visible?.value).isTrue()
        }

    @Test
    @EnableFlags(NotifRedesignFooter.FLAG_NAME)
    fun settingsAndHistoryButtonsNotVisible_whenMessageVisible() =
        testScope.runTest {
            val settingsVisible by collectLastValue(underTest.settingsButtonVisible)
            val historyVisible by collectLastValue(underTest.historyButtonVisible)

            activeNotificationListRepository.hasFilteredOutSeenNotifications.value = true

            assertThat(settingsVisible).isFalse()
            assertThat(historyVisible).isFalse()
        }

    @Test
    @EnableFlags(NotifRedesignFooter.FLAG_NAME)
    fun settingsAndHistoryButtonsNotVisible_whenMessageNotVisible() =
        testScope.runTest {
            val settingsVisible by collectLastValue(underTest.settingsButtonVisible)
            val historyVisible by collectLastValue(underTest.historyButtonVisible)

            activeNotificationListRepository.hasFilteredOutSeenNotifications.value = false

            assertThat(settingsVisible).isTrue()
            assertThat(historyVisible).isTrue()
        }
}
+61 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.shared

import com.android.systemui.Flags
import com.android.systemui.flags.FlagToken
import com.android.systemui.flags.RefactorFlagUtils

/** Helper for reading or using the flag state for the footer redesign. */
@Suppress("NOTHING_TO_INLINE")
object NotifRedesignFooter {
    /** The aconfig flag name */
    const val FLAG_NAME = Flags.FLAG_NOTIFICATIONS_REDESIGN_FOOTER_VIEW

    /** A token used for dependency declaration */
    val token: FlagToken
        get() = FlagToken(FLAG_NAME, isEnabled)

    /** Is the refactor enabled */
    @JvmStatic
    inline val isEnabled
        get() = Flags.notificationsRedesignFooterView()

    /**
     * Called to ensure code is only run when the flag is enabled. This protects users from the
     * unintended behaviors caused by accidentally running new logic, while also crashing on an eng
     * build to ensure that the refactor author catches issues in testing.
     */
    @JvmStatic
    inline fun isUnexpectedlyInLegacyMode() =
        RefactorFlagUtils.isUnexpectedlyInLegacyMode(isEnabled, FLAG_NAME)

    /**
     * Called to ensure code is only run when the flag is enabled. This will throw an exception if
     * the flag is not enabled to ensure that the refactor author catches issues in testing.
     * Caution!! Using this check incorrectly will cause crashes in nextfood builds!
     */
    @JvmStatic
    inline fun assertInNewMode() = RefactorFlagUtils.assertInNewMode(isEnabled, FLAG_NAME)

    /**
     * Called to ensure code is only run when the flag is disabled. This will throw an exception if
     * the flag is enabled to ensure that the refactor author catches issues in testing.
     */
    @JvmStatic
    inline fun assertInLegacyMode() = RefactorFlagUtils.assertInLegacyMode(isEnabled, FLAG_NAME)
}
+36 −5
Original line number Diff line number Diff line
@@ -40,10 +40,10 @@ import android.widget.TextView;
import androidx.annotation.NonNull;

import com.android.settingslib.Utils;
import com.android.systemui.Flags;
import com.android.systemui.res.R;
import com.android.systemui.statusbar.notification.ColorUpdateLogger;
import com.android.systemui.statusbar.notification.footer.shared.FooterViewRefactor;
import com.android.systemui.statusbar.notification.footer.shared.NotifRedesignFooter;
import com.android.systemui.statusbar.notification.row.FooterViewButton;
import com.android.systemui.statusbar.notification.row.StackScrollerDecorView;
import com.android.systemui.statusbar.notification.stack.AnimationProperties;
@@ -107,11 +107,31 @@ public class FooterView extends StackScrollerDecorView {
        setClearAllButtonVisible(visible, animate, /* onAnimationEnded = */ null);
    }

    /** Set the visibility of the "Manage"/"History" button to {@code visible}. */
    /**
     * Set the visibility of the "Manage"/"History" button to {@code visible}. This is replaced by
     * two separate buttons in the redesign.
     */
    public void setManageOrHistoryButtonVisible(boolean visible) {
        NotifRedesignFooter.assertInLegacyMode();
        mManageOrHistoryButton.setVisibility(visible ? View.VISIBLE : View.GONE);
    }

    /** Set the visibility of the Settings button to {@code visible}. */
    public void setSettingsButtonVisible(boolean visible) {
        if (NotifRedesignFooter.isUnexpectedlyInLegacyMode()) {
            return;
        }
        mSettingsButton.setVisibility(visible ? View.VISIBLE : View.GONE);
    }

    /** Set the visibility of the History button to {@code visible}. */
    public void setHistoryButtonVisible(boolean visible) {
        if (NotifRedesignFooter.isUnexpectedlyInLegacyMode()) {
            return;
        }
        mHistoryButton.setVisibility(visible ? View.VISIBLE : View.GONE);
    }

    /**
     * Set the visibility of the "Clear all" button to {@code visible}. Animate the change if
     * {@code animate} is true.
@@ -187,6 +207,7 @@ public class FooterView extends StackScrollerDecorView {

    /** Set the text label for the "Manage"/"History" button. */
    public void setManageOrHistoryButtonText(@StringRes int textId) {
        NotifRedesignFooter.assertInLegacyMode();
        if (FooterViewRefactor.isUnexpectedlyInLegacyMode()) return;
        if (mManageOrHistoryButtonTextId == textId) {
            return; // nothing changed
@@ -196,6 +217,7 @@ public class FooterView extends StackScrollerDecorView {
    }

    private void updateManageOrHistoryButtonText() {
        NotifRedesignFooter.assertInLegacyMode();
        if (mManageOrHistoryButtonTextId == 0) {
            return; // not initialized yet
        }
@@ -204,6 +226,7 @@ public class FooterView extends StackScrollerDecorView {

    /** Set the accessibility content description for the "Clear all" button. */
    public void setManageOrHistoryButtonDescription(@StringRes int contentDescriptionId) {
        NotifRedesignFooter.assertInLegacyMode();
        if (FooterViewRefactor.isUnexpectedlyInLegacyMode()) {
            return;
        }
@@ -215,6 +238,7 @@ public class FooterView extends StackScrollerDecorView {
    }

    private void updateManageOrHistoryButtonDescription() {
        NotifRedesignFooter.assertInLegacyMode();
        if (mManageOrHistoryButtonDescriptionId == 0) {
            return; // not initialized yet
        }
@@ -273,7 +297,7 @@ public class FooterView extends StackScrollerDecorView {
        }
        super.onFinishInflate();
        mClearAllButton = (FooterViewButton) findSecondaryView();
        if (Flags.notificationsRedesignFooterView()) {
        if (NotifRedesignFooter.isEnabled()) {
            mSettingsButton = findViewById(R.id.settings_button);
            mHistoryButton = findViewById(R.id.history_button);
        } else {
@@ -311,11 +335,17 @@ public class FooterView extends StackScrollerDecorView {

    /** Set onClickListener for the notification settings button. */
    public void setSettingsButtonClickListener(OnClickListener listener) {
        if (NotifRedesignFooter.isUnexpectedlyInLegacyMode()) {
            return;
        }
        mSettingsButton.setOnClickListener(listener);
    }

    /** Set onClickListener for the notification history button. */
    public void setHistoryButtonClickListener(OnClickListener listener) {
        if (NotifRedesignFooter.isUnexpectedlyInLegacyMode()) {
            return;
        }
        mHistoryButton.setOnClickListener(listener);
    }

@@ -324,6 +354,7 @@ public class FooterView extends StackScrollerDecorView {
     * in the redesign.
     */
    public void setManageButtonClickListener(OnClickListener listener) {
        NotifRedesignFooter.assertInLegacyMode();
        mManageOrHistoryButton.setOnClickListener(listener);
    }

@@ -364,7 +395,7 @@ public class FooterView extends StackScrollerDecorView {
            updateClearAllButtonText();
            updateClearAllButtonDescription();

            if (!Flags.notificationsRedesignFooterView()) {
            if (!NotifRedesignFooter.isEnabled()) {
                updateManageOrHistoryButtonText();
                updateManageOrHistoryButtonDescription();
            }
@@ -444,7 +475,7 @@ public class FooterView extends StackScrollerDecorView {
        }
        mClearAllButton.setBackground(clearAllBg);
        mClearAllButton.setTextColor(onSurface);
        if (Flags.notificationsRedesignFooterView()) {
        if (NotifRedesignFooter.isEnabled()) {
            mSettingsButton.setBackground(manageBg);
            mSettingsButton.setCompoundDrawableTintList(ColorStateList.valueOf(onSurface));

+24 −8
Original line number Diff line number Diff line
@@ -20,11 +20,11 @@ import android.view.View
import androidx.lifecycle.lifecycleScope
import com.android.app.tracing.coroutines.launchTraced as launch
import com.android.internal.jank.InteractionJankMonitor
import com.android.systemui.Flags
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.statusbar.notification.NotificationActivityStarter
import com.android.systemui.statusbar.notification.NotificationActivityStarter.SettingsIntent
import com.android.systemui.statusbar.notification.emptyshade.shared.ModesEmptyShadeFix
import com.android.systemui.statusbar.notification.footer.shared.NotifRedesignFooter
import com.android.systemui.statusbar.notification.footer.ui.view.FooterView
import com.android.systemui.statusbar.notification.footer.ui.viewmodel.FooterViewModel
import com.android.systemui.util.ui.isAnimating
@@ -66,7 +66,7 @@ object FooterViewBinder {
        notificationActivityStarter: NotificationActivityStarter,
    ) = coroutineScope {
        launch { bindClearAllButton(footer, viewModel, clearAllNotifications) }
        if (!Flags.notificationsRedesignFooterView()) {
        if (!NotifRedesignFooter.isEnabled) {
            launch {
                bindManageOrHistoryButton(
                    footer,
@@ -77,8 +77,8 @@ object FooterViewBinder {
                )
            }
        } else {
            bindSettingsButtonListener(footer, notificationActivityStarter)
            bindHistoryButtonListener(footer, notificationActivityStarter)
            launch { bindSettingsButton(footer, viewModel, notificationActivityStarter) }
            launch { bindHistoryButton(footer, viewModel, notificationActivityStarter) }
        }
        launch { bindMessage(footer, viewModel) }
    }
@@ -122,10 +122,11 @@ object FooterViewBinder {
        }
    }

    private fun bindSettingsButtonListener(
    private suspend fun bindSettingsButton(
        footer: FooterView,
        viewModel: FooterViewModel,
        notificationActivityStarter: NotificationActivityStarter,
    ) {
    ) = coroutineScope {
        val settingsIntent =
            SettingsIntent.forNotificationSettings(
                cujType = InteractionJankMonitor.CUJ_SHADE_APP_LAUNCH_FROM_HISTORY_BUTTON
@@ -134,12 +135,20 @@ object FooterViewBinder {
            notificationActivityStarter.startSettingsIntent(view, settingsIntent)
        }
        footer.setSettingsButtonClickListener(onClickListener)

        launch {
            // NOTE: This visibility change is never animated. We also don't need to do anything
            // special about the onClickListener here, since we're changing the visibility to
            // GONE so it won't be clickable anyway.
            viewModel.settingsButtonVisible.collect { footer.setSettingsButtonVisible(it) }
        }
    }

    private fun bindHistoryButtonListener(
    private suspend fun bindHistoryButton(
        footer: FooterView,
        viewModel: FooterViewModel,
        notificationActivityStarter: NotificationActivityStarter,
    ) {
    ) = coroutineScope {
        val settingsIntent =
            SettingsIntent.forNotificationHistory(
                cujType = InteractionJankMonitor.CUJ_SHADE_APP_LAUNCH_FROM_HISTORY_BUTTON
@@ -148,6 +157,13 @@ object FooterViewBinder {
            notificationActivityStarter.startSettingsIntent(view, settingsIntent)
        }
        footer.setHistoryButtonClickListener(onClickListener)

        launch {
            // NOTE: This visibility change is never animated. We also don't need to do anything
            // special about the onClickListener here, since we're changing the visibility to
            // GONE so it won't be clickable anyway.
            viewModel.historyButtonVisible.collect { footer.setHistoryButtonVisible(it) }
        }
    }

    private suspend fun bindManageOrHistoryButton(
+4 −0
Original line number Diff line number Diff line
@@ -95,6 +95,10 @@ class FooterViewModel(
                    .toAnimatedValueFlow(),
        )

    // Settings buttons are not visible when the message is.
    val settingsButtonVisible: Flow<Boolean> = message.isVisible.map { !it }
    val historyButtonVisible: Flow<Boolean> = message.isVisible.map { !it }

    val manageButtonShouldLaunchHistory =
        notificationSettingsInteractor.isNotificationHistoryEnabled

Loading