Rename VibrationThread fields/methods for clarity.
This change is purely renaming and clarification: no logic changes aside from a very minor refactor at "StepQueue.initializeForEffect" (was "offer") to keep the steps internal. These are groundwork for greater clarity in a larger refactor to follow. Key changes: - Rename "callback" items to have more context: whether they are actual callbacks or just calls into the manager. One is renamed to "hooks" instead because most methods aren't really callbacks. - Rename variables and methods around the handling of the "vibrator complete" callbacks to have their context. - Rename "CompleteStep" to EffectComplete step to confuse less with vibrator-complete callbacks. - Rename StepQueue methods to more accurately reflect their current narrow usage. - Change the word "anticipate" to better describe the case, such as resume/activate. I also had to fix a @GuardedBy annotation to reference mLock properly from the nested object to avoid a lint error. Test: presubmit Bug: 193792066 Change-Id: I552572ce60264b56252b5e3dfd546ee602bc1490
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user