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

Commit afacdac1 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Rebind bundle header to newly activated view-model" into main

parents a5beb4fa 2e57d229
Loading
Loading
Loading
Loading
+9 −25
Original line number Diff line number Diff line
@@ -16,7 +16,6 @@

package com.android.systemui.notifications.ui.composable.row

import android.content.Context
import android.graphics.drawable.Drawable
import androidx.compose.animation.core.FastOutSlowInEasing
import androidx.compose.animation.core.LinearEasing
@@ -35,7 +34,6 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
@@ -49,7 +47,6 @@ import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.layout.Layout
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow
@@ -61,18 +58,13 @@ import androidx.compose.ui.util.fastForEach
import androidx.compose.ui.util.fastMap
import androidx.compose.ui.util.fastMaxOfOrDefault
import androidx.compose.ui.util.fastSumBy
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
import com.android.compose.animation.scene.ContentScope
import com.android.compose.animation.scene.ElementKey
import com.android.compose.animation.scene.SceneKey
import com.android.compose.animation.scene.SceneTransitionLayout
import com.android.compose.animation.scene.rememberMutableSceneTransitionLayoutState
import com.android.compose.animation.scene.transitions
import com.android.compose.theme.PlatformTheme
import com.android.compose.ui.graphics.painter.rememberDrawablePainter
import com.android.systemui.initOnBackPressedDispatcherOwner
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.statusbar.notification.row.ui.viewmodel.BundleHeaderViewModel

object BundleHeader {
@@ -92,24 +84,13 @@ object BundleHeader {
    }
}

fun createComposeView(viewModel: BundleHeaderViewModel, context: Context): ComposeView {
    return ComposeView(context).apply {
        repeatWhenAttached {
            repeatOnLifecycle(Lifecycle.State.CREATED) {
                initOnBackPressedDispatcherOwner(this@repeatWhenAttached.lifecycle)
                setContent {
                    // TODO(b/399588047): Check if we can init PlatformTheme once instead of once
                    //  per ComposeView
                    PlatformTheme { BundleHeader(viewModel) }
                }
            }
        }
    }
}

