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

Commit 9c78d598 authored by Orhan Uysal's avatar Orhan Uysal
Browse files

Refactor initializing of DesktopRepository.

This introduces a new class and an interface to initialize the
DesktopRepository. Also fixes the issue when tasks are marked as not
visible when moved outside of desktop and device is rebooted.

Test: atest DesktopRepositoryTest
Test: atest DesktopRepositoryInitializerTest
Fix: 375396271
Bug: 365725441
Flag: com.android.window.flags.enable_desktop_windowing_persistence
Change-Id: I5e1d8a103111bf3b66fe1c8e24768ea39d6e65aa
parent 403ef8a8
Loading
Loading
Loading
Loading
+18 −2
Original line number Diff line number Diff line
@@ -88,6 +88,8 @@ import com.android.wm.shell.desktopmode.education.AppHandleEducationController;
import com.android.wm.shell.desktopmode.education.AppHandleEducationFilter;
import com.android.wm.shell.desktopmode.education.data.AppHandleEducationDatastoreRepository;
import com.android.wm.shell.desktopmode.persistence.DesktopPersistentRepository;
import com.android.wm.shell.desktopmode.persistence.DesktopRepositoryInitializer;
import com.android.wm.shell.desktopmode.persistence.DesktopRepositoryInitializerImpl;
import com.android.wm.shell.draganddrop.DragAndDropController;
import com.android.wm.shell.draganddrop.GlobalDragListener;
import com.android.wm.shell.freeform.FreeformComponents;
@@ -909,8 +911,12 @@ public abstract class WMShellModule {
            Context context,
            ShellInit shellInit,
            DesktopPersistentRepository desktopPersistentRepository,
            @ShellMainThread CoroutineScope mainScope) {
        return new DesktopRepository(context, shellInit, desktopPersistentRepository, mainScope);
            DesktopRepositoryInitializer desktopRepositoryInitializer,
            @ShellMainThread CoroutineScope mainScope
    ) {
        return new DesktopRepository(context, shellInit, desktopPersistentRepository,
                desktopRepositoryInitializer,
                mainScope);
    }

    @WMSingleton
@@ -1057,6 +1063,16 @@ public abstract class WMShellModule {
        return new DesktopPersistentRepository(context, bgScope);
    }

    @WMSingleton
    @Provides
    static DesktopRepositoryInitializer provideDesktopRepositoryInitializer(
            Context context,
            DesktopPersistentRepository desktopPersistentRepository,
            @ShellMainThread CoroutineScope mainScope) {
        return new DesktopRepositoryInitializerImpl(context, desktopPersistentRepository,
                mainScope);
    }

    //
    // Drag and drop
    //
