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

Commit 66eb980c authored by Chandru S's avatar Chandru S Committed by Tracy Zhou
Browse files

Add a flow that can be used to determine whether cross window blur is enabled/supported right now.

CrossWindowBlurListeners handles the following checks for blur:
 1. whether the device supports blur or not (ro.surface_flinger.supports_background_blur property)
 2. whether battery saver is enabled or not
 3. whether critical thermal status has reached or not
 4. whether blur is disabled in dev settings or not
 5. whether multimedia tunneling is enabled or not.

Repository adds two additional checks:
 1. whether persist.sysui.disableBlur is set or not (used by tests)
 2. whether ActivityManager.isHighEndGfx is true or not, BlurUtils has this check before enabling or disabling blur.

Bug: 391409723
Test: Tried adding unit tests but it might be flakey because of ActivityManager.isHighEndGfx check, it is unclear how this can be mocked
Flag: com.android.systemui.bouncer_ui_revamp
Change-Id: Ie4ec36e132fef04a40bd3e0c054065554be1b302
parent 34c706fb
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -45,13 +45,17 @@ import com.android.systemui.shade.domain.interactor.ShadeLockscreenInteractor
import com.android.systemui.shade.domain.interactor.ShadeLockscreenInteractorImpl
import com.android.systemui.shade.domain.interactor.ShadeModeInteractor
import com.android.systemui.shade.domain.interactor.ShadeModeInteractorImpl
import com.android.systemui.window.dagger.WindowRootViewBlurModule
import dagger.Binds
import dagger.Module
import dagger.Provides
import javax.inject.Provider

/** Module for classes related to the notification shade. */
@Module(includes = [StartShadeModule::class, ShadeViewProviderModule::class])
@Module(
    includes =
        [StartShadeModule::class, ShadeViewProviderModule::class, WindowRootViewBlurModule::class]
)
abstract class ShadeModule {
    companion object {
        @Provides
+35 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 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.window.dagger

import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.window.data.repository.WindowRootViewBlurRepository
import com.android.systemui.window.data.repository.WindowRootViewBlurRepositoryImpl
import dagger.Binds
import dagger.Module

/**
 * Module that can be installed in sysui variants where we support cross window blur.
 */
@Module
interface WindowRootViewBlurModule {
    @Binds
    @SysUISingleton
    fun bindWindowRootViewBlurRepository(
        windowRootViewBlurRepositoryImpl: WindowRootViewBlurRepositoryImpl
    ): WindowRootViewBlurRepository
}
+35 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 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.window.dagger

import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.window.data.repository.NoopWindowRootViewBlurRepository
import com.android.systemui.window.data.repository.WindowRootViewBlurRepository
import dagger.Binds
import dagger.Module

/**
 * Module that can be installed in sysui variants where we don't support cross window blur.
 */
@Module
interface WindowRootViewBlurNotSupportedModule {
    @Binds
    @SysUISingleton
    fun bindWindowRootViewBlurRepository(
        windowRootViewBlurRepositoryImpl: NoopWindowRootViewBlurRepository
    ): WindowRootViewBlurRepository
}
+28 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 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.window.data.repository

import com.android.systemui.window.data.repository.WindowRootViewBlurRepository
import javax.inject.Inject
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow

class NoopWindowRootViewBlurRepository @Inject constructor() : WindowRootViewBlurRepository {
    override val blurRadius: MutableStateFlow<Int> = MutableStateFlow(0)
    override val isBlurOpaque: MutableStateFlow<Boolean> = MutableStateFlow(true)
    override val isBlurSupported: StateFlow<Boolean> = MutableStateFlow(false)
}
 No newline at end of file
+57 −3
Original line number Diff line number Diff line
@@ -16,14 +16,68 @@

package com.android.systemui.window.data.repository

import android.app.ActivityManager
import android.os.SystemProperties
import android.view.CrossWindowBlurListeners
import com.android.systemui.common.coroutine.ChannelExt.trySendWithFailureLogging
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow
import java.util.concurrent.Executor
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.stateIn

/** Repository that maintains state for the window blur effect. */
interface WindowRootViewBlurRepository {
    val blurRadius: MutableStateFlow<Int>
    val isBlurOpaque: MutableStateFlow<Boolean>

    /** Is blur supported based on settings toggle and battery power saver mode. */
    val isBlurSupported: StateFlow<Boolean>
}

@SysUISingleton
class WindowRootViewBlurRepository @Inject constructor() {
    val blurRadius = MutableStateFlow(0)
class WindowRootViewBlurRepositoryImpl
@Inject
constructor(
    crossWindowBlurListeners: CrossWindowBlurListeners,
    @Main private val executor: Executor,
    @Application private val scope: CoroutineScope,
) : WindowRootViewBlurRepository {
    override val blurRadius = MutableStateFlow(0)

    override val isBlurOpaque = MutableStateFlow(false)

    override val isBlurSupported: StateFlow<Boolean> =
        conflatedCallbackFlow {
                val sendUpdate = { value: Boolean ->
                    trySendWithFailureLogging(
                        !isBlurExplicitlyDisabled() && value,
                        TAG,
                        "unable to send blur enabled/disable state change",
                    )
                }
                crossWindowBlurListeners.addListener(executor, sendUpdate)
                sendUpdate(crossWindowBlurListeners.isCrossWindowBlurEnabled)

                awaitClose { crossWindowBlurListeners.removeListener(sendUpdate) }
            } // stateIn because this is backed by a binder call.
            .stateIn(scope, SharingStarted.WhileSubscribed(), false)

    val isBlurOpaque = MutableStateFlow(false)
    private fun isBlurExplicitlyDisabled(): Boolean {
        return !ActivityManager.isHighEndGfx() ||
            SystemProperties.getBoolean(DISABLE_BLUR_PROPERTY, false)
    }

    companion object {
        const val TAG = "WindowRootViewBlurRepository"
        // property that can be used to disable the cross window blur for tests
        private const val DISABLE_BLUR_PROPERTY = "persist.sysui.disableBlur"
    }
}
Loading