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

Commit 3bf7386d authored by Jeff DeCew's avatar Jeff DeCew Committed by Android (Google) Code Review
Browse files

Merge "Pause ViewFlippers while lock screen is showing" into 24D1-dev

parents f8cf5e9a ae0c57f4
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -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"
+7 −1
Original line number Diff line number Diff line
@@ -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>
@@ -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)
@@ -41,5 +44,8 @@ constructor(
        if (notifLinearlayoutOptimized()) {
            add(optimizedLinearLayoutFactory)
        }
        if (NotificationViewFlipperPausing.isEnabled) {
            add(notificationViewFlipperFactory.get())
        }
    }
}
+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
        }
    }
}
+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()
        }
    }
}
+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