/*
 * Copyright 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 com.android.server.policy;

import static android.os.IInputConstants.INVALID_INPUT_DEVICE_ID;
import static android.view.Display.INVALID_DISPLAY;

import android.annotation.IntDef;
import android.os.SystemClock;

import com.android.internal.util.DataClass;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
 * Single gesture event that describes the gesture that was started, completed or cancelled.
 *
 * Currently supported single key gestures are: long press, very long press and multi-press
 * (include single press gestures).
 *
 * <p>
 * Long press, Very long press gestures: Start event is sent on first key down of the
 * relevant key. Complete event is sent if the long press or very long press was successfully
 * detected. Cancel event is sent when due to some reason (some other key pressed, key not
 * pressed for long enough time, etc.), the gesture was cancelled.
 *
 * <p>
 * n-press gestures: Start event is usually sent on nth key up. For the nth press where n
 * is the max press count, we directly send a complete event on nth key down event. Complete
 * event is sent when n-th press was successfully detected. Cancel event is sent when the
 * gesture is cancelled (due to some other key press) or (n+1)th key down occurred.
 *
 * <p>
 * Example: Power key rule registered with max press count = 3 and very long press support.
 * Following are the gestures that are generated:
 * First key down: Long press (START), Very long press (START)
 * First key up (before timeout): Long press (CANCEL), Very long press (CANCEL), 1-press (START)
 * Second key down (before multi-press timeout): 1-press (CANCEL)
 * Second key up: 2-press (START)
 * After multi-press timeout: 2-press (COMPLETE)
 */
@DataClass(
        genBuilder = true,
        genEqualsHashCode = true,
        genToString = true
)
final class SingleKeyGestureEvent {
    public static final int SINGLE_KEY_GESTURE_TYPE_PRESS = 0;
    public static final int SINGLE_KEY_GESTURE_TYPE_LONG_PRESS = 1;
    public static final int SINGLE_KEY_GESTURE_TYPE_VERY_LONG_PRESS = 2;
    public static final int ACTION_START = 0;
    public static final int ACTION_COMPLETE = 1;
    public static final int ACTION_CANCEL = 2;

    /**
     * The key used for the gesture.
     */
    private final int mKeyCode;

    /**
     * The gesture type (long press, very long press, single press or multi press)
     */
    @SingleKeyGestureType
    private final int mType;

    /**
     * The gesture action (start, complete, cancel)
     *
     * <p>
     * Start events are sent when a gesture was started. For long press and very long press, it is
     * when the first key down event occurred. For n-press, it is usually sent when nth up
     * occurred.
     *
     * <p>
     * Complete events are sent when the gesture was correctly detected and there is no other
     * possible gesture.
     *
     * <p>
     * NOTE: All gestures that were started, either are completed or cancelled.
     */
    @Action
    private final int mAction;

    /**
     * Start time for the gesture
     */
    private long mStartTime = SystemClock.uptimeMillis();

    /**
     * Gesture event time
     */
    private long mEventTime = SystemClock.uptimeMillis();

    /**
     * Represent number of presses involved in this gesture when gesture type is "press"
     */
    private int mPressCount = 0;

    /**
     * Display id for the key gesture
     */
    private int mDisplayId = INVALID_DISPLAY;

    /**
     * Device id for the device that produced the key gesture
     */
    private int mDeviceId = INVALID_INPUT_DEVICE_ID;



    // Code below generated by codegen v1.0.23.
    //
    // DO NOT MODIFY!
    // CHECKSTYLE:OFF Generated code
    //
    // To regenerate run:
    // $ codegen $ANDROID_BUILD_TOP/frameworks/base/services/core/java/com/android/server/policy/SingleKeyGestureEvent.java
    //
    // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
    //   Settings > Editor > Code Style > Formatter Control
    //@formatter:off


