radiohswidget/src/radiohswidget.cpp
changeset 34 bc10a61bd7d3
child 36 ba22309243a1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/radiohswidget/src/radiohswidget.cpp	Fri Jun 25 19:09:05 2010 +0300
@@ -0,0 +1,1097 @@
+/*
+* Copyright (c) 2010 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:  FM Radio home screen widget
+*
+*/
+
+// System includes
+#include <HbPushButton>
+#include <HbLabel>
+#include <HbDocumentLoader>
+#include <HbFrameDrawer>
+#include <HbIcon>
+#include <HbIconAnimationManager>
+#include <HbIconAnimationDefinition>
+#include <HbColorScheme>
+#include <HbDeviceMessageBox>
+#include <QGraphicsLinearLayout>
+#include <QGraphicsItem>
+#include <QDesktopServices>
+#include <QSignalMapper>
+
+// User includes
+#include "radiohswidget.h"
+#include "radiohswidgetprofilereader.h"
+#include "radiohswidgetradioserviceclient.h"
+#include "radioservicedef.h"
+#include "radio_global.h"
+#include "radiologger.h"
+
+// Constants
+/** Path to docml file */
+const QString DOCML(":/ui/resource/fmradiohswidget.docml");
+
+/**  DOCML object name for mainLayout */
+const QString DOCML_OBJECT_NAME_MAIN_LAYOUT("mainLayout");
+/**  DOCML object name for contentLayout */
+const QString DOCML_OBJECT_NAME_CONTENT_LAYOUT("contentLayout");
+/**  DOCML object name for tunerBackgroundPushButton */
+const QString DOCML_OBJECT_NAME_TUNER_BACKGROUND_BUTTON(
+    "tunerBackgroundPushButton");
+/**  DOCML object name for tunerStackedLayout */
+const QString DOCML_OBJECT_NAME_TUNER_STACKED_LAYOUT("tunerStackedLayout");
+/**  DOCML object name for tunerInformationStackedLayout */
+const QString DOCML_OBJECT_NAME_TUNER_INFORMATION_STACKED_LAYOUT(
+    "tunerInformationStackedLayout");
+/**  DOCML object name for controlButtons */
+const QString DOCML_OBJECT_NAME_CONTROL_BUTTONS_LAYOUT("controlButtons");
+/**  DOCML object name for powerToggleButton */
+const QString DOCML_OBJECT_NAME_POWER_BUTTON("powerButton");
+/**  DOCML object name for previousPushButton */
+const QString DOCML_OBJECT_NAME_PREVIOUS_BUTTON("previousPushButton");
+/**  DOCML object name for nextPushButton */
+const QString DOCML_OBJECT_NAME_NEXT_BUTTON("nextPushButton");
+/**  DOCML object name for twoRowsLayout */
+const QString DOCML_OBJECT_NAME_TWO_ROWS_LAYOUT("twoRowsLayout");
+/**  DOCML object name for firstRowLabel */
+const QString DOCML_OBJECT_NAME_FIRST_ROW_LABEL("firstRowLabel");
+/**  DOCML object name for secondRowLabel */
+const QString DOCML_OBJECT_NAME_SECOND_ROW_LABEL("secondRowLabel");
+/**  DOCML object name for lonelyRowLabel */
+const QString DOCML_OBJECT_NAME_LONELY_ROW_LABEL("lonelyRowLabel");
+/**  DOCML object name for animationIcon */
+const QString DOCML_OBJECT_NAME_ANIMATION_ICON("animationIcon");
+
+/** Unknown favorite station count. */
+const int FAVORITE_STATION_COUNT_UNDEFINED(-1);
+/** One favorite station set. */
+const int FAVORITE_STATION_COUNT_ONE(1);
+/** Favorite station count lower boundary including this number. */
+const int FAVORITE_STATION_COUNT_LOWER_BOUNDARY(0);
+/** Favorite station count upper boundary including this number. */
+const int FAVORITE_STATION_COUNT_UPPER_BOUNDARY(100);
+
+// Graphics identifiers for different push button states
+const QString CONTROL_BUTTON_GRAPHICS_NORMAL  ("qtg_fr_hsbutton_normal");
+const QString CONTROL_BUTTON_GRAPHICS_PRESSED ("qtg_fr_hsbutton_pressed");
+const QString CONTROL_BUTTON_GRAPHICS_DISABLED("qtg_fr_hsbutton_disabled");
+const QString CONTROL_BUTTON_GRAPHICS_LATCHED ("qtg_fr_hsbutton_latched");
+
+// Push button icon colors for each of the states (normal, pressed, disabled
+// and latched)
+const QString CONTROL_BUTTON_ICON_COLOR_NORMAL  ("qtc_button_normal");
+const QString CONTROL_BUTTON_ICON_COLOR_PRESSED ("qtc_button_pressed");
+const QString CONTROL_BUTTON_ICON_COLOR_DISABLED("qtc_button_disabled");
+const QString CONTROL_BUTTON_ICON_COLOR_LATCHED ("qtc_button_latched");
+
+// File name suffix lists for push buttons
+const QStringList POWER_BUTTON_SUFFIX(
+    (QStringList() << "_l" << "_c" << "_cr"));
+const QStringList PREVIOUS_BUTTON_SUFFIX(
+    (QStringList() << "_cl" << "_c" << "_cr"));
+const QStringList NEXT_BUTTON_SUFFIX(
+    (QStringList() << "_cl" << "_c" << "_r"));
+
+/** Icon for power button off. */
+const QString POWER_BUTTON_ICON_OFF("qtg_mono_power"); 
+/** Icon for power button on. */
+const QString POWER_BUTTON_ICON_ON ("qtg_mono_power"); 
+
+// Tuner background button graphics for different states.
+const QString TUNER_BUTTON_NORMAL_OFF("qtg_fr_tuner");
+const QString TUNER_BUTTON_NORMAL_ON("qtg_fr_tuner");
+const QString TUNER_BUTTON_NORMAL_PRESSED("qtg_fr_hsitems2_pressed");
+
+/*!
+    \class RadioHsWidget
+    \brief Implementation of FM Radio home screen widget.
+
+    RadioHsWidget implements needed functions for the FM Radio home screen
+    widget.
+*/
+
+// ======== MEMBER FUNCTIONS ========
+
+/*!
+    Constructs a widget which is a child of \a parent, with widget flags set
+    to \a flags.
+    
+    Constructor should be empty and all the actual construction should be
+    done in onInitialize().
+ */
+RadioHsWidget::RadioHsWidget(QGraphicsItem* parent, Qt::WindowFlags flags)
+    : HbWidget(parent, flags),
+      mInformationAreaBackgroundButton(NULL),
+      mPowerButton(NULL),
+      mPreviousButton(NULL),
+      mNextButton(NULL),
+      mInformationAreaTwoRowsLayout(NULL),
+      mInformationLonelyRowLabel(NULL),
+      mInformationFirstRowLabel(NULL),
+      mInformationSecondRowLabel(NULL),
+      mAnimationIcon(NULL),
+      mFmRadioState(FmRadio::StateUndefined),
+      mFavoriteStationCount(FAVORITE_STATION_COUNT_UNDEFINED),
+      mCurrentStationIsFavorite(false),
+      mProfileMonitor(NULL),
+      mRadioServiceClient(NULL)
+{
+    LOG_METHOD;
+}
+
+/*!
+    Destructor
+ */
+RadioHsWidget::~RadioHsWidget()
+{
+    LOG_METHOD;
+}
+
+/*!
+    Handles changes in FM Radio information.
+
+    \param informationType Type of changed information.
+    \param information Actual information.
+ */
+void RadioHsWidget::handleRadioInformationChange(const int informationType,
+    const QVariant &information)
+{
+    LOG_METHOD;
+    switch (informationType) {
+
+    case RadioServiceNotification::FavoriteCount:
+        LOG("FavoriteCount");
+        if (information.canConvert(QVariant::Int) &&
+            information.toInt() >= FAVORITE_STATION_COUNT_LOWER_BOUNDARY &&
+            information.toInt() <= FAVORITE_STATION_COUNT_UPPER_BOUNDARY) {
+            mFavoriteStationCount = information.toInt();
+            // If there are favorite stations, enable the next/previous
+            // buttons.
+            LOG_FORMAT("mFavoriteStationCount: %d", mFavoriteStationCount);
+            // Enable or disable buttons only if favoriteCount differs
+            // from 1. CurrentIsFavorite case handles situation when there
+            // is only one favorite station.
+            if (mFavoriteStationCount != FAVORITE_STATION_COUNT_ONE) {
+                enableStationButtons();
+            }
+        } else {
+            mFavoriteStationCount = FAVORITE_STATION_COUNT_UNDEFINED;
+        }
+        break;
+
+    case RadioServiceNotification::CurrentIsFavorite:
+        LOG("CurrentIsFavorite");
+        if (information.canConvert(QVariant::Bool)) {
+            mCurrentStationIsFavorite = information.toBool();
+            LOG_FORMAT("currentIsFavorite: %d", mCurrentStationIsFavorite);
+            // If current station is favorite disable next/prev buttons.
+            // Radio sends this information only when there is only one
+            // favorite station set.
+            enableStationButtons();
+        }
+        break;
+
+    case RadioServiceNotification::RadioStatus:
+        LOG("RadioStatus");
+        if (information.canConvert(QVariant::Int)) {
+            const int status = information.toInt();
+            switch (status) {
+            case RadioStatus::Playing:
+                LOG("Playing");
+                break;
+            case RadioStatus::Muted:
+                LOG("Muted");
+                break;
+            case RadioStatus::Seeking:
+                LEVEL2(LOG("Seeking"));
+                handleRadioStateChange(FmRadio::StateSeeking);
+                break;
+            case RadioStatus::NoAntenna:
+                LEVEL2(LOG("NoAntenna"));
+                handleRadioStateChange(FmRadio::StateAntennaNotConnected);
+                break;
+            case RadioStatus::PoweringOff:
+                LEVEL2(LOG("PoweringOff"));
+                handleRadioStateChange(FmRadio::StateClosing);
+                break;
+            default:
+                LOG("default case at case RadioStatus");
+                break;
+            }
+        }
+        break;
+
+    case RadioServiceNotification::Frequency:
+        LOG("Frequency");
+        // TODO: Should information.toString() be checked for too many characters? What's the limit?
+        if (information.canConvert(QVariant::String)) {
+            LOG_FORMAT("frequency: %s", GETSTRING(information.toString()));
+            // TODO: Remove comment when localisation is working on device.
+            //frequencyString = hbTrId("txt_fmradiohswidget_rad_list_l1_mhz").arg(freqString);
+            bool frequencyCleared = false;
+            // If widget has some frequency information and new frequency
+            // differs from that
+            if (mRadioInformation.contains(Frequency)
+                && mRadioInformation[Frequency].compare(information.toString()) != 0) {
+                // Clear all infromation from widget because station has changed.
+                clearRadioInformation();
+                frequencyCleared = true;
+            }
+            // If widget do not have any frquency information, update it.
+            bool frequencyUpdated = updateRadioInformation(Frequency,
+                information.toString());
+            if (frequencyCleared || frequencyUpdated) {
+                // Information changed, update the UI.
+                changeInRadioInformation();
+            }
+        }
+        break;
+
+    case RadioServiceNotification::Name:
+        LOG("Name");
+        handleSimilarRadioInformation(StationName, information);
+        break;
+
+    case RadioServiceNotification::Genre:
+        LOG("Genre");
+        handleSimilarRadioInformation(Pty, information);
+        break;
+
+    case RadioServiceNotification::RadioText:
+        LOG("RadioText");
+        handleSimilarRadioInformation(RadioText, information);
+        break;
+
+    case RadioServiceNotification::DynamicPS:
+        LOG("DynamicPS");
+        handleSimilarRadioInformation(DynamicPsName, information);
+        break;
+
+    default:
+        LOG("default case at notificationId");
+        break;
+    }
+}
+
+/*!
+    Handles changes in FM Radio state.
+
+    \param value New state of the radio application.
+*/
+void RadioHsWidget::handleRadioStateChange(const QVariant &value)
+{
+    LOG_METHOD;
+    int state;
+    if (value.canConvert(QVariant::Int)) {
+        state = value.toInt();
+    } else {
+        return;
+    }
+
+    if (state == mFmRadioState) {
+        // State did not change, so return.
+        return;
+    }
+
+    switch (state) {
+    case FmRadio::StateUndefined:
+        LOG("FmRadio::StateUndefined");
+        // Something went wrong. Widget should not be in this state after onInitialize().
+        mFmRadioState = FmRadio::StateUndefined;
+        break;
+    case FmRadio::StateNotRunning:
+        LOG("FmRadio::StateNotRunning");
+        mFmRadioState = FmRadio::StateNotRunning;
+        mRadioServiceClient->stopMonitoring();
+        changePowerButtonOn(false);
+        mFavoriteStationCount = FAVORITE_STATION_COUNT_UNDEFINED;
+        mCurrentStationIsFavorite = false;
+        enableStationButtons();
+        clearRadioInformation();
+        mInformationFirstRowLabel->setPlainText("");
+        mInformationSecondRowLabel->setPlainText("");
+        mInformationLonelyRowLabel->setPlainText(hbTrId("txt_fmradiohswidget_rad_list_fm_radio"));
+        changeInformationAreaLayout(OneRow);
+        break;
+    case FmRadio::StateStarting:
+        LOG("FmRadio::StateStarting");
+        mFmRadioState = FmRadio::StateStarting;
+        changePowerButtonOn(true);
+        mFavoriteStationCount = FAVORITE_STATION_COUNT_UNDEFINED;
+        mCurrentStationIsFavorite = false;
+        enableStationButtons();
+        changeInformationAreaLayout(Animation);
+        break;
+    case FmRadio::StateRunning:
+        LOG("FmRadio::StateRunning");
+        mFmRadioState = FmRadio::StateRunning;
+        // Stop timer if it is running because radio is now running.
+        mRadioServiceClient->startMonitoring(
+            FmRadio::VisibiltyDoNotChange);
+        changePowerButtonOn(true);
+        enableStationButtons();
+        changeInformationAreaLayout(OneRow);
+        break;
+    case FmRadio::StateSeeking:
+        LOG("FmRadio::StateSeeking");
+        mFmRadioState = FmRadio::StateSeeking;
+        mFavoriteStationCount = FAVORITE_STATION_COUNT_UNDEFINED;
+        mCurrentStationIsFavorite = false;
+        enableStationButtons();
+        changeInformationAreaLayout(Animation);
+        break;
+    case FmRadio::StateAntennaNotConnected:
+        LOG("FmRadio::StateAntennaNotConnected");
+        mFmRadioState = FmRadio::StateAntennaNotConnected;
+        mFavoriteStationCount = FAVORITE_STATION_COUNT_UNDEFINED;
+        mCurrentStationIsFavorite = false;
+        enableStationButtons();
+        mInformationFirstRowLabel->setPlainText("");
+        mInformationSecondRowLabel->setPlainText("");
+        mInformationLonelyRowLabel->setPlainText(hbTrId(
+            "txt_fmradiohswidget_rad_info_connect_wired_headset"));
+        changeInformationAreaLayout(OneRow);
+        break;
+    case FmRadio::StateClosing:
+        LOG("FmRadio::StateClosing");
+        mFmRadioState = FmRadio::StateClosing;
+        changePowerButtonOn(false);
+        mFavoriteStationCount = FAVORITE_STATION_COUNT_UNDEFINED;
+        mCurrentStationIsFavorite = false;
+        enableStationButtons();
+        clearRadioInformation();
+        mInformationFirstRowLabel->setPlainText("");
+        mInformationSecondRowLabel->setPlainText("");
+        mInformationLonelyRowLabel->setPlainText(hbTrId(
+            "txt_fmradiohswidget_rad_list_fm_radio"));
+        changeInformationAreaLayout(OneRow);
+        break;
+    default:
+        LOG_FORMAT("default case at state. State: %d", state);
+        break;
+    }
+}
+
+/*!
+    Called when widget is initialized. Constructs objects and connects them.
+*/
+void RadioHsWidget::onInitialize()
+{
+    LOG_METHOD_ENTER;
+    mProfileMonitor = new RadioHsWidgetProfileReader(this);
+    mRadioServiceClient = new RadioHsWidgetRadioServiceClient(this);
+    
+    load(DOCML);
+    
+    // Use signal mapper to indicate button identifiers to button event
+    // slots. 
+    QSignalMapper* signalMapperPressed = new QSignalMapper(this); 
+    signalMapperPressed->setMapping(mPowerButton, Power);
+    signalMapperPressed->setMapping(mPreviousButton, Previous);
+    signalMapperPressed->setMapping(mNextButton, Next);
+
+    // Need to use different signal mapper for pressed and released events, 
+    // both have same mappings but they are mapped to different slots.
+    QSignalMapper* signalMapperReleased = new QSignalMapper(this);
+    signalMapperReleased->setMapping(mPowerButton, Power);
+    signalMapperReleased->setMapping(mPreviousButton, Previous);
+    signalMapperReleased->setMapping(mNextButton, Next);
+
+    // Connect button events to signal maps.
+    Radio::connect(mPowerButton, SIGNAL(pressed()), signalMapperPressed, SLOT (map()));
+    Radio::connect(mPowerButton, SIGNAL(released()), signalMapperReleased, SLOT (map()));
+    Radio::connect(mPreviousButton, SIGNAL(pressed()), signalMapperPressed, SLOT (map()));
+    Radio::connect(mPreviousButton, SIGNAL(released()), signalMapperReleased, SLOT (map()));
+    Radio::connect(mNextButton, SIGNAL(pressed()), signalMapperPressed, SLOT (map()));
+    Radio::connect(mNextButton, SIGNAL(released()), signalMapperReleased, SLOT (map()));
+    
+    // Connect mapper signals to self implemented slots.
+    Radio::connect(signalMapperPressed, SIGNAL(mapped(int)), this, SLOT(changeButtonToPressed(int)));
+    Radio::connect(signalMapperReleased, SIGNAL(mapped(int)), this, SLOT(changeButtonToReleased(int)));
+    
+    mProfileMonitor->startMonitoringRadioRunningStatus();
+}
+
+/*!
+    Called when widget is shown in the home screen
+*/
+void RadioHsWidget::onShow()
+{
+    LOG_METHOD_ENTER;
+}
+
+/*!
+    Called when widget is hidden from the home screen
+*/
+void RadioHsWidget::onHide()
+{
+    LOG_METHOD_ENTER;
+}
+
+/*!
+    Emited from HbPushButton:pressed() signal, changes the button layout to
+    pressed state.
+ 
+    \param hsButtonIdentifier Identifies the button which was pressed.
+ */
+void RadioHsWidget::changeButtonToPressed(int hsButtonIdentifier)
+{
+    LEVEL2(LOG_METHOD);
+    buttonEvent(static_cast<ControlButtonIdentifier>(hsButtonIdentifier), Pressed);
+}
+
+/*!
+    Emited from HbPushButton:released() signal, changes the button layout to
+    normal state.
+ 
+    \param hsButtonIdentifier Identifies the button which was released.
+ */
+void RadioHsWidget::changeButtonToReleased(int hsButtonIdentifier)
+{
+    LEVEL2(LOG_METHOD);
+    buttonEvent(static_cast<ControlButtonIdentifier>(hsButtonIdentifier), Normal);
+}
+
+/*!
+    Slot for closing FM Radio application from power button.
+ */
+void RadioHsWidget::closeRadio()
+{
+    LOG_SLOT_CALLER;
+    mRadioServiceClient->commandFmRadio(RadioServiceCommand::PowerOff);
+}
+
+/*!
+    Slot for previous button clicked.
+ */
+void RadioHsWidget::changeToPreviousStation()
+{
+    LOG_SLOT_CALLER;
+    clearRadioInformation();
+    mRadioServiceClient->commandFmRadio(RadioServiceCommand::Previous);
+}
+
+/*!
+    Slot for next button clicked.
+ */
+void RadioHsWidget::changeToNextStation()
+{
+    LOG_SLOT_CALLER;
+    clearRadioInformation();
+    mRadioServiceClient->commandFmRadio(RadioServiceCommand::Next);
+
+}
+
+/*!
+    Slot for bringing the radio application to foreground.
+ */
+void RadioHsWidget::changeRadioToForeground()
+{
+    LOG_SLOT_CALLER;
+    // If radio is not running start it to foreground by monitor request.
+    if (mFmRadioState == FmRadio::StateNotRunning) {
+        bool okToStartRadio = radioStartPermission();
+        if (okToStartRadio) {
+            handleRadioStateChange(FmRadio::StateStarting);
+            mRadioServiceClient->startMonitoring(
+                FmRadio::VisibiltyToForeground);
+        }
+    }
+    else {
+        if (mFmRadioState == FmRadio::StateClosing) {
+            // Radio is closing but user wants to power it up again.
+            mRadioServiceClient->commandFmRadio(RadioServiceCommand::PowerOn);
+            // Stop and start monitoring to get refresh.
+            mRadioServiceClient->stopMonitoring();
+            mRadioServiceClient->startMonitoring(
+                FmRadio::VisibiltyToBackground);
+            handleRadioStateChange(FmRadio::StateRunning);
+        }
+        // If radio is running, bring it to the foreground.
+        mRadioServiceClient->commandFmRadio(RadioServiceCommand::Foreground);
+    }
+}
+
+/*!
+    Slot for putting the radio application to the background.
+ */
+void RadioHsWidget::changeRadioToBackground()
+{
+    LOG_SLOT_CALLER;
+    // If radio is not running start it to background by monitor request.
+    if (mFmRadioState == FmRadio::StateNotRunning) {
+        bool okToStartRadio = radioStartPermission();
+        if (okToStartRadio) {
+            handleRadioStateChange(FmRadio::StateStarting);
+            mRadioServiceClient->startMonitoring(
+                FmRadio::VisibiltyToBackground);
+        }
+    }
+    else if (mFmRadioState == FmRadio::StateStarting) {
+        // Do nothing if radio is starting.
+    }
+    else if (mFmRadioState == FmRadio::StateClosing) {
+        // Radio is closing but user wants to power it up again.
+        mRadioServiceClient->commandFmRadio(RadioServiceCommand::PowerOn);
+        // Stop and start monitoring to get refresh.
+        mRadioServiceClient->stopMonitoring();
+        mRadioServiceClient->startMonitoring(
+            FmRadio::VisibiltyToBackground);
+        handleRadioStateChange(FmRadio::StateRunning);
+    }
+    else {
+        // If radio is running, put it to the background.
+        // This is little bit useless because the radio is in background if
+        // user is able to click the widget.
+        mRadioServiceClient->commandFmRadio(RadioServiceCommand::Background);
+    }
+}
+
+/*!
+    Powering off or on the radio.
+ */
+void RadioHsWidget::toggleRadioPower()
+{
+    LOG_SLOT_CALLER;
+    // If radio is not running start it to background by monitor request.
+    if (mFmRadioState == FmRadio::StateNotRunning || mFmRadioState == FmRadio::StateClosing) {
+        LEVEL2(LOG("Power on"));
+        // Start radio
+        changeRadioToBackground();
+    } else {
+        LEVEL2(LOG("Power off"));
+        // Close radio
+        closeRadio();
+    }
+}
+
+/*!
+    Loads docml file.
+ 
+    \param docml Docml filename to be loaded.
+ */
+void RadioHsWidget::load(const QString &docml)
+{
+    LOG_METHOD_ENTER;
+
+    QScopedPointer<HbDocumentLoader> documentLoader(new HbDocumentLoader());
+    bool loaded = false;
+    documentLoader->load(docml, &loaded);
+    if (loaded) {
+        // Find mainLayout
+        HbWidget *mainLayout = qobject_cast<HbWidget*> (
+            documentLoader->findWidget(DOCML_OBJECT_NAME_MAIN_LAYOUT));
+
+        if (mainLayout) {
+            QGraphicsLinearLayout *widgetLayout = new QGraphicsLinearLayout(
+                Qt::Vertical, this);
+            widgetLayout->addItem(mainLayout);
+            setLayout(widgetLayout);
+        }
+
+        // Find contentLayout
+        HbWidget *contentLayout = qobject_cast<HbWidget*> (
+            documentLoader->findWidget(DOCML_OBJECT_NAME_CONTENT_LAYOUT));
+        if (contentLayout) {
+
+            // Find stacked layout for tuner area.
+            HbWidget *tunerStackedLayout = qobject_cast<HbWidget*> (
+                documentLoader->findWidget(
+                    DOCML_OBJECT_NAME_TUNER_STACKED_LAYOUT));
+            if (tunerStackedLayout) {
+
+                // Find stacked layout for information area.
+                HbWidget *tunerInformationStackedLayout = qobject_cast<
+                    HbWidget*> (documentLoader->findWidget(
+                    DOCML_OBJECT_NAME_TUNER_INFORMATION_STACKED_LAYOUT));
+                if (tunerInformationStackedLayout) {
+                }
+
+                // Find lonely label
+                mInformationLonelyRowLabel = qobject_cast<HbLabel *> (
+                    documentLoader->findWidget(
+                        DOCML_OBJECT_NAME_LONELY_ROW_LABEL));
+                if (mInformationLonelyRowLabel) {
+                    // TODO: Set the color in docml when application designer supports it.
+                    QColor color = HbColorScheme::color(
+                        "qtc_radio_tuner_normal");
+                    mInformationLonelyRowLabel->setTextColor(color);
+                }
+
+                // Find layout for two rows
+                mInformationAreaTwoRowsLayout = qobject_cast<
+                    QGraphicsWidget *> (documentLoader->findObject(
+                    DOCML_OBJECT_NAME_TWO_ROWS_LAYOUT));
+                if (mInformationAreaTwoRowsLayout) {
+                    // Find first row
+                    mInformationFirstRowLabel = qobject_cast<HbLabel *> (
+                        documentLoader->findWidget(
+                            DOCML_OBJECT_NAME_FIRST_ROW_LABEL));
+                    if (mInformationFirstRowLabel) {
+                        // TODO: Set the color in docml when application designer supports it.
+                        QColor color = HbColorScheme::color(
+                            "qtc_radio_tuner_normal");
+                        mInformationFirstRowLabel->setTextColor(color);
+                    }
+
+                    // Find second row
+                    mInformationSecondRowLabel = qobject_cast<HbLabel *> (
+                        documentLoader->findWidget(
+                            DOCML_OBJECT_NAME_SECOND_ROW_LABEL));
+                    if (mInformationSecondRowLabel) {
+                        // TODO: Set the color in docml when application designer supports it.
+                        QColor color = HbColorScheme::color(
+                            "qtc_radio_tuner_normal");
+                        mInformationSecondRowLabel->setTextColor(color);
+                    }
+                }
+
+                mAnimationIcon = qobject_cast<HbLabel *> (
+                    documentLoader->findWidget(
+                        DOCML_OBJECT_NAME_ANIMATION_ICON));
+                if (mAnimationIcon) {
+                    // Use animation manager to access anim loading animation.
+                    HbIconAnimationManager *animationManager =
+                        HbIconAnimationManager::global();
+                    // TODO: Axml extension can be removed after wk24 release.
+                    animationManager->addDefinitionFile(QLatin1String(
+                        "qtg_anim_loading.axml"));
+                    mAnimationIcon->setIcon(HbIcon("qtg_anim_loading"));
+                }
+            }
+
+            // Find push button for tuner area.
+            mInformationAreaBackgroundButton = qobject_cast<HbPushButton*> (
+                documentLoader->findWidget(
+                    DOCML_OBJECT_NAME_TUNER_BACKGROUND_BUTTON));
+            if (mInformationAreaBackgroundButton) {
+                // Use the frame background.
+                HbFrameDrawer *tunerBackgroundButtonFrameDrawer =
+                    new HbFrameDrawer("qtg_fr_tuner",
+                        HbFrameDrawer::ThreePiecesHorizontal);
+                tunerBackgroundButtonFrameDrawer->setFillWholeRect(true);
+                mInformationAreaBackgroundButton->setFrameBackground(
+                    tunerBackgroundButtonFrameDrawer);
+                // Connect the button's clicked signal. 
+                Radio::connect(mInformationAreaBackgroundButton,
+                    SIGNAL(clicked()), this, SLOT(changeRadioToForeground()));
+            }
+
+            // Find layout for control buttons.
+            HbWidget *controlButtonsLayout = qobject_cast<HbWidget*> (
+                documentLoader->findWidget(
+                    DOCML_OBJECT_NAME_CONTROL_BUTTONS_LAYOUT));
+            if (controlButtonsLayout) {
+
+                // Find power button.
+                mPowerButton
+                    = qobject_cast<HbPushButton *> (
+                        documentLoader->findWidget(
+                            DOCML_OBJECT_NAME_POWER_BUTTON));
+                if (mPowerButton) {
+                    defineButton(*mPowerButton,
+                        CONTROL_BUTTON_GRAPHICS_NORMAL, POWER_BUTTON_SUFFIX,
+                        POWER_BUTTON_ICON_ON,
+                        CONTROL_BUTTON_ICON_COLOR_NORMAL);
+                    // Connect the button's clicked signal.
+                    Radio::connect(mPowerButton, SIGNAL(clicked()), this,
+                        SLOT(toggleRadioPower()));
+                }
+
+                // Find previous button.
+                mPreviousButton = qobject_cast<HbPushButton *> (
+                    documentLoader->findWidget(
+                        DOCML_OBJECT_NAME_PREVIOUS_BUTTON));
+                if (mPreviousButton) {
+                    defineButton(*mPreviousButton,
+                        CONTROL_BUTTON_GRAPHICS_DISABLED,
+                        PREVIOUS_BUTTON_SUFFIX, NULL,
+                        CONTROL_BUTTON_ICON_COLOR_DISABLED);
+                    // Connect the button's clicked signal.
+                    Radio::connect(mPreviousButton, SIGNAL(clicked()), this,
+                        SLOT(changeToPreviousStation()));
+                }
+
+                // Find next button.
+                mNextButton
+                    = qobject_cast<HbPushButton *> (
+                        documentLoader->findWidget(
+                            DOCML_OBJECT_NAME_NEXT_BUTTON));
+                if (mNextButton) {
+                    defineButton(*mNextButton,
+                        CONTROL_BUTTON_GRAPHICS_DISABLED, NEXT_BUTTON_SUFFIX,
+                        NULL, CONTROL_BUTTON_ICON_COLOR_DISABLED);
+                    // Connect the button's clicked signal.
+                    Radio::connect(mNextButton, SIGNAL(clicked()), this,
+                        SLOT(changeToNextStation()));
+                }
+            }
+        }
+    }
+    else {
+        // Docml was not succesfully loaded. UI cannot be displayed.
+        // Emit error to home screen framework, which removes the widget. 
+        emit error();
+    }
+}
+
+/*!
+    Groups handling of similar kind of radio information (textual) to one
+    function.
+
+    \param informationType Type of changed information.
+    \param information Actual textual information.
+ */
+void RadioHsWidget::handleSimilarRadioInformation(
+    const FmRadioInformationType informationType, const QVariant &information)
+{
+    LOG_METHOD_ENTER;
+    // TODO: Should information.toString() be checked for too many characters? What's the limit?
+    if (information.canConvert(QVariant::String) && updateRadioInformation(
+        informationType, information.toString())) {
+        LOG_FORMAT("informationType: %d, information: %s", informationType, GETSTRING(information.toString()));
+        changeInRadioInformation();
+    }
+}
+
+/*!
+    Check if the the radio information is changed. If it is changed, it is
+    also updated.
+
+    \param informationType Type of the information.
+    \param information  Information text.
+
+    \returns Returns \c true, if information is updated. Returns \c false otherwise.
+ */
+bool RadioHsWidget::updateRadioInformation(const FmRadioInformationType informationType,
+    const QString &information)
+{
+    LOG_METHOD_RET("%d");
+    // If hash contains this type of information.
+    if (mRadioInformation.contains(informationType)) {
+        // If new information is empty.
+        if (information.isEmpty()) {
+            // Remove old information from the hash.
+            LEVEL2(LOG_FORMAT("informationType: %s removed", GETSTRING(informationType)));
+            mRadioInformation.remove(informationType);
+            // Return true to indicate the change.
+            return true;
+        }
+        // If new information differs from the old one.
+        if (mRadioInformation[informationType].compare(information) != 0) {
+            // Update the information.
+            LEVEL2(LOG_FORMAT("informationType: %s = %s", GETSTRING(informationType), GETSTRING(information)));
+            mRadioInformation[informationType] = information;
+            // And return true to indicate the change.
+            return true;
+        }
+    } else { // Hash do not contain this type of information.
+        // If new information is not empty.
+        if (!information.isEmpty()) {
+            // Add it to the hash.
+            LEVEL2(LOG_FORMAT("informationType: %s = %s", GETSTRING(informationType), GETSTRING(information)));
+            mRadioInformation[informationType] = information;
+            // Return true to indicate the change.
+            return true;
+        }
+    }
+    // Return false to indicate that nothing changed.
+    return false;
+}
+
+/*!
+    Formatting radio information texts after a change.
+ */
+void RadioHsWidget::changeInRadioInformation()
+{
+    LOG_METHOD_ENTER;
+    // Clear the rows.
+    mRadioInformationFirstRow.clear();
+    mRadioInformationSecondRow.clear();
+
+    // First row contains station name.
+    if (mRadioInformation.contains(StationName)) {
+        mRadioInformationFirstRow.append(mRadioInformation.value(StationName));
+    }
+    else if (mRadioInformation.contains(Frequency)) {
+        // Or frequency.
+        mRadioInformationFirstRow.append(mRadioInformation.value(Frequency));
+    } LEVEL2(LOG_FORMAT("mRadioInformationFirstRow: %s", GETSTRING(mRadioInformationFirstRow)));
+
+    // Second row of information contains radio text.
+    if (mRadioInformation.contains(RadioText)) {
+        mRadioInformationSecondRow.append(mRadioInformation.value(RadioText));
+    }
+    else if (mRadioInformation.contains(DynamicPsName)) {
+        // Or Dynamic PS name.
+        mRadioInformationSecondRow.append(mRadioInformation.value(DynamicPsName));
+    }
+    else if (mRadioInformation.contains(Pty)) {
+        // Or PTY.
+        mRadioInformationSecondRow.append(mRadioInformation.value(Pty));
+    }
+    LEVEL2(LOG_FORMAT("mRadioInformationSecondRow: %s", GETSTRING(mRadioInformationSecondRow)));
+    
+    // If second row is empty.
+    if (mRadioInformationSecondRow.isEmpty()) {
+        // Show only the lonely row.
+        mInformationLonelyRowLabel->setPlainText(mRadioInformationFirstRow);
+        changeInformationAreaLayout(OneRow);
+    }
+    else {
+        // Else display both rows.
+        mInformationFirstRowLabel->setPlainText(mRadioInformationFirstRow);
+        mInformationSecondRowLabel->setPlainText(mRadioInformationSecondRow);
+        changeInformationAreaLayout(TwoRows);
+    }
+}
+
+/*!
+    Clears the radio station information. For example, when the station is
+    changed, old information should be cleared.
+ */
+void RadioHsWidget::clearRadioInformation()
+{
+    LOG_METHOD_ENTER;
+    mRadioInformation.clear();
+}
+
+/*!
+    Changes visible widgets of information area stacked layout.
+
+    \param layout The layout to switch visible.
+ */
+void RadioHsWidget::changeInformationAreaLayout(const InformationAreaLayout layout)
+{
+    LOG_METHOD_ENTER;
+    mInformationLonelyRowLabel->setVisible(layout == OneRow);
+    mInformationAreaTwoRowsLayout->setVisible(layout == TwoRows);
+    mAnimationIcon->setVisible(layout == Animation);
+}
+
+/*!
+    Changes state of power button.
+    
+    \param isPowerOn \c true the power is on and \c false the power is off.
+ */
+void RadioHsWidget::changePowerButtonOn(const bool isPowerOn)
+{
+    LEVEL2(LOG_METHOD);
+    if (isPowerOn) {
+        LEVEL2(LOG("Power on"));
+        // TODO: Temporarily set the text to clarify the action it performs.
+        // Remove when graphics displays the difference.
+        mPowerButton->setText("Off");
+        buttonEvent(Power, Latched);
+    } else {
+        LEVEL2(LOG("Power off"));
+        // TODO: Temporarily set the text to clarify the action it performs.
+        // Remove when graphics displays the difference.
+        mPowerButton->setText("On");
+        buttonEvent(Power, Normal);
+    }
+}
+
+/*!
+    Changes enabled state of station buttons.
+ */
+void RadioHsWidget::enableStationButtons()
+{
+    LEVEL2(LOG_METHOD_ENTER);
+    if ((mFavoriteStationCount > 1) || (mFavoriteStationCount == 1
+        && !mCurrentStationIsFavorite)) {
+        changeButtonToEnabled(Next);
+        changeButtonToEnabled(Previous);
+    }
+    else if ((mFavoriteStationCount == 1 && mCurrentStationIsFavorite)
+        || (mFavoriteStationCount < 1)) {
+        changeButtonToDisabled(Next);
+        changeButtonToDisabled(Previous);
+    }
+}
+
+/*!
+    Makes homescreen specific push button based on parameters.
+ 
+    \param target Target push button to modify. Must not be NULL.
+    \param graphicsId Defines the target button background graphics.
+    \param suffix Defines the suffix for the target button background graphics.
+    \param icon Defines the icon for the target button. 
+    \param iconColor Defines the icon color for the target button. 
+ */
+void RadioHsWidget::defineButton(HbPushButton &target, const QString &graphicsId,
+    const QStringList &suffix, const QString &icon, const QString &iconColor)
+{
+    LEVEL2(LOG_METHOD);
+    HbFrameDrawer* drawer = NULL;
+
+    // First check if the drawer is already created for this push button
+    if (!target.frameBackground()) {
+        LEVEL2(LOG("Creating new frame background."));
+        // Nope, create one now
+        drawer = new HbFrameDrawer(graphicsId,
+            HbFrameDrawer::ThreePiecesHorizontal);
+        target.setFrameBackground(drawer);
+    }
+    else {
+        // Frame drawer already created, only need to update frame graphics
+        drawer = target.frameBackground();
+        drawer->setFrameGraphicsName(graphicsId);
+    }
+
+    // Set file name suffix list, so that drawer can load correct 3-piece graphic files 
+    drawer->setFileNameSuffixList(suffix);
+    
+    // Set the icon, if it is not NULL
+    if (!icon.isNull()) {
+        target.setIcon(HbIcon(icon));
+    }
+
+    // Update also the icon color
+    QColor color = HbColorScheme::color(iconColor);
+    target.icon().setColor(color);
+
+    // Lastly, check if the buttton is disabled
+    if (iconColor == CONTROL_BUTTON_ICON_COLOR_DISABLED) {
+        target.setEnabled(false);
+    }
+    else {
+        target.setEnabled(true);
+    }
+}
+
+/*!
+    Prepares the information needed for displaying the button correctly
+    reflecting its state.
+ 
+    \param buttonId Identifies the button.
+    \param state Tells in what state the button is.
+ */
+void RadioHsWidget::buttonEvent(ControlButtonIdentifier buttonId,
+    const ControlButtonState state)
+{
+    LEVEL2(LOG_METHOD);
+    HbPushButton* target = NULL;
+    QStringList suffix;
+    QString icon;
+
+    switch (buttonId) {
+    case Power:
+        LEVEL2(LOG("Power"));
+        target = mPowerButton;
+        icon = POWER_BUTTON_ICON_ON;
+        suffix = POWER_BUTTON_SUFFIX;
+        break;
+    case Previous:
+        LEVEL2(LOG("Previous"));
+        target = mPreviousButton;
+        suffix = PREVIOUS_BUTTON_SUFFIX;
+        break;
+    case Next:
+        LEVEL2(LOG("Next"));
+        target = mNextButton;
+        suffix = NEXT_BUTTON_SUFFIX;
+        break;
+    default:
+        LOG("default case at buttonId");
+        break;
+    }
+    
+    QString buttonBackgroundGraphics;
+    QString buttonIconColors;
+    switch (state) {
+    case Normal:
+        LEVEL2(LOG("Normal"));
+        target->setProperty("state", "normal");
+        buttonBackgroundGraphics = CONTROL_BUTTON_GRAPHICS_NORMAL;
+        buttonIconColors = CONTROL_BUTTON_ICON_COLOR_NORMAL;
+        break;
+    case Pressed:
+        LEVEL2(LOG("Pressed"));
+        target->setProperty("state", "pressed");
+        buttonBackgroundGraphics = CONTROL_BUTTON_GRAPHICS_PRESSED;
+        buttonIconColors = CONTROL_BUTTON_ICON_COLOR_PRESSED;
+        break;
+    case Disabled:
+        LEVEL2(LOG("Disabled"));
+        target->setProperty("state", "disabled");
+        buttonBackgroundGraphics = CONTROL_BUTTON_GRAPHICS_DISABLED;
+        buttonIconColors = CONTROL_BUTTON_ICON_COLOR_DISABLED;
+        break;
+    case Latched:
+        LEVEL2(LOG("Latched"));
+        target->setProperty("state", "latched");
+        buttonBackgroundGraphics = CONTROL_BUTTON_GRAPHICS_LATCHED;
+        buttonIconColors = CONTROL_BUTTON_ICON_COLOR_LATCHED;
+        break;
+    default:
+        LOG("default case at button state");
+        break;
+    }
+
+    RadioHsWidget::defineButton(*target, buttonBackgroundGraphics,
+        suffix, icon, buttonIconColors);
+}
+
+/*!
+    Disables specified push button.
+ 
+    \param hsButtonIdentifier Which button is to be disabled.
+ */
+void RadioHsWidget::changeButtonToDisabled(int hsButtonIdentifier)
+{
+    LEVEL2(LOG_METHOD_ENTER);
+    buttonEvent(static_cast<ControlButtonIdentifier>(hsButtonIdentifier), Disabled);
+}
+
+/*!
+    Enabled specified push button.
+ 
+    \param hsButtonIdentifier Which button is to be enabled.
+ */
+void RadioHsWidget::changeButtonToEnabled(int hsButtonIdentifier)
+{
+    LEVEL2(LOG_METHOD_ENTER);
+    changeButtonToReleased(hsButtonIdentifier);
+}
+
+/*!
+    Checks the profile of the device. If profile is offline, user is asked a
+    permission to start the radio in offline profile. Dialog is shown on
+    behalf of the radio asking the permission.    
+    
+    \returns \c true if radio can be started, \c false if device is in
+    offline profile and user didn't gave permission to start the radio.  
+ */
+bool RadioHsWidget::radioStartPermission()
+{
+    LOG_METHOD_ENTER;
+    // This is true by default because we might not be in offline profile and
+    // starting the radio is allowed in other profiles without asking a
+    // permission.
+    bool radioStartPermssion = true;
+    if (mProfileMonitor->isCurrentProfileOffline()) {
+        // Device is in offline profile, ask the user for permission to start
+        HbDeviceMessageBox box(hbTrId(
+            "txt_fmradiohswidget_rad_info_activate_radio_in_offline_mode_hs"),
+            HbMessageBox::MessageTypeQuestion);
+        box.setTimeout(HbPopup::NoTimeout);
+        box.exec();
+        // radioStartPermssion is now true or false, depending what the user
+        // selected. If user didn't gave permission, then radio is not
+        // started.
+        radioStartPermssion = box.isAcceptAction(box.triggeredAction());
+    }
+    return radioStartPermssion;
+}