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 sptr<CallBase> ringCall = controlManager->GetOneCarrierCallObject(CallRunningState::CALL_RUNNING_STATE_RINGING);
128
129 switch (motionData.type) {
130 case MOTION_TYPE_FLIP:
131 if (motionData.status == FilpDirection::FLIP_UP) {
132 if (controlManager != nullptr && ringCall != nullptr) {
133 controlManager->MuteRinger();
134 TELEPHONY_LOGI("flip motion muteRinger");
135 }
136 }
137 break;
138 case MOTION_TYPE_PICKUP:
139 if (motionData.status != 0) {
140 break;
141 }
142 MotionRecogntion::UnsubscribePickupSensor();
143 ffrt::submit([=]() {
144 MotionRecogntion::ReduceRingToneVolume();
145 });
146 break;
147 default:
148 break;
149 }
150 }
151
ReduceRingToneVolume()152 void MotionRecogntion::ReduceRingToneVolume()
153 {
154 int32_t count = 0;
155 float value = 0.0f;
156 int32_t currentVolume = DelayedSingleton<AudioProxy>::GetInstance()->GetVolume(
157 AudioStandard::AudioVolumeType::STREAM_RING);
158 if (currentVolume <= 1) {
159 TELEPHONY_LOGE("currentVolume = %{public}d, return it", currentVolume);
160 return;
161 }
162 float beginVolumeDb = DelayedSingleton<AudioProxy>::GetInstance()->GetSystemRingVolumeInDb(currentVolume);
163 if (beginVolumeDb == 0.0f) {
164 TELEPHONY_LOGE("GetSystemRingVolumeInDb fail");
165 return;
166 }
167 int32_t reduceCount = currentVolume - 1;
168 while (count < reduceCount) {
169 count++;
170 float endVolumeDb = DelayedSingleton<AudioProxy>::GetInstance()->GetSystemRingVolumeInDb(currentVolume - count);
171 if (endVolumeDb == 0.0f || beginVolumeDb <= endVolumeDb) {
172 TELEPHONY_LOGE("GetSystemRingVolumeInDb fail or beginVolumeDb unexpected");
173 return;
174 }
175 DelayedSingleton<AudioControlManager>::GetInstance()->SetRingToneVolume(endVolumeDb / beginVolumeDb);
176 ffrt_usleep(REDUCE_RING_TOTAL_LENGTH / reduceCount);
177 }
178 }
179
CloseToEarMotionEventCallback(const Rosen::MotionSensorEvent & motionData)180 void CloseToEarMotionEventCallback(const Rosen::MotionSensorEvent &motionData)
181 {
182 TELEPHONY_LOGI("type = %{public}d, status = %{public}d", motionData.type, motionData.status);
183 auto controlManager = DelayedSingleton<CallControlManager>::GetInstance();
184 sptr<CallBase> ringCall = controlManager->GetOneCarrierCallObject(CallRunningState::CALL_RUNNING_STATE_RINGING);
185 sptr<CallBase> dialingCall = controlManager->GetOneCarrierCallObject(CallRunningState::CALL_RUNNING_STATE_DIALING);
186 sptr<CallBase> activeCall = controlManager->GetOneCarrierCallObject(CallRunningState::CALL_RUNNING_STATE_ACTIVE);
187 sptr<CallBase> holdingCall = controlManager->GetOneCarrierCallObject(CallRunningState::CALL_RUNNING_STATE_HOLD);
188 AudioDevice device = {
189 .deviceType = AudioDeviceType::DEVICE_EARPIECE,
190 .address = { 0 },
191 };
192 AudioDeviceType deviceType = DelayedSingleton<AudioDeviceManager>::GetInstance()->GetCurrentAudioDevice();
193 switch (motionData.type) {
194 case MOTION_TYPE_CLOSE_TO_EAR:
195 if (motionData.status != 0) {
196 TELEPHONY_LOGI("ignore status is not success");
197 break;
198 }
199 if (dialingCall == nullptr && activeCall == nullptr && holdingCall == nullptr &&
200 controlManager != nullptr && ringCall != nullptr) {
201 controlManager->AnswerCall(ringCall->GetCallID(), static_cast<int32_t>(VideoStateType::TYPE_VOICE));
202 TELEPHONY_LOGI("close to ear: AnswerCall");
203 };
204 if (controlManager != nullptr && (dialingCall != nullptr || activeCall != nullptr)) {
205 if (deviceType == AudioDeviceType::DEVICE_SPEAKER ||
206 deviceType == AudioDeviceType::DEVICE_BLUETOOTH_SCO) {
207 TELEPHONY_LOGI("current deviceType = %{public}d, det audioDevice to earpiece",
208 static_cast<int32_t>(deviceType));
209 controlManager->SetAudioDevice(device);
210 }
211 }
212 break;
213 default:
214 break;
215 }
216 }
217
SubscribePickupMotion()218 void MotionPickupSubscriber::SubscribePickupMotion()
219 {
220 if (isMotionPickupSubscribed_) {
221 return;
222 }
223 if (!SubscribeCallback(MOTION_TYPE_PICKUP, FlipMotionEventCallback)) {
224 TELEPHONY_LOGI("Pickup motion subscribe failed");
225 return;
226 }
227 isMotionPickupSubscribed_ = true;
228 }
229
UnsubscribePickupMotion()230 void MotionPickupSubscriber::UnsubscribePickupMotion()
231 {
232 if (!isMotionPickupSubscribed_) {
233 TELEPHONY_LOGI("Unsubscribe Pickup motion");
234 return;
235 }
236
237 if (!UnsubscribeCallback(MOTION_TYPE_PICKUP, FlipMotionEventCallback)) {
238 TELEPHONY_LOGI("Pickup motion unsubscribe failed");
239 return;
240 }
241 isMotionPickupSubscribed_ = false;
242 }
243
SubscribeFlipMotion()244 void MotionFlipSubscriber::SubscribeFlipMotion()
245 {
246 if (isMotionFlipSubscribed_) {
247 return;
248 }
249 if (!SubscribeCallback(MOTION_TYPE_FLIP, FlipMotionEventCallback)) {
250 TELEPHONY_LOGI("flip motion subscribe failed");
251 return;
252 }
253 isMotionFlipSubscribed_ = true;
254 }
255
UnsubscribeFlipMotion()256 void MotionFlipSubscriber::UnsubscribeFlipMotion()
257 {
258 if (!isMotionFlipSubscribed_) {
259 TELEPHONY_LOGI("Unsubscribe flip motion");
260 return;
261 }
262
263 if (!UnsubscribeCallback(MOTION_TYPE_FLIP, FlipMotionEventCallback)) {
264 TELEPHONY_LOGI("flip motion unsubscribe failed");
265 return;
266 }
267 isMotionFlipSubscribed_ = false;
268 }
269
SubscribeCloseToEarMotion()270 void MotionCloseToEarSubscriber::SubscribeCloseToEarMotion()
271 {
272 if (isMotionCloseToEarSubscribed_) {
273 return;
274 }
275 if (!SubscribeCallback(MOTION_TYPE_CLOSE_TO_EAR, CloseToEarMotionEventCallback)) {
276 TELEPHONY_LOGI("close to ear motion subscribe failed");
277 return;
278 }
279 isMotionCloseToEarSubscribed_ = true;
280 }
281
UnsubscribeCloseToEarMotion()282 void MotionCloseToEarSubscriber::UnsubscribeCloseToEarMotion()
283 {
284 if (!isMotionCloseToEarSubscribed_) {
285 TELEPHONY_LOGI("Unsubscribe close to ear motion");
286 return;
287 }
288 if (!UnsubscribeCallback(MOTION_TYPE_CLOSE_TO_EAR, CloseToEarMotionEventCallback)) {
289 TELEPHONY_LOGI("close to ear motion unsubscribe failed");
290 return;
291 }
292 isMotionCloseToEarSubscribed_ = false;
293 }
294 #endif
295 } // namespace Telephony
296 } // namespace OHOS