Skip to content

Commit

Permalink
[HapticFeedback] Implement vibrate() (flutter-tizen#75)
Browse files Browse the repository at this point in the history
* [HapticFeedback] Implement vibrate()

[Before] HapticFeedback.vibrate() was not implemented

[After] The code below will cause a short vibration:
      HapticFeedback.vibrate()

Signed-off-by: Pawel Wasowski <[email protected]>

* Make HapticFeedback.vibrate's dependencies dependent on profile

HapticFeedback.vibrate will only work on mobile and wearable profiles so
its dependencies should only be included in builds for these devices.

Signed-off-by: Pawel Wasowski <[email protected]>

* Make FeedbackManager a singleton

* [HapticFeedback.vibrate] Minfor fixes

- use the proper "MOBILE_PROFILE" and "WEARABLE_PROFILE" names instead of
  "MOBILE" and "WEARABLE"
- reorder lines in BUILD.gn

Signed-off-by: Pawel Wasowski <[email protected]>

* Refactor implementation of HapticFeedback.vibrate() and BUILD.gn

Signed-off-by: Pawel Wasowski <[email protected]>

* [HapticFeedback] Refactor FeedbackManager

Signed-off-by: Pawel Wasowski <[email protected]>

* [HapticFeedback] Use FT_LOGE for all error logs
  • Loading branch information
pwasowski2 authored and swift-kim committed Sep 27, 2021
1 parent e42dbe6 commit 2713898
Show file tree
Hide file tree
Showing 2 changed files with 192 additions and 1 deletion.
18 changes: 18 additions & 0 deletions shell/platform/tizen/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,10 @@ config("tizen_rootstrap_include_dirs") {
"$custom_sysroot/usr/include/emile-1",
"$custom_sysroot/usr/include/eo-1",
"$custom_sysroot/usr/include/evas-1",
"$custom_sysroot/usr/include/feedback",
"$custom_sysroot/usr/include/system",
"$custom_sysroot/usr/include/wayland-extension",

# For Evas_GL.
"$custom_sysroot/usr/include/ecore-con-1",
"$custom_sysroot/usr/include/ecore-file-1",
Expand All @@ -77,6 +79,8 @@ config("tizen_rootstrap_include_dirs") {
template("embedder_for_profile") {
forward_variables_from(invoker, [ "use_evas_gl_renderer" ])

profile = target_name

if (!defined(use_evas_gl_renderer)) {
use_evas_gl_renderer = false
}
Expand Down Expand Up @@ -121,6 +125,20 @@ template("embedder_for_profile") {
"wayland-client",
]

if (profile == "mobile") {
libs += [
"capi-base-common",
"feedback",
]
}

if (profile == "wearable") {
libs += [
"capi-base-common",
"feedback",
]
}

defines = invoker.defines

if (use_evas_gl_renderer) {
Expand Down
175 changes: 174 additions & 1 deletion shell/platform/tizen/channels/platform_channel.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "platform_channel.h"

#include <app.h>
#include <feedback.h>

#include <map>

Expand All @@ -28,6 +29,146 @@ PlatformChannel::PlatformChannel(flutter::BinaryMessenger* messenger,

PlatformChannel::~PlatformChannel() {}

namespace {

class FeedbackManager {
public:
enum class ResultCode {
kOk,
kNotSupportedError,
kPermissionDeniedError,
kUnknownError
};

static std::string GetVibrateVariantName(const char* haptic_feedback_type) {
FT_LOGD(
"Enter FeedbackManager::GetVibrateVariantName(): haptic_feedback_type: "
"(%s)",
haptic_feedback_type);

if (!haptic_feedback_type) {
return "HapticFeedback.vibrate";
}

const size_t kPrefixToRemoveLen = strlen("HapticFeedbackType.");

assert(strlen(haptic_feedback_type) >= kPrefixToRemoveLen);

const std::string kHapticFeedbackPrefix = "HapticFeedback.";

return kHapticFeedbackPrefix +
std::string{haptic_feedback_type + kPrefixToRemoveLen};
}

static std::string GetErrorMessage(const std::string& method_name,
ResultCode result_code) {
FT_LOGD(
"Enter FeedbackManager::GetErrorMessage(): method_name: (%s), "
"result_code: [%d]",
method_name.c_str(), static_cast<int>(result_code));

switch (result_code) {
case ResultCode::kNotSupportedError:
return method_name + "() is not supported";
case ResultCode::kPermissionDeniedError:
return std::string{"No permission to run "} + method_name +
"(). Add "
"\"http://tizen.org/privilege/feedback\" privilege to "
"tizen-manifest.xml "
"to use this method";
case ResultCode::kUnknownError:
default:
return std::string{"An unknown error on "} + method_name + "() call";
}
}

#if defined(MOBILE_PROFILE) || defined(WEARABLE_PROFILE)

static FeedbackManager& GetInstance() {
FT_LOGD("Enter FeedbackManager::GetInstance()");

static FeedbackManager instance;
return instance;
}

FeedbackManager(const FeedbackManager&) = delete;
FeedbackManager& operator=(const FeedbackManager&) = delete;

ResultCode Vibrate() {
FT_LOGD("Enter FeedbackManager::Vibrate()");

if (ResultCode::kOk != initialization_status_) {
FT_LOGE("Cannot run Vibrate(): initialization_status_: [%d]",
static_cast<int>(initialization_status_));
return initialization_status_;
}

auto ret =
feedback_play_type(FEEDBACK_TYPE_VIBRATION, FEEDBACK_PATTERN_SIP);
if (FEEDBACK_ERROR_NONE == ret) {
FT_LOGD("feedback_play_type() succeeded");
return ResultCode::kOk;
}
FT_LOGE("feedback_play_type() failed with error: [%d] (%s)", ret,
get_error_message(ret));

return NativeErrorToResultCode(ret);
}

private:
static ResultCode NativeErrorToResultCode(int native_error_code) {
FT_LOGD("Enter NativeErrorToResultCode: native_error_code: [%d]",
native_error_code);

switch (native_error_code) {
case FEEDBACK_ERROR_NONE:
return ResultCode::kOk;
case FEEDBACK_ERROR_NOT_SUPPORTED:
return ResultCode::kNotSupportedError;
case FEEDBACK_ERROR_PERMISSION_DENIED:
return ResultCode::kPermissionDeniedError;
case FEEDBACK_ERROR_OPERATION_FAILED:
case FEEDBACK_ERROR_INVALID_PARAMETER:
case FEEDBACK_ERROR_NOT_INITIALIZED:
default:
return ResultCode::kUnknownError;
}
}

FeedbackManager() {
FT_LOGD("Enter FeedbackManager::FeedbackManager()");

auto ret = feedback_initialize();
if (FEEDBACK_ERROR_NONE != ret) {
FT_LOGE("feedback_initialize() failed with error: [%d] (%s)", ret,
get_error_message(ret));
initialization_status_ = NativeErrorToResultCode(ret);
return;
}
FT_LOGD("feedback_initialize() succeeded");

initialization_status_ = ResultCode::kOk;
}

~FeedbackManager() {
FT_LOGD("Enter FeedbackManager::~FeedbackManager");

auto ret = feedback_deinitialize();
if (FEEDBACK_ERROR_NONE != ret) {
FT_LOGE("feedback_deinitialize() failed with error: [%d] (%s)", ret,
get_error_message(ret));
return;
}
FT_LOGD("feedback_deinitialize() succeeded");
}

ResultCode initialization_status_ = ResultCode::kUnknownError;

#endif // defined(MOBILE_PROFILE) || defined(WEARABLE_PROFILE)
};

} // namespace

void PlatformChannel::HandleMethodCall(
const flutter::MethodCall<rapidjson::Document>& call,
std::unique_ptr<flutter::MethodResult<rapidjson::Document>> result) {
Expand All @@ -39,7 +180,39 @@ void PlatformChannel::HandleMethodCall(
} else if (method == "SystemSound.play") {
result->NotImplemented();
} else if (method == "HapticFeedback.vibrate") {
result->NotImplemented();
FT_LOGD("HapticFeedback.vibrate() call received");

const std::string error_message = "Could not vibrate";

#if defined(MOBILE_PROFILE) || defined(WEARABLE_PROFILE)
/*
* We use a single type of vibration (FEEDBACK_PATTERN_SIP) to implement
* HapticFeedback's vibrate, lightImpact, mediumImpact, heavyImpact
* and selectionClick methods, because Tizen's "feedback" module
* has no dedicated vibration types for them.
* Thus, we ignore the "arguments" contents for "HapticFeedback.vibrate"
* calls.
*/

auto ret = FeedbackManager::GetInstance().Vibrate();
if (FeedbackManager::ResultCode::kOk == ret) {
result->Success();
return;
}

const auto vibrate_variant_name =
FeedbackManager::GetVibrateVariantName(call.arguments()[0].GetString());
const auto error_cause =
FeedbackManager::GetErrorMessage(vibrate_variant_name, ret);
FT_LOGE("%s: %s", error_cause.c_str(), error_message.c_str());
#else
const auto vibrate_variant_name =
FeedbackManager::GetVibrateVariantName(call.arguments()[0].GetString());
const auto error_cause = FeedbackManager::GetErrorMessage(
vibrate_variant_name, FeedbackManager::ResultCode::kNotSupportedError);
#endif // defined(MOBILE_PROFILE) || defined(WEARABLE_PROFILE)

result->Error(error_cause, error_message);
} else if (method == "Clipboard.getData") {
result->NotImplemented();
} else if (method == "Clipboard.setData") {
Expand Down

0 comments on commit 2713898

Please sign in to comment.