Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b701ad58 authored by Harpreet \"Eli\" Sangha's avatar Harpreet \"Eli\" Sangha
Browse files

Vibrator: Have Always-On Check DND/LowPower Modes



Bug: 145961380
Test: Verify always-on settings changes via dumpsys.
Change-Id: I201f04ef1c2bdf7f10961e8c3d9b47cb7a815f11
Signed-off-by: default avatarHarpreet \"Eli\" Sangha <eliptus@google.com>
parent f959a319
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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);
+3 −2
Original line number Diff line number Diff line
@@ -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);
        }
+12 −3
Original line number Diff line number Diff line
@@ -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,
    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;
    }
+66 −54
Original line number Diff line number Diff line
@@ -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);
        }
    }