    @IntDef(prefix = "SINGLE_KEY_GESTURE_TYPE_", value = {
        SINGLE_KEY_GESTURE_TYPE_PRESS,
        SINGLE_KEY_GESTURE_TYPE_LONG_PRESS,
        SINGLE_KEY_GESTURE_TYPE_VERY_LONG_PRESS
    })
    @Retention(RetentionPolicy.SOURCE)
    @DataClass.Generated.Member
    public @interface SingleKeyGestureType {}

    @DataClass.Generated.Member
    public static String singleKeyGestureTypeToString(@SingleKeyGestureType int value) {
        switch (value) {
            case SINGLE_KEY_GESTURE_TYPE_PRESS:
                    return "SINGLE_KEY_GESTURE_TYPE_PRESS";
            case SINGLE_KEY_GESTURE_TYPE_LONG_PRESS:
                    return "SINGLE_KEY_GESTURE_TYPE_LONG_PRESS";
            case SINGLE_KEY_GESTURE_TYPE_VERY_LONG_PRESS:
                    return "SINGLE_KEY_GESTURE_TYPE_VERY_LONG_PRESS";
            default: return Integer.toHexString(value);
        }
    }

    @IntDef(prefix = "ACTION_", value = {
        ACTION_START,
        ACTION_COMPLETE,
        ACTION_CANCEL
    })
    @Retention(RetentionPolicy.SOURCE)
    @DataClass.Generated.Member
    public @interface Action {}

    @DataClass.Generated.Member
    public static String actionToString(@Action int value) {
        switch (value) {
            case ACTION_START:
                    return "ACTION_START";
            case ACTION_COMPLETE:
                    return "ACTION_COMPLETE";
            case ACTION_CANCEL:
                    return "ACTION_CANCEL";
            default: return Integer.toHexString(value);
        }
    }

    @DataClass.Generated.Member
    /* package-private */ SingleKeyGestureEvent(
            int keyCode,
            @SingleKeyGestureType int type,
            @Action int action,
            long startTime,
            long eventTime,
            int pressCount,
            int displayId,
            int deviceId) {
        this.mKeyCode = keyCode;
        this.mType = type;

        if (!(mType == SINGLE_KEY_GESTURE_TYPE_PRESS)
                && !(mType == SINGLE_KEY_GESTURE_TYPE_LONG_PRESS)
                && !(mType == SINGLE_KEY_GESTURE_TYPE_VERY_LONG_PRESS)) {
            throw new java.lang.IllegalArgumentException(
                    "type was " + mType + " but must be one of: "
                            + "SINGLE_KEY_GESTURE_TYPE_PRESS(" + SINGLE_KEY_GESTURE_TYPE_PRESS + "), "
                            + "SINGLE_KEY_GESTURE_TYPE_LONG_PRESS(" + SINGLE_KEY_GESTURE_TYPE_LONG_PRESS + "), "
                            + "SINGLE_KEY_GESTURE_TYPE_VERY_LONG_PRESS(" + SINGLE_KEY_GESTURE_TYPE_VERY_LONG_PRESS + ")");
        }

        this.mAction = action;

        if (!(mAction == ACTION_START)
                && !(mAction == ACTION_COMPLETE)
                && !(mAction == ACTION_CANCEL)) {
            throw new java.lang.IllegalArgumentException(
                    "action was " + mAction + " but must be one of: "
                            + "ACTION_START(" + ACTION_START + "), "
                            + "ACTION_COMPLETE(" + ACTION_COMPLETE + "), "
                            + "ACTION_CANCEL(" + ACTION_CANCEL + ")");
        }

        this.mStartTime = startTime;
        this.mEventTime = eventTime;
        this.mPressCount = pressCount;
        this.mDisplayId = displayId;
        this.mDeviceId = deviceId;

        // onConstructed(); // You can define this method to get a callback
    }

    /**
     * The key used for the gesture.
     */
    @DataClass.Generated.Member
    public int getKeyCode() {
        return mKeyCode;
    }

