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.TestApi; 21 import android.os.Parcel; 22 import android.os.Parcelable; 23 import android.os.VibrationEffect; 24 25 import com.android.internal.util.Preconditions; 26 27 import java.util.Objects; 28 29 /** 30 * Representation of {@link VibrationEffectSegment} that holds a fixed vibration amplitude and 31 * frequency for a specified duration. 32 * 33 * <p>The amplitude is expressed by a float value in the range [0, 1], representing the relative 34 * output acceleration for the vibrator. The frequency is expressed in hertz by a positive finite 35 * float value. The special value zero is used here for an unspecified frequency, and will be 36 * automatically mapped to the device's default vibration frequency (usually the resonant 37 * frequency). 38 * 39 * @hide 40 */ 41 @TestApi 42 public final class StepSegment extends VibrationEffectSegment { 43 private final float mAmplitude; 44 private final float mFrequencyHz; 45 private final int mDuration; 46 StepSegment(@onNull Parcel in)47 StepSegment(@NonNull Parcel in) { 48 this(in.readFloat(), in.readFloat(), in.readInt()); 49 } 50 51 /** @hide */ StepSegment(float amplitude, float frequencyHz, int duration)52 public StepSegment(float amplitude, float frequencyHz, int duration) { 53 mAmplitude = amplitude; 54 mFrequencyHz = frequencyHz; 55 mDuration = duration; 56 } 57 58 @Override equals(Object o)59 public boolean equals(Object o) { 60 if (!(o instanceof StepSegment)) { 61 return false; 62 } 63 StepSegment other = (StepSegment) o; 64 return Float.compare(mAmplitude, other.mAmplitude) == 0 65 && Float.compare(mFrequencyHz, other.mFrequencyHz) == 0 66 && mDuration == other.mDuration; 67 } 68 getAmplitude()69 public float getAmplitude() { 70 return mAmplitude; 71 } 72 getFrequencyHz()73 public float getFrequencyHz() { 74 return mFrequencyHz; 75 } 76 77 @Override getDuration()78 public long getDuration() { 79 return mDuration; 80 } 81 82 /** @hide */ 83 @Override isHapticFeedbackCandidate()84 public boolean isHapticFeedbackCandidate() { 85 return true; 86 } 87 88 /** @hide */ 89 @Override hasNonZeroAmplitude()90 public boolean hasNonZeroAmplitude() { 91 // DEFAULT_AMPLITUDE == -1 is still a non-zero amplitude that will be resolved later. 92 return Float.compare(mAmplitude, 0) != 0; 93 } 94 95 /** @hide */ 96 @Override validate()97 public void validate() { 98 VibrationEffectSegment.checkFrequencyArgument(mFrequencyHz, "frequencyHz"); 99 VibrationEffectSegment.checkDurationArgument(mDuration, "duration"); 100 if (Float.compare(mAmplitude, VibrationEffect.DEFAULT_AMPLITUDE) != 0) { 101 Preconditions.checkArgumentInRange(mAmplitude, 0f, 1f, "amplitude"); 102 } 103 } 104 105 /** @hide */ 106 @NonNull 107 @Override resolve(int defaultAmplitude)108 public StepSegment resolve(int defaultAmplitude) { 109 if (defaultAmplitude > VibrationEffect.MAX_AMPLITUDE || defaultAmplitude <= 0) { 110 throw new IllegalArgumentException( 111 "amplitude must be between 1 and 255 inclusive (amplitude=" 112 + defaultAmplitude + ")"); 113 } 114 if (Float.compare(mAmplitude, VibrationEffect.DEFAULT_AMPLITUDE) != 0) { 115 return this; 116 } 117 return new StepSegment((float) defaultAmplitude / VibrationEffect.MAX_AMPLITUDE, 118 mFrequencyHz, 119 mDuration); 120 } 121 122 /** @hide */ 123 @NonNull 124 @Override scale(float scaleFactor)125 public StepSegment scale(float scaleFactor) { 126 if (Float.compare(mAmplitude, VibrationEffect.DEFAULT_AMPLITUDE) == 0) { 127 return this; 128 } 129 return new StepSegment(VibrationEffect.scale(mAmplitude, scaleFactor), mFrequencyHz, 130 mDuration); 131 } 132 133 /** @hide */ 134 @NonNull 135 @Override applyEffectStrength(int effectStrength)136 public StepSegment applyEffectStrength(int effectStrength) { 137 return this; 138 } 139 140 @Override hashCode()141 public int hashCode() { 142 return Objects.hash(mAmplitude, mFrequencyHz, mDuration); 143 } 144 145 @Override toString()146 public String toString() { 147 return "Step{amplitude=" + mAmplitude 148 + ", frequencyHz=" + mFrequencyHz 149 + ", duration=" + mDuration 150 + "}"; 151 } 152 153 @Override describeContents()154 public int describeContents() { 155 return 0; 156 } 157 158 @Override writeToParcel(@onNull Parcel out, int flags)159 public void writeToParcel(@NonNull Parcel out, int flags) { 160 out.writeInt(PARCEL_TOKEN_STEP); 161 out.writeFloat(mAmplitude); 162 out.writeFloat(mFrequencyHz); 163 out.writeInt(mDuration); 164 } 165 166 @NonNull 167 public static final Parcelable.Creator<StepSegment> CREATOR = 168 new Parcelable.Creator<StepSegment>() { 169 @Override 170 public StepSegment createFromParcel(Parcel in) { 171 // Skip the type token 172 in.readInt(); 173 return new StepSegment(in); 174 } 175 176 @Override 177 public StepSegment[] newArray(int size) { 178 return new StepSegment[size]; 179 } 180 }; 181 } 182