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

Commit 41337ccb authored by Nicolo' Mazzucato's avatar Nicolo' Mazzucato
Browse files

Create skeleton for SystemUIDisplaySubcomponent

This creates only the structure, that will be used in follow up cls.

Bug: 403481022
Test: DisplayComponentInstanceProviderTest (in child cl)
Flag: NONE - subcomponent never instantiated for now.
Change-Id: I4dd08379f1462b182607bc463ff7d28cbe9e1938
parent 74151e8e
Loading
Loading
Loading
Loading
+65 −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.display.dagger

import android.content.Context
import android.view.Display
import com.android.app.displaylib.DisplayRepository
import com.android.systemui.coroutines.newTracingContext
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.display.dagger.SystemUIDisplaySubcomponent.DisplayAware
import com.android.systemui.display.dagger.SystemUIDisplaySubcomponent.DisplayId
import com.android.systemui.display.dagger.SystemUIDisplaySubcomponent.PerDisplaySingleton
import dagger.Module
import dagger.Provides
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope

/** Module providing common dependencies for per-display singletons. */
@Module
class PerDisplayCommonModule {

    @Provides
    @PerDisplaySingleton
    fun provideDisplay(@DisplayId displayId: Int, displayRepository: DisplayRepository): Display {
        return displayRepository.getDisplay(displayId)
            ?: error("Couldn't get the display with id=$displayId")
    }

    @Provides
    @PerDisplaySingleton
    @DisplayAware
    fun provideDisplayContext(
        display: Display,
        @Application context: Context,
    ): Context {
        return context.createDisplayContext(display)
    }

    @Provides
    @PerDisplaySingleton
    @DisplayAware
    fun provideDisplayCoroutineScope(
        @Background backgroundDispatcher: CoroutineDispatcher,
        @DisplayId displayId: Int,
    ): CoroutineScope {
        return CoroutineScope(
            backgroundDispatcher + newTracingContext("DisplayScope(id=$displayId)")
        )
    }
}
+55 −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.display.dagger

import dagger.BindsInstance
import dagger.Subcomponent
import javax.inject.Qualifier
import javax.inject.Scope
import kotlinx.coroutines.CoroutineScope

/**
 * Subcomponent for SysUI classes that should be instantiated once per display.
 *
 * All display specific classes should be provided with the @DisplayAware annotation. Once the
 * display is removed, [displayCoroutineScope] gets cancelled. This means that if classes have some
 * teardown step it should be executed when the scope is cancelled. Also note that the scope is
 * cancelled in the background, so any teardown logic should be threadsafe. Cancelling on the main
 * thread is not feasible as it would cause jank.
 */
@Subcomponent(modules = [PerDisplayCommonModule::class])
interface SystemUIDisplaySubcomponent {

    @DisplayAware val displayCoroutineScope: CoroutineScope

    @Subcomponent.Factory
    interface Factory {
        fun create(@BindsInstance @DisplayId displayId: Int): SystemUIDisplaySubcomponent
    }

    /** Scope annotation for singletons associated to a display. */
    @MustBeDocumented
    @Retention(AnnotationRetention.RUNTIME)
    @Scope
    annotation class PerDisplaySingleton

    /** Qualifier used to represent that the object is provided/bound with the proper display. */
    @Qualifier @Retention(AnnotationRetention.RUNTIME) annotation class DisplayAware

    /** Annotates the display id inside the subcomponent. */
    @Qualifier @Retention(AnnotationRetention.RUNTIME) annotation class DisplayId
}
+58 −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.display.data.repository

import com.android.app.displaylib.PerDisplayInstanceProviderWithTeardown
import com.android.app.displaylib.PerDisplayInstanceRepositoryImpl
import com.android.app.displaylib.PerDisplayRepository
import com.android.app.tracing.traceSection
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.display.dagger.SystemUIDisplaySubcomponent
import dagger.Module
import dagger.Provides
import javax.inject.Inject
import kotlinx.coroutines.cancel

@SysUISingleton
class DisplayComponentInstanceProvider
@Inject
constructor(private val componentFactory: SystemUIDisplaySubcomponent.Factory) :
    PerDisplayInstanceProviderWithTeardown<SystemUIDisplaySubcomponent> {
    override fun createInstance(displayId: Int): SystemUIDisplaySubcomponent? =
        runCatching { componentFactory.create(displayId) }.getOrNull()

    override fun destroyInstance(instance: SystemUIDisplaySubcomponent) {
        traceSection("Destroying a display component instance") {
            instance.displayCoroutineScope.cancel("Cancelling scope associated to the display.")
        }
    }
}

@Module
object DisplayComponentRepository {
    @SysUISingleton
    @Provides
    fun provideDisplayComponentRepository(
        repositoryFactory: PerDisplayInstanceRepositoryImpl.Factory<SystemUIDisplaySubcomponent>,
        instanceProvider: DisplayComponentInstanceProvider,
    ): PerDisplayRepository<SystemUIDisplaySubcomponent> {
        return repositoryFactory.create(
            debugName = "DisplayComponentInstanceProvider",
            instanceProvider,
        )
    }
}