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

Commit 301beddc authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "Vibrator: Have Always-On Check DND/LowPower Modes"

parents ad189b5e 9adedac3
Loading
Loading
Loading
Loading
+2 −1
Original line number Original line Diff line number Diff line
@@ -24,7 +24,8 @@ interface IVibratorService
{
{
    boolean hasVibrator();
    boolean hasVibrator();
    boolean hasAmplitudeControl();
    boolean hasAmplitudeControl();
    boolean setAlwaysOnEffect(int id, in VibrationEffect effect, in AudioAttributes attributes);
    boolean setAlwaysOnEffect(int uid, String opPkg, int alwaysOnId, in VibrationEffect effect,
            in AudioAttributes attributes);
    void vibrate(int uid, String opPkg, in VibrationEffect effect, in AudioAttributes attributes,
    void vibrate(int uid, String opPkg, in VibrationEffect effect, in AudioAttributes attributes,
            String reason, IBinder token);
            String reason, IBinder token);
    void cancelVibrate(IBinder token);
    void cancelVibrate(IBinder token);
+3 −2
Original line number Original line Diff line number Diff line
@@ -70,13 +70,14 @@ public class SystemVibrator extends Vibrator {
    }
    }


    @Override
    @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) {
        if (mService == null) {
            Log.w(TAG, "Failed to set always-on effect; no vibrator service.");
            Log.w(TAG, "Failed to set always-on effect; no vibrator service.");
            return false;
            return false;
        }
        }
        try {
        try {
            return mService.setAlwaysOnEffect(id, effect, attributes);
            return mService.setAlwaysOnEffect(uid, opPkg, alwaysOnId, effect, attributes);
        } catch (RemoteException e) {
        } catch (RemoteException e) {
            Log.w(TAG, "Failed to set always-on effect.", e);
            Log.w(TAG, "Failed to set always-on effect.", e);
        }
        }
+12 −3
Original line number Original line Diff line number Diff line
@@ -155,7 +155,7 @@ public abstract class Vibrator {
    /**
    /**
     * Configure an always-on haptics effect.
     * 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 effect Vibration effect to assign to always-on id. Passing null will disable it.
     * @param attributes {@link AudioAttributes} corresponding to the vibration. For example,
     * @param attributes {@link AudioAttributes} corresponding to the vibration. For example,
     *        specify {@link AudioAttributes#USAGE_ALARM} for alarm vibrations or
     *        specify {@link AudioAttributes#USAGE_ALARM} for alarm vibrations or
@@ -164,8 +164,17 @@ public abstract class Vibrator {
     * @hide
     * @hide
     */
     */
    @RequiresPermission(android.Manifest.permission.VIBRATE_ALWAYS_ON)
    @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) {
            @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");
        Log.w(TAG, "Always-on effects aren't supported");
        return false;
        return false;
    }
    }
+68 −57
Original line number Original line Diff line number Diff line
@@ -60,7 +60,6 @@ import android.provider.DeviceConfig;
import android.provider.Settings;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
import android.provider.Settings.SettingNotFoundException;
import android.util.DebugUtils;
import android.util.DebugUtils;
import android.util.Pair;
import android.util.Slog;
import android.util.Slog;
import android.util.SparseArray;
import android.util.SparseArray;
import android.util.StatsLog;
import android.util.StatsLog;
@@ -162,8 +161,7 @@ public class VibratorService extends IVibratorService.Stub
    private int mHapticFeedbackIntensity;
    private int mHapticFeedbackIntensity;
    private int mNotificationIntensity;
    private int mNotificationIntensity;
    private int mRingIntensity;
    private int mRingIntensity;
    private SparseArray<Pair<VibrationEffect, AudioAttributes>> mAlwaysOnEffects =
    private SparseArray<Vibration> mAlwaysOnEffects = new SparseArray<>();
            new SparseArray<>();


    static native boolean vibratorExists();
    static native boolean vibratorExists();
    static native void vibratorInit();
    static native void vibratorInit();
