Loading core/api/system-current.txt +11 −0 Original line number Diff line number Diff line Loading @@ -3478,7 +3478,18 @@ package android.companion.datatransfer.continuity { @FlaggedApi("android.companion.enable_task_continuity") public class TaskContinuityManager { method @NonNull public java.util.List<android.companion.datatransfer.continuity.RemoteTask> getRemoteTasks(); method public void registerRemoteTaskListener(@NonNull java.util.concurrent.Executor, @NonNull android.companion.datatransfer.continuity.TaskContinuityManager.RemoteTaskListener); method public void requestHandoff(int, int, @NonNull java.util.concurrent.Executor, @NonNull android.companion.datatransfer.continuity.TaskContinuityManager.HandoffRequestCallback); method public void unregisterRemoteTaskListener(@NonNull android.companion.datatransfer.continuity.TaskContinuityManager.RemoteTaskListener); field public static final int HANDOFF_REQUEST_RESULT_FAILURE_DEVICE_NOT_FOUND = 5; // 0x5 field public static final int HANDOFF_REQUEST_RESULT_FAILURE_NO_DATA_PROVIDED_BY_TASK = 2; // 0x2 field public static final int HANDOFF_REQUEST_RESULT_FAILURE_SENDER_LOST_CONNECTION = 3; // 0x3 field public static final int HANDOFF_REQUEST_RESULT_FAILURE_TASK_NOT_FOUND = 1; // 0x1 field public static final int HANDOFF_REQUEST_RESULT_FAILURE_TIMEOUT = 4; // 0x4 field public static final int HANDOFF_REQUEST_RESULT_SUCCESS = 0; // 0x0 } public static interface TaskContinuityManager.HandoffRequestCallback { method public void onHandoffRequestFinished(int, int, int); } public static interface TaskContinuityManager.RemoteTaskListener { core/java/android/companion/datatransfer/continuity/IHandoffRequestCallback.aidl 0 → 100644 +26 −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 android.companion.datatransfer.continuity; import android.companion.datatransfer.continuity.RemoteTask; /** * {@hide} */ oneway interface IHandoffRequestCallback { void onHandoffRequestFinished(in int associationId, in int remoteTaskId, in int resultCode); } No newline at end of file core/java/android/companion/datatransfer/continuity/ITaskContinuityManager.aidl +5 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package android.companion.datatransfer.continuity; import android.companion.datatransfer.continuity.IHandoffRequestCallback; import android.companion.datatransfer.continuity.IRemoteTaskListener; import android.companion.datatransfer.continuity.RemoteTask; Loading @@ -28,5 +29,9 @@ interface ITaskContinuityManager { List<RemoteTask> getRemoteTasks(); void registerRemoteTaskListener(IRemoteTaskListener listener); void unregisterRemoteTaskListener(IRemoteTaskListener listener); void requestHandoff( in int associationId, in int remoteTaskId, in IHandoffRequestCallback callback); } core/java/android/companion/datatransfer/continuity/TaskContinuityManager.java +130 −0 Original line number Diff line number Diff line Loading @@ -16,10 +16,12 @@ package android.companion.datatransfer.continuity; import android.companion.datatransfer.continuity.IHandoffRequestCallback; import android.companion.datatransfer.continuity.IRemoteTaskListener; import android.companion.datatransfer.continuity.RemoteTask; import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.NonNull; Loading @@ -29,10 +31,13 @@ import android.util.ArrayMap; import com.android.internal.annotations.GuardedBy; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.concurrent.Executor; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Objects; /** * This class facilitates task continuity between devices owned by the same user. Loading @@ -51,6 +56,53 @@ public class TaskContinuityManager { private final RemoteTaskListenerHolder mListenerHolder; /** @hide */ @IntDef(prefix = {"HANDOFF_REQUEST_RESULT"}, value = { HANDOFF_REQUEST_RESULT_SUCCESS, HANDOFF_REQUEST_RESULT_FAILURE_TASK_NOT_FOUND, HANDOFF_REQUEST_RESULT_FAILURE_NO_DATA_PROVIDED_BY_TASK, HANDOFF_REQUEST_RESULT_FAILURE_SENDER_LOST_CONNECTION, HANDOFF_REQUEST_RESULT_FAILURE_TIMEOUT, HANDOFF_REQUEST_RESULT_FAILURE_DEVICE_NOT_FOUND, }) @Retention(RetentionPolicy.SOURCE) public @interface HandoffRequestResultCode {} /** * Indicate a request for handoff completed successfully. */ public static final int HANDOFF_REQUEST_RESULT_SUCCESS = 0; /** * Indicates a request for handoff failed because a remote task with the specified ID was not * found on the remote device. */ public static final int HANDOFF_REQUEST_RESULT_FAILURE_TASK_NOT_FOUND = 1; /** * Indicates a request for handoff failed because the remote task did not provide any data to * hand itself off to the current device. */ public static final int HANDOFF_REQUEST_RESULT_FAILURE_NO_DATA_PROVIDED_BY_TASK = 2; /** * Indicates a request for handoff failed because the connection to the remote device was lost * before the request could be completed. */ public static final int HANDOFF_REQUEST_RESULT_FAILURE_SENDER_LOST_CONNECTION = 3; /** * Indicates a request for handoff failed because the request timed out before it could be * completed. */ public static final int HANDOFF_REQUEST_RESULT_FAILURE_TIMEOUT = 4; /** * Indicates a request for handoff failed because the remote device was not found. */ public static final int HANDOFF_REQUEST_RESULT_FAILURE_DEVICE_NOT_FOUND = 5; /** @hide */ public TaskContinuityManager( @NonNull Context context, Loading @@ -73,6 +125,24 @@ public class TaskContinuityManager { void onRemoteTasksChanged(@NonNull List<RemoteTask> remoteTasks); } /** * Callback to be invoked when a handoff request is completed. */ public interface HandoffRequestCallback { /** * Invoked when a request to hand off a remote task has finished. * * @param associationId The ID of the association to which the remote device is connected. * @param remoteTaskId The ID of the task that was requested to be handed off. * @param resultCode The result code of the handoff request. */ void onHandoffRequestFinished( int associationId, int remoteTaskId, @HandoffRequestResultCode int resultCode); } /** * Returns a list of tasks currently running on the remote devices owned by the user. */ Loading @@ -97,6 +167,9 @@ public class TaskContinuityManager { @NonNull Executor executor, @NonNull RemoteTaskListener listener) { Objects.requireNonNull(executor); Objects.requireNonNull(listener); try { mListenerHolder.registerListener(executor, listener); // TODO: joeantonetti - Send an initial notification to the listener after it's Loading @@ -113,6 +186,8 @@ public class TaskContinuityManager { * @param listener The listener to be unregistered. */ public void unregisterRemoteTaskListener(@NonNull RemoteTaskListener listener) { Objects.requireNonNull(listener); try { mListenerHolder.unregisterListener(listener); } catch (RemoteException e) { Loading @@ -120,6 +195,56 @@ public class TaskContinuityManager { } } /** * Requests a handoff of the specified remote task to the current device. * * @param associationId The ID of the association to which the remote device is connected. This * is the same ID returned by {@link RemoteTask#getDeviceId()}. * @param remoteTaskId The remote task to hand off. * @param executor The executor to be used to invoke the callback. * @param callback The callback to be invoked when the handoff request is finished. */ public void requestHandoff( int associationId, int remoteTaskId, @NonNull Executor executor, @NonNull HandoffRequestCallback callback) { Objects.requireNonNull(executor); Objects.requireNonNull(callback); try { HandoffRequestCallbackHolder callbackHolder = new HandoffRequestCallbackHolder(executor, callback); mService.requestHandoff(associationId, remoteTaskId, callbackHolder); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } private final class HandoffRequestCallbackHolder extends IHandoffRequestCallback.Stub { private final Executor mExecutor; private final HandoffRequestCallback mCallback; HandoffRequestCallbackHolder( @NonNull Executor executor, @NonNull HandoffRequestCallback callback) { mExecutor = executor; mCallback = callback; } @Override public void onHandoffRequestFinished( int associationId, int remoteTaskId, @HandoffRequestResultCode int resultCode) throws RemoteException { mExecutor.execute( () -> mCallback.onHandoffRequestFinished(associationId, remoteTaskId, resultCode)); } } /** * Helper class which manages registered listeners and proxies them behind a single * IRemoteTaskListener, which is lazily registered with ITaskContinuityManager if there is Loading @@ -145,6 +270,9 @@ public class TaskContinuityManager { @NonNull Executor executor, @NonNull RemoteTaskListener listener) throws RemoteException { Objects.requireNonNull(executor); Objects.requireNonNull(listener); synchronized(mListeners) { if (!mRegistered) { mService.registerRemoteTaskListener(this); Loading @@ -163,6 +291,8 @@ public class TaskContinuityManager { public void unregisterListener( @NonNull RemoteTaskListener listener) throws RemoteException { Objects.requireNonNull(listener); synchronized(mListeners) { mListeners.remove(listener); if (mListeners.isEmpty() && mRegistered) { Loading services/companion/java/com/android/server/companion/datatransfer/continuity/TaskContinuityManagerService.java +10 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.server.companion.datatransfer.continuity; import android.annotation.NonNull; import android.companion.CompanionDeviceManager; import android.companion.datatransfer.continuity.IHandoffRequestCallback; import android.companion.datatransfer.continuity.ITaskContinuityManager; import android.companion.datatransfer.continuity.IRemoteTaskListener; import android.companion.datatransfer.continuity.RemoteTask; Loading Loading @@ -83,6 +84,15 @@ public final class TaskContinuityManagerService extends SystemService { @Override public void unregisterRemoteTaskListener(@NonNull IRemoteTaskListener listener) { } @Override public void requestHandoff( int associationId, int remoteTaskId, @NonNull IHandoffRequestCallback callback) { // TODO: joeantonetti - Implement this method. } } private void onTaskContinuityMessageReceived( Loading Loading
core/api/system-current.txt +11 −0 Original line number Diff line number Diff line Loading @@ -3478,7 +3478,18 @@ package android.companion.datatransfer.continuity { @FlaggedApi("android.companion.enable_task_continuity") public class TaskContinuityManager { method @NonNull public java.util.List<android.companion.datatransfer.continuity.RemoteTask> getRemoteTasks(); method public void registerRemoteTaskListener(@NonNull java.util.concurrent.Executor, @NonNull android.companion.datatransfer.continuity.TaskContinuityManager.RemoteTaskListener); method public void requestHandoff(int, int, @NonNull java.util.concurrent.Executor, @NonNull android.companion.datatransfer.continuity.TaskContinuityManager.HandoffRequestCallback); method public void unregisterRemoteTaskListener(@NonNull android.companion.datatransfer.continuity.TaskContinuityManager.RemoteTaskListener); field public static final int HANDOFF_REQUEST_RESULT_FAILURE_DEVICE_NOT_FOUND = 5; // 0x5 field public static final int HANDOFF_REQUEST_RESULT_FAILURE_NO_DATA_PROVIDED_BY_TASK = 2; // 0x2 field public static final int HANDOFF_REQUEST_RESULT_FAILURE_SENDER_LOST_CONNECTION = 3; // 0x3 field public static final int HANDOFF_REQUEST_RESULT_FAILURE_TASK_NOT_FOUND = 1; // 0x1 field public static final int HANDOFF_REQUEST_RESULT_FAILURE_TIMEOUT = 4; // 0x4 field public static final int HANDOFF_REQUEST_RESULT_SUCCESS = 0; // 0x0 } public static interface TaskContinuityManager.HandoffRequestCallback { method public void onHandoffRequestFinished(int, int, int); } public static interface TaskContinuityManager.RemoteTaskListener {
core/java/android/companion/datatransfer/continuity/IHandoffRequestCallback.aidl 0 → 100644 +26 −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 android.companion.datatransfer.continuity; import android.companion.datatransfer.continuity.RemoteTask; /** * {@hide} */ oneway interface IHandoffRequestCallback { void onHandoffRequestFinished(in int associationId, in int remoteTaskId, in int resultCode); } No newline at end of file
core/java/android/companion/datatransfer/continuity/ITaskContinuityManager.aidl +5 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package android.companion.datatransfer.continuity; import android.companion.datatransfer.continuity.IHandoffRequestCallback; import android.companion.datatransfer.continuity.IRemoteTaskListener; import android.companion.datatransfer.continuity.RemoteTask; Loading @@ -28,5 +29,9 @@ interface ITaskContinuityManager { List<RemoteTask> getRemoteTasks(); void registerRemoteTaskListener(IRemoteTaskListener listener); void unregisterRemoteTaskListener(IRemoteTaskListener listener); void requestHandoff( in int associationId, in int remoteTaskId, in IHandoffRequestCallback callback); }
core/java/android/companion/datatransfer/continuity/TaskContinuityManager.java +130 −0 Original line number Diff line number Diff line Loading @@ -16,10 +16,12 @@ package android.companion.datatransfer.continuity; import android.companion.datatransfer.continuity.IHandoffRequestCallback; import android.companion.datatransfer.continuity.IRemoteTaskListener; import android.companion.datatransfer.continuity.RemoteTask; import android.annotation.FlaggedApi; import android.annotation.IntDef; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.NonNull; Loading @@ -29,10 +31,13 @@ import android.util.ArrayMap; import com.android.internal.annotations.GuardedBy; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.concurrent.Executor; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Objects; /** * This class facilitates task continuity between devices owned by the same user. Loading @@ -51,6 +56,53 @@ public class TaskContinuityManager { private final RemoteTaskListenerHolder mListenerHolder; /** @hide */ @IntDef(prefix = {"HANDOFF_REQUEST_RESULT"}, value = { HANDOFF_REQUEST_RESULT_SUCCESS, HANDOFF_REQUEST_RESULT_FAILURE_TASK_NOT_FOUND, HANDOFF_REQUEST_RESULT_FAILURE_NO_DATA_PROVIDED_BY_TASK, HANDOFF_REQUEST_RESULT_FAILURE_SENDER_LOST_CONNECTION, HANDOFF_REQUEST_RESULT_FAILURE_TIMEOUT, HANDOFF_REQUEST_RESULT_FAILURE_DEVICE_NOT_FOUND, }) @Retention(RetentionPolicy.SOURCE) public @interface HandoffRequestResultCode {} /** * Indicate a request for handoff completed successfully. */ public static final int HANDOFF_REQUEST_RESULT_SUCCESS = 0; /** * Indicates a request for handoff failed because a remote task with the specified ID was not * found on the remote device. */ public static final int HANDOFF_REQUEST_RESULT_FAILURE_TASK_NOT_FOUND = 1; /** * Indicates a request for handoff failed because the remote task did not provide any data to * hand itself off to the current device. */ public static final int HANDOFF_REQUEST_RESULT_FAILURE_NO_DATA_PROVIDED_BY_TASK = 2; /** * Indicates a request for handoff failed because the connection to the remote device was lost * before the request could be completed. */ public static final int HANDOFF_REQUEST_RESULT_FAILURE_SENDER_LOST_CONNECTION = 3; /** * Indicates a request for handoff failed because the request timed out before it could be * completed. */ public static final int HANDOFF_REQUEST_RESULT_FAILURE_TIMEOUT = 4; /** * Indicates a request for handoff failed because the remote device was not found. */ public static final int HANDOFF_REQUEST_RESULT_FAILURE_DEVICE_NOT_FOUND = 5; /** @hide */ public TaskContinuityManager( @NonNull Context context, Loading @@ -73,6 +125,24 @@ public class TaskContinuityManager { void onRemoteTasksChanged(@NonNull List<RemoteTask> remoteTasks); } /** * Callback to be invoked when a handoff request is completed. */ public interface HandoffRequestCallback { /** * Invoked when a request to hand off a remote task has finished. * * @param associationId The ID of the association to which the remote device is connected. * @param remoteTaskId The ID of the task that was requested to be handed off. * @param resultCode The result code of the handoff request. */ void onHandoffRequestFinished( int associationId, int remoteTaskId, @HandoffRequestResultCode int resultCode); } /** * Returns a list of tasks currently running on the remote devices owned by the user. */ Loading @@ -97,6 +167,9 @@ public class TaskContinuityManager { @NonNull Executor executor, @NonNull RemoteTaskListener listener) { Objects.requireNonNull(executor); Objects.requireNonNull(listener); try { mListenerHolder.registerListener(executor, listener); // TODO: joeantonetti - Send an initial notification to the listener after it's Loading @@ -113,6 +186,8 @@ public class TaskContinuityManager { * @param listener The listener to be unregistered. */ public void unregisterRemoteTaskListener(@NonNull RemoteTaskListener listener) { Objects.requireNonNull(listener); try { mListenerHolder.unregisterListener(listener); } catch (RemoteException e) { Loading @@ -120,6 +195,56 @@ public class TaskContinuityManager { } } /** * Requests a handoff of the specified remote task to the current device. * * @param associationId The ID of the association to which the remote device is connected. This * is the same ID returned by {@link RemoteTask#getDeviceId()}. * @param remoteTaskId The remote task to hand off. * @param executor The executor to be used to invoke the callback. * @param callback The callback to be invoked when the handoff request is finished. */ public void requestHandoff( int associationId, int remoteTaskId, @NonNull Executor executor, @NonNull HandoffRequestCallback callback) { Objects.requireNonNull(executor); Objects.requireNonNull(callback); try { HandoffRequestCallbackHolder callbackHolder = new HandoffRequestCallbackHolder(executor, callback); mService.requestHandoff(associationId, remoteTaskId, callbackHolder); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } private final class HandoffRequestCallbackHolder extends IHandoffRequestCallback.Stub { private final Executor mExecutor; private final HandoffRequestCallback mCallback; HandoffRequestCallbackHolder( @NonNull Executor executor, @NonNull HandoffRequestCallback callback) { mExecutor = executor; mCallback = callback; } @Override public void onHandoffRequestFinished( int associationId, int remoteTaskId, @HandoffRequestResultCode int resultCode) throws RemoteException { mExecutor.execute( () -> mCallback.onHandoffRequestFinished(associationId, remoteTaskId, resultCode)); } } /** * Helper class which manages registered listeners and proxies them behind a single * IRemoteTaskListener, which is lazily registered with ITaskContinuityManager if there is Loading @@ -145,6 +270,9 @@ public class TaskContinuityManager { @NonNull Executor executor, @NonNull RemoteTaskListener listener) throws RemoteException { Objects.requireNonNull(executor); Objects.requireNonNull(listener); synchronized(mListeners) { if (!mRegistered) { mService.registerRemoteTaskListener(this); Loading @@ -163,6 +291,8 @@ public class TaskContinuityManager { public void unregisterListener( @NonNull RemoteTaskListener listener) throws RemoteException { Objects.requireNonNull(listener); synchronized(mListeners) { mListeners.remove(listener); if (mListeners.isEmpty() && mRegistered) { Loading
services/companion/java/com/android/server/companion/datatransfer/continuity/TaskContinuityManagerService.java +10 −0 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package com.android.server.companion.datatransfer.continuity; import android.annotation.NonNull; import android.companion.CompanionDeviceManager; import android.companion.datatransfer.continuity.IHandoffRequestCallback; import android.companion.datatransfer.continuity.ITaskContinuityManager; import android.companion.datatransfer.continuity.IRemoteTaskListener; import android.companion.datatransfer.continuity.RemoteTask; Loading Loading @@ -83,6 +84,15 @@ public final class TaskContinuityManagerService extends SystemService { @Override public void unregisterRemoteTaskListener(@NonNull IRemoteTaskListener listener) { } @Override public void requestHandoff( int associationId, int remoteTaskId, @NonNull IHandoffRequestCallback callback) { // TODO: joeantonetti - Implement this method. } } private void onTaskContinuityMessageReceived( Loading