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

Commit 2548b4b2 authored by Steve Elliott's avatar Steve Elliott Committed by Android (Google) Code Review
Browse files

Merge "Introduce NICViewModel#isolatedIcon and location" into main

parents 88cfb8b7 180f9289
Loading
Loading
Loading
Loading
+30 −0
Original line number Diff line number Diff line
/*
 * 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.data.repository

import android.graphics.Rect
import com.android.systemui.dagger.SysUISingleton
import javax.inject.Inject
import kotlinx.coroutines.flow.MutableStateFlow

/** View-states pertaining to heads-up notification icons. */
@SysUISingleton
class HeadsUpNotificationIconViewStateRepository @Inject constructor() {
    /** Notification key for a notification icon to show isolated, or `null` if none. */
    val isolatedNotification = MutableStateFlow<String?>(null)
    /** Area to display the isolated notification, or `null` if none. */
    val isolatedIconLocation = MutableStateFlow<Rect?>(null)
}
+44 −0
Original line number Diff line number Diff line
/*
 * 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.domain.interactor

import android.graphics.Rect
import com.android.systemui.statusbar.notification.data.repository.HeadsUpNotificationIconViewStateRepository
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow

/** Domain logic pertaining to heads up notification icons. */
class HeadsUpNotificationIconInteractor
@Inject
constructor(
    private val repository: HeadsUpNotificationIconViewStateRepository,
) {
    /** Notification key for a notification icon to show isolated, or `null` if none. */
    val isolatedIconLocation: Flow<Rect?> = repository.isolatedIconLocation

    /** Area to display the isolated notification, or `null` if none. */
    val isolatedNotification: Flow<String?> = repository.isolatedNotification

    /** Updates the location where isolated notification icons are shown. */
    fun setIsolatedIconLocation(rect: Rect?) {
        repository.isolatedIconLocation.value = rect
    }

    /** Updates which notification will have its icon displayed isolated. */
    fun setIsolatedIconNotificationKey(key: String?) {
        repository.isolatedNotification.value = key
    }
}
+3 −6
Original line number Diff line number Diff line
@@ -136,13 +136,10 @@ constructor(

    override fun updateAodNotificationIcons() = unsupported

    override fun showIconIsolated(icon: StatusBarIconView?, animated: Boolean) {
        notificationIcons!!.showIconIsolated(icon, animated)
    }
    override fun showIconIsolated(icon: StatusBarIconView?, animated: Boolean) = unsupported

    override fun setIsolatedIconLocation(iconDrawingRect: Rect, requireStateUpdate: Boolean) {
        notificationIcons!!.setIsolatedIconLocation(iconDrawingRect, requireStateUpdate)
    }
    override fun setIsolatedIconLocation(iconDrawingRect: Rect, requireStateUpdate: Boolean) =
        unsupported

    override fun setAnimationsEnabled(enabled: Boolean) = unsupported

+69 −25
Original line number Diff line number Diff line
@@ -77,8 +77,56 @@ object NotificationIconContainerViewBinder {
        val contrastColorUtil = ContrastColorUtil.getInstance(view.context)
        return view.repeatWhenAttached {
            repeatOnLifecycle(Lifecycle.State.CREATED) {
                launch { viewModel.animationsEnabled.collect(view::setAnimationsEnabled) }
                launch { bindAnimationsEnabled(viewModel, view) }
                launch { bindIsDozing(viewModel, view, dozeParameters) }
                // TODO(b/278765923): this should live where AOD is bound, not inside of the NIC
                //  view-binder
                launch {
                    bindVisibility(
                        viewModel,
                        view,
                        configuration,
                        featureFlags,
                        screenOffAnimationController,
                    )
                }
                launch { bindIconColors(viewModel, view, contrastColorUtil) }
                launch {
                    bindIconViewData(
                        viewModel,
                        view,
                        configuration,
                        configurationController,
                        viewStore,
                    )
                }
                launch { bindIsolatedIcon(viewModel, view, viewStore) }
            }
        }
    }

    private suspend fun bindAnimationsEnabled(
        viewModel: NotificationIconContainerViewModel,
        view: NotificationIconContainer
    ) {
        viewModel.animationsEnabled.collect(view::setAnimationsEnabled)
    }

    private suspend fun bindIconColors(
        viewModel: NotificationIconContainerViewModel,
        view: NotificationIconContainer,
        contrastColorUtil: ContrastColorUtil,
    ) {
        viewModel.iconColors
            .mapNotNull { lookup -> lookup.iconColors(view.viewBounds) }
            .collect { iconLookup -> applyTint(view, iconLookup, contrastColorUtil) }
    }

    private suspend fun bindIsDozing(
        viewModel: NotificationIconContainerViewModel,
        view: NotificationIconContainer,
        dozeParameters: DozeParameters,
    ) {
        viewModel.isDozing.collect { isDozing ->
            if (isDozing.isAnimating) {
                val animate = !dozeParameters.displayNeedsBlanking
@@ -97,30 +145,26 @@ object NotificationIconContainerViewBinder {
            }
        }
    }
                // TODO(b/278765923): this should live where AOD is bound, not inside of the NIC
                //  view-binder

    private suspend fun bindIsolatedIcon(
        viewModel: NotificationIconContainerViewModel,
        view: NotificationIconContainer,
        viewStore: IconViewStore,
    ) {
        coroutineScope {
            launch {
                    bindVisibility(
                        viewModel,
                        view,
                        configuration,
                        featureFlags,
                        screenOffAnimationController,
                    )
                viewModel.isolatedIconLocation.collect { location ->
                    view.setIsolatedIconLocation(location, true)
                }
                launch {
                    viewModel.iconColors
                        .mapNotNull { lookup -> lookup.iconColors(view.viewBounds) }
                        .collect { iconLookup -> applyTint(view, iconLookup, contrastColorUtil) }
            }
            launch {
                    bindIconViewData(
                        viewModel,
                        view,
                        configuration,
                        configurationController,
                        viewStore,
                    )
                viewModel.isolatedIcon.collect { iconInfo ->
                    val iconView = iconInfo.value?.let { viewStore.iconView(it.notifKey) }
                    if (iconInfo.isAnimating) {
                        view.showIconIsolatedAnimated(iconView, iconInfo::stopAnimating)
                    } else {
                        view.showIconIsolated(iconView)
                    }
                }
            }
        }
+7 −0
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@ import com.android.systemui.statusbar.notification.domain.interactor.Notificatio
import com.android.systemui.statusbar.notification.icon.domain.interactor.AlwaysOnDisplayNotificationIconsInteractor
import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerViewModel.ColorLookup
import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerViewModel.IconColors
import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerViewModel.IconInfo
import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerViewModel.IconsViewData
import com.android.systemui.statusbar.phone.DozeParameters
import com.android.systemui.statusbar.phone.ScreenOffAnimationController
@@ -46,6 +47,8 @@ import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.emptyFlow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map

/** View-model for the row of notification icons displayed on the always-on display. */
@@ -140,6 +143,10 @@ constructor(
            )
        }

    override val isolatedIcon: Flow<AnimatedValue<IconInfo?>> =
        flowOf(AnimatedValue.NotAnimating(null))
    override val isolatedIconLocation: Flow<Rect> = emptyFlow()

    /** Is there an expanded pulse, are we animating in response? */
    private fun isPulseExpandingAnimated(): Flow<AnimatedValue<Boolean>> {
        return notificationsKeyguardInteractor.isPulseExpanding
Loading