    /**
     * The gesture type (long press, very long press, single press or multi press)
     */
    @DataClass.Generated.Member
    public @SingleKeyGestureType int getType() {
        return mType;
    }

    /**
     * The gesture action (start, complete, cancel)
     *
     * <p>
     * Start events are sent when a gesture was started. For long press and very long press, it is
     * when the first key down event occurred. For n-press, it is usually sent when nth up
     * occurred.
     *
     * <p>
     * Complete events are sent when the gesture was correctly detected and there is no other
     * possible gesture.
     *
     * <p>
     * NOTE: All gestures that were started, either are completed or cancelled.
     */
    @DataClass.Generated.Member
    public @Action int getAction() {
        return mAction;
    }

    /**
     * Start time for the gesture
     */
    @DataClass.Generated.Member
    public long getStartTime() {
        return mStartTime;
    }

    /**
     * Gesture event time
     */
    @DataClass.Generated.Member
    public long getEventTime() {
        return mEventTime;
    }

    /**
     * Represent number of presses involved in this gesture when gesture type is "press"
     */
    @DataClass.Generated.Member
    public int getPressCount() {
        return mPressCount;
    }

    /**
     * Display id for the key gesture
     */
    @DataClass.Generated.Member
    public int getDisplayId() {
        return mDisplayId;
    }

    /**
     * Device id for the device that produced the key gesture
     */
    @DataClass.Generated.Member
    public int getDeviceId() {
        return mDeviceId;
    }

    @Override
    @DataClass.Generated.Member
    public String toString() {
        // You can override field toString logic by defining methods like:
        // String fieldNameToString() { ... }

        return "SingleKeyGestureEvent { " +
                "keyCode = " + mKeyCode + ", " +
                "type = " + singleKeyGestureTypeToString(mType) + ", " +
                "action = " + actionToString(mAction) + ", " +
                "startTime = " + mStartTime + ", " +
                "eventTime = " + mEventTime + ", " +
                "pressCount = " + mPressCount + ", " +
                "displayId = " + mDisplayId + ", " +
                "deviceId = " + mDeviceId +
        " }";
    }

    @Override
    @DataClass.Generated.Member
    public boolean equals(@android.annotation.Nullable Object o) {
        // You can override field equality logic by defining either of the methods like:
        // boolean fieldNameEquals(SingleKeyGestureEvent other) { ... }
        // boolean fieldNameEquals(FieldType otherValue) { ... }

        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        @SuppressWarnings("unchecked")
        SingleKeyGestureEvent that = (SingleKeyGestureEvent) o;
        //noinspection PointlessBooleanExpression
        return true
                && mKeyCode == that.mKeyCode
                && mType == that.mType
                && mAction == that.mAction
                && mStartTime == that.mStartTime
                && mEventTime == that.mEventTime
                && mPressCount == that.mPressCount
                && mDisplayId == that.mDisplayId
                && mDeviceId == that.mDeviceId;
    }

    @Override
    @DataClass.Generated.Member
    public int hashCode() {
        // You can override field hashCode logic by defining methods like:
        // int fieldNameHashCode() { ... }

        int _hash = 1;
        _hash = 31 * _hash + mKeyCode;
        _hash = 31 * _hash + mType;
        _hash = 31 * _hash + mAction;
        _hash = 31 * _hash + Long.hashCode(mStartTime);
        _hash = 31 * _hash + Long.hashCode(mEventTime);
        _hash = 31 * _hash + mPressCount;
        _hash = 31 * _hash + mDisplayId;
        _hash = 31 * _hash + mDeviceId;
        return _hash;
    }

    /**
     * A builder for {@link SingleKeyGestureEvent}
     */
    @SuppressWarnings("WeakerAccess")
    @DataClass.Generated.Member
    public static final class Builder {

