Loading services/companion/java/com/android/server/companion/datatransfer/continuity/TaskBroadcaster.java +39 −79 Original line number Diff line number Diff line Loading @@ -19,11 +19,9 @@ package com.android.server.companion.datatransfer.continuity; import static com.android.server.companion.datatransfer.contextsync.BitmapUtils.renderDrawableToByteArray; import android.annotation.NonNull; import android.app.ActivityManager; import android.app.ActivityManager.RunningTaskInfo; import android.app.ActivityTaskManager; import android.app.TaskStackListener; import android.companion.AssociationInfo; import android.content.ComponentName; import android.content.Context; import android.content.pm.PackageInfo; Loading @@ -32,7 +30,6 @@ import android.graphics.drawable.Drawable; import android.os.RemoteException; import android.util.Slog; import com.android.server.companion.datatransfer.continuity.connectivity.ConnectedAssociationStore; import com.android.server.companion.datatransfer.continuity.connectivity.TaskContinuityMessenger; import com.android.server.companion.datatransfer.continuity.messages.ContinuityDeviceConnected; import com.android.server.companion.datatransfer.continuity.messages.RemoteTaskAddedMessage; Loading @@ -41,21 +38,16 @@ import com.android.server.companion.datatransfer.continuity.messages.RemoteTaskU import com.android.server.companion.datatransfer.continuity.messages.RemoteTaskInfo; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.Objects; import java.util.stream.Collectors; /** * Responsible for broadcasting recent tasks on the current device to the user's * * other devices via {@link CompanionDeviceManager}. */ class TaskBroadcaster extends TaskStackListener implements ConnectedAssociationStore.Observer { class TaskBroadcaster extends TaskStackListener { private static final String TAG = "TaskBroadcaster"; Loading @@ -64,7 +56,7 @@ class TaskBroadcaster private final TaskContinuityMessenger mTaskContinuityMessenger; private final PackageManager mPackageManager; private boolean mIsBroadcasting = false; private boolean mIsListeningToActivityTaskManager = false; public TaskBroadcaster( @NonNull Context context, Loading @@ -79,56 +71,35 @@ class TaskBroadcaster mTaskContinuityMessenger = taskContinuityMessenger; } void startBroadcasting(){ if (mIsBroadcasting) { Slog.v(TAG, "TaskBroadcaster is already broadcasting"); return; } Slog.v(TAG, "Starting broadcasting"); mTaskContinuityMessenger.getConnectedAssociationStore().addObserver(this); public void onDeviceConnected(int id) { Slog.v(TAG, "Transport connected for association id: " + id); sendDeviceConnectedMessage(id); synchronized (this) { if (!mIsListeningToActivityTaskManager) { mActivityTaskManager.registerTaskStackListener(this); mIsBroadcasting = true; mIsListeningToActivityTaskManager = true; } } void stopBroadcasting(){ if (!mIsBroadcasting) { Slog.v(TAG, "TaskBroadcaster is not broadcasting"); return; } Slog.v(TAG, "Stopping broadcasting"); mIsBroadcasting = false; mTaskContinuityMessenger.getConnectedAssociationStore().removeObserver(this); public void onAllDevicesDisconnected() { synchronized (this) { if (mIsListeningToActivityTaskManager) { mActivityTaskManager.unregisterTaskStackListener(this); mIsListeningToActivityTaskManager = false; } @Override public void onTransportConnected(AssociationInfo associationInfo) { Slog.v( TAG, "Transport connected for association id: " + associationInfo.getId()); sendDeviceConnectedMessage(associationInfo.getId()); } @Override public void onTransportDisconnected(int associationId) { Slog.v( TAG, "Transport disconnected for association id: " + associationId); } @Override public void onTaskCreated( int taskId, ComponentName componentName) throws RemoteException { public void onTaskCreated(int taskId, ComponentName componentName) throws RemoteException { Slog.v(TAG, "onTaskCreated: taskId=" + taskId); RunningTaskInfo taskInfo = getRunningTask(taskId); if (taskInfo == null) { Slog.w(TAG, "Could not find RunningTaskInfo for taskId: " + taskId); return; } ActivityManager.RunningTaskInfo taskInfo = getRunningTask(taskId); if (taskInfo != null) { RemoteTaskInfo remoteTaskInfo = createRemoteTaskInfo(taskInfo); if (remoteTaskInfo == null) { Slog.w(TAG, "Could not create RemoteTaskInfo for task: " + taskInfo.taskId); Loading @@ -137,15 +108,11 @@ class TaskBroadcaster RemoteTaskAddedMessage taskAddedMessage = new RemoteTaskAddedMessage(remoteTaskInfo); mTaskContinuityMessenger.sendMessage(taskAddedMessage); } else { Slog.w(TAG, "Could not find RunningTaskInfo for taskId: " + taskId); } } @Override public void onTaskRemoved(int taskId) throws RemoteException { Slog.v(TAG, "onTaskRemoved: taskId=" + taskId); RemoteTaskRemovedMessage taskRemovedMessage = new RemoteTaskRemovedMessage(taskId); mTaskContinuityMessenger.sendMessage(taskRemovedMessage); } Loading @@ -170,17 +137,10 @@ class TaskBroadcaster "Sending device connected message for association id: " + associationId); List<ActivityManager.RunningTaskInfo> runningTasks = getRunningTasks(); List<RemoteTaskInfo> remoteTasks = new ArrayList<>(); for (ActivityManager.RunningTaskInfo taskInfo : runningTasks) { RemoteTaskInfo remoteTaskInfo = createRemoteTaskInfo(taskInfo); if (remoteTaskInfo != null) { remoteTasks.add(remoteTaskInfo); } else { Slog.w(TAG, "Could not create RemoteTaskInfo for task: " + taskInfo.taskId); } } List<RemoteTaskInfo> remoteTasks = getRunningTasks().stream() .map(this::createRemoteTaskInfo) .filter(Objects::nonNull) .collect(Collectors.toList()); ContinuityDeviceConnected deviceConnectedMessage = new ContinuityDeviceConnected(remoteTasks); Loading @@ -188,10 +148,10 @@ class TaskBroadcaster mTaskContinuityMessenger.sendMessage(associationId, deviceConnectedMessage); } private ActivityManager.RunningTaskInfo getRunningTask(int taskId) { List<ActivityManager.RunningTaskInfo> runningTasks = getRunningTasks(); private RunningTaskInfo getRunningTask(int taskId) { List<RunningTaskInfo> runningTasks = getRunningTasks(); if (runningTasks != null) { for (ActivityManager.RunningTaskInfo info : runningTasks) { for (RunningTaskInfo info : runningTasks) { if (info.taskId == taskId) { return info; } Loading @@ -201,11 +161,11 @@ class TaskBroadcaster return null; } private List<ActivityManager.RunningTaskInfo> getRunningTasks() { private List<RunningTaskInfo> getRunningTasks() { return mActivityTaskManager.getTasks(Integer.MAX_VALUE, true); } private RemoteTaskInfo createRemoteTaskInfo(ActivityManager.RunningTaskInfo taskInfo) { private RemoteTaskInfo createRemoteTaskInfo(RunningTaskInfo taskInfo) { PackageInfo packageInfo; try { packageInfo = mPackageManager.getPackageInfo( Loading services/companion/java/com/android/server/companion/datatransfer/continuity/TaskContinuityManagerService.java +23 −3 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.server.companion.datatransfer.continuity; import android.annotation.NonNull; import android.companion.AssociationInfo; import android.companion.CompanionDeviceManager; import android.companion.datatransfer.continuity.IHandoffRequestCallback; import android.companion.datatransfer.continuity.ITaskContinuityManager; Loading @@ -42,6 +43,7 @@ import com.android.server.SystemService; import java.util.ArrayList; import java.util.List; import java.util.Collection; /** * Service to handle task continuity features Loading @@ -66,8 +68,7 @@ public final class TaskContinuityManagerService mTaskContinuityMessenger = new TaskContinuityMessenger(context, this); mTaskBroadcaster = new TaskBroadcaster(context, mTaskContinuityMessenger); mRemoteTaskStore = new RemoteTaskStore( mTaskContinuityMessenger.getConnectedAssociationStore()); mRemoteTaskStore = new RemoteTaskStore(); mOutboundHandoffRequestController = new OutboundHandoffRequestController( context, mTaskContinuityMessenger); Loading @@ -79,7 +80,6 @@ public final class TaskContinuityManagerService public void onStart() { mTaskContinuityManagerService = new TaskContinuityManagerServiceImpl(); mTaskContinuityMessenger.enable(); mTaskBroadcaster.startBroadcasting(); publishBinderService(Context.TASK_CONTINUITY_SERVICE, mTaskContinuityManagerService); } Loading Loading @@ -116,6 +116,26 @@ public final class TaskContinuityManagerService } } @Override public void onAssociationConnected(@NonNull AssociationInfo associationInfo) { mRemoteTaskStore.addDevice( associationInfo.getId(), associationInfo.getDisplayName().toString()); mTaskBroadcaster.onDeviceConnected(associationInfo.getId()); } @Override public void onAssociationDisconnected( int associationId, @NonNull Collection<AssociationInfo> connectedAssociations) { mRemoteTaskStore.removeDevice(associationId); if (connectedAssociations.isEmpty()) { mTaskBroadcaster.onAllDevicesDisconnected(); } } @Override public void onMessageReceived( int associationId, Loading services/companion/java/com/android/server/companion/datatransfer/continuity/connectivity/ConnectedAssociationStore.java +54 −27 Original line number Diff line number Diff line Loading @@ -19,9 +19,10 @@ package com.android.server.companion.datatransfer.continuity.connectivity; import android.annotation.NonNull; import android.companion.AssociationInfo; import android.companion.CompanionDeviceManager; import android.util.Log; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; Loading @@ -29,36 +30,67 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.Executor; import java.util.function.Consumer; import java.util.Objects; import javax.annotation.concurrent.GuardedBy; public class ConnectedAssociationStore { class ConnectedAssociationStore { private static final String TAG = "ConnectedAssociationStore"; private final CompanionDeviceManager mCompanionDeviceManager; private final Listener mListener; private final Executor mExecutor; private final Map<Integer, AssociationInfo> mConnectedAssociations = new HashMap<>(); private final List<Observer> mObservers = new ArrayList<>(); public interface Observer { void onTransportConnected(AssociationInfo associationInfo); void onTransportDisconnected(int associationId); @GuardedBy("this") private Consumer<List<AssociationInfo>> mAssociationInfoConsumer; interface Listener { void onTransportConnected(@NonNull AssociationInfo associationInfo); void onTransportDisconnected( int associationId, @NonNull Collection<AssociationInfo> connectedAssociations); } public ConnectedAssociationStore( ConnectedAssociationStore( @NonNull CompanionDeviceManager companionDeviceManager, @NonNull Executor executor) { @NonNull Executor executor, @NonNull Listener listener) { Objects.requireNonNull(companionDeviceManager); Objects.requireNonNull(executor); Objects.requireNonNull(listener); mCompanionDeviceManager = companionDeviceManager; mCompanionDeviceManager.addOnTransportsChangedListener( executor, this::onTransportsChanged); mListener = listener; mExecutor = executor; } public void addObserver(@NonNull Observer observer) { mObservers.add(observer); public void enable() { synchronized (this) { if (mAssociationInfoConsumer != null) { Slog.i(TAG, "ConnectedAssociationStore is already enabled."); return; } mAssociationInfoConsumer = this::onTransportsChanged; mCompanionDeviceManager.addOnTransportsChangedListener( mExecutor, mAssociationInfoConsumer); Slog.i(TAG, "Enabled ConnectedAssociationStore."); } } public void removeObserver(@NonNull Observer observer) { mObservers.remove(observer); public void disable() { synchronized (this) { if (mAssociationInfoConsumer == null) { Slog.i(TAG, "ConnectedAssociationStore is already disabled."); return; } mCompanionDeviceManager.removeOnTransportsChangedListener(mAssociationInfoConsumer); mAssociationInfoConsumer = null; Slog.i(TAG, "Disabled ConnectedAssociationStore."); } } public Collection<AssociationInfo> getConnectedAssociations() { Loading @@ -69,7 +101,8 @@ public class ConnectedAssociationStore { return mConnectedAssociations.get(associationId); } private void onTransportsChanged(List<AssociationInfo> associationInfos) { @VisibleForTesting void onTransportsChanged(List<AssociationInfo> associationInfos) { Set<Integer> removedAssociations = new HashSet<>(mConnectedAssociations.keySet()); Loading @@ -85,27 +118,21 @@ public class ConnectedAssociationStore { } for (Integer associationId : removedAssociations) { Log.i( Slog.i( TAG, "Transport disconnected for association: " + associationId); mConnectedAssociations.remove(associationId); for (Observer observer : mObservers) { observer.onTransportDisconnected(associationId); } mListener.onTransportDisconnected(associationId, associationInfos); } for (AssociationInfo associationInfo : addedAssociations) { Log.i( Slog.i( TAG, "Transport connected for association: " + associationInfo.getId()); mConnectedAssociations.put(associationInfo.getId(), associationInfo); for (Observer observer : mObservers) { observer.onTransportConnected(associationInfo); } mListener.onTransportConnected(associationInfo); } } } No newline at end of file services/companion/java/com/android/server/companion/datatransfer/continuity/connectivity/TaskContinuityMessenger.java +37 −4 Original line number Diff line number Diff line Loading @@ -38,7 +38,7 @@ import java.util.Objects; * between devices. Internally, it uses the {@link CompanionDeviceManager} to send and receive * messages. */ public class TaskContinuityMessenger { public class TaskContinuityMessenger implements ConnectedAssociationStore.Listener { private static final String TAG = "TaskContinuityMessenger"; Loading @@ -51,6 +51,10 @@ public class TaskContinuityMessenger { private BiConsumer<Integer, byte[]> mIncomingMessageConsumer; public interface Listener { void onAssociationConnected(@NonNull AssociationInfo associationInfo); void onAssociationDisconnected( int associationId, @NonNull Collection<AssociationInfo> connectedAssociations); void onMessageReceived(int associationId, @NonNull TaskContinuityMessage message); } Loading @@ -65,7 +69,8 @@ public class TaskContinuityMessenger { mCompanionDeviceManager = context.getSystemService(CompanionDeviceManager.class); mConnectedAssociationStore = new ConnectedAssociationStore( mCompanionDeviceManager, mExecutor); mExecutor, this); } public void enable() { Loading @@ -80,6 +85,8 @@ public class TaskContinuityMessenger { MESSAGE_ONEWAY_TASK_CONTINUITY, mIncomingMessageConsumer); } mConnectedAssociationStore.enable(); } public void disable() { Loading @@ -93,6 +100,8 @@ public class TaskContinuityMessenger { mIncomingMessageConsumer); mIncomingMessageConsumer = null; } mConnectedAssociationStore.disable(); } @NonNull Loading @@ -111,13 +120,18 @@ public class TaskContinuityMessenger { int associationId, @NonNull TaskContinuityMessage message) { Objects.requireNonNull(message); return sendMessage(new int[] {associationId}, message); } public SendMessageResult sendMessage( int[] associationIds, @NonNull int[] associationIds, @NonNull TaskContinuityMessage message) { Objects.requireNonNull(associationIds); Objects.requireNonNull(message); Slog.i(TAG, "Sending message to " + associationIds.length + " associations."); byte[] serializedMessage; try { Loading Loading @@ -148,6 +162,8 @@ public class TaskContinuityMessenger { } public SendMessageResult sendMessage(@NonNull TaskContinuityMessage message) { Objects.requireNonNull(message); int[] connectedAssociations = mConnectedAssociationStore .getConnectedAssociations() .stream() Loading @@ -157,6 +173,23 @@ public class TaskContinuityMessenger { return sendMessage(connectedAssociations, message); } @Override public void onTransportConnected(@NonNull AssociationInfo associationInfo) { Objects.requireNonNull(associationInfo); mListener.onAssociationConnected(associationInfo); } @Override public void onTransportDisconnected( int associationId, @NonNull Collection<AssociationInfo> connectedAssociations) { Objects.requireNonNull(connectedAssociations); mListener.onAssociationDisconnected(associationId, connectedAssociations); } private void onMessageReceived(int associationId, byte[] data) { Slog.v(TAG, "Received message from association id: " + associationId); try { Loading services/companion/java/com/android/server/companion/datatransfer/continuity/tasks/RemoteTaskStore.java +42 −45 Original line number Diff line number Diff line Loading @@ -15,13 +15,12 @@ */ package com.android.server.companion.datatransfer.continuity.tasks; import android.companion.AssociationInfo; import android.annotation.NonNull; 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; import com.android.server.companion.datatransfer.continuity.messages.RemoteTaskInfo; import android.companion.datatransfer.continuity.RemoteTask; Loading @@ -30,21 +29,15 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; public class RemoteTaskStore implements ConnectedAssociationStore.Observer { public class RemoteTaskStore { private static final String TAG = "RemoteTaskStore"; private final ConnectedAssociationStore mConnectedAssociationStore; private final Map<Integer, RemoteDeviceTaskList> mRemoteDeviceTaskLists = new HashMap<>(); private final RemoteCallbackList<IRemoteTaskListener> mRemoteTaskListeners = new RemoteCallbackList<>(); public RemoteTaskStore(ConnectedAssociationStore connectedAssociationStore) { mConnectedAssociationStore = connectedAssociationStore; mConnectedAssociationStore.addObserver(this); } private final Map<Integer, RemoteDeviceTaskList> mRemoteDeviceTaskLists = new HashMap<>(); private final RemoteCallbackList<IRemoteTaskListener> mRemoteTaskListeners = new RemoteCallbackList<>(); /** * Sets the task list of the given association id to the given tasks. Loading @@ -53,9 +46,9 @@ public class RemoteTaskStore implements ConnectedAssociationStore.Observer { * @param tasks The list of tasks currently available on the device on first * connection. */ public void setTasks( int associationId, List<RemoteTaskInfo> tasks) { public void setTasks(int associationId, @NonNull List<RemoteTaskInfo> tasks) { Objects.requireNonNull(tasks); synchronized (mRemoteDeviceTaskLists) { if (!mRemoteDeviceTaskLists.containsKey(associationId)) { Slog.e( Loading @@ -70,7 +63,9 @@ public class RemoteTaskStore implements ConnectedAssociationStore.Observer { } } public void addTask(int associationId, RemoteTaskInfo taskInfo) { public void addTask(int associationId, @NonNull RemoteTaskInfo taskInfo) { Objects.requireNonNull(taskInfo); synchronized (mRemoteDeviceTaskLists) { if (!mRemoteDeviceTaskLists.containsKey(associationId)) { Slog.e( Loading @@ -95,7 +90,9 @@ public class RemoteTaskStore implements ConnectedAssociationStore.Observer { } } public void updateTask(int associationId, RemoteTaskInfo taskInfo) { public void updateTask(int associationId, @NonNull RemoteTaskInfo taskInfo) { Objects.requireNonNull(taskInfo); synchronized (mRemoteDeviceTaskLists) { if (!mRemoteDeviceTaskLists.containsKey(associationId)) { return; Loading @@ -111,6 +108,7 @@ public class RemoteTaskStore implements ConnectedAssociationStore.Observer { * @return A list of the most recent tasks from all devices in the task * store. */ @NonNull public List<RemoteTask> getMostRecentTasks() { synchronized (mRemoteDeviceTaskLists) { List<RemoteTask> mostRecentTasks = new ArrayList<>(); Loading @@ -124,50 +122,53 @@ public class RemoteTaskStore implements ConnectedAssociationStore.Observer { } } public void addListener(IRemoteTaskListener listener) { public void addListener(@NonNull IRemoteTaskListener listener) { Objects.requireNonNull(listener); synchronized (mRemoteTaskListeners) { mRemoteTaskListeners.register(listener); } } public void removeListener(IRemoteTaskListener listener) { public void removeListener(@NonNull IRemoteTaskListener listener) { Objects.requireNonNull(listener); synchronized (mRemoteTaskListeners) { mRemoteTaskListeners.unregister(listener); } } @Override public void onTransportConnected(AssociationInfo associationInfo) { public void addDevice(int id, @NonNull String name) { Objects.requireNonNull(name); synchronized (mRemoteDeviceTaskLists) { if (!mRemoteDeviceTaskLists.containsKey(associationInfo.getId())) { if (!mRemoteDeviceTaskLists.containsKey(id)) { Slog.v( TAG, "Creating new RemoteDeviceTaskList for association: " + associationInfo.getId()); "Creating new RemoteDeviceTaskList for association: " + id); RemoteDeviceTaskList taskList = new RemoteDeviceTaskList( associationInfo.getId(), associationInfo.getDisplayName().toString(), id, name, this::onMostRecentTaskChanged); mRemoteDeviceTaskLists.put(associationInfo.getId(), taskList); mRemoteDeviceTaskLists.put(id, taskList); } else { Slog.v( TAG, "Transport already connected for association: " + associationInfo.getId()); "Transport already connected for association: " + id); } } } @Override public void onTransportDisconnected(int associationId) { public void removeDevice(int id) { synchronized (mRemoteDeviceTaskLists) { Slog.v( TAG, "Deleting RemoteDeviceTaskList for association: " + associationId); "Deleting RemoteDeviceTaskList for association: " + id); mRemoteDeviceTaskLists.remove(associationId); mRemoteDeviceTaskLists.remove(id); notifyListeners(); } } Loading @@ -179,18 +180,14 @@ public class RemoteTaskStore implements ConnectedAssociationStore.Observer { private void notifyListeners() { synchronized (mRemoteTaskListeners) { List<RemoteTask> remoteTasks = getMostRecentTasks(); int i = mRemoteTaskListeners.beginBroadcast(); while (i > 0) { i--; mRemoteTaskListeners.broadcast( (listener) -> { try { mRemoteTaskListeners .getBroadcastItem(i) .onRemoteTasksChanged(remoteTasks); listener.onRemoteTasksChanged(remoteTasks); } catch (RemoteException e) { Slog.e(TAG, "Failed to notify listener: " + e.getMessage()); } } mRemoteTaskListeners.finishBroadcast(); }); } } } No newline at end of file Loading
services/companion/java/com/android/server/companion/datatransfer/continuity/TaskBroadcaster.java +39 −79 Original line number Diff line number Diff line Loading @@ -19,11 +19,9 @@ package com.android.server.companion.datatransfer.continuity; import static com.android.server.companion.datatransfer.contextsync.BitmapUtils.renderDrawableToByteArray; import android.annotation.NonNull; import android.app.ActivityManager; import android.app.ActivityManager.RunningTaskInfo; import android.app.ActivityTaskManager; import android.app.TaskStackListener; import android.companion.AssociationInfo; import android.content.ComponentName; import android.content.Context; import android.content.pm.PackageInfo; Loading @@ -32,7 +30,6 @@ import android.graphics.drawable.Drawable; import android.os.RemoteException; import android.util.Slog; import com.android.server.companion.datatransfer.continuity.connectivity.ConnectedAssociationStore; import com.android.server.companion.datatransfer.continuity.connectivity.TaskContinuityMessenger; import com.android.server.companion.datatransfer.continuity.messages.ContinuityDeviceConnected; import com.android.server.companion.datatransfer.continuity.messages.RemoteTaskAddedMessage; Loading @@ -41,21 +38,16 @@ import com.android.server.companion.datatransfer.continuity.messages.RemoteTaskU import com.android.server.companion.datatransfer.continuity.messages.RemoteTaskInfo; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.Objects; import java.util.stream.Collectors; /** * Responsible for broadcasting recent tasks on the current device to the user's * * other devices via {@link CompanionDeviceManager}. */ class TaskBroadcaster extends TaskStackListener implements ConnectedAssociationStore.Observer { class TaskBroadcaster extends TaskStackListener { private static final String TAG = "TaskBroadcaster"; Loading @@ -64,7 +56,7 @@ class TaskBroadcaster private final TaskContinuityMessenger mTaskContinuityMessenger; private final PackageManager mPackageManager; private boolean mIsBroadcasting = false; private boolean mIsListeningToActivityTaskManager = false; public TaskBroadcaster( @NonNull Context context, Loading @@ -79,56 +71,35 @@ class TaskBroadcaster mTaskContinuityMessenger = taskContinuityMessenger; } void startBroadcasting(){ if (mIsBroadcasting) { Slog.v(TAG, "TaskBroadcaster is already broadcasting"); return; } Slog.v(TAG, "Starting broadcasting"); mTaskContinuityMessenger.getConnectedAssociationStore().addObserver(this); public void onDeviceConnected(int id) { Slog.v(TAG, "Transport connected for association id: " + id); sendDeviceConnectedMessage(id); synchronized (this) { if (!mIsListeningToActivityTaskManager) { mActivityTaskManager.registerTaskStackListener(this); mIsBroadcasting = true; mIsListeningToActivityTaskManager = true; } } void stopBroadcasting(){ if (!mIsBroadcasting) { Slog.v(TAG, "TaskBroadcaster is not broadcasting"); return; } Slog.v(TAG, "Stopping broadcasting"); mIsBroadcasting = false; mTaskContinuityMessenger.getConnectedAssociationStore().removeObserver(this); public void onAllDevicesDisconnected() { synchronized (this) { if (mIsListeningToActivityTaskManager) { mActivityTaskManager.unregisterTaskStackListener(this); mIsListeningToActivityTaskManager = false; } @Override public void onTransportConnected(AssociationInfo associationInfo) { Slog.v( TAG, "Transport connected for association id: " + associationInfo.getId()); sendDeviceConnectedMessage(associationInfo.getId()); } @Override public void onTransportDisconnected(int associationId) { Slog.v( TAG, "Transport disconnected for association id: " + associationId); } @Override public void onTaskCreated( int taskId, ComponentName componentName) throws RemoteException { public void onTaskCreated(int taskId, ComponentName componentName) throws RemoteException { Slog.v(TAG, "onTaskCreated: taskId=" + taskId); RunningTaskInfo taskInfo = getRunningTask(taskId); if (taskInfo == null) { Slog.w(TAG, "Could not find RunningTaskInfo for taskId: " + taskId); return; } ActivityManager.RunningTaskInfo taskInfo = getRunningTask(taskId); if (taskInfo != null) { RemoteTaskInfo remoteTaskInfo = createRemoteTaskInfo(taskInfo); if (remoteTaskInfo == null) { Slog.w(TAG, "Could not create RemoteTaskInfo for task: " + taskInfo.taskId); Loading @@ -137,15 +108,11 @@ class TaskBroadcaster RemoteTaskAddedMessage taskAddedMessage = new RemoteTaskAddedMessage(remoteTaskInfo); mTaskContinuityMessenger.sendMessage(taskAddedMessage); } else { Slog.w(TAG, "Could not find RunningTaskInfo for taskId: " + taskId); } } @Override public void onTaskRemoved(int taskId) throws RemoteException { Slog.v(TAG, "onTaskRemoved: taskId=" + taskId); RemoteTaskRemovedMessage taskRemovedMessage = new RemoteTaskRemovedMessage(taskId); mTaskContinuityMessenger.sendMessage(taskRemovedMessage); } Loading @@ -170,17 +137,10 @@ class TaskBroadcaster "Sending device connected message for association id: " + associationId); List<ActivityManager.RunningTaskInfo> runningTasks = getRunningTasks(); List<RemoteTaskInfo> remoteTasks = new ArrayList<>(); for (ActivityManager.RunningTaskInfo taskInfo : runningTasks) { RemoteTaskInfo remoteTaskInfo = createRemoteTaskInfo(taskInfo); if (remoteTaskInfo != null) { remoteTasks.add(remoteTaskInfo); } else { Slog.w(TAG, "Could not create RemoteTaskInfo for task: " + taskInfo.taskId); } } List<RemoteTaskInfo> remoteTasks = getRunningTasks().stream() .map(this::createRemoteTaskInfo) .filter(Objects::nonNull) .collect(Collectors.toList()); ContinuityDeviceConnected deviceConnectedMessage = new ContinuityDeviceConnected(remoteTasks); Loading @@ -188,10 +148,10 @@ class TaskBroadcaster mTaskContinuityMessenger.sendMessage(associationId, deviceConnectedMessage); } private ActivityManager.RunningTaskInfo getRunningTask(int taskId) { List<ActivityManager.RunningTaskInfo> runningTasks = getRunningTasks(); private RunningTaskInfo getRunningTask(int taskId) { List<RunningTaskInfo> runningTasks = getRunningTasks(); if (runningTasks != null) { for (ActivityManager.RunningTaskInfo info : runningTasks) { for (RunningTaskInfo info : runningTasks) { if (info.taskId == taskId) { return info; } Loading @@ -201,11 +161,11 @@ class TaskBroadcaster return null; } private List<ActivityManager.RunningTaskInfo> getRunningTasks() { private List<RunningTaskInfo> getRunningTasks() { return mActivityTaskManager.getTasks(Integer.MAX_VALUE, true); } private RemoteTaskInfo createRemoteTaskInfo(ActivityManager.RunningTaskInfo taskInfo) { private RemoteTaskInfo createRemoteTaskInfo(RunningTaskInfo taskInfo) { PackageInfo packageInfo; try { packageInfo = mPackageManager.getPackageInfo( Loading
services/companion/java/com/android/server/companion/datatransfer/continuity/TaskContinuityManagerService.java +23 −3 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.server.companion.datatransfer.continuity; import android.annotation.NonNull; import android.companion.AssociationInfo; import android.companion.CompanionDeviceManager; import android.companion.datatransfer.continuity.IHandoffRequestCallback; import android.companion.datatransfer.continuity.ITaskContinuityManager; Loading @@ -42,6 +43,7 @@ import com.android.server.SystemService; import java.util.ArrayList; import java.util.List; import java.util.Collection; /** * Service to handle task continuity features Loading @@ -66,8 +68,7 @@ public final class TaskContinuityManagerService mTaskContinuityMessenger = new TaskContinuityMessenger(context, this); mTaskBroadcaster = new TaskBroadcaster(context, mTaskContinuityMessenger); mRemoteTaskStore = new RemoteTaskStore( mTaskContinuityMessenger.getConnectedAssociationStore()); mRemoteTaskStore = new RemoteTaskStore(); mOutboundHandoffRequestController = new OutboundHandoffRequestController( context, mTaskContinuityMessenger); Loading @@ -79,7 +80,6 @@ public final class TaskContinuityManagerService public void onStart() { mTaskContinuityManagerService = new TaskContinuityManagerServiceImpl(); mTaskContinuityMessenger.enable(); mTaskBroadcaster.startBroadcasting(); publishBinderService(Context.TASK_CONTINUITY_SERVICE, mTaskContinuityManagerService); } Loading Loading @@ -116,6 +116,26 @@ public final class TaskContinuityManagerService } } @Override public void onAssociationConnected(@NonNull AssociationInfo associationInfo) { mRemoteTaskStore.addDevice( associationInfo.getId(), associationInfo.getDisplayName().toString()); mTaskBroadcaster.onDeviceConnected(associationInfo.getId()); } @Override public void onAssociationDisconnected( int associationId, @NonNull Collection<AssociationInfo> connectedAssociations) { mRemoteTaskStore.removeDevice(associationId); if (connectedAssociations.isEmpty()) { mTaskBroadcaster.onAllDevicesDisconnected(); } } @Override public void onMessageReceived( int associationId, Loading
services/companion/java/com/android/server/companion/datatransfer/continuity/connectivity/ConnectedAssociationStore.java +54 −27 Original line number Diff line number Diff line Loading @@ -19,9 +19,10 @@ package com.android.server.companion.datatransfer.continuity.connectivity; import android.annotation.NonNull; import android.companion.AssociationInfo; import android.companion.CompanionDeviceManager; import android.util.Log; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; Loading @@ -29,36 +30,67 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.Executor; import java.util.function.Consumer; import java.util.Objects; import javax.annotation.concurrent.GuardedBy; public class ConnectedAssociationStore { class ConnectedAssociationStore { private static final String TAG = "ConnectedAssociationStore"; private final CompanionDeviceManager mCompanionDeviceManager; private final Listener mListener; private final Executor mExecutor; private final Map<Integer, AssociationInfo> mConnectedAssociations = new HashMap<>(); private final List<Observer> mObservers = new ArrayList<>(); public interface Observer { void onTransportConnected(AssociationInfo associationInfo); void onTransportDisconnected(int associationId); @GuardedBy("this") private Consumer<List<AssociationInfo>> mAssociationInfoConsumer; interface Listener { void onTransportConnected(@NonNull AssociationInfo associationInfo); void onTransportDisconnected( int associationId, @NonNull Collection<AssociationInfo> connectedAssociations); } public ConnectedAssociationStore( ConnectedAssociationStore( @NonNull CompanionDeviceManager companionDeviceManager, @NonNull Executor executor) { @NonNull Executor executor, @NonNull Listener listener) { Objects.requireNonNull(companionDeviceManager); Objects.requireNonNull(executor); Objects.requireNonNull(listener); mCompanionDeviceManager = companionDeviceManager; mCompanionDeviceManager.addOnTransportsChangedListener( executor, this::onTransportsChanged); mListener = listener; mExecutor = executor; } public void addObserver(@NonNull Observer observer) { mObservers.add(observer); public void enable() { synchronized (this) { if (mAssociationInfoConsumer != null) { Slog.i(TAG, "ConnectedAssociationStore is already enabled."); return; } mAssociationInfoConsumer = this::onTransportsChanged; mCompanionDeviceManager.addOnTransportsChangedListener( mExecutor, mAssociationInfoConsumer); Slog.i(TAG, "Enabled ConnectedAssociationStore."); } } public void removeObserver(@NonNull Observer observer) { mObservers.remove(observer); public void disable() { synchronized (this) { if (mAssociationInfoConsumer == null) { Slog.i(TAG, "ConnectedAssociationStore is already disabled."); return; } mCompanionDeviceManager.removeOnTransportsChangedListener(mAssociationInfoConsumer); mAssociationInfoConsumer = null; Slog.i(TAG, "Disabled ConnectedAssociationStore."); } } public Collection<AssociationInfo> getConnectedAssociations() { Loading @@ -69,7 +101,8 @@ public class ConnectedAssociationStore { return mConnectedAssociations.get(associationId); } private void onTransportsChanged(List<AssociationInfo> associationInfos) { @VisibleForTesting void onTransportsChanged(List<AssociationInfo> associationInfos) { Set<Integer> removedAssociations = new HashSet<>(mConnectedAssociations.keySet()); Loading @@ -85,27 +118,21 @@ public class ConnectedAssociationStore { } for (Integer associationId : removedAssociations) { Log.i( Slog.i( TAG, "Transport disconnected for association: " + associationId); mConnectedAssociations.remove(associationId); for (Observer observer : mObservers) { observer.onTransportDisconnected(associationId); } mListener.onTransportDisconnected(associationId, associationInfos); } for (AssociationInfo associationInfo : addedAssociations) { Log.i( Slog.i( TAG, "Transport connected for association: " + associationInfo.getId()); mConnectedAssociations.put(associationInfo.getId(), associationInfo); for (Observer observer : mObservers) { observer.onTransportConnected(associationInfo); } mListener.onTransportConnected(associationInfo); } } } No newline at end of file
services/companion/java/com/android/server/companion/datatransfer/continuity/connectivity/TaskContinuityMessenger.java +37 −4 Original line number Diff line number Diff line Loading @@ -38,7 +38,7 @@ import java.util.Objects; * between devices. Internally, it uses the {@link CompanionDeviceManager} to send and receive * messages. */ public class TaskContinuityMessenger { public class TaskContinuityMessenger implements ConnectedAssociationStore.Listener { private static final String TAG = "TaskContinuityMessenger"; Loading @@ -51,6 +51,10 @@ public class TaskContinuityMessenger { private BiConsumer<Integer, byte[]> mIncomingMessageConsumer; public interface Listener { void onAssociationConnected(@NonNull AssociationInfo associationInfo); void onAssociationDisconnected( int associationId, @NonNull Collection<AssociationInfo> connectedAssociations); void onMessageReceived(int associationId, @NonNull TaskContinuityMessage message); } Loading @@ -65,7 +69,8 @@ public class TaskContinuityMessenger { mCompanionDeviceManager = context.getSystemService(CompanionDeviceManager.class); mConnectedAssociationStore = new ConnectedAssociationStore( mCompanionDeviceManager, mExecutor); mExecutor, this); } public void enable() { Loading @@ -80,6 +85,8 @@ public class TaskContinuityMessenger { MESSAGE_ONEWAY_TASK_CONTINUITY, mIncomingMessageConsumer); } mConnectedAssociationStore.enable(); } public void disable() { Loading @@ -93,6 +100,8 @@ public class TaskContinuityMessenger { mIncomingMessageConsumer); mIncomingMessageConsumer = null; } mConnectedAssociationStore.disable(); } @NonNull Loading @@ -111,13 +120,18 @@ public class TaskContinuityMessenger { int associationId, @NonNull TaskContinuityMessage message) { Objects.requireNonNull(message); return sendMessage(new int[] {associationId}, message); } public SendMessageResult sendMessage( int[] associationIds, @NonNull int[] associationIds, @NonNull TaskContinuityMessage message) { Objects.requireNonNull(associationIds); Objects.requireNonNull(message); Slog.i(TAG, "Sending message to " + associationIds.length + " associations."); byte[] serializedMessage; try { Loading Loading @@ -148,6 +162,8 @@ public class TaskContinuityMessenger { } public SendMessageResult sendMessage(@NonNull TaskContinuityMessage message) { Objects.requireNonNull(message); int[] connectedAssociations = mConnectedAssociationStore .getConnectedAssociations() .stream() Loading @@ -157,6 +173,23 @@ public class TaskContinuityMessenger { return sendMessage(connectedAssociations, message); } @Override public void onTransportConnected(@NonNull AssociationInfo associationInfo) { Objects.requireNonNull(associationInfo); mListener.onAssociationConnected(associationInfo); } @Override public void onTransportDisconnected( int associationId, @NonNull Collection<AssociationInfo> connectedAssociations) { Objects.requireNonNull(connectedAssociations); mListener.onAssociationDisconnected(associationId, connectedAssociations); } private void onMessageReceived(int associationId, byte[] data) { Slog.v(TAG, "Received message from association id: " + associationId); try { Loading
services/companion/java/com/android/server/companion/datatransfer/continuity/tasks/RemoteTaskStore.java +42 −45 Original line number Diff line number Diff line Loading @@ -15,13 +15,12 @@ */ package com.android.server.companion.datatransfer.continuity.tasks; import android.companion.AssociationInfo; import android.annotation.NonNull; 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; import com.android.server.companion.datatransfer.continuity.messages.RemoteTaskInfo; import android.companion.datatransfer.continuity.RemoteTask; Loading @@ -30,21 +29,15 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; public class RemoteTaskStore implements ConnectedAssociationStore.Observer { public class RemoteTaskStore { private static final String TAG = "RemoteTaskStore"; private final ConnectedAssociationStore mConnectedAssociationStore; private final Map<Integer, RemoteDeviceTaskList> mRemoteDeviceTaskLists = new HashMap<>(); private final RemoteCallbackList<IRemoteTaskListener> mRemoteTaskListeners = new RemoteCallbackList<>(); public RemoteTaskStore(ConnectedAssociationStore connectedAssociationStore) { mConnectedAssociationStore = connectedAssociationStore; mConnectedAssociationStore.addObserver(this); } private final Map<Integer, RemoteDeviceTaskList> mRemoteDeviceTaskLists = new HashMap<>(); private final RemoteCallbackList<IRemoteTaskListener> mRemoteTaskListeners = new RemoteCallbackList<>(); /** * Sets the task list of the given association id to the given tasks. Loading @@ -53,9 +46,9 @@ public class RemoteTaskStore implements ConnectedAssociationStore.Observer { * @param tasks The list of tasks currently available on the device on first * connection. */ public void setTasks( int associationId, List<RemoteTaskInfo> tasks) { public void setTasks(int associationId, @NonNull List<RemoteTaskInfo> tasks) { Objects.requireNonNull(tasks); synchronized (mRemoteDeviceTaskLists) { if (!mRemoteDeviceTaskLists.containsKey(associationId)) { Slog.e( Loading @@ -70,7 +63,9 @@ public class RemoteTaskStore implements ConnectedAssociationStore.Observer { } } public void addTask(int associationId, RemoteTaskInfo taskInfo) { public void addTask(int associationId, @NonNull RemoteTaskInfo taskInfo) { Objects.requireNonNull(taskInfo); synchronized (mRemoteDeviceTaskLists) { if (!mRemoteDeviceTaskLists.containsKey(associationId)) { Slog.e( Loading @@ -95,7 +90,9 @@ public class RemoteTaskStore implements ConnectedAssociationStore.Observer { } } public void updateTask(int associationId, RemoteTaskInfo taskInfo) { public void updateTask(int associationId, @NonNull RemoteTaskInfo taskInfo) { Objects.requireNonNull(taskInfo); synchronized (mRemoteDeviceTaskLists) { if (!mRemoteDeviceTaskLists.containsKey(associationId)) { return; Loading @@ -111,6 +108,7 @@ public class RemoteTaskStore implements ConnectedAssociationStore.Observer { * @return A list of the most recent tasks from all devices in the task * store. */ @NonNull public List<RemoteTask> getMostRecentTasks() { synchronized (mRemoteDeviceTaskLists) { List<RemoteTask> mostRecentTasks = new ArrayList<>(); Loading @@ -124,50 +122,53 @@ public class RemoteTaskStore implements ConnectedAssociationStore.Observer { } } public void addListener(IRemoteTaskListener listener) { public void addListener(@NonNull IRemoteTaskListener listener) { Objects.requireNonNull(listener); synchronized (mRemoteTaskListeners) { mRemoteTaskListeners.register(listener); } } public void removeListener(IRemoteTaskListener listener) { public void removeListener(@NonNull IRemoteTaskListener listener) { Objects.requireNonNull(listener); synchronized (mRemoteTaskListeners) { mRemoteTaskListeners.unregister(listener); } } @Override public void onTransportConnected(AssociationInfo associationInfo) { public void addDevice(int id, @NonNull String name) { Objects.requireNonNull(name); synchronized (mRemoteDeviceTaskLists) { if (!mRemoteDeviceTaskLists.containsKey(associationInfo.getId())) { if (!mRemoteDeviceTaskLists.containsKey(id)) { Slog.v( TAG, "Creating new RemoteDeviceTaskList for association: " + associationInfo.getId()); "Creating new RemoteDeviceTaskList for association: " + id); RemoteDeviceTaskList taskList = new RemoteDeviceTaskList( associationInfo.getId(), associationInfo.getDisplayName().toString(), id, name, this::onMostRecentTaskChanged); mRemoteDeviceTaskLists.put(associationInfo.getId(), taskList); mRemoteDeviceTaskLists.put(id, taskList); } else { Slog.v( TAG, "Transport already connected for association: " + associationInfo.getId()); "Transport already connected for association: " + id); } } } @Override public void onTransportDisconnected(int associationId) { public void removeDevice(int id) { synchronized (mRemoteDeviceTaskLists) { Slog.v( TAG, "Deleting RemoteDeviceTaskList for association: " + associationId); "Deleting RemoteDeviceTaskList for association: " + id); mRemoteDeviceTaskLists.remove(associationId); mRemoteDeviceTaskLists.remove(id); notifyListeners(); } } Loading @@ -179,18 +180,14 @@ public class RemoteTaskStore implements ConnectedAssociationStore.Observer { private void notifyListeners() { synchronized (mRemoteTaskListeners) { List<RemoteTask> remoteTasks = getMostRecentTasks(); int i = mRemoteTaskListeners.beginBroadcast(); while (i > 0) { i--; mRemoteTaskListeners.broadcast( (listener) -> { try { mRemoteTaskListeners .getBroadcastItem(i) .onRemoteTasksChanged(remoteTasks); listener.onRemoteTasksChanged(remoteTasks); } catch (RemoteException e) { Slog.e(TAG, "Failed to notify listener: " + e.getMessage()); } } mRemoteTaskListeners.finishBroadcast(); }); } } } No newline at end of file