Loading services/companion/java/com/android/server/companion/datatransfer/continuity/TaskContinuityManagerService.java +17 −0 Original line number Diff line number Diff line Loading @@ -20,7 +20,9 @@ import android.companion.datatransfer.continuity.ITaskContinuityManager; import android.content.Context; import android.util.Slog; import com.android.server.companion.datatransfer.continuity.messages.ContinuityDeviceConnected; import com.android.server.companion.datatransfer.continuity.messages.TaskContinuityMessage; import com.android.server.companion.datatransfer.continuity.tasks.RemoteTaskStore; import com.android.server.SystemService; Loading @@ -37,11 +39,13 @@ public final class TaskContinuityManagerService extends SystemService { private TaskContinuityManagerServiceImpl mTaskContinuityManagerService; private TaskBroadcaster mTaskBroadcaster; private TaskContinuityMessageReceiver mTaskContinuityMessageReceiver; private RemoteTaskStore mRemoteTaskStore; public TaskContinuityManagerService(Context context) { super(context); mTaskBroadcaster = new TaskBroadcaster(context); mTaskContinuityMessageReceiver = new TaskContinuityMessageReceiver(context); mRemoteTaskStore = new RemoteTaskStore(); } @Override Loading @@ -61,5 +65,18 @@ public final class TaskContinuityManagerService extends SystemService { TaskContinuityMessage taskContinuityMessage) { Slog.v(TAG, "Received message from association id: " + associationId); switch (taskContinuityMessage.getData()) { case ContinuityDeviceConnected continuityDeviceConnected: // TODO: joeantonetti - Extract a readable device name and pass it to the store. mRemoteTaskStore.registerDevice( associationId, String.format("device-%d", associationId), continuityDeviceConnected.getRemoteTasks()); break; default: Slog.w(TAG, "Received unknown message from device: " + associationId); break; } } } services/companion/java/com/android/server/companion/datatransfer/continuity/tasks/RemoteDeviceTaskList.java 0 → 100644 +84 −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.server.companion.datatransfer.continuity.tasks; import com.android.server.companion.datatransfer.continuity.messages.RemoteTaskInfo; import java.util.ArrayList; import java.util.List; /** * Tracks remote tasks currently available on a specific remote device. */ class RemoteDeviceTaskList { private final int mAssociationId; private final String mDeviceName; private List<RemoteTaskInfo> mTasks; RemoteDeviceTaskList( int associationId, String deviceName, List<RemoteTaskInfo> tasks) { mAssociationId = associationId; mDeviceName = deviceName; mTasks = new ArrayList<>(tasks); } /** * Returns the association ID of the remote device. */ int getAssociationId() { return mAssociationId; } /** * Returns the device name of the remote device. */ String getDeviceName() { return mDeviceName; } /** * Adds a task to the list of tasks currently available on the remote * device. */ void addTask(RemoteTaskInfo taskInfo) { mTasks.add(taskInfo); } /** * Gets the most recently used task on this device, or null if there are no * tasks. */ RemoteTaskInfo getMostRecentTask() { if (mTasks.isEmpty()) { return null; } RemoteTaskInfo mostRecentTask = mTasks.get(0); for (RemoteTaskInfo task : mTasks) { if ( task.getLastUsedTimeMillis() > mostRecentTask.getLastUsedTimeMillis()) { mostRecentTask = task; } } return mostRecentTask; } } No newline at end of file services/companion/java/com/android/server/companion/datatransfer/continuity/tasks/RemoteTaskStore.java 0 → 100644 +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.server.companion.datatransfer.continuity.tasks; import com.android.server.companion.datatransfer.continuity.messages.RemoteTaskInfo; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class RemoteTaskStore { private final Map<Integer, RemoteDeviceTaskList> mRemoteDeviceTaskLists = new HashMap<>(); public RemoteTaskStore() {} /** * Registers a device with the task store. * * @param associationId The ID of the device. * @param deviceName The name of the device. * @param tasks The list of tasks currently available on the device on first * connection. */ public void registerDevice( int associationId, String deviceName, List<RemoteTaskInfo> tasks) { RemoteDeviceTaskList taskList = new RemoteDeviceTaskList(associationId, deviceName, tasks); mRemoteDeviceTaskLists.put(associationId, taskList); } /** * Returns the most recent tasks from all devices in the task store. * * @return A list of the most recent tasks from all devices in the task * store. */ public List<RemoteTaskInfo> getMostRecentTasks() { List<RemoteTaskInfo> mostRecentTasks = new ArrayList<>(); for (RemoteDeviceTaskList taskList : mRemoteDeviceTaskLists.values()) { RemoteTaskInfo mostRecentTask = taskList.getMostRecentTask(); if (mostRecentTask != null) { mostRecentTasks.add(mostRecentTask); } } return mostRecentTasks; } } No newline at end of file services/tests/servicestests/src/com/android/server/companion/datatransfer/continuity/tasks/RemoteDeviceTaskListTest.java 0 → 100644 +120 −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.server.companion.datatransfer.continuity.tasks; import static com.google.common.truth.Truth.assertThat; import android.app.ActivityManager; import android.platform.test.annotations.Presubmit; import android.testing.AndroidTestingRunner; import com.android.server.companion.datatransfer.continuity.messages.RemoteTaskInfo; import org.junit.Test; import org.junit.runner.RunWith; import java.util.Arrays; import java.util.ArrayList; import java.util.List; @Presubmit @RunWith(AndroidTestingRunner.class) public class RemoteDeviceTaskListTest { @Test public void testConstructor_initializesCorrectly() { int associationId = 123; String deviceName = "device1"; RemoteTaskInfo expectedTask = createNewRemoteTaskInfo("task1", 100); List<RemoteTaskInfo> initialTasks = Arrays.asList(expectedTask); RemoteDeviceTaskList taskList = new RemoteDeviceTaskList( associationId, deviceName, initialTasks); assertThat(taskList.getMostRecentTask()).isEqualTo(expectedTask); assertThat(taskList.getAssociationId()).isEqualTo(associationId); assertThat(taskList.getDeviceName()).isEqualTo(deviceName); } @Test public void testAddTask_updatesMostRecentTask() { RemoteDeviceTaskList taskList = new RemoteDeviceTaskList( 0, "device name", new ArrayList<>()); RemoteTaskInfo firstAddedTask = createNewRemoteTaskInfo("task2", 200); taskList.addTask(firstAddedTask); assertThat(taskList.getMostRecentTask()).isEqualTo(firstAddedTask); // Add another task with an older timestamp, verify it doesn't update // the most recent task. RemoteTaskInfo secondAddedTask = createNewRemoteTaskInfo("task1", 100); taskList.addTask(secondAddedTask); assertThat(taskList.getMostRecentTask()).isEqualTo(firstAddedTask); // Add another task with a newer timestamp, verifying it changes the // most recently used task. RemoteTaskInfo thirdAddedTask = createNewRemoteTaskInfo("task3", 300); taskList.addTask(thirdAddedTask); assertThat(taskList.getMostRecentTask()).isEqualTo(thirdAddedTask); } @Test public void testGetMostRecentTask_emptyList_returnsNull() { RemoteDeviceTaskList taskList = new RemoteDeviceTaskList( 0, "device name", new ArrayList<>()); assertThat(taskList.getMostRecentTask()).isNull(); } @Test public void testGetMostRecentTask_multipleTasks_returnsMostRecent() { RemoteTaskInfo expectedTask = createNewRemoteTaskInfo("task2", 200); int associationId = 123; List<RemoteTaskInfo> initialTasks = Arrays.asList( createNewRemoteTaskInfo("task1", 100), expectedTask, createNewRemoteTaskInfo("task3", 150)); RemoteDeviceTaskList taskList = new RemoteDeviceTaskList( associationId, "device name", initialTasks); assertThat(taskList.getMostRecentTask()).isEqualTo(expectedTask); } private RemoteTaskInfo createNewRemoteTaskInfo( String label, long lastUsedTimeMillis) { ActivityManager.RunningTaskInfo runningTaskInfo = new ActivityManager.RunningTaskInfo(); runningTaskInfo.taskId = 1; runningTaskInfo.taskDescription = new ActivityManager.TaskDescription(label); runningTaskInfo.lastActiveTime = lastUsedTimeMillis; return new RemoteTaskInfo(runningTaskInfo); } } No newline at end of file services/tests/servicestests/src/com/android/server/companion/datatransfer/continuity/tasks/RemoteTaskStoreTest.java 0 → 100644 +93 −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.server.companion.datatransfer.continuity.tasks; import static com.google.common.truth.Truth.assertThat; import android.app.ActivityManager; import android.platform.test.annotations.Presubmit; import android.testing.AndroidTestingRunner; import com.android.server.companion.datatransfer.continuity.messages.RemoteTaskInfo; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import java.util.Arrays; import java.util.ArrayList; import java.util.List; @Presubmit @RunWith(AndroidTestingRunner.class) public class RemoteTaskStoreTest { private RemoteTaskStore taskStore; @Before public void setUp() { taskStore = new RemoteTaskStore(); } @Test public void testRegisterDevice_addsDeviceToStore() { RemoteTaskInfo expectedTask = createNewRemoteTaskInfo("task1", 100); taskStore.registerDevice(0, "device name", Arrays.asList(expectedTask)); assertThat(taskStore.getMostRecentTasks()).containsExactly(expectedTask); } @Test public void testGetMostRecentTasks_emptyStore_returnsEmptyList() { assertThat(taskStore.getMostRecentTasks()).isEmpty(); } @Test public void testGetMostRecentTasks_multipleDevices_returnsMostRecentFromEach() { RemoteTaskInfo expectedTaskFromDevice1 = createNewRemoteTaskInfo("task1", 100); RemoteTaskInfo expectedTaskFromDevice2 = createNewRemoteTaskInfo("task2", 200); taskStore.registerDevice( 0, "device1", Arrays.asList(expectedTaskFromDevice1, createNewRemoteTaskInfo("task2", 1))); taskStore.registerDevice( 1, "device2", Arrays.asList(expectedTaskFromDevice2, createNewRemoteTaskInfo("task2", 1))); assertThat(taskStore.getMostRecentTasks()) .containsExactly(expectedTaskFromDevice1, expectedTaskFromDevice2); } @Test public void testGetMostRecentTasks_deviceWithNoTasks_returnsEmptyList() { taskStore.registerDevice(0, "device name", new ArrayList<>()); assertThat(taskStore.getMostRecentTasks()).isEmpty(); } private RemoteTaskInfo createNewRemoteTaskInfo(String label, long lastUsedTimeMillis) { ActivityManager.RunningTaskInfo runningTaskInfo = new ActivityManager.RunningTaskInfo(); runningTaskInfo.taskId = 1; runningTaskInfo.taskDescription = new ActivityManager.TaskDescription(label); runningTaskInfo.lastActiveTime = lastUsedTimeMillis; return new RemoteTaskInfo(runningTaskInfo); } } No newline at end of file Loading
services/companion/java/com/android/server/companion/datatransfer/continuity/TaskContinuityManagerService.java +17 −0 Original line number Diff line number Diff line Loading @@ -20,7 +20,9 @@ import android.companion.datatransfer.continuity.ITaskContinuityManager; import android.content.Context; import android.util.Slog; import com.android.server.companion.datatransfer.continuity.messages.ContinuityDeviceConnected; import com.android.server.companion.datatransfer.continuity.messages.TaskContinuityMessage; import com.android.server.companion.datatransfer.continuity.tasks.RemoteTaskStore; import com.android.server.SystemService; Loading @@ -37,11 +39,13 @@ public final class TaskContinuityManagerService extends SystemService { private TaskContinuityManagerServiceImpl mTaskContinuityManagerService; private TaskBroadcaster mTaskBroadcaster; private TaskContinuityMessageReceiver mTaskContinuityMessageReceiver; private RemoteTaskStore mRemoteTaskStore; public TaskContinuityManagerService(Context context) { super(context); mTaskBroadcaster = new TaskBroadcaster(context); mTaskContinuityMessageReceiver = new TaskContinuityMessageReceiver(context); mRemoteTaskStore = new RemoteTaskStore(); } @Override Loading @@ -61,5 +65,18 @@ public final class TaskContinuityManagerService extends SystemService { TaskContinuityMessage taskContinuityMessage) { Slog.v(TAG, "Received message from association id: " + associationId); switch (taskContinuityMessage.getData()) { case ContinuityDeviceConnected continuityDeviceConnected: // TODO: joeantonetti - Extract a readable device name and pass it to the store. mRemoteTaskStore.registerDevice( associationId, String.format("device-%d", associationId), continuityDeviceConnected.getRemoteTasks()); break; default: Slog.w(TAG, "Received unknown message from device: " + associationId); break; } } }
services/companion/java/com/android/server/companion/datatransfer/continuity/tasks/RemoteDeviceTaskList.java 0 → 100644 +84 −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.server.companion.datatransfer.continuity.tasks; import com.android.server.companion.datatransfer.continuity.messages.RemoteTaskInfo; import java.util.ArrayList; import java.util.List; /** * Tracks remote tasks currently available on a specific remote device. */ class RemoteDeviceTaskList { private final int mAssociationId; private final String mDeviceName; private List<RemoteTaskInfo> mTasks; RemoteDeviceTaskList( int associationId, String deviceName, List<RemoteTaskInfo> tasks) { mAssociationId = associationId; mDeviceName = deviceName; mTasks = new ArrayList<>(tasks); } /** * Returns the association ID of the remote device. */ int getAssociationId() { return mAssociationId; } /** * Returns the device name of the remote device. */ String getDeviceName() { return mDeviceName; } /** * Adds a task to the list of tasks currently available on the remote * device. */ void addTask(RemoteTaskInfo taskInfo) { mTasks.add(taskInfo); } /** * Gets the most recently used task on this device, or null if there are no * tasks. */ RemoteTaskInfo getMostRecentTask() { if (mTasks.isEmpty()) { return null; } RemoteTaskInfo mostRecentTask = mTasks.get(0); for (RemoteTaskInfo task : mTasks) { if ( task.getLastUsedTimeMillis() > mostRecentTask.getLastUsedTimeMillis()) { mostRecentTask = task; } } return mostRecentTask; } } No newline at end of file
services/companion/java/com/android/server/companion/datatransfer/continuity/tasks/RemoteTaskStore.java 0 → 100644 +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.server.companion.datatransfer.continuity.tasks; import com.android.server.companion.datatransfer.continuity.messages.RemoteTaskInfo; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class RemoteTaskStore { private final Map<Integer, RemoteDeviceTaskList> mRemoteDeviceTaskLists = new HashMap<>(); public RemoteTaskStore() {} /** * Registers a device with the task store. * * @param associationId The ID of the device. * @param deviceName The name of the device. * @param tasks The list of tasks currently available on the device on first * connection. */ public void registerDevice( int associationId, String deviceName, List<RemoteTaskInfo> tasks) { RemoteDeviceTaskList taskList = new RemoteDeviceTaskList(associationId, deviceName, tasks); mRemoteDeviceTaskLists.put(associationId, taskList); } /** * Returns the most recent tasks from all devices in the task store. * * @return A list of the most recent tasks from all devices in the task * store. */ public List<RemoteTaskInfo> getMostRecentTasks() { List<RemoteTaskInfo> mostRecentTasks = new ArrayList<>(); for (RemoteDeviceTaskList taskList : mRemoteDeviceTaskLists.values()) { RemoteTaskInfo mostRecentTask = taskList.getMostRecentTask(); if (mostRecentTask != null) { mostRecentTasks.add(mostRecentTask); } } return mostRecentTasks; } } No newline at end of file
services/tests/servicestests/src/com/android/server/companion/datatransfer/continuity/tasks/RemoteDeviceTaskListTest.java 0 → 100644 +120 −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.server.companion.datatransfer.continuity.tasks; import static com.google.common.truth.Truth.assertThat; import android.app.ActivityManager; import android.platform.test.annotations.Presubmit; import android.testing.AndroidTestingRunner; import com.android.server.companion.datatransfer.continuity.messages.RemoteTaskInfo; import org.junit.Test; import org.junit.runner.RunWith; import java.util.Arrays; import java.util.ArrayList; import java.util.List; @Presubmit @RunWith(AndroidTestingRunner.class) public class RemoteDeviceTaskListTest { @Test public void testConstructor_initializesCorrectly() { int associationId = 123; String deviceName = "device1"; RemoteTaskInfo expectedTask = createNewRemoteTaskInfo("task1", 100); List<RemoteTaskInfo> initialTasks = Arrays.asList(expectedTask); RemoteDeviceTaskList taskList = new RemoteDeviceTaskList( associationId, deviceName, initialTasks); assertThat(taskList.getMostRecentTask()).isEqualTo(expectedTask); assertThat(taskList.getAssociationId()).isEqualTo(associationId); assertThat(taskList.getDeviceName()).isEqualTo(deviceName); } @Test public void testAddTask_updatesMostRecentTask() { RemoteDeviceTaskList taskList = new RemoteDeviceTaskList( 0, "device name", new ArrayList<>()); RemoteTaskInfo firstAddedTask = createNewRemoteTaskInfo("task2", 200); taskList.addTask(firstAddedTask); assertThat(taskList.getMostRecentTask()).isEqualTo(firstAddedTask); // Add another task with an older timestamp, verify it doesn't update // the most recent task. RemoteTaskInfo secondAddedTask = createNewRemoteTaskInfo("task1", 100); taskList.addTask(secondAddedTask); assertThat(taskList.getMostRecentTask()).isEqualTo(firstAddedTask); // Add another task with a newer timestamp, verifying it changes the // most recently used task. RemoteTaskInfo thirdAddedTask = createNewRemoteTaskInfo("task3", 300); taskList.addTask(thirdAddedTask); assertThat(taskList.getMostRecentTask()).isEqualTo(thirdAddedTask); } @Test public void testGetMostRecentTask_emptyList_returnsNull() { RemoteDeviceTaskList taskList = new RemoteDeviceTaskList( 0, "device name", new ArrayList<>()); assertThat(taskList.getMostRecentTask()).isNull(); } @Test public void testGetMostRecentTask_multipleTasks_returnsMostRecent() { RemoteTaskInfo expectedTask = createNewRemoteTaskInfo("task2", 200); int associationId = 123; List<RemoteTaskInfo> initialTasks = Arrays.asList( createNewRemoteTaskInfo("task1", 100), expectedTask, createNewRemoteTaskInfo("task3", 150)); RemoteDeviceTaskList taskList = new RemoteDeviceTaskList( associationId, "device name", initialTasks); assertThat(taskList.getMostRecentTask()).isEqualTo(expectedTask); } private RemoteTaskInfo createNewRemoteTaskInfo( String label, long lastUsedTimeMillis) { ActivityManager.RunningTaskInfo runningTaskInfo = new ActivityManager.RunningTaskInfo(); runningTaskInfo.taskId = 1; runningTaskInfo.taskDescription = new ActivityManager.TaskDescription(label); runningTaskInfo.lastActiveTime = lastUsedTimeMillis; return new RemoteTaskInfo(runningTaskInfo); } } No newline at end of file
services/tests/servicestests/src/com/android/server/companion/datatransfer/continuity/tasks/RemoteTaskStoreTest.java 0 → 100644 +93 −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.server.companion.datatransfer.continuity.tasks; import static com.google.common.truth.Truth.assertThat; import android.app.ActivityManager; import android.platform.test.annotations.Presubmit; import android.testing.AndroidTestingRunner; import com.android.server.companion.datatransfer.continuity.messages.RemoteTaskInfo; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import java.util.Arrays; import java.util.ArrayList; import java.util.List; @Presubmit @RunWith(AndroidTestingRunner.class) public class RemoteTaskStoreTest { private RemoteTaskStore taskStore; @Before public void setUp() { taskStore = new RemoteTaskStore(); } @Test public void testRegisterDevice_addsDeviceToStore() { RemoteTaskInfo expectedTask = createNewRemoteTaskInfo("task1", 100); taskStore.registerDevice(0, "device name", Arrays.asList(expectedTask)); assertThat(taskStore.getMostRecentTasks()).containsExactly(expectedTask); } @Test public void testGetMostRecentTasks_emptyStore_returnsEmptyList() { assertThat(taskStore.getMostRecentTasks()).isEmpty(); } @Test public void testGetMostRecentTasks_multipleDevices_returnsMostRecentFromEach() { RemoteTaskInfo expectedTaskFromDevice1 = createNewRemoteTaskInfo("task1", 100); RemoteTaskInfo expectedTaskFromDevice2 = createNewRemoteTaskInfo("task2", 200); taskStore.registerDevice( 0, "device1", Arrays.asList(expectedTaskFromDevice1, createNewRemoteTaskInfo("task2", 1))); taskStore.registerDevice( 1, "device2", Arrays.asList(expectedTaskFromDevice2, createNewRemoteTaskInfo("task2", 1))); assertThat(taskStore.getMostRecentTasks()) .containsExactly(expectedTaskFromDevice1, expectedTaskFromDevice2); } @Test public void testGetMostRecentTasks_deviceWithNoTasks_returnsEmptyList() { taskStore.registerDevice(0, "device name", new ArrayList<>()); assertThat(taskStore.getMostRecentTasks()).isEmpty(); } private RemoteTaskInfo createNewRemoteTaskInfo(String label, long lastUsedTimeMillis) { ActivityManager.RunningTaskInfo runningTaskInfo = new ActivityManager.RunningTaskInfo(); runningTaskInfo.taskId = 1; runningTaskInfo.taskDescription = new ActivityManager.TaskDescription(label); runningTaskInfo.lastActiveTime = lastUsedTimeMillis; return new RemoteTaskInfo(runningTaskInfo); } } No newline at end of file