1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.vibrator; 18 19 import android.os.SystemClock; 20 import android.os.VibrationEffect; 21 import android.util.Slog; 22 23 import java.util.Arrays; 24 import java.util.List; 25 26 /** 27 * Represent a step on a single vibrator that plays one or more segments from a 28 * {@link VibrationEffect.Composed} effect. 29 */ 30 abstract class AbstractVibratorStep extends Step { 31 public final VibratorController controller; 32 public final VibrationEffect.Composed effect; 33 public final int segmentIndex; 34 35 long mVibratorOnResult; 36 long mPendingVibratorOffDeadline; 37 boolean mVibratorCompleteCallbackReceived; 38 39 /** 40 * @param conductor The VibrationStepConductor for these steps. 41 * @param startTime The time to schedule this step in the 42 * {@link VibrationStepConductor}. 43 * @param controller The vibrator that is playing the effect. 44 * @param effect The effect being played in this step. 45 * @param index The index of the next segment to be played by this step 46 * @param pendingVibratorOffDeadline The time the vibrator is expected to complete any 47 * previous vibration and turn off. This is used to allow this step to 48 * be triggered when the completion callback is received, and can 49 * be used to play effects back-to-back. 50 */ AbstractVibratorStep(VibrationStepConductor conductor, long startTime, VibratorController controller, VibrationEffect.Composed effect, int index, long pendingVibratorOffDeadline)51 AbstractVibratorStep(VibrationStepConductor conductor, long startTime, 52 VibratorController controller, VibrationEffect.Composed effect, int index, 53 long pendingVibratorOffDeadline) { 54 super(conductor, startTime); 55 this.controller = controller; 56 this.effect = effect; 57 this.segmentIndex = index; 58 mPendingVibratorOffDeadline = pendingVibratorOffDeadline; 59 } 60 getVibratorId()61 public int getVibratorId() { 62 return controller.getVibratorInfo().getId(); 63 } 64 65 @Override getVibratorOnDuration()66 public long getVibratorOnDuration() { 67 return mVibratorOnResult; 68 } 69 70 @Override acceptVibratorCompleteCallback(int vibratorId)71 public boolean acceptVibratorCompleteCallback(int vibratorId) { 72 if (getVibratorId() != vibratorId) { 73 return false; 74 } 75 76 // Only activate this step if a timeout was set to wait for the vibration to complete, 77 // otherwise we are waiting for the correct time to play the next step. 78 boolean shouldAcceptCallback = mPendingVibratorOffDeadline > SystemClock.uptimeMillis(); 79 if (VibrationThread.DEBUG) { 80 Slog.d(VibrationThread.TAG, 81 "Received completion callback from " + vibratorId 82 + ", accepted = " + shouldAcceptCallback); 83 } 84 85 // The callback indicates this vibrator has stopped, reset the timeout. 86 mPendingVibratorOffDeadline = 0; 87 mVibratorCompleteCallbackReceived = true; 88 return shouldAcceptCallback; 89 } 90 91 @Override cancel()92 public List<Step> cancel() { 93 return Arrays.asList(new CompleteEffectVibratorStep(conductor, SystemClock.uptimeMillis(), 94 /* cancelled= */ true, controller, mPendingVibratorOffDeadline)); 95 } 96 97 @Override cancelImmediately()98 public void cancelImmediately() { 99 if (mPendingVibratorOffDeadline > SystemClock.uptimeMillis()) { 100 // Vibrator might be running from previous steps, so turn it off while canceling. 101 stopVibrating(); 102 } 103 } 104 handleVibratorOnResult(long vibratorOnResult)105 protected long handleVibratorOnResult(long vibratorOnResult) { 106 mVibratorOnResult = vibratorOnResult; 107 if (VibrationThread.DEBUG) { 108 Slog.d(VibrationThread.TAG, 109 "Turned on vibrator " + getVibratorId() + ", result = " + mVibratorOnResult); 110 } 111 if (mVibratorOnResult > 0) { 112 // Vibrator was turned on by this step, with vibratorOnResult as the duration. 113 // Set an extra timeout to wait for the vibrator completion callback. 114 mPendingVibratorOffDeadline = SystemClock.uptimeMillis() + mVibratorOnResult 115 + VibrationStepConductor.CALLBACKS_EXTRA_TIMEOUT; 116 } else { 117 // Vibrator does not support the request or failed to turn on, reset callback deadline. 118 mPendingVibratorOffDeadline = 0; 119 } 120 return mVibratorOnResult; 121 } 122 stopVibrating()123 protected void stopVibrating() { 124 if (VibrationThread.DEBUG) { 125 Slog.d(VibrationThread.TAG, 126 "Turning off vibrator " + getVibratorId()); 127 } 128 controller.off(); 129 getVibration().stats.reportVibratorOff(); 130 mPendingVibratorOffDeadline = 0; 131 } 132 changeAmplitude(float amplitude)133 protected void changeAmplitude(float amplitude) { 134 if (VibrationThread.DEBUG) { 135 Slog.d(VibrationThread.TAG, 136 "Amplitude changed on vibrator " + getVibratorId() + " to " + amplitude); 137 } 138 controller.setAmplitude(amplitude); 139 getVibration().stats.reportSetAmplitude(); 140 } 141 142 /** 143 * Return the {@link VibrationStepConductor#nextVibrateStep} with start and off timings 144 * calculated from {@link #getVibratorOnDuration()} based on the current 145 * {@link SystemClock#uptimeMillis()} and jumping all played segments from the effect. 146 */ nextSteps(int segmentsPlayed)147 protected List<Step> nextSteps(int segmentsPlayed) { 148 // Schedule next steps to run right away. 149 long nextStartTime = SystemClock.uptimeMillis(); 150 if (mVibratorOnResult > 0) { 151 // Vibrator was turned on by this step, with mVibratorOnResult as the duration. 152 // Schedule next steps for right after the vibration finishes. 153 nextStartTime += mVibratorOnResult; 154 } 155 return nextSteps(nextStartTime, segmentsPlayed); 156 } 157 158 /** 159 * Return the {@link VibrationStepConductor#nextVibrateStep} with given start time, 160 * which might be calculated independently, and jumping all played segments from the effect. 161 * 162 * <p>This should be used when the vibrator on/off state is not responsible for the step 163 * execution timing, e.g. while playing the vibrator amplitudes. 164 */ nextSteps(long nextStartTime, int segmentsPlayed)165 protected List<Step> nextSteps(long nextStartTime, int segmentsPlayed) { 166 int nextSegmentIndex = segmentIndex + segmentsPlayed; 167 int effectSize = effect.getSegments().size(); 168 int repeatIndex = effect.getRepeatIndex(); 169 if (nextSegmentIndex >= effectSize && repeatIndex >= 0) { 170 // Count the loops that were played. 171 int loopSize = effectSize - repeatIndex; 172 int loopSegmentsPlayed = nextSegmentIndex - repeatIndex; 173 getVibration().stats.reportRepetition(loopSegmentsPlayed / loopSize); 174 nextSegmentIndex = repeatIndex + ((nextSegmentIndex - effectSize) % loopSize); 175 } 176 Step nextStep = conductor.nextVibrateStep(nextStartTime, controller, effect, 177 nextSegmentIndex, mPendingVibratorOffDeadline); 178 return nextStep == null ? VibrationStepConductor.EMPTY_STEP_LIST : Arrays.asList(nextStep); 179 } 180 } 181