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

Commit 5cecf533 authored by Maurice Lam's avatar Maurice Lam
Browse files

Add launch complete status to launchPendingIntent

Instead of separate onLaunchSuccess and onLaunchFailure methods, combine
them into onLaunchComplete(int status), which can either be SUCCESS or
indicate the reason for failure.

Bug: 219985243
Test: atest CtsVirtualDevicesTestCases
Change-Id: I822c189b4bfc49ce936f072ff6e06f504c8eb80d
parent 9d13dc95
Loading
Loading
Loading
Loading
+4 −6
Original line number Diff line number Diff line
@@ -2777,6 +2777,9 @@ package android.companion.virtual {
  public final class VirtualDeviceManager {
    method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.companion.virtual.VirtualDeviceManager.VirtualDevice createVirtualDevice(int, @NonNull android.companion.virtual.VirtualDeviceParams);
    field public static final int LAUNCH_FAILURE_NO_ACTIVITY = 2; // 0x2
    field public static final int LAUNCH_FAILURE_PENDING_INTENT_CANCELED = 1; // 0x1
    field public static final int LAUNCH_SUCCESS = 0; // 0x0
  }
  public static interface VirtualDeviceManager.ActivityListener {
@@ -2784,11 +2787,6 @@ package android.companion.virtual {
    method public void onTopActivityChanged(int, @NonNull android.content.ComponentName);
  }
  public static interface VirtualDeviceManager.LaunchCallback {
    method public void onLaunchFailed();
    method public void onLaunchSuccess();
  }
  public static class VirtualDeviceManager.VirtualDevice implements java.lang.AutoCloseable {
    method public void addActivityListener(@NonNull java.util.concurrent.Executor, @NonNull android.companion.virtual.VirtualDeviceManager.ActivityListener);
    method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void close();
@@ -2797,7 +2795,7 @@ package android.companion.virtual {
    method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualKeyboard createVirtualKeyboard(@NonNull android.hardware.display.VirtualDisplay, @NonNull String, int, int);
    method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualMouse createVirtualMouse(@NonNull android.hardware.display.VirtualDisplay, @NonNull String, int, int);
    method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public android.hardware.input.VirtualTouchscreen createVirtualTouchscreen(@NonNull android.hardware.display.VirtualDisplay, @NonNull String, int, int);
    method public void launchPendingIntent(int, @NonNull android.app.PendingIntent, @NonNull java.util.concurrent.Executor, @NonNull android.companion.virtual.VirtualDeviceManager.LaunchCallback);
    method public void launchPendingIntent(int, @NonNull android.app.PendingIntent, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.IntConsumer);
    method public void removeActivityListener(@NonNull android.companion.virtual.VirtualDeviceManager.ActivityListener);
    method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void setShowPointerIcon(boolean);
  }
+45 −28
Original line number Diff line number Diff line
@@ -17,13 +17,13 @@
package android.companion.virtual;

import android.annotation.CallbackExecutor;
import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.app.Activity;
import android.app.PendingIntent;
import android.companion.AssociationInfo;
import android.companion.virtual.audio.VirtualAudioDevice;
@@ -48,7 +48,12 @@ import android.os.ResultReceiver;
import android.util.ArrayMap;
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.concurrent.Executor;
import java.util.function.IntConsumer;

/**
 * System level service for managing virtual devices.
@@ -70,6 +75,35 @@ public final class VirtualDeviceManager {
                    | DisplayManager.VIRTUAL_DISPLAY_FLAG_SUPPORTS_TOUCH
                    | DisplayManager.VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP;

    /** @hide */
    @Retention(RetentionPolicy.SOURCE)
    @IntDef(
            prefix = "LAUNCH_",
            value = {
                    LAUNCH_SUCCESS,
                    LAUNCH_FAILURE_PENDING_INTENT_CANCELED,
                    LAUNCH_FAILURE_NO_ACTIVITY})
    @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
    public @interface PendingIntentLaunchStatus {}

    /**
     * Status for {@link VirtualDevice#launchPendingIntent}, indicating that the launch was
     * successful.
     */
    public static final int LAUNCH_SUCCESS = 0;

    /**
     * Status for {@link VirtualDevice#launchPendingIntent}, indicating that the launch failed
     * because the pending intent was canceled.
     */
    public static final int LAUNCH_FAILURE_PENDING_INTENT_CANCELED = 1;

    /**
     * Status for {@link VirtualDevice#launchPendingIntent}, indicating that the launch failed
     * because no activity starts were detected as a result of calling the pending intent.
     */
    public static final int LAUNCH_FAILURE_NO_ACTIVITY = 2;

    private final IVirtualDeviceManager mService;
    private final Context mContext;

@@ -173,16 +207,20 @@ public final class VirtualDeviceManager {
         *   intent, the activity will be started on the virtual display using
         *   {@link android.app.ActivityOptions#setLaunchDisplayId}. If the intent is a service or
         *   broadcast intent, an attempt will be made to catch activities started as a result of
         *   sending the pending intent and move them to the given display.
         *   sending the pending intent and move them to the given display. When it completes,
         *   {@code listener} will be called with the status of whether the launch attempt is
         *   successful or not.
         * @param executor The executor to run {@code launchCallback} on.
         * @param launchCallback Callback that is called when the pending intent launching is
         *   complete.
         * @param listener Listener that is called when the pending intent launching is complete.
         *   The argument is {@link #LAUNCH_SUCCESS} if the launch successfully started an activity
         *   on the virtual display, or one of the {@code LAUNCH_FAILED} status explaining why it
         *   failed.
         */
        public void launchPendingIntent(
                int displayId,
                @NonNull PendingIntent pendingIntent,
                @NonNull Executor executor,
                @NonNull LaunchCallback launchCallback) {
                @NonNull IntConsumer listener) {
            try {
                mVirtualDevice.launchPendingIntent(
                        displayId,
@@ -191,13 +229,7 @@ public final class VirtualDeviceManager {
                            @Override
                            protected void onReceiveResult(int resultCode, Bundle resultData) {
                                super.onReceiveResult(resultCode, resultData);
                                executor.execute(() -> {
                                    if (resultCode == Activity.RESULT_OK) {
                                        launchCallback.onLaunchSuccess();
                                    } else {
                                        launchCallback.onLaunchFailed();
                                    }
                                });
                                executor.execute(() -> listener.accept(resultCode));
                            }
                        });
            } catch (RemoteException e) {
@@ -439,28 +471,13 @@ public final class VirtualDeviceManager {
         * {@link #addActivityListener}.
         *
         * @param listener The listener to remove.
         * @see #addActivityListener(ActivityListener, Executor)
         * @see #addActivityListener(Executor, ActivityListener)
         */
        public void removeActivityListener(@NonNull ActivityListener listener) {
            mActivityListeners.remove(listener);
        }
    }

    /**
     * Callback for launching pending intents on the virtual device.
     */
    public interface LaunchCallback {
        /**
         * Called when the pending intent launched successfully.
         */
        void onLaunchSuccess();

        /**
         * Called when the pending intent failed to launch.
         */
        void onLaunchFailed();
    }

    /**
     * Listener for activity changes in this virtual device.
     */
+17 −3
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ import android.app.admin.DevicePolicyManager;
import android.companion.AssociationInfo;
import android.companion.virtual.IVirtualDevice;
import android.companion.virtual.IVirtualDeviceActivityListener;
import android.companion.virtual.VirtualDeviceManager;
import android.companion.virtual.VirtualDeviceManager.ActivityListener;
import android.companion.virtual.VirtualDeviceParams;
import android.companion.virtual.audio.IAudioSessionCallback;
@@ -77,6 +78,12 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
        implements IBinder.DeathRecipient {

    private static final String TAG = "VirtualDeviceImpl";

    /**
     * Timeout until {@link #launchPendingIntent} stops waiting for an activity to be launched.
     */
    private static final long PENDING_TRAMPOLINE_TIMEOUT_MS = 5000;

    private final Object mVirtualDeviceLock = new Object();

    private final Context mContext;
@@ -188,20 +195,27 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub
        if (pendingIntent.isActivity()) {
            try {
                sendPendingIntent(displayId, pendingIntent);
                resultReceiver.send(Activity.RESULT_OK, null);
                resultReceiver.send(VirtualDeviceManager.LAUNCH_SUCCESS, null);
            } catch (PendingIntent.CanceledException e) {
                Slog.w(TAG, "Pending intent canceled", e);
                resultReceiver.send(Activity.RESULT_CANCELED, null);
                resultReceiver.send(
                        VirtualDeviceManager.LAUNCH_FAILURE_PENDING_INTENT_CANCELED, null);
            }
        } else {
            PendingTrampoline pendingTrampoline = new PendingTrampoline(pendingIntent,
                    resultReceiver, displayId);
            mPendingTrampolineCallback.startWaitingForPendingTrampoline(pendingTrampoline);
            mContext.getMainThreadHandler().postDelayed(() -> {
                pendingTrampoline.mResultReceiver.send(
                        VirtualDeviceManager.LAUNCH_FAILURE_NO_ACTIVITY, null);
                mPendingTrampolineCallback.stopWaitingForPendingTrampoline(pendingTrampoline);
            }, PENDING_TRAMPOLINE_TIMEOUT_MS);
            try {
                sendPendingIntent(displayId, pendingIntent);
            } catch (PendingIntent.CanceledException e) {
                Slog.w(TAG, "Pending intent canceled", e);
                resultReceiver.send(Activity.RESULT_CANCELED, null);
                resultReceiver.send(
                        VirtualDeviceManager.LAUNCH_FAILURE_PENDING_INTENT_CANCELED, null);
                mPendingTrampolineCallback.stopWaitingForPendingTrampoline(pendingTrampoline);
            }
        }
+5 −4
Original line number Diff line number Diff line
@@ -21,7 +21,6 @@ import static com.android.server.wm.ActivityInterceptorCallback.VIRTUAL_DEVICE_S
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.ActivityOptions;
import android.companion.AssociationInfo;
import android.companion.CompanionDeviceManager;
@@ -29,6 +28,7 @@ import android.companion.CompanionDeviceManager.OnAssociationsChangedListener;
import android.companion.virtual.IVirtualDevice;
import android.companion.virtual.IVirtualDeviceActivityListener;
import android.companion.virtual.IVirtualDeviceManager;
import android.companion.virtual.VirtualDeviceManager;
import android.companion.virtual.VirtualDeviceParams;
import android.content.Context;
import android.os.Handler;
@@ -64,7 +64,7 @@ public class VirtualDeviceManagerService extends SystemService {

    private final Object mVirtualDeviceManagerLock = new Object();
    private final VirtualDeviceManagerImpl mImpl;
    private VirtualDeviceManagerInternal mLocalService;
    private final VirtualDeviceManagerInternal mLocalService;
    private final Handler mHandler = new Handler(Looper.getMainLooper());
    private final PendingTrampolineMap mPendingTrampolines = new PendingTrampolineMap(mHandler);
    /**
@@ -115,7 +115,7 @@ public class VirtualDeviceManagerService extends SystemService {
            if (pt == null) {
                return null;
            }
            pt.mResultReceiver.send(Activity.RESULT_OK, null);
            pt.mResultReceiver.send(VirtualDeviceManager.LAUNCH_SUCCESS, null);
            ActivityOptions options = info.checkedOptions;
            if (options == null) {
                options = ActivityOptions.makeBasic();
@@ -310,7 +310,8 @@ public class VirtualDeviceManagerService extends SystemService {
                    pendingTrampoline.mPendingIntent.getCreatorPackage(),
                    pendingTrampoline);
            if (existing != null) {
                existing.mResultReceiver.send(Activity.RESULT_CANCELED, null);
                existing.mResultReceiver.send(
                        VirtualDeviceManager.LAUNCH_FAILURE_NO_ACTIVITY, null);
            }
        }