• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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