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

Commit ac7d7a07 authored by Austin Wang's avatar Austin Wang
Browse files

Fixed leak and no clock carousel (1/3)

Previously, ClockRegistry is bond to activity lifecycle and it's not stable with unregister call followed by register in a short period of time.

Remove the register/unregister ClockRegistry from ClockRegistryProvider (used in activity), and move to app level singleton. Register ClockRegistry listeners when app started and cleaned up when app ended.

Bug: 285348630
Bug: 285321790
Test: resume/destroy WPP then launch LS tab
Test: rotate foldable inner screen
Test: run profiler check no related leaks
Change-Id: I5b9d8eba17b3164a3da5f81058c5c6c90f6a2272
parent c424efb6
Loading
Loading
Loading
Loading
+1 −4
Original line number Diff line number Diff line
@@ -18,7 +18,6 @@ package com.android.customization.module
import android.content.Context
import androidx.activity.ComponentActivity
import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.LifecycleOwner
import com.android.customization.model.theme.OverlayManagerCompat
import com.android.customization.model.theme.ThemeBundleProvider
import com.android.customization.model.theme.ThemeManager
@@ -48,13 +47,12 @@ interface CustomizationInjector : Injector {
        context: Context,
    ): KeyguardQuickAffordancePickerInteractor

    fun getClockRegistry(context: Context, lifecycleOwner: LifecycleOwner): ClockRegistry
    fun getClockRegistry(context: Context): ClockRegistry?

    fun getClockPickerInteractor(context: Context): ClockPickerInteractor

    fun getClockSectionViewModel(
        context: Context,
        lifecycleOwner: LifecycleOwner
    ): ClockSectionViewModel

    fun getColorPickerInteractor(
@@ -77,6 +75,5 @@ interface CustomizationInjector : Injector {
        context: Context,
        wallpaperColorsViewModel: WallpaperColorsViewModel,
        clockViewFactory: ClockViewFactory,
        lifecycleOwner: LifecycleOwner,
    ): ClockSettingsViewModel.Factory
}
+21 −28
Original line number Diff line number Diff line
@@ -196,16 +196,12 @@ open class ThemePickerInjector : WallpaperPicker2Injector(), CustomizationInject

    override fun getSnapshotRestorers(
        context: Context,
        lifecycleOwner: LifecycleOwner
    ): Map<Int, SnapshotRestorer> {
        return super<WallpaperPicker2Injector>.getSnapshotRestorers(context, lifecycleOwner)
            .toMutableMap()
            .apply {
        return super<WallpaperPicker2Injector>.getSnapshotRestorers(context).toMutableMap().apply {
            this[KEY_QUICK_AFFORDANCE_SNAPSHOT_RESTORER] =
                getKeyguardQuickAffordanceSnapshotRestorer(context)
            this[KEY_WALLPAPER_SNAPSHOT_RESTORER] = getWallpaperSnapshotRestorer(context)
                this[KEY_NOTIFICATIONS_SNAPSHOT_RESTORER] =
                    getNotificationsSnapshotRestorer(context)
            this[KEY_NOTIFICATIONS_SNAPSHOT_RESTORER] = getNotificationsSnapshotRestorer(context)
            this[KEY_DARK_MODE_SNAPSHOT_RESTORER] = getDarkModeSnapshotRestorer(context)
            this[KEY_THEMED_ICON_SNAPSHOT_RESTORER] = getThemedIconSnapshotRestorer(context)
            this[KEY_APP_GRID_SNAPSHOT_RESTORER] = getGridSnapshotRestorer(context)
@@ -347,7 +343,7 @@ open class ThemePickerInjector : WallpaperPicker2Injector(), CustomizationInject
                .also { notificationsSnapshotRestorer = it }
    }

    override fun getClockRegistry(context: Context, lifecycleOwner: LifecycleOwner): ClockRegistry {
    override fun getClockRegistry(context: Context): ClockRegistry {
        return (clockRegistryProvider
                ?: ClockRegistryProvider(
                        context = context.applicationContext,
@@ -356,7 +352,7 @@ open class ThemePickerInjector : WallpaperPicker2Injector(), CustomizationInject
                        backgroundDispatcher = Dispatchers.IO,
                    )
                    .also { clockRegistryProvider = it })
            .getForOwner(lifecycleOwner)
            .get()
    }

    override fun getClockPickerInteractor(
@@ -367,9 +363,8 @@ open class ThemePickerInjector : WallpaperPicker2Injector(), CustomizationInject
            ?: ClockPickerInteractor(
                    repository =
                        ClockPickerRepositoryImpl(
                            secureSettingsRepository = getSecureSettingsRepository(context),
                            // TODO (b/285978251): remove second argument once b/285348630 is fixed
                            registry = getClockRegistry(context, context as LifecycleOwner),
                            secureSettingsRepository = getSecureSettingsRepository(appContext),
                            registry = getClockRegistry(appContext),
                            scope = getApplicationCoroutineScope(),
                            mainDispatcher = Dispatchers.Main,
                        ),
@@ -380,10 +375,12 @@ open class ThemePickerInjector : WallpaperPicker2Injector(), CustomizationInject

    override fun getClockSectionViewModel(
        context: Context,
        lifecycleOwner: LifecycleOwner
    ): ClockSectionViewModel {
        return clockSectionViewModel
            ?: ClockSectionViewModel(context.applicationContext, getClockPickerInteractor(context))
            ?: ClockSectionViewModel(
                    context.applicationContext,
                    getClockPickerInteractor(context.applicationContext)
                )
                .also { clockSectionViewModel = it }
    }

@@ -404,10 +401,7 @@ open class ThemePickerInjector : WallpaperPicker2Injector(), CustomizationInject
                    ScreenSizeCalculator.getInstance()
                        .getScreenSize(activity.windowManager.defaultDisplay),
                    WallpaperManager.getInstance(activity.applicationContext),
                    getClockRegistry(
                        context = activity.applicationContext,
                        lifecycleOwner = activity,
                    ),
                    getClockRegistry(activity.applicationContext),
                )
                .also {
                    clockViewFactories[activityHashCode] = it
@@ -521,7 +515,6 @@ open class ThemePickerInjector : WallpaperPicker2Injector(), CustomizationInject
        context: Context,
        wallpaperColorsViewModel: WallpaperColorsViewModel,
        clockViewFactory: ClockViewFactory,
        lifecycleOwner: LifecycleOwner,
    ): ClockSettingsViewModel.Factory {
        return clockSettingsViewModelFactory
            ?: ClockSettingsViewModel.Factory(
+15 −39
Original line number Diff line number Diff line
@@ -19,8 +19,6 @@ import android.app.NotificationManager
import android.content.ComponentName
import android.content.Context
import android.view.LayoutInflater
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
import com.android.systemui.plugins.Plugin
import com.android.systemui.plugins.PluginManager
import com.android.systemui.shared.clocks.ClockRegistry
@@ -45,12 +43,10 @@ class ClockRegistryProvider(
    private val mainDispatcher: CoroutineDispatcher,
    private val backgroundDispatcher: CoroutineDispatcher,
) {
    private val lifecycleOwners = mutableSetOf<Int>()
    private val pluginManager: PluginManager by lazy { createPluginManager(context) }
    private val clockRegistry: ClockRegistry by lazy {
        ClockRegistry(
            context,
                pluginManager,
            createPluginManager(context),
            coroutineScope,
            mainDispatcher,
            backgroundDispatcher,
@@ -60,34 +56,14 @@ class ClockRegistryProvider(
            keepAllLoaded = true,
            subTag = "Picker",
        )
            .apply { registerListeners() }
    }

    fun getForOwner(lifecycleOwner: LifecycleOwner): ClockRegistry {
        registerLifecycleOwner(lifecycleOwner)
        return clockRegistry
    init {
        // Listeners in ClockRegistry get cleaned up when app ended
        clockRegistry.registerListeners()
    }

    private fun registerLifecycleOwner(lifecycleOwner: LifecycleOwner) {
        lifecycleOwners.add(lifecycleOwner.hashCode())

        lifecycleOwner.lifecycle.addObserver(
            object : DefaultLifecycleObserver {
                override fun onDestroy(owner: LifecycleOwner) {
                    super.onDestroy(owner)
                    unregisterLifecycleOwner(owner)
                }
            }
        )
    }

    private fun unregisterLifecycleOwner(lifecycleOwner: LifecycleOwner) {
        lifecycleOwners.remove(lifecycleOwner.hashCode())

        if (lifecycleOwners.isEmpty()) {
            clockRegistry.unregisterListeners()
        }
    }
    fun get() = clockRegistry

    private fun createPluginManager(context: Context): PluginManager {
        val privilegedPlugins = listOf<String>()
+0 −1
Original line number Diff line number Diff line
@@ -37,7 +37,6 @@ class ClockCustomDemoFragment : AppbarFragment() {
        clockRegistry =
            (InjectorProvider.getInjector() as ThemePickerInjector).getClockRegistry(
                requireContext(),
                this
            )
        val listInUse = clockRegistry.getClocks().filter { "NOT_IN_USE" !in it.clockId }

+0 −1
Original line number Diff line number Diff line
@@ -123,7 +123,6 @@ class ClockSettingsFragment : AppbarFragment() {
                        context,
                        injector.getWallpaperColorsViewModel(),
                        injector.getClockViewFactory(activity),
                        activity,
                    ),
                )
                .get(),