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

Commit cceab4de authored by Shaun Corkran's avatar Shaun Corkran Committed by Android (Google) Code Review
Browse files

Merge "Addition of native handoff of an intercepted intent matched according...

Merge "Addition of native handoff of an intercepted intent matched according to a provided IntentFilter."
parents 02662777 bc3f6fa5
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -2991,6 +2991,10 @@ package android.companion.virtual {
    method public void onTopActivityChanged(int, @NonNull android.content.ComponentName);
  }
  public static interface VirtualDeviceManager.IntentInterceptorCallback {
    method public void onIntentIntercepted(@NonNull android.content.Intent);
  }
  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();
@@ -3009,8 +3013,10 @@ package android.companion.virtual {
    method public int getDeviceId();
    method @Nullable public android.companion.virtual.sensor.VirtualSensor getVirtualSensor(int, @NonNull String);
    method public void launchPendingIntent(int, @NonNull android.app.PendingIntent, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.IntConsumer);
    method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void registerIntentInterceptor(@NonNull java.util.concurrent.Executor, @NonNull android.content.IntentFilter, @NonNull android.companion.virtual.VirtualDeviceManager.IntentInterceptorCallback);
    method public void removeActivityListener(@NonNull android.companion.virtual.VirtualDeviceManager.ActivityListener);
    method @NonNull @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void setShowPointerIcon(boolean);
    method @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE) public void unregisterIntentInterceptor(@NonNull android.companion.virtual.VirtualDeviceManager.IntentInterceptorCallback);
  }
  public final class VirtualDeviceParams implements android.os.Parcelable {
+13 −0
Original line number Diff line number Diff line
@@ -17,11 +17,13 @@
package android.companion.virtual;

import android.app.PendingIntent;
import android.companion.virtual.IVirtualDeviceIntentInterceptor;
import android.companion.virtual.audio.IAudioConfigChangedCallback;
import android.companion.virtual.audio.IAudioRoutingCallback;
import android.companion.virtual.sensor.IVirtualSensorStateChangeCallback;
import android.companion.virtual.sensor.VirtualSensorConfig;
import android.companion.virtual.sensor.VirtualSensorEvent;
import android.content.IntentFilter;
import android.graphics.Point;
import android.graphics.PointF;
import android.hardware.input.VirtualDpadConfig;
@@ -125,4 +127,15 @@ interface IVirtualDevice {

    /** Sets whether to show or hide the cursor while this virtual device is active. */
    void setShowPointerIcon(boolean showPointerIcon);

    /**
     * Registers an intent interceptor that will intercept an intent attempting to launch
     * when matching the provided IntentFilter and calls the callback with the intercepted
     * intent.
     */
    @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)")
    void registerIntentInterceptor(
            in IVirtualDeviceIntentInterceptor intentInterceptor, in IntentFilter filter);
    @JavaPassthrough(annotation="@android.annotation.RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)")
    void unregisterIntentInterceptor(in IVirtualDeviceIntentInterceptor intentInterceptor);
}
+39 −0
Original line number Diff line number Diff line
/*
 * Copyright 2022 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;

import android.content.Intent;

/**
 * Interceptor interface to be called when an intent matches the IntentFilter passed into {@link
 * VirtualDevice#registerIntentInterceptor}. When the interceptor is called after matching the
 * IntentFilter, the intended activity launch will be aborted and alternatively replaced by
 * the interceptor's receiver.
 *
 * @hide
 */
