1 /*
2  * Copyright (C) 2019 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 #include "../Macros.h"
18 
19 #include "VibratorInputMapper.h"
20 
21 namespace android {
22 
VibratorInputMapper(InputDeviceContext & deviceContext)23 VibratorInputMapper::VibratorInputMapper(InputDeviceContext& deviceContext)
24       : InputMapper(deviceContext), mVibrating(false) {}
25 
~VibratorInputMapper()26 VibratorInputMapper::~VibratorInputMapper() {}
27 
getSources()28 uint32_t VibratorInputMapper::getSources() {
29     return 0;
30 }
31 
populateDeviceInfo(InputDeviceInfo * info)32 void VibratorInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
33     InputMapper::populateDeviceInfo(info);
34 
35     info->setVibrator(true);
36 }
37 
process(const RawEvent * rawEvent)38 void VibratorInputMapper::process(const RawEvent* rawEvent) {
39     // TODO: Handle FF_STATUS, although it does not seem to be widely supported.
40 }
41 
vibrate(const nsecs_t * pattern,size_t patternSize,ssize_t repeat,int32_t token)42 void VibratorInputMapper::vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat,
43                                   int32_t token) {
44 #if DEBUG_VIBRATOR
45     std::string patternStr;
46     for (size_t i = 0; i < patternSize; i++) {
47         if (i != 0) {
48             patternStr += ", ";
49         }
50         patternStr += StringPrintf("%" PRId64, pattern[i]);
51     }
52     ALOGD("vibrate: deviceId=%d, pattern=[%s], repeat=%zd, token=%d", getDeviceId(),
53           patternStr.c_str(), repeat, token);
54 #endif
55 
56     mVibrating = true;
57     memcpy(mPattern, pattern, patternSize * sizeof(nsecs_t));
58     mPatternSize = patternSize;
59     mRepeat = repeat;
60     mToken = token;
61     mIndex = -1;
62 
63     nextStep();
64 }
65 
cancelVibrate(int32_t token)66 void VibratorInputMapper::cancelVibrate(int32_t token) {
67 #if DEBUG_VIBRATOR
68     ALOGD("cancelVibrate: deviceId=%d, token=%d", getDeviceId(), token);
69 #endif
70 
71     if (mVibrating && mToken == token) {
72         stopVibrating();
73     }
74 }
75 
timeoutExpired(nsecs_t when)76 void VibratorInputMapper::timeoutExpired(nsecs_t when) {
77     if (mVibrating) {
78         if (when >= mNextStepTime) {
79             nextStep();
80         } else {
81             getContext()->requestTimeoutAtTime(mNextStepTime);
82         }
83     }
84 }
85 
nextStep()86 void VibratorInputMapper::nextStep() {
87     mIndex += 1;
88     if (size_t(mIndex) >= mPatternSize) {
89         if (mRepeat < 0) {
90             // We are done.
91             stopVibrating();
92             return;
93         }
94         mIndex = mRepeat;
95     }
96 
97     bool vibratorOn = mIndex & 1;
98     nsecs_t duration = mPattern[mIndex];
99     if (vibratorOn) {
100 #if DEBUG_VIBRATOR
101         ALOGD("nextStep: sending vibrate deviceId=%d, duration=%" PRId64, getDeviceId(), duration);
102 #endif
103         getDeviceContext().vibrate(duration);
104     } else {
105 #if DEBUG_VIBRATOR
106         ALOGD("nextStep: sending cancel vibrate deviceId=%d", getDeviceId());
107 #endif
108         getDeviceContext().cancelVibrate();
109     }
110     nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
111     mNextStepTime = now + duration;
112     getContext()->requestTimeoutAtTime(mNextStepTime);
113 #if DEBUG_VIBRATOR
114     ALOGD("nextStep: scheduled timeout in %0.3fms", duration * 0.000001f);
115 #endif
116 }
117 
stopVibrating()118 void VibratorInputMapper::stopVibrating() {
119     mVibrating = false;
120 #if DEBUG_VIBRATOR
121     ALOGD("stopVibrating: sending cancel vibrate deviceId=%d", getDeviceId());
122 #endif
123     getDeviceContext().cancelVibrate();
124 }
125 
dump(std::string & dump)126 void VibratorInputMapper::dump(std::string& dump) {
127     dump += INDENT2 "Vibrator Input Mapper:\n";
128     dump += StringPrintf(INDENT3 "Vibrating: %s\n", toString(mVibrating));
129 }
130 
131 } // namespace android
132