• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
17 package android.os.vibrator;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.annotation.TestApi;
22 import android.os.Parcel;
23 import android.os.Parcelable;
24 import android.os.VibrationEffect;
25 import android.os.VibratorInfo;
26 
27 import com.android.internal.util.Preconditions;
28 
29 import java.util.Locale;
30 import java.util.Objects;
31 
32 /**
33  * Representation of {@link VibrationEffectSegment} that plays a primitive vibration effect after a
34  * specified delay and applying a given scale.
35  *
36  * @hide
37  */
38 @TestApi
39 public final class PrimitiveSegment extends VibrationEffectSegment {
40 
41     /** @hide */
42     public static final float DEFAULT_SCALE = 1f;
43 
44     /** @hide */
45     public static final int DEFAULT_DELAY_MILLIS = 0;
46 
47     /** @hide */
48     public static final int DEFAULT_DELAY_TYPE = VibrationEffect.Composition.DELAY_TYPE_PAUSE;
49 
50     private final int mPrimitiveId;
51     private final float mScale;
52     private final int mDelay;
53     private final int mDelayType;
54 
PrimitiveSegment(@onNull Parcel in)55     PrimitiveSegment(@NonNull Parcel in) {
56         this(in.readInt(), in.readFloat(), in.readInt(), in.readInt());
57     }
58 
59     /** @hide */
PrimitiveSegment(int id, float scale, int delay)60     public PrimitiveSegment(int id, float scale, int delay) {
61         this(id, scale, delay, DEFAULT_DELAY_TYPE);
62     }
63 
64     /** @hide */
PrimitiveSegment(int id, float scale, int delay, int delayType)65     public PrimitiveSegment(int id, float scale, int delay, int delayType) {
66         mPrimitiveId = id;
67         mScale = scale;
68         mDelay = delay;
69         mDelayType = delayType;
70     }
71 
getPrimitiveId()72     public int getPrimitiveId() {
73         return mPrimitiveId;
74     }
75 
getScale()76     public float getScale() {
77         return mScale;
78     }
79 
getDelay()80     public int getDelay() {
81         return mDelay;
82     }
83 
84     /** @hide */
getDelayType()85     public int getDelayType() {
86         return mDelayType;
87     }
88 
89     @Override
getDuration()90     public long getDuration() {
91         return -1;
92     }
93 
94     /** @hide */
95     @Override
getDuration(@ullable VibratorInfo vibratorInfo)96     public long getDuration(@Nullable VibratorInfo vibratorInfo) {
97         if (vibratorInfo == null) {
98             return getDuration();
99         }
100         int duration = vibratorInfo.getPrimitiveDuration(mPrimitiveId);
101         return duration > 0 ? duration + mDelay : getDuration();
102     }
103 
104     /** @hide */
105     @Override
areVibrationFeaturesSupported(@onNull VibratorInfo vibratorInfo)106     public boolean areVibrationFeaturesSupported(@NonNull VibratorInfo vibratorInfo) {
107         return vibratorInfo.isPrimitiveSupported(mPrimitiveId);
108     }
109 
110     /** @hide */
111     @Override
isHapticFeedbackCandidate()112     public boolean isHapticFeedbackCandidate() {
113         return true;
114     }
115 
116     /** @hide */
117     @NonNull
118     @Override
resolve(int defaultAmplitude)119     public PrimitiveSegment resolve(int defaultAmplitude) {
120         return this;
121     }
122 
123     /** @hide */
124     @NonNull
125     @Override
scale(float scaleFactor)126     public PrimitiveSegment scale(float scaleFactor) {
127         float newScale = VibrationEffect.scale(mScale, scaleFactor);
128         if (Float.compare(mScale, newScale) == 0) {
129             return this;
130         }
131         return new PrimitiveSegment(mPrimitiveId, newScale, mDelay, mDelayType);
132     }
133 
134     /** @hide */
135     @NonNull
136     @Override
scaleLinearly(float scaleFactor)137     public PrimitiveSegment scaleLinearly(float scaleFactor) {
138         float newScale = VibrationEffect.scaleLinearly(mScale, scaleFactor);
139         if (Float.compare(mScale, newScale) == 0) {
140             return this;
141         }
142         return new PrimitiveSegment(mPrimitiveId, newScale, mDelay, mDelayType);
143     }
144 
145     /** @hide */
146     @NonNull
147     @Override
applyEffectStrength(int effectStrength)148     public PrimitiveSegment applyEffectStrength(int effectStrength) {
149         return this;
150     }
151 
152     /** @hide */
153     @Override
validate()154     public void validate() {
155         Preconditions.checkArgumentInRange(mPrimitiveId, VibrationEffect.Composition.PRIMITIVE_NOOP,
156                 VibrationEffect.Composition.PRIMITIVE_LOW_TICK, "primitiveId");
157         Preconditions.checkArgumentInRange(mScale, 0f, 1f, "scale");
158         VibrationEffectSegment.checkDurationArgument(mDelay, "delay");
159         Preconditions.checkArgument(isValidDelayType(mDelayType), "delayType");
160     }
161 
162     @Override
writeToParcel(@onNull Parcel dest, int flags)163     public void writeToParcel(@NonNull Parcel dest, int flags) {
164         dest.writeInt(PARCEL_TOKEN_PRIMITIVE);
165         dest.writeInt(mPrimitiveId);
166         dest.writeFloat(mScale);
167         dest.writeInt(mDelay);
168         dest.writeInt(mDelayType);
169     }
170 
171     @Override
describeContents()172     public int describeContents() {
173         return 0;
174     }
175 
176     @Override
toString()177     public String toString() {
178         return "Primitive{"
179                 + "primitive=" + VibrationEffect.Composition.primitiveToString(mPrimitiveId)
180                 + ", scale=" + mScale
181                 + ", delay=" + mDelay
182                 + ", delayType=" + VibrationEffect.Composition.delayTypeToString(mDelayType)
183                 + '}';
184     }
185 
186     /** @hide */
187     @Override
toDebugString()188     public String toDebugString() {
189         return String.format(Locale.ROOT, "Primitive=%s(scale=%.2f, %s=%dms)",
190                 VibrationEffect.Composition.primitiveToString(mPrimitiveId), mScale,
191                 toDelayTypeDebugString(mDelayType), mDelay);
192     }
193 
194     @Override
equals(@ullable Object o)195     public boolean equals(@Nullable Object o) {
196         if (this == o) return true;
197         if (o == null || getClass() != o.getClass()) return false;
198         PrimitiveSegment that = (PrimitiveSegment) o;
199         return mPrimitiveId == that.mPrimitiveId
200                 && Float.compare(that.mScale, mScale) == 0
201                 && mDelay == that.mDelay
202                 && mDelayType == that.mDelayType;
203     }
204 
205     @Override
hashCode()206     public int hashCode() {
207         return Objects.hash(mPrimitiveId, mScale, mDelay, mDelayType);
208     }
209 
isValidDelayType(int delayType)210     private static boolean isValidDelayType(int delayType) {
211         return switch (delayType) {
212             case VibrationEffect.Composition.DELAY_TYPE_PAUSE,
213                  VibrationEffect.Composition.DELAY_TYPE_RELATIVE_START_OFFSET -> true;
214             default -> false;
215         };
216     }
217 
toDelayTypeDebugString(int delayType)218     private static String toDelayTypeDebugString(int delayType) {
219         return switch (delayType) {
220             case VibrationEffect.Composition.DELAY_TYPE_RELATIVE_START_OFFSET -> "startOffset";
221             default -> "pause";
222         };
223     }
224 
225     @NonNull
226     public static final Parcelable.Creator<PrimitiveSegment> CREATOR =
227             new Parcelable.Creator<PrimitiveSegment>() {
228                 @Override
229                 public PrimitiveSegment createFromParcel(Parcel in) {
230                     // Skip the type token
231                     in.readInt();
232                     return new PrimitiveSegment(in);
233                 }
234 
235                 @Override
236                 public PrimitiveSegment[] newArray(int size) {
237                     return new PrimitiveSegment[size];
238                 }
239             };
240 }
241