activityfw/activitydatabase/hsactivitydbclient/s60/src/hsactivitydbclient_p.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Wed, 23 Jun 2010 18:33:40 +0300
changeset 103 b99b84bcd2d1
parent 80 397d00875918
permissions -rw-r--r--
Revision: 201023 Kit: 2010125

/*
* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:
*
*/
#include <fbs.h>
#include <s32mem.h>

#include <qvariant.h>
#include <XQConversions>

#include "hsactivitydbclient_p.h"
#include "hsactivitydbasyncrequest_p.h"
#include "hsactivityglobals.h"
#include "hsserializer.h"
#include "afentry.h"



// -----------------------------------------------------------------------------
/**
 * Constructor
 */
HsActivityDbClientPrivate::HsActivityDbClientPrivate(HsActivityDbAsyncRequestObserver &observer):
    mObserver(observer)
{

}

// -----------------------------------------------------------------------------
/**
 * Destructor
 */
HsActivityDbClientPrivate::~HsActivityDbClientPrivate()
{
    mAsyncTasks.ResetAndDestroy();
    Close();
}

// -----------------------------------------------------------------------------
/**
 * Function establish connection to activity server
 * @return 0 on succees, error code otherwise
 */
int HsActivityDbClientPrivate::connect()
{
    TRAPD(errNo, connectL());
    return errNo;
}

// -----------------------------------------------------------------------------
/**
 * Interface implementation.
 * @see int HsActivityDbClientInterface::addActivity(const QVariantHash &)
 */
int HsActivityDbClientPrivate::addActivity(const QVariantHash &privateData,
                                           const QVariantHash &publicData)
{
    return execute(AddActivity, privateData, publicData);
    
}

// -----------------------------------------------------------------------------
/**
 * Interface implementation.
 * @see int HsActivityDbClientInterface::updateActivity(const QVariantHash &)
 */
int HsActivityDbClientPrivate::updateActivity(const QVariantHash &privateData,
                                              const QVariantHash &publicData)
{
    return execute(UpdateActivity, privateData, publicData);
}

// -----------------------------------------------------------------------------
/**
 * Interface implementation.
 * @see int HsActivityDbClientInterface::removeActivity(const QVariantHash &)
 */
int HsActivityDbClientPrivate::removeActivity(const QVariantHash &activity)
{
    return execute(RemoveActivity, QVariantHash(), activity);
}

// -----------------------------------------------------------------------------
/**
 * Interface implementation.
 * @see int HsActivityDbClientInterface::removeApplicationActivities(const QVariantHash &)
*/

int HsActivityDbClientPrivate::removeApplicationActivities(const QVariantHash &activity)
{
    return execute(RemoveApplicationActivities, QVariantHash(), activity);
}

// -----------------------------------------------------------------------------
/**
 * Interface implementation.
 * @see int HsActivityDbClientInterface::activities(QList<QVariantHash> &);
 */
int HsActivityDbClientPrivate::activities(QList<QVariantHash>& result)
{
    return execute(Activities, result, QVariantHash());
}

// -----------------------------------------------------------------------------
/**
 * Interface implementation.
 * @see int HsActivityDbClientInterface::applicationActivities(QList<QVariantHash> &, const QVariantHash &)
 */
int HsActivityDbClientPrivate::applicationActivities(QList<QVariantHash>& result,
        const QVariantHash &condition)
{
    return execute(ApplicationActivities, result, condition);
}

// -----------------------------------------------------------------------------
/**
 * Interface implementation.
 * @see int HsActivityDbClientInterface::activityData(QVariant &, const QVariantHash &)
 */
int HsActivityDbClientPrivate::activityData(QVariant &result, const QVariantHash &activity)
{
    TRAPD(errNo,
    User::LeaveIfError(checkDataConstraint(ApplicationActivity, activity));
    activityDataL(result, activity);)
    return errNo;
}

