Merge "Rename VibrationThread fields/methods for clarity."

This commit is contained in:
Simon Bowden
2022-02-17 10:05:56 +00:00
committed by Android (Google) Code Review
3 changed files with 129 additions and 115 deletions

View File

@@ -70,32 +70,42 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient {
private static final List<Step> EMPTY_STEP_LIST = new ArrayList<>();
/** Callbacks for playing a {@link Vibration}. */
interface VibrationCallbacks {
/** Calls into VibratorManager functionality needed for playing a {@link Vibration}. */
interface VibratorManagerHooks {
/**
* Callback triggered before starting a synchronized vibration step. This will be called
* with {@code requiredCapabilities = 0} if no synchronization is required.
* Request the manager to prepare for triggering a synchronized vibration step.
*
* @param requiredCapabilities The required syncing capabilities for this preparation step.
* Expects a combination of values from
* Expect CAP_SYNC and a combination of values from
* IVibratorManager.CAP_PREPARE_* and
* IVibratorManager.CAP_MIXED_TRIGGER_*.
* @param vibratorIds The id of the vibrators to be prepared.
*/
boolean prepareSyncedVibration(long requiredCapabilities, int[] vibratorIds);
/** Callback triggered after synchronized vibrations were prepared. */
/**
* Request the manager to trigger a synchronized vibration. The vibration must already
* have been prepared with {@link #prepareSyncedVibration}.
*/
boolean triggerSyncedVibration(long vibrationId);
/** Callback triggered to cancel a prepared synced vibration. */
/** Tell the manager to cancel a synced vibration. */
void cancelSyncedVibration();
/** Callback triggered when the vibration is complete. */
/**
* Tell the manager that the currently active vibration has completed its vibration, from
* the perspective of the Effect. However, the VibrationThread may still be continuing with
* cleanup tasks, and should not be given new work until {@link #onVibrationThreadReleased}
* is called.
*/
void onVibrationCompleted(long vibrationId, Vibration.Status status);
/** Callback triggered when the vibrators are released after the thread is complete. */
void onVibratorsReleased();
/**
* Tells the manager that the VibrationThread is finished with the previous vibration and
* all of its cleanup tasks, and the vibrators can now be used for another vibration.
*/
void onVibrationThreadReleased();
}
private final Object mLock = new Object();
@@ -105,7 +115,7 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient {
private final VibrationSettings mVibrationSettings;
private final DeviceVibrationEffectAdapter mDeviceEffectAdapter;
private final Vibration mVibration;
private final VibrationCallbacks mCallbacks;
private final VibratorManagerHooks mVibratorManagerHooks;
private final SparseArray<VibratorController> mVibrators = new SparseArray<>();
private final StepQueue mStepQueue = new StepQueue();
@@ -117,11 +127,11 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient {
VibrationThread(Vibration vib, VibrationSettings vibrationSettings,
DeviceVibrationEffectAdapter effectAdapter,
SparseArray<VibratorController> availableVibrators, PowerManager.WakeLock wakeLock,
IBatteryStats batteryStatsService, VibrationCallbacks callbacks) {
IBatteryStats batteryStatsService, VibratorManagerHooks vibratorManagerHooks) {
mVibration = vib;
mVibrationSettings = vibrationSettings;
mDeviceEffectAdapter = effectAdapter;
mCallbacks = callbacks;
mVibratorManagerHooks = vibratorManagerHooks;
mWorkSource = new WorkSource(mVibration.uid);
mWakeLock = wakeLock;
mBatteryStatsService = batteryStatsService;
@@ -163,7 +173,7 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient {
clientVibrationCompleteIfNotAlready(Vibration.Status.FINISHED_UNEXPECTED);
}
} finally {
mCallbacks.onVibratorsReleased();
mVibratorManagerHooks.onVibrationThreadReleased();
}
}
@@ -263,7 +273,7 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient {
private void clientVibrationCompleteIfNotAlready(Vibration.Status completedStatus) {
if (!mCalledVibrationCompleteCallback) {
mCalledVibrationCompleteCallback = true;
mCallbacks.onVibrationCompleted(mVibration.id, completedStatus);
mVibratorManagerHooks.onVibrationCompleted(mVibration.id, completedStatus);
}
}
@@ -272,25 +282,29 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient {
try {
CombinedVibration.Sequential sequentialEffect = toSequential(mVibration.getEffect());
final int sequentialEffectSize = sequentialEffect.getEffects().size();
mStepQueue.offer(new StartVibrateStep(sequentialEffect));
mStepQueue.initializeForEffect(sequentialEffect);
while (!mStepQueue.isEmpty()) {
long waitTime;
while (!mStepQueue.isFinished()) {
long waitMillisBeforeNextStep;
synchronized (mLock) {
waitTime = mStepQueue.calculateWaitTime();
if (waitTime > 0) {
waitMillisBeforeNextStep = mStepQueue.getWaitMillisBeforeNextStep();
if (waitMillisBeforeNextStep > 0) {
try {
mLock.wait(waitTime);
mLock.wait(waitMillisBeforeNextStep);
} catch (InterruptedException e) {
}
}
}
// If we waited, the queue may have changed, so let the loop run again.
if (waitTime <= 0) {
// Only run the next vibration step if we didn't have to wait in this loop.
// If we waited then the queue may have changed, so loop again to re-evaluate
// the scheduling of the queue top element.
if (waitMillisBeforeNextStep <= 0) {
if (DEBUG) {
Slog.d(TAG, "Play vibration consuming next step...");
}
mStepQueue.consumeNext();
// Run the step without holding the main lock, to avoid HAL interactions from
// blocking the thread.
mStepQueue.runNextStep();
}
Vibration.Status status = mStop ? Vibration.Status.CANCELLED
: mStepQueue.calculateVibrationStatus(sequentialEffectSize);
@@ -350,7 +364,7 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient {
}
if (segmentIndex < 0) {
// No more segments to play, last step is to complete the vibration on this vibrator.
return new CompleteStep(startTime, /* cancelled= */ false, controller,
return new EffectCompleteStep(startTime, /* cancelled= */ false, controller,
vibratorOffTimeout);
}
@@ -385,7 +399,7 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient {
@GuardedBy("mLock")
private final Queue<Step> mPendingOnVibratorCompleteSteps = new LinkedList<>();
@GuardedBy("mLock")
private final Queue<Integer> mNotifiedVibrators = new LinkedList<>();
private final Queue<Integer> mCompletionNotifiedVibrators = new LinkedList<>();
@GuardedBy("mLock")
private int mPendingVibrateSteps;
@@ -394,18 +408,16 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient {
@GuardedBy("mLock")
private int mSuccessfulVibratorOnSteps;
@GuardedBy("mLock")
private boolean mWaitToProcessVibratorCallbacks;
private boolean mWaitToProcessVibratorCompleteCallbacks;
public void offer(@NonNull Step step) {
public void initializeForEffect(@NonNull CombinedVibration.Sequential vibration) {
synchronized (mLock) {
if (!step.isCleanUp()) {
mPendingVibrateSteps++;
}
mNextSteps.offer(step);
mPendingVibrateSteps++;
mNextSteps.offer(new StartVibrateStep(vibration));
}
}
public boolean isEmpty() {
public boolean isFinished() {
synchronized (mLock) {
return mPendingOnVibratorCompleteSteps.isEmpty() && mNextSteps.isEmpty();
}
@@ -429,11 +441,11 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient {
}
}
/** Returns the time in millis to wait before calling {@link #consumeNext()}. */
@GuardedBy("mLock")
public long calculateWaitTime() {
/** Returns the time in millis to wait before calling {@link #runNextStep()}. */
@GuardedBy("VibrationThread.this.mLock")
public long getWaitMillisBeforeNextStep() {
if (!mPendingOnVibratorCompleteSteps.isEmpty()) {
// Steps anticipated by vibrator complete callback should be played right away.
// Steps resumed by vibrator complete callback should be played right away.
return 0;
}
Step nextStep = mNextSteps.peek();
@@ -444,7 +456,7 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient {
* Play and remove the step at the top of this queue, and also adds the next steps generated
* to be played next.
*/
public void consumeNext() {
public void runNextStep() {
// Vibrator callbacks should wait until the polled step is played and the next steps are
// added back to the queue, so they can handle the callback.
markWaitToProcessVibratorCallbacks();
@@ -472,7 +484,7 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient {
}
} finally {
synchronized (mLock) {
processVibratorCallbacks();
processVibratorCompleteCallbacks();
}
}
}
@@ -485,10 +497,10 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient {
*/
@GuardedBy("mLock")
public void notifyVibratorComplete(int vibratorId) {
mNotifiedVibrators.offer(vibratorId);
if (!mWaitToProcessVibratorCallbacks) {
mCompletionNotifiedVibrators.offer(vibratorId);
if (!mWaitToProcessVibratorCompleteCallbacks) {
// No step is being played or cancelled now, process the callback right away.
processVibratorCallbacks();
processVibratorCompleteCallbacks();
}
}
@@ -515,7 +527,7 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient {
}
} finally {
synchronized (mLock) {
processVibratorCallbacks();
processVibratorCompleteCallbacks();
}
}
}
@@ -540,7 +552,7 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient {
}
} finally {
synchronized (mLock) {
processVibratorCallbacks();
processVibratorCompleteCallbacks();
}
}
}
@@ -548,7 +560,7 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient {
@Nullable
private Step pollNext() {
synchronized (mLock) {
// Prioritize the steps anticipated by a vibrator complete callback.
// Prioritize the steps resumed by a vibrator complete callback.
if (!mPendingOnVibratorCompleteSteps.isEmpty()) {
return mPendingOnVibratorCompleteSteps.poll();
}
@@ -558,29 +570,29 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient {
private void markWaitToProcessVibratorCallbacks() {
synchronized (mLock) {
mWaitToProcessVibratorCallbacks = true;
mWaitToProcessVibratorCompleteCallbacks = true;
}
}
/**
* Notify the step in this queue that should be anticipated by the vibrator completion
* callback and keep it separate to be consumed by {@link #consumeNext()}.
* Notify the step in this queue that should be resumed by the vibrator completion
* callback and keep it separate to be consumed by {@link #runNextStep()}.
*
* <p>This is a lightweight method that do not trigger any operation from {@link
* VibratorController}, so it can be called directly from a native callback.
*
* <p>This assumes only one of the next steps is waiting on this given vibrator, so the
* first step found will be anticipated by this method, in no particular order.
* first step found will be resumed by this method, in no particular order.
*/
@GuardedBy("mLock")
private void processVibratorCallbacks() {
mWaitToProcessVibratorCallbacks = false;
while (!mNotifiedVibrators.isEmpty()) {
int vibratorId = mNotifiedVibrators.poll();
private void processVibratorCompleteCallbacks() {
mWaitToProcessVibratorCompleteCallbacks = false;
while (!mCompletionNotifiedVibrators.isEmpty()) {
int vibratorId = mCompletionNotifiedVibrators.poll();
Iterator<Step> it = mNextSteps.iterator();
while (it.hasNext()) {
Step step = it.next();
if (step.shouldPlayWhenVibratorComplete(vibratorId)) {
if (step.acceptVibratorCompleteCallback(vibratorId)) {
it.remove();
mPendingOnVibratorCompleteSteps.offer(step);
break;
@@ -637,10 +649,10 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient {
}
/**
* Return true to play this step right after a vibrator has notified vibration completed,
* used to anticipate steps waiting on vibrator callbacks with a timeout.
* Return true to run this step right after a vibrator has notified vibration completed,
* used to resume steps waiting on vibrator callbacks with a timeout.
*/
public boolean shouldPlayWhenVibratorComplete(int vibratorId) {
public boolean acceptVibratorCompleteCallback(int vibratorId) {
return false;
}
@@ -670,7 +682,7 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient {
* add a {@link FinishVibrateStep} to the queue, to be played after all vibrators have finished
* all their individual steps.
*
* <o>If this step does not start any vibrator, it will add a {@link StartVibrateStep} if the
* <p>If this step does not start any vibrator, it will add a {@link StartVibrateStep} if the
* sequential effect isn't finished yet.
*/
private final class StartVibrateStep extends Step {
@@ -805,7 +817,7 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient {
boolean hasTriggered = false;
long maxDuration = 0;
try {
hasPrepared = mCallbacks.prepareSyncedVibration(
hasPrepared = mVibratorManagerHooks.prepareSyncedVibration(
effectMapping.getRequiredSyncCapabilities(),
effectMapping.getVibratorIds());
@@ -821,13 +833,13 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient {
// Check if sync was prepared and if any step was accepted by a vibrator,
// otherwise there is nothing to trigger here.
if (hasPrepared && maxDuration > 0) {
hasTriggered = mCallbacks.triggerSyncedVibration(mVibration.id);
hasTriggered = mVibratorManagerHooks.triggerSyncedVibration(mVibration.id);
}
return maxDuration;
} finally {
if (hasPrepared && !hasTriggered) {
// Trigger has failed or all steps were ignored by the vibrators.
mCallbacks.cancelSyncedVibration();
mVibratorManagerHooks.cancelSyncedVibration();
nextSteps.clear();
} else if (maxDuration < 0) {
// Some vibrator failed without being prepared so other vibrators might be
@@ -910,7 +922,7 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient {
public final long vibratorOffTimeout;
long mVibratorOnResult;
boolean mVibratorCallbackReceived;
boolean mVibratorCompleteCallbackReceived;
/**
* @param startTime The time to schedule this step in the {@link StepQueue}.
@@ -919,7 +931,7 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient {
* @param index The index of the next segment to be played by this step
* @param vibratorOffTimeout The time the vibrator is expected to complete any previous
* vibration and turn off. This is used to allow this step to be
* anticipated when the completion callback is triggered, and can
* triggered when the completion callback is received, and can
* be used play effects back-to-back.
*/
SingleVibratorStep(long startTime, VibratorController controller,
@@ -937,17 +949,17 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient {
}
@Override
public boolean shouldPlayWhenVibratorComplete(int vibratorId) {
public boolean acceptVibratorCompleteCallback(int vibratorId) {
boolean isSameVibrator = controller.getVibratorInfo().getId() == vibratorId;
mVibratorCallbackReceived |= isSameVibrator;
// Only anticipate this step if a timeout was set to wait for the vibration to complete,
mVibratorCompleteCallbackReceived |= isSameVibrator;
// Only activate this step if a timeout was set to wait for the vibration to complete,
// otherwise we are waiting for the correct time to play the next step.
return isSameVibrator && (vibratorOffTimeout > SystemClock.uptimeMillis());
}
@Override
public List<Step> cancel() {
return Arrays.asList(new CompleteStep(SystemClock.uptimeMillis(),
return Arrays.asList(new EffectCompleteStep(SystemClock.uptimeMillis(),
/* cancelled= */ true, controller, vibratorOffTimeout));
}
@@ -1205,10 +1217,10 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient {
* <p>This runs right at the time the vibration is considered to end and will update the pending
* vibrators count. This can turn off the vibrator or slowly ramp it down to zero amplitude.
*/
private final class CompleteStep extends SingleVibratorStep {
private final class EffectCompleteStep extends SingleVibratorStep {
private final boolean mCancelled;
CompleteStep(long startTime, boolean cancelled, VibratorController controller,
EffectCompleteStep(long startTime, boolean cancelled, VibratorController controller,
long vibratorOffTimeout) {
super(startTime, controller, /* effect= */ null, /* index= */ -1, vibratorOffTimeout);
mCancelled = cancelled;
@@ -1232,13 +1244,13 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient {
@Override
public List<Step> play() {
Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "CompleteStep");
Trace.traceBegin(Trace.TRACE_TAG_VIBRATOR, "EffectCompleteStep");
try {
if (DEBUG) {
Slog.d(TAG, "Running " + (mCancelled ? "cancel" : "complete") + " vibration"
+ " step on vibrator " + controller.getVibratorInfo().getId());
}
if (mVibratorCallbackReceived) {
if (mVibratorCompleteCallbackReceived) {
// Vibration completion callback was received by this step, just turn if off
// and skip any clean-up.
stopVibrating();
@@ -1310,7 +1322,7 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient {
Slog.d(TAG, "Ramp down the vibrator amplitude, step with "
+ latency + "ms latency.");
}
if (mVibratorCallbackReceived) {
if (mVibratorCompleteCallbackReceived) {
// Vibration completion callback was received by this step, just turn if off
// and skip the rest of the steps to ramp down the vibrator amplitude.
stopVibrating();
@@ -1337,7 +1349,7 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient {
* Represents a step to turn the vibrator off.
*
* <p>This runs after a timeout on the expected time the vibrator should have finished playing,
* and can anticipated by vibrator complete callbacks.
* and can be brought forward by vibrator complete callbacks.
*/
private final class OffStep extends SingleVibratorStep {
@@ -1389,13 +1401,14 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient {
}
@Override
public boolean shouldPlayWhenVibratorComplete(int vibratorId) {
public boolean acceptVibratorCompleteCallback(int vibratorId) {
if (controller.getVibratorInfo().getId() == vibratorId) {
mVibratorCallbackReceived = true;
mVibratorCompleteCallbackReceived = true;
mNextOffTime = SystemClock.uptimeMillis();
}
// Timings are tightly controlled here, so only anticipate if the vibrator was supposed
// to be ON but has completed prematurely, to turn it back on as soon as possible.
// Timings are tightly controlled here, so only trigger this step if the vibrator was
// supposed to be ON but has completed prematurely, to turn it back on as soon as
// possible.
return mNextOffTime < startTime && controller.getCurrentAmplitude() > 0;
}
@@ -1409,8 +1422,8 @@ final class VibrationThread extends Thread implements IBinder.DeathRecipient {
Slog.d(TAG, "Running amplitude step with " + latency + "ms latency.");
}
if (mVibratorCallbackReceived && latency < 0) {
// This step was anticipated because the vibrator turned off prematurely.
if (mVibratorCompleteCallbackReceived && latency < 0) {
// This step was run early because the vibrator turned off prematurely.
// Turn it back on and return this same step to run at the exact right time.
mNextOffTime = turnVibratorBackOn(/* remainingDuration= */ -latency);
return Arrays.asList(new AmplitudeStep(startTime, controller, effect,

View File

@@ -125,7 +125,8 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
private final long mCapabilities;
private final int[] mVibratorIds;
private final SparseArray<VibratorController> mVibrators;
private final VibrationCallbacks mVibrationCallbacks = new VibrationCallbacks();
private final VibrationThreadCallbacks mVibrationThreadCallbacks =
new VibrationThreadCallbacks();
@GuardedBy("mLock")
private final SparseArray<AlwaysOnVibration> mAlwaysOnEffects = new SparseArray<>();
@GuardedBy("mLock")
@@ -634,7 +635,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
VibrationThread vibThread = new VibrationThread(vib, mVibrationSettings,
mDeviceVibrationEffectAdapter, mVibrators, mWakeLock, mBatteryStatsService,
mVibrationCallbacks);
mVibrationThreadCallbacks);
if (mCurrentVibration == null) {
return startVibrationThreadLocked(vibThread);
@@ -1115,10 +1116,10 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
}
/**
* Implementation of {@link VibrationThread.VibrationCallbacks} that controls synced vibrations
* and reports them when finished.
* Implementation of {@link VibrationThread.VibratorManagerHooks} that controls synced
* vibrations and reports them when finished.
*/
private final class VibrationCallbacks implements VibrationThread.VibrationCallbacks {
private final class VibrationThreadCallbacks implements VibrationThread.VibratorManagerHooks {
@Override
public boolean prepareSyncedVibration(long requiredCapabilities, int[] vibratorIds) {
@@ -1153,7 +1154,7 @@ public class VibratorManagerService extends IVibratorManagerService.Stub {
}
@Override
public void onVibratorsReleased() {
public void onVibrationThreadReleased() {
if (DEBUG) {
Slog.d(TAG, "Vibrators released after finished vibration");
}

View File

@@ -100,7 +100,7 @@ public class VibrationThreadTest {
public MockitoRule mMockitoRule = MockitoJUnit.rule();
@Mock
private VibrationThread.VibrationCallbacks mThreadCallbacks;
private VibrationThread.VibratorManagerHooks mManagerHooks;
@Mock
private VibratorController.OnVibrationCompleteListener mControllerCallbacks;
@Mock
@@ -648,9 +648,9 @@ public class VibrationThreadTest {
VibrationEffect.createOneShot(10, 100)));
verifyCallbacksTriggered(vibrationId, Vibration.Status.FINISHED);
verify(mThreadCallbacks, never()).prepareSyncedVibration(anyLong(), any());
verify(mThreadCallbacks, never()).triggerSyncedVibration(anyLong());
verify(mThreadCallbacks, never()).cancelSyncedVibration();
verify(mManagerHooks, never()).prepareSyncedVibration(anyLong(), any());
verify(mManagerHooks, never()).triggerSyncedVibration(anyLong());
verify(mManagerHooks, never()).cancelSyncedVibration();
}
@Test
@@ -807,8 +807,8 @@ public class VibrationThreadTest {
mockVibrators(vibratorIds);
mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
mVibratorProviders.get(2).setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
when(mThreadCallbacks.prepareSyncedVibration(anyLong(), eq(vibratorIds))).thenReturn(true);
when(mThreadCallbacks.triggerSyncedVibration(eq(vibrationId))).thenReturn(true);
when(mManagerHooks.prepareSyncedVibration(anyLong(), eq(vibratorIds))).thenReturn(true);
when(mManagerHooks.triggerSyncedVibration(eq(vibrationId))).thenReturn(true);
VibrationEffect composed = VibrationEffect.startComposition()
.addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1, 100)
@@ -823,9 +823,9 @@ public class VibrationThreadTest {
waitForCompletion(thread);
long expectedCap = IVibratorManager.CAP_SYNC | IVibratorManager.CAP_PREPARE_COMPOSE;
verify(mThreadCallbacks).prepareSyncedVibration(eq(expectedCap), eq(vibratorIds));
verify(mThreadCallbacks).triggerSyncedVibration(eq(vibrationId));
verify(mThreadCallbacks, never()).cancelSyncedVibration();
verify(mManagerHooks).prepareSyncedVibration(eq(expectedCap), eq(vibratorIds));
verify(mManagerHooks).triggerSyncedVibration(eq(vibrationId));
verify(mManagerHooks, never()).cancelSyncedVibration();
verifyCallbacksTriggered(vibrationId, Vibration.Status.FINISHED);
VibrationEffectSegment expected = expectedPrimitive(
@@ -840,8 +840,8 @@ public class VibrationThreadTest {
mockVibrators(vibratorIds);
mVibratorProviders.get(1).setSupportedEffects(VibrationEffect.EFFECT_CLICK);
mVibratorProviders.get(4).setCapabilities(IVibrator.CAP_COMPOSE_EFFECTS);
when(mThreadCallbacks.prepareSyncedVibration(anyLong(), any())).thenReturn(true);
when(mThreadCallbacks.triggerSyncedVibration(anyLong())).thenReturn(true);
when(mManagerHooks.prepareSyncedVibration(anyLong(), any())).thenReturn(true);
when(mManagerHooks.triggerSyncedVibration(anyLong())).thenReturn(true);
long vibrationId = 1;
VibrationEffect composed = VibrationEffect.startComposition()
@@ -863,9 +863,9 @@ public class VibrationThreadTest {
| IVibratorManager.CAP_MIXED_TRIGGER_ON
| IVibratorManager.CAP_MIXED_TRIGGER_PERFORM
| IVibratorManager.CAP_MIXED_TRIGGER_COMPOSE;
verify(mThreadCallbacks).prepareSyncedVibration(eq(expectedCap), eq(vibratorIds));
verify(mThreadCallbacks).triggerSyncedVibration(eq(vibrationId));
verify(mThreadCallbacks, never()).cancelSyncedVibration();
verify(mManagerHooks).prepareSyncedVibration(eq(expectedCap), eq(vibratorIds));
verify(mManagerHooks).triggerSyncedVibration(eq(vibrationId));
verify(mManagerHooks, never()).cancelSyncedVibration();
verifyCallbacksTriggered(vibrationId, Vibration.Status.FINISHED);
}
@@ -875,7 +875,7 @@ public class VibrationThreadTest {
mockVibrators(vibratorIds);
mVibratorProviders.get(1).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
mVibratorProviders.get(2).setCapabilities(IVibrator.CAP_AMPLITUDE_CONTROL);
when(mThreadCallbacks.prepareSyncedVibration(anyLong(), any())).thenReturn(false);
when(mManagerHooks.prepareSyncedVibration(anyLong(), any())).thenReturn(false);
long vibrationId = 1;
CombinedVibration effect = CombinedVibration.startParallel()
@@ -886,9 +886,9 @@ public class VibrationThreadTest {
waitForCompletion(thread);
long expectedCap = IVibratorManager.CAP_SYNC | IVibratorManager.CAP_PREPARE_ON;
verify(mThreadCallbacks).prepareSyncedVibration(eq(expectedCap), eq(vibratorIds));
verify(mThreadCallbacks, never()).triggerSyncedVibration(eq(vibrationId));
verify(mThreadCallbacks, never()).cancelSyncedVibration();
verify(mManagerHooks).prepareSyncedVibration(eq(expectedCap), eq(vibratorIds));
verify(mManagerHooks, never()).triggerSyncedVibration(eq(vibrationId));
verify(mManagerHooks, never()).cancelSyncedVibration();
assertEquals(Arrays.asList(expectedOneShot(10)),
mVibratorProviders.get(1).getEffectSegments());
@@ -903,8 +903,8 @@ public class VibrationThreadTest {
int[] vibratorIds = new int[]{1, 2};
mockVibrators(vibratorIds);
mVibratorProviders.get(2).setSupportedEffects(VibrationEffect.EFFECT_CLICK);
when(mThreadCallbacks.prepareSyncedVibration(anyLong(), any())).thenReturn(true);
when(mThreadCallbacks.triggerSyncedVibration(anyLong())).thenReturn(false);
when(mManagerHooks.prepareSyncedVibration(anyLong(), any())).thenReturn(true);
when(mManagerHooks.triggerSyncedVibration(anyLong())).thenReturn(false);
long vibrationId = 1;
CombinedVibration effect = CombinedVibration.startParallel()
@@ -919,9 +919,9 @@ public class VibrationThreadTest {
| IVibratorManager.CAP_PREPARE_PERFORM
| IVibratorManager.CAP_MIXED_TRIGGER_ON
| IVibratorManager.CAP_MIXED_TRIGGER_PERFORM;
verify(mThreadCallbacks).prepareSyncedVibration(eq(expectedCap), eq(vibratorIds));
verify(mThreadCallbacks).triggerSyncedVibration(eq(vibrationId));
verify(mThreadCallbacks).cancelSyncedVibration();
verify(mManagerHooks).prepareSyncedVibration(eq(expectedCap), eq(vibratorIds));
verify(mManagerHooks).triggerSyncedVibration(eq(vibrationId));
verify(mManagerHooks).cancelSyncedVibration();
assertTrue(mVibratorProviders.get(1).getAmplitudes().isEmpty());
}
@@ -1161,9 +1161,9 @@ public class VibrationThreadTest {
VibrationThread thread = startThreadAndDispatcher(vibrationId, effect);
// Vibration completed but vibrator not yet released.
verify(mThreadCallbacks, timeout(TEST_TIMEOUT_MILLIS)).onVibrationCompleted(eq(vibrationId),
verify(mManagerHooks, timeout(TEST_TIMEOUT_MILLIS)).onVibrationCompleted(eq(vibrationId),
eq(Vibration.Status.FINISHED));
verify(mThreadCallbacks, never()).onVibratorsReleased();
verify(mManagerHooks, never()).onVibrationThreadReleased();
// Thread still running ramp down.
assertTrue(thread.isAlive());
@@ -1177,9 +1177,9 @@ public class VibrationThreadTest {
waitForCompletion(thread);
// Does not cancel already finished vibration, but releases vibrator.
verify(mThreadCallbacks, never()).onVibrationCompleted(eq(vibrationId),
verify(mManagerHooks, never()).onVibrationCompleted(eq(vibrationId),
eq(Vibration.Status.CANCELLED));
verify(mThreadCallbacks).onVibratorsReleased();
verify(mManagerHooks).onVibrationThreadReleased();
}
@Test
@@ -1300,7 +1300,7 @@ public class VibrationThreadTest {
private VibrationThread startThreadAndDispatcher(Vibration vib) {
VibrationThread thread = new VibrationThread(vib, mVibrationSettings, mEffectAdapter,
createVibratorControllers(), mWakeLock, mIBatteryStatsMock, mThreadCallbacks);
createVibratorControllers(), mWakeLock, mIBatteryStatsMock, mManagerHooks);
doAnswer(answer -> {
thread.vibratorComplete(answer.getArgument(0));
return null;
@@ -1380,8 +1380,8 @@ public class VibrationThreadTest {
}
private void verifyCallbacksTriggered(long vibrationId, Vibration.Status expectedStatus) {
verify(mThreadCallbacks).onVibrationCompleted(eq(vibrationId), eq(expectedStatus));
verify(mThreadCallbacks).onVibratorsReleased();
verify(mManagerHooks).onVibrationCompleted(eq(vibrationId), eq(expectedStatus));
verify(mManagerHooks).onVibrationThreadReleased();
}
private final class TestLooperAutoDispatcher extends Thread {