@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun BundleHeader(viewModel: BundleHeaderViewModel, modifier: Modifier = Modifier) {
fun BundleHeader(
    viewModel: BundleHeaderViewModel,
    modifier: Modifier = Modifier,
    onHeaderClicked: () -> Unit = {},
) {
    val state =
        rememberMutableSceneTransitionLayoutState(
            initialScene = BundleHeader.Scenes.Collapsed,
@@ -163,7 +144,10 @@ fun BundleHeader(viewModel: BundleHeaderViewModel, modifier: Modifier = Modifier
            state = state,
            modifier =
                Modifier.clickable(
                    onClick = { viewModel.onHeaderClicked() },
                    onClick = {
                        viewModel.onHeaderClicked()
                        onHeaderClicked()
                    },
                    interactionSource = null,
                    indication = null,
                ),
+0 −5
Original line number Diff line number Diff line
@@ -17,7 +17,6 @@
package com.android.systemui.statusbar.notification.row.ui.viewmodel

import android.platform.test.annotations.EnableFlags
import android.view.View
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.compose.animation.scene.MutableSceneTransitionLayoutState
@@ -49,7 +48,6 @@ class BundleHeaderViewModelTest : SysuiTestCase() {

    @Mock lateinit var mockSceneTransitionLayoutState: MutableSceneTransitionLayoutState
    @Mock lateinit var mockComposeScope: CoroutineScope
    @Mock lateinit var onExpandClickListener: View.OnClickListener

    private lateinit var underTest: BundleHeaderViewModel

@@ -60,7 +58,6 @@ class BundleHeaderViewModelTest : SysuiTestCase() {

        underTest.state = mockSceneTransitionLayoutState
        underTest.composeScope = mockComposeScope
        underTest.onExpandClickListener = onExpandClickListener
    }

    @Test
@@ -75,7 +72,6 @@ class BundleHeaderViewModelTest : SysuiTestCase() {
        // Assert
        verify(mockSceneTransitionLayoutState)
            .setTargetScene(BundleHeader.Scenes.Expanded, mockComposeScope)
        verify(onExpandClickListener).onClick(null)
    }

    @Test
@@ -90,6 +86,5 @@ class BundleHeaderViewModelTest : SysuiTestCase() {
        // Assert
        verify(mockSceneTransitionLayoutState)
            .setTargetScene(BundleHeader.Scenes.Collapsed, mockComposeScope)
        verify(onExpandClickListener).onClick(null)
    }
}
+13 −5
Original line number Diff line number Diff line
@@ -121,7 +121,9 @@ public class NotificationChildrenContainerTest extends SysuiTestCase {
    @Test
    @EnableFlags(NotificationBundleUi.FLAG_NAME)
    public void testGetMaxAllowedVisibleChildren_bundle_likeCollapsed() {
        mChildrenContainer.initBundleHeader(mock(BundleHeaderViewModel.class));
        View headerView = new ComposeView(mContext);
        mChildrenContainer.setBundleHeaderView(headerView);
        mChildrenContainer.setBundleHeaderViewModel(mock(BundleHeaderViewModel.class));
        Assert.assertEquals(mChildrenContainer.getMaxAllowedVisibleChildren(true),
                NotificationChildrenContainer.NUMBER_OF_CHILDREN_BUNDLE_COLLAPSED);
    }
@@ -130,7 +132,9 @@ public class NotificationChildrenContainerTest extends SysuiTestCase {
    @Test
    @EnableFlags(NotificationBundleUi.FLAG_NAME)
    public void testGetMaxAllowedVisibleChildren_bundle_expandedChildren() {
        mChildrenContainer.initBundleHeader(mock(BundleHeaderViewModel.class));
        View headerView = new ComposeView(mContext);
        mChildrenContainer.setBundleHeaderView(headerView);
        mChildrenContainer.setBundleHeaderViewModel(mock(BundleHeaderViewModel.class));
        mChildrenContainer.setChildrenExpanded(true);
        Assert.assertEquals(mChildrenContainer.getMaxAllowedVisibleChildren(),
                NotificationChildrenContainer.NUMBER_OF_CHILDREN_BUNDLE_EXPANDED);
@@ -139,7 +143,9 @@ public class NotificationChildrenContainerTest extends SysuiTestCase {
    @Test
    @EnableFlags(NotificationBundleUi.FLAG_NAME)
    public void testGetMaxAllowedVisibleChildren_bundle_userLocked() {
        mChildrenContainer.initBundleHeader(mock(BundleHeaderViewModel.class));
        View headerView = new ComposeView(mContext);
        mChildrenContainer.setBundleHeaderView(headerView);
        mChildrenContainer.setBundleHeaderViewModel(mock(BundleHeaderViewModel.class));
        mGroup.setUserLocked(true);
        Assert.assertEquals(mChildrenContainer.getMaxAllowedVisibleChildren(),
                NotificationChildrenContainer.NUMBER_OF_CHILDREN_BUNDLE_EXPANDED);
@@ -311,12 +317,14 @@ public class NotificationChildrenContainerTest extends SysuiTestCase {
        View currentView = mChildrenContainer.getChildAt(mChildrenContainer.getChildCount() - 1);
        Assert.assertFalse(currentView instanceof ComposeView);

        View headerView = new ComposeView(mContext);
        mChildrenContainer.setBundleHeaderView(headerView);
        BundleHeaderViewModel viewModel = mKosmos.getBundleHeaderViewModel();
        mChildrenContainer.initBundleHeader(viewModel);
        mChildrenContainer.setBundleHeaderViewModel(viewModel);
        currentView = mChildrenContainer.getChildAt(mChildrenContainer.getChildCount() - 1);
        Assert.assertTrue(currentView instanceof ComposeView);

        mChildrenContainer.initBundleHeader(viewModel);
        mChildrenContainer.setBundleHeaderViewModel(viewModel);
        View finalView = mChildrenContainer.getChildAt(mChildrenContainer.getChildCount() - 1);
        Assert.assertEquals(currentView, finalView);
    }
+49 −14
Original line number Diff line number Diff line
@@ -18,10 +18,18 @@ package com.android.systemui.statusbar.notification.collection.render

import android.content.Context
import android.view.ViewGroup
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.ui.platform.ComposeView
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
import com.android.compose.theme.PlatformTheme
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.lifecycle.WindowLifecycleState
import com.android.systemui.initOnBackPressedDispatcherOwner
import com.android.systemui.lifecycle.rememberViewModel
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.lifecycle.viewModel
import com.android.systemui.notifications.ui.composable.row.BundleHeader
import com.android.systemui.settings.UserTracker
import com.android.systemui.shade.ShadeDisplayAware
import com.android.systemui.statusbar.NotificationPresenter
@@ -34,6 +42,7 @@ import com.android.systemui.statusbar.notification.row.RowInflaterTask
import com.android.systemui.statusbar.notification.row.RowInflaterTaskLogger
import com.android.systemui.statusbar.notification.row.dagger.BundleRowComponent
import com.android.systemui.statusbar.notification.row.dagger.ExpandableNotificationRowComponent
import com.android.systemui.statusbar.notification.row.ui.viewmodel.BundleHeaderViewModel
import com.android.systemui.statusbar.notification.stack.NotificationListContainer
import com.android.systemui.util.time.SystemClock
import dagger.Lazy
@@ -84,19 +93,7 @@ constructor(
            val controller = component.expandableNotificationRowController
            controller.init(bundleEntry)
            keyToControllerMap[bundleEntry.key] = controller

            val bundleRowComponent =
                bundleRowComponentBuilder.bindBundleRepository(bundleEntry.bundleRepository).build()

            row.repeatWhenAttached {
                row.viewModel(
                    traceName = "BundleHeaderViewModel",
                    minWindowLifecycleState = WindowLifecycleState.ATTACHED,
                    factory = bundleRowComponent.bundleViewModelFactory()::create,
                ) { viewModel ->
                    row.initBundleHeader(viewModel)
                }
            }
            initBundleHeaderView(bundleEntry, row)
        }
        debugBundleLog(TAG) { "calling inflate: ${bundleEntry.key}" }
        keyToControllerMap[bundleEntry.key] = null
@@ -105,6 +102,25 @@ constructor(
            .inflate(context, parent, bundleEntry, inflationFinishedListener)
    }

    private fun initBundleHeaderView(bundleEntry: BundleEntry, row: ExpandableNotificationRow) {
        val bundleRowComponent =
            bundleRowComponentBuilder.bindBundleRepository(bundleEntry.bundleRepository).build()
        val headerComposeView = ComposeView(context)
        row.setBundleHeaderView(headerComposeView)
        headerComposeView.repeatWhenAttached {
            repeatOnLifecycle(Lifecycle.State.CREATED) {
                headerComposeView.initOnBackPressedDispatcherOwner(lifecycle)
                headerComposeView.setContent {
                    HeaderComposeViewContent(
                        row = row,
                        bundleHeaderViewModelFactory =
                            bundleRowComponent.bundleViewModelFactory()::create,
                    )
                }
            }
        }
    }

    /** Return true if finished inflating. */
    fun isInflated(bundleEntry: BundleEntry): Boolean {
        return keyToControllerMap[bundleEntry.key] != null
@@ -142,4 +158,23 @@ constructor(
    }
}

@Composable
private fun HeaderComposeViewContent(
    row: ExpandableNotificationRow,
    bundleHeaderViewModelFactory: () -> BundleHeaderViewModel,
) {
    PlatformTheme {
        val viewModel =
            rememberViewModel(
                traceName = "BundleHeaderViewModel",
                factory = bundleHeaderViewModelFactory,
            )
        DisposableEffect(viewModel) {
            row.setBundleHeaderViewModel(viewModel)
            onDispose { row.setBundleHeaderViewModel(null) }
        }
        BundleHeader(viewModel, onHeaderClicked = { row.expandNotification() })
    }
}

private const val TAG = "BundleBarn"
+7 −8
Original line number Diff line number Diff line
@@ -1916,17 +1916,16 @@ public class ExpandableNotificationRow extends ActivatableNotificationView
        mRedactionType = redactionType;
    }

    /**
     * Init the bundle header view. The ComposeView is initialized within with the passed viewModel.
     * This can only be init once and not in conjunction with any other header view.
     */
    public void initBundleHeader(@NonNull BundleHeaderViewModel bundleHeaderViewModel) {
    public void setBundleHeaderView(@NonNull View view) {
        if (NotificationBundleUi.isUnexpectedlyInLegacyMode()) return;
        NotificationChildrenContainer childrenContainer = getChildrenContainerNonNull();
        bundleHeaderViewModel.setOnExpandClickListener(mExpandClickListener);

        childrenContainer.initBundleHeader(bundleHeaderViewModel);
        childrenContainer.setBundleHeaderView(view);
    }

    public void setBundleHeaderViewModel(@Nullable BundleHeaderViewModel viewModel) {
        if (NotificationBundleUi.isUnexpectedlyInLegacyMode()) return;
        NotificationChildrenContainer childrenContainer = getChildrenContainerNonNull();
        childrenContainer.setBundleHeaderViewModel(viewModel);
        if (TransparentHeaderFix.isEnabled()) {
            updateBackgroundForGroupState();
        }
Loading