        private int mKeyCode;
        private @SingleKeyGestureType int mType;
        private @Action int mAction;
        private long mStartTime;
        private long mEventTime;
        private int mPressCount;
        private int mDisplayId;
        private int mDeviceId;

        private long mBuilderFieldsSet = 0L;

        /**
         * Creates a new Builder.
         *
         * @param keyCode
         *   The key used for the gesture.
         * @param type
         *   The gesture type (long press, very long press, single press or multi press)
         * @param action
         *   The gesture action (start, complete, cancel)
         *
         *   <p>
         *   Start events are sent when a gesture was started. For long press and very long press, it is
         *   when the first key down event occurred. For n-press, it is usually sent when nth up
         *   occurred.
         *
         *   <p>
         *   Complete events are sent when the gesture was correctly detected and there is no other
         *   possible gesture.
         *
         *   <p>
         *   NOTE: All gestures that were started, either are completed or cancelled.
         */
        public Builder(
                int keyCode,
                @SingleKeyGestureType int type,
                @Action int action) {
            mKeyCode = keyCode;
            mType = type;

            if (!(mType == SINGLE_KEY_GESTURE_TYPE_PRESS)
                    && !(mType == SINGLE_KEY_GESTURE_TYPE_LONG_PRESS)
                    && !(mType == SINGLE_KEY_GESTURE_TYPE_VERY_LONG_PRESS)) {
                throw new java.lang.IllegalArgumentException(
                        "type was " + mType + " but must be one of: "
                                + "SINGLE_KEY_GESTURE_TYPE_PRESS(" + SINGLE_KEY_GESTURE_TYPE_PRESS + "), "
                                + "SINGLE_KEY_GESTURE_TYPE_LONG_PRESS(" + SINGLE_KEY_GESTURE_TYPE_LONG_PRESS + "), "
                                + "SINGLE_KEY_GESTURE_TYPE_VERY_LONG_PRESS(" + SINGLE_KEY_GESTURE_TYPE_VERY_LONG_PRESS + ")");
            }

            mAction = action;

            if (!(mAction == ACTION_START)
                    && !(mAction == ACTION_COMPLETE)
                    && !(mAction == ACTION_CANCEL)) {
                throw new java.lang.IllegalArgumentException(
                        "action was " + mAction + " but must be one of: "
                                + "ACTION_START(" + ACTION_START + "), "
                                + "ACTION_COMPLETE(" + ACTION_COMPLETE + "), "
                                + "ACTION_CANCEL(" + ACTION_CANCEL + ")");
            }

        }

        /**
         * The key used for the gesture.
         */
        @DataClass.Generated.Member
        public @android.annotation.NonNull Builder setKeyCode(int value) {
            checkNotUsed();
            mBuilderFieldsSet |= 0x1;
            mKeyCode = value;
            return this;
        }

        /**
         * The gesture type (long press, very long press, single press or multi press)
         */
        @DataClass.Generated.Member
        public @android.annotation.NonNull Builder setType(@SingleKeyGestureType int value) {
            checkNotUsed();
            mBuilderFieldsSet |= 0x2;
            mType = value;
            return this;
        }

        /**
         * The gesture action (start, complete, cancel)
         *
         * <p>
         * Start events are sent when a gesture was started. For long press and very long press, it is
         * when the first key down event occurred. For n-press, it is usually sent when nth up
         * occurred.
         *
         * <p>
         * Complete events are sent when the gesture was correctly detected and there is no other
         * possible gesture.
         *
         * <p>
         * NOTE: All gestures that were started, either are completed or cancelled.
         */
        @DataClass.Generated.Member
        public @android.annotation.NonNull Builder setAction(@Action int value) {
            checkNotUsed();
            mBuilderFieldsSet |= 0x4;
            mAction = value;
            return this;
        }

        /**
         * Start time for the gesture
         */
        @DataClass.Generated.Member
        public @android.annotation.NonNull Builder setStartTime(long value) {
            checkNotUsed();
            mBuilderFieldsSet |= 0x8;
            mStartTime = value;
            return this;
        }

