Loading core/java/android/companion/virtual/VirtualDeviceManager.java +4 −2 Original line number Diff line number Diff line Loading @@ -39,6 +39,7 @@ import android.companion.virtual.audio.VirtualAudioDevice; import android.companion.virtual.audio.VirtualAudioDevice.AudioConfigurationChangeCallback; 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.sensor.VirtualSensor; Loading Loading @@ -212,12 +213,13 @@ public final class VirtualDeviceManager { */ @RequiresPermission(android.Manifest.permission.ACCESS_COMPUTER_CONTROL) @NonNull public IComputerControlSession createComputerControlSession( public ComputerControlSession createComputerControlSession( @NonNull ComputerControlSessionParams params) { Objects.requireNonNull(params, "params must not be null"); try { return mService.createComputerControlSession( IComputerControlSession session = mService.createComputerControlSession( new Binder(), mContext.getAttributionSource(), params); return new ComputerControlSession(session); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } Loading core/java/android/companion/virtual/computercontrol/ComputerControlSession.java 0 → 100644 +102 −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.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.hardware.input.VirtualKeyEvent; import android.hardware.input.VirtualTouchEvent; import android.os.RemoteException; import android.view.Surface; import java.util.Objects; /** * A session for automated control of applications. * * <p>A session is associated with a single trusted virtual display, capable of hosting activities, * along with the input devices that allow input injection.</p> * * @hide */ public final class ComputerControlSession implements AutoCloseable { private final IComputerControlSession mSession; /** @hide */ public ComputerControlSession(@NonNull IComputerControlSession session) { mSession = Objects.requireNonNull(session); } /** Returns the ID of the single trusted virtual display for this session. */ public int getVirtualDisplayId() { try { return mSession.getVirtualDisplayId(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** Injects a key event into the trusted virtual display. */ public void sendKeyEvent(@NonNull VirtualKeyEvent event) { try { mSession.sendKeyEvent(Objects.requireNonNull(event)); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** Injects a touch event into the trusted virtual display. */ public void sendTouchEvent(@NonNull VirtualTouchEvent event) { try { mSession.sendTouchEvent(Objects.requireNonNull(event)); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** Creates an interactive virtual display, mirroring the trusted one. */ @Nullable public InteractiveMirrorDisplay createInteractiveMirrorDisplay( @IntRange(from = 1) int width, @IntRange(from = 1) int height, @NonNull Surface surface) { Objects.requireNonNull(surface); if (width <= 0 || height <= 0) { throw new IllegalArgumentException("Display dimensions must be positive"); } try { IInteractiveMirrorDisplay display = mSession.createInteractiveMirrorDisplay(width, height, surface); if (display == null) { return null; } return new InteractiveMirrorDisplay(display); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } @Override public void close() { try { mSession.close(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } } core/java/android/companion/virtual/computercontrol/ComputerControlSessionParams.aidl +2 −27 Original line number Diff line number Diff line Loading @@ -16,30 +16,5 @@ package android.companion.virtual.computercontrol; import android.view.Surface; /** * Parameters for creating a computer control session. * * @hide */ parcelable ComputerControlSessionParams { /** The name of the session. Only used internally and not shown to users. */ String name; /** The width of the display used for the session. */ int displayWidthPx; /** The height of the display used for the session. */ int displayHeightPx; /** The DPI of the display used for the session. */ int displayDpi; /** The surface of the display used for the session. */ Surface displaySurface; /** Whether the display used for the session should remain always unlocked. */ boolean isDisplayAlwaysUnlocked; } /** @hide */ parcelable ComputerControlSessionParams ; core/java/android/companion/virtual/computercontrol/ComputerControlSessionParams.java 0 → 100644 +253 −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.annotation.IntRange; import android.annotation.NonNull; import android.os.Parcel; import android.os.Parcelable; import android.view.Surface; import java.util.Objects; /** * Parameters for creating a {@link ComputerControlSession}. * * @hide */ public final class ComputerControlSessionParams implements Parcelable { private final String mName; private final int mDisplayWidthPx; private final int mDisplayHeightPx; private final int mDisplayDpi; private final Surface mDisplaySurface; private final boolean mIsDisplayAlwaysUnlocked; private ComputerControlSessionParams( @NonNull String name, int displayWidthPx, int displayHeightPx, int displayDpi, @NonNull Surface displaySurface, boolean isDisplayAlwaysUnlocked) { mName = name; mDisplayWidthPx = displayWidthPx; mDisplayHeightPx = displayHeightPx; mDisplayDpi = displayDpi; mDisplaySurface = displaySurface; mIsDisplayAlwaysUnlocked = isDisplayAlwaysUnlocked; } private ComputerControlSessionParams(Parcel parcel) { mName = parcel.readString8(); mDisplayWidthPx = parcel.readInt(); mDisplayHeightPx = parcel.readInt(); mDisplayDpi = parcel.readInt(); mDisplaySurface = parcel.readTypedObject(Surface.CREATOR); mIsDisplayAlwaysUnlocked = parcel.readBoolean(); } /** Returns the name of this computer control session. */ @NonNull public String getName() { return mName; } /** Returns the width of the display, in pixels. */ public int getDisplayWidthPx() { return mDisplayWidthPx; } /** Returns the height of the display, in pixels. */ public int getDisplayHeightPx() { return mDisplayHeightPx; } /** Returns the density of the display, in dpi. */ public int getDisplayDpi() { return mDisplayDpi; } /** Returns the surface to which the display content should be rendered. */ @NonNull public Surface getDisplaySurface() { return mDisplaySurface; } /** Returns true if the display should be always unlocked. */ public boolean isDisplayAlwaysUnlocked() { return mIsDisplayAlwaysUnlocked; } @Override public int describeContents() { return 0; } @Override public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeString8(mName); dest.writeInt(mDisplayWidthPx); dest.writeInt(mDisplayHeightPx); dest.writeInt(mDisplayDpi); dest.writeTypedObject(mDisplaySurface, flags); dest.writeBoolean(mIsDisplayAlwaysUnlocked); } @NonNull public static final Creator<ComputerControlSessionParams> CREATOR = new Creator<>() { @Override @NonNull public ComputerControlSessionParams createFromParcel(@NonNull Parcel in) { return new ComputerControlSessionParams(in); } @Override @NonNull public ComputerControlSessionParams[] newArray(int size) { return new ComputerControlSessionParams[size]; } }; /** Builder for {@link ComputerControlSessionParams}. */ public static final class Builder { private String mName; private int mDisplayWidthPx; private int mDisplayHeightPx; private int mDisplayDpi; private Surface mDisplaySurface; private boolean mIsDisplayAlwaysUnlocked; /** * Sets the name of this computer control session. * * @param name The name of the session. * @return This builder. */ @NonNull public Builder setName(@NonNull String name) { if (name == null || name.isEmpty()) { throw new IllegalArgumentException("Name must not be empty"); } mName = name; return this; } /** * Sets the width of the display, in pixels. * * @param displayWidthPx The width of the display. * @return This builder. */ @NonNull public Builder setDisplayWidthPx(@IntRange(from = 1) int displayWidthPx) { if (displayWidthPx <= 0) { throw new IllegalArgumentException("Display width must be positive"); } mDisplayWidthPx = displayWidthPx; return this; } /** * Sets the height of the display, in pixels. * * @param displayHeightPx The height of the display. * @return This builder. */ @NonNull public Builder setDisplayHeightPx(@IntRange(from = 1) int displayHeightPx) { if (displayHeightPx <= 0) { throw new IllegalArgumentException("Display height must be positive"); } mDisplayHeightPx = displayHeightPx; return this; } /** * Sets the density of the display, in dpi. * * @param displayDpi The density of the display. * @return This builder. */ @NonNull public Builder setDisplayDpi(@IntRange(from = 1) int displayDpi) { if (displayDpi <= 0) { throw new IllegalArgumentException("Display DPI must be positive"); } mDisplayDpi = displayDpi; return this; } /** * Sets the surface to which the display content should be rendered. * * @param displaySurface The surface for the display. * @return This builder. */ @NonNull public Builder setDisplaySurface(@NonNull Surface displaySurface) { mDisplaySurface = Objects.requireNonNull(displaySurface); return this; } /** * Sets whether the display should be always unlocked. * * @param isDisplayAlwaysUnlocked true if the display should be always unlocked. * @return This builder. */ @NonNull public Builder setDisplayAlwaysUnlocked(boolean isDisplayAlwaysUnlocked) { mIsDisplayAlwaysUnlocked = isDisplayAlwaysUnlocked; return this; } /** * Builds the {@link ComputerControlSessionParams} instance. * * @return The built {@link ComputerControlSessionParams}. * @throws IllegalArgumentException if the name or surface are not set, or if the display * width, height, or dpi are not positive. */ @NonNull public ComputerControlSessionParams build() { if (mName == null || mName.isEmpty()) { throw new IllegalArgumentException("Name must be set"); } if (mDisplaySurface == null) { throw new IllegalArgumentException("Surface must be set"); } if (mDisplayWidthPx <= 0) { throw new IllegalArgumentException("Display width must be positive"); } if (mDisplayHeightPx <= 0) { throw new IllegalArgumentException("Display height must be positive"); } if (mDisplayDpi <= 0) { throw new IllegalArgumentException("Display DPI must be positive"); } return new ComputerControlSessionParams( mName, mDisplayWidthPx, mDisplayHeightPx, mDisplayDpi, mDisplaySurface, mIsDisplayAlwaysUnlocked); } } } core/java/android/companion/virtual/computercontrol/InteractiveMirrorDisplay.java 0 → 100644 +72 −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.annotation.IntRange; import android.annotation.NonNull; import android.hardware.input.VirtualTouchEvent; import android.os.RemoteException; import com.android.internal.annotations.VisibleForTesting; import java.util.Objects; /** * A display, mirroring a computer control session display, and its associated touchscreen. * * @hide */ public final class InteractiveMirrorDisplay implements AutoCloseable { private final IInteractiveMirrorDisplay mDisplay; /** @hide */ @VisibleForTesting public InteractiveMirrorDisplay(@NonNull IInteractiveMirrorDisplay display) { mDisplay = Objects.requireNonNull(display); } /** Resizes the mirror display and updates the associated touchscreen. */ public void resize(@IntRange(from = 1) int width, @IntRange(from = 1) int height) { if (width <= 0 || height <= 0) { throw new IllegalArgumentException("Display dimensions must be positive"); } try { mDisplay.resize(width, height); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** Injects a touch event into the mirror display. */ public void sendTouchEvent(@NonNull VirtualTouchEvent event) { try { mDisplay.sendTouchEvent(Objects.requireNonNull(event)); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } @Override public void close() { try { mDisplay.close(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } } Loading
core/java/android/companion/virtual/VirtualDeviceManager.java +4 −2 Original line number Diff line number Diff line Loading @@ -39,6 +39,7 @@ import android.companion.virtual.audio.VirtualAudioDevice; import android.companion.virtual.audio.VirtualAudioDevice.AudioConfigurationChangeCallback; 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.sensor.VirtualSensor; Loading Loading @@ -212,12 +213,13 @@ public final class VirtualDeviceManager { */ @RequiresPermission(android.Manifest.permission.ACCESS_COMPUTER_CONTROL) @NonNull public IComputerControlSession createComputerControlSession( public ComputerControlSession createComputerControlSession( @NonNull ComputerControlSessionParams params) { Objects.requireNonNull(params, "params must not be null"); try { return mService.createComputerControlSession( IComputerControlSession session = mService.createComputerControlSession( new Binder(), mContext.getAttributionSource(), params); return new ComputerControlSession(session); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } Loading
core/java/android/companion/virtual/computercontrol/ComputerControlSession.java 0 → 100644 +102 −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.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.hardware.input.VirtualKeyEvent; import android.hardware.input.VirtualTouchEvent; import android.os.RemoteException; import android.view.Surface; import java.util.Objects; /** * A session for automated control of applications. * * <p>A session is associated with a single trusted virtual display, capable of hosting activities, * along with the input devices that allow input injection.</p> * * @hide */ public final class ComputerControlSession implements AutoCloseable { private final IComputerControlSession mSession; /** @hide */ public ComputerControlSession(@NonNull IComputerControlSession session) { mSession = Objects.requireNonNull(session); } /** Returns the ID of the single trusted virtual display for this session. */ public int getVirtualDisplayId() { try { return mSession.getVirtualDisplayId(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** Injects a key event into the trusted virtual display. */ public void sendKeyEvent(@NonNull VirtualKeyEvent event) { try { mSession.sendKeyEvent(Objects.requireNonNull(event)); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** Injects a touch event into the trusted virtual display. */ public void sendTouchEvent(@NonNull VirtualTouchEvent event) { try { mSession.sendTouchEvent(Objects.requireNonNull(event)); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** Creates an interactive virtual display, mirroring the trusted one. */ @Nullable public InteractiveMirrorDisplay createInteractiveMirrorDisplay( @IntRange(from = 1) int width, @IntRange(from = 1) int height, @NonNull Surface surface) { Objects.requireNonNull(surface); if (width <= 0 || height <= 0) { throw new IllegalArgumentException("Display dimensions must be positive"); } try { IInteractiveMirrorDisplay display = mSession.createInteractiveMirrorDisplay(width, height, surface); if (display == null) { return null; } return new InteractiveMirrorDisplay(display); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } @Override public void close() { try { mSession.close(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } }
core/java/android/companion/virtual/computercontrol/ComputerControlSessionParams.aidl +2 −27 Original line number Diff line number Diff line Loading @@ -16,30 +16,5 @@ package android.companion.virtual.computercontrol; import android.view.Surface; /** * Parameters for creating a computer control session. * * @hide */ parcelable ComputerControlSessionParams { /** The name of the session. Only used internally and not shown to users. */ String name; /** The width of the display used for the session. */ int displayWidthPx; /** The height of the display used for the session. */ int displayHeightPx; /** The DPI of the display used for the session. */ int displayDpi; /** The surface of the display used for the session. */ Surface displaySurface; /** Whether the display used for the session should remain always unlocked. */ boolean isDisplayAlwaysUnlocked; } /** @hide */ parcelable ComputerControlSessionParams ;
core/java/android/companion/virtual/computercontrol/ComputerControlSessionParams.java 0 → 100644 +253 −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.annotation.IntRange; import android.annotation.NonNull; import android.os.Parcel; import android.os.Parcelable; import android.view.Surface; import java.util.Objects; /** * Parameters for creating a {@link ComputerControlSession}. * * @hide */ public final class ComputerControlSessionParams implements Parcelable { private final String mName; private final int mDisplayWidthPx; private final int mDisplayHeightPx; private final int mDisplayDpi; private final Surface mDisplaySurface; private final boolean mIsDisplayAlwaysUnlocked; private ComputerControlSessionParams( @NonNull String name, int displayWidthPx, int displayHeightPx, int displayDpi, @NonNull Surface displaySurface, boolean isDisplayAlwaysUnlocked) { mName = name; mDisplayWidthPx = displayWidthPx; mDisplayHeightPx = displayHeightPx; mDisplayDpi = displayDpi; mDisplaySurface = displaySurface; mIsDisplayAlwaysUnlocked = isDisplayAlwaysUnlocked; } private ComputerControlSessionParams(Parcel parcel) { mName = parcel.readString8(); mDisplayWidthPx = parcel.readInt(); mDisplayHeightPx = parcel.readInt(); mDisplayDpi = parcel.readInt(); mDisplaySurface = parcel.readTypedObject(Surface.CREATOR); mIsDisplayAlwaysUnlocked = parcel.readBoolean(); } /** Returns the name of this computer control session. */ @NonNull public String getName() { return mName; } /** Returns the width of the display, in pixels. */ public int getDisplayWidthPx() { return mDisplayWidthPx; } /** Returns the height of the display, in pixels. */ public int getDisplayHeightPx() { return mDisplayHeightPx; } /** Returns the density of the display, in dpi. */ public int getDisplayDpi() { return mDisplayDpi; } /** Returns the surface to which the display content should be rendered. */ @NonNull public Surface getDisplaySurface() { return mDisplaySurface; } /** Returns true if the display should be always unlocked. */ public boolean isDisplayAlwaysUnlocked() { return mIsDisplayAlwaysUnlocked; } @Override public int describeContents() { return 0; } @Override public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeString8(mName); dest.writeInt(mDisplayWidthPx); dest.writeInt(mDisplayHeightPx); dest.writeInt(mDisplayDpi); dest.writeTypedObject(mDisplaySurface, flags); dest.writeBoolean(mIsDisplayAlwaysUnlocked); } @NonNull public static final Creator<ComputerControlSessionParams> CREATOR = new Creator<>() { @Override @NonNull public ComputerControlSessionParams createFromParcel(@NonNull Parcel in) { return new ComputerControlSessionParams(in); } @Override @NonNull public ComputerControlSessionParams[] newArray(int size) { return new ComputerControlSessionParams[size]; } }; /** Builder for {@link ComputerControlSessionParams}. */ public static final class Builder { private String mName; private int mDisplayWidthPx; private int mDisplayHeightPx; private int mDisplayDpi; private Surface mDisplaySurface; private boolean mIsDisplayAlwaysUnlocked; /** * Sets the name of this computer control session. * * @param name The name of the session. * @return This builder. */ @NonNull public Builder setName(@NonNull String name) { if (name == null || name.isEmpty()) { throw new IllegalArgumentException("Name must not be empty"); } mName = name; return this; } /** * Sets the width of the display, in pixels. * * @param displayWidthPx The width of the display. * @return This builder. */ @NonNull public Builder setDisplayWidthPx(@IntRange(from = 1) int displayWidthPx) { if (displayWidthPx <= 0) { throw new IllegalArgumentException("Display width must be positive"); } mDisplayWidthPx = displayWidthPx; return this; } /** * Sets the height of the display, in pixels. * * @param displayHeightPx The height of the display. * @return This builder. */ @NonNull public Builder setDisplayHeightPx(@IntRange(from = 1) int displayHeightPx) { if (displayHeightPx <= 0) { throw new IllegalArgumentException("Display height must be positive"); } mDisplayHeightPx = displayHeightPx; return this; } /** * Sets the density of the display, in dpi. * * @param displayDpi The density of the display. * @return This builder. */ @NonNull public Builder setDisplayDpi(@IntRange(from = 1) int displayDpi) { if (displayDpi <= 0) { throw new IllegalArgumentException("Display DPI must be positive"); } mDisplayDpi = displayDpi; return this; } /** * Sets the surface to which the display content should be rendered. * * @param displaySurface The surface for the display. * @return This builder. */ @NonNull public Builder setDisplaySurface(@NonNull Surface displaySurface) { mDisplaySurface = Objects.requireNonNull(displaySurface); return this; } /** * Sets whether the display should be always unlocked. * * @param isDisplayAlwaysUnlocked true if the display should be always unlocked. * @return This builder. */ @NonNull public Builder setDisplayAlwaysUnlocked(boolean isDisplayAlwaysUnlocked) { mIsDisplayAlwaysUnlocked = isDisplayAlwaysUnlocked; return this; } /** * Builds the {@link ComputerControlSessionParams} instance. * * @return The built {@link ComputerControlSessionParams}. * @throws IllegalArgumentException if the name or surface are not set, or if the display * width, height, or dpi are not positive. */ @NonNull public ComputerControlSessionParams build() { if (mName == null || mName.isEmpty()) { throw new IllegalArgumentException("Name must be set"); } if (mDisplaySurface == null) { throw new IllegalArgumentException("Surface must be set"); } if (mDisplayWidthPx <= 0) { throw new IllegalArgumentException("Display width must be positive"); } if (mDisplayHeightPx <= 0) { throw new IllegalArgumentException("Display height must be positive"); } if (mDisplayDpi <= 0) { throw new IllegalArgumentException("Display DPI must be positive"); } return new ComputerControlSessionParams( mName, mDisplayWidthPx, mDisplayHeightPx, mDisplayDpi, mDisplaySurface, mIsDisplayAlwaysUnlocked); } } }
core/java/android/companion/virtual/computercontrol/InteractiveMirrorDisplay.java 0 → 100644 +72 −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.annotation.IntRange; import android.annotation.NonNull; import android.hardware.input.VirtualTouchEvent; import android.os.RemoteException; import com.android.internal.annotations.VisibleForTesting; import java.util.Objects; /** * A display, mirroring a computer control session display, and its associated touchscreen. * * @hide */ public final class InteractiveMirrorDisplay implements AutoCloseable { private final IInteractiveMirrorDisplay mDisplay; /** @hide */ @VisibleForTesting public InteractiveMirrorDisplay(@NonNull IInteractiveMirrorDisplay display) { mDisplay = Objects.requireNonNull(display); } /** Resizes the mirror display and updates the associated touchscreen. */ public void resize(@IntRange(from = 1) int width, @IntRange(from = 1) int height) { if (width <= 0 || height <= 0) { throw new IllegalArgumentException("Display dimensions must be positive"); } try { mDisplay.resize(width, height); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } /** Injects a touch event into the mirror display. */ public void sendTouchEvent(@NonNull VirtualTouchEvent event) { try { mDisplay.sendTouchEvent(Objects.requireNonNull(event)); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } @Override public void close() { try { mDisplay.close(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } } }