Loading core/proto/android/companion/task_continuity_message.proto +8 −0 Original line number Diff line number Diff line Loading @@ -29,4 +29,12 @@ message TaskContinuityMessage { message ContinuityDeviceConnected { int32 currentForegroundTaskId = 1; repeated RemoteTaskInfo remoteTasks = 2; } message RemoteTaskInfo { int32 id = 1; string label = 2; int64 lastUsedTimeMillis = 3; bytes taskIcon = 4; } services/companion/java/com/android/server/companion/datatransfer/continuity/TaskBroadcaster.java +9 −1 Original line number Diff line number Diff line Loading @@ -26,9 +26,11 @@ 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.RemoteTaskInfo; import com.android.server.companion.datatransfer.continuity.messages.TaskContinuityMessage; import com.android.server.companion.datatransfer.continuity.messages.TaskContinuityMessageData; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; Loading Loading @@ -122,13 +124,19 @@ class TaskBroadcaster { currentForegroundTaskId = runningTasks.get(0).taskId; } List<RemoteTaskInfo> remoteTasks = new ArrayList<>(); for (ActivityManager.RunningTaskInfo taskInfo : runningTasks) { remoteTasks.add(new RemoteTaskInfo(taskInfo)); } ContinuityDeviceConnected deviceConnectedMessage = new ContinuityDeviceConnected(currentForegroundTaskId); new ContinuityDeviceConnected(currentForegroundTaskId, remoteTasks); sendMessage(associationId, deviceConnectedMessage); } private void sendMessage(int associationId, TaskContinuityMessageData data) { Slog.v( TAG, "Sending message to association id: " Loading services/companion/java/com/android/server/companion/datatransfer/continuity/messages/ContinuityDeviceConnected.java +32 −1 Original line number Diff line number Diff line Loading @@ -21,6 +21,8 @@ import android.util.proto.ProtoOutputStream; import android.util.proto.ProtoParseException; import java.io.IOException; import java.util.ArrayList; import java.util.List; /** * Deserialized version of the {@link ContinuityDeviceConnected} proto. Loading @@ -28,15 +30,21 @@ import java.io.IOException; public class ContinuityDeviceConnected implements TaskContinuityMessageData { private int mCurrentForegroundTaskId = 0; private List<RemoteTaskInfo> mRemoteTasks; public ContinuityDeviceConnected( int currentForegroundTaskId, List<RemoteTaskInfo> remoteTasks) { public ContinuityDeviceConnected(int currentForegroundTaskId) { mCurrentForegroundTaskId = currentForegroundTaskId; mRemoteTasks = remoteTasks; } ContinuityDeviceConnected(ProtoInputStream pis) throws IOException, ProtoParseException { boolean hasReadForegroundTaskId = false; List<RemoteTaskInfo> remoteTasks = new ArrayList<>(); while (pis.nextField() != ProtoInputStream.NO_MORE_FIELDS) { switch (pis.getFieldNumber()) { case (int) android.companion.ContinuityDeviceConnected.CURRENT_FOREGROUND_TASK_ID: Loading @@ -46,6 +54,13 @@ public class ContinuityDeviceConnected implements TaskContinuityMessageData { hasReadForegroundTaskId = true; break; case (int) android.companion.ContinuityDeviceConnected.REMOTE_TASKS: final long remoteTasksToken = pis.start( android.companion.ContinuityDeviceConnected.REMOTE_TASKS); remoteTasks.add(new RemoteTaskInfo(pis)); pis.end(remoteTasksToken); break; } } Loading @@ -53,6 +68,8 @@ public class ContinuityDeviceConnected implements TaskContinuityMessageData { throw new ProtoParseException( "Missing required field: current_foreground_task_id"); } mRemoteTasks = remoteTasks; } /** Loading @@ -62,6 +79,13 @@ public class ContinuityDeviceConnected implements TaskContinuityMessageData { return mCurrentForegroundTaskId; } /** * Gets which remote tasks are running on the device. */ public List<RemoteTaskInfo> getRemoteTasks() { return mRemoteTasks; } /** * Writes this object to a proto output stream. */ Loading @@ -70,5 +94,12 @@ public class ContinuityDeviceConnected implements TaskContinuityMessageData { pos.writeInt32( android.companion.ContinuityDeviceConnected.CURRENT_FOREGROUND_TASK_ID, mCurrentForegroundTaskId); for (RemoteTaskInfo remoteTaskInfo : mRemoteTasks) { long remoteTasksToken = pos.start( android.companion.ContinuityDeviceConnected.REMOTE_TASKS); remoteTaskInfo.writeToProto(pos); pos.end(remoteTasksToken); } } } No newline at end of file services/companion/java/com/android/server/companion/datatransfer/continuity/messages/RemoteTaskInfo.java 0 → 100644 +94 −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.messages; import android.app.TaskInfo; import android.util.proto.ProtoInputStream; import android.util.proto.ProtoOutputStream; import android.util.proto.ProtoParseException; import java.io.IOException; public class RemoteTaskInfo { private int mId = 0; private String mLabel = ""; private long mLastUsedTimeMillis = 0; private byte[] mTaskIcon = new byte[0]; public RemoteTaskInfo(TaskInfo taskInfo) { mId = taskInfo.taskId; mLabel = taskInfo.taskDescription.getLabel().toString(); mLastUsedTimeMillis = taskInfo.lastActiveTime; } public RemoteTaskInfo(ProtoInputStream protoInputStream) throws IOException, ProtoParseException { while (protoInputStream.nextField() != ProtoInputStream.NO_MORE_FIELDS) { switch (protoInputStream.getFieldNumber()) { case (int) android.companion.RemoteTaskInfo.ID: mId = protoInputStream.readInt( android.companion.RemoteTaskInfo.ID); break; case (int) android.companion.RemoteTaskInfo.LABEL: mLabel = protoInputStream.readString( android.companion.RemoteTaskInfo.LABEL); break; case (int) android.companion.RemoteTaskInfo.LAST_USED_TIME_MILLIS: mLastUsedTimeMillis = protoInputStream.readLong( android.companion.RemoteTaskInfo.LAST_USED_TIME_MILLIS); break; case (int) android.companion.RemoteTaskInfo.TASK_ICON: mTaskIcon = protoInputStream .readBytes(android.companion.RemoteTaskInfo.TASK_ICON); break; } } } public int getId() { return mId; } public String getLabel() { return mLabel; } public long getLastUsedTimeMillis() { return mLastUsedTimeMillis; } public byte[] getTaskIcon() { return mTaskIcon; } public void writeToProto(ProtoOutputStream protoOutputStream) { protoOutputStream .writeInt32(android.companion.RemoteTaskInfo.ID, mId); protoOutputStream .writeString(android.companion.RemoteTaskInfo.LABEL, mLabel); protoOutputStream .writeInt64( android.companion.RemoteTaskInfo.LAST_USED_TIME_MILLIS, mLastUsedTimeMillis); protoOutputStream .writeBytes(android.companion.RemoteTaskInfo.TASK_ICON, mTaskIcon); } } No newline at end of file services/tests/servicestests/src/com/android/server/companion/datatransfer/continuity/TaskBroadcasterTest.java +9 −0 Original line number Diff line number Diff line Loading @@ -132,9 +132,13 @@ public class TaskBroadcasterTest { IOnTransportsChangedListener listener = listenerCaptor.getValue(); // Setup a fake foreground task. String expectedLabel = "test"; ActivityManager.RunningTaskInfo taskInfo = new ActivityManager.RunningTaskInfo(); taskInfo.taskId = 1; taskInfo.taskDescription = new ActivityManager.TaskDescription(expectedLabel); when(mMockActivityTaskManager.getTasks(Integer.MAX_VALUE, true)) .thenReturn(Arrays.asList(taskInfo)); Loading @@ -161,5 +165,10 @@ public class TaskBroadcasterTest { = (ContinuityDeviceConnected) taskContinuityMessage.getData(); assertThat(continuityDeviceConnected.getCurrentForegroundTaskId()) .isEqualTo(taskInfo.taskId); assertThat(continuityDeviceConnected.getRemoteTasks()).hasSize(1); assertThat(continuityDeviceConnected.getRemoteTasks().get(0).getId()) .isEqualTo(taskInfo.taskId); assertThat(continuityDeviceConnected.getRemoteTasks().get(0).getLabel()) .isEqualTo(expectedLabel); } } No newline at end of file Loading
core/proto/android/companion/task_continuity_message.proto +8 −0 Original line number Diff line number Diff line Loading @@ -29,4 +29,12 @@ message TaskContinuityMessage { message ContinuityDeviceConnected { int32 currentForegroundTaskId = 1; repeated RemoteTaskInfo remoteTasks = 2; } message RemoteTaskInfo { int32 id = 1; string label = 2; int64 lastUsedTimeMillis = 3; bytes taskIcon = 4; }
services/companion/java/com/android/server/companion/datatransfer/continuity/TaskBroadcaster.java +9 −1 Original line number Diff line number Diff line Loading @@ -26,9 +26,11 @@ 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.RemoteTaskInfo; import com.android.server.companion.datatransfer.continuity.messages.TaskContinuityMessage; import com.android.server.companion.datatransfer.continuity.messages.TaskContinuityMessageData; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; Loading Loading @@ -122,13 +124,19 @@ class TaskBroadcaster { currentForegroundTaskId = runningTasks.get(0).taskId; } List<RemoteTaskInfo> remoteTasks = new ArrayList<>(); for (ActivityManager.RunningTaskInfo taskInfo : runningTasks) { remoteTasks.add(new RemoteTaskInfo(taskInfo)); } ContinuityDeviceConnected deviceConnectedMessage = new ContinuityDeviceConnected(currentForegroundTaskId); new ContinuityDeviceConnected(currentForegroundTaskId, remoteTasks); sendMessage(associationId, deviceConnectedMessage); } private void sendMessage(int associationId, TaskContinuityMessageData data) { Slog.v( TAG, "Sending message to association id: " Loading
services/companion/java/com/android/server/companion/datatransfer/continuity/messages/ContinuityDeviceConnected.java +32 −1 Original line number Diff line number Diff line Loading @@ -21,6 +21,8 @@ import android.util.proto.ProtoOutputStream; import android.util.proto.ProtoParseException; import java.io.IOException; import java.util.ArrayList; import java.util.List; /** * Deserialized version of the {@link ContinuityDeviceConnected} proto. Loading @@ -28,15 +30,21 @@ import java.io.IOException; public class ContinuityDeviceConnected implements TaskContinuityMessageData { private int mCurrentForegroundTaskId = 0; private List<RemoteTaskInfo> mRemoteTasks; public ContinuityDeviceConnected( int currentForegroundTaskId, List<RemoteTaskInfo> remoteTasks) { public ContinuityDeviceConnected(int currentForegroundTaskId) { mCurrentForegroundTaskId = currentForegroundTaskId; mRemoteTasks = remoteTasks; } ContinuityDeviceConnected(ProtoInputStream pis) throws IOException, ProtoParseException { boolean hasReadForegroundTaskId = false; List<RemoteTaskInfo> remoteTasks = new ArrayList<>(); while (pis.nextField() != ProtoInputStream.NO_MORE_FIELDS) { switch (pis.getFieldNumber()) { case (int) android.companion.ContinuityDeviceConnected.CURRENT_FOREGROUND_TASK_ID: Loading @@ -46,6 +54,13 @@ public class ContinuityDeviceConnected implements TaskContinuityMessageData { hasReadForegroundTaskId = true; break; case (int) android.companion.ContinuityDeviceConnected.REMOTE_TASKS: final long remoteTasksToken = pis.start( android.companion.ContinuityDeviceConnected.REMOTE_TASKS); remoteTasks.add(new RemoteTaskInfo(pis)); pis.end(remoteTasksToken); break; } } Loading @@ -53,6 +68,8 @@ public class ContinuityDeviceConnected implements TaskContinuityMessageData { throw new ProtoParseException( "Missing required field: current_foreground_task_id"); } mRemoteTasks = remoteTasks; } /** Loading @@ -62,6 +79,13 @@ public class ContinuityDeviceConnected implements TaskContinuityMessageData { return mCurrentForegroundTaskId; } /** * Gets which remote tasks are running on the device. */ public List<RemoteTaskInfo> getRemoteTasks() { return mRemoteTasks; } /** * Writes this object to a proto output stream. */ Loading @@ -70,5 +94,12 @@ public class ContinuityDeviceConnected implements TaskContinuityMessageData { pos.writeInt32( android.companion.ContinuityDeviceConnected.CURRENT_FOREGROUND_TASK_ID, mCurrentForegroundTaskId); for (RemoteTaskInfo remoteTaskInfo : mRemoteTasks) { long remoteTasksToken = pos.start( android.companion.ContinuityDeviceConnected.REMOTE_TASKS); remoteTaskInfo.writeToProto(pos); pos.end(remoteTasksToken); } } } No newline at end of file
services/companion/java/com/android/server/companion/datatransfer/continuity/messages/RemoteTaskInfo.java 0 → 100644 +94 −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.messages; import android.app.TaskInfo; import android.util.proto.ProtoInputStream; import android.util.proto.ProtoOutputStream; import android.util.proto.ProtoParseException; import java.io.IOException; public class RemoteTaskInfo { private int mId = 0; private String mLabel = ""; private long mLastUsedTimeMillis = 0; private byte[] mTaskIcon = new byte[0]; public RemoteTaskInfo(TaskInfo taskInfo) { mId = taskInfo.taskId; mLabel = taskInfo.taskDescription.getLabel().toString(); mLastUsedTimeMillis = taskInfo.lastActiveTime; } public RemoteTaskInfo(ProtoInputStream protoInputStream) throws IOException, ProtoParseException { while (protoInputStream.nextField() != ProtoInputStream.NO_MORE_FIELDS) { switch (protoInputStream.getFieldNumber()) { case (int) android.companion.RemoteTaskInfo.ID: mId = protoInputStream.readInt( android.companion.RemoteTaskInfo.ID); break; case (int) android.companion.RemoteTaskInfo.LABEL: mLabel = protoInputStream.readString( android.companion.RemoteTaskInfo.LABEL); break; case (int) android.companion.RemoteTaskInfo.LAST_USED_TIME_MILLIS: mLastUsedTimeMillis = protoInputStream.readLong( android.companion.RemoteTaskInfo.LAST_USED_TIME_MILLIS); break; case (int) android.companion.RemoteTaskInfo.TASK_ICON: mTaskIcon = protoInputStream .readBytes(android.companion.RemoteTaskInfo.TASK_ICON); break; } } } public int getId() { return mId; } public String getLabel() { return mLabel; } public long getLastUsedTimeMillis() { return mLastUsedTimeMillis; } public byte[] getTaskIcon() { return mTaskIcon; } public void writeToProto(ProtoOutputStream protoOutputStream) { protoOutputStream .writeInt32(android.companion.RemoteTaskInfo.ID, mId); protoOutputStream .writeString(android.companion.RemoteTaskInfo.LABEL, mLabel); protoOutputStream .writeInt64( android.companion.RemoteTaskInfo.LAST_USED_TIME_MILLIS, mLastUsedTimeMillis); protoOutputStream .writeBytes(android.companion.RemoteTaskInfo.TASK_ICON, mTaskIcon); } } No newline at end of file
services/tests/servicestests/src/com/android/server/companion/datatransfer/continuity/TaskBroadcasterTest.java +9 −0 Original line number Diff line number Diff line Loading @@ -132,9 +132,13 @@ public class TaskBroadcasterTest { IOnTransportsChangedListener listener = listenerCaptor.getValue(); // Setup a fake foreground task. String expectedLabel = "test"; ActivityManager.RunningTaskInfo taskInfo = new ActivityManager.RunningTaskInfo(); taskInfo.taskId = 1; taskInfo.taskDescription = new ActivityManager.TaskDescription(expectedLabel); when(mMockActivityTaskManager.getTasks(Integer.MAX_VALUE, true)) .thenReturn(Arrays.asList(taskInfo)); Loading @@ -161,5 +165,10 @@ public class TaskBroadcasterTest { = (ContinuityDeviceConnected) taskContinuityMessage.getData(); assertThat(continuityDeviceConnected.getCurrentForegroundTaskId()) .isEqualTo(taskInfo.taskId); assertThat(continuityDeviceConnected.getRemoteTasks()).hasSize(1); assertThat(continuityDeviceConnected.getRemoteTasks().get(0).getId()) .isEqualTo(taskInfo.taskId); assertThat(continuityDeviceConnected.getRemoteTasks().get(0).getLabel()) .isEqualTo(expectedLabel); } } No newline at end of file