Loading packages/SystemUI/aconfig/systemui.aconfig +10 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,16 @@ flag { } } flag { name: "notification_view_flipper_pausing" namespace: "systemui" description: "Pause ViewFlippers inside Notification custom layouts when the shade is closed." bug: "309146176" metadata { purpose: PURPOSE_BUGFIX } } flag { name: "notification_async_group_header_inflation" namespace: "systemui" Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifRemoteViewsFactoryContainer.kt +7 −1 Original line number Diff line number Diff line Loading @@ -19,7 +19,9 @@ package com.android.systemui.statusbar.notification.row import android.widget.flags.Flags.notifLinearlayoutOptimized import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.Flags import com.android.systemui.statusbar.notification.shared.NotificationViewFlipperPausing import javax.inject.Inject import javax.inject.Provider interface NotifRemoteViewsFactoryContainer { val factories: Set<NotifRemoteViewsFactory> Loading @@ -31,7 +33,8 @@ constructor( featureFlags: FeatureFlags, precomputedTextViewFactory: PrecomputedTextViewFactory, bigPictureLayoutInflaterFactory: BigPictureLayoutInflaterFactory, optimizedLinearLayoutFactory: NotificationOptimizedLinearLayoutFactory optimizedLinearLayoutFactory: NotificationOptimizedLinearLayoutFactory, notificationViewFlipperFactory: Provider<NotificationViewFlipperFactory>, ) : NotifRemoteViewsFactoryContainer { override val factories: Set<NotifRemoteViewsFactory> = buildSet { add(precomputedTextViewFactory) Loading @@ -41,5 +44,8 @@ constructor( if (notifLinearlayoutOptimized()) { add(optimizedLinearLayoutFactory) } if (NotificationViewFlipperPausing.isEnabled) { add(notificationViewFlipperFactory.get()) } } } packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationViewFlipperFactory.kt 0 → 100644 +59 −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.row import android.content.Context import android.util.AttributeSet import android.view.View import android.widget.ViewFlipper import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag import com.android.systemui.statusbar.notification.row.ui.viewbinder.NotificationViewFlipperBinder import com.android.systemui.statusbar.notification.row.ui.viewmodel.NotificationViewFlipperViewModel import com.android.systemui.statusbar.notification.shared.NotificationViewFlipperPausing import javax.inject.Inject /** * A factory which owns the construction of any ViewFlipper inside of Notifications, and binds it * with a view model. This ensures that ViewFlippers are paused when the keyguard is showing. */ class NotificationViewFlipperFactory @Inject constructor( private val viewModel: NotificationViewFlipperViewModel, ) : NotifRemoteViewsFactory { init { /* check if */ NotificationViewFlipperPausing.isUnexpectedlyInLegacyMode() } override fun instantiate( row: ExpandableNotificationRow, @InflationFlag layoutType: Int, parent: View?, name: String, context: Context, attrs: AttributeSet ): View? { return when (name) { ViewFlipper::class.java.name, ViewFlipper::class.java.simpleName -> ViewFlipper(context, attrs).also { viewFlipper -> NotificationViewFlipperBinder.bindWhileAttached(viewFlipper, viewModel) } else -> null } } } packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewbinder/NotificationViewFlipperBinder.kt 0 → 100644 +54 −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.row.ui.viewbinder import android.widget.ViewFlipper import androidx.lifecycle.lifecycleScope import com.android.systemui.lifecycle.repeatWhenAttached import com.android.systemui.statusbar.notification.row.ui.viewmodel.NotificationViewFlipperViewModel import kotlinx.coroutines.DisposableHandle import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.launch /** Binds a [NotificationViewFlipper] to its [view model][NotificationViewFlipperViewModel]. */ object NotificationViewFlipperBinder { fun bindWhileAttached( viewFlipper: ViewFlipper, viewModel: NotificationViewFlipperViewModel, ): DisposableHandle { if (viewFlipper.isAutoStart) { // If the ViewFlipper is not set to AutoStart, the pause binding is meaningless return DisposableHandle {} } return viewFlipper.repeatWhenAttached { lifecycleScope.launch { bind(viewFlipper, viewModel) } } } suspend fun bind( viewFlipper: ViewFlipper, viewModel: NotificationViewFlipperViewModel, ) = coroutineScope { launch { viewModel.isPaused.collect { viewFlipper.setPaused(it) } } } private fun ViewFlipper.setPaused(paused: Boolean) { if (paused) { stopFlipping() } else if (isAutoStart) { startFlipping() } } } packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/NotificationViewFlipperViewModel.kt 0 → 100644 +39 −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.row.ui.viewmodel import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dump.DumpManager import com.android.systemui.statusbar.notification.shared.NotificationViewFlipperPausing import com.android.systemui.statusbar.notification.stack.domain.interactor.NotificationStackInteractor import com.android.systemui.util.kotlin.FlowDumperImpl import javax.inject.Inject /** A model which represents whether ViewFlippers inside notifications should be paused. */ @SysUISingleton class NotificationViewFlipperViewModel @Inject constructor( dumpManager: DumpManager, stackInteractor: NotificationStackInteractor, ) : FlowDumperImpl(dumpManager) { init { /* check if */ NotificationViewFlipperPausing.isUnexpectedlyInLegacyMode() } val isPaused = stackInteractor.isShowingOnLockscreen.dumpWhileCollecting("isPaused") } Loading
packages/SystemUI/aconfig/systemui.aconfig +10 −0 Original line number Diff line number Diff line Loading @@ -24,6 +24,16 @@ flag { } } flag { name: "notification_view_flipper_pausing" namespace: "systemui" description: "Pause ViewFlippers inside Notification custom layouts when the shade is closed." bug: "309146176" metadata { purpose: PURPOSE_BUGFIX } } flag { name: "notification_async_group_header_inflation" namespace: "systemui" Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotifRemoteViewsFactoryContainer.kt +7 −1 Original line number Diff line number Diff line Loading @@ -19,7 +19,9 @@ package com.android.systemui.statusbar.notification.row import android.widget.flags.Flags.notifLinearlayoutOptimized import com.android.systemui.flags.FeatureFlags import com.android.systemui.flags.Flags import com.android.systemui.statusbar.notification.shared.NotificationViewFlipperPausing import javax.inject.Inject import javax.inject.Provider interface NotifRemoteViewsFactoryContainer { val factories: Set<NotifRemoteViewsFactory> Loading @@ -31,7 +33,8 @@ constructor( featureFlags: FeatureFlags, precomputedTextViewFactory: PrecomputedTextViewFactory, bigPictureLayoutInflaterFactory: BigPictureLayoutInflaterFactory, optimizedLinearLayoutFactory: NotificationOptimizedLinearLayoutFactory optimizedLinearLayoutFactory: NotificationOptimizedLinearLayoutFactory, notificationViewFlipperFactory: Provider<NotificationViewFlipperFactory>, ) : NotifRemoteViewsFactoryContainer { override val factories: Set<NotifRemoteViewsFactory> = buildSet { add(precomputedTextViewFactory) Loading @@ -41,5 +44,8 @@ constructor( if (notifLinearlayoutOptimized()) { add(optimizedLinearLayoutFactory) } if (NotificationViewFlipperPausing.isEnabled) { add(notificationViewFlipperFactory.get()) } } }
packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationViewFlipperFactory.kt 0 → 100644 +59 −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.row import android.content.Context import android.util.AttributeSet import android.view.View import android.widget.ViewFlipper import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag import com.android.systemui.statusbar.notification.row.ui.viewbinder.NotificationViewFlipperBinder import com.android.systemui.statusbar.notification.row.ui.viewmodel.NotificationViewFlipperViewModel import com.android.systemui.statusbar.notification.shared.NotificationViewFlipperPausing import javax.inject.Inject /** * A factory which owns the construction of any ViewFlipper inside of Notifications, and binds it * with a view model. This ensures that ViewFlippers are paused when the keyguard is showing. */ class NotificationViewFlipperFactory @Inject constructor( private val viewModel: NotificationViewFlipperViewModel, ) : NotifRemoteViewsFactory { init { /* check if */ NotificationViewFlipperPausing.isUnexpectedlyInLegacyMode() } override fun instantiate( row: ExpandableNotificationRow, @InflationFlag layoutType: Int, parent: View?, name: String, context: Context, attrs: AttributeSet ): View? { return when (name) { ViewFlipper::class.java.name, ViewFlipper::class.java.simpleName -> ViewFlipper(context, attrs).also { viewFlipper -> NotificationViewFlipperBinder.bindWhileAttached(viewFlipper, viewModel) } else -> null } } }
packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewbinder/NotificationViewFlipperBinder.kt 0 → 100644 +54 −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.row.ui.viewbinder import android.widget.ViewFlipper import androidx.lifecycle.lifecycleScope import com.android.systemui.lifecycle.repeatWhenAttached import com.android.systemui.statusbar.notification.row.ui.viewmodel.NotificationViewFlipperViewModel import kotlinx.coroutines.DisposableHandle import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.launch /** Binds a [NotificationViewFlipper] to its [view model][NotificationViewFlipperViewModel]. */ object NotificationViewFlipperBinder { fun bindWhileAttached( viewFlipper: ViewFlipper, viewModel: NotificationViewFlipperViewModel, ): DisposableHandle { if (viewFlipper.isAutoStart) { // If the ViewFlipper is not set to AutoStart, the pause binding is meaningless return DisposableHandle {} } return viewFlipper.repeatWhenAttached { lifecycleScope.launch { bind(viewFlipper, viewModel) } } } suspend fun bind( viewFlipper: ViewFlipper, viewModel: NotificationViewFlipperViewModel, ) = coroutineScope { launch { viewModel.isPaused.collect { viewFlipper.setPaused(it) } } } private fun ViewFlipper.setPaused(paused: Boolean) { if (paused) { stopFlipping() } else if (isAutoStart) { startFlipping() } } }
packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/NotificationViewFlipperViewModel.kt 0 → 100644 +39 −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.row.ui.viewmodel import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dump.DumpManager import com.android.systemui.statusbar.notification.shared.NotificationViewFlipperPausing import com.android.systemui.statusbar.notification.stack.domain.interactor.NotificationStackInteractor import com.android.systemui.util.kotlin.FlowDumperImpl import javax.inject.Inject /** A model which represents whether ViewFlippers inside notifications should be paused. */ @SysUISingleton class NotificationViewFlipperViewModel @Inject constructor( dumpManager: DumpManager, stackInteractor: NotificationStackInteractor, ) : FlowDumperImpl(dumpManager) { init { /* check if */ NotificationViewFlipperPausing.isUnexpectedlyInLegacyMode() } val isPaused = stackInteractor.isShowingOnLockscreen.dumpWhileCollecting("isPaused") }