Loading core/api/system-current.txt +4 −0 Original line number Diff line number Diff line Loading @@ -3450,8 +3450,10 @@ package android.companion.virtual { method public int describeContents(); method @NonNull public java.time.Duration getDoubleTapMinTimeDuration(); method @NonNull public java.time.Duration getDoubleTapTimeoutDuration(); method @NonNull public java.time.Duration getLongPressTimeoutDuration(); method @FloatRange(from=0) public float getMaximumFlingVelocityDpPerSecond(); method @FloatRange(from=0) public float getMinimumFlingVelocityDpPerSecond(); method @NonNull public java.time.Duration getMultiPressTimeoutDuration(); method @FloatRange(from=0) public float getScrollFriction(); method @NonNull public java.time.Duration getTapTimeoutDuration(); method @FloatRange(from=0) public float getTouchSlopDp(); Loading @@ -3464,8 +3466,10 @@ package android.companion.virtual { method @NonNull public android.companion.virtual.ViewConfigurationParams build(); method @NonNull public android.companion.virtual.ViewConfigurationParams.Builder setDoubleTapMinTimeDuration(@NonNull java.time.Duration); method @NonNull public android.companion.virtual.ViewConfigurationParams.Builder setDoubleTapTimeoutDuration(@NonNull java.time.Duration); method @NonNull public android.companion.virtual.ViewConfigurationParams.Builder setLongPressTimeoutDuration(@NonNull java.time.Duration); method @NonNull public android.companion.virtual.ViewConfigurationParams.Builder setMaximumFlingVelocityDpPerSecond(@FloatRange(from=0) float); method @NonNull public android.companion.virtual.ViewConfigurationParams.Builder setMinimumFlingVelocityDpPerSecond(@FloatRange(from=0) float); method @NonNull public android.companion.virtual.ViewConfigurationParams.Builder setMultiPressTimeoutDuration(@NonNull java.time.Duration); method @NonNull public android.companion.virtual.ViewConfigurationParams.Builder setScrollFriction(@FloatRange(from=0) float); method @NonNull public android.companion.virtual.ViewConfigurationParams.Builder setTapTimeoutDuration(@NonNull java.time.Duration); method @NonNull public android.companion.virtual.ViewConfigurationParams.Builder setTouchSlopDp(@FloatRange(from=0) float); core/java/android/companion/virtual/ViewConfigurationParams.java +82 −5 Original line number Diff line number Diff line Loading @@ -51,10 +51,13 @@ public final class ViewConfigurationParams implements Parcelable { private final int mTapTimeoutMillis; private final int mDoubleTapTimeoutMillis; private final int mDoubleTapMinTimeMillis; private final int mLongPressTimeoutMillis; private final int mMultiPressTimeoutMillis; private ViewConfigurationParams(float touchSlopDp, float minimumFlingVelocityDpPerSecond, float maximumFlingVelocityDpPerSecond, float scrollFriction, int tapTimeoutMillis, int doubleTapTimeoutMillis, int doubleTapMinTimeMillis) { int doubleTapTimeoutMillis, int doubleTapMinTimeMillis, int longPressTimeoutMillis, int multiPressTimeoutMillis) { mTouchSlopDp = touchSlopDp; mMinimumFlingVelocityDpPerSecond = minimumFlingVelocityDpPerSecond; mMaximumFlingVelocityDpPerSecond = maximumFlingVelocityDpPerSecond; Loading @@ -62,6 +65,8 @@ public final class ViewConfigurationParams implements Parcelable { mTapTimeoutMillis = tapTimeoutMillis; mDoubleTapTimeoutMillis = doubleTapTimeoutMillis; mDoubleTapMinTimeMillis = doubleTapMinTimeMillis; mLongPressTimeoutMillis = longPressTimeoutMillis; mMultiPressTimeoutMillis = multiPressTimeoutMillis; } private ViewConfigurationParams(Parcel in) { Loading @@ -72,6 +77,8 @@ public final class ViewConfigurationParams implements Parcelable { mTapTimeoutMillis = in.readInt(); mDoubleTapTimeoutMillis = in.readInt(); mDoubleTapMinTimeMillis = in.readInt(); mLongPressTimeoutMillis = in.readInt(); mMultiPressTimeoutMillis = in.readInt(); } @Override Loading @@ -88,6 +95,8 @@ public final class ViewConfigurationParams implements Parcelable { dest.writeInt(mTapTimeoutMillis); dest.writeInt(mDoubleTapTimeoutMillis); dest.writeInt(mDoubleTapMinTimeMillis); dest.writeInt(mLongPressTimeoutMillis); dest.writeInt(mMultiPressTimeoutMillis); } @Override Loading @@ -102,14 +111,17 @@ public final class ViewConfigurationParams implements Parcelable { && Float.compare(mScrollFriction, that.mScrollFriction) == 0 && mTapTimeoutMillis == that.mTapTimeoutMillis && mDoubleTapTimeoutMillis == that.mDoubleTapTimeoutMillis && mDoubleTapMinTimeMillis == that.mDoubleTapMinTimeMillis; && mDoubleTapMinTimeMillis == that.mDoubleTapMinTimeMillis && mLongPressTimeoutMillis == that.mLongPressTimeoutMillis && mMultiPressTimeoutMillis == that.mMultiPressTimeoutMillis; } @Override public int hashCode() { return Objects.hash(mTouchSlopDp, mMinimumFlingVelocityDpPerSecond, mMaximumFlingVelocityDpPerSecond, mScrollFriction, mTapTimeoutMillis, mDoubleTapTimeoutMillis, mDoubleTapMinTimeMillis); mDoubleTapTimeoutMillis, mDoubleTapMinTimeMillis, mLongPressTimeoutMillis, mMultiPressTimeoutMillis); } @Override Loading @@ -123,6 +135,8 @@ public final class ViewConfigurationParams implements Parcelable { + ", mTapTimeoutMillis=" + mTapTimeoutMillis + ", mDoubleTapTimeoutMillis=" + mDoubleTapTimeoutMillis + ", mDoubleTapMinTimeMillis=" + mDoubleTapMinTimeMillis + ", mLongPressTimeoutMillis=" + mLongPressTimeoutMillis + ", mMultiPressTimeoutMillis=" + mMultiPressTimeoutMillis + ')'; } Loading Loading @@ -194,6 +208,22 @@ public final class ViewConfigurationParams implements Parcelable { return Duration.ofMillis(mDoubleTapMinTimeMillis); } /** * Returns a {@link Duration} representing the long press timeout. */ @NonNull public Duration getLongPressTimeoutDuration() { return Duration.ofMillis(mLongPressTimeoutMillis); } /** * Returns a {@link Duration} representing the multi press timeout. */ @NonNull public Duration getMultiPressTimeoutDuration() { return Duration.ofMillis(mMultiPressTimeoutMillis); } @NonNull public static final Creator<ViewConfigurationParams> CREATOR = new Creator<>() { Loading Loading @@ -221,6 +251,8 @@ public final class ViewConfigurationParams implements Parcelable { private int mTapTimeoutMillis = INVALID_VALUE; private int mDoubleTapTimeoutMillis = INVALID_VALUE; private int mDoubleTapMinTimeMillis = INVALID_VALUE; private int mLongPressTimeoutMillis = INVALID_VALUE; private int mMultiPressTimeoutMillis = INVALID_VALUE; /** * Sets the touch slop in density independent pixels (dp). When this is set, Loading Loading @@ -357,6 +389,48 @@ public final class ViewConfigurationParams implements Parcelable { return this; } /** * Sets the long press timeout as {@link Duration}. * * @throws IllegalArgumentException if the corresponding milliseconds value is negative, or * greater than {@link Integer#MAX_VALUE}. */ @NonNull public Builder setLongPressTimeoutDuration(@NonNull Duration duration) { Objects.requireNonNull(duration); if (duration.isNegative()) { throw new IllegalArgumentException("Long press timeout cannot be negative"); } long millis = duration.toMillis(); if (millis > Integer.MAX_VALUE) { throw new IllegalArgumentException( "Long press timeout cannot be larger than " + Integer.MAX_VALUE); } mLongPressTimeoutMillis = (int) millis; return this; } /** * Sets the multi press timeout as {@link Duration}. * * @throws IllegalArgumentException if the corresponding milliseconds value is negative, or * greater than {@link Integer#MAX_VALUE}. */ @NonNull public Builder setMultiPressTimeoutDuration(@NonNull Duration duration) { Objects.requireNonNull(duration); if (duration.isNegative()) { throw new IllegalArgumentException("Multi press timeout cannot be negative"); } long millis = duration.toMillis(); if (millis > Integer.MAX_VALUE) { throw new IllegalArgumentException( "Multi press timeout cannot be larger than " + Integer.MAX_VALUE); } mMultiPressTimeoutMillis = (int) millis; return this; } /** * Builds the {@link ViewConfigurationParams} instance. * Loading @@ -371,7 +445,9 @@ public final class ViewConfigurationParams implements Parcelable { && mScrollFriction == INVALID_VALUE && mTapTimeoutMillis == INVALID_VALUE && mDoubleTapTimeoutMillis == INVALID_VALUE && mDoubleTapMinTimeMillis == INVALID_VALUE) { && mDoubleTapMinTimeMillis == INVALID_VALUE && mLongPressTimeoutMillis == INVALID_VALUE && mMultiPressTimeoutMillis == INVALID_VALUE) { throw new IllegalArgumentException("None of the parameters are set"); } if (mMinimumFlingVelocityDpPerSecond != INVALID_VALUE Loading @@ -382,7 +458,8 @@ public final class ViewConfigurationParams implements Parcelable { } return new ViewConfigurationParams(mTouchSlopDp, mMinimumFlingVelocityDpPerSecond, mMaximumFlingVelocityDpPerSecond, mScrollFriction, mTapTimeoutMillis, mDoubleTapTimeoutMillis, mDoubleTapMinTimeMillis); mDoubleTapTimeoutMillis, mDoubleTapMinTimeMillis, mLongPressTimeoutMillis, mMultiPressTimeoutMillis); } } } services/companion/java/com/android/server/companion/virtual/ViewConfigurationController.java +79 −31 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.server.companion.virtual; import android.annotation.NonNull; import android.annotation.Nullable; import android.companion.virtual.ViewConfigurationParams; import android.content.ContentResolver; import android.content.Context; import android.content.om.FabricatedOverlay; import android.content.om.OverlayConstraint; Loading @@ -26,6 +27,7 @@ import android.content.om.OverlayIdentifier; import android.content.om.OverlayManager; import android.content.om.OverlayManagerTransaction; import android.os.Binder; import android.provider.Settings; import android.util.Slog; import android.util.TypedValue; Loading @@ -33,6 +35,7 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import java.util.List; import java.util.Objects; /** * Controls the application of {@link ViewConfigurationParams} for a virtual device. Loading @@ -56,6 +59,7 @@ public class ViewConfigurationController { "dimen/config_viewMaxFlingVelocity"; private static final String SCROLL_FRICTION_RESOURCE_NAME = "dimen/config_scrollFriction"; private final Context mContext; private final OverlayManager mOverlayManager; private final Object mLock = new Object(); Loading @@ -63,6 +67,7 @@ public class ViewConfigurationController { private OverlayIdentifier mOverlayIdentifier = null; public ViewConfigurationController(@NonNull Context context) { mContext = Objects.requireNonNull(context); mOverlayManager = context.getSystemService(OverlayManager.class); } Loading @@ -75,26 +80,53 @@ public class ViewConfigurationController { return; } applyResourceOverlays(deviceId, viewConfigurationParams); applySettings(deviceId, viewConfigurationParams); } /** * Clears the applied {@link ViewConfigurationParams}. */ public void close() { OverlayManagerTransaction transaction; synchronized (mLock) { if (mOverlayIdentifier == null) { return; } transaction = new OverlayManagerTransaction.Builder().unregisterFabricatedOverlay( mOverlayIdentifier).build(); } Binder.withCleanCallingIdentity(() -> mOverlayManager.commit(transaction)); } private void applyResourceOverlays(int deviceId, @NonNull ViewConfigurationParams viewConfigurationParams) { FabricatedOverlay overlay = new FabricatedOverlay.Builder( FRAMEWORK_PACKAGE_NAME /* owningPackage */, "vdOverlay" + deviceId /* overlayName */, FRAMEWORK_PACKAGE_NAME /* targetPackage */) .build(); OverlayIdentifier overlayIdentifier = overlay.getIdentifier(); setResourceDpValue(overlay, TOUCH_SLOP_RESOURCE_NAME, boolean change = false; change |= setResourceDpValue(overlay, TOUCH_SLOP_RESOURCE_NAME, viewConfigurationParams.getTouchSlopDp()); setResourceDpValue(overlay, MIN_FLING_VELOCITY_RESOURCE_NAME, change |= setResourceDpValue(overlay, MIN_FLING_VELOCITY_RESOURCE_NAME, viewConfigurationParams.getMinimumFlingVelocityDpPerSecond()); setResourceDpValue(overlay, MAX_FLING_VELOCITY_RESOURCE_NAME, change |= setResourceDpValue(overlay, MAX_FLING_VELOCITY_RESOURCE_NAME, viewConfigurationParams.getMaximumFlingVelocityDpPerSecond()); setResourceFloatValue(overlay, SCROLL_FRICTION_RESOURCE_NAME, change |= setResourceFloatValue(overlay, SCROLL_FRICTION_RESOURCE_NAME, viewConfigurationParams.getScrollFriction()); setResourceIntValue(overlay, TAP_TIMEOUT_RESOURCE_NAME, change |= setResourceIntValue(overlay, TAP_TIMEOUT_RESOURCE_NAME, (int) viewConfigurationParams.getTapTimeoutDuration().toMillis()); setResourceIntValue(overlay, DOUBLE_TAP_TIMEOUT_RESOURCE_NAME, change |= setResourceIntValue(overlay, DOUBLE_TAP_TIMEOUT_RESOURCE_NAME, (int) viewConfigurationParams.getDoubleTapTimeoutDuration().toMillis()); setResourceIntValue(overlay, DOUBLE_TAP_MIN_TIME_RESOURCE_NAME, change |= setResourceIntValue(overlay, DOUBLE_TAP_MIN_TIME_RESOURCE_NAME, (int) viewConfigurationParams.getDoubleTapMinTimeDuration().toMillis()); if (!change) { return; } int callingUserId = Binder.getCallingUserHandle().getIdentifier(); Binder.withCleanCallingIdentity(() -> { Loading @@ -111,59 +143,75 @@ public class ViewConfigurationController { }); } /** * Clears the applied {@link ViewConfigurationParams}. */ public void close() { OverlayManagerTransaction transaction; synchronized (mLock) { if (mOverlayIdentifier == null) { private void applySettings(int deviceId, @NonNull ViewConfigurationParams viewConfigurationParams) { int longPressTimeout = (int) viewConfigurationParams.getLongPressTimeoutDuration().toMillis(); int multiPressTimeout = (int) viewConfigurationParams.getMultiPressTimeoutDuration().toMillis(); boolean isLongPressTimeoutInvalid = isInvalid(longPressTimeout); boolean isMultiPressTimeoutInvalid = isInvalid(multiPressTimeout); if (isLongPressTimeoutInvalid && isMultiPressTimeoutInvalid) { return; } transaction = new OverlayManagerTransaction.Builder().unregisterFabricatedOverlay( mOverlayIdentifier).build(); Context deviceContext = mContext.createDeviceContext(deviceId); ContentResolver contentResolver = deviceContext.getContentResolver(); Binder.withCleanCallingIdentity(() -> { if (!isLongPressTimeoutInvalid) { Settings.Secure.putInt(contentResolver, Settings.Secure.LONG_PRESS_TIMEOUT, longPressTimeout); } Binder.withCleanCallingIdentity(() -> mOverlayManager.commit(transaction)); if (!isMultiPressTimeoutInvalid) { Settings.Secure.putInt(contentResolver, Settings.Secure.MULTI_PRESS_TIMEOUT, multiPressTimeout); } }); } private static void setResourceDpValue(@NonNull FabricatedOverlay overlay, private static boolean setResourceDpValue(@NonNull FabricatedOverlay overlay, @NonNull String resourceName, float value) { if (value == ViewConfigurationParams.INVALID_VALUE) { return; if (isInvalid(value)) { return false; } if (!android.content.res.Flags.dimensionFrro()) { Slog.e(TAG, "Dimension resource overlay is not supported"); return; return false; } overlay.setResourceValue(resourceName, value, TypedValue.COMPLEX_UNIT_DIP, null /* configuration */); return true; } private static void setResourceFloatValue(@NonNull FabricatedOverlay overlay, private static boolean setResourceFloatValue(@NonNull FabricatedOverlay overlay, @NonNull String resourceName, float value) { if (value == ViewConfigurationParams.INVALID_VALUE) { return; if (isInvalid(value)) { return false; } if (!android.content.res.Flags.dimensionFrro()) { Slog.e(TAG, "Dimension resource overlay is not supported"); return; return false; } overlay.setResourceValue(resourceName, value, null /* configuration */); return true; } private static void setResourceIntValue(@NonNull FabricatedOverlay overlay, private static boolean setResourceIntValue(@NonNull FabricatedOverlay overlay, @NonNull String resourceName, int value) { if (value == ViewConfigurationParams.INVALID_VALUE) { return; if (isInvalid(value)) { return false; } overlay.setResourceValue(resourceName, TypedValue.TYPE_INT_DEC, value, null /* configuration */); return true; } private static boolean isInvalid(float value) { return value == ViewConfigurationParams.INVALID_VALUE; } } services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java +8 −4 Original line number Diff line number Diff line Loading @@ -49,6 +49,7 @@ import android.companion.virtual.IVirtualDevice; import android.companion.virtual.IVirtualDeviceActivityListener; import android.companion.virtual.IVirtualDeviceIntentInterceptor; import android.companion.virtual.IVirtualDeviceSoundEffectListener; import android.companion.virtual.ViewConfigurationParams; import android.companion.virtual.VirtualDevice; import android.companion.virtual.VirtualDeviceManager; import android.companion.virtual.VirtualDeviceParams; Loading Loading @@ -490,10 +491,6 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub } mVirtualCameraController = virtualCameraController; mViewConfigurationController = viewConfigurationController; if (mViewConfigurationController != null) { mViewConfigurationController.applyViewConfigurationParams(deviceId, params.getViewConfigurationParams()); } try { token.linkToDeath(this, 0); } catch (RemoteException e) { Loading Loading @@ -532,6 +529,13 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub } } void applyViewConfigurationParams(@Nullable ViewConfigurationParams viewConfigurationParams) { if (mViewConfigurationController != null) { mViewConfigurationController.applyViewConfigurationParams(mDeviceId, viewConfigurationParams); } } @VisibleForTesting SensorController getSensorControllerForTest() { return mSensorController; Loading services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java +5 −0 Original line number Diff line number Diff line Loading @@ -41,6 +41,7 @@ import android.companion.virtual.VirtualDevice; import android.companion.virtual.VirtualDeviceManager; import android.companion.virtual.VirtualDeviceParams; import android.companion.virtual.sensor.VirtualSensor; import android.companion.virtualdevice.flags.Flags; import android.companion.virtualnative.IVirtualDeviceManagerNative; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledAfter; Loading Loading @@ -494,6 +495,10 @@ public class VirtualDeviceManagerService extends SystemService { mVirtualDevices.put(deviceId, virtualDevice); } if (Flags.viewconfigurationApis()) { virtualDevice.applyViewConfigurationParams(params.getViewConfigurationParams()); } mVirtualDeviceListeners.broadcast(listener -> { try { listener.onVirtualDeviceCreated(deviceId); Loading Loading
core/api/system-current.txt +4 −0 Original line number Diff line number Diff line Loading @@ -3450,8 +3450,10 @@ package android.companion.virtual { method public int describeContents(); method @NonNull public java.time.Duration getDoubleTapMinTimeDuration(); method @NonNull public java.time.Duration getDoubleTapTimeoutDuration(); method @NonNull public java.time.Duration getLongPressTimeoutDuration(); method @FloatRange(from=0) public float getMaximumFlingVelocityDpPerSecond(); method @FloatRange(from=0) public float getMinimumFlingVelocityDpPerSecond(); method @NonNull public java.time.Duration getMultiPressTimeoutDuration(); method @FloatRange(from=0) public float getScrollFriction(); method @NonNull public java.time.Duration getTapTimeoutDuration(); method @FloatRange(from=0) public float getTouchSlopDp(); Loading @@ -3464,8 +3466,10 @@ package android.companion.virtual { method @NonNull public android.companion.virtual.ViewConfigurationParams build(); method @NonNull public android.companion.virtual.ViewConfigurationParams.Builder setDoubleTapMinTimeDuration(@NonNull java.time.Duration); method @NonNull public android.companion.virtual.ViewConfigurationParams.Builder setDoubleTapTimeoutDuration(@NonNull java.time.Duration); method @NonNull public android.companion.virtual.ViewConfigurationParams.Builder setLongPressTimeoutDuration(@NonNull java.time.Duration); method @NonNull public android.companion.virtual.ViewConfigurationParams.Builder setMaximumFlingVelocityDpPerSecond(@FloatRange(from=0) float); method @NonNull public android.companion.virtual.ViewConfigurationParams.Builder setMinimumFlingVelocityDpPerSecond(@FloatRange(from=0) float); method @NonNull public android.companion.virtual.ViewConfigurationParams.Builder setMultiPressTimeoutDuration(@NonNull java.time.Duration); method @NonNull public android.companion.virtual.ViewConfigurationParams.Builder setScrollFriction(@FloatRange(from=0) float); method @NonNull public android.companion.virtual.ViewConfigurationParams.Builder setTapTimeoutDuration(@NonNull java.time.Duration); method @NonNull public android.companion.virtual.ViewConfigurationParams.Builder setTouchSlopDp(@FloatRange(from=0) float);
core/java/android/companion/virtual/ViewConfigurationParams.java +82 −5 Original line number Diff line number Diff line Loading @@ -51,10 +51,13 @@ public final class ViewConfigurationParams implements Parcelable { private final int mTapTimeoutMillis; private final int mDoubleTapTimeoutMillis; private final int mDoubleTapMinTimeMillis; private final int mLongPressTimeoutMillis; private final int mMultiPressTimeoutMillis; private ViewConfigurationParams(float touchSlopDp, float minimumFlingVelocityDpPerSecond, float maximumFlingVelocityDpPerSecond, float scrollFriction, int tapTimeoutMillis, int doubleTapTimeoutMillis, int doubleTapMinTimeMillis) { int doubleTapTimeoutMillis, int doubleTapMinTimeMillis, int longPressTimeoutMillis, int multiPressTimeoutMillis) { mTouchSlopDp = touchSlopDp; mMinimumFlingVelocityDpPerSecond = minimumFlingVelocityDpPerSecond; mMaximumFlingVelocityDpPerSecond = maximumFlingVelocityDpPerSecond; Loading @@ -62,6 +65,8 @@ public final class ViewConfigurationParams implements Parcelable { mTapTimeoutMillis = tapTimeoutMillis; mDoubleTapTimeoutMillis = doubleTapTimeoutMillis; mDoubleTapMinTimeMillis = doubleTapMinTimeMillis; mLongPressTimeoutMillis = longPressTimeoutMillis; mMultiPressTimeoutMillis = multiPressTimeoutMillis; } private ViewConfigurationParams(Parcel in) { Loading @@ -72,6 +77,8 @@ public final class ViewConfigurationParams implements Parcelable { mTapTimeoutMillis = in.readInt(); mDoubleTapTimeoutMillis = in.readInt(); mDoubleTapMinTimeMillis = in.readInt(); mLongPressTimeoutMillis = in.readInt(); mMultiPressTimeoutMillis = in.readInt(); } @Override Loading @@ -88,6 +95,8 @@ public final class ViewConfigurationParams implements Parcelable { dest.writeInt(mTapTimeoutMillis); dest.writeInt(mDoubleTapTimeoutMillis); dest.writeInt(mDoubleTapMinTimeMillis); dest.writeInt(mLongPressTimeoutMillis); dest.writeInt(mMultiPressTimeoutMillis); } @Override Loading @@ -102,14 +111,17 @@ public final class ViewConfigurationParams implements Parcelable { && Float.compare(mScrollFriction, that.mScrollFriction) == 0 && mTapTimeoutMillis == that.mTapTimeoutMillis && mDoubleTapTimeoutMillis == that.mDoubleTapTimeoutMillis && mDoubleTapMinTimeMillis == that.mDoubleTapMinTimeMillis; && mDoubleTapMinTimeMillis == that.mDoubleTapMinTimeMillis && mLongPressTimeoutMillis == that.mLongPressTimeoutMillis && mMultiPressTimeoutMillis == that.mMultiPressTimeoutMillis; } @Override public int hashCode() { return Objects.hash(mTouchSlopDp, mMinimumFlingVelocityDpPerSecond, mMaximumFlingVelocityDpPerSecond, mScrollFriction, mTapTimeoutMillis, mDoubleTapTimeoutMillis, mDoubleTapMinTimeMillis); mDoubleTapTimeoutMillis, mDoubleTapMinTimeMillis, mLongPressTimeoutMillis, mMultiPressTimeoutMillis); } @Override Loading @@ -123,6 +135,8 @@ public final class ViewConfigurationParams implements Parcelable { + ", mTapTimeoutMillis=" + mTapTimeoutMillis + ", mDoubleTapTimeoutMillis=" + mDoubleTapTimeoutMillis + ", mDoubleTapMinTimeMillis=" + mDoubleTapMinTimeMillis + ", mLongPressTimeoutMillis=" + mLongPressTimeoutMillis + ", mMultiPressTimeoutMillis=" + mMultiPressTimeoutMillis + ')'; } Loading Loading @@ -194,6 +208,22 @@ public final class ViewConfigurationParams implements Parcelable { return Duration.ofMillis(mDoubleTapMinTimeMillis); } /** * Returns a {@link Duration} representing the long press timeout. */ @NonNull public Duration getLongPressTimeoutDuration() { return Duration.ofMillis(mLongPressTimeoutMillis); } /** * Returns a {@link Duration} representing the multi press timeout. */ @NonNull public Duration getMultiPressTimeoutDuration() { return Duration.ofMillis(mMultiPressTimeoutMillis); } @NonNull public static final Creator<ViewConfigurationParams> CREATOR = new Creator<>() { Loading Loading @@ -221,6 +251,8 @@ public final class ViewConfigurationParams implements Parcelable { private int mTapTimeoutMillis = INVALID_VALUE; private int mDoubleTapTimeoutMillis = INVALID_VALUE; private int mDoubleTapMinTimeMillis = INVALID_VALUE; private int mLongPressTimeoutMillis = INVALID_VALUE; private int mMultiPressTimeoutMillis = INVALID_VALUE; /** * Sets the touch slop in density independent pixels (dp). When this is set, Loading Loading @@ -357,6 +389,48 @@ public final class ViewConfigurationParams implements Parcelable { return this; } /** * Sets the long press timeout as {@link Duration}. * * @throws IllegalArgumentException if the corresponding milliseconds value is negative, or * greater than {@link Integer#MAX_VALUE}. */ @NonNull public Builder setLongPressTimeoutDuration(@NonNull Duration duration) { Objects.requireNonNull(duration); if (duration.isNegative()) { throw new IllegalArgumentException("Long press timeout cannot be negative"); } long millis = duration.toMillis(); if (millis > Integer.MAX_VALUE) { throw new IllegalArgumentException( "Long press timeout cannot be larger than " + Integer.MAX_VALUE); } mLongPressTimeoutMillis = (int) millis; return this; } /** * Sets the multi press timeout as {@link Duration}. * * @throws IllegalArgumentException if the corresponding milliseconds value is negative, or * greater than {@link Integer#MAX_VALUE}. */ @NonNull public Builder setMultiPressTimeoutDuration(@NonNull Duration duration) { Objects.requireNonNull(duration); if (duration.isNegative()) { throw new IllegalArgumentException("Multi press timeout cannot be negative"); } long millis = duration.toMillis(); if (millis > Integer.MAX_VALUE) { throw new IllegalArgumentException( "Multi press timeout cannot be larger than " + Integer.MAX_VALUE); } mMultiPressTimeoutMillis = (int) millis; return this; } /** * Builds the {@link ViewConfigurationParams} instance. * Loading @@ -371,7 +445,9 @@ public final class ViewConfigurationParams implements Parcelable { && mScrollFriction == INVALID_VALUE && mTapTimeoutMillis == INVALID_VALUE && mDoubleTapTimeoutMillis == INVALID_VALUE && mDoubleTapMinTimeMillis == INVALID_VALUE) { && mDoubleTapMinTimeMillis == INVALID_VALUE && mLongPressTimeoutMillis == INVALID_VALUE && mMultiPressTimeoutMillis == INVALID_VALUE) { throw new IllegalArgumentException("None of the parameters are set"); } if (mMinimumFlingVelocityDpPerSecond != INVALID_VALUE Loading @@ -382,7 +458,8 @@ public final class ViewConfigurationParams implements Parcelable { } return new ViewConfigurationParams(mTouchSlopDp, mMinimumFlingVelocityDpPerSecond, mMaximumFlingVelocityDpPerSecond, mScrollFriction, mTapTimeoutMillis, mDoubleTapTimeoutMillis, mDoubleTapMinTimeMillis); mDoubleTapTimeoutMillis, mDoubleTapMinTimeMillis, mLongPressTimeoutMillis, mMultiPressTimeoutMillis); } } }
services/companion/java/com/android/server/companion/virtual/ViewConfigurationController.java +79 −31 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.server.companion.virtual; import android.annotation.NonNull; import android.annotation.Nullable; import android.companion.virtual.ViewConfigurationParams; import android.content.ContentResolver; import android.content.Context; import android.content.om.FabricatedOverlay; import android.content.om.OverlayConstraint; Loading @@ -26,6 +27,7 @@ import android.content.om.OverlayIdentifier; import android.content.om.OverlayManager; import android.content.om.OverlayManagerTransaction; import android.os.Binder; import android.provider.Settings; import android.util.Slog; import android.util.TypedValue; Loading @@ -33,6 +35,7 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import java.util.List; import java.util.Objects; /** * Controls the application of {@link ViewConfigurationParams} for a virtual device. Loading @@ -56,6 +59,7 @@ public class ViewConfigurationController { "dimen/config_viewMaxFlingVelocity"; private static final String SCROLL_FRICTION_RESOURCE_NAME = "dimen/config_scrollFriction"; private final Context mContext; private final OverlayManager mOverlayManager; private final Object mLock = new Object(); Loading @@ -63,6 +67,7 @@ public class ViewConfigurationController { private OverlayIdentifier mOverlayIdentifier = null; public ViewConfigurationController(@NonNull Context context) { mContext = Objects.requireNonNull(context); mOverlayManager = context.getSystemService(OverlayManager.class); } Loading @@ -75,26 +80,53 @@ public class ViewConfigurationController { return; } applyResourceOverlays(deviceId, viewConfigurationParams); applySettings(deviceId, viewConfigurationParams); } /** * Clears the applied {@link ViewConfigurationParams}. */ public void close() { OverlayManagerTransaction transaction; synchronized (mLock) { if (mOverlayIdentifier == null) { return; } transaction = new OverlayManagerTransaction.Builder().unregisterFabricatedOverlay( mOverlayIdentifier).build(); } Binder.withCleanCallingIdentity(() -> mOverlayManager.commit(transaction)); } private void applyResourceOverlays(int deviceId, @NonNull ViewConfigurationParams viewConfigurationParams) { FabricatedOverlay overlay = new FabricatedOverlay.Builder( FRAMEWORK_PACKAGE_NAME /* owningPackage */, "vdOverlay" + deviceId /* overlayName */, FRAMEWORK_PACKAGE_NAME /* targetPackage */) .build(); OverlayIdentifier overlayIdentifier = overlay.getIdentifier(); setResourceDpValue(overlay, TOUCH_SLOP_RESOURCE_NAME, boolean change = false; change |= setResourceDpValue(overlay, TOUCH_SLOP_RESOURCE_NAME, viewConfigurationParams.getTouchSlopDp()); setResourceDpValue(overlay, MIN_FLING_VELOCITY_RESOURCE_NAME, change |= setResourceDpValue(overlay, MIN_FLING_VELOCITY_RESOURCE_NAME, viewConfigurationParams.getMinimumFlingVelocityDpPerSecond()); setResourceDpValue(overlay, MAX_FLING_VELOCITY_RESOURCE_NAME, change |= setResourceDpValue(overlay, MAX_FLING_VELOCITY_RESOURCE_NAME, viewConfigurationParams.getMaximumFlingVelocityDpPerSecond()); setResourceFloatValue(overlay, SCROLL_FRICTION_RESOURCE_NAME, change |= setResourceFloatValue(overlay, SCROLL_FRICTION_RESOURCE_NAME, viewConfigurationParams.getScrollFriction()); setResourceIntValue(overlay, TAP_TIMEOUT_RESOURCE_NAME, change |= setResourceIntValue(overlay, TAP_TIMEOUT_RESOURCE_NAME, (int) viewConfigurationParams.getTapTimeoutDuration().toMillis()); setResourceIntValue(overlay, DOUBLE_TAP_TIMEOUT_RESOURCE_NAME, change |= setResourceIntValue(overlay, DOUBLE_TAP_TIMEOUT_RESOURCE_NAME, (int) viewConfigurationParams.getDoubleTapTimeoutDuration().toMillis()); setResourceIntValue(overlay, DOUBLE_TAP_MIN_TIME_RESOURCE_NAME, change |= setResourceIntValue(overlay, DOUBLE_TAP_MIN_TIME_RESOURCE_NAME, (int) viewConfigurationParams.getDoubleTapMinTimeDuration().toMillis()); if (!change) { return; } int callingUserId = Binder.getCallingUserHandle().getIdentifier(); Binder.withCleanCallingIdentity(() -> { Loading @@ -111,59 +143,75 @@ public class ViewConfigurationController { }); } /** * Clears the applied {@link ViewConfigurationParams}. */ public void close() { OverlayManagerTransaction transaction; synchronized (mLock) { if (mOverlayIdentifier == null) { private void applySettings(int deviceId, @NonNull ViewConfigurationParams viewConfigurationParams) { int longPressTimeout = (int) viewConfigurationParams.getLongPressTimeoutDuration().toMillis(); int multiPressTimeout = (int) viewConfigurationParams.getMultiPressTimeoutDuration().toMillis(); boolean isLongPressTimeoutInvalid = isInvalid(longPressTimeout); boolean isMultiPressTimeoutInvalid = isInvalid(multiPressTimeout); if (isLongPressTimeoutInvalid && isMultiPressTimeoutInvalid) { return; } transaction = new OverlayManagerTransaction.Builder().unregisterFabricatedOverlay( mOverlayIdentifier).build(); Context deviceContext = mContext.createDeviceContext(deviceId); ContentResolver contentResolver = deviceContext.getContentResolver(); Binder.withCleanCallingIdentity(() -> { if (!isLongPressTimeoutInvalid) { Settings.Secure.putInt(contentResolver, Settings.Secure.LONG_PRESS_TIMEOUT, longPressTimeout); } Binder.withCleanCallingIdentity(() -> mOverlayManager.commit(transaction)); if (!isMultiPressTimeoutInvalid) { Settings.Secure.putInt(contentResolver, Settings.Secure.MULTI_PRESS_TIMEOUT, multiPressTimeout); } }); } private static void setResourceDpValue(@NonNull FabricatedOverlay overlay, private static boolean setResourceDpValue(@NonNull FabricatedOverlay overlay, @NonNull String resourceName, float value) { if (value == ViewConfigurationParams.INVALID_VALUE) { return; if (isInvalid(value)) { return false; } if (!android.content.res.Flags.dimensionFrro()) { Slog.e(TAG, "Dimension resource overlay is not supported"); return; return false; } overlay.setResourceValue(resourceName, value, TypedValue.COMPLEX_UNIT_DIP, null /* configuration */); return true; } private static void setResourceFloatValue(@NonNull FabricatedOverlay overlay, private static boolean setResourceFloatValue(@NonNull FabricatedOverlay overlay, @NonNull String resourceName, float value) { if (value == ViewConfigurationParams.INVALID_VALUE) { return; if (isInvalid(value)) { return false; } if (!android.content.res.Flags.dimensionFrro()) { Slog.e(TAG, "Dimension resource overlay is not supported"); return; return false; } overlay.setResourceValue(resourceName, value, null /* configuration */); return true; } private static void setResourceIntValue(@NonNull FabricatedOverlay overlay, private static boolean setResourceIntValue(@NonNull FabricatedOverlay overlay, @NonNull String resourceName, int value) { if (value == ViewConfigurationParams.INVALID_VALUE) { return; if (isInvalid(value)) { return false; } overlay.setResourceValue(resourceName, TypedValue.TYPE_INT_DEC, value, null /* configuration */); return true; } private static boolean isInvalid(float value) { return value == ViewConfigurationParams.INVALID_VALUE; } }
services/companion/java/com/android/server/companion/virtual/VirtualDeviceImpl.java +8 −4 Original line number Diff line number Diff line Loading @@ -49,6 +49,7 @@ import android.companion.virtual.IVirtualDevice; import android.companion.virtual.IVirtualDeviceActivityListener; import android.companion.virtual.IVirtualDeviceIntentInterceptor; import android.companion.virtual.IVirtualDeviceSoundEffectListener; import android.companion.virtual.ViewConfigurationParams; import android.companion.virtual.VirtualDevice; import android.companion.virtual.VirtualDeviceManager; import android.companion.virtual.VirtualDeviceParams; Loading Loading @@ -490,10 +491,6 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub } mVirtualCameraController = virtualCameraController; mViewConfigurationController = viewConfigurationController; if (mViewConfigurationController != null) { mViewConfigurationController.applyViewConfigurationParams(deviceId, params.getViewConfigurationParams()); } try { token.linkToDeath(this, 0); } catch (RemoteException e) { Loading Loading @@ -532,6 +529,13 @@ final class VirtualDeviceImpl extends IVirtualDevice.Stub } } void applyViewConfigurationParams(@Nullable ViewConfigurationParams viewConfigurationParams) { if (mViewConfigurationController != null) { mViewConfigurationController.applyViewConfigurationParams(mDeviceId, viewConfigurationParams); } } @VisibleForTesting SensorController getSensorControllerForTest() { return mSensorController; Loading
services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java +5 −0 Original line number Diff line number Diff line Loading @@ -41,6 +41,7 @@ import android.companion.virtual.VirtualDevice; import android.companion.virtual.VirtualDeviceManager; import android.companion.virtual.VirtualDeviceParams; import android.companion.virtual.sensor.VirtualSensor; import android.companion.virtualdevice.flags.Flags; import android.companion.virtualnative.IVirtualDeviceManagerNative; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledAfter; Loading Loading @@ -494,6 +495,10 @@ public class VirtualDeviceManagerService extends SystemService { mVirtualDevices.put(deviceId, virtualDevice); } if (Flags.viewconfigurationApis()) { virtualDevice.applyViewConfigurationParams(params.getViewConfigurationParams()); } mVirtualDeviceListeners.broadcast(listener -> { try { listener.onVirtualDeviceCreated(deviceId); Loading