tizen beta release
[framework/web/wrt-installer.git] / src / jobs / widget_install / task_widget_config.cpp
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3  *
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
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 /*
17  * @file    task_widget_config.cpp
18  * @author  Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com)
19  * @version 1.0
20  * @brief   Implementation file for installer task widget config
21  */
22 #include <string>
23 #include <sstream>
24 #include <dpl/foreach.h>
25 #include <dpl/errno_string.h>
26 #include <dpl/wrt-dao-rw/feature_dao.h>
27 #include <dpl/utils/wrt_utility.h>
28 #include <root_parser.h>
29 #include <powder_parser.h>
30 #include <widget_parser.h>
31 #include <parser_runner.h>
32 #include <libiriwrapper.h>
33 #include <widget_install/task_widget_config.h>
34 #include <widget_install/job_widget_install.h>
35 #include <widget_install/widget_install_errors.h>
36 #include <widget_install/widget_install_context.h>
37 #include <dpl/utils/file_utils.h>
38 #include <dpl/utils/mime_type_utils.h>
39 #include <sys/stat.h>
40 #include "wrt_powder_info_util.h"
41 #include <dpl/utils/wrt_global_settings.h>
42
43 namespace { // anonymous
44 const char *WIDGET_SCHEMA = "widget";
45 const WidgetHandle WIDGET_HANDLE_START_VALUE = 1000;
46 const char * AGE_RATING = "Age Rating: ";
47 const char * CATEGORY = "Category: ";
48 const char * LEVEL = "Level: ";
49 const char * CONTEXT = "Context: ";
50 const DPL::String POWDER_INFO = DPL::FromUTF8String("Powder Info");
51 const DPL::String POWDER_PASSWORD = DPL::FromUTF8String(
52         "Parental Mode is ON.<br>"
53         "Please enter your password");
54 const DPL::String WIDGET_HEAD = DPL::FromUTF8String("Widget information");
55 const std::string OK_BUTTON_LABEL = "OK";
56 const std::string CANCEL_BUTTON_LABEL = "Cancel";
57 const DPL::String BR = DPL::FromUTF8String("<br>");
58 const DPL::String DOUBLE_BR = DPL::FromUTF8String("<br><br>");
59 const DPL::String POWDER_HEAD = DPL::FromUTF8String("Powder information");
60 const DPL::String FEATURE_HEAD = DPL::FromUTF8String("Feature information");
61 } // namespace anonymous
62
63 namespace Jobs {
64 namespace WidgetInstall {
65 void InstallerTaskWidgetPopupData::PopupData::addWidgetInfo(
66         const DPL::String &head,
67         const DPL::String &info)
68 {
69     widgetInfo += head;
70     widgetInfo += DOUBLE_BR;
71     widgetInfo += info;
72     widgetInfo += BR;
73 }
74
75 TaskWidgetConfig::TaskWidgetConfig(InstallerContext& installContext) :
76     DPL::TaskDecl<TaskWidgetConfig>(this),
77     m_installContext(installContext),
78     m_installCancel(false)
79 {
80     AddStep(&TaskWidgetConfig::StepProcessConfigurationFile);
81     AddStep(&TaskWidgetConfig::ReadLocaleFolders);
82     AddStep(&TaskWidgetConfig::ProcessLocalizedStartFiles);
83     AddStep(&TaskWidgetConfig::ProcessLocalizedIcons);
84     AddStep(&TaskWidgetConfig::StepProcessPowderFile);
85     AddStep(&TaskWidgetConfig::StepVerifyFeatures);
86
87     //in case of tests, no popups are shown
88     if (GlobalSettings::GetPopupsEnabledFlag()) {
89         AddStep(&TaskWidgetConfig::StepShowWidgetInfo);
90         AddStep(&TaskWidgetConfig::StepCancelWidgetInstallation);
91     }
92 }
93
94 void TaskWidgetConfig::StepProcessConfigurationFile()
95 {
96     Try
97     {
98         WidgetConfigurationManagerSingleton::Instance().processFile(
99             m_installContext.tempWidgetPath,
100             m_installContext.widgetConfig);
101     }
102     Catch(WidgetConfigurationManager::Exception::ProcessFailed)
103     {
104         LogError("Parsing failed.");
105         ReThrow(Exceptions::WidgetConfigFileInvalid);
106     }
107     Try
108     {
109         // To get widget type for distribute WAC, TIZEN WebApp
110         setApplicationType();
111     }
112     Catch(WidgetConfigurationManager::Exception::ProcessFailed)
113     {
114         LogError("Config.xml has more than one namespace");
115         ReThrow(Exceptions::WidgetConfigFileInvalid);
116     }
117
118     m_installContext.job->SetProgressFlag(true);
119     m_installContext.job->UpdateProgress(
120         InstallerContext::INSTALL_WIDGET_CONFIG1,
121         "Parsing was suscessfull");
122 }
123
124 void TaskWidgetConfig::ReadLocaleFolders()
125 {
126     LogDebug("Reading locale");
127     //Adding default locale
128     m_localeFolders.insert(L"");
129
130     std::string localePath = m_installContext.tempWidgetPath + "/locales";
131     DIR* localeDir = opendir(localePath.c_str());
132     if (!localeDir) {
133         LogDebug("No /locales directory in the widget package.");
134         return;
135     }
136
137     struct dirent* dirent;
138     struct stat statStruct;
139     do {
140         errno = 0;
141         if ((dirent = readdir(localeDir))) {
142             DPL::String dirName = DPL::FromUTF8String(dirent->d_name);
143             std::string absoluteDirName = localePath + "/";
144             absoluteDirName += dirent->d_name;
145
146             if (stat(absoluteDirName.c_str(), &statStruct) != 0) {
147                 LogError("stat() failed with " << DPL::GetErrnoString());
148                 continue;
149             }
150
151             if (S_ISDIR(statStruct.st_mode)) {
152                 //Yes, we ignore current, parent & hidden directories
153                 if (dirName[0] != L'.') {
154                     LogDebug("Adding locale directory \"" << dirName << "\"");
155                     m_localeFolders.insert(dirName);
156                 }
157             }
158         }
159     }
160     while (dirent);
161
162     if (errno != 0) {
163         LogError("readdir() failed with " << DPL::GetErrnoString());
164     }
165
166     if (closedir(localeDir)) {
167         LogError("closedir() failed with " << DPL::GetErrnoString());
168     }
169 }
170
171 void TaskWidgetConfig::ProcessLocalizedStartFiles()
172 {
173     typedef DPL::String S;
174     ProcessStartFile(
175         m_installContext.widgetConfig.configInfo.startFile,
176         m_installContext.widgetConfig.configInfo.
177             startFileContentType,
178         m_installContext.widgetConfig.configInfo.startFileEncoding,
179         true);
180     ProcessStartFile(S(L"index.htm"), S(L"text/html"));
181     ProcessStartFile(S(L"index.html"), S(L"text/html"));
182     ProcessStartFile(S(L"index.svg"), S(L"image/svg+xml"));
183     ProcessStartFile(S(L"index.xhtml"), S(L"application/xhtml+xml"));
184     ProcessStartFile(S(L"index.xht"), S(L"application/xhtml+xml"));
185     // TODO: (l.wrzosek) we need better check if in current locales widget is valid.
186     FOREACH(it, m_installContext.widgetConfig.localizationData.startFiles) {
187         if (it->propertiesForLocales.size() > 0) {
188             return;
189         }
190     }
191     ThrowMsg(Exceptions::WidgetConfigFileInvalid,
192              L"The Widget has no valid start file");
193 }
194
195 void TaskWidgetConfig::ProcessStartFile(const DPL::OptionalString& path,
196         const DPL::OptionalString& type,
197         const DPL::OptionalString& encoding,
198         bool typeForcedInConfig)
199 {
200     using namespace WrtDB;
201
202     if (!!path) {
203         WidgetRegisterInfo::LocalizedStartFile startFileData;
204         startFileData.path = *path;
205
206         FOREACH(i, m_localeFolders) {
207             DPL::String pathPrefix = *i;
208             if (!pathPrefix.empty()) {
209                 pathPrefix = L"locales/" + pathPrefix + L"/";
210             }
211
212             DPL::String relativePath = pathPrefix + *path;
213             DPL::String absolutePath = DPL::FromUTF8String(
214                     m_installContext.tempWidgetPath) + L"/" + relativePath;
215
216             // get property data from packaged app
217             if (FileUtils::FileExists(absolutePath)) {
218                 WidgetRegisterInfo::StartFileProperties startFileProperties;
219                 if (!!type) {
220                     startFileProperties.type = *type;
221                 } else {
222                     startFileProperties.type =
223                         MimeTypeUtils::identifyFileMimeType(absolutePath);
224                 }
225
226                 //proceed only if MIME type is supported
227                 if (MimeTypeUtils::isMimeTypeSupportedForStartFile(
228                         startFileProperties.type))
229                 {
230                     if (!!encoding) {
231                         startFileProperties.encoding = *encoding;
232                     } else {
233                         MimeTypeUtils::MimeAttributes attributes =
234                             MimeTypeUtils::getMimeAttributes(
235                             startFileProperties.type);
236                         if (attributes.count(L"charset") > 0) {
237                             startFileProperties.encoding =
238                                 attributes[L"charset"];
239                         } else {
240                             startFileProperties.encoding = L"UTF-8";
241                         }
242                     }
243
244                     startFileData.propertiesForLocales[*i] =
245                         startFileProperties;
246                 } else {
247                     //9.1.16.5.content.8
248                     //(there seems to be no similar requirement in .6,
249                     //so let's throw only when mime type is
250                     // provided explcitly in config.xml)
251                     if (typeForcedInConfig) {
252                         ThrowMsg(Exceptions::WidgetConfigFileInvalid,
253                                  "Unsupported MIME type for start file.");
254                     }
255                 }
256             } else {
257                 // set property data for hosted start url
258                 // Hosted start url only support TIZEN WebApp
259                 if (m_installContext.widgetConfig.type ==
260                     APP_TYPE_TIZENWEBAPP)
261                 {
262                     const char *startPath =
263                         DPL::ToUTF8String(startFileData.path).c_str();
264                     if (strstr(startPath, "http") == startPath) {
265                         WidgetRegisterInfo::StartFileProperties
266                             startFileProperties;
267                         if (!!type) {
268                             startFileProperties.type = *type;
269                         }
270                         if (!!encoding) {
271                             startFileProperties.encoding = *encoding;
272                         }
273                         startFileData.propertiesForLocales[*i] =
274                             startFileProperties;
275                     }
276                 }
277             }
278         }
279
280         m_installContext.widgetConfig.localizationData.startFiles.push_back(
281             startFileData);
282     }
283 }
284
285 void TaskWidgetConfig::ProcessLocalizedIcons()
286 {
287     using namespace WrtDB;
288     ProcessIcon(ConfigParserData::Icon(L"icon.svg"));
289     ProcessIcon(ConfigParserData::Icon(L"icon.ico"));
290     ProcessIcon(ConfigParserData::Icon(L"icon.png"));
291     ProcessIcon(ConfigParserData::Icon(L"icon.gif"));
292     ProcessIcon(ConfigParserData::Icon(L"icon.jpg"));
293
294     FOREACH(i, m_installContext.widgetConfig.configInfo.iconsList)
295     {
296         ProcessIcon(*i);
297     }
298 }
299
300 void TaskWidgetConfig::ProcessIcon(const WrtDB::ConfigParserData::Icon& icon)
301 {
302     bool isAnyIconExisted = false;
303     //In case a default filename is passed as custom filename in config.xml, we
304     //need to keep a set of already processed filenames to avoid icon duplication
305     //in database.
306
307     using namespace WrtDB;
308
309     if (m_processedIconSet.count(icon.src) > 0) {
310         return;
311     }
312
313     m_processedIconSet.insert(icon.src);
314
315     LocaleSet localesAvailableForIcon;
316
317     FOREACH(i, m_localeFolders)
318     {
319         DPL::String pathPrefix = *i;
320         if (!pathPrefix.empty()) {
321             pathPrefix = L"locales/" + pathPrefix + L"/";
322         }
323
324         DPL::String relativePath = pathPrefix + icon.src;
325         DPL::String absolutePath = DPL::FromUTF8String(
326                 m_installContext.tempWidgetPath) + L"/" + relativePath;
327
328         if (FileUtils::FileExists(absolutePath)) {
329             isAnyIconExisted = true;
330             DPL::String type = MimeTypeUtils::identifyFileMimeType(absolutePath);
331
332             if (MimeTypeUtils::isMimeTypeSupportedForIcon(type)) {
333                 localesAvailableForIcon.insert(*i);
334             }
335             LogInfo("Icon absolutePath :" << absolutePath <<
336                     ", assigned locale :" << *i);
337         }
338     }
339
340     if(isAnyIconExisted)
341     {
342         WidgetRegisterInfo::LocalizedIcon localizedIcon(icon,
343                                                         localesAvailableForIcon);
344         m_installContext.widgetConfig.localizationData.icons.push_back(
345             localizedIcon);
346     }
347 }
348
349 void TaskWidgetConfig::StepProcessPowderFile(void)
350 {
351     using namespace WrtDB;
352     const std::string& path = m_installContext.tempWidgetPath;
353     WidgetRegisterInfo* widgetConfiguration =
354         &m_installContext.widgetConfig;
355
356     LogInfo("Process powder for guid " <<
357             widgetConfiguration->guid);
358     if (!!widgetConfiguration->guid) {
359         LibIri::Wrapper iri(DPL::ToUTF8String(
360                                 *widgetConfiguration->guid).c_str());
361         DPL::String widgetHost;
362         DPL::String widgetPath;
363         if (NULL != iri.m_Iri->host) {
364             widgetHost = DPL::FromUTF8String(iri.m_Iri->host);
365         }
366         if (NULL != iri.m_Iri->path) {
367             widgetPath = DPL::FromUTF8String(iri.m_Iri->path);
368         }
369         PowderParserData parserData(&widgetConfiguration->powderDescription,
370                                     widgetHost, widgetPath);
371         ConfigParserData::StringsList& descriptions =
372             widgetConfiguration->configInfo.powderDescriptionLinks;
373
374         FOREACH(linkIter, descriptions)
375         {
376             LogInfo("Process powder link: " << *linkIter);
377             LibIri::Wrapper link(DPL::ToUTF8String(*linkIter).c_str());
378             LogInfo("Parser link" << link);
379             if (strcmp(link.m_Iri->scheme, WIDGET_SCHEMA) == 0) {
380                 if (NULL != link.m_Iri->host) {
381                     std::ostringstream stream;
382                     //FIXME: Current libiri library is not able to parse
383                     //       URL: widget:/powder.xml Field host
384                     //       is filed with path
385                     stream << path << "/" << link.m_Iri->host;
386                     ParserRunner().Parse(
387                         stream.str(),
388                         ElementParserPtr(new
389                                          RootParser<PowderParser>(&parserData,
390                                                                   DPL::
391                                                                       FromUTF32String(
392                                                                       L"powder"))));
393                 } else {
394                     ThrowMsg(Exceptions::WidgetConfigFileInvalid,
395                              "Powder link " << *linkIter << " path empty.");
396                 }
397             } else {
398                 ThrowMsg(Exceptions::WidgetConfigFileInvalid,
399                          "Powder link " <<
400                          *linkIter <<
401                          " schema not supported.");
402             }
403         }
404     }
405
406     //TODO:FIXME make progress valid
407     m_installContext.job->UpdateProgress(
408         InstallerContext::INSTALL_WIDGET_CONFIG1,
409         "Widget Config powder step Finished");
410 }
411
412 void TaskWidgetConfig::AnswerCallback(const DPL::Popup::AnswerCallbackData &answer)
413 {
414     LogInfo("Callback called");
415     if (WRT_POPUP_BUTTON_CANCEL == answer.buttonAnswer) {
416         m_installCancel = WRT_POPUP_BUTTON_CANCEL;
417     }
418     m_installContext.job->Resume();
419 }
420
421 void TaskWidgetConfig::StepCancelWidgetInstallation()
422 {
423     if (WRT_POPUP_BUTTON_CANCEL == m_installCancel) {
424         ThrowMsg(Exceptions::NotAllowed, "Widget not allowed");
425     }
426 }
427
428 //TODO this step is not added in constructor
429 void TaskWidgetConfig::StepShowPowderPasswordCancel()
430 {
431     if (WRT_POPUP_BUTTON_CANCEL == m_installCancel) {
432         ThrowMsg(Exceptions::NotAllowed, "Parental Mode is ON");
433     }
434 }
435
436 void TaskWidgetConfig::PopupCreate()
437 {
438     m_installContext.job->Pause();
439     using namespace DPL::Popup;
440     CtrlPopupPtr popup = PopupControllerSingleton::Instance().CreatePopup();
441     popup->SetTitle(DPL::ToUTF8String(WIDGET_HEAD));
442     popup->Append(new PopupObject::Label(
443                       DPL::ToUTF8String(m_popupData.widgetInfo)));
444     m_popupData.widgetInfo.clear();
445     popup->Append(new PopupObject::Button(OK_BUTTON_LABEL,
446                                            WRT_POPUP_BUTTON_OK));
447     popup->Append(new PopupObject::Button(CANCEL_BUTTON_LABEL,
448                                            WRT_POPUP_BUTTON_CANCEL));
449     ListenForAnswer(popup);
450     ShowPopupEvent event(popup, MakeAnswerCallback(
451                              this,
452                              &TaskWidgetConfig::
453                                  AnswerCallback), DPL::Event::UNDEFINED_LOOP_HANDLE);
454     CONTROLLER_POST_EVENT(PopupController, event);
455 }
456
457 DPL::String TaskWidgetConfig::createPowderInfo() const
458 {
459     WrtDB::Powder::Description &powderDescription =
460         m_installContext.widgetConfig.powderDescription;
461     std::ostringstream powderInfo;
462     if (!!powderDescription.ageRating) {
463         powderInfo << AGE_RATING;
464         powderInfo << *powderDescription.ageRating;
465         powderInfo << BR;
466     }
467     FOREACH(categoriesIterator, powderDescription.categories) {
468         powderInfo << CATEGORY;
469         powderInfo << PowderInfoUtilSingleton::Instance().
470             getCategoryLabel(categoriesIterator->first);
471         powderInfo << BR;
472
473         FOREACH(levelIterator, categoriesIterator->second.levels) {
474             powderInfo << LEVEL;
475             powderInfo << static_cast<int>(levelIterator->level);
476             powderInfo << BR;
477
478             FOREACH(contextIterator, levelIterator->context) {
479                 powderInfo << CONTEXT;
480                 powderInfo << PowderInfoUtilSingleton::Instance().
481                     getContextLabel(*contextIterator);
482                 powderInfo << BR;
483             }
484         }
485     }
486
487     return DPL::FromUTF8String(powderInfo.str());
488 }
489
490 void TaskWidgetConfig::StepShowWidgetInfo()
491 {
492     if (!createPowderInfo().empty()) {
493         m_popupData.addWidgetInfo(POWDER_HEAD,
494                                   createPowderInfo());
495     }
496
497     if (!m_popupData.widgetInfo.empty()) {
498         PopupCreate();
499         m_installContext.job->UpdateProgress(
500             InstallerContext::INSTALL_WIDGET_CONFIG2,
501             "Show Widget Info Finished");
502     }
503 }
504
505 //TODO this step is not added in constructor
506 void TaskWidgetConfig::StepShowPowderPassword()
507 {
508     using namespace WrtDB;
509     if (GlobalDAOReadOnly::GetParentalMode()) {
510         m_popupData.addWidgetInfo(POWDER_INFO, POWDER_PASSWORD);
511     }
512     m_installContext.job->UpdateProgress(
513         InstallerContext::INSTALL_WIDGET_CONFIG2,
514         "Show Powder Password Finished");
515 }
516
517 void TaskWidgetConfig::StepVerifyFeatures()
518 {
519     using namespace WrtDB;
520     ConfigParserData &data = m_installContext.widgetConfig.configInfo;
521     ConfigParserData::FeaturesList list = data.featuresList;
522     ConfigParserData::FeaturesList newList;
523
524     //in case of tests, this variable is unused
525     std::string featureInfo;
526     FOREACH(it, list)
527     {
528         // check feature vender for permission
529         // WAC, TIZEN WebApp cannot use other feature
530         if (!isFeatureAllowed(m_installContext.widgetConfig.type.appType,
531                               it->name))
532         {
533             LogInfo("This application type not allowed to use this feature");
534             ThrowMsg(
535                 Exceptions::WidgetConfigFileInvalid,
536                 "This app type [" <<
537                 m_installContext.widgetConfig.type.getApptypeToString() <<
538                 "] cannot be allowed to use [" <<
539                 DPL::ToUTF8String(it->name) + "] feature");
540         }
541         if (!WrtDB::FeatureDAOReadOnly::isFeatureInstalled(
542                 DPL::ToUTF8String(it->name))) {
543             LogWarning("Feature not found. Checking if required :[" <<
544                        DPL::ToUTF8String(it->name) << "]");
545
546             if (it->required) {
547                 LogWarning(
548                     "Required Features missing, Installation topped: [" <<
549                     DPL::ToUTF8String(it->name) << "]");
550
551                 ThrowMsg(
552                     Exceptions::WidgetConfigFileInvalid,
553                     "Widget cannot be installedm equired feature is missing:["
554                     +
555                     DPL::ToUTF8String(it->name) + "]");
556             }
557         } else {
558             newList.insert(*it);
559             featureInfo += DPL::ToUTF8String(it->name);
560             featureInfo += DPL::ToUTF8String(BR);
561         }
562     }
563     data.featuresList = newList;
564     if (!featureInfo.empty()) {
565         m_popupData.addWidgetInfo(FEATURE_HEAD,
566                                   DPL::FromUTF8String(featureInfo));
567     }
568
569     m_installContext.job->UpdateProgress(
570         InstallerContext::INSTALL_WIDGET_CONFIG2,
571         "Widget Config step2 Finished");
572 }
573
574 void TaskWidgetConfig::setApplicationType()
575 {
576     using namespace WrtDB;
577     WidgetRegisterInfo* widgetInfo = &(m_installContext.widgetConfig);
578     ConfigParserData* configInfo = &(widgetInfo->configInfo);
579
580     FOREACH(iterator, configInfo->nameSpaces) {
581         LogInfo("namespace = [" << *iterator << "]");
582         AppType currentAppType = APP_TYPE_UNKNOWN;
583
584         if (*iterator == ConfigurationNamespace::W3CWidgetNamespaceName) {
585             continue;
586         } else if (*iterator ==
587                 ConfigurationNamespace::JilWidgetNamespaceName) {
588             currentAppType = APP_TYPE_WAC10;
589         } else if (
590             *iterator ==
591             ConfigurationNamespace::WacWidgetNamespaceNameForLinkElement ||
592             *iterator ==
593             ConfigurationNamespace::WacWidgetNamespaceName)
594         {
595             currentAppType = APP_TYPE_WAC20;
596         } else if (*iterator == ConfigurationNamespace::TizenWebAppNamespaceName) {
597             currentAppType = APP_TYPE_TIZENWEBAPP;
598         }
599
600         if (widgetInfo->type == APP_TYPE_UNKNOWN) {
601             widgetInfo->type = currentAppType;
602         } else if (widgetInfo->type == currentAppType) {
603             continue;
604         } else {
605             ThrowMsg(Exceptions::WidgetConfigFileInvalid,
606                      "Config.xml has more than one namespace");
607         }
608     }
609
610     // If there is no define, type set to WAC 2.0
611     if (widgetInfo->type == APP_TYPE_UNKNOWN) {
612         widgetInfo->type = APP_TYPE_WAC20;
613     }
614
615     LogInfo("type = [" << widgetInfo->type.getApptypeToString() << "]");
616 }
617
618 bool TaskWidgetConfig::isFeatureAllowed(WrtDB::AppType appType,
619                                         DPL::String featureName)
620 {
621     using namespace WrtDB;
622     LogInfo("AppType = [" <<
623             WidgetType(appType).getApptypeToString() << "]");
624     LogInfo("FetureName = [" << featureName << "]");
625
626     AppType featureType = APP_TYPE_UNKNOWN;
627     const char* feature = DPL::ToUTF8String(featureName).c_str();
628     // check prefix of  feature name
629     if (strstr(feature, PluginsPrefix::TIZENPluginsPrefix) == feature) {
630         // Tizen WebApp feature
631         featureType = APP_TYPE_TIZENWEBAPP;
632     } else if (strstr(feature, PluginsPrefix::WACPluginsPrefix) == feature) {
633         // WAC 2.0 feature
634         featureType = APP_TYPE_WAC20;
635     } else if (strstr(feature, PluginsPrefix::W3CPluginsPrefix) == feature) {
636         // W3C standard feature
637         // Both WAC and TIZEN WebApp are possible to use W3C plugins
638         return true;
639     } else {
640         // unknown feature
641         // unknown feature will be checked next step
642         return true;
643     }
644
645     if (appType == featureType) {
646         return true;
647     }
648     return false;
649 }
650
651 } //namespace WidgetInstall
652 } //namespace Jobs