Implement showDesktopApps
Copy logic over from proto1 to bring desktop apps to front. There is one key difference from proto1 logic. In proto2, before desktop tasks are shown, we ensure that the home task is brought to front. And then place desktop tasks on top. This is due to proto2 having fullscreen and freeform tasks running at the same time. Bug: 260645044 Test: atest DesktopTasksControllerTest Change-Id: Ic5de4d431b96893ef5d685a4dce28e08f17f6f97
This commit is contained in:
@@ -16,10 +16,14 @@
|
||||
|
||||
package com.android.wm.shell.desktopmode
|
||||
|
||||
import android.app.WindowConfiguration.ACTIVITY_TYPE_HOME
|
||||
import android.content.Context
|
||||
import android.view.WindowManager
|
||||
import android.window.WindowContainerTransaction
|
||||
import androidx.annotation.BinderThread
|
||||
import com.android.internal.protolog.common.ProtoLog
|
||||
import com.android.wm.shell.ShellTaskOrganizer
|
||||
import com.android.wm.shell.common.ExecutorUtils
|
||||
import com.android.wm.shell.common.ExternalInterfaceBinder
|
||||
import com.android.wm.shell.common.RemoteCallable
|
||||
import com.android.wm.shell.common.ShellExecutor
|
||||
@@ -32,6 +36,7 @@ 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
|
||||
import java.util.function.Consumer
|
||||
|
||||
/** Handles moving tasks in and out of desktop */
|
||||
class DesktopTasksController(
|
||||
@@ -62,6 +67,55 @@ class DesktopTasksController(
|
||||
)
|
||||
}
|
||||
|
||||
/** Show all tasks, that are part of the desktop, on top of launcher */
|
||||
fun showDesktopApps() {
|
||||
ProtoLog.v(WM_SHELL_DESKTOP_MODE, "showDesktopApps")
|
||||
val wct = WindowContainerTransaction()
|
||||
|
||||
bringDesktopAppsToFront(wct)
|
||||
|
||||
// Execute transaction if there are pending operations
|
||||
if (!wct.isEmpty) {
|
||||
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
|
||||
transitions.startTransition(WindowManager.TRANSIT_TO_FRONT, wct, null /* handler */)
|
||||
} else {
|
||||
shellTaskOrganizer.applyTransaction(wct)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun bringDesktopAppsToFront(wct: WindowContainerTransaction) {
|
||||
val activeTasks = desktopModeTaskRepository.getActiveTasks()
|
||||
|
||||
// Skip if all tasks are already visible
|
||||
if (activeTasks.isNotEmpty() && activeTasks.all(desktopModeTaskRepository::isVisibleTask)) {
|
||||
ProtoLog.d(
|
||||
WM_SHELL_DESKTOP_MODE,
|
||||
"bringDesktopAppsToFront: active tasks are already in front, skipping."
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
ProtoLog.v(WM_SHELL_DESKTOP_MODE, "bringDesktopAppsToFront")
|
||||
|
||||
// First move home to front and then other tasks on top of it
|
||||
moveHomeTaskToFront(wct)
|
||||
|
||||
val allTasksInZOrder = desktopModeTaskRepository.getFreeformTasksInZOrder()
|
||||
activeTasks
|
||||
// Sort descending as the top task is at index 0. It should be ordered to top last
|
||||
.sortedByDescending { taskId -> allTasksInZOrder.indexOf(taskId) }
|
||||
.mapNotNull { taskId -> shellTaskOrganizer.getRunningTaskInfo(taskId) }
|
||||
.forEach { task -> wct.reorder(task.token, true /* onTop */) }
|
||||
}
|
||||
|
||||
private fun moveHomeTaskToFront(wct: WindowContainerTransaction) {
|
||||
shellTaskOrganizer
|
||||
.getRunningTasks(context.displayId)
|
||||
.firstOrNull { task -> task.activityType == ACTIVITY_TYPE_HOME }
|
||||
?.let { homeTask -> wct.reorder(homeTask.getToken(), true /* onTop */) }
|
||||
}
|
||||
|
||||
override fun getContext(): Context {
|
||||
return context
|
||||
}
|
||||
@@ -110,7 +164,11 @@ class DesktopTasksController(
|
||||
}
|
||||
|
||||
override fun showDesktopApps() {
|
||||
// TODO
|
||||
ExecutorUtils.executeRemoteCallWithTaskPermission(
|
||||
controller,
|
||||
"showDesktopApps",
|
||||
Consumer(DesktopTasksController::showDesktopApps)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
|
||||
package com.android.wm.shell.desktopmode;
|
||||
|
||||
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
|
||||
import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
|
||||
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
|
||||
@@ -28,6 +26,9 @@ import static android.view.WindowManager.TRANSIT_TO_FRONT;
|
||||
import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER;
|
||||
|
||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
|
||||
import static com.android.wm.shell.desktopmode.DesktopTestHelpers.createFreeformTask;
|
||||
import static com.android.wm.shell.desktopmode.DesktopTestHelpers.createFullscreenTask;
|
||||
import static com.android.wm.shell.desktopmode.DesktopTestHelpers.createHomeTask;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
@@ -47,7 +48,6 @@ import android.os.IBinder;
|
||||
import android.testing.AndroidTestingRunner;
|
||||
import android.window.DisplayAreaInfo;
|
||||
import android.window.TransitionRequestInfo;
|
||||
import android.window.WindowContainerToken;
|
||||
import android.window.WindowContainerTransaction;
|
||||
import android.window.WindowContainerTransaction.Change;
|
||||
import android.window.WindowContainerTransaction.HierarchyOp;
|
||||
@@ -58,7 +58,6 @@ import com.android.dx.mockito.inline.extended.StaticMockitoSession;
|
||||
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
|
||||
import com.android.wm.shell.ShellTaskOrganizer;
|
||||
import com.android.wm.shell.ShellTestCase;
|
||||
import com.android.wm.shell.TestRunningTaskInfoBuilder;
|
||||
import com.android.wm.shell.TestShellExecutor;
|
||||
import com.android.wm.shell.common.ShellExecutor;
|
||||
import com.android.wm.shell.sysui.ShellController;
|
||||
@@ -354,7 +353,7 @@ public class DesktopModeControllerTest extends ShellTestCase {
|
||||
@Test
|
||||
public void testHandleTransitionRequest_returnsWct() {
|
||||
RunningTaskInfo trigger = new RunningTaskInfo();
|
||||
trigger.token = new MockToken().mToken;
|
||||
trigger.token = new MockToken().token();
|
||||
trigger.configuration.windowConfiguration.setWindowingMode(WINDOWING_MODE_FREEFORM);
|
||||
WindowContainerTransaction wct = mController.handleRequest(
|
||||
mock(IBinder.class),
|
||||
@@ -369,40 +368,13 @@ public class DesktopModeControllerTest extends ShellTestCase {
|
||||
}
|
||||
|
||||
private DisplayAreaInfo createMockDisplayArea() {
|
||||
DisplayAreaInfo displayAreaInfo = new DisplayAreaInfo(new MockToken().mToken,
|
||||
DisplayAreaInfo displayAreaInfo = new DisplayAreaInfo(new MockToken().token(),
|
||||
mContext.getDisplayId(), 0);
|
||||
when(mRootTaskDisplayAreaOrganizer.getDisplayAreaInfo(mContext.getDisplayId()))
|
||||
.thenReturn(displayAreaInfo);
|
||||
return displayAreaInfo;
|
||||
}
|
||||
|
||||
private RunningTaskInfo createFreeformTask() {
|
||||
return new TestRunningTaskInfoBuilder()
|
||||
.setToken(new MockToken().token())
|
||||
.setActivityType(ACTIVITY_TYPE_STANDARD)
|
||||
.setWindowingMode(WINDOWING_MODE_FREEFORM)
|
||||
.setLastActiveTime(100)
|
||||
.build();
|
||||
}
|
||||
|
||||
private RunningTaskInfo createFullscreenTask() {
|
||||
return new TestRunningTaskInfoBuilder()
|
||||
.setToken(new MockToken().token())
|
||||
.setActivityType(ACTIVITY_TYPE_STANDARD)
|
||||
.setWindowingMode(WINDOWING_MODE_FULLSCREEN)
|
||||
.setLastActiveTime(100)
|
||||
.build();
|
||||
}
|
||||
|
||||
private RunningTaskInfo createHomeTask() {
|
||||
return new TestRunningTaskInfoBuilder()
|
||||
.setToken(new MockToken().token())
|
||||
.setActivityType(ACTIVITY_TYPE_HOME)
|
||||
.setWindowingMode(WINDOWING_MODE_FULLSCREEN)
|
||||
.setLastActiveTime(100)
|
||||
.build();
|
||||
}
|
||||
|
||||
private WindowContainerTransaction getDesktopModeSwitchTransaction() {
|
||||
ArgumentCaptor<WindowContainerTransaction> arg = ArgumentCaptor.forClass(
|
||||
WindowContainerTransaction.class);
|
||||
@@ -430,18 +402,4 @@ public class DesktopModeControllerTest extends ShellTestCase {
|
||||
assertThat(change.getConfiguration().windowConfiguration.getBounds().isEmpty()).isTrue();
|
||||
}
|
||||
|
||||
private static class MockToken {
|
||||
private final WindowContainerToken mToken;
|
||||
private final IBinder mBinder;
|
||||
|
||||
MockToken() {
|
||||
mToken = mock(WindowContainerToken.class);
|
||||
mBinder = mock(IBinder.class);
|
||||
when(mToken.asBinder()).thenReturn(mBinder);
|
||||
}
|
||||
|
||||
WindowContainerToken token() {
|
||||
return mToken;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,10 @@
|
||||
|
||||
package com.android.wm.shell.desktopmode
|
||||
|
||||
import android.app.ActivityManager.RunningTaskInfo
|
||||
import android.testing.AndroidTestingRunner
|
||||
import android.window.WindowContainerTransaction
|
||||
import android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
|
||||
import com.android.dx.mockito.inline.extended.ExtendedMockito.never
|
||||
@@ -25,39 +28,44 @@ 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.desktopmode.DesktopTestHelpers.Companion.createFreeformTask
|
||||
import com.android.wm.shell.desktopmode.DesktopTestHelpers.Companion.createHomeTask
|
||||
import com.android.wm.shell.sysui.ShellController
|
||||
import com.android.wm.shell.sysui.ShellInit
|
||||
import com.android.wm.shell.transition.Transitions
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import com.google.common.truth.Truth.assertWithMessage
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.mockito.ArgumentCaptor
|
||||
import org.mockito.ArgumentMatchers.isNull
|
||||
import org.mockito.Mock
|
||||
import org.mockito.Mockito
|
||||
import org.mockito.Mockito.any
|
||||
import org.mockito.Mockito.anyInt
|
||||
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
|
||||
@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
|
||||
|
||||
// Mock running tasks are registered here so we can get the list from mock shell task organizer
|
||||
private val runningTasks = mutableListOf<RunningTaskInfo>()
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
mockitoSession = mockitoSession().mockStatic(DesktopModeStatus::class.java).startMocking()
|
||||
@@ -66,19 +74,30 @@ class DesktopTasksControllerTest : ShellTestCase() {
|
||||
shellInit = Mockito.spy(ShellInit(testExecutor))
|
||||
desktopModeTaskRepository = DesktopModeTaskRepository()
|
||||
|
||||
whenever(shellTaskOrganizer.getRunningTasks(anyInt())).thenAnswer { runningTasks }
|
||||
|
||||
controller = createController()
|
||||
|
||||
shellInit.init()
|
||||
}
|
||||
|
||||
private fun createController(): DesktopTasksController {
|
||||
return DesktopTasksController(context, shellInit, shellController,
|
||||
shellTaskOrganizer, transitions, desktopModeTaskRepository, TestShellExecutor())
|
||||
return DesktopTasksController(
|
||||
context,
|
||||
shellInit,
|
||||
shellController,
|
||||
shellTaskOrganizer,
|
||||
transitions,
|
||||
desktopModeTaskRepository,
|
||||
TestShellExecutor()
|
||||
)
|
||||
}
|
||||
|
||||
@After
|
||||
fun tearDown() {
|
||||
mockitoSession.finishMocking()
|
||||
|
||||
runningTasks.clear()
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -95,4 +114,111 @@ class DesktopTasksControllerTest : ShellTestCase() {
|
||||
|
||||
verify(shellInit, never()).addInitCallback(any(), any<DesktopTasksController>())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun showDesktopApps_allAppsInvisible_bringsToFront() {
|
||||
val homeTask = setUpHomeTask()
|
||||
val task1 = setUpDesktopTask()
|
||||
val task2 = setUpDesktopTask()
|
||||
markTaskHidden(task1)
|
||||
markTaskHidden(task2)
|
||||
|
||||
controller.showDesktopApps()
|
||||
|
||||
val wct = getLatestWct()
|
||||
assertThat(wct.hierarchyOps).hasSize(3)
|
||||
// Expect order to be from bottom: home, task1, task2
|
||||
wct.assertReorderAt(index = 0, homeTask)
|
||||
wct.assertReorderAt(index = 1, task1)
|
||||
wct.assertReorderAt(index = 2, task2)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun showDesktopApps_appsAlreadyVisible_doesNothing() {
|
||||
setUpHomeTask()
|
||||
val task1 = setUpDesktopTask()
|
||||
val task2 = setUpDesktopTask()
|
||||
markTaskVisible(task1)
|
||||
markTaskVisible(task2)
|
||||
|
||||
controller.showDesktopApps()
|
||||
|
||||
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
|
||||
verify(transitions, never()).startTransition(anyInt(), any(), isNull())
|
||||
} else {
|
||||
verify(shellTaskOrganizer, never()).applyTransaction(any())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun showDesktopApps_someAppsInvisible_reordersAll() {
|
||||
val homeTask = setUpHomeTask()
|
||||
val task1 = setUpDesktopTask()
|
||||
val task2 = setUpDesktopTask()
|
||||
markTaskHidden(task1)
|
||||
markTaskVisible(task2)
|
||||
|
||||
controller.showDesktopApps()
|
||||
|
||||
val wct = getLatestWct()
|
||||
assertThat(wct.hierarchyOps).hasSize(3)
|
||||
// Expect order to be from bottom: home, task1, task2
|
||||
wct.assertReorderAt(index = 0, homeTask)
|
||||
wct.assertReorderAt(index = 1, task1)
|
||||
wct.assertReorderAt(index = 2, task2)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun showDesktopApps_noActiveTasks_reorderHomeToTop() {
|
||||
val homeTask = setUpHomeTask()
|
||||
|
||||
controller.showDesktopApps()
|
||||
|
||||
val wct = getLatestWct()
|
||||
assertThat(wct.hierarchyOps).hasSize(1)
|
||||
wct.assertReorderAt(index = 0, homeTask)
|
||||
}
|
||||
|
||||
private fun setUpDesktopTask(): RunningTaskInfo {
|
||||
val task = createFreeformTask()
|
||||
whenever(shellTaskOrganizer.getRunningTaskInfo(task.taskId)).thenReturn(task)
|
||||
desktopModeTaskRepository.addActiveTask(task.taskId)
|
||||
desktopModeTaskRepository.addOrMoveFreeformTaskToTop(task.taskId)
|
||||
runningTasks.add(task)
|
||||
return task
|
||||
}
|
||||
|
||||
private fun setUpHomeTask(): RunningTaskInfo {
|
||||
val task = createHomeTask()
|
||||
whenever(shellTaskOrganizer.getRunningTaskInfo(task.taskId)).thenReturn(task)
|
||||
runningTasks.add(task)
|
||||
return task
|
||||
}
|
||||
|
||||
private fun markTaskVisible(task: RunningTaskInfo) {
|
||||
desktopModeTaskRepository.updateVisibleFreeformTasks(task.taskId, visible = true)
|
||||
}
|
||||
|
||||
private fun markTaskHidden(task: RunningTaskInfo) {
|
||||
desktopModeTaskRepository.updateVisibleFreeformTasks(task.taskId, visible = false)
|
||||
}
|
||||
|
||||
private fun getLatestWct(): WindowContainerTransaction {
|
||||
val arg = ArgumentCaptor.forClass(WindowContainerTransaction::class.java)
|
||||
if (Transitions.ENABLE_SHELL_TRANSITIONS) {
|
||||
verify(transitions).startTransition(anyInt(), arg.capture(), isNull())
|
||||
} else {
|
||||
verify(shellTaskOrganizer).applyTransaction(arg.capture())
|
||||
}
|
||||
return arg.value
|
||||
}
|
||||
}
|
||||
|
||||
private fun WindowContainerTransaction.assertReorderAt(index: Int, task: RunningTaskInfo) {
|
||||
assertWithMessage("WCT does not have a hierarchy operation at index $index")
|
||||
.that(hierarchyOps.size)
|
||||
.isGreaterThan(index)
|
||||
val op = hierarchyOps[index]
|
||||
assertThat(op.type).isEqualTo(HIERARCHY_OP_TYPE_REORDER)
|
||||
assertThat(op.container).isEqualTo(task.token.asBinder())
|
||||
}
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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.app.ActivityManager.RunningTaskInfo
|
||||
import android.app.WindowConfiguration.ACTIVITY_TYPE_HOME
|
||||
import android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD
|
||||
import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM
|
||||
import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN
|
||||
import com.android.wm.shell.TestRunningTaskInfoBuilder
|
||||
|
||||
class DesktopTestHelpers {
|
||||
companion object {
|
||||
/** Create a task that has windowing mode set to [WINDOWING_MODE_FREEFORM] */
|
||||
@JvmStatic
|
||||
fun createFreeformTask(): RunningTaskInfo {
|
||||
return TestRunningTaskInfoBuilder()
|
||||
.setToken(MockToken().token())
|
||||
.setActivityType(ACTIVITY_TYPE_STANDARD)
|
||||
.setWindowingMode(WINDOWING_MODE_FREEFORM)
|
||||
.setLastActiveTime(100)
|
||||
.build()
|
||||
}
|
||||
|
||||
/** Create a task that has windowing mode set to [WINDOWING_MODE_FULLSCREEN] */
|
||||
@JvmStatic
|
||||
fun createFullscreenTask(): RunningTaskInfo {
|
||||
return TestRunningTaskInfoBuilder()
|
||||
.setToken(MockToken().token())
|
||||
.setActivityType(ACTIVITY_TYPE_STANDARD)
|
||||
.setWindowingMode(WINDOWING_MODE_FULLSCREEN)
|
||||
.setLastActiveTime(100)
|
||||
.build()
|
||||
}
|
||||
|
||||
/** Create a new home task */
|
||||
@JvmStatic
|
||||
fun createHomeTask(): RunningTaskInfo {
|
||||
return TestRunningTaskInfoBuilder()
|
||||
.setToken(MockToken().token())
|
||||
.setActivityType(ACTIVITY_TYPE_HOME)
|
||||
.setWindowingMode(WINDOWING_MODE_FULLSCREEN)
|
||||
.setLastActiveTime(100)
|
||||
.build()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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 static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.os.IBinder;
|
||||
import android.window.WindowContainerToken;
|
||||
|
||||
/**
|
||||
* {@link WindowContainerToken} wrapper that supports a mock binder
|
||||
*/
|
||||
class MockToken {
|
||||
private final WindowContainerToken mToken;
|
||||
|
||||
MockToken() {
|
||||
mToken = mock(WindowContainerToken.class);
|
||||
IBinder binder = mock(IBinder.class);
|
||||
when(mToken.asBinder()).thenReturn(binder);
|
||||
}
|
||||
|
||||
WindowContainerToken token() {
|
||||
return mToken;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user