summaryrefslogtreecommitdiff
path: root/core/java/android/os/vibrator/VibrationEffectSegment.java
blob: be1055362f1c6b18a254b4b166363c5e1448691b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
/*
 * Copyright (C) 2021 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.os.vibrator;

import android.annotation.NonNull;
import android.annotation.TestApi;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.VibrationEffect;

/**
 * Representation of a single segment of a {@link VibrationEffect}.
 *
 * <p>Vibration effects are represented as a sequence of segments that describes how vibration
 * amplitude and frequency changes over time. Segments can be described as one of the following:
 *
 * <ol>
 *     <li>A predefined vibration effect;
 *     <li>A composable effect primitive;
 *     <li>Fixed amplitude and frequency values to be held for a specified duration;
 *     <li>Pairs of amplitude and frequency values to be ramped to for a specified duration;
 * </ol>
 *
 * @hide
 */
@TestApi
@SuppressWarnings({"ParcelNotFinal", "ParcelCreator"}) // Parcel only extended here.
public abstract class VibrationEffectSegment implements Parcelable {
    static final int PARCEL_TOKEN_PREBAKED = 1;
    static final int PARCEL_TOKEN_PRIMITIVE = 2;
    static final int PARCEL_TOKEN_STEP = 3;
    static final int PARCEL_TOKEN_RAMP = 4;

    /** Prevent subclassing from outside of this package */
    VibrationEffectSegment() {
    }

    /**
     * Gets the estimated duration of the segment in milliseconds.
     *
     * <p>For segments with an unknown duration (e.g. prebaked or primitive effects where the length
     * is device and potentially run-time dependent), this returns -1.
     */
    public abstract long getDuration();

    /**
     * Returns true if this segment could be a haptic feedback effect candidate.
     *
     * @see VibrationEffect#isHapticFeedbackCandidate()
     * @hide
     */
    public abstract boolean isHapticFeedbackCandidate();

    /**
     * Returns true if this segment plays at a non-zero amplitude at some point.
     *
     * @hide
     */
    public abstract boolean hasNonZeroAmplitude();

    /**
     * Validates the segment, throwing exceptions if any parameter is invalid.
     *
     * @hide
     */
    public abstract void validate();

    /**
     * Resolves amplitudes set to {@link VibrationEffect#DEFAULT_AMPLITUDE}.
     *
     * <p>This might fail with {@link IllegalArgumentException} if value is non-positive or larger
     * than {@link VibrationEffect#MAX_AMPLITUDE}.
     *
     * @hide
     */
    @NonNull
    public abstract <T extends VibrationEffectSegment> T resolve(int defaultAmplitude);

    /**
     * Scale the segment intensity with the given factor.
     *
     * @param scaleFactor scale factor to be applied to the intensity. Values within [0,1) will
     *                    scale down the intensity, values larger than 1 will scale up
     *
     * @hide
     */
    @NonNull
    public abstract <T extends VibrationEffectSegment> T scale(float scaleFactor);

    /**
     * Applies given effect strength to prebaked effects.
     *
     * @param effectStrength new effect strength to be applied, one of
     *                       VibrationEffect.EFFECT_STRENGTH_*.
     *
     * @hide
     */
    @NonNull
    public abstract <T extends VibrationEffectSegment> T applyEffectStrength(int effectStrength);

    /**
     * Checks the given frequency argument is valid to represent a vibration effect frequency in
     * hertz, i.e. a finite non-negative value.
     *
     * @param value the frequency argument value to be checked
     * @param name the argument name for the error message.
     *
     * @hide
     */
    public static void checkFrequencyArgument(float value, @NonNull String name) {
        // Similar to combining Preconditions checkArgumentFinite + checkArgumentNonnegative,
        // but this implementation doesn't create the error message unless a check fail.
        if (Float.isNaN(value)) {
            throw new IllegalArgumentException(name + " must not be NaN");
        }
        if (Float.isInfinite(value)) {
            throw new IllegalArgumentException(name + " must not be infinite");
        }
        if (value < 0) {
            throw new IllegalArgumentException(name + " must be >= 0, got " + value);
        }
    }

    /**
     * Checks the given duration argument is valid, i.e. a non-negative value.
     *
     * @param value the duration value to be checked
     * @param name the argument name for the error message.
     *
     * @hide
     */
    public static void checkDurationArgument(long value, @NonNull String name) {
        if (value < 0) {
            throw new IllegalArgumentException(name + " must be >= 0, got " + value);
        }
    }

    @NonNull
    public static final Creator<VibrationEffectSegment> CREATOR =
            new Creator<VibrationEffectSegment>() {
                @Override
                public VibrationEffectSegment createFromParcel(Parcel in) {
                    switch (in.readInt()) {
                        case PARCEL_TOKEN_STEP:
                            return new StepSegment(in);
                        case PARCEL_TOKEN_RAMP:
                            return new RampSegment(in);
                        case PARCEL_TOKEN_PREBAKED:
                            return new PrebakedSegment(in);
                        case PARCEL_TOKEN_PRIMITIVE:
                            return new PrimitiveSegment(in);
                        default:
                            throw new IllegalStateException(
                                    "Unexpected vibration event type token in parcel.");
                    }
                }

                @Override
                public VibrationEffectSegment[] newArray(int size) {
                    return new VibrationEffectSegment[size];
                }
            };
}