Loading core/java/android/os/VibrationAttributes.java +18 −5 Original line number Diff line number Diff line Loading @@ -146,7 +146,8 @@ public final class VibrationAttributes implements Parcelable { @IntDef(prefix = { "FLAG_" }, flag = true, value = { FLAG_BYPASS_INTERRUPTION_POLICY, FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF, FLAG_INVALIDATE_SETTINGS_CACHE FLAG_INVALIDATE_SETTINGS_CACHE, FLAG_PIPELINED_EFFECT }) @Retention(RetentionPolicy.SOURCE) public @interface Flag{} Loading @@ -157,7 +158,7 @@ public final class VibrationAttributes implements Parcelable { * <p>Only privileged apps can ignore user settings that limit interruptions, and this * flag will be ignored otherwise. */ public static final int FLAG_BYPASS_INTERRUPTION_POLICY = 0x1; public static final int FLAG_BYPASS_INTERRUPTION_POLICY = 1; /** * Flag requesting vibration effect to be played even when user settings are disabling it. Loading @@ -168,7 +169,7 @@ public final class VibrationAttributes implements Parcelable { * * @hide */ public static final int FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF = 0x2; public static final int FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF = 1 << 1; /** * Flag requesting vibration effect to be played with fresh user settings values. Loading @@ -183,7 +184,19 @@ public final class VibrationAttributes implements Parcelable { * * @hide */ public static final int FLAG_INVALIDATE_SETTINGS_CACHE = 0x4; public static final int FLAG_INVALIDATE_SETTINGS_CACHE = 1 << 2; /** * Flag requesting that this vibration effect be pipelined with other vibration effects from the * same package that also carry this flag. * * <p>Pipelined effects won't cancel a running pipelined effect, but will instead play after * it completes. However, only one pipelined effect can be waiting at a time - so if an effect * is already waiting (but not running), it will be cancelled in favor of a newer one. * * @hide */ public static final int FLAG_PIPELINED_EFFECT = 1 << 3; /** * All flags supported by vibrator service, update it when adding new flag. Loading @@ -191,7 +204,7 @@ public final class VibrationAttributes implements Parcelable { */ public static final int FLAG_ALL_SUPPORTED = FLAG_BYPASS_INTERRUPTION_POLICY | FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF | FLAG_INVALIDATE_SETTINGS_CACHE; | FLAG_INVALIDATE_SETTINGS_CACHE | FLAG_PIPELINED_EFFECT; /** Creates a new {@link VibrationAttributes} instance with given usage. */ public static @NonNull VibrationAttributes createForUsage(@Usage int usage) { Loading services/core/java/com/android/server/vibrator/Vibration.java +14 −0 Original line number Diff line number Diff line Loading @@ -251,6 +251,20 @@ final class Vibration { uid, vibrationType, attrs.getUsage(), mStatus, mStats, completionUptimeMillis); } /** * Returns true if this vibration can pipeline with the specified one. * * <p>Note that currently, repeating vibrations can't pipeline with following vibrations, * because the cancel() call to stop the repetition will cancel a pending vibration too. This * can be changed if we have a use-case to reason around behavior for. It may also be nice to * pipeline very short vibrations together, regardless of the flag. */ public boolean canPipelineWith(Vibration vib) { return uid == vib.uid && attrs.isFlagSet(VibrationAttributes.FLAG_PIPELINED_EFFECT) && vib.attrs.isFlagSet(VibrationAttributes.FLAG_PIPELINED_EFFECT) && !isRepeating(); } /** Immutable info passed as a signal to end a vibration. */ static final class EndInfo { /** The {@link Status} to be set to the vibration when it ends with this info. */ Loading services/core/java/com/android/server/vibrator/VibrationStepConductor.java +8 −0 Original line number Diff line number Diff line Loading @@ -281,6 +281,14 @@ final class VibrationStepConductor implements IBinder.DeathRecipient { // to run it before processing callbacks as the window is tiny. Step nextStep = pollNext(); if (nextStep != null) { if (DEBUG) { Slog.d(TAG, "Playing vibration id " + getVibration().id + ((nextStep instanceof AbstractVibratorStep) ? " on vibrator " + ((AbstractVibratorStep) nextStep).getVibratorId() : "") + " " + nextStep.getClass().getSimpleName() + (nextStep.isCleanUp() ? " (cleanup)" : "")); } List<Step> nextSteps = nextStep.play(); if (nextStep.getVibratorOnDuration() > 0) { mSuccessfulVibratorOnSteps++; Loading services/core/java/com/android/server/vibrator/VibrationThread.java +0 −3 Original line number Diff line number Diff line Loading @@ -292,9 +292,6 @@ final class VibrationThread extends Thread { boolean readyToRun = mExecutingConductor.waitUntilNextStepIsDue(); // If we waited, don't run the next step, but instead re-evaluate status. if (readyToRun) { if (DEBUG) { Slog.d(TAG, "Play vibration consuming next step..."); } // Run the step without holding the main lock, to avoid HAL interactions from // blocking the thread. mExecutingConductor.runNextStep(); Loading services/core/java/com/android/server/vibrator/VibratorManagerService.java +24 −8 Original line number Diff line number Diff line Loading @@ -450,6 +450,15 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { final long ident = Binder.clearCallingIdentity(); try { if (mCurrentVibration != null) { if (mCurrentVibration.getVibration().canPipelineWith(vib)) { // Don't cancel the current vibration if it's pipeline-able. // Note that if there is a pending next vibration that can't be // pipelined, it will have already cancelled the current one, so we // don't need to consider it here as well. if (DEBUG) { Slog.d(TAG, "Pipelining vibration " + vib.id); } } else { vib.stats().reportInterruptedAnotherVibration( mCurrentVibration.getVibration().attrs.getUsage()); mCurrentVibration.notifyCancelled( Loading @@ -458,6 +467,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { vib.attrs.getUsage()), /* immediate= */ false); } } status = startVibrationLocked(vib); } finally { Binder.restoreCallingIdentity(ident); Loading Loading @@ -690,6 +700,8 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { } // If there's already a vibration queued (waiting for the previous one to finish // cancelling), end it cleanly and replace it with the new one. // Note that we don't consider pipelining here, because new pipelined ones should // replace pending non-executing pipelined ones anyway. clearNextVibrationLocked( new Vibration.EndInfo(Vibration.Status.IGNORED_SUPERSEDED, vib.uid, vib.attrs.getUsage())); Loading Loading @@ -1594,6 +1606,10 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { @GuardedBy("mLock") private void clearNextVibrationLocked(Vibration.EndInfo vibrationEndInfo) { if (mNextVibration != null) { if (DEBUG) { Slog.d(TAG, "Dropping pending vibration " + mNextVibration.getVibration().id + " with end info: " + vibrationEndInfo); } // Clearing next vibration before playing it, end it and report metrics right away. endVibrationLocked(mNextVibration.getVibration(), vibrationEndInfo, /* shouldWriteStats= */ true); Loading Loading
core/java/android/os/VibrationAttributes.java +18 −5 Original line number Diff line number Diff line Loading @@ -146,7 +146,8 @@ public final class VibrationAttributes implements Parcelable { @IntDef(prefix = { "FLAG_" }, flag = true, value = { FLAG_BYPASS_INTERRUPTION_POLICY, FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF, FLAG_INVALIDATE_SETTINGS_CACHE FLAG_INVALIDATE_SETTINGS_CACHE, FLAG_PIPELINED_EFFECT }) @Retention(RetentionPolicy.SOURCE) public @interface Flag{} Loading @@ -157,7 +158,7 @@ public final class VibrationAttributes implements Parcelable { * <p>Only privileged apps can ignore user settings that limit interruptions, and this * flag will be ignored otherwise. */ public static final int FLAG_BYPASS_INTERRUPTION_POLICY = 0x1; public static final int FLAG_BYPASS_INTERRUPTION_POLICY = 1; /** * Flag requesting vibration effect to be played even when user settings are disabling it. Loading @@ -168,7 +169,7 @@ public final class VibrationAttributes implements Parcelable { * * @hide */ public static final int FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF = 0x2; public static final int FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF = 1 << 1; /** * Flag requesting vibration effect to be played with fresh user settings values. Loading @@ -183,7 +184,19 @@ public final class VibrationAttributes implements Parcelable { * * @hide */ public static final int FLAG_INVALIDATE_SETTINGS_CACHE = 0x4; public static final int FLAG_INVALIDATE_SETTINGS_CACHE = 1 << 2; /** * Flag requesting that this vibration effect be pipelined with other vibration effects from the * same package that also carry this flag. * * <p>Pipelined effects won't cancel a running pipelined effect, but will instead play after * it completes. However, only one pipelined effect can be waiting at a time - so if an effect * is already waiting (but not running), it will be cancelled in favor of a newer one. * * @hide */ public static final int FLAG_PIPELINED_EFFECT = 1 << 3; /** * All flags supported by vibrator service, update it when adding new flag. Loading @@ -191,7 +204,7 @@ public final class VibrationAttributes implements Parcelable { */ public static final int FLAG_ALL_SUPPORTED = FLAG_BYPASS_INTERRUPTION_POLICY | FLAG_BYPASS_USER_VIBRATION_INTENSITY_OFF | FLAG_INVALIDATE_SETTINGS_CACHE; | FLAG_INVALIDATE_SETTINGS_CACHE | FLAG_PIPELINED_EFFECT; /** Creates a new {@link VibrationAttributes} instance with given usage. */ public static @NonNull VibrationAttributes createForUsage(@Usage int usage) { Loading
services/core/java/com/android/server/vibrator/Vibration.java +14 −0 Original line number Diff line number Diff line Loading @@ -251,6 +251,20 @@ final class Vibration { uid, vibrationType, attrs.getUsage(), mStatus, mStats, completionUptimeMillis); } /** * Returns true if this vibration can pipeline with the specified one. * * <p>Note that currently, repeating vibrations can't pipeline with following vibrations, * because the cancel() call to stop the repetition will cancel a pending vibration too. This * can be changed if we have a use-case to reason around behavior for. It may also be nice to * pipeline very short vibrations together, regardless of the flag. */ public boolean canPipelineWith(Vibration vib) { return uid == vib.uid && attrs.isFlagSet(VibrationAttributes.FLAG_PIPELINED_EFFECT) && vib.attrs.isFlagSet(VibrationAttributes.FLAG_PIPELINED_EFFECT) && !isRepeating(); } /** Immutable info passed as a signal to end a vibration. */ static final class EndInfo { /** The {@link Status} to be set to the vibration when it ends with this info. */ Loading
services/core/java/com/android/server/vibrator/VibrationStepConductor.java +8 −0 Original line number Diff line number Diff line Loading @@ -281,6 +281,14 @@ final class VibrationStepConductor implements IBinder.DeathRecipient { // to run it before processing callbacks as the window is tiny. Step nextStep = pollNext(); if (nextStep != null) { if (DEBUG) { Slog.d(TAG, "Playing vibration id " + getVibration().id + ((nextStep instanceof AbstractVibratorStep) ? " on vibrator " + ((AbstractVibratorStep) nextStep).getVibratorId() : "") + " " + nextStep.getClass().getSimpleName() + (nextStep.isCleanUp() ? " (cleanup)" : "")); } List<Step> nextSteps = nextStep.play(); if (nextStep.getVibratorOnDuration() > 0) { mSuccessfulVibratorOnSteps++; Loading
services/core/java/com/android/server/vibrator/VibrationThread.java +0 −3 Original line number Diff line number Diff line Loading @@ -292,9 +292,6 @@ final class VibrationThread extends Thread { boolean readyToRun = mExecutingConductor.waitUntilNextStepIsDue(); // If we waited, don't run the next step, but instead re-evaluate status. if (readyToRun) { if (DEBUG) { Slog.d(TAG, "Play vibration consuming next step..."); } // Run the step without holding the main lock, to avoid HAL interactions from // blocking the thread. mExecutingConductor.runNextStep(); Loading
services/core/java/com/android/server/vibrator/VibratorManagerService.java +24 −8 Original line number Diff line number Diff line Loading @@ -450,6 +450,15 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { final long ident = Binder.clearCallingIdentity(); try { if (mCurrentVibration != null) { if (mCurrentVibration.getVibration().canPipelineWith(vib)) { // Don't cancel the current vibration if it's pipeline-able. // Note that if there is a pending next vibration that can't be // pipelined, it will have already cancelled the current one, so we // don't need to consider it here as well. if (DEBUG) { Slog.d(TAG, "Pipelining vibration " + vib.id); } } else { vib.stats().reportInterruptedAnotherVibration( mCurrentVibration.getVibration().attrs.getUsage()); mCurrentVibration.notifyCancelled( Loading @@ -458,6 +467,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { vib.attrs.getUsage()), /* immediate= */ false); } } status = startVibrationLocked(vib); } finally { Binder.restoreCallingIdentity(ident); Loading Loading @@ -690,6 +700,8 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { } // If there's already a vibration queued (waiting for the previous one to finish // cancelling), end it cleanly and replace it with the new one. // Note that we don't consider pipelining here, because new pipelined ones should // replace pending non-executing pipelined ones anyway. clearNextVibrationLocked( new Vibration.EndInfo(Vibration.Status.IGNORED_SUPERSEDED, vib.uid, vib.attrs.getUsage())); Loading Loading @@ -1594,6 +1606,10 @@ public class VibratorManagerService extends IVibratorManagerService.Stub { @GuardedBy("mLock") private void clearNextVibrationLocked(Vibration.EndInfo vibrationEndInfo) { if (mNextVibration != null) { if (DEBUG) { Slog.d(TAG, "Dropping pending vibration " + mNextVibration.getVibration().id + " with end info: " + vibrationEndInfo); } // Clearing next vibration before playing it, end it and report metrics right away. endVibrationLocked(mNextVibration.getVibration(), vibrationEndInfo, /* shouldWriteStats= */ true); Loading