1 /* 2 * Copyright (C) 2024 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.FlaggedApi; 20 import android.annotation.NonNull; 21 import android.annotation.TestApi; 22 import android.os.Parcel; 23 import android.os.VibrationEffect; 24 import android.os.VibratorInfo; 25 26 import com.android.internal.util.Preconditions; 27 28 import java.util.Locale; 29 import java.util.Objects; 30 31 /** 32 * A {@link VibrationEffectSegment} that represents a smooth transition from the starting 33 * intensity and sharpness to new values over a specified duration. 34 * 35 * <p>The intensity and sharpness are expressed by float values in the range [0, 1], where 36 * intensity represents the user-perceived strength of the vibration, while sharpness represents 37 * the crispness of the vibration. 38 * 39 * @hide 40 */ 41 @TestApi 42 @FlaggedApi(Flags.FLAG_NORMALIZED_PWLE_EFFECTS) 43 public final class BasicPwleSegment extends VibrationEffectSegment { 44 private final float mStartIntensity; 45 private final float mEndIntensity; 46 private final float mStartSharpness; 47 private final float mEndSharpness; 48 private final long mDuration; 49 BasicPwleSegment(@onNull Parcel in)50 BasicPwleSegment(@NonNull Parcel in) { 51 this(in.readFloat(), in.readFloat(), in.readFloat(), in.readFloat(), in.readLong()); 52 } 53 54 /** @hide */ 55 @FlaggedApi(Flags.FLAG_NORMALIZED_PWLE_EFFECTS) BasicPwleSegment(float startIntensity, float endIntensity, float startSharpness, float endSharpness, long duration)56 public BasicPwleSegment(float startIntensity, float endIntensity, float startSharpness, 57 float endSharpness, long duration) { 58 mStartIntensity = startIntensity; 59 mEndIntensity = endIntensity; 60 mStartSharpness = startSharpness; 61 mEndSharpness = endSharpness; 62 mDuration = duration; 63 } 64 getStartIntensity()65 public float getStartIntensity() { 66 return mStartIntensity; 67 } 68 getEndIntensity()69 public float getEndIntensity() { 70 return mEndIntensity; 71 } 72 getStartSharpness()73 public float getStartSharpness() { 74 return mStartSharpness; 75 } 76 getEndSharpness()77 public float getEndSharpness() { 78 return mEndSharpness; 79 } 80 81 @Override getDuration()82 public long getDuration() { 83 return mDuration; 84 } 85 86 @Override equals(Object o)87 public boolean equals(Object o) { 88 if (!(o instanceof BasicPwleSegment)) { 89 return false; 90 } 91 BasicPwleSegment other = (BasicPwleSegment) o; 92 return Float.compare(mStartIntensity, other.mStartIntensity) == 0 93 && Float.compare(mEndIntensity, other.mEndIntensity) == 0 94 && Float.compare(mStartSharpness, other.mStartSharpness) == 0 95 && Float.compare(mEndSharpness, other.mEndSharpness) == 0 96 && mDuration == other.mDuration; 97 } 98 99 /** @hide */ 100 @Override areVibrationFeaturesSupported(@onNull VibratorInfo vibratorInfo)101 public boolean areVibrationFeaturesSupported(@NonNull VibratorInfo vibratorInfo) { 102 return vibratorInfo.areEnvelopeEffectsSupported(); 103 } 104 105 /** @hide */ 106 @Override isHapticFeedbackCandidate()107 public boolean isHapticFeedbackCandidate() { 108 return true; 109 } 110 111 /** @hide */ 112 @Override validate()113 public void validate() { 114 Preconditions.checkArgumentInRange(mStartSharpness, 0f, 1f, "startSharpness"); 115 Preconditions.checkArgumentInRange(mEndSharpness, 0f, 1f, "endSharpness"); 116 Preconditions.checkArgumentInRange(mStartIntensity, 0f, 1f, "startIntensity"); 117 Preconditions.checkArgumentInRange(mEndIntensity, 0f, 1f, "endIntensity"); 118 Preconditions.checkArgumentPositive(mDuration, "Time must be greater than zero."); 119 } 120 121 /** @hide */ 122 @NonNull 123 @Override resolve(int defaultAmplitude)124 public BasicPwleSegment resolve(int defaultAmplitude) { 125 return this; 126 } 127 128 /** @hide */ 129 @NonNull 130 @Override scale(float scaleFactor)131 public BasicPwleSegment scale(float scaleFactor) { 132 float newStartIntensity = VibrationEffect.scale(mStartIntensity, scaleFactor); 133 float newEndIntensity = VibrationEffect.scale(mEndIntensity, scaleFactor); 134 if (Float.compare(mStartIntensity, newStartIntensity) == 0 135 && Float.compare(mEndIntensity, newEndIntensity) == 0) { 136 return this; 137 } 138 return new BasicPwleSegment(newStartIntensity, newEndIntensity, mStartSharpness, 139 mEndSharpness, 140 mDuration); 141 } 142 143 /** @hide */ 144 @NonNull 145 @Override scaleLinearly(float scaleFactor)146 public BasicPwleSegment scaleLinearly(float scaleFactor) { 147 float newStartIntensity = VibrationEffect.scaleLinearly(mStartIntensity, scaleFactor); 148 float newEndIntensity = VibrationEffect.scaleLinearly(mEndIntensity, scaleFactor); 149 if (Float.compare(mStartIntensity, newStartIntensity) == 0 150 && Float.compare(mEndIntensity, newEndIntensity) == 0) { 151 return this; 152 } 153 return new BasicPwleSegment(newStartIntensity, newEndIntensity, mStartSharpness, 154 mEndSharpness, 155 mDuration); 156 } 157 158 /** @hide */ 159 @NonNull 160 @Override applyEffectStrength(int effectStrength)161 public BasicPwleSegment applyEffectStrength(int effectStrength) { 162 return this; 163 } 164 165 @Override hashCode()166 public int hashCode() { 167 return Objects.hash(mStartIntensity, mEndIntensity, mStartSharpness, mEndSharpness, 168 mDuration); 169 } 170 171 @Override toString()172 public String toString() { 173 return "BasicPwle{startIntensity=" + mStartIntensity 174 + ", endIntensity=" + mEndIntensity 175 + ", startSharpness=" + mStartSharpness 176 + ", endSharpness=" + mEndSharpness 177 + ", duration=" + mDuration 178 + "}"; 179 } 180 181 /** @hide */ 182 @Override toDebugString()183 public String toDebugString() { 184 return String.format(Locale.US, "Pwle=%dms(intensity=%.2f @ %.2f to %.2f @ %.2f)", 185 mDuration, 186 mStartIntensity, 187 mStartSharpness, 188 mEndIntensity, 189 mEndSharpness); 190 } 191 192 @Override describeContents()193 public int describeContents() { 194 return 0; 195 } 196 197 @Override writeToParcel(@onNull Parcel dest, int flags)198 public void writeToParcel(@NonNull Parcel dest, int flags) { 199 dest.writeInt(PARCEL_TOKEN_PWLE); 200 dest.writeFloat(mStartIntensity); 201 dest.writeFloat(mEndIntensity); 202 dest.writeFloat(mStartSharpness); 203 dest.writeFloat(mEndSharpness); 204 dest.writeLong(mDuration); 205 } 206 207 @NonNull 208 public static final Creator<BasicPwleSegment> CREATOR = 209 new Creator<BasicPwleSegment>() { 210 @Override 211 public BasicPwleSegment createFromParcel(Parcel in) { 212 // Skip the type token 213 in.readInt(); 214 return new BasicPwleSegment(in); 215 } 216 217 @Override 218 public BasicPwleSegment[] newArray(int size) { 219 return new BasicPwleSegment[size]; 220 } 221 }; 222 } 223