oneway interface IVirtualDeviceIntentInterceptor {

    /**
     * Called when an intent that matches the IntentFilter registered in {@link
     * VirtualDevice#registerIntentInterceptor} is intercepted for the virtual device to
     * handle.
     *
     * @param intent The intent that has been intercepted by the interceptor.
     */
    void onIntentIntercepted(in Intent intent);
}
+99 −0
Original line number Diff line number Diff line
@@ -35,6 +35,8 @@ import android.companion.virtual.sensor.VirtualSensor;
import android.companion.virtual.sensor.VirtualSensorConfig;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Point;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.display.DisplayManager;
@@ -269,6 +271,9 @@ public final class VirtualDeviceManager {
        private final IVirtualDevice mVirtualDevice;
        private final ArrayMap<ActivityListener, ActivityListenerDelegate> mActivityListeners =
                new ArrayMap<>();
        private final ArrayMap<IntentInterceptorCallback,
                     VirtualIntentInterceptorDelegate> mIntentInterceptorListeners =
                new ArrayMap<>();
        private final IVirtualDeviceActivityListener mActivityListenerBinder =
                new IVirtualDeviceActivityListener.Stub() {

@@ -857,6 +862,53 @@ public final class VirtualDeviceManager {
        public void removeActivityListener(@NonNull ActivityListener listener) {
            mActivityListeners.remove(listener);
        }

        /**
         * Registers an intent interceptor that will intercept an intent attempting to launch
         * when matching the provided IntentFilter and calls the callback with the intercepted
         * intent.
         *
         * @param executor The executor where the interceptor is executed on.
         * @param interceptorFilter The filter to match intents intended for interception.
         * @param interceptorCallback The callback called when an intent matching interceptorFilter
         * is intercepted.
         * @see #unregisterIntentInterceptor(IntentInterceptorCallback)
         */
        @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
        public void registerIntentInterceptor(
                @CallbackExecutor @NonNull Executor executor,
                @NonNull IntentFilter interceptorFilter,
                @NonNull IntentInterceptorCallback interceptorCallback) {
            Objects.requireNonNull(executor);
            Objects.requireNonNull(interceptorFilter);
            Objects.requireNonNull(interceptorCallback);
            final VirtualIntentInterceptorDelegate delegate =
                    new VirtualIntentInterceptorDelegate(executor, interceptorCallback);
            try {
                mVirtualDevice.registerIntentInterceptor(delegate, interceptorFilter);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
            mIntentInterceptorListeners.put(interceptorCallback, delegate);
        }

        /**
         * Unregisters the intent interceptorCallback previously registered with
         * {@link #registerIntentInterceptor}.
         */
        @RequiresPermission(android.Manifest.permission.CREATE_VIRTUAL_DEVICE)
        public void unregisterIntentInterceptor(
                    @NonNull IntentInterceptorCallback interceptorCallback) {
            Objects.requireNonNull(interceptorCallback);
            final VirtualIntentInterceptorDelegate delegate =
                    mIntentInterceptorListeners.get(interceptorCallback);
            try {
                mVirtualDevice.unregisterIntentInterceptor(delegate);
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
            mIntentInterceptorListeners.remove(interceptorCallback);
        }
    }

    /**
@@ -908,4 +960,51 @@ public final class VirtualDeviceManager {
            mExecutor.execute(() -> mActivityListener.onDisplayEmpty(displayId));
        }
    }

    /**
     * Interceptor interface to be called when an intent matches the IntentFilter passed into {@link
     * VirtualDevice#registerIntentInterceptor}. When the interceptor is called after matching the
     * IntentFilter, the intended activity launch will be aborted and alternatively replaced by
     * the interceptor's receiver.
     *
     * @hide
     */
    @SystemApi
    public interface IntentInterceptorCallback {

        /**
         * Called when an intent that matches the IntentFilter registered in {@link
         * VirtualDevice#registerIntentInterceptor} is intercepted for the virtual device to
         * handle.
         *
         * @param intent The intent that has been intercepted by the interceptor.
         */
        void onIntentIntercepted(@NonNull Intent intent);
    }

    /**
     * A wrapper for {@link IntentInterceptorCallback} that executes callbacks on the
     * the given executor.
     */
    private static class VirtualIntentInterceptorDelegate
            extends IVirtualDeviceIntentInterceptor.Stub {
        @NonNull private final IntentInterceptorCallback mIntentInterceptorCallback;
        @NonNull private final Executor mExecutor;

        private VirtualIntentInterceptorDelegate(Executor executor,
                IntentInterceptorCallback interceptorCallback) {
            mExecutor = executor;
            mIntentInterceptorCallback = interceptorCallback;
        }

        @Override
        public void onIntentIntercepted(Intent intent) {
            final long token = Binder.clearCallingIdentity();
            try {
                mExecutor.execute(() -> mIntentInterceptorCallback.onIntentIntercepted(intent));
            } finally {
                Binder.restoreCallingIdentity(token);
            }
        }
    }
}
+2 −1
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import android.annotation.NonNull;
import android.app.WindowConfiguration;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.util.ArraySet;

@@ -114,7 +115,7 @@ public abstract class DisplayWindowPolicyController {
    /**
     * Returns {@code true} if the given new task can be launched on this virtual display.
     */
    public abstract boolean canActivityBeLaunched(@NonNull ActivityInfo activityInfo,
    public abstract boolean canActivityBeLaunched(@NonNull ActivityInfo activityInfo, Intent intent,
            @WindowConfiguration.WindowingMode int windowingMode, int launchingFromDisplayId,
            boolean isNewTask);

Loading