// -----------------------------------------------------------------------------
/**
 * Interface implementation.
 * @see int HsActivityDbClientInterface::waitActivity(const QVariantHash &)
 */
int HsActivityDbClientPrivate::waitActivity(const QVariantHash &activity)
{
    return execute(WaitActivity, QVariantHash(), activity);
}

// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
//
int HsActivityDbClientPrivate::getThumbnail(QSize size, QString imagePath, QString  mimeType, void *userDdata)
{
    TRAPD(errNo, getThumbnailL(size, imagePath, mimeType, userDdata);)
    return errNo;
}

// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
//
int HsActivityDbClientPrivate::notifyDataChange()
{
    return execute(NotifyChange, QVariantHash(), QVariantHash());
}

// -----------------------------------------------------------------------------
/**
 * Interface implementation.
 * @see int HsActivityDbClientInterface::launchActivity(const QVariantHash &)
 */
int HsActivityDbClientPrivate::launchActivity(const QVariantHash &activity)
{
    return execute(LaunchActivity, QVariantHash(), activity);
}

// -----------------------------------------------------------------------------
/**
 * Interface implementation.
 * @see int HsActivityDbClientInterface::cancelWaitActivity()
 */
int HsActivityDbClientPrivate::cancelWaitActivity()
{
    return SendReceive(CancelWait, TIpcArgs());
}

// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
//
int HsActivityDbClientPrivate::cancelNotifyDataChange()
{
    return SendReceive(CancelNotify, TIpcArgs());
}

// -----------------------------------------------------------------------------
/**
 * Function start activity server process.
 * Function can leave on failure.
 */
void HsActivityDbClientPrivate::startServerL()
{
    RProcess server;
    const TUidType uid(KNullUid, KNullUid, KActivityServerUid);
    User::LeaveIfError(server.Create(KActivityServerName, KNullDesC, uid));
    TRequestStatus stat;
    server.Rendezvous(stat);
    if (stat != KRequestPending) {
        server.Kill(0);
    } else {
        server.Resume();
    }
    User::WaitForRequest(stat);
    int errNo = (EExitPanic == server.ExitType()) ?
                KErrGeneral : stat.Int();
    if (KErrCancel == errNo) {
        errNo = KErrNone;
    }
    server.Close();
    User::LeaveIfError(errNo);
}

// -----------------------------------------------------------------------------
/**
 * Function establish connection to activity server.
 * Function can leave on failure
 */
void HsActivityDbClientPrivate::connectL()
{
    const int asyncMessageSlots(12);
    const int maxRetry(4);

    TInt retry = maxRetry;
    TInt errNo(KErrNone);
    do {
        errNo = CreateSession(KActivityServerName, TVersion(0, 0, 0), asyncMessageSlots);
        if (KErrNotFound != errNo && KErrServerTerminated != errNo) {
            retry =0;
        } else {
            TRAP(errNo, startServerL());
            if (KErrNone != errNo && KErrAlreadyExists != errNo) {
                retry =0;
                errNo = CreateSession(KActivityServerName, TVersion(0, 0, 0), asyncMessageSlots);
            }
        }
    } while (--retry > 0);
    User::LeaveIfError(errNo);
}

// -----------------------------------------------------------------------------
/**
 * Function execute remote call request.
 * @param function - remote function identyfier
 * @param activity - remote function parameters
 */
