javauis/coreui_akn/src/startupscreen/startscreen.cpp
branchRCL_3
changeset 19 04becd199f91
child 23 98ccebc37403
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javauis/coreui_akn/src/startupscreen/startscreen.cpp	Tue Apr 27 16:30:29 2010 +0300
@@ -0,0 +1,698 @@
+/*
+* 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: A user start screen impl.
+*
+*/
+
+#include <iostream>
+#include <fstream>
+#include <AknsBasicBackgroundControlContext.h>
+#include <AknsDrawUtils.h>
+#include <AknUtils.h>
+#include <layoutmetadata.cdl.h>
+#include <imageconversion.h>
+
+#include "startscreen.h"
+#include "logger.h"
+#include "javasymbianoslayer.h"
+#include "coreuiavkonimpl.h"
+
+_LIT(KUserFolder, "startupimages\\");
+_LIT(KUserDefaultImage, "startupscreen.img");
+_LIT(KUserLandscapeImage, "startupscreen_landscape.img");
+_LIT(KUserPortraitImage, "startupscreen_portrait.img");
+
+_LIT(KAutoFolder, "autostartupimages\\");
+_LIT(KAutoLandscapeImage, "landscape.png"); // Gets prefixed by TUid
+_LIT(KAutoPortraitImage, "portrait.png"); // Gets prefixed by TUid
+
+
+CStartScreen* CStartScreen::NewL(CStartScreen::TStartScreenType aType,
+                                 const java::ui::CoreUiParams& aParams)
+{
+    JELOG2(EJavaUI);
+    CStartScreen* self = new(ELeave) CStartScreen(aType, aParams);
+    CleanupStack::PushL(self);
+    self->ConstructL();
+    CleanupStack::Pop(self);
+    return self;
+}
+
+CStartScreen::~CStartScreen()
+{
+    JELOG2(EJavaUI);
+    Cancel();
+    delete mPortraitBmp;
+    delete mPortraitMask;
+    if (mPortraitBmp != mLandscapeBmp)
+    {
+        delete mLandscapeBmp;
+        delete mLandscapeMask;
+    }
+    delete mAsyncSaveBmp;
+    delete mDecoder;
+    delete mEncoder;
+    mPath.Close();
+    mAsyncSavePath.Close();
+}
+
+void CStartScreen::Draw(CWindowGc& aGc,
+                        const TRect& aRect) const
+{
+    JELOG2(EJavaUI);
+
+    CFbsBitmap* bmp = 0;
+    CFbsBitmap* mask = 0;
+    if (Layout_Meta_Data::IsLandscapeOrientation())
+    {
+        bmp = mLandscapeBmp;
+        mask = mLandscapeMask;
+    }
+    else
+    {
+        bmp = mPortraitBmp;
+        mask = mPortraitMask;
+    }
+
+    if (!bmp)
+    {
+        return;
+    }
+
+    TPoint topLeft(aRect.iTl);
+    if (mType == EStartScreenAutomatic)
+    {
+        aGc.BitBlt(topLeft, bmp);
+    }
+    else
+    {
+        const TSize bmpSizeOrg(bmp->SizeInPixels());
+        const TSize rectSize(aRect.Size());
+        TSize bmpSize(bmpSizeOrg);
+
+        // Scale the image if needed
+        TBool scaled(EFalse);
+        if (bmpSize.iWidth > rectSize.iWidth || bmpSize.iHeight > rectSize.iHeight)
+        {
+            scaled = ETrue;
+            bmpSize = GetAspectRatioScaledBitmapSize(bmpSize, rectSize);
+        }
+
+        // Center the image
+        if (bmpSize.iWidth < rectSize.iWidth)
+        {
+            topLeft.iX = (rectSize.iWidth - bmpSize.iWidth) / 2;
+        }
+        if (bmpSize.iHeight < rectSize.iHeight)
+        {
+            topLeft.iY = (rectSize.iHeight - bmpSize.iHeight) / 2;
+        }
+
+        if (scaled)
+        {
+            TRect destRect(topLeft, bmpSize);
+            if (!mask)
+            {
+                aGc.DrawBitmap(destRect, bmp, TRect(bmpSizeOrg));
+            }
+            else
+            {
+                aGc.DrawBitmapMasked(destRect, bmp, TRect(bmpSizeOrg), mask, EFalse);
+            }
+        }
+        else
+        {
+            // Faster drawing
+            if (!mask)
+            {
+                aGc.BitBlt(topLeft, bmp);
+            }
+            else
+            {
+                aGc.BitBltMasked(topLeft, bmp, TRect(bmpSize), mask, EFalse);
+            }
+        }
+    }
+}
+
+void CStartScreen::HandleResolutionChange()
+{
+    if (mLandscapeBmp && mPortraitBmp)
+    {
+        return;
+    }
+
+    if (Layout_Meta_Data::IsLandscapeOrientation())
+    {
+        if (!mLandscapeBmp)
+        {
+            TRAP_IGNORE(SyncLoadImageL(EImageLandscape));
+        }
+    }
+    else
+    {
+        if (!mPortraitBmp)
+        {
+            TRAP_IGNORE(SyncLoadImageL(EImagePortrait));
+        }
+    }
+}
+
+TBool CStartScreen::IsEmpty() const
+{
+    if (Layout_Meta_Data::IsLandscapeOrientation())
+    {
+        return (mLandscapeBmp == 0);
+    }
+    else
+    {
+        return (mPortraitBmp == 0);
+    }
+}
+
+TSize CStartScreen::Size() const
+{
+    if (Layout_Meta_Data::IsLandscapeOrientation())
+    {
+        if (mLandscapeBmp)
+            return mLandscapeBmp->SizeInPixels();
+    }
+    else
+    {
+        if (mPortraitBmp)
+            return mPortraitBmp->SizeInPixels();
+    }
+
+    return TSize(0, 0);
+}
+
+void CStartScreen::AsyncSaveScreenL(TCallBack aCallBack)
+{
+    // Expecting this is done once and only once.
+    ASSERT(!mAsyncSaveBmp);
+    ASSERT(!mEncoder);
+
+    mCallBack = aCallBack;
+    mAsyncSaveBmp = TakeScreenShotL();
+    if (mAsyncSaveBmp)
+    {
+        if (Layout_Meta_Data::IsLandscapeOrientation())
+        {
+            AsyncSaveImageL(EImageLandscape, *mAsyncSaveBmp);
+        }
+        else
+        {
+            AsyncSaveImageL(EImagePortrait, *mAsyncSaveBmp);
+        }
+    }
+}
+
+CStartScreen::TStartScreenType CStartScreen::Type() const
+{
+    return mType;
+}
+
+TInt64 CStartScreen::LoadStartupTime()
+{
+    TInt64 res = 0;
+    std::ifstream file;
+    file.open(StartupTimeFileName().c_str(), std::ifstream::in);
+    file >> res;
+    file.close();
+    return res;
+}
+
+void CStartScreen::SaveStartupTime(TInt64 aPeriod)
+{
+    std::ofstream file;
+    file.open(StartupTimeFileName().c_str());
+    file << aPeriod;
+    file.close();
+}
+
+CStartScreen::CStartScreen(TStartScreenType aType,
+                           const java::ui::CoreUiParams& aParams)
+        : CActive(EPriorityStandard), mType(aType), mParams(aParams)
+{
+    CActiveScheduler::Add(this);
+}
+
+void CStartScreen::ConstructL()
+{
+    JELOG2(EJavaUI);
+
+    InitPathL();
+    ScanFolderL();
+
+    if (mImageCount > 0)
+    {
+        if (mType == EStartScreenAutomatic || mImageCount >= 2)
+        {
+            if (Layout_Meta_Data::IsLandscapeOrientation())
+            {
+                TRAP_IGNORE(SyncLoadImageL(EImageLandscape));
+            }
+            else
+            {
+                TRAP_IGNORE(SyncLoadImageL(EImagePortrait));
+            }
+        }
+        else
+        {
+            TRAP_IGNORE(SyncLoadImageL(EImageDefault));
+        }
+    }
+}
+
+void CStartScreen::InitPathL()
+{
+    HBufC* root(wstringToBuf(mParams.getImagePath()));
+    if (!root || root->Length() == 0)
+    {
+        delete root;
+        User::Leave(KErrPathNotFound);
+    }
+    CleanupStack::PushL(root);
+    const TDesC& folder = FolderName();
+    mPath.CreateL(root->Length() + folder.Length());
+    mPath.Append(root->Des());
+    CleanupStack::PopAndDestroy(root);
+    mPath.Append(folder);
+}
+
+void CStartScreen::ScanFolderL()
+{
+    ASSERT(mPath.Length());
+
+    TUint fileAttrMask = KEntryAttNormal | KEntryAttSystem | KEntryAttDir;
+    CDir* dir = 0;
+    RFs& fs = CCoeEnv::Static()->FsSession();
+    TInt err = fs.GetDir(mPath, fileAttrMask, ESortByName, dir);
+
+    if (KErrNone == err)
+    {
+        if (!dir)
+        {
+            err = KErrNotFound;
+            ELOG1(EJavaUI, "CStartScreen::InitStateL, "
+                  "RFs::GetDir failed: %d", err);
+        }
+        else
+        {
+            mImageCount = dir->Count();
+        }
+    }
+    else
+    {
+        ELOG1(EJavaUI, "CStartScreen::InitStateL, "
+              "RFs::GetDir failed: %d", err);
+    }
+
+    if (mType == EStartScreenAutomatic && KErrNone != err)
+    {
+        err = fs.MkDir(mPath);
+    }
+
+    User::LeaveIfError(err);
+}
+
+void CStartScreen::SyncLoadImageL(TImageId aId)
+{
+    RBuf fullPath;
+    const TDesC& img = ImageName(aId);
+    // Do prefixing here just to avoid dealing with another RBuf :)
+    TUidName uid;
+    if (mType == EStartScreenAutomatic)
+        uid = java::ui::CoreUiAvkonImpl::getInstanceImpl().getMidletTUid().Name();
+    fullPath.CreateL(mPath.Length() + img.Length() + uid.Length());
+    fullPath.CleanupClosePushL();
+    fullPath.Append(mPath);
+    if (mType == EStartScreenAutomatic)
+        fullPath.Append(uid);
+    fullPath.Append(img);
+
+    switch (aId)
+    {
+    case EImageDefault:
+        ASSERT(!mPortraitBmp);
+        ASSERT(!mLandscapeBmp);
+        DoSyncLoadImageL(fullPath, mPortraitBmp, mPortraitMask);
+        mLandscapeBmp = mPortraitBmp;
+        mLandscapeMask = mPortraitMask;
+        break;
+    case EImagePortrait:
+        ASSERT(!mPortraitBmp);
+        DoSyncLoadImageL(fullPath, mPortraitBmp, mPortraitMask);
+        break;
+    case EImageLandscape:
+        ASSERT(!mLandscapeBmp);
+        DoSyncLoadImageL(fullPath, mLandscapeBmp, mLandscapeMask);
+        break;
+    default:
+        break;
+    }
+
+    CleanupStack::PopAndDestroy(&fullPath);
+}
+
+
+void CStartScreen::DoSyncLoadImageL(const TDesC& aPath, CFbsBitmap*& aResBmp,
+                                    CFbsBitmap*& aResMask)
+{
+    ASSERT(!aResBmp);
+    ASSERT(!aResMask);
+
+    if (IsActive())
+    {
+        Cancel();
+    }
+
+    if (mDecoder != NULL)
+    {
+        delete mDecoder;
+        mDecoder = 0;
+    }
+
+    mDecoder = CImageDecoder::FileNewL(CCoeEnv::Static()->FsSession(), aPath);
+
+    CFbsBitmap* bmp = new(ELeave) CFbsBitmap();
+    CleanupStack::PushL(bmp);
+
+    const TFrameInfo& frameInfo = mDecoder->FrameInfo();
+
+    TInt err = bmp->Create(frameInfo.iOverallSizeInPixels,
+                           frameInfo.iFrameDisplayMode);
+    if (KErrNone != err)
+    {
+        CleanupStack::PopAndDestroy(bmp);
+        ELOG1(EJavaUI, "CStartScreen::DoSyncLoadImageL, "
+              "Bitmap creation failed: %d", err);
+        User::Leave(err);
+    }
+
+    CFbsBitmap* mask = 0;
+
+    if (!(frameInfo.iFlags & TFrameInfo::ETransparencyPossible))
+    {
+        mState = ESyncRead;
+        mDecoder->Convert(&iStatus, *bmp);
+    }
+    else
+    {
+        mask = new(ELeave) CFbsBitmap();
+        CleanupStack::PushL(mask);
+
+        TDisplayMode mode(EGray2);
+        if (frameInfo.iFlags & TFrameInfo::EAlphaChannel)
+        {
+            mode = EGray256;
+        }
+
+        err = mask->Create(frameInfo.iOverallSizeInPixels, mode);
+        if (KErrNone != err)
+        {
+            CleanupStack::PopAndDestroy(mask);
+            CleanupStack::PopAndDestroy(bmp);
+            ELOG1(EJavaUI, "CImageReader::DoSyncLoadImageL, "
+                  "Mask creation failed: %d", err);
+            User::Leave(err);
+        }
+
+        mState = ESyncRead;
+        mDecoder->Convert(&iStatus, *bmp, *mask);
+    }
+
+    SetActive();
+    mWait.Start();
+
+    err = iStatus.Int();
+    if (KErrNone != err)
+    {
+        if (mask)
+        {
+            CleanupStack::PopAndDestroy(mask);
+        }
+        CleanupStack::PopAndDestroy(bmp);
+        ELOG1(EJavaUI, "CImageReader::DoSyncLoadImageL, "
+              "CImageDecoder::Convert failed: %d", err);
+        User::Leave(err);
+    }
+
+    if (mask)
+    {
+        CleanupStack::Pop(mask);
+    }
+    CleanupStack::Pop(bmp);
+    aResBmp = bmp;
+    aResMask = mask;
+}
+
+void CStartScreen::AsyncSaveImageL(TImageId aId, const CFbsBitmap& aBmp)
+{
+    const TDesC& img = ImageName(aId);
+    // Do prefixing here just to avoid dealing with another RBuf :)
+    TUidName uid;
+    if (mType == EStartScreenAutomatic)
+        uid = java::ui::CoreUiAvkonImpl::getInstanceImpl().getMidletTUid().Name();
+    mAsyncSavePath.CreateL(mPath.Length() + img.Length() + uid.Length());
+    mAsyncSavePath.Append(mPath);
+    if (mType == EStartScreenAutomatic)
+        mAsyncSavePath.Append(uid);
+    mAsyncSavePath.Append(img);
+
+    DoAsyncSaveImageL(mAsyncSavePath, aBmp);
+}
+
+void CStartScreen::DoAsyncSaveImageL(const TDesC& aPath, const CFbsBitmap& aBmp)
+{
+    if (IsActive())
+    {
+        Cancel();
+    }
+
+    mEncoder = CImageEncoder::FileNewL(CCoeEnv::Static()->FsSession(), aPath,
+                                       CImageEncoder::EOptionNone, KImageTypePNGUid);
+
+    mState = EAsyncWrite;
+    mEncoder->Convert(&iStatus, aBmp);
+    SetActive();
+}
+
+TSize CStartScreen::GetAspectRatioScaledBitmapSize(
+    const TSize& aSourceSize, const TSize& aMaxDestSize) const
+{
+    JELOG2(EJavaUI);
+    TSize imageSize = aSourceSize;
+    TInt yDiff = 0;
+    TInt xDiff = 0;
+    TBool scalingNeeded = EFalse;
+
+    if (aSourceSize.iWidth == 0 || aSourceSize.iHeight == 0)
+    {
+        return imageSize;
+    }
+
+    // Figure out if any scaling is needed
+    if (aSourceSize.iHeight > aMaxDestSize.iHeight)
+    {
+        yDiff = aSourceSize.iHeight - aMaxDestSize.iHeight;
+        scalingNeeded = ETrue;
+    }
+    if (aSourceSize.iWidth > aMaxDestSize.iWidth)
+    {
+        xDiff = aSourceSize.iWidth - aMaxDestSize.iWidth;
+        scalingNeeded = ETrue;
+    }
+
+    if (scalingNeeded)
+    {
+        if (xDiff > yDiff)
+        {
+            imageSize.iWidth = aMaxDestSize.iWidth;
+            imageSize.iHeight = (aSourceSize.iHeight * aMaxDestSize.iWidth)
+                                / aSourceSize.iWidth;
+        }
+        else if (yDiff > xDiff)
+        {
+            imageSize.iHeight = aMaxDestSize.iHeight;
+            imageSize.iWidth = (aSourceSize.iWidth * aMaxDestSize.iHeight)
+                               / aSourceSize.iHeight;
+        }
+        else
+        {
+            // Aspect ratios are the same
+            imageSize = aMaxDestSize;
+        }
+    }
+
+    return imageSize;
+}
+
+CFbsBitmap* CStartScreen::TakeScreenShotL()
+{
+    CEikonEnv* env = CEikonEnv::Static();
+    CFbsBitmap* bmp = new(ELeave) CFbsBitmap();
+    CleanupStack::PushL(bmp);
+    CWsScreenDevice* screenDevice = env->ScreenDevice();
+    TInt err = bmp->Create(screenDevice->SizeInPixels(), screenDevice->DisplayMode());
+    if (KErrNone != err)
+    {
+        ELOG1(EJavaUI, "CStartScreen::TakeScreenShotL, "
+              "CFbsBitmap::Create failed: %d", err);
+    }
+    err = screenDevice->CopyScreenToBitmap(bmp);
+    if (KErrNone != err)
+    {
+        ELOG1(EJavaUI, "CStartScreen::TakeScreenShotL, "
+              "CWsScreenDevice::CopyScreenToBitmap failed: %d", err);
+    }
+    User::LeaveIfError(err);
+    CleanupStack::Pop(bmp);
+    return bmp;
+}
+
+const TDesC& CStartScreen::FolderName() const
+{
+    if (mParams.getScreenMode() == java::ui::USER_DEFINED_SCREEN)
+    {
+        return KNullDesC;
+    }
+    if (mType == EStartScreenAutomatic)
+    {
+        return KAutoFolder;
+    }
+    else
+    {
+        return KUserFolder;
+    }
+}
+
+const TDesC& CStartScreen::ImageName(CStartScreen::TImageId aId) const
+{
+    if (mParams.getScreenMode() == java::ui::USER_DEFINED_SCREEN)
+    {
+        return KNullDesC;
+    }
+    if (mType == EStartScreenAutomatic)
+    {
+        switch (aId)
+        {
+        case EImagePortrait:
+            return KAutoPortraitImage;
+        case EImageLandscape:
+            return KAutoLandscapeImage;
+        default:
+            return KNullDesC;
+        }
+    }
+    else
+    {
+        switch (aId)
+        {
+        case EImagePortrait:
+            return KUserPortraitImage;
+        case EImageLandscape:
+            return KUserLandscapeImage;
+        case EImageDefault:
+        default:
+            return KUserDefaultImage;
+        }
+    }
+}
+
+std::string CStartScreen::StartupTimeFileName() const
+{
+    std::wstring temp(mParams.getImagePath());
+    temp.append(L"autostartupimages\\");
+    temp.append(java::ui::CoreUiAvkonImpl::getInstanceImpl().getMidletUid().toString());
+    temp.append(L"time.txt");
+    // This is ok as we know for sure we have only ascii in the path.
+    std::string path(temp.begin(), temp.end());
+    return path;
+}
+
+void CStartScreen::RunL()
+{
+    if (mState == ESyncRead)
+    {
+        if (iStatus == KErrUnderflow)
+        {
+            ELOG1(EJavaUI, "CStartScreen::RunL, "
+                  "CImageDecoder::Convert failed: %d", KErrUnderflow);
+            mDecoder->ContinueConvert(&iStatus);
+            SetActive();
+        }
+        else
+        {
+            if (mWait.IsStarted())
+            {
+                mWait.AsyncStop();
+            }
+
+            // Release the lock on the file.
+            ASSERT(mDecoder);
+            delete mDecoder;
+            mDecoder = NULL;
+
+            // Reset state
+            mState = EIdle;
+        }
+    }
+    else if (mState == EAsyncWrite)
+    {
+        // Release the lock on the file.
+        ASSERT(mEncoder);
+        delete mEncoder;
+        mEncoder = 0;
+
+        // Reset state
+        mState = EIdle;
+
+        if (iStatus == KErrNone)
+        {
+            // The callback will delete the object in the current setup.
+            mCallBack.CallBack();
+        }
+        else
+        {
+            TInt err = iStatus.Int();
+            ELOG1(EJavaUI, "CStartScreen::RunL, "
+                  "CImageEncoder::Convert failed: %d", err);
+        }
+    }
+}
+
+void CStartScreen::DoCancel()
+{
+    if (mState == ESyncRead)
+    {
+        if (mDecoder)
+        {
+            mDecoder->Cancel();
+        }
+        if (mWait.IsStarted())
+        {
+            mWait.AsyncStop();
+        }
+    }
+    else if (mState == EAsyncWrite)
+    {
+        if (mEncoder)
+        {
+            mEncoder->Cancel();
+        }
+    }
+
+    mState = EIdle;
+}