+3 −27
Original line number Diff line number Diff line
@@ -30,7 +30,7 @@ import androidx.core.util.valueIterator
import com.android.internal.protolog.ProtoLog
import com.android.window.flags.Flags
import com.android.wm.shell.desktopmode.persistence.DesktopPersistentRepository
import com.android.wm.shell.desktopmode.persistence.DesktopTaskState
import com.android.wm.shell.desktopmode.persistence.DesktopRepositoryInitializer
import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE
import com.android.wm.shell.shared.annotations.ShellMainThread
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
@@ -46,6 +46,7 @@ class DesktopRepository (
    private val context: Context,
    shellInit: ShellInit,
    private val persistentRepository: DesktopPersistentRepository,
    private val repositoryInitializer: DesktopRepositoryInitializer,
    @ShellMainThread private val mainCoroutineScope: CoroutineScope,
){

@@ -120,32 +121,7 @@ class DesktopRepository (
    }

    private fun initRepoFromPersistentStorage() {
        if (!Flags.enableDesktopWindowingPersistence()) return
        //  TODO: b/365962554 - Handle the case that user moves to desktop before it's initialized
        mainCoroutineScope.launch {
            val desktop = persistentRepository.readDesktop() ?: return@launch

            val maxTasks =
                DesktopModeStatus.getMaxTaskLimit(context).takeIf { it > 0 }
                    ?: desktop.zOrderedTasksCount

            var visibleTasksCount = 0
            desktop.zOrderedTasksList
                // Reverse it so we initialize the repo from bottom to top.
                .reversed()
                .mapNotNull { taskId -> desktop.tasksByTaskIdMap[taskId] }
                .forEach { task ->
                    if (task.desktopTaskState == DesktopTaskState.VISIBLE
                        && visibleTasksCount < maxTasks
                    ) {
                        visibleTasksCount++
                        addTask(desktop.displayId, task.taskId, isVisible = false)
                    } else {
                        addTask(desktop.displayId, task.taskId, isVisible = false)
                        minimizeTask(desktop.displayId, task.taskId)
                    }
                }
        }
        repositoryInitializer.initialize(this)
    }

    /** Adds [activeTasksListener] to be notified of updates to active tasks. */
+24 −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.wm.shell.desktopmode.persistence

import com.android.wm.shell.desktopmode.DesktopRepository

/** Interface for initializing the [DesktopRepository]. */
fun interface DesktopRepositoryInitializer {
    fun initialize(repository: DesktopRepository)
}
+66 −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.wm.shell.desktopmode.persistence

import android.content.Context
import com.android.window.flags.Flags
import com.android.wm.shell.desktopmode.DesktopRepository
import com.android.wm.shell.shared.annotations.ShellMainThread
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch

/**
 * Initializes the [DesktopRepository] from the [DesktopPersistentRepository].
 *
 * This class is responsible for reading the [DesktopPersistentRepository] and initializing the
 * [DesktopRepository] with the tasks that previously existed in desktop.
 */
class DesktopRepositoryInitializerImpl(
    private val context: Context,
    private val persistentRepository: DesktopPersistentRepository,
    @ShellMainThread private val mainCoroutineScope: CoroutineScope,
) : DesktopRepositoryInitializer {
    override fun initialize(repository: DesktopRepository) {
        if (!Flags.enableDesktopWindowingPersistence()) return
        //  TODO: b/365962554 - Handle the case that user moves to desktop before it's initialized
        mainCoroutineScope.launch {
            val desktop = persistentRepository.readDesktop() ?: return@launch

            val maxTasks =
                DesktopModeStatus.getMaxTaskLimit(context).takeIf { it > 0 }
                    ?: desktop.zOrderedTasksCount

            var visibleTasksCount = 0
            desktop.zOrderedTasksList
                // Reverse it so we initialize the repo from bottom to top.
                .reversed()
                .mapNotNull { taskId -> desktop.tasksByTaskIdMap[taskId] }
                .forEach { task ->
                    if (task.desktopTaskState == DesktopTaskState.VISIBLE
                        && visibleTasksCount < maxTasks
                    ) {
                        visibleTasksCount++
                        repository.addTask(desktop.displayId, task.taskId, isVisible = false)
                    } else {
                        repository.addTask(desktop.displayId, task.taskId, isVisible = false)
                        repository.minimizeTask(desktop.displayId, task.taskId)
                    }
                }
        }
    }
}
+10 −2
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@ import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFreef
import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createFullscreenTask
import com.android.wm.shell.desktopmode.persistence.Desktop
import com.android.wm.shell.desktopmode.persistence.DesktopPersistentRepository
import com.android.wm.shell.desktopmode.persistence.DesktopRepositoryInitializer
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
import com.android.wm.shell.sysui.ShellInit
import com.android.wm.shell.transition.Transitions
@@ -50,10 +51,10 @@ import junit.framework.Assert.assertEquals
import junit.framework.Assert.assertTrue
import kotlin.test.assertNotNull
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.cancel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.StandardTestDispatcher
import kotlinx.coroutines.test.setMain
@@ -94,6 +95,7 @@ class DesktopActivityOrientationChangeHandlerTest : ShellTestCase() {
    @Mock lateinit var resizeTransitionHandler: ToggleResizeDesktopTaskTransitionHandler
    @Mock lateinit var taskStackListener: TaskStackListenerImpl
    @Mock lateinit var persistentRepository: DesktopPersistentRepository
    @Mock lateinit var repositoryInitializer: DesktopRepositoryInitializer

    private lateinit var mockitoSession: StaticMockitoSession
    private lateinit var handler: DesktopActivityOrientationChangeHandler
@@ -116,7 +118,13 @@ class DesktopActivityOrientationChangeHandlerTest : ShellTestCase() {
        testScope = CoroutineScope(Dispatchers.Unconfined + SupervisorJob())
        shellInit = spy(ShellInit(testExecutor))
        taskRepository =
            DesktopRepository(context, shellInit, persistentRepository, testScope)
            DesktopRepository(
                context,
                shellInit,
                persistentRepository,
                repositoryInitializer,
                testScope
            )
        whenever(shellTaskOrganizer.getRunningTasks(anyInt())).thenAnswer { runningTasks }
        whenever(transitions.startTransition(anyInt(), any(), isNull())).thenAnswer { Binder() }
        whenever(runBlocking { persistentRepository.readDesktop(any(), any()) }).thenReturn(
Loading