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

Commit d6a3c6ff authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Add APIs for long press and multi press timeouts" into main

parents c018324a 9130fe4d
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -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();
@@ -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);
+82 −5
Original line number Diff line number Diff line
@@ -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;
@@ -62,6 +65,8 @@ public final class ViewConfigurationParams implements Parcelable {
        mTapTimeoutMillis = tapTimeoutMillis;
        mDoubleTapTimeoutMillis = doubleTapTimeoutMillis;
        mDoubleTapMinTimeMillis = doubleTapMinTimeMillis;
        mLongPressTimeoutMillis = longPressTimeoutMillis;
        mMultiPressTimeoutMillis = multiPressTimeoutMillis;
    }

    private ViewConfigurationParams(Parcel in) {
@@ -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
@@ -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
@@ -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
@@ -123,6 +135,8 @@ public final class ViewConfigurationParams implements Parcelable {
                + ", mTapTimeoutMillis=" + mTapTimeoutMillis
                + ", mDoubleTapTimeoutMillis=" + mDoubleTapTimeoutMillis
                + ", mDoubleTapMinTimeMillis=" + mDoubleTapMinTimeMillis
                + ", mLongPressTimeoutMillis=" + mLongPressTimeoutMillis
                + ", mMultiPressTimeoutMillis=" + mMultiPressTimeoutMillis
                + ')';
    }

@@ -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<>() {
@@ -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,
@@ -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.
         *
@@ -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
@@ -382,7 +458,8 @@ public final class ViewConfigurationParams implements Parcelable {
            }
            return new ViewConfigurationParams(mTouchSlopDp, mMinimumFlingVelocityDpPerSecond,
                    mMaximumFlingVelocityDpPerSecond, mScrollFriction, mTapTimeoutMillis,
                    mDoubleTapTimeoutMillis, mDoubleTapMinTimeMillis);
                    mDoubleTapTimeoutMillis, mDoubleTapMinTimeMillis, mLongPressTimeoutMillis,
                    mMultiPressTimeoutMillis);
        }
    }
}
+79 −31
Original line number Diff line number Diff line
@@ -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;
@@ -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;

@@ -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.
@@ -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();

@@ -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);
    }

@@ -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(() -> {
@@ -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;
    }
}
+8 −4
Original line number Diff line number Diff line
@@ -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;
@@ -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) {
@@ -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;
+5 −0
Original line number Diff line number Diff line
@@ -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;
@@ -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