/*
* Copyright (C) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "motion_recognition.h"
#include "chrono"
#include "securec.h"
#include "audio_control_manager.h"
#include "audio_device_manager.h"
#include "audio_proxy.h"
#include "call_base.h"
#include "call_control_manager.h"
#include "call_object_manager.h"
#include "telephony_log_wrapper.h"
namespace OHOS {
namespace Telephony {
#ifdef OHOS_SUBSCRIBE_MOTION_ENABLE
/**
* 表示拿起动作
*
* 上报数据:
*
* - status: 返回0表示设备发生拿起动作。
*/
constexpr int32_t MOTION_TYPE_PICKUP = 100;
/**
* 表示翻转动作
*
* 上报数据:
*
* - status: 返回0表示设备发生拿起靠近耳朵动作。
*/
constexpr int32_t MOTION_TYPE_FLIP = 200;
/**
* 表示靠近耳朵动作
*
* 上报数据:
*
* - status: 返回0表示设备被拿起靠近耳朵。
*/
constexpr int32_t MOTION_TYPE_CLOSE_TO_EAR = 300;
//来电铃声减弱总时长
constexpr int32_t REDUCE_RING_TOTAL_LENGTH = 1500000; //us
/**
* @brief 翻转方向
*
*/
typedef enum FilpDirection {
FLIP_DOWN = 3, /**向上翻转 */
FLIP_UP = 4, /**向下翻转 */
} FilpDirection;
bool MotionFlipSubscriber::isMotionFlipSubscribed_ = false;
bool MotionCloseToEarSubscriber::isMotionCloseToEarSubscribed_ = false;
bool MotionPickupSubscriber::isMotionPickupSubscribed_ = false;
static void FlipMotionEventCallback(const Rosen::MotionSensorEvent &motionData);
static void CloseToEarMotionEventCallback(const Rosen::MotionSensorEvent &motionData);
#endif
void MotionRecogntion::SubscribePickupSensor()
{
#ifdef OHOS_SUBSCRIBE_MOTION_ENABLE
MotionPickupSubscriber::SubscribePickupMotion();
#endif
}
void MotionRecogntion::UnsubscribePickupSensor()
{
#ifdef OHOS_SUBSCRIBE_MOTION_ENABLE
MotionPickupSubscriber::UnsubscribePickupMotion();
#endif
}
void MotionRecogntion::SubscribeFlipSensor()
{
#ifdef OHOS_SUBSCRIBE_MOTION_ENABLE
MotionFlipSubscriber::SubscribeFlipMotion();
#endif
}
void MotionRecogntion::UnsubscribeFlipSensor()
{
#ifdef OHOS_SUBSCRIBE_MOTION_ENABLE
MotionFlipSubscriber::UnsubscribeFlipMotion();
#endif
}
void MotionRecogntion::SubscribeCloseToEarSensor()
{
#ifdef OHOS_SUBSCRIBE_MOTION_ENABLE
MotionCloseToEarSubscriber::SubscribeCloseToEarMotion();
#endif
}
void MotionRecogntion::UnsubscribeCloseToEarSensor()
{
#ifdef OHOS_SUBSCRIBE_MOTION_ENABLE
MotionCloseToEarSubscriber::UnsubscribeCloseToEarMotion();
#endif
}
#ifdef OHOS_SUBSCRIBE_MOTION_ENABLE
void FlipMotionEventCallback(const Rosen::MotionSensorEvent &motionData)
{
TELEPHONY_LOGI("type = %{public}d, status = %{public}d", motionData.type, motionData.status);
auto controlManager = DelayedSingleton::GetInstance();
switch (motionData.type) {
case MOTION_TYPE_FLIP:
if (motionData.status == FilpDirection::FLIP_UP && controlManager != nullptr) {
sptr ringCall = controlManager->
GetOneCarrierCallObject(CallRunningState::CALL_RUNNING_STATE_RINGING);
if (ringCall != nullptr) {
controlManager->MuteRinger();
TELEPHONY_LOGI("flip motion muteRinger");
}
controlManager->StopFlashRemind();
}
break;
case MOTION_TYPE_PICKUP:
if (motionData.status != 0) {
break;
}
MotionRecogntion::UnsubscribePickupSensor();
if (controlManager != nullptr) {
controlManager->StopFlashRemind();
}
ffrt::submit([=]() {
MotionRecogntion::ReduceRingToneVolume();
});
break;
default:
break;
}
}
void MotionRecogntion::ReduceRingToneVolume()
{
int32_t count = 0;
float value = 0.0f;
int32_t currentVolume = DelayedSingleton::GetInstance()->GetVolume(
AudioStandard::AudioVolumeType::STREAM_RING);
if (currentVolume <= 1) {
TELEPHONY_LOGE("currentVolume = %{public}d, return it", currentVolume);
return;
}
float beginVolumeDb = DelayedSingleton::GetInstance()->GetSystemRingVolumeInDb(currentVolume);
if (beginVolumeDb == 0.0f) {
TELEPHONY_LOGE("GetSystemRingVolumeInDb fail");
return;
}
int32_t reduceCount = currentVolume - 1;
while (count < reduceCount) {
count++;
float endVolumeDb = DelayedSingleton::GetInstance()->GetSystemRingVolumeInDb(currentVolume - count);
if (endVolumeDb == 0.0f || beginVolumeDb <= endVolumeDb) {
TELEPHONY_LOGE("GetSystemRingVolumeInDb fail or beginVolumeDb unexpected");
return;
}
DelayedSingleton::GetInstance()->SetRingToneVolume(endVolumeDb / beginVolumeDb);
ffrt_usleep(REDUCE_RING_TOTAL_LENGTH / reduceCount);
}
}
void CloseToEarMotionEventCallback(const Rosen::MotionSensorEvent &motionData)
{
TELEPHONY_LOGI("type = %{public}d, status = %{public}d", motionData.type, motionData.status);
auto controlManager = DelayedSingleton::GetInstance();
if (controlManager == nullptr) {
return;
}
sptr ringCall = controlManager->GetOneCarrierCallObject(CallRunningState::CALL_RUNNING_STATE_RINGING);
sptr dialingCall = controlManager->GetOneCarrierCallObject(CallRunningState::CALL_RUNNING_STATE_DIALING);
sptr activeCall = controlManager->GetOneCarrierCallObject(CallRunningState::CALL_RUNNING_STATE_ACTIVE);
sptr holdingCall = controlManager->GetOneCarrierCallObject(CallRunningState::CALL_RUNNING_STATE_HOLD);
AudioDevice device = {
.deviceType = AudioDeviceType::DEVICE_EARPIECE,
.address = { 0 },
};
AudioDeviceType deviceType = DelayedSingleton::GetInstance()->GetCurrentAudioDevice();
switch (motionData.type) {
case MOTION_TYPE_CLOSE_TO_EAR:
if (motionData.status != 0) {
TELEPHONY_LOGI("ignore status is not success");
break;
}
if (dialingCall == nullptr && activeCall == nullptr && holdingCall == nullptr && ringCall != nullptr) {
controlManager->AnswerCall(ringCall->GetCallID(), static_cast(VideoStateType::TYPE_VOICE));
TELEPHONY_LOGI("close to ear: AnswerCall");
};
if (dialingCall != nullptr || activeCall != nullptr) {
if (deviceType == AudioDeviceType::DEVICE_SPEAKER ||
deviceType == AudioDeviceType::DEVICE_BLUETOOTH_SCO ||
deviceType == AudioDeviceType::DEVICE_NEARLINK) {
TELEPHONY_LOGI("current deviceType = %{public}d, det audioDevice to earpiece",
static_cast(deviceType));
controlManager->SetAudioDevice(device);
}
}
controlManager->StopFlashRemind();
break;
default:
break;
}
}
void MotionPickupSubscriber::SubscribePickupMotion()
{
if (isMotionPickupSubscribed_) {
return;
}
if (!SubscribeCallback(MOTION_TYPE_PICKUP, FlipMotionEventCallback)) {
TELEPHONY_LOGI("Pickup motion subscribe failed");
return;
}
isMotionPickupSubscribed_ = true;
}
void MotionPickupSubscriber::UnsubscribePickupMotion()
{
if (!isMotionPickupSubscribed_) {
TELEPHONY_LOGI("Unsubscribe Pickup motion");
return;
}
if (!UnsubscribeCallback(MOTION_TYPE_PICKUP, FlipMotionEventCallback)) {
TELEPHONY_LOGI("Pickup motion unsubscribe failed");
return;
}
isMotionPickupSubscribed_ = false;
}
void MotionFlipSubscriber::SubscribeFlipMotion()
{
if (isMotionFlipSubscribed_) {
return;
}
if (!SubscribeCallback(MOTION_TYPE_FLIP, FlipMotionEventCallback)) {
TELEPHONY_LOGI("flip motion subscribe failed");
return;
}
isMotionFlipSubscribed_ = true;
}
void MotionFlipSubscriber::UnsubscribeFlipMotion()
{
if (!isMotionFlipSubscribed_) {
TELEPHONY_LOGI("Unsubscribe flip motion");
return;
}
if (!UnsubscribeCallback(MOTION_TYPE_FLIP, FlipMotionEventCallback)) {
TELEPHONY_LOGI("flip motion unsubscribe failed");
return;
}
isMotionFlipSubscribed_ = false;
}
void MotionCloseToEarSubscriber::SubscribeCloseToEarMotion()
{
if (isMotionCloseToEarSubscribed_) {
return;
}
if (!SubscribeCallback(MOTION_TYPE_CLOSE_TO_EAR, CloseToEarMotionEventCallback)) {
TELEPHONY_LOGI("close to ear motion subscribe failed");
return;
}
isMotionCloseToEarSubscribed_ = true;
}
void MotionCloseToEarSubscriber::UnsubscribeCloseToEarMotion()
{
if (!isMotionCloseToEarSubscribed_) {
TELEPHONY_LOGI("Unsubscribe close to ear motion");
return;
}
if (!UnsubscribeCallback(MOTION_TYPE_CLOSE_TO_EAR, CloseToEarMotionEventCallback)) {
TELEPHONY_LOGI("close to ear motion unsubscribe failed");
return;
}
isMotionCloseToEarSubscribed_ = false;
}
#endif
} // namespace Telephony
} // namespace OHOS