1 /*
2 * Copyright (C) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "motion_recognition.h"
17
18 #include "chrono"
19 #include "securec.h"
20
21 #include "audio_control_manager.h"
22 #include "audio_device_manager.h"
23 #include "audio_proxy.h"
24 #include "call_base.h"
25 #include "call_control_manager.h"
26 #include "call_object_manager.h"
27 #include "telephony_log_wrapper.h"
28
29 namespace OHOS {
30 namespace Telephony {
31
32 #ifdef OHOS_SUBSCRIBE_MOTION_ENABLE
33 /**
34 * 表示拿起动作
35 * <p>
36 * 上报数据:</b>
37 * <ul>
38 * <li> status: 返回0表示设备发生拿起动作。</li>
39 */
40 constexpr int32_t MOTION_TYPE_PICKUP = 100;
41
42 /**
43 * 表示翻转动作
44 * <p>
45 * 上报数据:</b>
46 * <ul>
47 * <li> status: 返回0表示设备发生拿起靠近耳朵动作。</li>
48 */
49 constexpr int32_t MOTION_TYPE_FLIP = 200;
50
51 /**
52 * 表示靠近耳朵动作
53 * <p>
54 * 上报数据:</b>
55 * <ul>
56 * <li> status: 返回0表示设备被拿起靠近耳朵。 </li>
57 */
58 constexpr int32_t MOTION_TYPE_CLOSE_TO_EAR = 300;
59
60 //来电铃声减弱总时长
61 constexpr int32_t REDUCE_RING_TOTAL_LENGTH = 1500000; //us
62
63 /**
64 * @brief 翻转方向
65 *
66 */
67 typedef enum FilpDirection {
68 FLIP_DOWN = 3, /**向上翻转 */
69 FLIP_UP = 4, /**向下翻转 */
70 } FilpDirection;
71
72 bool MotionFlipSubscriber::isMotionFlipSubscribed_ = false;
73 bool MotionCloseToEarSubscriber::isMotionCloseToEarSubscribed_ = false;
74 bool MotionPickupSubscriber::isMotionPickupSubscribed_ = false;
75
76 static void FlipMotionEventCallback(const Rosen::MotionSensorEvent &motionData);
77 static void CloseToEarMotionEventCallback(const Rosen::MotionSensorEvent &motionData);
78 #endif
79
SubscribePickupSensor()80 void MotionRecogntion::SubscribePickupSensor()
81 {
82 #ifdef OHOS_SUBSCRIBE_MOTION_ENABLE
83 MotionPickupSubscriber::SubscribePickupMotion();
84 #endif
85 }
86
UnsubscribePickupSensor()87 void MotionRecogntion::UnsubscribePickupSensor()
88 {
89 #ifdef OHOS_SUBSCRIBE_MOTION_ENABLE
90 MotionPickupSubscriber::UnsubscribePickupMotion();
91 #endif
92 }
93
SubscribeFlipSensor()94 void MotionRecogntion::SubscribeFlipSensor()
95 {
96 #ifdef OHOS_SUBSCRIBE_MOTION_ENABLE
97 MotionFlipSubscriber::SubscribeFlipMotion();
98 #endif
99 }
100
UnsubscribeFlipSensor()101 void MotionRecogntion::UnsubscribeFlipSensor()
102 {
103 #ifdef OHOS_SUBSCRIBE_MOTION_ENABLE
104 MotionFlipSubscriber::UnsubscribeFlipMotion();
105 #endif
106 }
107
SubscribeCloseToEarSensor()108 void MotionRecogntion::SubscribeCloseToEarSensor()
109 {
110 #ifdef OHOS_SUBSCRIBE_MOTION_ENABLE
111 MotionCloseToEarSubscriber::SubscribeCloseToEarMotion();
112 #endif
113 }
114
UnsubscribeCloseToEarSensor()115 void MotionRecogntion::UnsubscribeCloseToEarSensor()
116 {
117 #ifdef OHOS_SUBSCRIBE_MOTION_ENABLE
118 MotionCloseToEarSubscriber::UnsubscribeCloseToEarMotion();
119 #endif
120 }
121
122 #ifdef OHOS_SUBSCRIBE_MOTION_ENABLE
FlipMotionEventCallback(const Rosen::MotionSensorEvent & motionData)123 void FlipMotionEventCallback(const Rosen::MotionSensorEvent &motionData)
124 {
125 TELEPHONY_LOGI("type = %{public}d, status = %{public}d", motionData.type, motionData.status);
126 auto controlManager = DelayedSingleton<CallControlManager>::GetInstance();
127
128 switch (motionData.type) {
129 case MOTION_TYPE_FLIP:
130 if (motionData.status == FilpDirection::FLIP_UP && controlManager != nullptr) {
131 sptr<CallBase> ringCall = controlManager->
132 GetOneCarrierCallObject(CallRunningState::CALL_RUNNING_STATE_RINGING);
133 if (ringCall != nullptr) {
134 controlManager->MuteRinger();
135 TELEPHONY_LOGI("flip motion muteRinger");
136 }
137 controlManager->StopFlashRemind();
138 }
139 break;
140 case MOTION_TYPE_PICKUP:
141 if (motionData.status != 0) {
142 break;
143 }
144 MotionRecogntion::UnsubscribePickupSensor();
145 if (controlManager != nullptr) {
146 controlManager->StopFlashRemind();
147 }
148 ffrt::submit([=]() {
149 MotionRecogntion::ReduceRingToneVolume();
150 });
151 break;
152 default:
153 break;
154 }
155 }
156
ReduceRingToneVolume()157 void MotionRecogntion::ReduceRingToneVolume()
158 {
159 int32_t count = 0;
160 float value = 0.0f;
161 int32_t currentVolume = DelayedSingleton<AudioProxy>::GetInstance()->GetVolume(
162 AudioStandard::AudioVolumeType::STREAM_RING);
163 if (currentVolume <= 1) {
164 TELEPHONY_LOGE("currentVolume = %{public}d, return it", currentVolume);
165 return;
166 }
167 float beginVolumeDb = DelayedSingleton<AudioProxy>::GetInstance()->GetSystemRingVolumeInDb(currentVolume);
168 if (beginVolumeDb == 0.0f) {
169 TELEPHONY_LOGE("GetSystemRingVolumeInDb fail");
170 return;
171 }
172 int32_t reduceCount = currentVolume - 1;
173 while (count < reduceCount) {
174 count++;
175 float endVolumeDb = DelayedSingleton<AudioProxy>::GetInstance()->GetSystemRingVolumeInDb(currentVolume - count);
176 if (endVolumeDb == 0.0f || beginVolumeDb <= endVolumeDb) {
177 TELEPHONY_LOGE("GetSystemRingVolumeInDb fail or beginVolumeDb unexpected");
178 return;
179 }
180 DelayedSingleton<AudioControlManager>::GetInstance()->SetRingToneVolume(endVolumeDb / beginVolumeDb);
181 ffrt_usleep(REDUCE_RING_TOTAL_LENGTH / reduceCount);
182 }
183 }
184
CloseToEarMotionEventCallback(const Rosen::MotionSensorEvent & motionData)185 void CloseToEarMotionEventCallback(const Rosen::MotionSensorEvent &motionData)
186 {
187 TELEPHONY_LOGI("type = %{public}d, status = %{public}d", motionData.type, motionData.status);
188 auto controlManager = DelayedSingleton<CallControlManager>::GetInstance();
189 if (controlManager == nullptr) {
190 return;
191 }
192 sptr<CallBase> ringCall = controlManager->GetOneCarrierCallObject(CallRunningState::CALL_RUNNING_STATE_RINGING);
193 sptr<CallBase> dialingCall = controlManager->GetOneCarrierCallObject(CallRunningState::CALL_RUNNING_STATE_DIALING);
194 sptr<CallBase> activeCall = controlManager->GetOneCarrierCallObject(CallRunningState::CALL_RUNNING_STATE_ACTIVE);
195 sptr<CallBase> holdingCall = controlManager->GetOneCarrierCallObject(CallRunningState::CALL_RUNNING_STATE_HOLD);
196 AudioDevice device = {
197 .deviceType = AudioDeviceType::DEVICE_EARPIECE,
198 .address = { 0 },
199 };
200 AudioDeviceType deviceType = DelayedSingleton<AudioDeviceManager>::GetInstance()->GetCurrentAudioDevice();
201
202 switch (motionData.type) {
203 case MOTION_TYPE_CLOSE_TO_EAR:
204 if (motionData.status != 0) {
205 TELEPHONY_LOGI("ignore status is not success");
206 break;
207 }
208 if (dialingCall == nullptr && activeCall == nullptr && holdingCall == nullptr && ringCall != nullptr) {
209 controlManager->AnswerCall(ringCall->GetCallID(), static_cast<int32_t>(VideoStateType::TYPE_VOICE));
210 TELEPHONY_LOGI("close to ear: AnswerCall");
211 };
212 if (dialingCall != nullptr || activeCall != nullptr) {
213 if (deviceType == AudioDeviceType::DEVICE_SPEAKER ||
214 deviceType == AudioDeviceType::DEVICE_BLUETOOTH_SCO ||
215 deviceType == AudioDeviceType::DEVICE_NEARLINK) {
216 TELEPHONY_LOGI("current deviceType = %{public}d, det audioDevice to earpiece",
217 static_cast<int32_t>(deviceType));
218 controlManager->SetAudioDevice(device);
219 }
220 }
221 controlManager->StopFlashRemind();
222 break;
223 default:
224 break;
225 }
226 }
227
SubscribePickupMotion()228 void MotionPickupSubscriber::SubscribePickupMotion()
229 {
230 if (isMotionPickupSubscribed_) {
231 return;
232 }
233 if (!SubscribeCallback(MOTION_TYPE_PICKUP, FlipMotionEventCallback)) {
234 TELEPHONY_LOGI("Pickup motion subscribe failed");
235 return;
236 }
237 isMotionPickupSubscribed_ = true;
238 }
239
UnsubscribePickupMotion()240 void MotionPickupSubscriber::UnsubscribePickupMotion()
241 {
242 if (!isMotionPickupSubscribed_) {
243 TELEPHONY_LOGI("Unsubscribe Pickup motion");
244 return;
245 }
246
247 if (!UnsubscribeCallback(MOTION_TYPE_PICKUP, FlipMotionEventCallback)) {
248 TELEPHONY_LOGI("Pickup motion unsubscribe failed");
249 return;
250 }
251 isMotionPickupSubscribed_ = false;
252 }
253
SubscribeFlipMotion()254 void MotionFlipSubscriber::SubscribeFlipMotion()
255 {
256 if (isMotionFlipSubscribed_) {
257 return;
258 }
259 if (!SubscribeCallback(MOTION_TYPE_FLIP, FlipMotionEventCallback)) {
260 TELEPHONY_LOGI("flip motion subscribe failed");
261 return;
262 }
263 isMotionFlipSubscribed_ = true;
264 }
265
UnsubscribeFlipMotion()266 void MotionFlipSubscriber::UnsubscribeFlipMotion()
267 {
268 if (!isMotionFlipSubscribed_) {
269 TELEPHONY_LOGI("Unsubscribe flip motion");
270 return;
271 }
272
273 if (!UnsubscribeCallback(MOTION_TYPE_FLIP, FlipMotionEventCallback)) {
274 TELEPHONY_LOGI("flip motion unsubscribe failed");
275 return;
276 }
277 isMotionFlipSubscribed_ = false;
278 }
279
SubscribeCloseToEarMotion()280 void MotionCloseToEarSubscriber::SubscribeCloseToEarMotion()
281 {
282 if (isMotionCloseToEarSubscribed_) {
283 return;
284 }
285 if (!SubscribeCallback(MOTION_TYPE_CLOSE_TO_EAR, CloseToEarMotionEventCallback)) {
286 TELEPHONY_LOGI("close to ear motion subscribe failed");
287 return;
288 }
289 isMotionCloseToEarSubscribed_ = true;
290 }
291
UnsubscribeCloseToEarMotion()292 void MotionCloseToEarSubscriber::UnsubscribeCloseToEarMotion()
293 {
294 if (!isMotionCloseToEarSubscribed_) {
295 TELEPHONY_LOGI("Unsubscribe close to ear motion");
296 return;
297 }
298 if (!UnsubscribeCallback(MOTION_TYPE_CLOSE_TO_EAR, CloseToEarMotionEventCallback)) {
299 TELEPHONY_LOGI("close to ear motion unsubscribe failed");
300 return;
301 }
302 isMotionCloseToEarSubscribed_ = false;
303 }
304 #endif
305 } // namespace Telephony
306 } // namespace OHOS