2 * Copyright (c) 2019 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include <dali-toolkit/internal/feedback/feedback-style.h>
22 #include <dali/public-api/common/vector-wrapper.h>
23 #include <dali/integration-api/debug.h>
24 #include <dali/public-api/common/stage.h>
25 #include <dali/public-api/object/object-registry.h>
26 #include <dali/devel-api/adaptor-framework/style-monitor.h>
29 #include <dali-toolkit/devel-api/asset-manager/asset-manager.h>
30 #include <dali-toolkit/devel-api/builder/json-parser.h>
31 #include <dali-toolkit/internal/feedback/feedback-ids.h>
33 namespace // unnamed namespace
36 #if defined(DEBUG_ENABLED)
37 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::General, false, "LOG_FEEDBACK");
40 const char* DEFAULT_FEEDBACK_THEME_FILE_NAME = "default-feedback-theme.json";
42 // Sets bool and string if the node has a child "name"
43 void GetIfString(const Dali::Toolkit::TreeNode& node, const std::string& name, bool& exists, std::string& str)
45 const Dali::Toolkit::TreeNode* child = node.GetChild(name);
47 Dali::Toolkit::TreeNode::STRING == child->GetType() )
50 str = child->GetString();
54 } // unnamed namespace
65 struct SignalFeedbackInfo
68 * Default constructor.
71 :mHasHapticFeedbackInfo(false),
72 mHasSoundFeedbackInfo(false)
76 bool mHasHapticFeedbackInfo;
77 bool mHasSoundFeedbackInfo;
78 std::string mSignalName;
79 std::string mHapticFeedbackPattern;
80 std::string mSoundFeedbackPattern;
81 std::string mHapticFeedbackFile;
82 std::string mSoundFeedbackFile;
85 typedef std::vector<SignalFeedbackInfo> SignalFeedbackInfoContainer;
86 typedef SignalFeedbackInfoContainer::const_iterator SignalFeedbackInfoConstIter;
88 struct FeedbackStyleInfo
91 * Default constructor.
97 std::string mTypeName;
99 SignalFeedbackInfoContainer mSignalFeedbackInfoList;
102 static const FeedbackStyleInfo DEFAULT_FEEDBACK_STYLE_INFO;
104 FeedbackStyle::FeedbackStyle()
106 mFeedback = Dali::FeedbackPlayer::Get();
108 const std::string styleDirPath = AssetManager::GetDaliStylePath();
109 const std::string defaultThemeFilePath = styleDirPath + DEFAULT_FEEDBACK_THEME_FILE_NAME;
111 std::string defaultTheme;
113 if( mFeedback && mFeedback.LoadFile( defaultThemeFilePath, defaultTheme ) )
115 LoadTheme( defaultTheme );
116 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "ResourceLoader::LoadTheme(%s) - loaded %d bytes\n",
117 defaultThemeFilePath.c_str(), defaultTheme.size() );
121 DALI_LOG_ERROR("ResourceLoader::LoadTheme(%s) - failed to load\n", defaultThemeFilePath.c_str());
126 FeedbackStyle::~FeedbackStyle()
130 struct PlayFeedbackFromSignal
132 PlayFeedbackFromSignal( FeedbackStyle& controller, const std::string& typeName, const std::string& signalName )
133 : mController( controller ),
134 mTypeName( typeName ),
135 mSignalName( signalName )
141 mController.PlayFeedback( mTypeName, mSignalName );
144 FeedbackStyle& mController;
145 std::string mTypeName;
146 std::string mSignalName;
150 void FeedbackStyle::ObjectCreated( BaseHandle handle )
154 const std::string& type = handle.GetTypeName();
156 const FeedbackStyleInfo styleInfo = GetStyleInfo( type );
158 for( SignalFeedbackInfoConstIter iter = styleInfo.mSignalFeedbackInfoList.begin(); iter != styleInfo.mSignalFeedbackInfoList.end(); ++iter )
160 const SignalFeedbackInfo& info = *iter;
162 if( info.mHasHapticFeedbackInfo || info.mHasSoundFeedbackInfo )
164 if( !info.mHapticFeedbackPattern.empty() || !info.mHapticFeedbackFile.empty() ||
165 !info.mSoundFeedbackPattern.empty() || !info.mSoundFeedbackFile.empty() )
167 handle.ConnectSignal( this,
169 PlayFeedbackFromSignal( *this, type, info.mSignalName ) );
171 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FeedbackStyle::Set found Haptic pattern %s for Object type: %s, Signal Type: %s\n",
172 info.mHapticFeedbackPattern.c_str(), type.c_str(), info.mSignalName.c_str() );
176 DALI_LOG_ERROR("FeedbackStyle::Set() Warning Inconsistent data in theme file!\n");
183 const FeedbackStyleInfo& FeedbackStyle::GetStyleInfo( const std::string& type ) const
185 std::map<const std::string, FeedbackStyleInfo>::const_iterator iter( mStyleInfoLut.find( type ) );
186 if( iter != mStyleInfoLut.end() )
192 return DEFAULT_FEEDBACK_STYLE_INFO;
196 void FeedbackStyle::StyleChanged( const std::string& userDefinedThemePath, Dali::StyleChange::Type styleChange )
198 if( styleChange == StyleChange::THEME_CHANGE )
200 std::string userDefinedTheme;
202 if( mFeedback && mFeedback.LoadFile( userDefinedThemePath, userDefinedTheme ) )
204 if( !LoadTheme( userDefinedTheme ) )
206 DALI_LOG_ERROR("FeedbackStyle::StyleChanged() User defined theme failed to load! \n");
208 const std::string styleDirPath = AssetManager::GetDaliStylePath();
209 const std::string defaultThemeFilePath = styleDirPath + DEFAULT_FEEDBACK_THEME_FILE_NAME;
211 //If there is any problem is using the user defined theme, then fall back to default theme
212 if( !LoadTheme( defaultThemeFilePath ) )
214 //If the default theme fails, Then No luck!
215 DALI_LOG_ERROR("FeedbackStyle::StyleChanged() Default theme failed to load! \n");
220 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "ResourceLoader::LoadTheme(%s) - loaded %d bytes\n",
221 userDefinedThemePath.c_str(), userDefinedTheme.size() );
226 DALI_LOG_ERROR("ResourceLoader::LoadTheme(%s) - failed to load\n", userDefinedThemePath.c_str());
231 bool FeedbackStyle::LoadTheme( const std::string& data )
237 LoadFromString( data );
243 //Problem in user set theme, So fallback to use default theme.
244 DALI_LOG_ERROR( "FeedbackStyle::LoadTheme() Failed to load theme\n" );
250 void FeedbackStyle::LoadFromString( const std::string& data )
252 Toolkit::JsonParser parser = Toolkit::JsonParser::New();
253 const Toolkit::TreeNode* root = NULL;
255 if( !parser.Parse( data ) )
257 DALI_LOG_WARNING( "JSON Parse Error:'%s'\n", parser.GetErrorDescription().c_str() );
258 DALI_LOG_WARNING( "JSON Parse Line :'%d (%d)'\n",
259 parser.GetErrorLineNumber(),
260 parser.GetErrorColumn() );
264 root = parser.GetRoot();
269 // Clear previously loaded style
270 mStyleInfoLut.clear();
273 if( const TreeNode* node = root->GetChild("style") )
275 Toolkit::TreeNode::ConstIterator iter = node->CBegin();
276 Toolkit::TreeNode::ConstIterator end = node->CEnd();
277 for( ; iter != end; ++iter )
279 const char* key = (*iter).first;
280 FeedbackStyleInfo themeInfo;
281 themeInfo.mTypeName = key;
283 if( const TreeNode* signals = (*iter).second.GetChild("signals") )
285 TreeNode::ConstIterator signalIter = signals->CBegin();
286 TreeNode::ConstIterator signalEnd = signals->CEnd();
287 for( ; signalIter != signalEnd; ++signalIter )
289 SignalFeedbackInfo signalFeedbackInfo;
291 const TreeNode* type = (*signalIter).second.GetChild("type");
292 DALI_ASSERT_ALWAYS(type && TreeNode::STRING == type->GetType() && "Signal must have a type");
293 signalFeedbackInfo.mSignalName = type->GetString();
295 GetIfString( (*signalIter).second, "hapticFeedbackPattern",
296 signalFeedbackInfo.mHasHapticFeedbackInfo,
297 signalFeedbackInfo.mHapticFeedbackPattern );
299 GetIfString( (*signalIter).second, "hapticFeedbackFile",
300 signalFeedbackInfo.mHasHapticFeedbackInfo,
301 signalFeedbackInfo.mHapticFeedbackFile );
303 GetIfString( (*signalIter).second, "soundFeedbackPattern",
304 signalFeedbackInfo.mHasSoundFeedbackInfo,
305 signalFeedbackInfo.mSoundFeedbackPattern );
307 GetIfString( (*signalIter).second, "hapticFeedbackFile",
308 signalFeedbackInfo.mHasSoundFeedbackInfo,
309 signalFeedbackInfo.mSoundFeedbackFile );
311 if( signalFeedbackInfo.mHasHapticFeedbackInfo || signalFeedbackInfo.mHasSoundFeedbackInfo )
313 AddSignalInfo( themeInfo, std::move( signalFeedbackInfo ) );
318 mStyleInfoLut[key] = themeInfo;
324 } // LoadFromString()
326 void FeedbackStyle::AddSignalInfo( FeedbackStyleInfo& styleInfo, SignalFeedbackInfo&& signalInfo )
328 bool updated = false;
329 SignalFeedbackInfoContainer::iterator iter;
331 // If info exists for the signal then update it, else add new
332 for( iter = styleInfo.mSignalFeedbackInfoList.begin(); iter != styleInfo.mSignalFeedbackInfoList.end(); ++iter )
334 if( (*iter).mSignalName == signalInfo.mSignalName )
336 (*iter).mHasHapticFeedbackInfo = signalInfo.mHasHapticFeedbackInfo;
337 (*iter).mHapticFeedbackPattern = signalInfo.mHapticFeedbackPattern;
338 (*iter).mHapticFeedbackFile = signalInfo.mHapticFeedbackFile;
339 (*iter).mHasSoundFeedbackInfo = signalInfo.mHasSoundFeedbackInfo;
340 (*iter).mSoundFeedbackPattern = signalInfo.mSoundFeedbackPattern;
341 (*iter).mSoundFeedbackFile = signalInfo.mSoundFeedbackFile;
350 styleInfo.mSignalFeedbackInfoList.emplace_back( std::move( signalInfo ) );
354 void FeedbackStyle::PlayFeedback(const std::string& type, const std::string& signalName)
356 const FeedbackStyleInfo styleInfo = GetStyleInfo(type);
357 SignalFeedbackInfoConstIter iter;
359 for(iter = styleInfo.mSignalFeedbackInfoList.begin(); iter != styleInfo.mSignalFeedbackInfoList.end(); ++iter)
361 const SignalFeedbackInfo& info = *iter;
363 if(info.mSignalName == signalName)
365 if(info.mHasHapticFeedbackInfo)
367 if(!info.mHapticFeedbackPattern.empty())
369 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FeedbackStyle::PlayFeedback Playing Haptic effect: Object type: %s, Signal type: %s, pattern type: %s\n",
370 type.c_str(), signalName.c_str(), info.mHapticFeedbackPattern.c_str());
372 mFeedback.PlayFeedbackPattern( FEEDBACK_TYPE_VIBRATION, GetFeedbackPattern(info.mHapticFeedbackPattern) );
374 else if(!info.mHapticFeedbackFile.empty())
376 mFeedback.PlayFile( info.mHapticFeedbackFile );
380 if(info.mHasSoundFeedbackInfo)
382 if(!info.mSoundFeedbackPattern.empty())
384 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "FeedbackStyle::PlayFeedback Playing Sound effect: Object type: %s, Signal type: %s, pattern type: %s\n",
385 type.c_str(), signalName.c_str(), info.mHapticFeedbackPattern.c_str());
387 mFeedback.PlayFeedbackPattern( FEEDBACK_TYPE_SOUND, GetFeedbackPattern(info.mSoundFeedbackPattern) );
389 else if(!info.mSoundFeedbackFile.empty())
391 mFeedback.PlaySound( info.mSoundFeedbackFile );
400 FeedbackPattern FeedbackStyle::GetFeedbackPattern( const std::string &pattern )
402 if( 0 == mFeedbackPatternLut.size() )
404 mFeedbackPatternLut["FEEDBACK_PATTERN_NONE"] = Dali::FEEDBACK_PATTERN_NONE;
405 mFeedbackPatternLut["FEEDBACK_PATTERN_TAP"] = Dali::FEEDBACK_PATTERN_TAP;
406 mFeedbackPatternLut["FEEDBACK_PATTERN_SIP"] = Dali::FEEDBACK_PATTERN_SIP;
407 mFeedbackPatternLut["FEEDBACK_PATTERN_SIP_BACKSPACE"] = Dali::FEEDBACK_PATTERN_SIP_BACKSPACE;
408 mFeedbackPatternLut["FEEDBACK_PATTERN_MAX_CHARACTER"] = Dali::FEEDBACK_PATTERN_MAX_CHARACTER;
409 mFeedbackPatternLut["FEEDBACK_PATTERN_KEY0"] = Dali::FEEDBACK_PATTERN_KEY0;
410 mFeedbackPatternLut["FEEDBACK_PATTERN_KEY1"] = Dali::FEEDBACK_PATTERN_KEY1;
411 mFeedbackPatternLut["FEEDBACK_PATTERN_KEY2"] = Dali::FEEDBACK_PATTERN_KEY2;
412 mFeedbackPatternLut["FEEDBACK_PATTERN_KEY3"] = Dali::FEEDBACK_PATTERN_KEY3;
413 mFeedbackPatternLut["FEEDBACK_PATTERN_KEY4"] = Dali::FEEDBACK_PATTERN_KEY4;
414 mFeedbackPatternLut["FEEDBACK_PATTERN_KEY5"] = Dali::FEEDBACK_PATTERN_KEY5;
415 mFeedbackPatternLut["FEEDBACK_PATTERN_KEY6"] = Dali::FEEDBACK_PATTERN_KEY6;
416 mFeedbackPatternLut["FEEDBACK_PATTERN_KEY7"] = Dali::FEEDBACK_PATTERN_KEY7;
417 mFeedbackPatternLut["FEEDBACK_PATTERN_KEY8"] = Dali::FEEDBACK_PATTERN_KEY8;
418 mFeedbackPatternLut["FEEDBACK_PATTERN_KEY9"] = Dali::FEEDBACK_PATTERN_KEY9;
419 mFeedbackPatternLut["FEEDBACK_PATTERN_KEY_STAR"] = Dali::FEEDBACK_PATTERN_KEY_STAR;
420 mFeedbackPatternLut["FEEDBACK_PATTERN_KEY_SHARP"] = Dali::FEEDBACK_PATTERN_KEY_SHARP;
421 mFeedbackPatternLut["FEEDBACK_PATTERN_HOLD"] = Dali::FEEDBACK_PATTERN_HOLD;
422 mFeedbackPatternLut["FEEDBACK_PATTERN_MULTI_TAP"] = Dali::FEEDBACK_PATTERN_MULTI_TAP;
423 mFeedbackPatternLut["FEEDBACK_PATTERN_HW_TAP"] = Dali::FEEDBACK_PATTERN_HW_TAP;
424 mFeedbackPatternLut["FEEDBACK_PATTERN_HW_HOLD"] = Dali::FEEDBACK_PATTERN_HW_HOLD;
425 mFeedbackPatternLut["FEEDBACK_PATTERN_MESSAGE"] = Dali::FEEDBACK_PATTERN_MESSAGE;
426 mFeedbackPatternLut["FEEDBACK_PATTERN_MESSAGE_ON_CALL"] = Dali::FEEDBACK_PATTERN_MESSAGE_ON_CALL;
427 mFeedbackPatternLut["FEEDBACK_PATTERN_EMAIL"] = Dali::FEEDBACK_PATTERN_EMAIL;
428 mFeedbackPatternLut["FEEDBACK_PATTERN_EMAIL_ON_CALL"] = Dali::FEEDBACK_PATTERN_EMAIL_ON_CALL;
429 mFeedbackPatternLut["FEEDBACK_PATTERN_WAKEUP"] = Dali::FEEDBACK_PATTERN_WAKEUP;
430 mFeedbackPatternLut["FEEDBACK_PATTERN_WAKEUP_ON_CALL"] = Dali::FEEDBACK_PATTERN_WAKEUP_ON_CALL;
431 mFeedbackPatternLut["FEEDBACK_PATTERN_SCHEDULE"] = Dali::FEEDBACK_PATTERN_SCHEDULE;
432 mFeedbackPatternLut["FEEDBACK_PATTERN_SCHEDULE_ON_CALL"] = Dali::FEEDBACK_PATTERN_SCHEDULE_ON_CALL;
433 mFeedbackPatternLut["FEEDBACK_PATTERN_TIMER"] = Dali::FEEDBACK_PATTERN_TIMER;
434 mFeedbackPatternLut["FEEDBACK_PATTERN_TIMER_ON_CALL"] = Dali::FEEDBACK_PATTERN_TIMER_ON_CALL;
435 mFeedbackPatternLut["FEEDBACK_PATTERN_GENERAL"] = Dali::FEEDBACK_PATTERN_GENERAL;
436 mFeedbackPatternLut["FEEDBACK_PATTERN_GENERAL_ON_CALL"] = Dali::FEEDBACK_PATTERN_GENERAL_ON_CALL;
437 mFeedbackPatternLut["FEEDBACK_PATTERN_POWER_ON"] = Dali::FEEDBACK_PATTERN_POWER_ON;
438 mFeedbackPatternLut["FEEDBACK_PATTERN_POWER_OFF"] = Dali::FEEDBACK_PATTERN_POWER_OFF;
439 mFeedbackPatternLut["FEEDBACK_PATTERN_CHARGERCONN"] = Dali::FEEDBACK_PATTERN_CHARGERCONN;
440 mFeedbackPatternLut["FEEDBACK_PATTERN_CHARGERCONN_ON_CALL"] = Dali::FEEDBACK_PATTERN_CHARGERCONN_ON_CALL;
441 mFeedbackPatternLut["FEEDBACK_PATTERN_FULLCHARGED"] = Dali::FEEDBACK_PATTERN_FULLCHARGED;
442 mFeedbackPatternLut["FEEDBACK_PATTERN_FULLCHARGED_ON_CALL"] = Dali::FEEDBACK_PATTERN_FULLCHARGED_ON_CALL;
443 mFeedbackPatternLut["FEEDBACK_PATTERN_LOWBATT"] = Dali::FEEDBACK_PATTERN_LOWBATT;
444 mFeedbackPatternLut["FEEDBACK_PATTERN_LOWBATT_ON_CALL"] = Dali::FEEDBACK_PATTERN_LOWBATT_ON_CALL;
445 mFeedbackPatternLut["FEEDBACK_PATTERN_LOCK"] = Dali::FEEDBACK_PATTERN_LOCK;
446 mFeedbackPatternLut["FEEDBACK_PATTERN_UNLOCK"] = Dali::FEEDBACK_PATTERN_UNLOCK;
447 mFeedbackPatternLut["FEEDBACK_PATTERN_CALLCONNECT"] = Dali::FEEDBACK_PATTERN_CALLCONNECT;
448 mFeedbackPatternLut["FEEDBACK_PATTERN_DISCALLCONNECT"] = Dali::FEEDBACK_PATTERN_DISCALLCONNECT;
449 mFeedbackPatternLut["FEEDBACK_PATTERN_MINUTEMINDER"] = Dali::FEEDBACK_PATTERN_MINUTEMINDER;
450 mFeedbackPatternLut["FEEDBACK_PATTERN_VIBRATION"] = Dali::FEEDBACK_PATTERN_VIBRATION;
451 mFeedbackPatternLut["FEEDBACK_PATTERN_SHUTTER"] = Dali::FEEDBACK_PATTERN_SHUTTER;
452 mFeedbackPatternLut["FEEDBACK_PATTERN_LIST_REORDER"] = Dali::FEEDBACK_PATTERN_LIST_REORDER;
453 mFeedbackPatternLut["FEEDBACK_PATTERN_SLIDER_SWEEP"] = Dali::FEEDBACK_PATTERN_SLIDER_SWEEP;
456 std::map<const std::string, FeedbackPattern>::const_iterator iter( mFeedbackPatternLut.find( pattern ) );
458 if( iter != mFeedbackPatternLut.end() )
464 DALI_LOG_ERROR( "Unknown feedback pattern type: %s, So Defaulting to FEEDBACK_PATTERN_NONE!\n" );
465 return Dali::FEEDBACK_PATTERN_NONE;
469 } // namespace Toolkit
471 } // namespace Internal