Vibrator: Have Always-On Check DND/LowPower Modes
Bug: 145961380 Test: Verify always-on settings changes via dumpsys. Change-Id: I201f04ef1c2bdf7f10961e8c3d9b47cb7a815f11 Signed-off-by: Harpreet \"Eli\" Sangha <eliptus@google.com>
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -164,8 +164,17 @@ public abstract class Vibrator {
|
||||
* @hide
|
||||
*/
|
||||
@RequiresPermission(android.Manifest.permission.VIBRATE_ALWAYS_ON)
|
||||
public boolean setAlwaysOnEffect(int id, @Nullable VibrationEffect effect,
|
||||
@Nullable AudioAttributes attributes) {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -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();
|
||||
@@ -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) {
|
||||
@@ -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");
|
||||
}
|
||||
@@ -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)) {
|
||||
@@ -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;
|
||||
@@ -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) {
|
||||
@@ -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.
|
||||
@@ -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);
|
||||
@@ -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");
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user