@@ -477,6 +475,10 @@ public class VibratorService extends IVibratorService.Stub
                    Settings.System.getUriFor(Settings.System.RING_VIBRATION_INTENSITY),
                    Settings.System.getUriFor(Settings.System.RING_VIBRATION_INTENSITY),
                    true, mSettingObserver, UserHandle.USER_ALL);
                    true, mSettingObserver, UserHandle.USER_ALL);


            mContext.getContentResolver().registerContentObserver(
                    Settings.Global.getUriFor(Settings.Global.ZEN_MODE),
                    true, mSettingObserver, UserHandle.USER_ALL);

            mContext.registerReceiver(new BroadcastReceiver() {
            mContext.registerReceiver(new BroadcastReceiver() {
                @Override
                @Override
                public void onReceive(Context context, Intent intent) {
                public void onReceive(Context context, Intent intent) {
@@ -524,7 +526,8 @@ public class VibratorService extends IVibratorService.Stub
    }
    }


    @Override // Binder call
    @Override // Binder call
    public boolean setAlwaysOnEffect(int id, VibrationEffect effect, AudioAttributes attrs) {
    public boolean setAlwaysOnEffect(int uid, String opPkg, int alwaysOnId, VibrationEffect effect,
            AudioAttributes attrs) {
        if (!hasPermission(android.Manifest.permission.VIBRATE_ALWAYS_ON)) {
        if (!hasPermission(android.Manifest.permission.VIBRATE_ALWAYS_ON)) {
            throw new SecurityException("Requires VIBRATE_ALWAYS_ON permission");
            throw new SecurityException("Requires VIBRATE_ALWAYS_ON permission");
        }
        }
@@ -534,8 +537,8 @@ public class VibratorService extends IVibratorService.Stub
        }
        }
        if (effect == null) {
        if (effect == null) {
            synchronized (mLock) {
            synchronized (mLock) {
                mAlwaysOnEffects.delete(id);
                mAlwaysOnEffects.delete(alwaysOnId);
                vibratorAlwaysOnDisable(id);
                vibratorAlwaysOnDisable(alwaysOnId);
            }
            }
        } else {
        } else {
            if (!verifyVibrationEffect(effect)) {
            if (!verifyVibrationEffect(effect)) {
@@ -545,14 +548,11 @@ public class VibratorService extends IVibratorService.Stub
                Slog.e(TAG, "Only prebaked effects supported for always-on.");
                Slog.e(TAG, "Only prebaked effects supported for always-on.");
                return false;
                return false;
            }
            }
            if (attrs == null) {
            attrs = fixupVibrationAttributes(attrs);
                attrs = new AudioAttributes.Builder()
                        .setUsage(AudioAttributes.USAGE_UNKNOWN)
                        .build();
            }
            synchronized (mLock) {
            synchronized (mLock) {
                mAlwaysOnEffects.put(id, Pair.create(effect, attrs));
                Vibration vib = new Vibration(null, effect, attrs, uid, opPkg, null);
                updateAlwaysOnLocked(id, effect, attrs);
                mAlwaysOnEffects.put(alwaysOnId, vib);
                updateAlwaysOnLocked(alwaysOnId, vib);
            }
            }
        }
        }
        return true;
        return true;
@@ -592,6 +592,25 @@ public class VibratorService extends IVibratorService.Stub
        return true;
        return true;
    }
    }


    private AudioAttributes fixupVibrationAttributes(AudioAttributes attrs) {
        if (attrs == null) {
            attrs = new AudioAttributes.Builder()
                    .setUsage(AudioAttributes.USAGE_UNKNOWN)
                    .build();
        }
        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();
            }
        }

        return attrs;
    }

    private static long[] getLongIntArray(Resources r, int resid) {
    private static long[] getLongIntArray(Resources r, int resid) {
        int[] ar = r.getIntArray(resid);
        int[] ar = r.getIntArray(resid);
        if (ar == null) {
        if (ar == null) {
@@ -621,21 +640,7 @@ public class VibratorService extends IVibratorService.Stub
                return;
                return;
            }
            }


            if (attrs == null) {
            attrs = fixupVibrationAttributes(attrs);
                attrs = new AudioAttributes.Builder()
                        .setUsage(AudioAttributes.USAGE_UNKNOWN)
                        .build();
            }

            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();
                }
            }


            // If our current vibration is longer than the new vibration and is the same amplitude,
            // If our current vibration is longer than the new vibration and is the same amplitude,
            // then just let the current one finish.
            // then just let the current one finish.