void HsActivityDbClientPrivate::execSimpleRequestL(int function,
                                                   const QVariantHash &privateData,
                                                   const QVariantHash &publicData)
{

    TPckgBuf<TInt> bitmapHdl(0);
    int flags(0);
    if(publicData.end() != publicData.find(ActivityPersistence) &&
       publicData[ActivityPersistence].toBool()) {
        flags |= CAfEntry::Persistent;
    }
    if(publicData.end() != publicData.find(ActivityVisibility) &&
       !publicData[ActivityVisibility].toBool()) {
        flags |= CAfEntry::Invisible;
    }
    CFbsBitmap* bitmap(0);
    if (publicData.end() != publicData.find(ActivityScreenshotKeyword)) {
        bitmap = publicData[ActivityScreenshotKeyword].value<QPixmap>().toSymbianCFbsBitmap();
        if (bitmap) {
            CleanupStack::PushL(bitmap);
            bitmapHdl = bitmap->Handle();
        }
        
        
    }

    RBuf8 prvBuffer, pubBuffer, data;
    CleanupClosePushL(data);
    CleanupClosePushL(prvBuffer);
    CleanupClosePushL(pubBuffer);

    prvBuffer << privateData;
    if (publicData.end() != publicData.find(ActivityScreenshotKeyword)) {
        QVariantHash localData(publicData);
        localData.remove(ActivityScreenshotKeyword);
        pubBuffer << localData;
    } else {
        pubBuffer << publicData;
    }
    
    HBufC *actId = XQConversions::qStringToS60Desc(publicData[ActivityActivityKeyword].toString());
    CleanupStack::PushL(actId);
    CAfEntry *entry = CAfEntry::NewL(flags,
                                     publicData[ActivityApplicationKeyword].toInt(),
                                     *actId,
                                     KNullDesC,
                                     prvBuffer,
                                     pubBuffer);
    CleanupStack::PopAndDestroy(actId);
    CleanupStack::PopAndDestroy(&pubBuffer);
    CleanupStack::PopAndDestroy(&prvBuffer);

    CleanupStack::PushL(entry);
    data.CreateL(entry->Size());
    RDesWriteStream stream(data);
    CleanupClosePushL(stream);
    stream << (*entry);
    CleanupStack::PopAndDestroy(&stream);
    CleanupStack::PopAndDestroy(entry);
    User::LeaveIfError(SendReceive(function, TIpcArgs(&data, &bitmapHdl)));
    
    CleanupStack::PopAndDestroy(&data);
    if (0 != bitmap) {
        CleanupStack::PopAndDestroy(bitmap);
    }

}

// -----------------------------------------------------------------------------
/**
 * Function retrieve all stored activity
 * Function can leave on failure
 * @param result - list of activity
 */
void HsActivityDbClientPrivate::activitiesL(QList<QVariantHash>& result)
{
    result.clear();

    RBuf8 buffer;
    CleanupClosePushL(buffer);

    TPckgBuf<int> emptyFilter(0), length(0), taskId(0);
    User::LeaveIfError(SendReceive(Activities,
                                   TIpcArgs(&emptyFilter, &length, &taskId)));

    CAfEntry::ReallocL(buffer, length());

    User::LeaveIfError(SendReceive(GetData, TIpcArgs(&taskId, &buffer)));

    RPointerArray<CAfEntry> entries;
    CleanupClosePushL(entries);

    entries << buffer;
    buffer.Close();//release unneeded resources


    while(entries.Count()) {
        QVariantHash publicData;
        publicData << entries[0]->Data(CAfEntry::Public);
        publicData.insert(ActivityScreenshotKeyword,
                          QString::fromUtf16(entries[0]->ImageSrc().Ptr(),
                                             entries[0]->ImageSrc().Length()));
        result.append(publicData);
        entries.Remove(0);
    }
    CleanupStack::PopAndDestroy(&entries);
    CleanupStack::PopAndDestroy(&buffer);
}

// -----------------------------------------------------------------------------
/**
 * Function retrieve all stored activity
 * Function can leave on failure
 * @param result - list of activity
 * @param cond - request conditions
 */
