diff options
-rw-r--r-- | api/current.txt | 31 | ||||
-rw-r--r-- | api/test-current.txt | 8 | ||||
-rw-r--r-- | core/java/android/os/ExternalVibration.java | 4 | ||||
-rw-r--r-- | core/java/android/os/IVibratorService.aidl | 9 | ||||
-rw-r--r-- | core/java/android/os/SystemVibrator.java | 9 | ||||
-rw-r--r-- | core/java/android/os/VibrationAttributes.aidl | 18 | ||||
-rw-r--r-- | core/java/android/os/VibrationAttributes.java | 401 | ||||
-rw-r--r-- | services/core/java/com/android/server/VibratorService.java | 128 | ||||
-rw-r--r-- | tests/permission/src/com/android/framework/permission/tests/VibratorServicePermissionTest.java | 6 |
9 files changed, 521 insertions, 93 deletions
diff --git a/api/current.txt b/api/current.txt index 9425b81ee2d1..f2f6a1723673 100644 --- a/api/current.txt +++ b/api/current.txt @@ -36090,6 +36090,37 @@ package android.os { method public int getUserOperationResult(); } + public final class VibrationAttributes implements android.os.Parcelable { + method public int describeContents(); + method public int getFlags(); + method public int getUsage(); + method public int getUsageClass(); + method public boolean isFlagSet(int); + method public void writeToParcel(@NonNull android.os.Parcel, int); + field @NonNull public static final android.os.Parcelable.Creator<android.os.VibrationAttributes> CREATOR; + field public static final int FLAG_BYPASS_INTERRUPTION_POLICY = 1; // 0x1 + field public static final int USAGE_ALARM = 17; // 0x11 + field public static final int USAGE_CLASS_ALARM = 1; // 0x1 + field public static final int USAGE_CLASS_FEEDBACK = 2; // 0x2 + field public static final int USAGE_CLASS_MASK = 15; // 0xf + field public static final int USAGE_CLASS_UNKNOWN = 0; // 0x0 + field public static final int USAGE_COMMUNICATION_REQUEST = 65; // 0x41 + field public static final int USAGE_HARDWARE_FEEDBACK = 50; // 0x32 + field public static final int USAGE_NOTIFICATION = 49; // 0x31 + field public static final int USAGE_PHYSICAL_EMULATION = 34; // 0x22 + field public static final int USAGE_RINGTONE = 33; // 0x21 + field public static final int USAGE_TOUCH = 18; // 0x12 + field public static final int USAGE_UNKNOWN = 0; // 0x0 + } + + public static final class VibrationAttributes.Builder { + ctor public VibrationAttributes.Builder(); + ctor public VibrationAttributes.Builder(@Nullable android.os.VibrationAttributes); + method @NonNull public android.os.VibrationAttributes build(); + method @NonNull public android.os.VibrationAttributes.Builder replaceFlags(int); + method @NonNull public android.os.VibrationAttributes.Builder setUsage(int); + } + public abstract class VibrationEffect implements android.os.Parcelable { method public static android.os.VibrationEffect createOneShot(long, int); method @NonNull public static android.os.VibrationEffect createPredefined(int); diff --git a/api/test-current.txt b/api/test-current.txt index 1c1d79473734..38d89d358a21 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -2183,6 +2183,14 @@ package android.os { field public static final String ACTION_USER_RESTRICTIONS_CHANGED = "android.os.action.USER_RESTRICTIONS_CHANGED"; } + public final class VibrationAttributes implements android.os.Parcelable { + method @Deprecated @NonNull public android.media.AudioAttributes getAudioAttributes(); + } + + public static final class VibrationAttributes.Builder { + ctor public VibrationAttributes.Builder(@NonNull android.media.AudioAttributes, @Nullable android.os.VibrationEffect); + } + public abstract class VibrationEffect implements android.os.Parcelable { method public static android.os.VibrationEffect get(int); method public static android.os.VibrationEffect get(int, boolean); diff --git a/core/java/android/os/ExternalVibration.java b/core/java/android/os/ExternalVibration.java index 37ca868598f5..2991db2dac02 100644 --- a/core/java/android/os/ExternalVibration.java +++ b/core/java/android/os/ExternalVibration.java @@ -84,6 +84,10 @@ public class ExternalVibration implements Parcelable { return mAttrs; } + public VibrationAttributes getVibrationAttributes() { + return new VibrationAttributes.Builder(mAttrs, null).build(); + } + /** * Mutes the external vibration if it's playing and unmuted. * diff --git a/core/java/android/os/IVibratorService.aidl b/core/java/android/os/IVibratorService.aidl index 6b881fecad56..7b2d148bfa37 100644 --- a/core/java/android/os/IVibratorService.aidl +++ b/core/java/android/os/IVibratorService.aidl @@ -16,17 +16,18 @@ package android.os; -import android.media.AudioAttributes; import android.os.VibrationEffect; +import android.os.VibrationAttributes; /** {@hide} */ interface IVibratorService { boolean hasVibrator(); boolean hasAmplitudeControl(); - boolean setAlwaysOnEffect(int id, in VibrationEffect effect, in AudioAttributes attributes); - void vibrate(int uid, String opPkg, in VibrationEffect effect, in AudioAttributes attributes, - String reason, IBinder token); + boolean setAlwaysOnEffect(int id, in VibrationEffect effect, + in VibrationAttributes attributes); + void vibrate(int uid, String opPkg, in VibrationEffect effect, + in VibrationAttributes attributes, String reason, IBinder token); void cancelVibrate(IBinder token); } diff --git a/core/java/android/os/SystemVibrator.java b/core/java/android/os/SystemVibrator.java index f585c75b6bb7..c1542c7ee68f 100644 --- a/core/java/android/os/SystemVibrator.java +++ b/core/java/android/os/SystemVibrator.java @@ -76,7 +76,8 @@ public class SystemVibrator extends Vibrator { return false; } try { - return mService.setAlwaysOnEffect(id, effect, attributes); + VibrationAttributes atr = new VibrationAttributes.Builder(attributes, effect).build(); + return mService.setAlwaysOnEffect(id, effect, atr); } catch (RemoteException e) { Log.w(TAG, "Failed to set always-on effect.", e); } @@ -91,7 +92,11 @@ public class SystemVibrator extends Vibrator { return; } try { - mService.vibrate(uid, opPkg, effect, attributes, reason, mToken); + if (attributes == null) { + attributes = new AudioAttributes.Builder().build(); + } + VibrationAttributes atr = new VibrationAttributes.Builder(attributes, effect).build(); + mService.vibrate(uid, opPkg, effect, atr, reason, mToken); } catch (RemoteException e) { Log.w(TAG, "Failed to vibrate.", e); } diff --git a/core/java/android/os/VibrationAttributes.aidl b/core/java/android/os/VibrationAttributes.aidl new file mode 100644 index 000000000000..5c05a4e8f65e --- /dev/null +++ b/core/java/android/os/VibrationAttributes.aidl @@ -0,0 +1,18 @@ +/* Copyright 2019, The Android Open Source Project +** +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at +** +** http://www.apache.org/licenses/LICENSE-2.0 +** +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and +** limitations under the License. +*/ + +package android.os; + +parcelable VibrationAttributes; diff --git a/core/java/android/os/VibrationAttributes.java b/core/java/android/os/VibrationAttributes.java new file mode 100644 index 000000000000..3e16640895eb --- /dev/null +++ b/core/java/android/os/VibrationAttributes.java @@ -0,0 +1,401 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.os; + +import android.annotation.IntDef; +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.annotation.TestApi; +import android.media.AudioAttributes; +import android.util.Slog; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.util.Objects; + +/** + * A class to encapsulate a collection of attributes describing information about a vibration + */ +public final class VibrationAttributes implements Parcelable { + private static final String TAG = "VibrationAttributes"; + + /** + * @hide + */ + @IntDef(prefix = { "USAGE_CLASS_" }, value = { + USAGE_CLASS_UNKNOWN, + USAGE_CLASS_ALARM, + USAGE_CLASS_FEEDBACK, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface UsageClass{} + + /** + * @hide + */ + @IntDef(prefix = { "USAGE_" }, value = { + USAGE_UNKNOWN, + USAGE_ALARM, + USAGE_RINGTONE, + USAGE_NOTIFICATION, + USAGE_COMMUNICATION_REQUEST, + USAGE_TOUCH, + USAGE_PHYSICAL_EMULATION, + USAGE_HARDWARE_FEEDBACK, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface Usage{} + + /** + * Vibration usage class value to use when the vibration usage class is unknown. + */ + public static final int USAGE_CLASS_UNKNOWN = 0x0; + /** + * Vibration usage class value to use when the vibration is initiated to catch user's + * attention, such as alarm, ringtone, and notification vibrations. + */ + public static final int USAGE_CLASS_ALARM = 0x1; + /** + * Vibration usage class value to use when the vibration is initiated as a response to user's + * actions, such as emulation of physical effects, and texting feedback vibration. + */ + public static final int USAGE_CLASS_FEEDBACK = 0x2; + + /** + * Mask for vibration usage class value. + */ + public static final int USAGE_CLASS_MASK = 0xF; + + /** + * Usage value to use when usage is unknown. + */ + public static final int USAGE_UNKNOWN = 0x0 | USAGE_CLASS_UNKNOWN; + /** + * Usage value to use for alarm vibrations. + */ + public static final int USAGE_ALARM = 0x10 | USAGE_CLASS_ALARM; + /** + * Usage value to use for ringtone vibrations. + */ + public static final int USAGE_RINGTONE = 0x20 | USAGE_CLASS_ALARM; + /** + * Usage value to use for notification vibrations. + */ + public static final int USAGE_NOTIFICATION = 0x30 | USAGE_CLASS_ALARM; + /** + * Usage value to use for vibrations which mean a request to enter/end a + * communication, such as a VoIP communication or video-conference. + */ + public static final int USAGE_COMMUNICATION_REQUEST = 0x40 | USAGE_CLASS_ALARM; + /** + * Usage value to use for touch vibrations. + */ + public static final int USAGE_TOUCH = 0x10 | USAGE_CLASS_FEEDBACK; + /** + * Usage value to use for vibrations which emulate physical effects, such as edge squeeze. + */ + public static final int USAGE_PHYSICAL_EMULATION = 0x20 | USAGE_CLASS_FEEDBACK; + /** + * Usage value to use for vibrations which provide a feedback for hardware interaction, + * such as a fingerprint sensor. + */ + public static final int USAGE_HARDWARE_FEEDBACK = 0x30 | USAGE_CLASS_FEEDBACK; + + /** + * @hide + */ + @IntDef(prefix = { "FLAG_" }, value = { + FLAG_BYPASS_INTERRUPTION_POLICY, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface Flag{} + + /** + * Flag requesting vibration effect to be played even under limited interruptions. + */ + public static final int FLAG_BYPASS_INTERRUPTION_POLICY = 0x1; + + // If a vibration is playing for longer than 5s, it's probably not haptic feedback + private static final long MAX_HAPTIC_FEEDBACK_DURATION = 5000; + + private final int mUsage; + private final int mFlags; + + private final AudioAttributes mAudioAttributes; + + private VibrationAttributes(int usage, int flags, @NonNull AudioAttributes audio) { + mUsage = usage; + mFlags = flags; + mAudioAttributes = audio; + } + + /** + * Return the vibration usage class. + * @return USAGE_CLASS_ALARM, USAGE_CLASS_FEEDBACK or USAGE_CLASS_UNKNOWN + */ + public int getUsageClass() { + return mUsage & USAGE_CLASS_MASK; + } + + /** + * Return the vibration usage. + * @return one of the values that can be set in {@link Builder#setUsage(int)} + */ + public int getUsage() { + return mUsage; + } + + /** + * Return the flags. + * @return a combined mask of all flags + */ + public int getFlags() { + return mFlags; + } + + /** + * Check whether a flag is set + * @return true if a flag is set and false otherwise + */ + public boolean isFlagSet(int flag) { + return (mFlags & flag) > 0; + } + + /** + * Return AudioAttributes equivalent to this VibrationAttributes. + * @deprecated Temporary support of AudioAttributes, will be removed when out of WIP + * @hide + */ + @Deprecated + @TestApi + public @NonNull AudioAttributes getAudioAttributes() { + return mAudioAttributes; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeInt(mUsage); + dest.writeInt(mFlags); + dest.writeParcelable(mAudioAttributes, flags); + } + + private VibrationAttributes(Parcel src) { + mUsage = src.readInt(); + mFlags = src.readInt(); + mAudioAttributes = (AudioAttributes) src.readParcelable( + AudioAttributes.class.getClassLoader()); + } + + public static final @NonNull Parcelable.Creator<VibrationAttributes> + CREATOR = new Parcelable.Creator<VibrationAttributes>() { + public VibrationAttributes createFromParcel(Parcel p) { + return new VibrationAttributes(p); + } + public VibrationAttributes[] newArray(int size) { + return new VibrationAttributes[size]; + } + }; + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + VibrationAttributes rhs = (VibrationAttributes) o; + return mUsage == rhs.mUsage && mFlags == rhs.mFlags; + } + + @Override + public int hashCode() { + return Objects.hash(mUsage, mFlags); + } + + @Override + public String toString() { + return "VibrationAttributes:" + + " Usage=" + usageToString() + + " Flags=" + mFlags; + } + + /** @hide */ + public String usageToString() { + return usageToString(mUsage); + } + + /** @hide */ + public String usageToString(int usage) { + switch (usage) { + case USAGE_UNKNOWN: + return "UNKNOWN"; + case USAGE_ALARM: + return "ALARM"; + case USAGE_RINGTONE: + return "RIGNTONE"; + case USAGE_NOTIFICATION: + return "NOTIFICATION"; + case USAGE_COMMUNICATION_REQUEST: + return "COMMUNICATION_REQUEST"; + case USAGE_TOUCH: + return "TOUCH"; + case USAGE_PHYSICAL_EMULATION: + return "PHYSICAL_EMULATION"; + case USAGE_HARDWARE_FEEDBACK: + return "HARDWARE_FEEDBACK"; + default: + return "unknown usage " + usage; + } + } + + /** + * Builder class for {@link VibrationAttributes} objects. + * By default, all information is set to UNKNOWN. + */ + public static final class Builder { + private int mUsage = USAGE_UNKNOWN; + private int mFlags = 0x0; + + private AudioAttributes mAudioAttributes = new AudioAttributes.Builder().build(); + + /** + * Constructs a new Builder with the defaults. + */ + public Builder() { + } + + /** + * Constructs a new Builder from a given VibrationAttributes. + */ + public Builder(@Nullable VibrationAttributes vib) { + if (vib != null) { + mUsage = vib.mUsage; + mFlags = vib.mFlags; + mAudioAttributes = vib.mAudioAttributes; + } + } + + /** + * Constructs a new Builder from AudioAttributes. + * @hide + */ + @TestApi + public Builder(@NonNull AudioAttributes audio, + @Nullable VibrationEffect effect) { + mAudioAttributes = audio; + setUsage(audio); + applyHapticFeedbackHeuristics(effect); + } + + private void applyHapticFeedbackHeuristics(@Nullable VibrationEffect effect) { + if (effect != null) { + if (mUsage == USAGE_UNKNOWN && effect instanceof VibrationEffect.Prebaked) { + VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) effect; + switch (prebaked.getId()) { + case VibrationEffect.EFFECT_CLICK: + case VibrationEffect.EFFECT_DOUBLE_CLICK: + case VibrationEffect.EFFECT_HEAVY_CLICK: + case VibrationEffect.EFFECT_TEXTURE_TICK: + case VibrationEffect.EFFECT_TICK: + case VibrationEffect.EFFECT_POP: + case VibrationEffect.EFFECT_THUD: + mUsage = USAGE_TOUCH; + break; + default: + Slog.w(TAG, "Unknown prebaked vibration effect, assuming it isn't " + + "haptic feedback"); + } + } + final long duration = effect.getDuration(); + if (mUsage == USAGE_UNKNOWN && duration >= 0 + && duration < MAX_HAPTIC_FEEDBACK_DURATION) { + mUsage = USAGE_TOUCH; + } + } + } + + private void setUsage(@NonNull AudioAttributes audio) { + switch (audio.getUsage()) { + case AudioAttributes.USAGE_NOTIFICATION: + case AudioAttributes.USAGE_NOTIFICATION_EVENT: + case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_DELAYED: + case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_INSTANT: + mUsage = USAGE_NOTIFICATION; + break; + case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST: + case AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY: + mUsage = USAGE_COMMUNICATION_REQUEST; + break; + case AudioAttributes.USAGE_NOTIFICATION_RINGTONE: + mUsage = USAGE_RINGTONE; + break; + case AudioAttributes.USAGE_ASSISTANCE_SONIFICATION: + mUsage = USAGE_TOUCH; + break; + case AudioAttributes.USAGE_ALARM: + mUsage = USAGE_ALARM; + break; + default: + mUsage = USAGE_UNKNOWN; + } + } + + /** + * Combines all of the attributes that have been set and returns a new + * {@link VibrationAttributes} object. + * @return a new {@link VibrationAttributes} object + */ + public @NonNull VibrationAttributes build() { + VibrationAttributes ans = new VibrationAttributes(mUsage, mFlags, + mAudioAttributes); + return ans; + } + + /** + * Sets the attribute describing the type of corresponding vibration. + * @param usage one of {@link VibrationAttributes#USAGE_ALARM}, + * {@link VibrationAttributes#USAGE_RINGTONE}, + * {@link VibrationAttributes#USAGE_NOTIFICATION}, + * {@link VibrationAttributes#USAGE_COMMUNICATION_REQUEST}, + * {@link VibrationAttributes#USAGE_TOUCH}, + * {@link VibrationAttributes#USAGE_PHYSICAL_EMULATION}, + * {@link VibrationAttributes#USAGE_HARDWARE_FEEDBACK}. + * @return the same Builder instance. + */ + public @NonNull Builder setUsage(int usage) { + mUsage = usage; + return this; + } + + /** + * Replaces flags + * @param flags any combination of flags. + * @return the same Builder instance. + */ + public @NonNull Builder replaceFlags(int flags) { + mFlags = flags; + return this; + } + } +} + diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java index 76a8f92312ae..27e0d52d78ee 100644 --- a/services/core/java/com/android/server/VibratorService.java +++ b/services/core/java/com/android/server/VibratorService.java @@ -32,7 +32,6 @@ import android.hardware.input.InputManager; import android.hardware.vibrator.IVibrator; import android.hardware.vibrator.V1_0.EffectStrength; import android.icu.text.DateFormat; -import android.media.AudioAttributes; import android.media.AudioManager; import android.os.BatteryStats; import android.os.Binder; @@ -54,6 +53,7 @@ import android.os.ShellCommand; import android.os.SystemClock; import android.os.Trace; import android.os.UserHandle; +import android.os.VibrationAttributes; import android.os.VibrationEffect; import android.os.Vibrator; import android.os.WorkSource; @@ -107,8 +107,9 @@ public class VibratorService extends IVibratorService.Stub private static final int SCALE_VERY_LOW_MAX_AMPLITUDE = 168; // 2/3 * 255 private static final int SCALE_LOW_MAX_AMPLITUDE = 192; // 3/4 * 255 - // If a vibration is playing for longer than 5s, it's probably not haptic feedback. - private static final long MAX_HAPTIC_FEEDBACK_DURATION = 5000; + // Default vibration attributes. Used when vibration is requested without attributes + private static final VibrationAttributes DEFAULT_ATTRIBUTES = + new VibrationAttributes.Builder().build(); // If HAL supports callbacks set the timeout to ASYNC_TIMEOUT_MULTIPLIER * duration. private static final long ASYNC_TIMEOUT_MULTIPLIER = 2; @@ -163,7 +164,7 @@ public class VibratorService extends IVibratorService.Stub private int mHapticFeedbackIntensity; private int mNotificationIntensity; private int mRingIntensity; - private SparseArray<Pair<VibrationEffect, AudioAttributes>> mAlwaysOnEffects = + private SparseArray<Pair<VibrationEffect, VibrationAttributes>> mAlwaysOnEffects = new SparseArray<>(); static native boolean vibratorExists(); @@ -207,7 +208,7 @@ public class VibratorService extends IVibratorService.Stub // with other system events, any duration calculations should be done use startTime so as // not to be affected by discontinuities created by RTC adjustments. public final long startTimeDebug; - public final AudioAttributes attrs; + public final VibrationAttributes attrs; public final int uid; public final String opPkg; public final String reason; @@ -220,7 +221,7 @@ public class VibratorService extends IVibratorService.Stub public VibrationEffect originalEffect; private Vibration(IBinder token, VibrationEffect effect, - AudioAttributes attrs, int uid, String opPkg, String reason) { + VibrationAttributes attrs, int uid, String opPkg, String reason) { this.token = token; this.effect = effect; this.startTime = SystemClock.elapsedRealtime(); @@ -253,28 +254,7 @@ public class VibratorService extends IVibratorService.Stub } public boolean isHapticFeedback() { - if (VibratorService.this.isHapticFeedback(attrs.getUsage())) { - return true; - } - if (effect instanceof VibrationEffect.Prebaked) { - VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) effect; - switch (prebaked.getId()) { - case VibrationEffect.EFFECT_CLICK: - case VibrationEffect.EFFECT_DOUBLE_CLICK: - case VibrationEffect.EFFECT_HEAVY_CLICK: - case VibrationEffect.EFFECT_TEXTURE_TICK: - case VibrationEffect.EFFECT_TICK: - case VibrationEffect.EFFECT_POP: - case VibrationEffect.EFFECT_THUD: - return true; - default: - Slog.w(TAG, "Unknown prebaked vibration effect, " - + "assuming it isn't haptic feedback."); - return false; - } - } - final long duration = effect.getDuration(); - return duration >= 0 && duration < MAX_HAPTIC_FEEDBACK_DURATION; + return VibratorService.this.isHapticFeedback(attrs.getUsage()); } public boolean isNotification() { @@ -303,13 +283,13 @@ public class VibratorService extends IVibratorService.Stub private final long mStartTimeDebug; private final VibrationEffect mEffect; private final VibrationEffect mOriginalEffect; - private final AudioAttributes mAttrs; + private final VibrationAttributes mAttrs; private final int mUid; private final String mOpPkg; private final String mReason; - public VibrationInfo(long startTimeDebug, VibrationEffect effect, - VibrationEffect originalEffect, AudioAttributes attrs, int uid, + VibrationInfo(long startTimeDebug, VibrationEffect effect, + VibrationEffect originalEffect, VibrationAttributes attrs, int uid, String opPkg, String reason) { mStartTimeDebug = startTimeDebug; mEffect = effect; @@ -528,7 +508,7 @@ public class VibratorService extends IVibratorService.Stub } @Override // Binder call - public boolean setAlwaysOnEffect(int id, VibrationEffect effect, AudioAttributes attrs) { + public boolean setAlwaysOnEffect(int id, VibrationEffect effect, VibrationAttributes attrs) { if (!hasPermission(android.Manifest.permission.VIBRATE_ALWAYS_ON)) { throw new SecurityException("Requires VIBRATE_ALWAYS_ON permission"); } @@ -550,8 +530,7 @@ public class VibratorService extends IVibratorService.Stub return false; } if (attrs == null) { - attrs = new AudioAttributes.Builder() - .setUsage(AudioAttributes.USAGE_UNKNOWN) + attrs = new VibrationAttributes.Builder() .build(); } synchronized (mLock) { @@ -610,7 +589,7 @@ public class VibratorService extends IVibratorService.Stub @Override // Binder call public void vibrate(int uid, String opPkg, VibrationEffect effect, - @Nullable AudioAttributes attrs, String reason, IBinder token) { + @Nullable VibrationAttributes attrs, String reason, IBinder token) { Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "vibrate, reason = " + reason); try { if (!hasPermission(android.Manifest.permission.VIBRATE)) { @@ -626,18 +605,16 @@ public class VibratorService extends IVibratorService.Stub } if (attrs == null) { - attrs = new AudioAttributes.Builder() - .setUsage(AudioAttributes.USAGE_UNKNOWN) - .build(); + attrs = DEFAULT_ATTRIBUTES; } if (shouldBypassDnd(attrs)) { if (!(hasPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) || hasPermission(android.Manifest.permission.MODIFY_PHONE_STATE) || hasPermission(android.Manifest.permission.MODIFY_AUDIO_ROUTING))) { - final int flags = attrs.getAllFlags() - & ~AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY; - attrs = new AudioAttributes.Builder(attrs).replaceFlags(flags).build(); + final int flags = attrs.getFlags() + & ~VibrationAttributes.FLAG_BYPASS_INTERRUPTION_POLICY; + attrs = new VibrationAttributes.Builder(attrs).replaceFlags(flags).build(); } } @@ -868,18 +845,10 @@ public class VibratorService extends IVibratorService.Stub return true; } - if (vib.attrs.getUsage() == AudioAttributes.USAGE_NOTIFICATION_RINGTONE) { - return true; - } - - if (vib.attrs.getUsage() == AudioAttributes.USAGE_ALARM - || vib.attrs.getUsage() == AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY - || vib.attrs.getUsage() - == AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST) { - return true; - } - - return false; + int usage = vib.attrs.getUsage(); + return usage == VibrationAttributes.USAGE_RINGTONE + || usage == VibrationAttributes.USAGE_ALARM + || usage == VibrationAttributes.USAGE_COMMUNICATION_REQUEST; } private int getCurrentIntensityLocked(Vibration vib) { @@ -968,13 +937,13 @@ public class VibratorService extends IVibratorService.Stub } } - private static boolean shouldBypassDnd(AudioAttributes attrs) { - return (attrs.getAllFlags() & AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY) != 0; + private static boolean shouldBypassDnd(VibrationAttributes attrs) { + return attrs.isFlagSet(VibrationAttributes.FLAG_BYPASS_INTERRUPTION_POLICY); } private int getAppOpMode(Vibration vib) { int mode = mAppOps.checkAudioOpNoThrow(AppOpsManager.OP_VIBRATE, - vib.attrs.getUsage(), vib.uid, vib.opPkg); + vib.attrs.getAudioAttributes().getUsage(), vib.uid, vib.opPkg); if (mode == AppOpsManager.MODE_ALLOWED) { mode = mAppOps.startOpNoThrow(AppOpsManager.OP_VIBRATE, vib.uid, vib.opPkg); } @@ -1100,7 +1069,7 @@ public class VibratorService extends IVibratorService.Stub mVibrator.getDefaultRingVibrationIntensity(), UserHandle.USER_CURRENT); } - private void updateAlwaysOnLocked(int id, VibrationEffect effect, AudioAttributes attrs) { + private void updateAlwaysOnLocked(int id, VibrationEffect effect, VibrationAttributes attrs) { // TODO: Check DND and LowPower settings final Vibration vib = new Vibration(null, effect, attrs, 0, null, null); final int intensity = getCurrentIntensityLocked(vib); @@ -1116,7 +1085,7 @@ public class VibratorService extends IVibratorService.Stub private void updateAlwaysOnLocked() { for (int i = 0; i < mAlwaysOnEffects.size(); i++) { int id = mAlwaysOnEffects.keyAt(i); - Pair<VibrationEffect, AudioAttributes> pair = mAlwaysOnEffects.valueAt(i); + Pair<VibrationEffect, VibrationAttributes> pair = mAlwaysOnEffects.valueAt(i); updateAlwaysOnLocked(id, pair.first, pair.second); } } @@ -1148,7 +1117,7 @@ public class VibratorService extends IVibratorService.Stub return vibratorExists(); } - private void doVibratorOn(long millis, int amplitude, int uid, AudioAttributes attrs) { + private void doVibratorOn(long millis, int amplitude, int uid, VibrationAttributes attrs) { Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "doVibratorOn"); try { synchronized (mInputDeviceVibrators) { @@ -1163,7 +1132,7 @@ public class VibratorService extends IVibratorService.Stub final int vibratorCount = mInputDeviceVibrators.size(); if (vibratorCount != 0) { for (int i = 0; i < vibratorCount; i++) { - mInputDeviceVibrators.get(i).vibrate(millis, attrs); + mInputDeviceVibrators.get(i).vibrate(millis, attrs.getAudioAttributes()); } } else { // Note: ordering is important here! Many haptic drivers will reset their @@ -1272,28 +1241,19 @@ public class VibratorService extends IVibratorService.Stub } private static boolean isNotification(int usageHint) { - switch (usageHint) { - case AudioAttributes.USAGE_NOTIFICATION: - case AudioAttributes.USAGE_NOTIFICATION_EVENT: - case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST: - case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_INSTANT: - case AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_DELAYED: - return true; - default: - return false; - } + return usageHint == VibrationAttributes.USAGE_NOTIFICATION; } private static boolean isRingtone(int usageHint) { - return usageHint == AudioAttributes.USAGE_NOTIFICATION_RINGTONE; + return usageHint == VibrationAttributes.USAGE_RINGTONE; } private static boolean isHapticFeedback(int usageHint) { - return usageHint == AudioAttributes.USAGE_ASSISTANCE_SONIFICATION; + return usageHint == VibrationAttributes.USAGE_TOUCH; } private static boolean isAlarm(int usageHint) { - return usageHint == AudioAttributes.USAGE_ALARM; + return usageHint == VibrationAttributes.USAGE_ALARM; } private void noteVibratorOnLocked(int uid, long millis) { @@ -1332,11 +1292,11 @@ public class VibratorService extends IVibratorService.Stub private class VibrateThread extends Thread { private final VibrationEffect.Waveform mWaveform; private final int mUid; - private final AudioAttributes mAttrs; + private final VibrationAttributes mAttrs; private boolean mForceStop; - VibrateThread(VibrationEffect.Waveform waveform, int uid, AudioAttributes attrs) { + VibrateThread(VibrationEffect.Waveform waveform, int uid, VibrationAttributes attrs) { mWaveform = waveform; mUid = uid; mAttrs = attrs; @@ -1600,7 +1560,7 @@ public class VibratorService extends IVibratorService.Stub Slog.e(TAG, "Playing external vibration: " + vib); } } - final int usage = vib.getAudioAttributes().getUsage(); + final int usage = vib.getVibrationAttributes().getUsage(); final int defaultIntensity; final int currentIntensity; if (isRingtone(usage)) { @@ -1731,7 +1691,7 @@ public class VibratorService extends IVibratorService.Stub VibrationEffect effect = VibrationEffect.createOneShot(duration, VibrationEffect.DEFAULT_AMPLITUDE); - AudioAttributes attrs = createAudioAttributes(commonOptions); + VibrationAttributes attrs = createVibrationAttributes(commonOptions); vibrate(Binder.getCallingUid(), description, effect, attrs, "Shell Command", mToken); return 0; @@ -1792,7 +1752,7 @@ public class VibratorService extends IVibratorService.Stub amplitudesList.stream().mapToInt(Integer::intValue).toArray(); effect = VibrationEffect.createWaveform(timings, amplitudes, repeat); } - AudioAttributes attrs = createAudioAttributes(commonOptions); + VibrationAttributes attrs = createVibrationAttributes(commonOptions); vibrate(Binder.getCallingUid(), description, effect, attrs, "Shell Command", mToken); return 0; @@ -1824,7 +1784,7 @@ public class VibratorService extends IVibratorService.Stub VibrationEffect effect = VibrationEffect.get(id, false); - AudioAttributes attrs = createAudioAttributes(commonOptions); + VibrationAttributes attrs = createVibrationAttributes(commonOptions); vibrate(Binder.getCallingUid(), description, effect, attrs, "Shell Command", mToken); return 0; @@ -1833,13 +1793,13 @@ public class VibratorService extends IVibratorService.Stub } } - private AudioAttributes createAudioAttributes(CommonOptions commonOptions) { + private VibrationAttributes createVibrationAttributes(CommonOptions commonOptions) { final int flags = commonOptions.force - ? AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY + ? VibrationAttributes.FLAG_BYPASS_INTERRUPTION_POLICY : 0; - return new AudioAttributes.Builder() - .setUsage(AudioAttributes.USAGE_UNKNOWN) - .setFlags(flags) + return new VibrationAttributes.Builder() + .setUsage(VibrationAttributes.USAGE_UNKNOWN) + .replaceFlags(flags) .build(); } diff --git a/tests/permission/src/com/android/framework/permission/tests/VibratorServicePermissionTest.java b/tests/permission/src/com/android/framework/permission/tests/VibratorServicePermissionTest.java index c50229ae30f4..d1d6a26790fd 100644 --- a/tests/permission/src/com/android/framework/permission/tests/VibratorServicePermissionTest.java +++ b/tests/permission/src/com/android/framework/permission/tests/VibratorServicePermissionTest.java @@ -16,12 +16,12 @@ package com.android.framework.permission.tests; -import android.media.AudioAttributes; import android.os.Binder; import android.os.IVibratorService; import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; +import android.os.VibrationAttributes; import android.os.VibrationEffect; import android.test.suitebuilder.annotation.SmallTest; @@ -52,8 +52,8 @@ public class VibratorServicePermissionTest extends TestCase { try { final VibrationEffect effect = VibrationEffect.createOneShot(100, VibrationEffect.DEFAULT_AMPLITUDE); - final AudioAttributes attrs = new AudioAttributes.Builder() - .setUsage(AudioAttributes.USAGE_ALARM) + final VibrationAttributes attrs = new VibrationAttributes.Builder() + .setUsage(VibrationAttributes.USAGE_ALARM) .build(); mVibratorService.vibrate(Process.myUid(), null, effect, attrs, "testVibrate", new Binder()); |