        /**
         * Gesture event time
         */
        @DataClass.Generated.Member
        public @android.annotation.NonNull Builder setEventTime(long value) {
            checkNotUsed();
            mBuilderFieldsSet |= 0x10;
            mEventTime = value;
            return this;
        }

        /**
         * Represent number of presses involved in this gesture when gesture type is "press"
         */
        @DataClass.Generated.Member
        public @android.annotation.NonNull Builder setPressCount(int value) {
            checkNotUsed();
            mBuilderFieldsSet |= 0x20;
            mPressCount = value;
            return this;
        }

        /**
         * Display id for the key gesture
         */
        @DataClass.Generated.Member
        public @android.annotation.NonNull Builder setDisplayId(int value) {
            checkNotUsed();
            mBuilderFieldsSet |= 0x40;
            mDisplayId = value;
            return this;
        }

        /**
         * Device id for the device that produced the key gesture
         */
        @DataClass.Generated.Member
        public @android.annotation.NonNull Builder setDeviceId(int value) {
            checkNotUsed();
            mBuilderFieldsSet |= 0x80;
            mDeviceId = value;
            return this;
        }

        /** Builds the instance. This builder should not be touched after calling this! */
        public @android.annotation.NonNull SingleKeyGestureEvent build() {
            checkNotUsed();
            mBuilderFieldsSet |= 0x100; // Mark builder used

            if ((mBuilderFieldsSet & 0x8) == 0) {
                mStartTime = SystemClock.uptimeMillis();
            }
            if ((mBuilderFieldsSet & 0x10) == 0) {
                mEventTime = SystemClock.uptimeMillis();
            }
            if ((mBuilderFieldsSet & 0x20) == 0) {
                mPressCount = 0;
            }
            if ((mBuilderFieldsSet & 0x40) == 0) {
                mDisplayId = INVALID_DISPLAY;
            }
            if ((mBuilderFieldsSet & 0x80) == 0) {
                mDeviceId = INVALID_INPUT_DEVICE_ID;
            }
            SingleKeyGestureEvent o = new SingleKeyGestureEvent(
                    mKeyCode,
                    mType,
                    mAction,
                    mStartTime,
                    mEventTime,
                    mPressCount,
                    mDisplayId,
                    mDeviceId);
            return o;
        }

        private void checkNotUsed() {
            if ((mBuilderFieldsSet & 0x100) != 0) {
                throw new IllegalStateException(
                        "This Builder should not be reused. Use a new Builder instance instead");
            }
        }
    }

    @DataClass.Generated(
            time = 1747056679256L,
            codegenVersion = "1.0.23",
            sourceFile = "frameworks/base/services/core/java/com/android/server/policy/SingleKeyGestureEvent.java",
            inputSignatures = "public static final  int SINGLE_KEY_GESTURE_TYPE_PRESS\npublic static final  int SINGLE_KEY_GESTURE_TYPE_LONG_PRESS\npublic static final  int SINGLE_KEY_GESTURE_TYPE_VERY_LONG_PRESS\npublic static final  int ACTION_START\npublic static final  int ACTION_COMPLETE\npublic static final  int ACTION_CANCEL\nprivate final  int mKeyCode\nprivate final @com.android.server.policy.SingleKeyGestureEvent.SingleKeyGestureType int mType\nprivate final @com.android.server.policy.SingleKeyGestureEvent.Action int mAction\nprivate  long mStartTime\nprivate  long mEventTime\nprivate  int mPressCount\nprivate  int mDisplayId\nprivate  int mDeviceId\nclass SingleKeyGestureEvent extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genBuilder=true, genEqualsHashCode=true, genToString=true)")
    @Deprecated
    private void __metadata() {}


    //@formatter:on
    // End of generated code

}
