Merge "Add launch complete status to launchPendingIntent" into tm-dev

This commit is contained in:
TreeHugger Robot 2022-03-30 22:47:56 +00:00 committed by Android (Google) Code Review
commit 3ece298e8b
4 changed files with 71 additions and 41 deletions

View File

@ -2784,6 +2784,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 {
@ -2791,11 +2794,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();
@ -2804,7 +2802,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);
}

View File

@ -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.
*/

View File

@ -33,6 +33,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.IAudioConfigChangedCallback;
@ -79,6 +80,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;
@ -195,20 +202,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);
}
}

View File

@ -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();
@ -314,7 +314,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);
}
}