* 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 "vibrator_ffi.h"
#include <map>
#include <set>
#include <string>
#include "file_utils.h"
#include "miscdevice_log.h"
#include "sensors_errors.h"
#include "vibrator_agent.h"
#undef LOG_TAG
#define LOG_TAG "Vibrator-Cj"
namespace OHOS {
namespace Sensors {
static std::map<std::string, int32_t> g_usageType = {
{"unknown", USAGE_UNKNOWN},
{"alarm", USAGE_ALARM},
{"ring", USAGE_RING},
{"notification", USAGE_NOTIFICATION},
{"communication", USAGE_COMMUNICATION},
{"touch", USAGE_TOUCH},
{"media", USAGE_MEDIA},
{"physicalFeedback", USAGE_PHYSICAL_FEEDBACK},
{"simulateReality", USAGE_SIMULATE_REALITY},
};
static std::set<std::string> g_allowedTypes = {"time", "preset", "file", "pattern"};
struct CJVibrateInfo {
std::string type;
std::string usage;
bool systemUsage;
int32_t duration = 0;
std::string effectId;
int32_t count = 0;
int32_t fd = -1;
int64_t offset = 0;
int64_t length = -1;
int32_t intensity = 0;
VibratorPattern vibratorPattern;
};
char* MallocCString(const std::string& origin)
{
if (origin.empty()) {
return nullptr;
}
auto length = origin.length() + 1;
char* res = static_cast<char*>(malloc(sizeof(char) * length));
if (res == nullptr) {
return nullptr;
}
return std::char_traits<char>::copy(res, origin.c_str(), length);
}
bool SetUsage(const std::string &usage, bool systemUsage)
{
if (auto iter = g_usageType.find(usage); iter == g_usageType.end()) {
MISC_HILOGE("Wrong usage type");
return false;
}
return SetUsage(g_usageType[usage], systemUsage);
}
int32_t StartVibrate(const CJVibrateInfo &info)
{
CALL_LOG_ENTER;
if (!SetUsage(info.usage, info.systemUsage)) {
MISC_HILOGE("SetUsage fail");
return PARAMETER_ERROR;
}
if (g_allowedTypes.find(info.type) == g_allowedTypes.end()) {
MISC_HILOGE("Invalid vibrate type, type:%{public}s", info.type.c_str());
return PARAMETER_ERROR;
}
if (info.type == "preset") {
if (!SetLoopCount(info.count)) {
MISC_HILOGE("SetLoopCount fail");
return PARAMETER_ERROR;
}
return PlayPrimitiveEffect(info.effectId.c_str(), info.intensity);
} else if (info.type == "file") {
return PlayVibratorCustom(info.fd, info.offset, info.length);
} else if (info.type == "pattern") {
return PlayPattern(info.vibratorPattern);
}
return StartVibratorOnce(info.duration);
}
bool SetUsage(const VibratorIdentifier &identifier, const std::string &usage, bool systemUsage)
{
if (auto iter = g_usageType.find(usage); iter == g_usageType.end()) {
MISC_HILOGE("Wrong usage type");
return false;
}
return SetUsageEnhanced(identifier, g_usageType[usage], systemUsage);
}
int32_t CheckParameters(const CJVibrateInfo &info, const VibratorIdentifier &identifier)
{
CALL_LOG_ENTER;
if (!SetUsage(identifier, info.usage, info.systemUsage)) {
MISC_HILOGE("SetUsage fail");
return DEVICE_OPERATION_FAILED;
}
if (g_allowedTypes.find(info.type) == g_allowedTypes.end()) {
MISC_HILOGE("Invalid vibrate type, type:%{public}s", info.type.c_str());
return DEVICE_OPERATION_FAILED;
}
return ERR_OK;
}
int32_t StartVibrateEnhanced(const CJVibrateInfo &info, const VibratorIdentifier &identifier)
{
CALL_LOG_ENTER;
if (CheckParameters(info, identifier)!= ERR_OK) {
MISC_HILOGE("SetUsage fail");
return DEVICE_OPERATION_FAILED;
}
if (info.type == "file") {
return PlayVibratorCustomEnhanced(identifier, info.fd, info.offset, info.length);
} else if (info.type == "pattern") {
return PlayPatternEnhanced(identifier, info.vibratorPattern);
}
return StartVibratorOnceEnhanced(identifier, info.duration);
}
extern "C" {
void FfiVibratorStartVibrationTime(RetVibrateTime effect, RetVibrateAttribute attribute, int32_t &code)
{
CJVibrateInfo info;
std::string strType(effect.timeType);
info.type = strType;
info.duration = effect.duration;
std::string strUsage(attribute.usage);
info.usage = strUsage;
info.systemUsage = false;
code = StartVibrate(info);
};
void FfiVibratorStartVibrationPreset(RetVibratePreset effect, RetVibrateAttribute attribute, int32_t &code)
{
CJVibrateInfo info;
std::string strType(effect.presetType);
info.type = strType;
std::string strEffectId(effect.effectId);
info.effectId = strEffectId;
info.count = effect.count;
info.intensity = effect.intensity;
std::string strUsage(attribute.usage);
info.usage = strUsage;
info.systemUsage = false;
code = StartVibrate(info);
};
void FfiVibratorStartVibrationFile(RetVibrateFromFile effect, RetVibrateAttribute attribute, int32_t &code)
{
CJVibrateInfo info;
std::string strType(effect.fileType);
info.type = strType;
info.fd = effect.hapticFd.fd;
info.offset = effect.hapticFd.offSet;
info.length = effect.hapticFd.length;
std::string strUsage(attribute.usage);
info.usage = strUsage;
info.systemUsage = false;
code = StartVibrate(info);
};
void FfiVibratorStopVibration(int32_t &code)
{
code = Cancel();
}
void FfiVibratorStopVibrationMode(char* vibMode, int32_t &code)
{
if (vibMode == nullptr) {
code = PARAMETER_ERROR;
return;
}
if (strcmp(vibMode, "time") != 0 && strcmp(vibMode, "preset") != 0) {
code = PARAMETER_ERROR;
return;
}
std::string mode(vibMode);
code = StopVibrator(mode.c_str());
}
bool FfiVibratorSupportEffect(char* id, int32_t &code)
{
bool isSupportEffect = false;
if (id == nullptr) {
code = PARAMETER_ERROR;
return isSupportEffect;
}
if (strcmp(id, "haptic.clock.timer") != 0) {
code = PARAMETER_ERROR;
return isSupportEffect;
}
std::string effectId(id);
code = IsSupportEffect(effectId.c_str(), &isSupportEffect);
return isSupportEffect;
}
bool FfiVibratorIsHdHapticSupported()
{
return IsHdHapticSupported();
}
FFI_EXPORT int32_t FfiVibratorStartVibrationTimeEnhanced(RetVibrateTime effect,
RetVibrateAttributeEnhanced attribute)
{
CJVibrateInfo info;
if (effect.timeType == nullptr || attribute.usage == nullptr) {
return PARAMETER_ERROR;
}
std::string strType(effect.timeType);
info.type = strType;
info.duration = effect.duration;
std::string strUsage(attribute.usage);
info.usage = strUsage;
info.systemUsage = false;
VibratorIdentifier identifier;
identifier.deviceId = attribute.deviceId;
identifier.vibratorId = attribute.id;
if (identifier.vibratorId == 0) {
identifier.vibratorId = -1;
}
return StartVibrateEnhanced(info, identifier);
}
FFI_EXPORT int32_t FfiVibratorStartVibrationFileEnhanced(RetVibrateFromFile effect,
RetVibrateAttributeEnhanced attribute)
{
if (effect.fileType == nullptr || attribute.usage == nullptr) {
return PARAMETER_ERROR;
}
CJVibrateInfo info;
std::string strType(effect.fileType);
info.type = strType;
info.fd = effect.hapticFd.fd;
info.offset = effect.hapticFd.offSet;
info.length = effect.hapticFd.length;
std::string strUsage(attribute.usage);
info.usage = strUsage;
info.systemUsage = false;
VibratorIdentifier identifier;
identifier.deviceId = attribute.deviceId;
identifier.vibratorId = attribute.id;
if (identifier.vibratorId == 0) {
identifier.vibratorId = -1;
}
return StartVibrateEnhanced(info, identifier);
};
FFI_EXPORT int32_t FfiVibratorStartVibrationPresetEnhanced(RetVibratePreset effect,
RetVibrateAttributeEnhanced attribute)
{
if (effect.presetType == nullptr || effect.effectId == nullptr || attribute.usage == nullptr) {
return PARAMETER_ERROR;
}
CJVibrateInfo info;
std::string strType(effect.presetType);
info.type = strType;
std::string strEffectId(effect.effectId);
info.effectId = strEffectId;
info.count = effect.count;
info.intensity = effect.intensity;
std::string strUsage(attribute.usage);
info.usage = strUsage;
info.systemUsage = false;
VibratorIdentifier identifier;
identifier.deviceId = attribute.deviceId;
identifier.vibratorId = attribute.id;
if (identifier.vibratorId == 0) {
identifier.vibratorId = -1;
}
if (!SetLoopCountEnhanced(identifier, info.count) || CheckParameters(info, identifier) != ERR_OK
|| info.effectId.empty()) {
return DEVICE_OPERATION_FAILED;
}
return PlayPrimitiveEffect(info.effectId.c_str(), info.intensity);
};
FFI_EXPORT CArrRetVibratorInfo FfiVibratorGetVibratorInfo(RetVibratorInfoParam param, int32_t *code)
{
CArrRetVibratorInfo arrInfo = {.head = nullptr, .size = 0};
VibratorIdentifier identifier;
identifier.deviceId = param.deviceId;
identifier.vibratorId = param.vibratorId;
std::vector<VibratorInfos> vibratorInfo;
int32_t ret = GetVibratorList(identifier, vibratorInfo);
if (ret != SUCCESS) {
*code = ret;
return arrInfo;
}
arrInfo.size = static_cast<int64_t>(vibratorInfo.size());
if (arrInfo.size == 0) {
return arrInfo;
}
RetVibratorInfos* retValue = static_cast<RetVibratorInfos*>(
malloc(sizeof(RetVibratorInfos) * arrInfo.size));
if (retValue == nullptr) {
*code = DEVICE_OPERATION_FAILED;
return arrInfo;
}
int32_t flag = 0;
bool fail = false;
for (int64_t i = 0; i < arrInfo.size; ++i) {
retValue[i].deviceId = vibratorInfo[i].deviceId;
retValue[i].vibratorId = vibratorInfo[i].vibratorId;
if (vibratorInfo[i].deviceName.empty()) {
retValue[i].deviceName = nullptr;
} else {
retValue[i].deviceName = MallocCString(vibratorInfo[i].deviceName);
if (retValue[i].deviceName == nullptr) {
fail = true;
*code = DEVICE_OPERATION_FAILED;
break;
}
}
retValue[i].isSupportHdHaptic = vibratorInfo[i].isSupportHdHaptic;
retValue[i].isLocalVibrator = vibratorInfo[i].isLocalVibrator;
flag += 1;
}
if (fail == true) {
for (int32_t i = 0; i < flag; ++i) {
free(retValue[i].deviceName);
}
free(retValue);
retValue = nullptr;
}
arrInfo.head = retValue;
return arrInfo;
}
FFI_EXPORT int32_t FfiVibratorStopVibrationEnhanced(RetVibratorInfoParam param)
{
VibratorIdentifier identifier;
identifier.deviceId = param.deviceId;
identifier.vibratorId = param.vibratorId;
return CancelEnhanced(identifier);
}
}
}
}