void HsActivityDbClientPrivate::applicationActivitiesL(QList<QVariantHash>& result,
                                                     const QVariantHash & condition)
{
    result.clear();

    RBuf8 buffer;
    CleanupClosePushL(buffer);
    CAfEntry *entry = CAfEntry::NewLC(0,
                                      condition[ActivityApplicationKeyword].toInt(),
                                      KNullDesC,
                                      KNullDesC,
                                      KNullDesC8,
                                      KNullDesC8);//filtering using application id only
    CAfEntry::ReallocL(buffer, entry->Size());
    RDesWriteStream writer(buffer);
    CleanupClosePushL(writer);
    writer << (*entry);
    CleanupStack::PopAndDestroy(&writer);
    CleanupStack::PopAndDestroy(entry);

    TPckgBuf<int> length(0), taskId(0);
    User::LeaveIfError(SendReceive(ApplicationActivities,
                                   TIpcArgs(&buffer, &length, &taskId)));

    CAfEntry::ReallocL(buffer, length());

    User::LeaveIfError(SendReceive(GetData, TIpcArgs(&taskId, &buffer)));

    RPointerArray<CAfEntry> entries;
    CleanupClosePushL(entries);

    entries << buffer;
    buffer.Close();//release unneeded resources


    while(entries.Count()) {
        QVariantHash publicData;
        publicData << entries[0]->Data(CAfEntry::Public);
        publicData.insert(ActivityScreenshotKeyword,
                          QString::fromUtf16(entries[0]->ImageSrc().Ptr(),
                                             entries[0]->ImageSrc().Length()));
        result.append(publicData);
        entries.Remove(0);
    }
    CleanupStack::PopAndDestroy(&entries);
    CleanupStack::PopAndDestroy(&buffer);
}

// -----------------------------------------------------------------------------
/**
 * Function retrieve private data of stored activity
 * Function can leave on failure
 * @param result - list of activity
 * @param activity - request conditions
 */
void HsActivityDbClientPrivate::activityDataL(QVariant &result, const QVariantHash &activity)
{
    result.clear();

    RBuf8 buffer;
    CleanupClosePushL(buffer);

    {   // prepare entry to send
        HBufC *activityId = XQConversions::qStringToS60Desc(activity[ActivityActivityKeyword].toString());
        CleanupStack::PushL(activityId);

        CAfEntry *entry = CAfEntry::NewLC(0,
                                          activity[ActivityApplicationKeyword].toInt(),
                                          *activityId,
                                          KNullDesC,
                                          KNullDesC8,
                                          KNullDesC8);//filtering using application id only
        CAfEntry::ReallocL(buffer, entry->Size());
        RDesWriteStream writer(buffer);
        CleanupClosePushL(writer);
        writer << (*entry);
        CleanupStack::PopAndDestroy(&writer);
        CleanupStack::PopAndDestroy(entry);
        CleanupStack::PopAndDestroy(activityId);
    }

    {   // get data
        TPckgBuf<int> length(0), taskId(0);
        User::LeaveIfError(SendReceive(ApplicationActivity, TIpcArgs(&buffer, &length, &taskId)));

        CAfEntry::ReallocL(buffer, length());
        User::LeaveIfError(SendReceive(GetData, TIpcArgs(&taskId, &buffer)));
    }

    {   // read data to Qt structure
        CAfEntry *entry = CAfEntry::NewLC();
        RDesReadStream reader(buffer);
        CleanupClosePushL(reader);
        entry->InternalizeL(reader);
        CleanupStack::PopAndDestroy(&reader);

        buffer.Close(); //release unneeded resources

        QVariantHash privateData;
        privateData << entry->Data(CAfEntry::Private);
        result = privateData.value(ActivityDataKeyword);

        CleanupStack::PopAndDestroy(entry);
    }
    CleanupStack::PopAndDestroy(&buffer);
}

// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
//
void HsActivityDbClientPrivate::launchActivityL(const QVariantHash &activity)
{
    TPckgC<TInt> applicationId(activity[ActivityApplicationKeyword].toInt());
    HBufC8 *activityId = XQConversions::qStringToS60Desc8(activity[ActivityActivityKeyword].toString());
    CleanupStack::PushL(activityId);
    TPtrC8 empty(KNullDesC8);
    User::LeaveIfError(SendReceive(LaunchActivity,
                                   TIpcArgs(&applicationId, activityId, &empty, &empty)));
    CleanupStack::PopAndDestroy(activityId);

}

// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
//
void HsActivityDbClientPrivate::getThumbnailL(QSize size, QString imagePath, QString  mimeType, void *userDdata)
{
    HsActivityDbAsyncRequestPrivate::getThumbnailLD(mObserver,
                              *this, size, imagePath, mimeType, userDdata);
}

// -----------------------------------------------------------------------------
/**
 * Function get cached data from server
 * @param taskId - request task id
 * @param dst - destination, preallocated buffer
 */
void HsActivityDbClientPrivate::getData(int taskId, RBuf8 &data)
{
    TPckgBuf<int> requestId(taskId);
    SendReceive(GetData, TIpcArgs(&requestId, &data));
}

// -----------------------------------------------------------------------------
/**
 * Function initialize aync request
 * @param func - requested function
 * @param data - request data
 * @param status - request status
 */
void HsActivityDbClientPrivate::sendDataAsync(int func,
                                              const TIpcArgs &data,
                                              TRequestStatus& status)
{
    SendReceive(func, data, status);
}

// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
//
void HsActivityDbClientPrivate::PushL(HsActivityDbAsyncRequestPrivate * task)
{
    (KErrNotFound == mAsyncTasks.Find(task)) ?
        mAsyncTasks.AppendL(task):
        User::Leave(KErrAlreadyExists);
}

// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
//
void HsActivityDbClientPrivate::Pop(HsActivityDbAsyncRequestPrivate *task)
{
    const TInt offset(mAsyncTasks.Find(task));
    if (KErrNotFound != offset) {
        mAsyncTasks.Remove(offset);
    }
}

// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
//
int HsActivityDbClientPrivate::execute(int func, const QVariantHash &privateData, const QVariantHash &publicData)
{
    TRAPD(errNo,
    User::LeaveIfError(checkDataConstraint(func, publicData));
    switch (func) {
    case AddActivity:
    case UpdateActivity:
    case RemoveActivity:
    case RemoveApplicationActivities:
        execSimpleRequestL(func, privateData, publicData);
        break;
    
    case LaunchActivity:
        launchActivityL(publicData);
        break;
    
    case NotifyChange:
        HsActivityDbAsyncRequestPrivate::notifyDataChangeLD(mObserver, *this);
        break;
    
    case WaitActivity:
        HsActivityDbAsyncRequestPrivate::waitActivityLD(mObserver,*this, publicData);
        break;
    
    }
    
    )
    return errNo;
}

// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
//
int HsActivityDbClientPrivate::execute(int func, 
                                       QList<QVariantHash>&dst, 
                                       const QVariantHash &src)
{
    TRAPD(errNo,
    User::LeaveIfError(checkDataConstraint(func, src));
    switch (func) {
    case Activities: activitiesL(dst);break;
    case ApplicationActivities: applicationActivitiesL(dst, src); break;
    }
    )
    return errNo;
}

// -----------------------------------------------------------------------------
//
// -----------------------------------------------------------------------------
//
int HsActivityDbClientPrivate::checkDataConstraint(int func, const QVariantHash &data)
{
    int retVal(KErrNone);
    QStringList constraints;
    switch(func) {
    case AddActivity:
    case UpdateActivity:
        constraints << ActivityApplicationKeyword 
                    << ActivityActivityKeyword 
                    << ActivityScreenshotKeyword;
        break;
    
    case ApplicationActivity:
    case LaunchActivity:
    case RemoveActivity:
        constraints << ActivityApplicationKeyword
                    << ActivityActivityKeyword;
                    break;
    
    case WaitActivity:
    case RemoveApplicationActivities:
        constraints << ActivityApplicationKeyword;
        break;
    }
    foreach (QString constraint, constraints) {
        if (data.end() == data.find(constraint)) {
            retVal = KErrCorrupt;
            break;
        }
    }
    return retVal;
}