Loading core/java/android/os/IVibratorService.aidl +1 −1 Original line number Diff line number Diff line Loading @@ -24,7 +24,7 @@ interface IVibratorService { boolean hasVibrator(); boolean hasAmplitudeControl(); boolean setAlwaysOnEffect(int id, in VibrationEffect effect, boolean setAlwaysOnEffect(int uid, String opPkg, int alwaysOnId, in VibrationEffect effect, in VibrationAttributes attributes); void vibrate(int uid, String opPkg, in VibrationEffect effect, in VibrationAttributes attributes, String reason, IBinder token); Loading core/java/android/os/SystemVibrator.java +3 −2 Original line number Diff line number Diff line Loading @@ -70,14 +70,15 @@ public class SystemVibrator extends Vibrator { } @Override public boolean setAlwaysOnEffect(int id, VibrationEffect effect, AudioAttributes attributes) { public boolean setAlwaysOnEffect(int uid, String opPkg, int alwaysOnId, VibrationEffect effect, AudioAttributes attributes) { if (mService == null) { Log.w(TAG, "Failed to set always-on effect; no vibrator service."); return false; } try { VibrationAttributes atr = new VibrationAttributes.Builder(attributes, effect).build(); return mService.setAlwaysOnEffect(id, effect, atr); return mService.setAlwaysOnEffect(uid, opPkg, alwaysOnId, effect, atr); } catch (RemoteException e) { Log.w(TAG, "Failed to set always-on effect.", e); } Loading core/java/android/os/Vibrator.java +12 −3 Original line number Diff line number Diff line Loading @@ -155,7 +155,7 @@ public abstract class Vibrator { /** * Configure an always-on haptics effect. * * @param id The board-specific always-on ID to configure. * @param alwaysOnId The board-specific always-on ID to configure. * @param effect Vibration effect to assign to always-on id. Passing null will disable it. * @param attributes {@link AudioAttributes} corresponding to the vibration. For example, * specify {@link AudioAttributes#USAGE_ALARM} for alarm vibrations or Loading @@ -164,8 +164,17 @@ public abstract class Vibrator { * @hide */ @RequiresPermission(android.Manifest.permission.VIBRATE_ALWAYS_ON) public boolean setAlwaysOnEffect(int id, @Nullable VibrationEffect effect, public boolean setAlwaysOnEffect(int alwaysOnId, @Nullable VibrationEffect effect, @Nullable AudioAttributes attributes) { return setAlwaysOnEffect(Process.myUid(), mPackageName, alwaysOnId, effect, attributes); } /** * @hide */ @RequiresPermission(android.Manifest.permission.VIBRATE_ALWAYS_ON) public boolean setAlwaysOnEffect(int uid, String opPkg, int alwaysOnId, @Nullable VibrationEffect effect, @Nullable AudioAttributes attributes) { Log.w(TAG, "Always-on effects aren't supported"); return false; } Loading services/core/java/com/android/server/VibratorService.java +66 −54 Original line number Diff line number Diff line Loading @@ -61,7 +61,6 @@ import android.provider.DeviceConfig; import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; import android.util.DebugUtils; import android.util.Pair; import android.util.Slog; import android.util.SparseArray; import android.util.StatsLog; Loading Loading @@ -164,8 +163,7 @@ public class VibratorService extends IVibratorService.Stub private int mHapticFeedbackIntensity; private int mNotificationIntensity; private int mRingIntensity; private SparseArray<Pair<VibrationEffect, VibrationAttributes>> mAlwaysOnEffects = new SparseArray<>(); private SparseArray<Vibration> mAlwaysOnEffects = new SparseArray<>(); static native boolean vibratorExists(); static native void vibratorInit(); Loading Loading @@ -461,6 +459,10 @@ public class VibratorService extends IVibratorService.Stub Settings.System.getUriFor(Settings.System.RING_VIBRATION_INTENSITY), true, mSettingObserver, UserHandle.USER_ALL); mContext.getContentResolver().registerContentObserver( Settings.Global.getUriFor(Settings.Global.ZEN_MODE), true, mSettingObserver, UserHandle.USER_ALL); mContext.registerReceiver(new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { Loading Loading @@ -508,7 +510,8 @@ public class VibratorService extends IVibratorService.Stub } @Override // Binder call public boolean setAlwaysOnEffect(int id, VibrationEffect effect, VibrationAttributes attrs) { public boolean setAlwaysOnEffect(int uid, String opPkg, int alwaysOnId, VibrationEffect effect, VibrationAttributes attrs) { if (!hasPermission(android.Manifest.permission.VIBRATE_ALWAYS_ON)) { throw new SecurityException("Requires VIBRATE_ALWAYS_ON permission"); } Loading @@ -518,8 +521,8 @@ public class VibratorService extends IVibratorService.Stub } if (effect == null) { synchronized (mLock) { mAlwaysOnEffects.delete(id); vibratorAlwaysOnDisable(id); mAlwaysOnEffects.delete(alwaysOnId); vibratorAlwaysOnDisable(alwaysOnId); } } else { if (!verifyVibrationEffect(effect)) { Loading @@ -529,13 +532,11 @@ public class VibratorService extends IVibratorService.Stub Slog.e(TAG, "Only prebaked effects supported for always-on."); return false; } if (attrs == null) { attrs = new VibrationAttributes.Builder() .build(); } attrs = fixupVibrationAttributes(attrs); synchronized (mLock) { mAlwaysOnEffects.put(id, Pair.create(effect, attrs)); updateAlwaysOnLocked(id, effect, attrs); Vibration vib = new Vibration(null, effect, attrs, uid, opPkg, null); mAlwaysOnEffects.put(alwaysOnId, vib); updateAlwaysOnLocked(alwaysOnId, vib); } } return true; Loading Loading @@ -575,6 +576,23 @@ public class VibratorService extends IVibratorService.Stub return true; } private VibrationAttributes fixupVibrationAttributes(VibrationAttributes attrs) { if (attrs == null) { 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.getFlags() & ~VibrationAttributes.FLAG_BYPASS_INTERRUPTION_POLICY; attrs = new VibrationAttributes.Builder(attrs).replaceFlags(flags).build(); } } return attrs; } private static long[] getLongIntArray(Resources r, int resid) { int[] ar = r.getIntArray(resid); if (ar == null) { Loading Loading @@ -604,19 +622,7 @@ public class VibratorService extends IVibratorService.Stub return; } if (attrs == null) { 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.getFlags() & ~VibrationAttributes.FLAG_BYPASS_INTERRUPTION_POLICY; attrs = new VibrationAttributes.Builder(attrs).replaceFlags(flags).build(); } } attrs = fixupVibrationAttributes(attrs); // If our current vibration is longer than the new vibration and is the same amplitude, // then just let the current one finish. Loading Loading @@ -777,29 +783,8 @@ public class VibratorService extends IVibratorService.Stub private void startVibrationLocked(final Vibration vib) { Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "startVibrationLocked"); try { if (!isAllowedToVibrateLocked(vib)) { return; } final int intensity = getCurrentIntensityLocked(vib); if (intensity == Vibrator.VIBRATION_INTENSITY_OFF) { return; } if (vib.isRingtone() && !shouldVibrateForRingtone()) { if (DEBUG) { Slog.e(TAG, "Vibrate ignored, not vibrating for ringtones"); } return; } final int mode = getAppOpMode(vib); if (mode != AppOpsManager.MODE_ALLOWED) { if (mode == AppOpsManager.MODE_ERRORED) { // We might be getting calls from within system_server, so we don't actually // want to throw a SecurityException here. Slog.w(TAG, "Would be an error: vibrate from uid " + vib.uid); } if (!shouldVibrate(vib, intensity)) { return; } applyVibrationIntensityScalingLocked(vib, intensity); Loading Loading @@ -958,6 +943,35 @@ public class VibratorService extends IVibratorService.Stub return mode; } private boolean shouldVibrate(Vibration vib, int intensity) { if (!isAllowedToVibrateLocked(vib)) { return false; } if (intensity == Vibrator.VIBRATION_INTENSITY_OFF) { return false; } if (vib.isRingtone() && !shouldVibrateForRingtone()) { if (DEBUG) { Slog.e(TAG, "Vibrate ignored, not vibrating for ringtones"); } return false; } final int mode = getAppOpMode(vib); if (mode != AppOpsManager.MODE_ALLOWED) { if (mode == AppOpsManager.MODE_ERRORED) { // We might be getting calls from within system_server, so we don't actually // want to throw a SecurityException here. Slog.w(TAG, "Would be an error: vibrate from uid " + vib.uid); } return false; } return true; } @GuardedBy("mLock") private void reportFinishVibrationLocked() { Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "reportFinishVibrationLocked"); Loading Loading @@ -1069,14 +1083,12 @@ public class VibratorService extends IVibratorService.Stub mVibrator.getDefaultRingVibrationIntensity(), UserHandle.USER_CURRENT); } 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); private void updateAlwaysOnLocked(int id, Vibration vib) { final int intensity = getCurrentIntensityLocked(vib); if (intensity == Vibrator.VIBRATION_INTENSITY_OFF) { if (!shouldVibrate(vib, intensity)) { vibratorAlwaysOnDisable(id); } else { final VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) effect; final VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) vib.effect; final int strength = intensityToEffectStrength(intensity); vibratorAlwaysOnEnable(id, prebaked.getId(), strength); } Loading @@ -1085,8 +1097,8 @@ public class VibratorService extends IVibratorService.Stub private void updateAlwaysOnLocked() { for (int i = 0; i < mAlwaysOnEffects.size(); i++) { int id = mAlwaysOnEffects.keyAt(i); Pair<VibrationEffect, VibrationAttributes> pair = mAlwaysOnEffects.valueAt(i); updateAlwaysOnLocked(id, pair.first, pair.second); Vibration vib = mAlwaysOnEffects.valueAt(i); updateAlwaysOnLocked(id, vib); } } Loading Loading
core/java/android/os/IVibratorService.aidl +1 −1 Original line number Diff line number Diff line Loading @@ -24,7 +24,7 @@ interface IVibratorService { boolean hasVibrator(); boolean hasAmplitudeControl(); boolean setAlwaysOnEffect(int id, in VibrationEffect effect, boolean setAlwaysOnEffect(int uid, String opPkg, int alwaysOnId, in VibrationEffect effect, in VibrationAttributes attributes); void vibrate(int uid, String opPkg, in VibrationEffect effect, in VibrationAttributes attributes, String reason, IBinder token); Loading
core/java/android/os/SystemVibrator.java +3 −2 Original line number Diff line number Diff line Loading @@ -70,14 +70,15 @@ public class SystemVibrator extends Vibrator { } @Override public boolean setAlwaysOnEffect(int id, VibrationEffect effect, AudioAttributes attributes) { public boolean setAlwaysOnEffect(int uid, String opPkg, int alwaysOnId, VibrationEffect effect, AudioAttributes attributes) { if (mService == null) { Log.w(TAG, "Failed to set always-on effect; no vibrator service."); return false; } try { VibrationAttributes atr = new VibrationAttributes.Builder(attributes, effect).build(); return mService.setAlwaysOnEffect(id, effect, atr); return mService.setAlwaysOnEffect(uid, opPkg, alwaysOnId, effect, atr); } catch (RemoteException e) { Log.w(TAG, "Failed to set always-on effect.", e); } Loading
core/java/android/os/Vibrator.java +12 −3 Original line number Diff line number Diff line Loading @@ -155,7 +155,7 @@ public abstract class Vibrator { /** * Configure an always-on haptics effect. * * @param id The board-specific always-on ID to configure. * @param alwaysOnId The board-specific always-on ID to configure. * @param effect Vibration effect to assign to always-on id. Passing null will disable it. * @param attributes {@link AudioAttributes} corresponding to the vibration. For example, * specify {@link AudioAttributes#USAGE_ALARM} for alarm vibrations or Loading @@ -164,8 +164,17 @@ public abstract class Vibrator { * @hide */ @RequiresPermission(android.Manifest.permission.VIBRATE_ALWAYS_ON) public boolean setAlwaysOnEffect(int id, @Nullable VibrationEffect effect, public boolean setAlwaysOnEffect(int alwaysOnId, @Nullable VibrationEffect effect, @Nullable AudioAttributes attributes) { return setAlwaysOnEffect(Process.myUid(), mPackageName, alwaysOnId, effect, attributes); } /** * @hide */ @RequiresPermission(android.Manifest.permission.VIBRATE_ALWAYS_ON) public boolean setAlwaysOnEffect(int uid, String opPkg, int alwaysOnId, @Nullable VibrationEffect effect, @Nullable AudioAttributes attributes) { Log.w(TAG, "Always-on effects aren't supported"); return false; } Loading
services/core/java/com/android/server/VibratorService.java +66 −54 Original line number Diff line number Diff line Loading @@ -61,7 +61,6 @@ import android.provider.DeviceConfig; import android.provider.Settings; import android.provider.Settings.SettingNotFoundException; import android.util.DebugUtils; import android.util.Pair; import android.util.Slog; import android.util.SparseArray; import android.util.StatsLog; Loading Loading @@ -164,8 +163,7 @@ public class VibratorService extends IVibratorService.Stub private int mHapticFeedbackIntensity; private int mNotificationIntensity; private int mRingIntensity; private SparseArray<Pair<VibrationEffect, VibrationAttributes>> mAlwaysOnEffects = new SparseArray<>(); private SparseArray<Vibration> mAlwaysOnEffects = new SparseArray<>(); static native boolean vibratorExists(); static native void vibratorInit(); Loading Loading @@ -461,6 +459,10 @@ public class VibratorService extends IVibratorService.Stub Settings.System.getUriFor(Settings.System.RING_VIBRATION_INTENSITY), true, mSettingObserver, UserHandle.USER_ALL); mContext.getContentResolver().registerContentObserver( Settings.Global.getUriFor(Settings.Global.ZEN_MODE), true, mSettingObserver, UserHandle.USER_ALL); mContext.registerReceiver(new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { Loading Loading @@ -508,7 +510,8 @@ public class VibratorService extends IVibratorService.Stub } @Override // Binder call public boolean setAlwaysOnEffect(int id, VibrationEffect effect, VibrationAttributes attrs) { public boolean setAlwaysOnEffect(int uid, String opPkg, int alwaysOnId, VibrationEffect effect, VibrationAttributes attrs) { if (!hasPermission(android.Manifest.permission.VIBRATE_ALWAYS_ON)) { throw new SecurityException("Requires VIBRATE_ALWAYS_ON permission"); } Loading @@ -518,8 +521,8 @@ public class VibratorService extends IVibratorService.Stub } if (effect == null) { synchronized (mLock) { mAlwaysOnEffects.delete(id); vibratorAlwaysOnDisable(id); mAlwaysOnEffects.delete(alwaysOnId); vibratorAlwaysOnDisable(alwaysOnId); } } else { if (!verifyVibrationEffect(effect)) { Loading @@ -529,13 +532,11 @@ public class VibratorService extends IVibratorService.Stub Slog.e(TAG, "Only prebaked effects supported for always-on."); return false; } if (attrs == null) { attrs = new VibrationAttributes.Builder() .build(); } attrs = fixupVibrationAttributes(attrs); synchronized (mLock) { mAlwaysOnEffects.put(id, Pair.create(effect, attrs)); updateAlwaysOnLocked(id, effect, attrs); Vibration vib = new Vibration(null, effect, attrs, uid, opPkg, null); mAlwaysOnEffects.put(alwaysOnId, vib); updateAlwaysOnLocked(alwaysOnId, vib); } } return true; Loading Loading @@ -575,6 +576,23 @@ public class VibratorService extends IVibratorService.Stub return true; } private VibrationAttributes fixupVibrationAttributes(VibrationAttributes attrs) { if (attrs == null) { 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.getFlags() & ~VibrationAttributes.FLAG_BYPASS_INTERRUPTION_POLICY; attrs = new VibrationAttributes.Builder(attrs).replaceFlags(flags).build(); } } return attrs; } private static long[] getLongIntArray(Resources r, int resid) { int[] ar = r.getIntArray(resid); if (ar == null) { Loading Loading @@ -604,19 +622,7 @@ public class VibratorService extends IVibratorService.Stub return; } if (attrs == null) { 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.getFlags() & ~VibrationAttributes.FLAG_BYPASS_INTERRUPTION_POLICY; attrs = new VibrationAttributes.Builder(attrs).replaceFlags(flags).build(); } } attrs = fixupVibrationAttributes(attrs); // If our current vibration is longer than the new vibration and is the same amplitude, // then just let the current one finish. Loading Loading @@ -777,29 +783,8 @@ public class VibratorService extends IVibratorService.Stub private void startVibrationLocked(final Vibration vib) { Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "startVibrationLocked"); try { if (!isAllowedToVibrateLocked(vib)) { return; } final int intensity = getCurrentIntensityLocked(vib); if (intensity == Vibrator.VIBRATION_INTENSITY_OFF) { return; } if (vib.isRingtone() && !shouldVibrateForRingtone()) { if (DEBUG) { Slog.e(TAG, "Vibrate ignored, not vibrating for ringtones"); } return; } final int mode = getAppOpMode(vib); if (mode != AppOpsManager.MODE_ALLOWED) { if (mode == AppOpsManager.MODE_ERRORED) { // We might be getting calls from within system_server, so we don't actually // want to throw a SecurityException here. Slog.w(TAG, "Would be an error: vibrate from uid " + vib.uid); } if (!shouldVibrate(vib, intensity)) { return; } applyVibrationIntensityScalingLocked(vib, intensity); Loading Loading @@ -958,6 +943,35 @@ public class VibratorService extends IVibratorService.Stub return mode; } private boolean shouldVibrate(Vibration vib, int intensity) { if (!isAllowedToVibrateLocked(vib)) { return false; } if (intensity == Vibrator.VIBRATION_INTENSITY_OFF) { return false; } if (vib.isRingtone() && !shouldVibrateForRingtone()) { if (DEBUG) { Slog.e(TAG, "Vibrate ignored, not vibrating for ringtones"); } return false; } final int mode = getAppOpMode(vib); if (mode != AppOpsManager.MODE_ALLOWED) { if (mode == AppOpsManager.MODE_ERRORED) { // We might be getting calls from within system_server, so we don't actually // want to throw a SecurityException here. Slog.w(TAG, "Would be an error: vibrate from uid " + vib.uid); } return false; } return true; } @GuardedBy("mLock") private void reportFinishVibrationLocked() { Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "reportFinishVibrationLocked"); Loading Loading @@ -1069,14 +1083,12 @@ public class VibratorService extends IVibratorService.Stub mVibrator.getDefaultRingVibrationIntensity(), UserHandle.USER_CURRENT); } 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); private void updateAlwaysOnLocked(int id, Vibration vib) { final int intensity = getCurrentIntensityLocked(vib); if (intensity == Vibrator.VIBRATION_INTENSITY_OFF) { if (!shouldVibrate(vib, intensity)) { vibratorAlwaysOnDisable(id); } else { final VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) effect; final VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) vib.effect; final int strength = intensityToEffectStrength(intensity); vibratorAlwaysOnEnable(id, prebaked.getId(), strength); } Loading @@ -1085,8 +1097,8 @@ public class VibratorService extends IVibratorService.Stub private void updateAlwaysOnLocked() { for (int i = 0; i < mAlwaysOnEffects.size(); i++) { int id = mAlwaysOnEffects.keyAt(i); Pair<VibrationEffect, VibrationAttributes> pair = mAlwaysOnEffects.valueAt(i); updateAlwaysOnLocked(id, pair.first, pair.second); Vibration vib = mAlwaysOnEffects.valueAt(i); updateAlwaysOnLocked(id, vib); } } Loading