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.annotation.NonNull; 20 import android.os.SystemClock; 21 import android.util.Slog; 22 23 import java.util.Arrays; 24 import java.util.List; 25 26 /** Represent a step on a single vibrator that plays a command on {@link VibratorController}. */ 27 abstract class AbstractVibratorStep extends Step { 28 public final VibratorController controller; 29 30 long mVibratorOnResult; 31 long mPendingVibratorOffDeadline; 32 boolean mVibratorCompleteCallbackReceived; 33 34 /** 35 * @param conductor The VibrationStepConductor for these steps. 36 * @param startTime The time to schedule this step in the 37 * {@link VibrationStepConductor}. 38 * @param controller The vibrator that is playing the effect. 39 * @param pendingVibratorOffDeadline The time the vibrator is expected to complete any 40 * previous vibration and turn off. This is used to allow this step to 41 * be triggered when the completion callback is received, and can 42 * be used to play effects back-to-back. 43 */ AbstractVibratorStep(VibrationStepConductor conductor, long startTime, VibratorController controller, long pendingVibratorOffDeadline)44 AbstractVibratorStep(VibrationStepConductor conductor, long startTime, 45 VibratorController controller, long pendingVibratorOffDeadline) { 46 super(conductor, startTime); 47 this.controller = controller; 48 mPendingVibratorOffDeadline = pendingVibratorOffDeadline; 49 } 50 getVibratorId()51 public int getVibratorId() { 52 return controller.getVibratorInfo().getId(); 53 } 54 55 @Override getVibratorOnDuration()56 public long getVibratorOnDuration() { 57 return mVibratorOnResult; 58 } 59 60 @Override acceptVibratorCompleteCallback(int vibratorId)61 public boolean acceptVibratorCompleteCallback(int vibratorId) { 62 if (getVibratorId() != vibratorId) { 63 return false; 64 } 65 66 // Only activate this step if a timeout was set to wait for the vibration to complete, 67 // otherwise we are waiting for the correct time to play the next step. 68 boolean shouldAcceptCallback = mPendingVibratorOffDeadline > SystemClock.uptimeMillis(); 69 if (VibrationThread.DEBUG) { 70 Slog.d(VibrationThread.TAG, 71 "Received completion callback from " + vibratorId 72 + ", accepted = " + shouldAcceptCallback); 73 } 74 75 // The callback indicates this vibrator has stopped, reset the timeout. 76 mPendingVibratorOffDeadline = 0; 77 mVibratorCompleteCallbackReceived = true; 78 return shouldAcceptCallback; 79 } 80 81 @NonNull 82 @Override cancel()83 public List<Step> cancel() { 84 return Arrays.asList(new CompleteEffectVibratorStep(conductor, SystemClock.uptimeMillis(), 85 /* cancelled= */ true, controller, mPendingVibratorOffDeadline)); 86 } 87 88 @Override cancelImmediately()89 public void cancelImmediately() { 90 if (mPendingVibratorOffDeadline > SystemClock.uptimeMillis()) { 91 // Vibrator might be running from previous steps, so turn it off while canceling. 92 stopVibrating(); 93 } 94 } 95 handleVibratorOnResult(long vibratorOnResult)96 protected long handleVibratorOnResult(long vibratorOnResult) { 97 mVibratorOnResult = vibratorOnResult; 98 if (VibrationThread.DEBUG) { 99 Slog.d(VibrationThread.TAG, 100 "Turned on vibrator " + getVibratorId() + ", result = " + mVibratorOnResult); 101 } 102 if (mVibratorOnResult > 0) { 103 // Vibrator was turned on by this step, with vibratorOnResult as the duration. 104 // Set an extra timeout to wait for the vibrator completion callback. 105 mPendingVibratorOffDeadline = SystemClock.uptimeMillis() + mVibratorOnResult 106 + VibrationStepConductor.CALLBACKS_EXTRA_TIMEOUT; 107 } else { 108 // Vibrator does not support the request or failed to turn on, reset callback deadline. 109 mPendingVibratorOffDeadline = 0; 110 } 111 return mVibratorOnResult; 112 } 113 stopVibrating()114 protected void stopVibrating() { 115 if (conductor.isInSession) { 116 if (VibrationThread.DEBUG) { 117 Slog.d(VibrationThread.TAG, 118 "Vibration in session, skipping request to turn off vibrator " 119 + getVibratorId()); 120 } 121 return; 122 } 123 if (VibrationThread.DEBUG) { 124 Slog.d(VibrationThread.TAG, 125 "Turning off vibrator " + getVibratorId()); 126 } 127 // Make sure we ignore any pending callback from old vibration commands. 128 conductor.nextVibratorCallbackStepId(getVibratorId()); 129 controller.off(); 130 getVibration().stats.reportVibratorOff(); 131 mPendingVibratorOffDeadline = 0; 132 } 133 changeAmplitude(float amplitude)134 protected void changeAmplitude(float amplitude) { 135 if (VibrationThread.DEBUG) { 136 Slog.d(VibrationThread.TAG, 137 "Amplitude changed on vibrator " + getVibratorId() + " to " + amplitude); 138 } 139 controller.setAmplitude(amplitude); 140 getVibration().stats.reportSetAmplitude(); 141 } 142 } 143