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

Commit 20fe1406 authored by [D's avatar [D[1;5D Committed by Vladimir Komsiyski
Browse files

Async ComputerControl session creation and callback

Bug: 432678191
Test: atest
Flag: android.companion.virtualdevice.flags.computer_control_access
Change-Id: I4be26c94a9280a5644ce160ab9fc05cfaf7f73a7
parent ccb4fd07
Loading
Loading
Loading
Loading
+5 −5
Original line number Diff line number Diff line
@@ -23,7 +23,7 @@ import android.companion.virtual.IVirtualDeviceSoundEffectListener;
import android.companion.virtual.VirtualDevice;
import android.companion.virtual.VirtualDeviceParams;
import android.companion.virtual.computercontrol.ComputerControlSessionParams;
import android.companion.virtual.computercontrol.IComputerControlSession;
import android.companion.virtual.computercontrol.IComputerControlSessionCallback;
import android.content.AttributionSource;

/**
@@ -53,12 +53,12 @@ interface IVirtualDeviceManager {
            in IVirtualDeviceSoundEffectListener soundEffectListener);

    /**
     * Creates a new computer control session.
     * Requests a new computer control session.
     */
    @EnforcePermission("ACCESS_COMPUTER_CONTROL")
    IComputerControlSession createComputerControlSession(
            in IBinder token, in AttributionSource attributionSource,
            in ComputerControlSessionParams params);
    void requestComputerControlSession(
            in AttributionSource attributionSource, in ComputerControlSessionParams params,
            in IComputerControlSessionCallback callback);

    /**
     * Returns the details of all available virtual devices.
+21 −7
Original line number Diff line number Diff line
@@ -41,7 +41,7 @@ import android.companion.virtual.camera.VirtualCamera;
import android.companion.virtual.camera.VirtualCameraConfig;
import android.companion.virtual.computercontrol.ComputerControlSession;
import android.companion.virtual.computercontrol.ComputerControlSessionParams;
import android.companion.virtual.computercontrol.IComputerControlSession;
import android.companion.virtual.computercontrol.IComputerControlSessionCallback;
import android.companion.virtual.sensor.VirtualSensor;
import android.companion.virtualdevice.flags.Flags;
import android.content.ComponentName;
@@ -209,17 +209,31 @@ public final class VirtualDeviceManager {
    }

    /**
     * Requests the creation of a new {@link ComputerControlSession}.
     *
     * @param params The configuration of the session.
     * @param executor An executor to run the callback on.
     * @param callback A callback to get notified about the result of this operation.
     *
     * @hide
     */
    @RequiresPermission(android.Manifest.permission.ACCESS_COMPUTER_CONTROL)
    @NonNull
    public ComputerControlSession createComputerControlSession(
            @NonNull ComputerControlSessionParams params) {
    public void requestComputerControlSession(
            @NonNull ComputerControlSessionParams params,
            @NonNull @CallbackExecutor Executor executor,
            @NonNull ComputerControlSession.Callback callback) {
        if (mService == null) {
            Log.w(TAG, "Failed to request a new session; no virtual device manager service.");
            return;
        }
        Objects.requireNonNull(params, "params must not be null");
        Objects.requireNonNull(executor, "executor must not be null");
        Objects.requireNonNull(callback, "callback must not be null");
        try {
            IComputerControlSession session = mService.createComputerControlSession(
                    new Binder(), mContext.getAttributionSource(), params);
            return new ComputerControlSession(session);
            IComputerControlSessionCallback callbackProxy =
                    new ComputerControlSession.CallbackProxy(executor, callback);
            mService.requestComputerControlSession(
                    mContext.getAttributionSource(), params, callbackProxy);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
+59 −0
Original line number Diff line number Diff line
@@ -16,15 +16,22 @@

package android.companion.virtual.computercontrol;

import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.hardware.input.VirtualKeyEvent;
import android.hardware.input.VirtualTouchEvent;
import android.os.Binder;
import android.os.RemoteException;
import android.view.Surface;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Objects;
import java.util.concurrent.Executor;

/**
 * A session for automated control of applications.
@@ -36,6 +43,23 @@ import java.util.Objects;
 */
public final class ComputerControlSession implements AutoCloseable {

    /**
     * Error code indicating that a new session cannot be created because the maximum number of
     * allowed concurrent sessions has been reached.
     *
     * <p>This is a transient error and the session creation request can be retried later.</p>
     */
    public static final int ERROR_SESSION_LIMIT_REACHED = -1;

    /** @hide */
    @Retention(RetentionPolicy.SOURCE)
    @IntDef(
            prefix = "ERROR_",
            value = {ERROR_SESSION_LIMIT_REACHED})
    @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
    public @interface SessionCreationError {
    }

    private final IComputerControlSession mSession;

    /** @hide */
@@ -99,4 +123,39 @@ public final class ComputerControlSession implements AutoCloseable {
            throw e.rethrowFromSystemServer();
        }
    }

    /** Callback for computer control session events. */
    public interface Callback {

        /** Called when the session request was successfully fulfilled. */
        void onSessionCreated(@NonNull ComputerControlSession session);

        /** Called when the session failed to be created. */
        void onSessionCreationFailed(@SessionCreationError int errorCode);
    }

    /** @hide */
    public static class CallbackProxy extends IComputerControlSessionCallback.Stub {

        private final Callback mCallback;
        private final Executor mExecutor;

        public CallbackProxy(@NonNull Executor executor, @NonNull Callback callback) {
            mExecutor = executor;
            mCallback = callback;
        }

        @Override
        public void onSessionCreated(IComputerControlSession session) {
            Binder.withCleanCallingIdentity(() ->
                    mExecutor.execute(() ->
                            mCallback.onSessionCreated(new ComputerControlSession(session))));
        }

        @Override
        public void onSessionCreationFailed(@SessionCreationError int errorCode) {
            Binder.withCleanCallingIdentity(() ->
                    mExecutor.execute(() -> mCallback.onSessionCreationFailed(errorCode)));
        }
    }
}
+33 −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.virtual.computercontrol;

import android.companion.virtual.computercontrol.IComputerControlSession;

/**
 * Callback for computer control session events.
 *
 * @hide
 */
oneway interface IComputerControlSessionCallback {

    /** Called when the session has been successfully created. */
    void onSessionCreated(in IComputerControlSession session);

    /** Called when the session failed to be created. */
    void onSessionCreationFailed(int errorCode);
}
+8 −8
Original line number Diff line number Diff line
@@ -42,7 +42,7 @@ import android.companion.virtual.VirtualDevice;
import android.companion.virtual.VirtualDeviceManager;
import android.companion.virtual.VirtualDeviceParams;
import android.companion.virtual.computercontrol.ComputerControlSessionParams;
import android.companion.virtual.computercontrol.IComputerControlSession;
import android.companion.virtual.computercontrol.IComputerControlSessionCallback;
import android.companion.virtual.sensor.VirtualSensor;
import android.companion.virtualdevice.flags.Flags;
import android.companion.virtualnative.IVirtualDeviceManagerNative;
@@ -416,22 +416,22 @@ public class VirtualDeviceManagerService extends SystemService {

        @EnforcePermission(android.Manifest.permission.ACCESS_COMPUTER_CONTROL)
        @Override // Binder call
        public IComputerControlSession createComputerControlSession(
                @NonNull IBinder token,
        public void requestComputerControlSession(
                @NonNull AttributionSource attributionSource,
                @NonNull ComputerControlSessionParams params) {
                @NonNull ComputerControlSessionParams params,
                @NonNull IComputerControlSessionCallback callback) {
            // TODO(b/432678187): Replace the permission check with an alternative
            createComputerControlSession_enforcePermission();
            requestComputerControlSession_enforcePermission();
            if (!android.companion.virtualdevice.flags.Flags.computerControlAccess()) {
                throw new IllegalStateException(
                        "Cannot create ComputerControlSession - flag disabled");
            }
            Objects.requireNonNull(token);
            Objects.requireNonNull(attributionSource);
            Objects.requireNonNull(params);
            Objects.requireNonNull(callback);

            return mComputerControlSessionProcessor.processNewSession(
                    token, attributionSource, params);
            mComputerControlSessionProcessor.processNewSessionRequest(
                    attributionSource, params, callback);
        }

        @EnforcePermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
Loading