diff -r 000000000000 -r 16d8024aca5e src/hbcore/indicatorplugins/hbindicatorpluginmanager.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hbcore/indicatorplugins/hbindicatorpluginmanager.cpp Mon Apr 19 14:02:13 2010 +0300 @@ -0,0 +1,553 @@ +/**************************************************************************** +** +** Copyright (C) 2008-2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (developer.feedback@nokia.com) +** +** This file is part of the HbCore module of the UI Extensions for Mobile. +** +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at developer.feedback@nokia.com. +** +****************************************************************************/ + +#include +#include + +#include +#include +#include +#include +#include + +/* + \class HbIndicatorPluginManager + \brief HbIndicatorPluginManager manages loading and unloading of indicator plugins + + HbIndicatorPluginManager maintains a list of indicators which are created from + indicator plugins +*/ + +// Constructor +HbIndicatorPluginManager::HbIndicatorPluginManager(QObject *parent) : + QObject(parent), mNameCache(pluginKeys) +{ + // Get list of plugin directories to watch/scan + const QStringList pathList = pluginPathList(); + for (int i = 0; i < pathList.length(); i++) { + updateCachePath(pathList.at(i)); + } +} + +// Destructor +HbIndicatorPluginManager::~HbIndicatorPluginManager() +{ +} + +/* + Searches for plugin, that implements the indicator of type \a indicatorType. + Creates and stores the indicator. + Does nothing, if indicator is already added. + Returns true on success and false on failure. +*/ +HbIndicatorInterface *HbIndicatorPluginManager::addIndicator(const QString &indicatorType, + const QVariantMap &securityCredentials, int *errorCode) +{ + TRACE_ENTRY + int error = HbDeviceDialogNoError; + if (!errorCode) { + errorCode = &error; + } + HbIndicatorInterface *indicator = 0; + bool loaded = false; + bool added = false; + *errorCode = HbDeviceDialogNoError; + + //search indicator 1. among already loaded plugins. + int index = findPlugin(indicatorType); + if (index < 0) { + //2. search and load the correct plugin. + index = loadPlugin(indicatorType); + loaded = true; + } + // Allow plugin to do access control + if (index >= 0) { + if (!checkAccess(index, indicatorType, securityCredentials)) { + if (loaded) { + mPlugins.removeAt(index); + } + *errorCode = HbDeviceDialogAccessDeniedError; + index = -1; + } + } + if (index >= 0) { + PluginInfo &pluginInfo = mPlugins[index]; + if (!loaded) { + //check is the indicator is already created. + foreach(const IndicatorInfo &indicatorInfo, + pluginInfo.mAddedIndicators) { + if (indicatorInfo.indicator->indicatorType() == + indicatorType) { + indicator = indicatorInfo.indicator; + added = true; + break; + } + } + } + if (!added) { + //create and store the indicator. + HbIndicatorPluginInterface *plugin = pluginInfo.plugin(); + if (plugin) { + indicator = plugin->createIndicator(indicatorType); + } + if (indicator) { + pluginInfo.mAddedIndicators.append(indicator); + added = true; + } else { + if (pluginInfo.mAddedIndicators.count() == 0) { + mPlugins.removeAt(index); + } + *errorCode = plugin->error(); + TRACE("creating indicator: " + << indicatorType << " from plugin failed"); + } + } + } + + if (!added && error == HbDeviceDialogNoError) { + *errorCode = HbDeviceDialogUnknownIndicatorError; + } + + TRACE_EXIT + return indicator; +} + +/* + Activates the indicator. + Assumes indicator-instance is already created (addIndicator called). +*/ +bool HbIndicatorPluginManager::activateIndicator(const QString &indicatorType, + const QVariant ¶meter, const QVariantMap &securityCredentials) +{ + bool success = false; + IndicatorInfo *indicatorInfo = 0; + int index = findPlugin(indicatorType, &indicatorInfo); + if (index >= 0 && checkAccess(index, indicatorType, securityCredentials)) { + HbIndicatorInterface *indicator = indicatorInfo->indicator; + + indicator->disconnect(this, SLOT(deactivateIndicator())); + connect(indicator, SIGNAL(deactivate()), SLOT(deactivateIndicator()), Qt::QueuedConnection); + + indicator->processClientRequest( + HbIndicatorInterface::RequestActivate, parameter); + //in case indicator deactivated itself, find the indicator again. + index = findPlugin(indicatorType, &indicatorInfo); + + if (index >= 0 && !indicatorInfo->activated) { + indicatorInfo->activated = true; + emit indicatorActivated(indicator); + indicatorInfo->statusAreaIconPath = statusAreaIconPath(indicator); + emit indicatorActivated(IndicatorClientInfo( + indicator->indicatorType(), + indicatorInfo->statusAreaIconPath, + indicator->category())); + + connect(indicator, SIGNAL(dataChanged()), SLOT(indicatorDataChanged())); + } + success = true; + } + return success; +} + +/* + removes indicator from memory. + Returns true, if indicator was removed, false otherwise. +*/ +bool HbIndicatorPluginManager::removeIndicator(const QString &indicatorType) +{ + TRACE_ENTRY + bool removed = false; + int infoIndex = 0; + IndicatorInfo *indicatorInfo = 0; + + int index = findPlugin(indicatorType, &indicatorInfo, &infoIndex); + if (index >= 0) { + PluginInfo &pluginInfo = mPlugins[index]; + HbIndicatorInterface *indicator = indicatorInfo->indicator; + QString statusAreaPath(indicatorInfo->statusAreaIconPath); + + pluginInfo.mAddedIndicators.remove(infoIndex); + indicatorInfo = 0; //destroyed + emit indicatorRemoved(indicator); + + emit indicatorRemoved(IndicatorClientInfo( + indicator->indicatorType(), + statusAreaPath, + indicator->category())); + + //plugin-interface may also be HbIndicatorInterface. + //in that case, don't delete. + HbIndicatorInterface *testPlugin = + dynamic_cast(pluginInfo.plugin()); + if ( testPlugin != indicator) { + //indicator deletion must occur before idle-timer-cleanup. + delete indicator; + indicator = 0; + } + + // delete plugin interface + int count = mPlugins.count(); + for(int i = count-1; i >= 0; --i) { + PluginInfo &pluginInfo = mPlugins[i]; + if (pluginInfo.mAddedIndicators.count() == 0) { + mPlugins.removeAt(i); + } + } + removed = true; + } + TRACE_EXIT + return removed; +} + +//returns the indicator information needed in client side. +QList + HbIndicatorPluginManager::indicatorClientInfoList() const +{ + QList clientInfoList; + + //add icons from all the activated indicators of group priority 1 and 2. + foreach (const PluginInfo &pluginInfo, mPlugins) { + foreach(const IndicatorInfo &indicatorInfo, + pluginInfo.mAddedIndicators) { + + HbIndicatorInterface *indicator = indicatorInfo.indicator; + HbIndicatorInterface::Category category = indicator->category(); + + QString path(indicatorInfo.statusAreaIconPath); + + if (!path.isEmpty()) { + IndicatorClientInfo clientInfo( + indicator->indicatorType(), path, category); + clientInfoList.append(clientInfo); + } + } + } + return clientInfoList; +} + +QList + HbIndicatorPluginManager::indicators() const +{ + QList indicatorList; + foreach (const PluginInfo &pluginInfo, mPlugins) { + foreach(const IndicatorInfo &indicatorInfo, + pluginInfo.mAddedIndicators) { + if (indicatorInfo.activated) { + indicatorList.append(indicatorInfo.indicator); + } + } + } + return indicatorList; +} + +void HbIndicatorPluginManager::connectTo(QObject *widget) +{ + widget->disconnect(this); + + //connect pluginmanager signals to indicatormenu slots, so that + //popup will get indicator updates. + widget->connect(this, + SIGNAL(indicatorActivated(HbIndicatorInterface*)), + SLOT(indicatorActivated(HbIndicatorInterface*))); + widget->connect(this, + SIGNAL(indicatorRemoved(HbIndicatorInterface*)), + SLOT(indicatorRemoved(HbIndicatorInterface*))); + QList addedIndicators = indicators(); + + if (addedIndicators.count() > 0) { + //initialize popup with added indicators. + QMetaObject::invokeMethod(widget, "indicatorsActivated", + Qt::DirectConnection, + Q_ARG(QList, addedIndicators)); + } +} + +bool HbIndicatorPluginManager::deactivateIndicator(const QString &indicatorType, + const QVariant ¶meter, const QVariantMap &securityCredentials) +{ + TRACE_ENTRY + bool success = false; + IndicatorInfo *info = 0; + int index = findPlugin(indicatorType, &info); + if (index >= 0 && checkAccess(index, indicatorType, securityCredentials)) { + HbIndicatorInterface *indicator = info->indicator; + if (indicator->indicatorType() == indicatorType && info->activated) { + indicator->processClientRequest( + HbIndicatorInterface::RequestDeactivate, parameter); + } + success = true; + } + TRACE_EXIT + return success; +} + +void HbIndicatorPluginManager::deactivateIndicator() +{ + HbIndicatorInterface* indicator = + qobject_cast(sender()); + if (indicator) { + indicator->disconnect(this); + removeIndicator(indicator->indicatorType()); + } +} + +void HbIndicatorPluginManager::indicatorDataChanged() +{ + const HbIndicatorInterface* indicator = + qobject_cast(sender()); + if (!indicator) { + return; + } + + IndicatorInfo *indicatorInfo = 0; + int index = findPlugin(indicator->indicatorType(), &indicatorInfo); + if (index >= 0) { + indicator = indicatorInfo->indicator; + QString statusAreaPath(statusAreaIconPath(indicator)); + + if (indicatorInfo->statusAreaIconPath != statusAreaPath) { + indicatorInfo->statusAreaIconPath = statusAreaPath; + + emit indicatorUpdated(IndicatorClientInfo( + indicator->indicatorType(), + indicatorInfo->statusAreaIconPath, + indicator->category())); + } + } +} + +bool HbIndicatorPluginManager::checkAccess(int index, const QString &indicatorType, + const QVariantMap &securityCredentials) +{ + return mPlugins.at(index).plugin()->accessAllowed(indicatorType, securityCredentials); +} + +// Scan plugins in file system +int HbIndicatorPluginManager::loadPlugin(const QString &indicatorType) +{ + TRACE_ENTRY + + // Check if plugin file name is in cache + int index = -1; + const QString filePath = mNameCache.find(indicatorType); + if (!filePath.isEmpty()) { + TRACE("cache hit") + index = loadPlugin(indicatorType, filePath); + // If plugin wasn't loaded, the cache has stale information. Rescan the directory. + if (index < 0) { + TRACE("cache stale") + updateCachePath(filePath); + } + } + if (index < 0) { + TRACE("cache miss") + // Plugin name wasn't in cache, try to find it + index = scanPlugins(indicatorType); + if (index >= 0) { + // Plugin was found, update plugin name cache by scanning the directory + updateCachePath(mPlugins[index].mLoader->fileName()); + } + } + TRACE_EXIT + return index; +} + +// Scan for and load plugin in file system +int HbIndicatorPluginManager::scanPlugins(const QString &indicatorType) +{ + TRACE_ENTRY + const QStringList pathList = pluginPathList(); + const QString fileNameFilter = pluginFileNameFilter(); + int index = -1; + + foreach (const QString &path, pathList) { + QDir pluginDir(path, fileNameFilter, QDir::NoSort, QDir::Files | QDir::Readable); + foreach (const QString &fileName, pluginDir.entryList()) { + index = loadPlugin(indicatorType, pluginDir.absoluteFilePath(fileName)); + if (index >= 0) { + break; + } + } + } + TRACE_EXIT + return index; +} + +// Load plugin from file path name +int HbIndicatorPluginManager::loadPlugin(const QString &indicatorType, const QString &filePath) +{ + TRACE_ENTRY + int index = -1; + + HbLockedPluginLoader *loader = new HbLockedPluginLoader(mNameCache, filePath); + QObject *pluginInstance = loader->instance(); + + if (pluginInstance) { + HbIndicatorPluginInterface *plugin = + qobject_cast(pluginInstance); + if (plugin) { + QStringList types = plugin->indicatorTypes(); + if (types.contains(indicatorType)) { + // Save plugin into a list + PluginInfo pluginInfo; + pluginInfo.mTypes = types; + pluginInfo.mLoader = loader; + loader = 0; + mPlugins.append(pluginInfo); + pluginInfo.mLoader = 0; // ownership was transferred to the list + index = mPlugins.count() - 1; + } + } + } + if (loader) { + loader->unload(); + delete loader; + loader = 0; + } + TRACE_EXIT_ARGS(index) + return index; +} + +// Find index of a plugin +int HbIndicatorPluginManager::findPlugin( + const QString &indicatorType) const +{ + TRACE_ENTRY + int count = mPlugins.count(); + for(int i = 0; i < count; i++) { + if (mPlugins.at(i).mTypes.contains(indicatorType)) { + TRACE_EXIT + return i; + } + } + TRACE_EXIT + return -1; +} + +int HbIndicatorPluginManager::findPlugin(const QString &indicatorType, + IndicatorInfo **indicatorInfo, int *infoIndex) +{ + int count = mPlugins.count(); + for(int i = 0; i < count; i++) { + PluginInfo &pluginInfo = mPlugins[i]; + const int indicatorCount = pluginInfo.mAddedIndicators.count(); + for(int j = 0; j < indicatorCount; ++j) { + IndicatorInfo *info = &pluginInfo.mAddedIndicators[j]; + if (info->indicator->indicatorType() == indicatorType) { + *indicatorInfo = info; + if (infoIndex) { + *infoIndex = j; + } + return i; + } + } + } + return -1; +} + +QString HbIndicatorPluginManager::statusAreaIconPath( + const HbIndicatorInterface *indicator) const +{ + //Use MonoDecorationNameRole-role first, if empty, + //try with DecorationRole. + QString path(indicator->indicatorData( + HbIndicatorInterface::MonoDecorationNameRole).toString()); + + if (path.isEmpty()) { + path = indicator->indicatorData( + HbIndicatorInterface::DecorationNameRole).toString(); + } + + return path; +} + +// Update plugin name cache watch/scan list +void HbIndicatorPluginManager::updateCachePath(const QString &path) +{ + QString dirPath = HbPluginNameCache::directoryPath(path); + QFileInfo fileInfo(dirPath); + if (fileInfo.exists()) { + // If directory is writable, watch it. Otherwise scan it only once. + if (fileInfo.isWritable()) { + mNameCache.addWatchPath(dirPath); + } else { + mNameCache.scanDirectory(dirPath); + } + } else { + mNameCache.removeWatchPath(dirPath); + } +} + +// Generate directory path list to search plugins +QStringList HbIndicatorPluginManager::pluginPathList() +{ + QStringList pluginPathList; + +#if defined(Q_OS_SYMBIAN) + const QString pluginRelativePath("resource/plugins/indicators/"); + + QFileInfoList driveInfoList = QDir::drives(); + + foreach (const QFileInfo &driveInfo, driveInfoList) { + const QString drive = driveInfo.absolutePath(); + if (drive.startsWith("z:", Qt::CaseInsensitive) || + drive.startsWith("c:", Qt::CaseInsensitive)) { + QString path(drive + pluginRelativePath); + pluginPathList << path; + } + } +#elif defined(Q_OS_WIN32) || defined(Q_OS_UNIX) + pluginPathList << qApp->applicationDirPath() + '/' << HB_PLUGINS_DIR"/indicators/"; +#endif + + // Plugin name caching differentiates directory and file names by trailing slash in a name + for (int i = 0; i < pluginPathList.length(); i++) { + Q_ASSERT(pluginPathList.at(i).endsWith('/')); + } + + return pluginPathList; +} + +// Generate plugin file name filter +QString HbIndicatorPluginManager::pluginFileNameFilter() +{ +#if defined(Q_OS_LINUX) + return QString("*.so"); +#elif defined(Q_OS_MAC) + return QString("*.dylib"); +#elif defined(Q_OS_WIN32) + return QString("*.dll"); +#else + return QString("*.qtplugin"); +#endif +} + +// Return keys (indicator types) the plugin implements +QStringList HbIndicatorPluginManager::pluginKeys(QObject *pluginInstance) +{ + HbIndicatorPluginInterface *plugin = + qobject_cast(pluginInstance); + return plugin ? plugin->indicatorTypes() : QStringList(); +}