Create controller for desktop prototype 2
Create the controller class, set up dagger. Ensure controller is not initialized when flag is off. Bug: 260645044 Test: atest DesktopTasksControllerTest Change-Id: I0435e07a22e379f403ae5d1b23f39a67a12e8a6d
This commit is contained in:
@@ -61,6 +61,7 @@ import com.android.wm.shell.desktopmode.DesktopMode;
|
||||
import com.android.wm.shell.desktopmode.DesktopModeController;
|
||||
import com.android.wm.shell.desktopmode.DesktopModeStatus;
|
||||
import com.android.wm.shell.desktopmode.DesktopModeTaskRepository;
|
||||
import com.android.wm.shell.desktopmode.DesktopTasksController;
|
||||
import com.android.wm.shell.displayareahelper.DisplayAreaHelper;
|
||||
import com.android.wm.shell.displayareahelper.DisplayAreaHelperController;
|
||||
import com.android.wm.shell.draganddrop.DragAndDropController;
|
||||
@@ -677,7 +678,11 @@ public abstract class WMShellBaseModule {
|
||||
@WMSingleton
|
||||
@Provides
|
||||
static Optional<DesktopMode> provideDesktopMode(
|
||||
Optional<DesktopModeController> desktopModeController) {
|
||||
Optional<DesktopModeController> desktopModeController,
|
||||
Optional<DesktopTasksController> desktopTasksController) {
|
||||
if (DesktopModeStatus.isProto2Enabled()) {
|
||||
return desktopTasksController.map(DesktopTasksController::asDesktopMode);
|
||||
}
|
||||
return desktopModeController.map(DesktopModeController::asDesktopMode);
|
||||
}
|
||||
|
||||
@@ -698,6 +703,23 @@ public abstract class WMShellBaseModule {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@BindsOptionalOf
|
||||
@DynamicOverride
|
||||
abstract DesktopTasksController optionalDesktopTasksController();
|
||||
|
||||
@WMSingleton
|
||||
@Provides
|
||||
static Optional<DesktopTasksController> providesDesktopTasksController(
|
||||
@DynamicOverride Optional<Lazy<DesktopTasksController>> desktopTasksController) {
|
||||
// Use optional-of-lazy for the dependency that this provider relies on.
|
||||
// Lazy ensures that this provider will not be the cause the dependency is created
|
||||
// when it will not be returned due to the condition below.
|
||||
if (DesktopModeStatus.isProto2Enabled()) {
|
||||
return desktopTasksController.map(Lazy::get);
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@BindsOptionalOf
|
||||
@DynamicOverride
|
||||
abstract DesktopModeTaskRepository optionalDesktopModeTaskRepository();
|
||||
|
||||
@@ -50,6 +50,7 @@ import com.android.wm.shell.common.annotations.ShellBackgroundThread;
|
||||
import com.android.wm.shell.common.annotations.ShellMainThread;
|
||||
import com.android.wm.shell.desktopmode.DesktopModeController;
|
||||
import com.android.wm.shell.desktopmode.DesktopModeTaskRepository;
|
||||
import com.android.wm.shell.desktopmode.DesktopTasksController;
|
||||
import com.android.wm.shell.draganddrop.DragAndDropController;
|
||||
import com.android.wm.shell.freeform.FreeformComponents;
|
||||
import com.android.wm.shell.freeform.FreeformTaskListener;
|
||||
@@ -613,6 +614,22 @@ public abstract class WMShellModule {
|
||||
mainExecutor);
|
||||
}
|
||||
|
||||
@WMSingleton
|
||||
@Provides
|
||||
@DynamicOverride
|
||||
static DesktopTasksController provideDesktopTasksController(
|
||||
Context context,
|
||||
ShellInit shellInit,
|
||||
ShellController shellController,
|
||||
ShellTaskOrganizer shellTaskOrganizer,
|
||||
Transitions transitions,
|
||||
@DynamicOverride DesktopModeTaskRepository desktopModeTaskRepository,
|
||||
@ShellMainThread ShellExecutor mainExecutor
|
||||
) {
|
||||
return new DesktopTasksController(context, shellInit, shellController, shellTaskOrganizer,
|
||||
transitions, desktopModeTaskRepository, mainExecutor);
|
||||
}
|
||||
|
||||
@WMSingleton
|
||||
@Provides
|
||||
@DynamicOverride
|
||||
|
||||
@@ -70,9 +70,13 @@ public class DesktopModeStatus {
|
||||
* @return {@code true} if active
|
||||
*/
|
||||
public static boolean isActive(Context context) {
|
||||
if (!IS_SUPPORTED) {
|
||||
if (!isAnyEnabled()) {
|
||||
return false;
|
||||
}
|
||||
if (isProto2Enabled()) {
|
||||
// Desktop mode is always active in prototype 2
|
||||
return true;
|
||||
}
|
||||
try {
|
||||
int result = Settings.System.getIntForUser(context.getContentResolver(),
|
||||
Settings.System.DESKTOP_MODE, UserHandle.USER_CURRENT);
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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
|
||||
|
||||
import android.content.Context
|
||||
import androidx.annotation.BinderThread
|
||||
import com.android.internal.protolog.common.ProtoLog
|
||||
import com.android.wm.shell.ShellTaskOrganizer
|
||||
import com.android.wm.shell.common.ExternalInterfaceBinder
|
||||
import com.android.wm.shell.common.RemoteCallable
|
||||
import com.android.wm.shell.common.ShellExecutor
|
||||
import com.android.wm.shell.common.annotations.ExternalThread
|
||||
import com.android.wm.shell.common.annotations.ShellMainThread
|
||||
import com.android.wm.shell.desktopmode.DesktopModeTaskRepository.VisibleTasksListener
|
||||
import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE
|
||||
import com.android.wm.shell.sysui.ShellController
|
||||
import com.android.wm.shell.sysui.ShellInit
|
||||
import com.android.wm.shell.sysui.ShellSharedConstants
|
||||
import com.android.wm.shell.transition.Transitions
|
||||
import java.util.concurrent.Executor
|
||||
|
||||
/** Handles moving tasks in and out of desktop */
|
||||
class DesktopTasksController(
|
||||
private val context: Context,
|
||||
shellInit: ShellInit,
|
||||
private val shellController: ShellController,
|
||||
private val shellTaskOrganizer: ShellTaskOrganizer,
|
||||
private val transitions: Transitions,
|
||||
private val desktopModeTaskRepository: DesktopModeTaskRepository,
|
||||
@ShellMainThread private val mainExecutor: ShellExecutor
|
||||
) : RemoteCallable<DesktopTasksController> {
|
||||
|
||||
private val desktopMode: DesktopModeImpl
|
||||
|
||||
init {
|
||||
desktopMode = DesktopModeImpl()
|
||||
if (DesktopModeStatus.isProto2Enabled()) {
|
||||
shellInit.addInitCallback({ onInit() }, this)
|
||||
}
|
||||
}
|
||||
|
||||
private fun onInit() {
|
||||
ProtoLog.d(WM_SHELL_DESKTOP_MODE, "Initialize DesktopTasksController")
|
||||
shellController.addExternalInterface(
|
||||
ShellSharedConstants.KEY_EXTRA_SHELL_DESKTOP_MODE,
|
||||
{ createExternalInterface() },
|
||||
this
|
||||
)
|
||||
}
|
||||
|
||||
override fun getContext(): Context {
|
||||
return context
|
||||
}
|
||||
|
||||
override fun getRemoteCallExecutor(): ShellExecutor {
|
||||
return mainExecutor
|
||||
}
|
||||
|
||||
/** Creates a new instance of the external interface to pass to another process. */
|
||||
private fun createExternalInterface(): ExternalInterfaceBinder {
|
||||
return IDesktopModeImpl(this)
|
||||
}
|
||||
|
||||
/** Get connection interface between sysui and shell */
|
||||
fun asDesktopMode(): DesktopMode {
|
||||
return desktopMode
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a listener to find out about changes in the visibility of freeform tasks.
|
||||
*
|
||||
* @param listener the listener to add.
|
||||
* @param callbackExecutor the executor to call the listener on.
|
||||
*/
|
||||
fun addListener(listener: VisibleTasksListener, callbackExecutor: Executor) {
|
||||
desktopModeTaskRepository.addVisibleTasksListener(listener, callbackExecutor)
|
||||
}
|
||||
|
||||
/** The interface for calls from outside the shell, within the host process. */
|
||||
@ExternalThread
|
||||
private inner class DesktopModeImpl : DesktopMode {
|
||||
override fun addListener(listener: VisibleTasksListener, callbackExecutor: Executor) {
|
||||
mainExecutor.execute {
|
||||
this@DesktopTasksController.addListener(listener, callbackExecutor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** The interface for calls from outside the host process. */
|
||||
@BinderThread
|
||||
private class IDesktopModeImpl(private var controller: DesktopTasksController?) :
|
||||
IDesktopMode.Stub(), ExternalInterfaceBinder {
|
||||
/** Invalidates this instance, preventing future calls from updating the controller. */
|
||||
override fun invalidate() {
|
||||
controller = null
|
||||
}
|
||||
|
||||
override fun showDesktopApps() {
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (C) 2022 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
|
||||
|
||||
import android.testing.AndroidTestingRunner
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
|
||||
import com.android.dx.mockito.inline.extended.ExtendedMockito.never
|
||||
import com.android.dx.mockito.inline.extended.StaticMockitoSession
|
||||
import com.android.wm.shell.ShellTaskOrganizer
|
||||
import com.android.wm.shell.ShellTestCase
|
||||
import com.android.wm.shell.TestShellExecutor
|
||||
import com.android.wm.shell.common.ShellExecutor
|
||||
import com.android.wm.shell.sysui.ShellController
|
||||
import com.android.wm.shell.sysui.ShellInit
|
||||
import com.android.wm.shell.transition.Transitions
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito
|
||||
import org.mockito.Mockito.any
|
||||
import org.mockito.Mockito.clearInvocations
|
||||
import org.mockito.Mockito.verify
|
||||
import org.mockito.Mockito.`when` as whenever
|
||||
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidTestingRunner::class)
|
||||
class DesktopTasksControllerTest : ShellTestCase() {
|
||||
|
||||
@Mock
|
||||
lateinit var testExecutor: ShellExecutor
|
||||
@Mock
|
||||
lateinit var shellController: ShellController
|
||||
@Mock
|
||||
lateinit var shellTaskOrganizer: ShellTaskOrganizer
|
||||
@Mock
|
||||
lateinit var transitions: Transitions
|
||||
|
||||
lateinit var mockitoSession: StaticMockitoSession
|
||||
lateinit var controller: DesktopTasksController
|
||||
lateinit var shellInit: ShellInit
|
||||
lateinit var desktopModeTaskRepository: DesktopModeTaskRepository
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
mockitoSession = mockitoSession().mockStatic(DesktopModeStatus::class.java).startMocking()
|
||||
whenever(DesktopModeStatus.isProto2Enabled()).thenReturn(true)
|
||||
|
||||
shellInit = Mockito.spy(ShellInit(testExecutor))
|
||||
desktopModeTaskRepository = DesktopModeTaskRepository()
|
||||
|
||||
controller = createController()
|
||||
|
||||
shellInit.init()
|
||||
}
|
||||
|
||||
private fun createController(): DesktopTasksController {
|
||||
return DesktopTasksController(context, shellInit, shellController,
|
||||
shellTaskOrganizer, transitions, desktopModeTaskRepository, TestShellExecutor())
|
||||
}
|
||||
|
||||
@After
|
||||
fun tearDown() {
|
||||
mockitoSession.finishMocking()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun instantiate_addInitCallback() {
|
||||
verify(shellInit).addInitCallback(any(), any<DesktopTasksController>())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun instantiate_flagOff_doNotAddInitCallback() {
|
||||
whenever(DesktopModeStatus.isProto2Enabled()).thenReturn(false)
|
||||
clearInvocations(shellInit)
|
||||
|
||||
createController()
|
||||
|
||||
verify(shellInit, never()).addInitCallback(any(), any<DesktopTasksController>())
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user