@@ -796,29 +801,8 @@ public class VibratorService extends IVibratorService.Stub
    private void startVibrationLocked(final Vibration vib) {
    private void startVibrationLocked(final Vibration vib) {
        Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "startVibrationLocked");
        Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "startVibrationLocked");
        try {
        try {
            if (!isAllowedToVibrateLocked(vib)) {
                return;
            }

            final int intensity = getCurrentIntensityLocked(vib);
            final int intensity = getCurrentIntensityLocked(vib);
            if (intensity == Vibrator.VIBRATION_INTENSITY_OFF) {
            if (!shouldVibrate(vib, intensity)) {
                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);
                }
                return;
                return;
            }
            }
            applyVibrationIntensityScalingLocked(vib, intensity);
            applyVibrationIntensityScalingLocked(vib, intensity);
@@ -985,6 +969,35 @@ public class VibratorService extends IVibratorService.Stub
        return mode;
        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")
    @GuardedBy("mLock")
    private void reportFinishVibrationLocked() {
    private void reportFinishVibrationLocked() {
        Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "reportFinishVibrationLocked");
        Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "reportFinishVibrationLocked");
@@ -1096,14 +1109,12 @@ public class VibratorService extends IVibratorService.Stub
                mVibrator.getDefaultRingVibrationIntensity(), UserHandle.USER_CURRENT);
                mVibrator.getDefaultRingVibrationIntensity(), UserHandle.USER_CURRENT);
    }
    }


    private void updateAlwaysOnLocked(int id, VibrationEffect effect, AudioAttributes attrs) {
    private void updateAlwaysOnLocked(int id, Vibration vib) {
        // TODO: Check DND and LowPower settings
        final Vibration vib = new Vibration(null, effect, attrs, 0, null, null);
        final int intensity = getCurrentIntensityLocked(vib);
        final int intensity = getCurrentIntensityLocked(vib);
        if (intensity == Vibrator.VIBRATION_INTENSITY_OFF) {
        if (!shouldVibrate(vib, intensity)) {
            vibratorAlwaysOnDisable(id);
            vibratorAlwaysOnDisable(id);
        } else {
        } else {
            final VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) effect;
            final VibrationEffect.Prebaked prebaked = (VibrationEffect.Prebaked) vib.effect;
            final int strength = intensityToEffectStrength(intensity);
            final int strength = intensityToEffectStrength(intensity);
            vibratorAlwaysOnEnable(id, prebaked.getId(), strength);
            vibratorAlwaysOnEnable(id, prebaked.getId(), strength);
        }
        }
@@ -1112,8 +1123,8 @@ public class VibratorService extends IVibratorService.Stub
    private void updateAlwaysOnLocked() {
    private void updateAlwaysOnLocked() {
        for (int i = 0; i < mAlwaysOnEffects.size(); i++) {
        for (int i = 0; i < mAlwaysOnEffects.size(); i++) {
            int id = mAlwaysOnEffects.keyAt(i);
            int id = mAlwaysOnEffects.keyAt(i);
            Pair<VibrationEffect, AudioAttributes> pair = mAlwaysOnEffects.valueAt(i);
            Vibration vib = mAlwaysOnEffects.valueAt(i);
            updateAlwaysOnLocked(id, pair.first, pair.second);
            updateAlwaysOnLocked(id, vib);
        }
        }
    }
    }