Skip to content

Commit 81ff054

Browse files
authored
[HapticFeedback] Implement vibrate() (flutter-tizen#75)
* [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
1 parent 8629ed7 commit 81ff054

File tree

2 files changed

+192
-1
lines changed

2 files changed

+192
-1
lines changed

shell/platform/tizen/BUILD.gn

+18
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,10 @@ config("tizen_rootstrap_include_dirs") {
5252
"$custom_sysroot/usr/include/emile-1",
5353
"$custom_sysroot/usr/include/eo-1",
5454
"$custom_sysroot/usr/include/evas-1",
55+
"$custom_sysroot/usr/include/feedback",
5556
"$custom_sysroot/usr/include/system",
5657
"$custom_sysroot/usr/include/wayland-extension",
58+
5759
# For Evas_GL.
5860
"$custom_sysroot/usr/include/ecore-con-1",
5961
"$custom_sysroot/usr/include/ecore-file-1",
@@ -77,6 +79,8 @@ config("tizen_rootstrap_include_dirs") {
7779
template("embedder_for_profile") {
7880
forward_variables_from(invoker, [ "use_evas_gl_renderer" ])
7981

82+
profile = target_name
83+
8084
if (!defined(use_evas_gl_renderer)) {
8185
use_evas_gl_renderer = false
8286
}
@@ -121,6 +125,20 @@ template("embedder_for_profile") {
121125
"wayland-client",
122126
]
123127

128+
if (profile == "mobile") {
129+
libs += [
130+
"capi-base-common",
131+
"feedback",
132+
]
133+
}
134+
135+
if (profile == "wearable") {
136+
libs += [
137+
"capi-base-common",
138+
"feedback",
139+
]
140+
}
141+
124142
defines = invoker.defines
125143

126144
if (use_evas_gl_renderer) {

shell/platform/tizen/channels/platform_channel.cc

+174-1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include "platform_channel.h"
66

77
#include <app.h>
8+
#include <feedback.h>
89

910
#include <map>
1011

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

2930
PlatformChannel::~PlatformChannel() {}
3031

32+
namespace {
33+
34+
class FeedbackManager {
35+
public:
36+
enum class ResultCode {
37+
kOk,
38+
kNotSupportedError,
39+
kPermissionDeniedError,
40+
kUnknownError
41+
};
42+
43+
static std::string GetVibrateVariantName(const char* haptic_feedback_type) {
44+
FT_LOGD(
45+
"Enter FeedbackManager::GetVibrateVariantName(): haptic_feedback_type: "
46+
"(%s)",
47+
haptic_feedback_type);
48+
49+
if (!haptic_feedback_type) {
50+
return "HapticFeedback.vibrate";
51+
}
52+
53+
const size_t kPrefixToRemoveLen = strlen("HapticFeedbackType.");
54+
55+
assert(strlen(haptic_feedback_type) >= kPrefixToRemoveLen);
56+
57+
const std::string kHapticFeedbackPrefix = "HapticFeedback.";
58+
59+
return kHapticFeedbackPrefix +
60+
std::string{haptic_feedback_type + kPrefixToRemoveLen};
61+
}
62+
63+
static std::string GetErrorMessage(const std::string& method_name,
64+
ResultCode result_code) {
65+
FT_LOGD(
66+
"Enter FeedbackManager::GetErrorMessage(): method_name: (%s), "
67+
"result_code: [%d]",
68+
method_name.c_str(), static_cast<int>(result_code));
69+
70+
switch (result_code) {
71+
case ResultCode::kNotSupportedError:
72+
return method_name + "() is not supported";
73+
case ResultCode::kPermissionDeniedError:
74+
return std::string{"No permission to run "} + method_name +
75+
"(). Add "
76+
"\"http://tizen.org/privilege/feedback\" privilege to "
77+
"tizen-manifest.xml "
78+
"to use this method";
79+
case ResultCode::kUnknownError:
80+
default:
81+
return std::string{"An unknown error on "} + method_name + "() call";
82+
}
83+
}
84+
85+
#if defined(MOBILE_PROFILE) || defined(WEARABLE_PROFILE)
86+
87+
static FeedbackManager& GetInstance() {
88+
FT_LOGD("Enter FeedbackManager::GetInstance()");
89+
90+
static FeedbackManager instance;
91+
return instance;
92+
}
93+
94+
FeedbackManager(const FeedbackManager&) = delete;
95+
FeedbackManager& operator=(const FeedbackManager&) = delete;
96+
97+
ResultCode Vibrate() {
98+
FT_LOGD("Enter FeedbackManager::Vibrate()");
99+
100+
if (ResultCode::kOk != initialization_status_) {
101+
FT_LOGE("Cannot run Vibrate(): initialization_status_: [%d]",
102+
static_cast<int>(initialization_status_));
103+
return initialization_status_;
104+
}
105+
106+
auto ret =
107+
feedback_play_type(FEEDBACK_TYPE_VIBRATION, FEEDBACK_PATTERN_SIP);
108+
if (FEEDBACK_ERROR_NONE == ret) {
109+
FT_LOGD("feedback_play_type() succeeded");
110+
return ResultCode::kOk;
111+
}
112+
FT_LOGE("feedback_play_type() failed with error: [%d] (%s)", ret,
113+
get_error_message(ret));
114+
115+
return NativeErrorToResultCode(ret);
116+
}
117+
118+
private:
119+
static ResultCode NativeErrorToResultCode(int native_error_code) {
120+
FT_LOGD("Enter NativeErrorToResultCode: native_error_code: [%d]",
121+
native_error_code);
122+
123+
switch (native_error_code) {
124+
case FEEDBACK_ERROR_NONE:
125+
return ResultCode::kOk;
126+
case FEEDBACK_ERROR_NOT_SUPPORTED:
127+
return ResultCode::kNotSupportedError;
128+
case FEEDBACK_ERROR_PERMISSION_DENIED:
129+
return ResultCode::kPermissionDeniedError;
130+
case FEEDBACK_ERROR_OPERATION_FAILED:
131+
case FEEDBACK_ERROR_INVALID_PARAMETER:
132+
case FEEDBACK_ERROR_NOT_INITIALIZED:
133+
default:
134+
return ResultCode::kUnknownError;
135+
}
136+
}
137+
138+
FeedbackManager() {
139+
FT_LOGD("Enter FeedbackManager::FeedbackManager()");
140+
141+
auto ret = feedback_initialize();
142+
if (FEEDBACK_ERROR_NONE != ret) {
143+
FT_LOGE("feedback_initialize() failed with error: [%d] (%s)", ret,
144+
get_error_message(ret));
145+
initialization_status_ = NativeErrorToResultCode(ret);
146+
return;
147+
}
148+
FT_LOGD("feedback_initialize() succeeded");
149+
150+
initialization_status_ = ResultCode::kOk;
151+
}
152+
153+
~FeedbackManager() {
154+
FT_LOGD("Enter FeedbackManager::~FeedbackManager");
155+
156+
auto ret = feedback_deinitialize();
157+
if (FEEDBACK_ERROR_NONE != ret) {
158+
FT_LOGE("feedback_deinitialize() failed with error: [%d] (%s)", ret,
159+
get_error_message(ret));
160+
return;
161+
}
162+
FT_LOGD("feedback_deinitialize() succeeded");
163+
}
164+
165+
ResultCode initialization_status_ = ResultCode::kUnknownError;
166+
167+
#endif // defined(MOBILE_PROFILE) || defined(WEARABLE_PROFILE)
168+
};
169+
170+
} // namespace
171+
31172
void PlatformChannel::HandleMethodCall(
32173
const flutter::MethodCall<rapidjson::Document>& call,
33174
std::unique_ptr<flutter::MethodResult<rapidjson::Document>> result) {
@@ -39,7 +180,39 @@ void PlatformChannel::HandleMethodCall(
39180
} else if (method == "SystemSound.play") {
40181
result->NotImplemented();
41182
} else if (method == "HapticFeedback.vibrate") {
42-
result->NotImplemented();
183+
FT_LOGD("HapticFeedback.vibrate() call received");
184+
185+
const std::string error_message = "Could not vibrate";
186+
187+
#if defined(MOBILE_PROFILE) || defined(WEARABLE_PROFILE)
188+
/*
189+
* We use a single type of vibration (FEEDBACK_PATTERN_SIP) to implement
190+
* HapticFeedback's vibrate, lightImpact, mediumImpact, heavyImpact
191+
* and selectionClick methods, because Tizen's "feedback" module
192+
* has no dedicated vibration types for them.
193+
* Thus, we ignore the "arguments" contents for "HapticFeedback.vibrate"
194+
* calls.
195+
*/
196+
197+
auto ret = FeedbackManager::GetInstance().Vibrate();
198+
if (FeedbackManager::ResultCode::kOk == ret) {
199+
result->Success();
200+
return;
201+
}
202+
203+
const auto vibrate_variant_name =
204+
FeedbackManager::GetVibrateVariantName(call.arguments()[0].GetString());
205+
const auto error_cause =
206+
FeedbackManager::GetErrorMessage(vibrate_variant_name, ret);
207+
FT_LOGE("%s: %s", error_cause.c_str(), error_message.c_str());
208+
#else
209+
const auto vibrate_variant_name =
210+
FeedbackManager::GetVibrateVariantName(call.arguments()[0].GetString());
211+
const auto error_cause = FeedbackManager::GetErrorMessage(
212+
vibrate_variant_name, FeedbackManager::ResultCode::kNotSupportedError);
213+
#endif // defined(MOBILE_PROFILE) || defined(WEARABLE_PROFILE)
214+
215+
result->Error(error_cause, error_message);
43216
} else if (method == "Clipboard.getData") {
44217
result->NotImplemented();
45218
} else if (method == "Clipboard.setData") {

0 commit comments

Comments
 (0)