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

Commit ec205077 authored by Joe Antonetti's avatar Joe Antonetti Committed by Android (Google) Code Review
Browse files

Merge "Allow Listeners to subscribe to RemoteTaskStore" into main

parents 33d6b13d ef115acc
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -85,10 +85,12 @@ public final class TaskContinuityManagerService extends SystemService {

        @Override
        public void registerRemoteTaskListener(@NonNull IRemoteTaskListener listener) {
            mRemoteTaskStore.addListener(listener);
        }

        @Override
        public void unregisterRemoteTaskListener(@NonNull IRemoteTaskListener listener) {
            mRemoteTaskStore.removeListener(listener);
        }

        @Override
+65 −19
Original line number Diff line number Diff line
@@ -17,26 +17,52 @@
package com.android.server.companion.datatransfer.continuity.tasks;

import android.companion.datatransfer.continuity.RemoteTask;
import android.util.Slog;

import com.android.server.companion.datatransfer.continuity.messages.RemoteTaskInfo;

import java.util.function.Consumer;
import java.util.ArrayList;
import java.util.List;
import java.util.Comparator;
import java.util.HashSet;
import java.util.PriorityQueue;
import java.util.Set;

/**
 * Tracks remote tasks currently available on a specific remote device.
 */
class RemoteDeviceTaskList {

    private static final String TAG = "RemoteDeviceTaskList";

    private final int mAssociationId;
    private final String mDeviceName;
    private final List<RemoteTaskInfo> mTasks = new ArrayList<>();
    private final Consumer<RemoteTask> mOnMostRecentTaskChangedListener;
    private PriorityQueue<RemoteTaskInfo> mTasks;

    RemoteDeviceTaskList(
        int associationId,
        String deviceName) {
        String deviceName,
        Consumer<RemoteTask> onMostRecentTaskChangedListener) {

        mAssociationId = associationId;
        mDeviceName = deviceName;
        mOnMostRecentTaskChangedListener = onMostRecentTaskChangedListener;
        mTasks = new PriorityQueue<>(new Comparator<RemoteTaskInfo>() {
            @Override
            public int compare(RemoteTaskInfo task1, RemoteTaskInfo task2) {
                long lastUsedTime1 = task1.getLastUsedTimeMillis();
                long lastUsedTime2 = task2.getLastUsedTimeMillis();
                if (lastUsedTime1 < lastUsedTime2) {
                    return 1;
                } else if (lastUsedTime1 > lastUsedTime2) {
                    return -1;
                } else {
                    return 0;
                }
            }
        });
    }

    /**
@@ -58,22 +84,49 @@ class RemoteDeviceTaskList {
     * device.
     */
    void addTask(RemoteTaskInfo taskInfo) {
        synchronized (mTasks) {
            Slog.v(TAG, "Adding task: " + taskInfo.getId() + " to association: " + mAssociationId);
            int previousTopTaskId
                = mTasks.peek() == null ? -1 : mTasks.peek().getId();

            mTasks.add(taskInfo);
            if (taskInfo.getId() != previousTopTaskId) {
                Slog.v(
                    TAG,
                    "Notifying most recent task changed for association: " + mAssociationId);
                mOnMostRecentTaskChangedListener.accept(getMostRecentTask());
            }
        }
    }

    /**
     * Sets the list of tasks currently available on the remote device.
     */
    void setTasks(List<RemoteTaskInfo> tasks) {
        synchronized (mTasks) {
            Slog.v(TAG, "Setting remote tasks for association: " + mAssociationId);
            mTasks.clear();
            mTasks.addAll(tasks);
            mOnMostRecentTaskChangedListener.accept(getMostRecentTask());
        }
    }

    /**
     * Removes a task from the list of tasks currently available on the remote device.
     */
    void removeTask(int taskId) {
        synchronized (mTasks) {
            Slog.v(TAG, "Removing task: " + taskId + " for association: " + mAssociationId);
            boolean shouldNotifyListeners
                = (mTasks.peek() != null && mTasks.peek().getId() == taskId);
            mTasks.removeIf(task -> task.getId() == taskId);
            if (shouldNotifyListeners) {
                Slog.v(
                    TAG,
                    "Notifying most recent task changed for association: " + mAssociationId);
                mOnMostRecentTaskChangedListener.accept(getMostRecentTask());
            }
        }
    }

    /**
@@ -81,20 +134,13 @@ class RemoteDeviceTaskList {
     * tasks.
     */
    RemoteTask getMostRecentTask() {
        synchronized (mTasks) {
            Slog.v(TAG, "Getting most recent task for association: " + mAssociationId);
            if (mTasks.isEmpty()) {
                return null;
            }

        RemoteTaskInfo mostRecentTask = mTasks.get(0);
        for (RemoteTaskInfo task : mTasks) {
            if (
                task.getLastUsedTimeMillis()
                    > mostRecentTask.getLastUsedTimeMillis()) {

                mostRecentTask = task;
            }
            return mTasks.peek().toRemoteTask(mAssociationId, mDeviceName);
        }

        return mostRecentTask.toRemoteTask(mAssociationId, mDeviceName);
    }
}
 No newline at end of file
+46 −3
Original line number Diff line number Diff line
@@ -16,6 +16,9 @@
package com.android.server.companion.datatransfer.continuity.tasks;

import android.companion.AssociationInfo;
import android.companion.datatransfer.continuity.IRemoteTaskListener;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.util.Slog;

import com.android.server.companion.datatransfer.continuity.connectivity.ConnectedAssociationStore;
@@ -35,6 +38,8 @@ public class RemoteTaskStore implements ConnectedAssociationStore.Observer {
    private final ConnectedAssociationStore mConnectedAssociationStore;
    private final Map<Integer, RemoteDeviceTaskList> mRemoteDeviceTaskLists
        = new HashMap<>();
    private final RemoteCallbackList<IRemoteTaskListener>
        mRemoteTaskListeners = new RemoteCallbackList<>();

    public RemoteTaskStore(
        ConnectedAssociationStore connectedAssociationStore) {
@@ -57,7 +62,8 @@ public class RemoteTaskStore implements ConnectedAssociationStore.Observer {
            if (!mRemoteDeviceTaskLists.containsKey(associationId)) {
                Slog.e(
                    TAG,
                    "Attempted to set tasks for association: " + associationId + " which is not connected.");
                    "Attempted to set tasks for association: " + associationId
                        + " which is not connected.");

                return;
            }
@@ -110,18 +116,32 @@ public class RemoteTaskStore implements ConnectedAssociationStore.Observer {
        }
    }

    public void addListener(IRemoteTaskListener listener) {
        synchronized (mRemoteTaskListeners) {
            mRemoteTaskListeners.register(listener);
        }
    }

    public void removeListener(IRemoteTaskListener listener) {
        synchronized (mRemoteTaskListeners) {
            mRemoteTaskListeners.unregister(listener);
        }
    }

    @Override
    public void onTransportConnected(AssociationInfo associationInfo) {
        synchronized (mRemoteDeviceTaskLists) {
            if (!mRemoteDeviceTaskLists.containsKey(associationInfo.getId())) {
                Slog.v(
                    TAG,
                    "Creating new RemoteDeviceTaskList for association: " + associationInfo.getId());
                    "Creating new RemoteDeviceTaskList for association: "
                        + associationInfo.getId());

                RemoteDeviceTaskList taskList
                    = new RemoteDeviceTaskList(
                        associationInfo.getId(),
                        associationInfo.getDisplayName().toString());
                        associationInfo.getDisplayName().toString(),
                        this::onMostRecentTaskChanged);

                mRemoteDeviceTaskLists.put(associationInfo.getId(), taskList);
            } else {
@@ -140,6 +160,29 @@ public class RemoteTaskStore implements ConnectedAssociationStore.Observer {
                "Deleting RemoteDeviceTaskList for association: " + associationId);

            mRemoteDeviceTaskLists.remove(associationId);
            notifyListeners();
        }
    }

    private void onMostRecentTaskChanged(RemoteTask task) {
        notifyListeners();
    }

    private void notifyListeners() {
       synchronized (mRemoteTaskListeners) {
            List<RemoteTask> remoteTasks = getMostRecentTasks();
            int i = mRemoteTaskListeners.beginBroadcast();
            while (i > 0) {
                i--;
                try {
                    mRemoteTaskListeners
                        .getBroadcastItem(i)
                        .onRemoteTasksChanged(remoteTasks);
                } catch (RemoteException e) {
                    Slog.e(TAG, "Failed to notify listener: " + e.getMessage());
                }
            }
            mRemoteTaskListeners.finishBroadcast();
        }
    }
}
 No newline at end of file
+81 −39
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import android.testing.AndroidTestingRunner;

import com.android.server.companion.datatransfer.continuity.messages.RemoteTaskInfo;

import org.junit.Before;
import org.junit.Test;
import org.junit.Before;
import org.junit.runner.RunWith;
@@ -38,6 +39,9 @@ import java.util.List;
@RunWith(AndroidTestingRunner.class)
public class RemoteDeviceTaskListTest {

    private RemoteTask mMostRecentTask;
    private int mObserverCallCount;

    private static final int ASSOCIATION_ID = 123;
    private static final String DEVICE_NAME = "device1";

@@ -45,7 +49,13 @@ public class RemoteDeviceTaskListTest {

    @Before
    public void setUp() {
        taskList = new RemoteDeviceTaskList(ASSOCIATION_ID, DEVICE_NAME);
        mMostRecentTask = null;
        mObserverCallCount = 0;

        taskList = new RemoteDeviceTaskList(
            ASSOCIATION_ID,
            DEVICE_NAME,
            this::onMostRecentTaskChanged);
    }

    @Test
@@ -56,27 +66,37 @@ public class RemoteDeviceTaskListTest {
    }

    @Test
    public void testAddTask_updatesMostRecentTask() {
        RemoteTaskInfo firstAddedTask = createNewRemoteTaskInfo(2, "task2", 200);

        taskList.addTask(firstAddedTask);
    public void testAddTask_updatesMostRecentTaskAndNotifiesListeners() {
        // Before adding any tasks, the most recent task should be null.
        assertThat(taskList.getMostRecentTask()).isNull();

        assertThat(taskList.getMostRecentTask())
            .isEqualTo(firstAddedTask.toRemoteTask(ASSOCIATION_ID, DEVICE_NAME));
        // Add a task, verify it automatically becomes the most recent task.
        RemoteTaskInfo firstAddedTaskInfo
            = createNewRemoteTaskInfo(2, "task2", 200);
        RemoteTask firstAddedTask
            = firstAddedTaskInfo.toRemoteTask(ASSOCIATION_ID, DEVICE_NAME);
        taskList.addTask(firstAddedTaskInfo);
        assertThat(mObserverCallCount).isEqualTo(1);
        assertThat(mMostRecentTask).isEqualTo(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(1, "task1", 100);
        taskList.addTask(secondAddedTask);
        assertThat(taskList.getMostRecentTask())
            .isEqualTo(firstAddedTask.toRemoteTask(ASSOCIATION_ID, DEVICE_NAME));
        RemoteTaskInfo secondAddedTaskInfo = createNewRemoteTaskInfo(1, "task1", 100);
        taskList.addTask(secondAddedTaskInfo);
        assertThat(taskList.getMostRecentTask()).isEqualTo(firstAddedTask);
        assertThat(mObserverCallCount).isEqualTo(2);
        assertThat(mMostRecentTask).isEqualTo(firstAddedTask);

        // Add another task with a newer timestamp, verifying it changes the
        // most recently used task.
        RemoteTaskInfo thirdAddedTask = createNewRemoteTaskInfo(3, "task3", 300);
        taskList.addTask(thirdAddedTask);
        assertThat(taskList.getMostRecentTask())
            .isEqualTo(thirdAddedTask.toRemoteTask(ASSOCIATION_ID, DEVICE_NAME));
        RemoteTaskInfo thirdAddedTaskInfo = createNewRemoteTaskInfo(3, "task3", 300);
        RemoteTask thirdAddedTask = thirdAddedTaskInfo.toRemoteTask(ASSOCIATION_ID, DEVICE_NAME);
        taskList.addTask(thirdAddedTaskInfo);

        assertThat(taskList.getMostRecentTask()).isEqualTo(thirdAddedTask);
        assertThat(mObserverCallCount).isEqualTo(3);
        assertThat(mMostRecentTask).isEqualTo(thirdAddedTask);
    }

    @Test
@@ -94,12 +114,11 @@ public class RemoteDeviceTaskListTest {

        taskList.setTasks(initialTasks);

        assertThat(taskList.getMostRecentTask())
            .isEqualTo(expectedTask.toRemoteTask(ASSOCIATION_ID, DEVICE_NAME));
        assertThat(taskList.getMostRecentTask().getId()).isEqualTo(expectedTask.getId());
    }

    @Test
    public void testRemoveTask_removesTask() {
    public void testRemoveTask_removesTaskAndNotifiesListeners() {
        RemoteTaskInfo mostRecentTaskInfo = createNewRemoteTaskInfo(1, "task2", 200);
        RemoteTask mostRecentTask = mostRecentTaskInfo.toRemoteTask(ASSOCIATION_ID, DEVICE_NAME);
        RemoteTaskInfo secondMostRecentTaskInfo = createNewRemoteTaskInfo(2, "task1", 100);
@@ -107,57 +126,75 @@ public class RemoteDeviceTaskListTest {
            = secondMostRecentTaskInfo.toRemoteTask(ASSOCIATION_ID, DEVICE_NAME);

        taskList.setTasks(Arrays.asList(mostRecentTaskInfo, secondMostRecentTaskInfo));
        assertThat(taskList.getMostRecentTask())
            .isEqualTo(mostRecentTask);
        assertThat(taskList.getMostRecentTask()).isEqualTo(mostRecentTask);
        assertThat(mObserverCallCount).isEqualTo(1);
        assertThat(mMostRecentTask).isEqualTo(mostRecentTask);

        taskList.removeTask(mostRecentTask.getId());
        assertThat(taskList.getMostRecentTask())
            .isEqualTo(secondMostRecentTask);
        assertThat(taskList.getMostRecentTask()).isEqualTo(secondMostRecentTask);
        assertThat(mObserverCallCount).isEqualTo(2);
        assertThat(mMostRecentTask).isEqualTo(secondMostRecentTask);
    }

    @Test
    public void testSetTasks_updatesMostRecentTask() {
    public void testSetTasks_updatesMostRecentTaskAndNotifiesListeners() {

        // Set tasks initially, verify the most recent task is the first one.
        RemoteTaskInfo firstExpectedTask
            = createNewRemoteTaskInfo(1, "task2", 200);
        RemoteTaskInfo firstExpectedTaskInfo = createNewRemoteTaskInfo(1, "task2", 200);
        RemoteTask firstExpectedTask
            = firstExpectedTaskInfo.toRemoteTask(ASSOCIATION_ID, DEVICE_NAME);

        List<RemoteTaskInfo> initialTasks = Arrays.asList(
                createNewRemoteTaskInfo(2, "task1", 100),
                firstExpectedTask,
                firstExpectedTaskInfo,
                createNewRemoteTaskInfo(3, "task3", 150));

        taskList.setTasks(initialTasks);
        assertThat(taskList.getMostRecentTask())
            .isEqualTo(firstExpectedTask.toRemoteTask(ASSOCIATION_ID, DEVICE_NAME));

        assertThat(taskList.getMostRecentTask().getId()).isEqualTo(firstExpectedTask.getId());
        assertThat(mObserverCallCount).isEqualTo(1);
        assertThat(mMostRecentTask.getId()).isEqualTo(firstExpectedTask.getId());

        // Set the tasks to a different list, verify the most recent task is the
        // first one.
        RemoteTaskInfo secondExpectedTask
            = createNewRemoteTaskInfo(4, "task4", 300);
        RemoteTaskInfo secondExpectedTaskInfo = createNewRemoteTaskInfo(4, "task4", 300);
        List<RemoteTaskInfo> secondExpectedTasks = Arrays.asList(
                secondExpectedTask,
                secondExpectedTaskInfo,
                createNewRemoteTaskInfo(7, "task7", 200),
                createNewRemoteTaskInfo(5, "task5", 200),
                createNewRemoteTaskInfo(6, "task6", 100));
        RemoteTask secondExpectedTask =
            secondExpectedTaskInfo.toRemoteTask(ASSOCIATION_ID, DEVICE_NAME);

        taskList.setTasks(secondExpectedTasks);
        assertThat(taskList.getMostRecentTask())
            .isEqualTo(secondExpectedTask.toRemoteTask(ASSOCIATION_ID, DEVICE_NAME));

        assertThat(mObserverCallCount).isEqualTo(2);
        assertThat(mMostRecentTask).isEqualTo(secondExpectedTask);
        assertThat(taskList.getMostRecentTask()).isEqualTo(secondExpectedTask);
    }

    @Test
    public void testSetTasks_overwritesExistingTasks() {
    public void testSetTasks_overwritesExistingTasksAndNotifiesListeners() {
        // Set the initial state of the list.
        RemoteTaskInfo firstExpectedTask = createNewRemoteTaskInfo(1, "task1", 100);
        RemoteTask firstExpectedRemoteTask =
            firstExpectedTask.toRemoteTask(ASSOCIATION_ID, DEVICE_NAME);
        taskList.setTasks(Arrays.asList(firstExpectedTask));
        assertThat(taskList.getMostRecentTask())
            .isEqualTo(firstExpectedTask.toRemoteTask(ASSOCIATION_ID, DEVICE_NAME));
        assertThat(taskList.getMostRecentTask()).isEqualTo(firstExpectedRemoteTask);
        assertThat(mObserverCallCount).isEqualTo(1);
        assertThat(mMostRecentTask).isEqualTo(firstExpectedRemoteTask);

        // Replace the tasks with a different list. The only task in this was used before the
        // previous task.
        RemoteTaskInfo secondExpectedTask = createNewRemoteTaskInfo(2, "task2", 10);
        RemoteTaskInfo secondExpectedTask = createNewRemoteTaskInfo(2, "task2", 200);
        RemoteTask secondExpectedRemoteTask
            = secondExpectedTask.toRemoteTask(ASSOCIATION_ID, DEVICE_NAME);
        taskList.setTasks(Arrays.asList(secondExpectedTask));

        // Because the task list is overwritten, the most recent task should be the second task.
        assertThat(taskList.getMostRecentTask())
            .isEqualTo(secondExpectedTask.toRemoteTask(ASSOCIATION_ID, DEVICE_NAME));
        assertThat(taskList.getMostRecentTask()).isEqualTo(secondExpectedRemoteTask);
        assertThat(mObserverCallCount).isEqualTo(2);
        assertThat(mMostRecentTask).isEqualTo(secondExpectedRemoteTask);
    }

    private RemoteTaskInfo createNewRemoteTaskInfo(
@@ -172,4 +209,9 @@ public class RemoteDeviceTaskListTest {

        return new RemoteTaskInfo(runningTaskInfo);
    }

    public void onMostRecentTaskChanged(RemoteTask task) {
        mMostRecentTask = task;
        mObserverCallCount++;
    }
}
 No newline at end of file
+40 −7
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import static com.android.server.companion.datatransfer.continuity.TaskContinuit
import android.app.ActivityManager;
import android.companion.AssociationInfo;
import android.companion.datatransfer.continuity.RemoteTask;
import android.companion.datatransfer.continuity.IRemoteTaskListener;
import android.platform.test.annotations.Presubmit;
import android.testing.AndroidTestingRunner;

@@ -42,6 +43,7 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

@@ -52,13 +54,23 @@ public class RemoteTaskStoreTest {
    @Mock
    private ConnectedAssociationStore mMockConnectedAssociationStore;

    private final IRemoteTaskListener mRemoteTaskListener = new IRemoteTaskListener.Stub() {
        @Override
        public void onRemoteTasksChanged(List<RemoteTask> remoteTasks) {
            remoteTasksReportedToListener.add(remoteTasks);
        }
    };

    private final List<List<RemoteTask>> remoteTasksReportedToListener = new ArrayList<>();
    private RemoteTaskStore taskStore;

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);

        remoteTasksReportedToListener.clear();
        taskStore = new RemoteTaskStore(mMockConnectedAssociationStore);
        taskStore.addListener(mRemoteTaskListener);
    }

    @Test
@@ -68,20 +80,25 @@ public class RemoteTaskStoreTest {
    }

    @Test
    public void onTransportConnected_addsNewAssociation() {
    public void onTransportConnected_addsNewAssociationAndNotifiesListeners() {
        // Simulate a new association being connected.
        AssociationInfo associationInfo = createAssociationInfo(1, "name");
        taskStore.onTransportConnected(associationInfo);
        assertThat(remoteTasksReportedToListener).hasSize(0);

        // Add tasks to the new association.
        RemoteTaskInfo remoteTaskInfo = createNewRemoteTaskInfo(1, "task1", 100L);
        RemoteTask remoteTask
            = remoteTaskInfo.toRemoteTask(associationInfo.getId(), "name");

        taskStore.setTasks(
            associationInfo.getId(),
            Collections.singletonList(remoteTaskInfo));
        assertThat(remoteTasksReportedToListener).hasSize(1);
        assertThat(remoteTasksReportedToListener.get(0)).containsExactly(remoteTask);

        // Verify the most recent task is added to the task store.
        assertThat(taskStore.getMostRecentTasks())
            .containsExactly(remoteTaskInfo.toRemoteTask(associationInfo.getId(), "name"));
        assertThat(taskStore.getMostRecentTasks()).containsExactly(remoteTask);
    }

    @Test
@@ -96,6 +113,7 @@ public class RemoteTaskStoreTest {
        taskStore.setTasks(0, Collections.singletonList(remoteTaskInfo));

        assertThat(taskStore.getMostRecentTasks()).isEmpty();
        assertThat(remoteTasksReportedToListener).isEmpty();
    }

    @Test
@@ -117,32 +135,43 @@ public class RemoteTaskStoreTest {

        assertThat(taskStore.getMostRecentTasks())
            .containsExactly(mostRecentTask);
        assertThat(remoteTasksReportedToListener).hasSize(1);
        assertThat(remoteTasksReportedToListener.get(0)).containsExactly(mostRecentTask);

        taskStore.removeTask(associationInfo.getId(), mostRecentTaskInfo.getId());
        assertThat(taskStore.getMostRecentTasks()).containsExactly(secondMostRecentTask);
        assertThat(remoteTasksReportedToListener).hasSize(2);
        assertThat(remoteTasksReportedToListener.get(1))
            .containsExactly(secondMostRecentTask);
    }

    @Test
    public void onTransportDisconnected_removesAssociation() {
    public void onTransportDisconnected_removesAssociationAndNotifiesListeners() {
        // Create a fake association info, and have connected association store
        // return it.
        AssociationInfo associationInfo = createAssociationInfo(1, "name");
        when(mMockConnectedAssociationStore.getConnectedAssociationById(1))
                .thenReturn(associationInfo);
        taskStore.onTransportConnected(associationInfo);

        // Set tasks for the association.
        RemoteTaskInfo remoteTaskInfo = createNewRemoteTaskInfo(1, "task1", 100L);
        taskStore.setTasks(0, Collections.singletonList(remoteTaskInfo));
        taskStore.setTasks(associationInfo.getId(), Collections.singletonList(remoteTaskInfo));
        assertThat(remoteTasksReportedToListener).hasSize(1);
        assertThat(remoteTasksReportedToListener.get(0))
            .containsExactly(remoteTaskInfo.toRemoteTask(1, "name"));

        // Simulate the association being disconnected.
        taskStore.onTransportDisconnected(0);
        taskStore.onTransportDisconnected(associationInfo.getId());

        // Verify the most recent task is added to the task store.
        assertThat(taskStore.getMostRecentTasks()).isEmpty();
        assertThat(remoteTasksReportedToListener).hasSize(2);
        assertThat(remoteTasksReportedToListener.get(1)).isEmpty();
    }

    @Test
    public void addTask_addsTaskToAssociation() {
    public void addTask_addsTaskToAssociationAndNotifiesListeners() {
        // Create a fake association info, and have connected association store return it.
        AssociationInfo associationInfo = createAssociationInfo(1, "name");
        when(mMockConnectedAssociationStore.getConnectedAssociationById(1))
@@ -153,6 +182,8 @@ public class RemoteTaskStoreTest {
        RemoteTask remoteTask = remoteTaskInfo.toRemoteTask(associationInfo.getId(), "name");
        taskStore.setTasks(1, Collections.singletonList(remoteTaskInfo));
        assertThat(taskStore.getMostRecentTasks()).containsExactly(remoteTask);
        assertThat(remoteTasksReportedToListener).hasSize(1);
        assertThat(remoteTasksReportedToListener.get(0)).containsExactly(remoteTask);

        // Add a new task to the association.
        RemoteTaskInfo newRemoteTaskInfo = createNewRemoteTaskInfo(2, "task2", 200L);
@@ -161,6 +192,8 @@ public class RemoteTaskStoreTest {

        // Verify the most recent tasks are added to the task store.
        assertThat(taskStore.getMostRecentTasks()).containsExactly(newRemoteTask);
        assertThat(remoteTasksReportedToListener).hasSize(2);
        assertThat(remoteTasksReportedToListener.get(1)).containsExactly(newRemoteTask);
    }

    @Test