//TODO: this should eventually just be the == operator. However, for now, allow operator== to be a weaker comparison //whereas this function will compare every *info* field (not counting internal fields like execution lock, etc) bool ApplicationDescription::strictCompare(const ApplicationDescription& cmp) const { if (m_id != cmp.id()) return false; if (m_category != cmp.m_category) return false; if (m_entryPoint != cmp.m_entryPoint) return false; if (cmp.m_isRemovable && (m_version != cmp.m_version)) return false; if (m_mimeTypes != cmp.m_mimeTypes) return false; if (m_redirectTypes != cmp.m_redirectTypes) return false; if (m_folderPath != cmp.m_folderPath) return false; if (m_vendorName != cmp.m_vendorName) return false; if (m_vendorUrl != cmp.m_vendorUrl) return false; if (m_isHeadLess != cmp.m_isHeadLess) return false; if (m_hasTransparentWindows != cmp.m_hasTransparentWindows) return false; if (m_isVisible != cmp.m_isVisible) return false; if (m_appSize != cmp.m_appSize) return false; if (m_tapToShareSupported != cmp.m_tapToShareSupported) return false; return true; }
bool WebAppManager::validateApplication(const ApplicationDescription& desc) { if (desc.id().length() == 0) return false; if (desc.entryPoint().isLocalFile() && !QFile::exists(desc.entryPoint().toLocalFile())) return false; return true; }
bool ApplicationDescription::operator!=(const ApplicationDescription& cmp) const { return (m_id != cmp.id()); }
ApplicationDescription* ApplicationDescription::fromFile(const std::string& filePath, const std::string& folderPath) { bool success = false; ApplicationDescription* appDesc = 0; char* jsonStr = 0; const gchar* palmAppDirPrefix = "/usr/palm/applications/"; std::vector<MimeRegInfo> extractedMimeTypes; std::string launchParams; std::string builtinEntrypt; std::string builtinArgs; jsonStr = readFile(filePath.c_str()); if (!jsonStr || !g_utf8_validate(jsonStr, -1, NULL)) { return 0; } struct json_object* root=0; struct json_object* label=0; std::string title, icon, dirPath; gchar* dirPathCStr; dirPathCStr = g_path_get_dirname(filePath.c_str()); dirPath = dirPathCStr; dirPath += "/"; g_free(dirPathCStr); root = json_tokener_parse( jsonStr ); if( !root || is_error( root ) ) { g_warning("%s: Failed to parse '%s' into a JSON string", __FUNCTION__, filePath.c_str() ); goto Done; } appDesc = new ApplicationDescription(); appDesc->m_folderPath = folderPath; // ID: mandatory label = json_object_object_get(root, "id"); if( label && !is_error(label) ) { appDesc->m_id = json_object_get_string(label); } else { g_warning("%s: App %s does not have an ID", __FUNCTION__, filePath.c_str() ); goto Done; } // MAIN: optional label = json_object_object_get(root, "main"); if( label && !is_error(label) ) { appDesc->m_entryPoint = json_object_get_string(label); } else { appDesc->m_entryPoint = "index.html"; } if (!strstr(appDesc->m_entryPoint.c_str(), "://")) appDesc->m_entryPoint = std::string("file://") + dirPath + appDesc->m_entryPoint; // TITLE: mandatory label = json_object_object_get(root, "title"); if( label && !is_error(label) ) { appDesc->m_title = json_object_get_string(label); } else { g_warning("%s: App %s does not have a title",__FUNCTION__, filePath.c_str() ); goto Done; } // SHORT NAME: optional label = json_object_object_get(root,"appmenu"); if ( label && !is_error(label)) { appDesc->m_appmenuName = json_object_get_string(label); } else appDesc->m_appmenuName = appDesc->m_title; // KEYWORDS: optional label = json_object_object_get(root,"keywords"); if ( label && !is_error(label)) { appDesc->m_keywords.addKeywords(label); } //MIME HANDLING REGISTRATIONS: optional label = json_object_object_get(root,"mimeTypes"); if ( label && !is_error(label)) { if (utilExtractMimeTypes(label,extractedMimeTypes)) { //found some! for (std::vector<MimeRegInfo>::iterator it = extractedMimeTypes.begin(); it != extractedMimeTypes.end(); ++it) { if ((*it).mimeType.size()) { // ADD BY MIME TYPE. The extension that is appropriate for this mimeType will be automatically filled in into "extension" if successful if (MimeSystem::instance()->addResourceHandler((*it).extension,(*it).mimeType,!((*it).stream),appDesc->id(),NULL,false) > 0) appDesc->m_mimeTypes.push_back(ResourceHandler((*it).extension,(*it).mimeType,appDesc->id(),(*it).stream)); //success adding to mime system, so add it to this app descriptor for bookeeping purposes } else if ((*it).extension.size()) { // ADD BY EXTENSION... count on the extension->mime mapping to already exist, or this will fail if (MimeSystem::instance()->addResourceHandler((*it).extension,!((*it).stream),appDesc->id(),NULL,false) > 0) { //get the mime type MimeSystem::instance()->getMimeTypeByExtension((*it).extension,(*it).mimeType); appDesc->m_mimeTypes.push_back(ResourceHandler((*it).extension,(*it).mimeType,appDesc->id(),(*it).stream)); } } else if ((*it).scheme.size()) { //TODO: fix this so it's more robust; it should check if the way the appinfo file specified the scheme is in fact a valid "scheme form" regexp and if not, make it one // ADD REDIRECT: THIS IS A SCHEME or "COMMAND" FORM.... (e.g. "tel://") (*it).scheme = std::string("^")+(*it).scheme+std::string(":"); if (MimeSystem::instance()->addRedirectHandler((*it).scheme,appDesc->id(),NULL,true,false) > 0) { appDesc->m_redirectTypes.push_back(RedirectHandler((*it).scheme,appDesc->id(),true)); } } else if ((*it).urlPattern.size()) { // ADD REDIRECT: THIS IS A PURE REDIRECT FORM... (e.g. "^[^:]+://www.youtube.com/watch\\?v=" if (MimeSystem::instance()->addRedirectHandler((*it).urlPattern,appDesc->id(),NULL,false,false) > 0) { appDesc->m_redirectTypes.push_back(RedirectHandler((*it).urlPattern,appDesc->id(),false)); } } } } } // ICON: we have a default if this is not present. label = json_object_object_get(root, "icon"); if( label && !is_error(label) ) { icon = dirPath + json_object_get_string(label); } else icon = dirPath + "icon.png"; // Optional parameters success = true; // Type: optional (defaults to Type_Web) label = json_object_object_get(root, "type"); if (label && !is_error(label) && json_object_is_type(label, json_type_string)) { if (strncmp(json_object_get_string(label), "game", 4) == 0) appDesc->m_type = Type_Native; else if (strncmp(json_object_get_string(label), "pdk", 3) == 0) appDesc->m_type = Type_PDK; else if (strncmp(json_object_get_string(label), "qt", 2) == 0) appDesc->m_type = Type_Qt; else if (strncmp(json_object_get_string(label), "sysmgrbuiltin" , 13 ) == 0) appDesc->m_type = Type_SysmgrBuiltin; else appDesc->m_type = Type_Web; } // SPLASH ICON: optional (Used for loading/splash screen for cards) label = json_object_object_get(root, "splashicon"); if (label && !is_error(label)) { appDesc->m_splashIconName = dirPath + json_object_get_string(label); } // SPLASH BACKGROUND: optional (Used for loading/splash screen for cards) label = json_object_object_get(root, "splashBackground"); if (label && !is_error(label) && json_object_is_type(label, json_type_string)) { appDesc->m_splashBackgroundName = dirPath + json_object_get_string(label); } else { label = json_object_object_get(root, "splashbackground"); if (label && !is_error(label) && json_object_is_type(label, json_type_string)) { appDesc->m_splashBackgroundName = dirPath + json_object_get_string(label); } } // MINI ICON: optional (Used for notification banner area) label = json_object_object_get(root, "miniicon"); if( label && !is_error(label) ) { appDesc->m_miniIconName = json_object_get_string(label); } else appDesc->m_miniIconName = "miniicon.png"; appDesc->m_miniIconName = dirPath + appDesc->m_miniIconName; // LAUNCH IN NEW GROUP: optional (Used to prevent app from launching in current card stack) label = json_object_object_get(root, "launchinnewgroup"); if( label && !is_error(label) ) { appDesc->m_launchInNewGroup = json_object_get_boolean(label); } else appDesc->m_launchInNewGroup = false; // CATEGORY: optional label = json_object_object_get(root, "category"); if( label && !is_error(label) ) { appDesc->m_category = json_object_get_string(label); } // VENDOR: optional label = json_object_object_get(root, "vendor"); if( label && !is_error(label) ) { appDesc->m_vendorName = json_object_get_string(label); } else if (g_str_has_prefix(dirPath.c_str(), palmAppDirPrefix)) { appDesc->m_vendorName = "Palm, Inc."; } // VENDOR URL: optional label = json_object_object_get(root, "vendorurl"); if( label && !is_error(label) ) { appDesc->m_vendorUrl = json_object_get_string(label); } // SIZE: optional label = json_object_object_get(root, "appsize"); if( label && !is_error(label) ) { appDesc->m_appSize = (unsigned int) json_object_get_int(label); } // RUNTIME MEMORY REQUIRED: optional label = json_object_object_get(root, "requiredMemory"); if( label && !is_error(label) ) { appDesc->m_runtimeMemoryRequired = (unsigned int) json_object_get_int(label); //json_object_put( label ); } // HEADLESS: optional label = json_object_object_get(root, "noWindow"); if( label && !is_error(label) ) { appDesc->m_isHeadLess = (strcasecmp( json_object_get_string(label), "true") == 0); } //VISIBLE: optional* by default the launch icons are visible...set to false in the json and they won't show in the //launcher screen label = json_object_object_get(root, "visible"); if( label && !is_error(label) ) { if (json_object_is_type(label,json_type_string)) appDesc->m_isVisible = (strcasecmp( json_object_get_string(label), "true") == 0); else appDesc->m_isVisible = json_object_get_boolean(label); } // TRANSPARENT: optional label = json_object_object_get(root, "transparent"); if( label && !is_error(label) ) { appDesc->m_hasTransparentWindows = (strcasecmp( json_object_get_string(label), "true") == 0); } // VERSION: optional? label = json_object_object_get(root, "version"); if (label && !is_error(label)) { appDesc->m_version = json_object_get_string(label); } // additional attributes, like http proxy label = json_object_object_get(root, "attributes"); if (label && !is_error(label)) { appDesc->m_attributes = json_object_get_string(label); } // REMOVABLE: optional label = json_object_object_get(root, "removable"); if (label && !is_error(label) && json_object_is_type(label, json_type_boolean)) { // Any appinfo.json can set removable to true. But if you want to set removable to false you better be a trusted palm application // NOTE: we should always be able to trust the removable flag set in the appinfo appDesc->m_isRemovable = json_object_get_boolean(label); g_debug("%s: App %s is %s because of appinfo.json",__FUNCTION__, appDesc->m_id.c_str(), appDesc->m_isRemovable ? "removable" : "non-removable"); } else { // apps in ROM are never removable appDesc->m_isRemovable = !(folderPath.find("/usr") == 0); g_debug("%s: App %s is %s by default",__FUNCTION__, appDesc->m_id.c_str(), appDesc->m_isRemovable ? "removable" : "non-removable"); } // DOCK ENABLED: optional (defines if this app can provide a Dock mode stage) label = json_object_object_get(root, "exhibitionMode"); if (!label || is_error (label)) // maintaining backward compatibility label = json_object_object_get(root, "dockMode"); if (label && !is_error(label) && json_object_is_type(label, json_type_boolean)) { appDesc->m_dockMode = json_object_get_boolean(label); if(appDesc->m_dockMode) { // read the optional Dock mode parameters struct json_object *dockOptions=0, *dockLabel=0; // DOCK Mode options: (optional) dockOptions = json_object_object_get(root, "exhibitionModeOptions"); if (!dockOptions || is_error (dockOptions)) // maintaining backward compatibility dockOptions = json_object_object_get(root, "dockModeOptions"); if (dockOptions && !is_error(dockOptions)) { dockLabel = json_object_object_get(dockOptions, "title"); if (dockLabel && !is_error(dockLabel) && json_object_is_type(dockLabel, json_type_string)) { appDesc->m_dockModeTitle = json_object_get_string(dockLabel); } else { appDesc->m_dockModeTitle = appDesc->m_appmenuName; } } else { appDesc->m_dockModeTitle = appDesc->m_appmenuName; } } } // Hardware features needed: optional label = json_object_object_get(root, "hardwareFeaturesNeeded"); if (label && !is_error(label) && json_object_is_type(label, json_type_array)) { for (int i = 0; i < json_object_array_length(label); i++) { struct json_object* entry = json_object_array_get_idx(label, i); if (!entry || is_error(entry)) continue; if (!json_object_is_type(entry, json_type_string)) continue; const char* str = json_object_get_string(entry); if (strncasecmp(str, "wifi", 4) == 0) appDesc->m_hardwareFeaturesNeeded |= HardwareFeaturesNeeded_Wifi; else if (strncasecmp(str, "bluetooth", 9) == 0) appDesc->m_hardwareFeaturesNeeded |= HardwareFeaturesNeeded_Bluetooth; else if (strncasecmp(str, "compass", 7) == 0) appDesc->m_hardwareFeaturesNeeded |= HardwareFeaturesNeeded_Compass; else if (strncasecmp(str, "accelerometer", 13) == 0) appDesc->m_hardwareFeaturesNeeded |= HardwareFeaturesNeeded_Accelerometer; } } //Universal Search JSON objct: optional label = json_object_object_get(root, "universalSearch"); if(label && !is_error(label)) { appDesc->m_universalSearchJsonStr = json_object_to_json_string(label); } // Services JSON array: optional label = json_object_object_get(root, "services"); if (label && !is_error(label)) appDesc->m_servicesJsonStr = json_object_to_json_string(label); // Accounts JSON array: optional label = json_object_object_get(root, "accounts"); if (label && !is_error(label)) appDesc->m_accountsJsonStr = json_object_to_json_string(label); // Launch params: optional label = json_object_object_get(root, "params"); if (label && !is_error(label)) { if (appDesc->m_type == Type_Qt) launchParams = json_object_get_string(label); else launchParams = json_object_to_json_string(label); } // Tap to Share Supported: optional label = json_object_object_get(root, "tapToShareSupported"); if (label && !is_error(label)) { appDesc->m_tapToShareSupported = json_object_get_boolean(label); } // Requested Window Orientation: optional label = json_object_object_get(root, "requestedWindowOrientation"); if( label && !is_error(label) && json_object_is_type(label, json_type_string)) { appDesc->m_requestedWindowOrientation = json_object_get_string(label); } //check to see if it's a sysmgr-builtin if (appDesc->m_type == Type_SysmgrBuiltin) { //must have an entrypoint label = json_object_object_get(root,"entrypoint"); if ((!label) || is_error(label)) { g_warning("%s: App %s of type SysmgrBuiltin doesn't name an entrypoint",__FUNCTION__,appDesc->m_id.c_str()); success = false; goto Done; } builtinEntrypt = json_object_get_string(label); label = json_object_object_get(root,"args"); if (label && !is_error(label)) builtinArgs = json_object_get_string(label); else builtinArgs = ""; //update fields that can be localized ...won't be done automatically because of sysmgr builtins being in a special location appDesc->updateSysmgrBuiltinWithLocalization(); //try and create a launch helper if (appDesc->initSysmgrBuiltIn(ApplicationManager::instance(),builtinEntrypt,builtinArgs) == false) { //failed...something was specified wrong g_warning("%s: App %s cannot be formed into a sysmgrbuiltin: entry = [%s] , args = [%s]", __FUNCTION__,appDesc->m_id.c_str(),builtinEntrypt.c_str(),builtinArgs.c_str()); success = false; goto Done; } } Done: if( root && !is_error(root) )json_object_put(root); delete [] jsonStr; if (!success) { delete appDesc; return 0; } // Default launchpoint (with empty params) LaunchPoint * defaultLp = new LaunchPoint(appDesc, appDesc->m_id, appDesc->m_id + "_default", appDesc->m_title, appDesc->m_appmenuName, icon, launchParams,appDesc->m_isRemovable); defaultLp->setAsDefault(); appDesc->m_launchPoints.push_back(defaultLp); return appDesc; }
void WebAppBase::attach(WebPage* page) { WebAppManager::instance()->reportAppLaunched(page->appId(), page->processId()); if (m_page) { detach(); } m_page = page; m_page->setClient(this); m_appId = page->appId(); m_processId = page->processId(); createActivity(); ApplicationDescription* appDesc = getAppDescription(); if (appDesc == NULL || appDesc->id().empty() || appDesc->attributes().empty()) { return; } struct json_object* root = json_tokener_parse(appDesc->attributes().c_str()); if (!root || is_error(root)) { fprintf(stderr, "Failed to parse '%s' into a JSON string.\n", appDesc->attributes().c_str()); return; } // parse out optional http proxy host and port app attributes char* httpProxyHost = NULL; int httpProxyPort = 0; struct json_object* label = json_object_object_get(root, "proxyhost"); if (label && !is_error(label)) { httpProxyHost = json_object_get_string(label); } label = json_object_object_get(root, "proxyport"); if (label && !is_error(label)) { httpProxyPort = json_object_get_int(label); } if (httpProxyHost != NULL && httpProxyPort != 0 && m_page->webkitPage()) { m_page->webkitPage()->enableHttpProxy(httpProxyHost, httpProxyPort); } // parse out optional data connection interface type attributes char* interfaceName = NULL; label = json_object_object_get(root, "forceInterface"); if (label && !is_error(label)) { interfaceName = json_object_get_string(label); } if (interfaceName != NULL && m_page->webkitPage()) { if (0 == strcmp(interfaceName, wanIdentifierString)) { m_page->webkitPage()->forceNetworkInterface(Settings::LunaSettings()->wanInterfaceName.c_str()); // use cellular } else if (0 == strcmp(interfaceName, wifiIdentifierString)) { m_page->webkitPage()->forceNetworkInterface(Settings::LunaSettings()->wifiInterfaceName.c_str()); // use wifi } else { m_page->webkitPage()->forceNetworkInterface(NULL); // use any } } if (root && !is_error(root)) { json_object_put(root); } }
/** * Launch an application (webApps only, not native). * * @param appId The application ID to launch. * @param params The call parameters. * @param the ID of the application performing the launch (can be NULL). * @param launchingProcId (can be NULL). * @param errMsg The error message (will be empty if this call was successful). * * @todo: this should now be moved private and be protected...leaving it for now as to not break stuff and make things * slightly faster for intra-sysmgr mainloop launches * * @return The process ID of the newly launched application. Empty upon error. If empty lool at errMsg. */ std::string ProcessManager::launch(const std::string& appDescString, const std::string& params, const std::string& launchingAppId, const std::string& launchingProcId, std::string& errMsg) { std::string processId = ""; ApplicationDescription* desc = ApplicationDescription::fromJsonString(appDescString.c_str()); errMsg.erase(); // This now will only launch Web Apps. Native Apps are now launched by the WebAppMgrProxy. // Find out what type of window we need to create Window::Type winType = Window::Type_Card; std::string winTypeStr; if (extractFromJson(params, "windowType", winTypeStr)) { if (winTypeStr == "dashboard") winType = Window::Type_Dashboard; else if (winTypeStr == "popupalert") winType = Window::Type_PopupAlert; else if (winTypeStr == "emergency") winType = Window::Type_Emergency; else if (winTypeStr == "dockModeWindow") // $$$ FIX THIS, it is just a patch to test Dock mode apps for now winType = Window::Type_DockModeWindow; else { winType = Window::Type_Emulated_Card; if (desc->uiRevision() == 2) { winType = Window::Type_Card; } } } if (winType == Window::Type_Card) { if (desc->uiRevision() != 2) { winType = Window::Type_Emulated_Card; } } // Get a list of all apps typedef std::list<const ProcessBase*> ProcessList; ProcessList runningApps = WebAppManager::instance()->runningApps(); const ProcessBase* app = 0; for (ProcessList::const_iterator it = runningApps.begin(); it != runningApps.end(); ++it) { if ((*it)->appId() == desc->id()) { app = (*it); processId = app->processId(); break; } } if (!app) { // App not running? Launch it std::string url = desc->entryPoint(); if (desc->isHeadLess()) winType = Window::Type_None; processId = processIdFactory(); WebAppManager::instance()->onLaunchUrl(url.c_str(), winType, appDescString.c_str(), processId.c_str(), params.c_str(), launchingAppId.c_str(), launchingProcId.c_str()); g_debug("Launched Id %s", processId.c_str() ); } else { WebAppManager::instance()->onRelaunchApp(processId.c_str(), params.c_str(), launchingAppId.c_str(), launchingProcId.c_str()); } delete desc; return processId; }