diff -r 000000000000 -r 16d8024aca5e src/hbcore/devicedialogbase/hbdevicedialogsymbian.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/hbcore/devicedialogbase/hbdevicedialogsymbian.cpp Mon Apr 19 14:02:13 2010 +0300 @@ -0,0 +1,568 @@ +/**************************************************************************** +** +** 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 "hbdevicedialogserverdefs_p.h" +#include "hbdevicedialogerrors_p.h" +#include "hbdevicedialogclientsession_p.h" +#include + +#include "hbdevicedialogsymbian.h" +#include "hbsymbianvariant.h" +#include "hbsymbianvariantconverter_p.h" +#include "hbdeleteguardsymbian_p.h" + +/*! + \class CHbDeviceDialogSymbian + \brief CHbDeviceDialog displays dialogs on top of applications. It is a client interface for Symbian applications to Hb + device dialogs. + \sa HbDeviceDialog + + Data given to this API in symbian format is packed to QVariantMap. See + CHbSymbianVariant to see which Qt datatypes are supported. + \sa CHbSymbianVariant + \sa CHbSymbianVariantMap + + When plugin returns data in Qt format, the data is converted, if possible, + to CHbSymbianVariantMap. + + \proto + + \hbcore + */ + +/*! + \enum CHbDeviceDialogSymbian::TDeviceDialogError + Defines device dialog error codes and ranges. +*/ +/*! + \var TDeviceDialogError::DeviceDialogError HbDeviceDialog::EFrameworkErrors + Start of an error range for errors originating from device dialog framework (client or server). +*/ +/*! + \var TDeviceDialogError::DeviceDialogError HbDeviceDialog::EPluginErrors + Start of an error range for errors originating from device dialog plugins. The framework passes + these from the plugin unmodified. +*/ +/*! + \var TDeviceDialogError::DeviceDialogError HbDeviceDialog::EErrorTypeMask + Mask for error type part of the error code. +*/ +/*! + \var TDeviceDialogError::DeviceDialogError HbDeviceDialog::ECancelledError + Operation was cancelled by Cancel(). +*/ +/*! + \var TDeviceDialogError::DeviceDialogError HbDeviceDialog::ESystemCancelledError + Operation was cancelled by device dialog framework. +*/ + +/*! + \fn void MHbDeviceDialogObserver::DataReceived(CHbSymbianVariantMap& aData) + + This callback is called when data is received from a device dialog. + \a aData contains data from the dialog plugin. + The structure and meaning of the data is a contract between the dialog and + a client. Structure should be aligned with the data types supported by + CHbSymbianVariantMap. + + \sa CHbSymbianVariantMap. +*/ + +/*! + \fn void MHbDeviceDialogObserver::DeviceDialogClosed(TInt aCompletionCode) + + This callback is called when a device dialog is closed. Any data sent by + the dialog is indicated by the dataReceived() callback. If no observer is + set in CHbDeviceDialogSymbian::Show the latest data can be retrieved with + CHbDeviceDialogSymbian::receivedData() + + \a aCompletionCode gives the result of the dialog completion. Code can be + either Symbian error code or device dialog error code. + + \sa DataReceived() ReceivedData() +*/ + +// Device dialogs are implemented only for Symbian/S60 OS. + +class CHbDeviceDialogSymbianPrivate : public CActive +{ +public: + CHbDeviceDialogSymbianPrivate(); + ~CHbDeviceDialogSymbianPrivate(); + TInt Show( const QByteArray& aArray ); + TInt Update( const QByteArray& aArray ); + void CancelDialog(); + TInt Error() const; + void SetObserver( MHbDeviceDialogObserver* aObserver ); + + // CActive + void RunL(); + void DoCancel(); + TInt RunError( TInt aError ); + + void Start(); + TInt SymToDeviceDialogError( TInt errorCode ); + void SetError(TInt aError); + bool CallDialogClosedObserver(TInt aCompletionCode); + bool CallDataReceivedObserver(CHbSymbianVariantMap& aData); + +public: + TInt iFlags; + RHbDeviceDialogClientSession iHbSession; + TInt iLastError; + TPckgBuf iUpdateInfo; + TPckgBuf iDeviceDialogId; + HBufC8* iBuffer; + TPtr8 iDataPtr; + TBool iRequesting; + QVariantMap iDataReceived; + CActiveSchedulerWait* iWait; + MHbDeviceDialogObserver* iObserver; + bool *iDeleted; +}; + +CHbDeviceDialogSymbianPrivate::CHbDeviceDialogSymbianPrivate(): +CActive( EPriorityStandard ), +iFlags(0), +iLastError(0), +iDeviceDialogId(0), +iBuffer(NULL), +iDataPtr(NULL, 0, 0), +iRequesting(EFalse), +iObserver(NULL) +{ + if (!iBuffer) { + iBuffer = HBufC8::NewL(64); + if (iBuffer) { + iDataPtr.Set(iBuffer->Des()); + } + } +} + +CHbDeviceDialogSymbianPrivate::~CHbDeviceDialogSymbianPrivate() +{ + // Inform the server to finish the dialog session and not to cancel it + if(!iObserver) { + iHbSession.SendSyncRequest(EHbSrvClientClosing); + } + + Cancel(); + iHbSession.Close(); + + delete iBuffer; + iBuffer = NULL; + + iObserver= NULL; + // Set object deleted flag + if (iDeleted) { + // Mark the object as deleted. + *iDeleted = true; + iDeleted = 0; + } +} + +TInt CHbDeviceDialogSymbianPrivate::Show(const QByteArray& aArray ) +{ + TInt error = iLastError = KErrNone; + + TPtrC8 ptr( reinterpret_cast(aArray.data()), aArray.size() ); + // Synchronous call to server to show dialog. + error = iHbSession.SendSyncRequest( EHbSrvShowDeviceDialog, ptr, &iDeviceDialogId ); + //error = SymToDeviceDialogError(error); + + if (error == KErrNone) { + // Start listening for server updates. Device dialog update and closing is + // received via this channel. Error status received in RunL method. + Start(); + } + // Error, just return the error code + else { + SetError(error); + } + return error; +} + +/*! + \internal + + Send device dialog update. +*/ +TInt CHbDeviceDialogSymbianPrivate::Update( const QByteArray& aArray ) +{ + TInt error = iLastError = KErrNone; + if (iRequesting) { + + TPtrC8 ptr( reinterpret_cast(aArray.data()), aArray.size() ); + + error = iHbSession.SendSyncRequest( EHbSrvUpdateDeviceDialog, ptr ); + //error = SymToDeviceDialogError(error); + if (error != KErrNone) { + SetError(error); + } + } + else { + SetError(KErrBadHandle); + error = KErrBadHandle; + } + return error; +} + +/*! + \internal + + Cancel a scheduled popup on HbDeviceDialogManager. Event buffer is cleared + at server. +*/ +void CHbDeviceDialogSymbianPrivate::CancelDialog() +{ + iLastError = KErrNone; + int error = KErrNotFound; + + if (iRequesting) { + // Ignore other than server errors. + error = iHbSession.SendSyncRequest(EHbSrvCancelDeviceDialog, iDeviceDialogId()); + // error = SymToDeviceDialogError(error); + } + if (error != KErrNone) { + SetError(error); + } +} + +/*! + \internal + + Return last error. +*/ +TInt CHbDeviceDialogSymbianPrivate::Error() const +{ + return iLastError; +} + +void CHbDeviceDialogSymbianPrivate::SetObserver( MHbDeviceDialogObserver* aObserver ) +{ + iObserver = aObserver; +} +/*! + \internal + RunL from CActive. +*/ +void CHbDeviceDialogSymbianPrivate::RunL() +{ + TInt completionCode = iStatus.Int(); + //int errorCode = SymToDeviceDialogError(completionCode); + + if (completionCode < KErrNone) { + // Any Symbian error, stop requesting, sycnhoronous requests are stopped + // in the end of the RunL + iRequesting = EFalse; + SetError(completionCode); + if (CallDialogClosedObserver(completionCode)) { + return; // observed deleted this object, do not touch it + } + } + else { + // Check that event is for latest device dialog. iDeviceDialogId was updated by server + // during show() + THbDeviceDialogSrvUpdateInfo &updateInfo = iUpdateInfo(); + if (updateInfo.iDeviceDialogId == iDeviceDialogId()) { + switch(updateInfo.iUpdateType) { + case EHbDeviceDialogUpdateData: { + if (completionCode == KErrNone && + updateInfo.iInfo.iDataInfo.iDataSize > 0) { + // Resize buffer and get new data synchronously + delete iBuffer; + iBuffer = NULL; + iBuffer = HBufC8::NewL(updateInfo.iInfo.iDataInfo.iDataSize); + iDataPtr.Set(iBuffer->Des()); + completionCode = iHbSession.SendSyncRequest(EHbSrvUpdateData, iDataPtr); + //errorCode = SymToDeviceDialogError(completionCode); + + // data request failed + if (completionCode < KErrNone) { + iRequesting = EFalse; + SetError(completionCode); + if (CallDialogClosedObserver(completionCode)) { + return; // observed deleted this object, do not touch it + } + } + } + if (completionCode == KErrNone) { + // Signal data if there are connections. Otherwise keep a copy. + QByteArray resArray((const char*)iDataPtr.Ptr(), iDataPtr.Size()); + QDataStream stream(&resArray, QIODevice::ReadOnly); + + iDataReceived.clear(); + + QVariant var; + stream >> var; + QVariantMap varMap = var.toMap(); + + if (iObserver) { + CHbSymbianVariantMap* symbianMap = + HbSymbianVariantConverter::fromQVariantMapL(varMap); + bool thisIsDeleted = CallDataReceivedObserver(*symbianMap); + delete symbianMap; + symbianMap = 0; + if (thisIsDeleted) { // observer deleted this, do not touch anymore + return; + } + } + else { + iDataReceived = varMap; + } + } + break; + } + case EHbDeviceDialogUpdateClosed: + // Signal possible cancelled error + if (completionCode != KErrNone) { + SetError(completionCode); + } + iRequesting = EFalse; + if (CallDialogClosedObserver(completionCode)) { + return; // observed deleted this object, do not touch it + } + break; + default: + break; + } + } + } + // Make a new request if there was no errors and device dialog wasn't closed + if (iRequesting) { + Start(); + } +} + +/*! + \internal + DoCancel from CActive. +*/ +void CHbDeviceDialogSymbianPrivate::DoCancel() +{ + SetError(KErrCancel); + iRequesting = EFalse; + iHbSession.SendSyncRequest(EHbSrvCancelUpdateChannel); +} + +/*! + \internal + RunError from CActive. +*/ +TInt CHbDeviceDialogSymbianPrivate::RunError( TInt /*aError*/ ) +{ + SetError( KErrGeneral ); + return KErrNone; +} + +/*! + \internal + Starts asynchronous message to receive update and close events from session. +*/ +void CHbDeviceDialogSymbianPrivate::Start() +{ + iDataPtr.Zero(); + + if ( !IsActive() ) { + iHbSession.SendASyncRequest( EHbSrvOpenUpdateChannel, iDataPtr, iUpdateInfo, iStatus ); + SetActive(); + iRequesting = ETrue; + } +} + +// Convert symbian error code into HbDeviceDialog error code +int CHbDeviceDialogSymbianPrivate::SymToDeviceDialogError( TInt errorCode ) +{ + if (errorCode != HbDeviceDialogNoError) { + // Any Symbian error, close session handle. It will be reopened on next show() + if (errorCode < KErrNone) { + iHbSession.Close(); + } + // All Symbian errors are connected to HbDeviceDialogConnectError + if (errorCode < KErrNone) { + errorCode = HbDeviceDialogConnectError; + } + } + return errorCode; +} + +void CHbDeviceDialogSymbianPrivate::SetError( TInt aError ) +{ + iLastError = aError; +} + +// Call device dialog closed observer. Return true if observer deleted this object. +bool CHbDeviceDialogSymbianPrivate::CallDialogClosedObserver(TInt aCompletionCode) +{ + if (iObserver) { + RHbDeleteGuardSymbian guard; + guard.OpenAndPushL(&iDeleted); + iObserver->DeviceDialogClosed(aCompletionCode); + return guard.PopAndClose(); + } else { + return false; + } +} + +// Call device dialog data received observer. Return true if observer deleted this object. +bool CHbDeviceDialogSymbianPrivate::CallDataReceivedObserver(CHbSymbianVariantMap& aData) +{ + if (iObserver) { + RHbDeleteGuardSymbian guard; + guard.OpenAndPushL(&iDeleted); + iObserver->DataReceived(aData); + return guard.PopAndClose(); + } else { + return false; + } +} + +/*! + Constructs CHbDeviceDialogSymbian object. \a f contains construct flags. Device + dialog service will clean all dialogs launched when the instance is deleted. +*/ + +EXPORT_C CHbDeviceDialogSymbian* CHbDeviceDialogSymbian::NewL( TInt aFlags ) +{ + CHbDeviceDialogSymbian* deviceDialog = new (ELeave) CHbDeviceDialogSymbian(aFlags); + int error = KErrNone; + if(deviceDialog->d) { + error = deviceDialog->d->iHbSession.Connect(); + } + if(error != KErrNone) { + CleanupStack::PushL(deviceDialog); + User::Leave(error); + delete deviceDialog; + deviceDialog = 0; + } + return deviceDialog; +} + +EXPORT_C CHbDeviceDialogSymbian::~CHbDeviceDialogSymbian() +{ + delete d; +} + +/*! + Show of device dialog. Each time a Show() is called a new dialog is launched. + aParameter data is sent to device dialog in Qt's QVariantMap object. + The function is asynchronous and returns immediately. Closing and data events from the + dialog can be received by observer interface. Deleting CHbDeviceDialogSymbian object + closes and deletes the device dialog at server if observer is set. If observer is null + the dialog is left executing at the server and it's assumed it closes itself by a timeout. + Cancel() to closes the device dialog. + + \a aDeviceDialogType is name of the device dialog. Identifies the device + dialog plugin. \a aParameters is a buffer containing data for the device dialog. + + \a aObserver is used to observe the session. + + Return value informs if the call was successful. + + \sa Update() Cancel() + */ +EXPORT_C TInt CHbDeviceDialogSymbian::Show(const TDesC& aDeviceDialogType, const CHbSymbianVariantMap& aParameters, MHbDeviceDialogObserver* aObserver) +{ + d->SetObserver(aObserver); + + QString deviceDialogType = QString::fromUtf16(aDeviceDialogType.Ptr(), aDeviceDialogType.Length()); + + QVariantMap parameters; + HbSymbianVariantConverter::toQtVariantMap(aParameters, parameters); + + QByteArray array; + QDataStream stream( &array, QIODevice::WriteOnly ); + + QVariant var( parameters ); + stream << deviceDialogType; + stream << var; + + return d->Show(array); +} + +/*! + Updates device dialog parameters by a set of new values. Show() must be called before an + Update() can be called. Returns true on success and false + if error occurred. + + \sa Show() +*/ +EXPORT_C TInt CHbDeviceDialogSymbian::Update(const CHbSymbianVariantMap& aParameters) +{ + if(!d) { + return KErrNotReady; + } + QVariantMap parameters; + + HbSymbianVariantConverter::toQtVariantMap(aParameters, parameters); + + QByteArray array; + QDataStream stream( &array, QIODevice::WriteOnly ); + + QVariant var( parameters ); + stream << var; + + return d->Update(array); +} + +/*! + Get the data received from device dialog if using synchronous Show + in s60 data types. Caller gets the ownership. +*/ +EXPORT_C CHbSymbianVariantMap* CHbDeviceDialogSymbian::ReceivedDataL() const +{ + CHbSymbianVariantMap* map = HbSymbianVariantConverter::fromQVariantMapL(d->iDataReceived); + return map; +} + +/*! + Cancel device dialog session. Visible dialog is removed from the screen. + Waiting dialogs are canceled and no effect if dialog already dismissed +*/ +EXPORT_C void CHbDeviceDialogSymbian::Cancel() +{ + d->CancelDialog(); +} + +/*! + Set observer for device dialog events. \aObserver is pointer to the + observer. Null disables observing. +*/ +EXPORT_C void CHbDeviceDialogSymbian::SetObserver(MHbDeviceDialogObserver* aObserver) +{ + d->SetObserver(aObserver); +} + +CHbDeviceDialogSymbian::CHbDeviceDialogSymbian(TInt aFlags) : d(NULL) +{ + d = new CHbDeviceDialogSymbianPrivate; + d->iFlags = aFlags; + CActiveScheduler::Add(d); + + // Is needed to implement? + //if (mDeviceDialogFlags & HbDeviceDialog::ImmediateResourceReservationFlag) +}