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 26 import java.util.Objects; 27 28 /** 29 * Representation of {@link VibrationEffectSegment} that plays a prebaked vibration effect. 30 * 31 * @hide 32 */ 33 @TestApi 34 public final class PrebakedSegment extends VibrationEffectSegment { 35 private final int mEffectId; 36 private final boolean mFallback; 37 private final int mEffectStrength; 38 PrebakedSegment(@onNull Parcel in)39 PrebakedSegment(@NonNull Parcel in) { 40 mEffectId = in.readInt(); 41 mFallback = in.readByte() != 0; 42 mEffectStrength = in.readInt(); 43 } 44 45 /** @hide */ PrebakedSegment(int effectId, boolean shouldFallback, int effectStrength)46 public PrebakedSegment(int effectId, boolean shouldFallback, int effectStrength) { 47 mEffectId = effectId; 48 mFallback = shouldFallback; 49 mEffectStrength = effectStrength; 50 } 51 getEffectId()52 public int getEffectId() { 53 return mEffectId; 54 } 55 getEffectStrength()56 public int getEffectStrength() { 57 return mEffectStrength; 58 } 59 60 /** Return true if a fallback effect should be played if this effect is not supported. */ shouldFallback()61 public boolean shouldFallback() { 62 return mFallback; 63 } 64 65 @Override getDuration()66 public long getDuration() { 67 return -1; 68 } 69 70 /** @hide */ 71 @Override isHapticFeedbackCandidate()72 public boolean isHapticFeedbackCandidate() { 73 switch (mEffectId) { 74 case VibrationEffect.EFFECT_CLICK: 75 case VibrationEffect.EFFECT_DOUBLE_CLICK: 76 case VibrationEffect.EFFECT_HEAVY_CLICK: 77 case VibrationEffect.EFFECT_POP: 78 case VibrationEffect.EFFECT_TEXTURE_TICK: 79 case VibrationEffect.EFFECT_THUD: 80 case VibrationEffect.EFFECT_TICK: 81 return true; 82 default: 83 // VibrationEffect.RINGTONES are not segments that could represent a haptic feedback 84 return false; 85 } 86 } 87 88 /** @hide */ 89 @Override hasNonZeroAmplitude()90 public boolean hasNonZeroAmplitude() { 91 return true; 92 } 93 94 /** @hide */ 95 @NonNull 96 @Override resolve(int defaultAmplitude)97 public PrebakedSegment resolve(int defaultAmplitude) { 98 return this; 99 } 100 101 /** @hide */ 102 @NonNull 103 @Override scale(float scaleFactor)104 public PrebakedSegment scale(float scaleFactor) { 105 // Prebaked effect strength cannot be scaled with this method. 106 return this; 107 } 108 109 /** @hide */ 110 @NonNull 111 @Override applyEffectStrength(int effectStrength)112 public PrebakedSegment applyEffectStrength(int effectStrength) { 113 if (effectStrength != mEffectStrength && isValidEffectStrength(effectStrength)) { 114 return new PrebakedSegment(mEffectId, mFallback, effectStrength); 115 } 116 return this; 117 } 118 isValidEffectStrength(int strength)119 private static boolean isValidEffectStrength(int strength) { 120 switch (strength) { 121 case VibrationEffect.EFFECT_STRENGTH_LIGHT: 122 case VibrationEffect.EFFECT_STRENGTH_MEDIUM: 123 case VibrationEffect.EFFECT_STRENGTH_STRONG: 124 return true; 125 default: 126 return false; 127 } 128 } 129 130 /** @hide */ 131 @Override validate()132 public void validate() { 133 switch (mEffectId) { 134 case VibrationEffect.EFFECT_CLICK: 135 case VibrationEffect.EFFECT_DOUBLE_CLICK: 136 case VibrationEffect.EFFECT_HEAVY_CLICK: 137 case VibrationEffect.EFFECT_POP: 138 case VibrationEffect.EFFECT_TEXTURE_TICK: 139 case VibrationEffect.EFFECT_THUD: 140 case VibrationEffect.EFFECT_TICK: 141 break; 142 default: 143 int[] ringtones = VibrationEffect.RINGTONES; 144 if (mEffectId < ringtones[0] || mEffectId > ringtones[ringtones.length - 1]) { 145 throw new IllegalArgumentException( 146 "Unknown prebaked effect type (value=" + mEffectId + ")"); 147 } 148 } 149 if (!isValidEffectStrength(mEffectStrength)) { 150 throw new IllegalArgumentException( 151 "Unknown prebaked effect strength (value=" + mEffectStrength + ")"); 152 } 153 } 154 155 @Override equals(@ullable Object o)156 public boolean equals(@Nullable Object o) { 157 if (!(o instanceof PrebakedSegment)) { 158 return false; 159 } 160 PrebakedSegment other = (PrebakedSegment) o; 161 return mEffectId == other.mEffectId 162 && mFallback == other.mFallback 163 && mEffectStrength == other.mEffectStrength; 164 } 165 166 @Override hashCode()167 public int hashCode() { 168 return Objects.hash(mEffectId, mFallback, mEffectStrength); 169 } 170 171 @Override toString()172 public String toString() { 173 return "Prebaked{effect=" + VibrationEffect.effectIdToString(mEffectId) 174 + ", strength=" + VibrationEffect.effectStrengthToString(mEffectStrength) 175 + ", fallback=" + mFallback 176 + "}"; 177 } 178 179 @Override describeContents()180 public int describeContents() { 181 return 0; 182 } 183 184 @Override writeToParcel(@onNull Parcel out, int flags)185 public void writeToParcel(@NonNull Parcel out, int flags) { 186 out.writeInt(PARCEL_TOKEN_PREBAKED); 187 out.writeInt(mEffectId); 188 out.writeByte((byte) (mFallback ? 1 : 0)); 189 out.writeInt(mEffectStrength); 190 } 191 192 @NonNull 193 public static final Parcelable.Creator<PrebakedSegment> CREATOR = 194 new Parcelable.Creator<PrebakedSegment>() { 195 @Override 196 public PrebakedSegment createFromParcel(Parcel in) { 197 // Skip the type token 198 in.readInt(); 199 return new PrebakedSegment(in); 200 } 201 202 @Override 203 public PrebakedSegment[] newArray(int size) { 204 return new PrebakedSegment[size]; 205 } 206 }; 207 } 208