blob: 115a66c5580a1d47bf776031850e2834443e3ea6 [file] [log] [blame]
Aurimas Liutikas88c7ff12023-08-10 12:42:26 -07001/*
2 * Copyright (C) 2021 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.os.vibrator;
18
19import android.annotation.NonNull;
20import android.annotation.TestApi;
21import android.os.Parcel;
22import android.os.Parcelable;
23import android.os.VibrationEffect;
24import android.os.Vibrator;
25
26import com.android.internal.util.Preconditions;
27
28import java.util.Objects;
29
30/**
31 * Representation of {@link VibrationEffectSegment} that holds a fixed vibration amplitude and
32 * frequency for a specified duration.
33 *
34 * <p>The amplitude is expressed by a float value in the range [0, 1], representing the relative
35 * output acceleration for the vibrator. The frequency is expressed in hertz by a positive finite
36 * float value. The special value zero is used here for an unspecified frequency, and will be
37 * automatically mapped to the device's default vibration frequency (usually the resonant
38 * frequency).
39 *
40 * @hide
41 */
42@TestApi
43public final class StepSegment extends VibrationEffectSegment {
44 private final float mAmplitude;
45 private final float mFrequencyHz;
46 private final int mDuration;
47
48 StepSegment(@NonNull Parcel in) {
49 this(in.readFloat(), in.readFloat(), in.readInt());
50 }
51
52 /** @hide */
53 public StepSegment(float amplitude, float frequencyHz, int duration) {
54 mAmplitude = amplitude;
55 mFrequencyHz = frequencyHz;
56 mDuration = duration;
57 }
58
59 @Override
60 public boolean equals(Object o) {
61 if (!(o instanceof StepSegment)) {
62 return false;
63 }
64 StepSegment other = (StepSegment) o;
65 return Float.compare(mAmplitude, other.mAmplitude) == 0
66 && Float.compare(mFrequencyHz, other.mFrequencyHz) == 0
67 && mDuration == other.mDuration;
68 }
69
70 public float getAmplitude() {
71 return mAmplitude;
72 }
73
74 public float getFrequencyHz() {
75 return mFrequencyHz;
76 }
77
78 @Override
79 public long getDuration() {
80 return mDuration;
81 }
82
83 /** @hide */
84 @Override
85 public boolean areVibrationFeaturesSupported(@NonNull Vibrator vibrator) {
86 boolean areFeaturesSupported = true;
87 if (frequencyRequiresFrequencyControl(mFrequencyHz)) {
88 areFeaturesSupported &= vibrator.hasFrequencyControl();
89 }
90 if (amplitudeRequiresAmplitudeControl(mAmplitude)) {
91 areFeaturesSupported &= vibrator.hasAmplitudeControl();
92 }
93 return areFeaturesSupported;
94 }
95
96 /** @hide */
97 @Override
98 public boolean isHapticFeedbackCandidate() {
99 return true;
100 }
101
102 /** @hide */
103 @Override
104 public boolean hasNonZeroAmplitude() {
105 // DEFAULT_AMPLITUDE == -1 is still a non-zero amplitude that will be resolved later.
106 return Float.compare(mAmplitude, 0) != 0;
107 }
108
109 /** @hide */
110 @Override
111 public void validate() {
112 VibrationEffectSegment.checkFrequencyArgument(mFrequencyHz, "frequencyHz");
113 VibrationEffectSegment.checkDurationArgument(mDuration, "duration");
114 if (Float.compare(mAmplitude, VibrationEffect.DEFAULT_AMPLITUDE) != 0) {
115 Preconditions.checkArgumentInRange(mAmplitude, 0f, 1f, "amplitude");
116 }
117 }
118
119 /** @hide */
120 @NonNull
121 @Override
122 public StepSegment resolve(int defaultAmplitude) {
123 if (defaultAmplitude > VibrationEffect.MAX_AMPLITUDE || defaultAmplitude <= 0) {
124 throw new IllegalArgumentException(
125 "amplitude must be between 1 and 255 inclusive (amplitude="
126 + defaultAmplitude + ")");
127 }
128 if (Float.compare(mAmplitude, VibrationEffect.DEFAULT_AMPLITUDE) != 0) {
129 return this;
130 }
131 return new StepSegment((float) defaultAmplitude / VibrationEffect.MAX_AMPLITUDE,
132 mFrequencyHz,
133 mDuration);
134 }
135
136 /** @hide */
137 @NonNull
138 @Override
139 public StepSegment scale(float scaleFactor) {
140 if (Float.compare(mAmplitude, VibrationEffect.DEFAULT_AMPLITUDE) == 0) {
141 return this;
142 }
143 return new StepSegment(VibrationEffect.scale(mAmplitude, scaleFactor), mFrequencyHz,
144 mDuration);
145 }
146
147 /** @hide */
148 @NonNull
149 @Override
150 public StepSegment applyEffectStrength(int effectStrength) {
151 return this;
152 }
153
154 @Override
155 public int hashCode() {
156 return Objects.hash(mAmplitude, mFrequencyHz, mDuration);
157 }
158
159 @Override
160 public String toString() {
161 return "Step{amplitude=" + mAmplitude
162 + ", frequencyHz=" + mFrequencyHz
163 + ", duration=" + mDuration
164 + "}";
165 }
166
167 @Override
168 public int describeContents() {
169 return 0;
170 }
171
172 @Override
173 public void writeToParcel(@NonNull Parcel out, int flags) {
174 out.writeInt(PARCEL_TOKEN_STEP);
175 out.writeFloat(mAmplitude);
176 out.writeFloat(mFrequencyHz);
177 out.writeInt(mDuration);
178 }
179
180 @NonNull
181 public static final Parcelable.Creator<StepSegment> CREATOR =
182 new Parcelable.Creator<StepSegment>() {
183 @Override
184 public StepSegment createFromParcel(Parcel in) {
185 // Skip the type token
186 in.readInt();
187 return new StepSegment(in);
188 }
189
190 @Override
191 public StepSegment[] newArray(int size) {
192 return new StepSegment[size];
193 }
194 };
195}