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.Vibrator;
26 
27 import com.android.internal.util.Preconditions;
28 
29 import java.util.Objects;
30 
31 /**
32  * Representation of {@link VibrationEffectSegment} that plays a primitive vibration effect after a
33  * specified delay and applying a given scale.
34  *
35  * @hide
36  */
37 @TestApi
38 public final class PrimitiveSegment extends VibrationEffectSegment {
39     private final int mPrimitiveId;
40     private final float mScale;
41     private final int mDelay;
42 
PrimitiveSegment(@onNull Parcel in)43     PrimitiveSegment(@NonNull Parcel in) {
44         this(in.readInt(), in.readFloat(), in.readInt());
45     }
46 
47     /** @hide */
PrimitiveSegment(int id, float scale, int delay)48     public PrimitiveSegment(int id, float scale, int delay) {
49         mPrimitiveId = id;
50         mScale = scale;
51         mDelay = delay;
52     }
53 
getPrimitiveId()54     public int getPrimitiveId() {
55         return mPrimitiveId;
56     }
57 
getScale()58     public float getScale() {
59         return mScale;
60     }
61 
getDelay()62     public int getDelay() {
63         return mDelay;
64     }
65 
66     @Override
getDuration()67     public long getDuration() {
68         return -1;
69     }
70 
71     /** @hide */
72     @Override
areVibrationFeaturesSupported(@onNull Vibrator vibrator)73     public boolean areVibrationFeaturesSupported(@NonNull Vibrator vibrator) {
74         return vibrator.areAllPrimitivesSupported(mPrimitiveId);
75     }
76 
77     /** @hide */
78     @Override
isHapticFeedbackCandidate()79     public boolean isHapticFeedbackCandidate() {
80         return true;
81     }
82 
83     /** @hide */
84     @Override
hasNonZeroAmplitude()85     public boolean hasNonZeroAmplitude() {
86         // Every primitive plays a vibration with a non-zero amplitude, even at scale == 0.
87         return true;
88     }
89 
90     /** @hide */
91     @NonNull
92     @Override
resolve(int defaultAmplitude)93     public PrimitiveSegment resolve(int defaultAmplitude) {
94         return this;
95     }
96 
97     /** @hide */
98     @NonNull
99     @Override
scale(float scaleFactor)100     public PrimitiveSegment scale(float scaleFactor) {
101         return new PrimitiveSegment(mPrimitiveId, VibrationEffect.scale(mScale, scaleFactor),
102                 mDelay);
103     }
104 
105     /** @hide */
106     @NonNull
107     @Override
applyEffectStrength(int effectStrength)108     public PrimitiveSegment applyEffectStrength(int effectStrength) {
109         return this;
110     }
111 
112     /** @hide */
113     @Override
validate()114     public void validate() {
115         Preconditions.checkArgumentInRange(mPrimitiveId, VibrationEffect.Composition.PRIMITIVE_NOOP,
116                 VibrationEffect.Composition.PRIMITIVE_LOW_TICK, "primitiveId");
117         Preconditions.checkArgumentInRange(mScale, 0f, 1f, "scale");
118         VibrationEffectSegment.checkDurationArgument(mDelay, "delay");
119     }
120 
121     @Override
writeToParcel(@onNull Parcel dest, int flags)122     public void writeToParcel(@NonNull Parcel dest, int flags) {
123         dest.writeInt(PARCEL_TOKEN_PRIMITIVE);
124         dest.writeInt(mPrimitiveId);
125         dest.writeFloat(mScale);
126         dest.writeInt(mDelay);
127     }
128 
129     @Override
describeContents()130     public int describeContents() {
131         return 0;
132     }
133 
134     @Override
toString()135     public String toString() {
136         return "Primitive{"
137                 + "primitive=" + VibrationEffect.Composition.primitiveToString(mPrimitiveId)
138                 + ", scale=" + mScale
139                 + ", delay=" + mDelay
140                 + '}';
141     }
142 
143     @Override
equals(@ullable Object o)144     public boolean equals(@Nullable Object o) {
145         if (this == o) return true;
146         if (o == null || getClass() != o.getClass()) return false;
147         PrimitiveSegment that = (PrimitiveSegment) o;
148         return mPrimitiveId == that.mPrimitiveId
149                 && Float.compare(that.mScale, mScale) == 0
150                 && mDelay == that.mDelay;
151     }
152 
153     @Override
hashCode()154     public int hashCode() {
155         return Objects.hash(mPrimitiveId, mScale, mDelay);
156     }
157 
158     @NonNull
159     public static final Parcelable.Creator<PrimitiveSegment> CREATOR =
160             new Parcelable.Creator<PrimitiveSegment>() {
161                 @Override
162                 public PrimitiveSegment createFromParcel(Parcel in) {
163                     // Skip the type token
164                     in.readInt();
165                     return new PrimitiveSegment(in);
166                 }
167 
168                 @Override
169                 public PrimitiveSegment[] newArray(int size) {
170                     return new PrimitiveSegment[size];
171                 }
172             };
173 }
174