commit 82e0c384ab163831cb1532c83b1046bb289541c4
Author: I-Fan, Chen <tick@openmoko.com>
Date:   Sat Nov 22 21:44:18 2008 +0800

    Volume Control Slide Bar.
    Make users can control the call volume via a slide bar.
    According to http://doc.trolltech.com/qtextended4.4/qphoneprofile.html#setVolume the
    range of volume is 0~5.
    
    In ficgta01 phonevendor plugin we use AT+CLVL controls the TI calypso modem volume.
    
    You can controls the default volume by setting the QPhoneProfile::setVolume.

diff --git a/devices/ficgta01/src/plugins/phonevendors/ficgta01/vendor_ficgta01.cpp b/devices/ficgta01/src/plugins/phonevendors/ficgta01/vendor_ficgta01.cpp
index 567035c..0a8ab3d 100644
--- a/devices/ficgta01/src/plugins/phonevendors/ficgta01/vendor_ficgta01.cpp
+++ b/devices/ficgta01/src/plugins/phonevendors/ficgta01/vendor_ficgta01.cpp
@@ -835,13 +835,23 @@ Ficgta01CallVolume::Ficgta01CallVolume(Ficgta01ModemService *service)
 {
    this->service = service;
 
-
     QtopiaIpcAdaptor *adaptor
             = new QtopiaIpcAdaptor( "QPE/Ficgta01Modem", this );
 
+    // Set default, then query real value
+    setSpeakerVolumeRange(0, 5);
+    currentVolumeLevel = 3;
+    minVolumeLevel = 0; 
+    maxVolumeLevel = 255;
+    currentVolumeLevel = 153;
+
+    service->primaryAtChat()->chat("AT+CLVL=?", this, SLOT(volumeLevelRangeQueryDone(bool,QAtResult)) );
+    service->primaryAtChat()->chat("AT+CLVL?", this, SLOT(volumeLevelQueryDone(bool,QAtResult)) );
+
     QtopiaIpcAdaptor::connect
             ( adaptor, MESSAGE(setSpeakerVolumeRange(int, int)),
               this, SLOT(setSpeakerVolumeRange(int,int)) );
+
     QtopiaIpcAdaptor::connect
             ( adaptor, MESSAGE(setMicVolumeRange(int, int)),
               this, SLOT(setMicVolumeRange(int,int)) );
@@ -867,10 +877,16 @@ bool Ficgta01CallVolume::hasDelayedInit() const
 
 void Ficgta01CallVolume::setSpeakerVolume( int volume )
 {
+    int volumeLevel;
     int boundedVolume = qBound(value("MinimumSpeakerVolume").toInt(), volume,
                                value("MaximumSpeakerVolume").toInt());
 
     setValue( "SpeakerVolume", boundedVolume );
+    volumeLevel = virtual2real(boundedVolume);
+    if (currentVolumeLevel == volumeLevel)
+        return;
+    currentVolumeLevel = volumeLevel;
+    service->primaryAtChat()->chat("AT+CLVL="+QString::number(currentVolumeLevel));
     emit speakerVolumeChanged(boundedVolume);
 }
 
@@ -896,6 +912,65 @@ void Ficgta01CallVolume::setMicVolumeRange(int min,int max)
     setValue( "MaximumMicrophoneVolume", max );
 }
 
+void Ficgta01CallVolume::volumeLevelRangeQueryDone(bool ok,const QAtResult & result)
+{
+    if (!ok)
+        return;
+    QAtResultParser parser( result );
+    if ( parser.next( "+CLVL:" ) ) {
+        QList<QAtResultParser::Node> nodes = parser.readList();
+        if (!nodes.isEmpty()) {
+            if (nodes.at(0).isRange()) {
+                minVolumeLevel = nodes.at(0).asFirst();
+                maxVolumeLevel = nodes.at(0).asLast();
+            }
+        }
+    }
+}
+
+void Ficgta01CallVolume::volumeLevelQueryDone(bool ok,const QAtResult & result) 
+{
+    int volumeLevel;
+    if (!ok)
+        return;
+    QAtResultParser parser( result );
+    if ( parser.next( "+CLVL:" )) {
+        volumeLevel = (int) parser.readNumeric();
+        if (volumeLevel != currentVolumeLevel) {
+            currentVolumeLevel = volumeLevel;
+            setSpeakerVolume(real2virtual(currentVolumeLevel));
+        }
+    }
+}
+
+int Ficgta01CallVolume::virtual2real(int volume)
+{
+    int ans;
+    int min = value("MinimumSpeakerVolume").toInt();
+    int max = value("MaximumSpeakerVolume").toInt();
+    if (minVolumeLevel >= maxVolumeLevel)
+        return 0;
+    if (min >= max)
+        return 0;
+    ans = volume * (maxVolumeLevel - minVolumeLevel);
+    ans = ans / (max - min);
+    return ans;
+}
+
+int Ficgta01CallVolume::real2virtual(int volumeLevel)
+{
+    int ans;
+    int min = value("MinimumSpeakerVolume").toInt();
+    int max = value("MaximumSpeakerVolume").toInt();
+    if (minVolumeLevel >= maxVolumeLevel)
+        return 0;
+    if (min >= max)
+        return 0;
+    ans = volumeLevel * (max - min);
+    ans = ans / (maxVolumeLevel - minVolumeLevel);
+    return ans;
+}
+
 Ficgta01PreferredNetworkOperators::Ficgta01PreferredNetworkOperators( QModemService *service )
     : QModemPreferredNetworkOperators( service )
 {
diff --git a/devices/ficgta01/src/plugins/phonevendors/ficgta01/vendor_ficgta01_p.h b/devices/ficgta01/src/plugins/phonevendors/ficgta01/vendor_ficgta01_p.h
index 92e5aae..c2cc1e3 100644
--- a/devices/ficgta01/src/plugins/phonevendors/ficgta01/vendor_ficgta01_p.h
+++ b/devices/ficgta01/src/plugins/phonevendors/ficgta01/vendor_ficgta01_p.h
@@ -182,13 +182,19 @@ public slots:
     void setSpeakerVolumeRange(int,int);
     void setMicVolumeRange(int,int);
 
+protected slots:
+    void volumeLevelRangeQueryDone(bool ok, const QAtResult & result );
+    void volumeLevelQueryDone(bool ok, const QAtResult & result );
+
 protected:
     bool hasDelayedInit() const;
     
 private:
+    int virtual2real(int volume);
+    int real2virtual(int volumeLevel);
     Ficgta01ModemService *service;
-
-
+    int minVolumeLevel, maxVolumeLevel;
+    int currentVolumeLevel;
 };
 
 class Ficgta01PreferredNetworkOperators : public QModemPreferredNetworkOperators
diff --git a/src/server/phone/callscreen/semithemed/callscreen.cpp b/src/server/phone/callscreen/semithemed/callscreen.cpp
index b57c1dc..b41c794 100644
--- a/src/server/phone/callscreen/semithemed/callscreen.cpp
+++ b/src/server/phone/callscreen/semithemed/callscreen.cpp
@@ -48,6 +48,7 @@
 #include <QList>
 #include <QLabel>
 #include <QProcess>
+#include <QCallVolume>
 
 #include <QAudioStateConfiguration>
 #include <QAudioStateInfo>
@@ -373,6 +374,9 @@ public:
     void addOptionsToMenu(QMenu *menu);
     void callStateChanged(bool enableAudio);
 
+public slots:
+    void setVolume(int volume);
+
 private slots:
     void actionTriggered(QAction *action);
     void availabilityChanged();
@@ -507,6 +511,12 @@ void CallAudioHandler::callStateChanged(bool enableAudio)
     }
 }
 
+void CallAudioHandler::setVolume(int volume) 
+{
+    QtopiaIpcAdaptor e("QPE/AudioVolumeManager");
+    e.send("setVolume(int)", volume);
+}
+
 //===========================================================================
 CallScreenView::CallScreenView(QWidget* parent)
     : PhoneThemedView(parent)
@@ -535,6 +545,68 @@ void CallScreenView::themeLoaded(const QString& fn)
     emit themeWasLoaded(fn);
 }
 
+//===========================================================================
+class CallScreenVolumeView : public QWidget
+{
+    Q_OBJECT
+public:
+    CallScreenVolumeView(QWidget *parent=0);
+    ~CallScreenVolumeView();
+
+public slots:
+    void setVolume(int volume);
+
+signals:
+    void volumeChange(int volume);
+
+private:
+    int __volume;
+    QLabel *m_setVolumeDown;
+    QLabel *m_setVolumeUp;
+    QSlider *m_volume;
+    QHBoxLayout *layout;
+    QVBoxLayout *vlayout;
+};
+
+CallScreenVolumeView::CallScreenVolumeView(QWidget *parent) : QWidget( parent )
+{
+    vlayout = new QVBoxLayout;
+    layout = new QHBoxLayout;
+    m_setVolumeDown = new QLabel ( tr("Down") , this);
+    m_volume = new QSlider(Qt::Horizontal, this);
+    m_setVolumeUp = new QLabel ( tr("Up") , this);
+
+    m_volume->setRange(0 , 5);
+    __volume = 4;
+
+    m_volume->setTickInterval(1);
+    m_volume->setSingleStep( 1 );
+    m_volume->setPageStep( 1 );
+    m_volume->setValue(__volume);
+    vlayout->addWidget(m_volume, 1);
+    layout->addWidget(m_setVolumeDown);
+    layout->addStretch();
+    layout->addWidget(m_setVolumeUp);
+    vlayout->addLayout(layout);
+    setLayout(vlayout);
+    QObject::connect(m_volume, SIGNAL(valueChanged(int)), this, SLOT(setVolume(int)));
+}
+
+CallScreenVolumeView::~CallScreenVolumeView() 
+{
+    delete m_setVolumeDown;
+    delete m_setVolumeUp;
+    delete m_volume;
+    delete layout;
+    delete vlayout;
+}
+
+void CallScreenVolumeView::setVolume(int volume)
+{
+    __volume = volume;
+    m_volume->setValue(volume);
+    emit volumeChange(__volume);
+}
 
 
 //===========================================================================
@@ -640,10 +712,14 @@ CallScreen::CallScreen(DialerControl *ctrl, QWidget *parent, Qt::WFlags fl)
     connect(m_digits, SIGNAL(textChanged(QString)),
             this, SLOT(updateLabels()) );
 
+    m_volumeView = new CallScreenVolumeView(this);
+    m_volumeView->setVisible(false);
+
     QVBoxLayout* lay = new QVBoxLayout(this);
     lay->setMargin(0);
     lay->addWidget(m_view);
     lay->addWidget(m_digits);
+    lay->addWidget(m_volumeView);
     
 
     m_contextMenu = QSoftMenuBar::menuFor(this);
@@ -698,6 +774,7 @@ CallScreen::CallScreen(DialerControl *ctrl, QWidget *parent, Qt::WFlags fl)
     m_actionTransfer->setVisible(false);
     m_contextMenu->addAction(m_actionTransfer);
 
+
     m_audioConf = new QAudioStateConfiguration(this);
 
     if (m_audioConf->isInitialized())
@@ -706,6 +783,8 @@ CallScreen::CallScreen(DialerControl *ctrl, QWidget *parent, Qt::WFlags fl)
         QObject::connect(m_audioConf, SIGNAL(configurationInitialized()),
                          this, SLOT(initializeAudioConf()));
 
+    QObject::connect(m_volumeView, SIGNAL(volumeChange(int)), m_callAudioHandler, SLOT(setVolume(int)));
+
     setWindowTitle(tr("Calls"));
 
     QObject::connect(m_control,
@@ -1120,6 +1199,7 @@ void CallScreen::stateChanged()
     m_actionResume->setVisible(m_holdCount && !m_incoming && !dialing);
     m_actionEnd->setVisible((m_activeCount || m_holdCount || dialing) && !m_incoming);
     m_actionEndAll->setVisible(m_activeCount && m_holdCount && !m_incoming);
+    m_volumeView->setVisible((m_activeCount || m_holdCount));
     m_actionMerge->setVisible(m_activeCount && m_holdCount &&
                             m_activeCount < MAX_JOINED_CALLS &&
                             m_holdCount < MAX_JOINED_CALLS && !m_incoming);
@@ -1181,6 +1261,7 @@ void CallScreen::stateChanged()
         m_dtmfActiveCall = QString();
     update();
     
+    m_volumeView->setVolume(currentProfile.volume());
     // If there is no ring tone, we skip the muteRing action
     if (currentProfile.volume() == 0)
         muteRingSelected();
@@ -1282,6 +1363,7 @@ void CallScreen::splitCall()
     m_actionHold->setVisible(false);
     m_actionResume->setVisible(false);
     m_actionEnd->setVisible(false);
+    m_volumeView->setVisible(false);
     m_actionEndAll->setVisible(false);
     m_actionMerge->setVisible(false);
     m_actionSplit->setVisible(false);
diff --git a/src/server/phone/callscreen/semithemed/callscreen.h b/src/server/phone/callscreen/semithemed/callscreen.h
index b0ad4c8..2ce66f1 100644
--- a/src/server/phone/callscreen/semithemed/callscreen.h
+++ b/src/server/phone/callscreen/semithemed/callscreen.h
@@ -45,6 +45,7 @@ class QPhoneCall;
 class QSimToolkit;
 class QAbstractMessageBox;
 class MouseControlDialog;
+class CallScreenVolumeView;
 
 class CallScreenView : public PhoneThemedView {
     Q_OBJECT
@@ -153,6 +154,7 @@ private:
     QAction *m_actionSplit;
     QAction *m_actionTransfer;
     QAction *m_actionGsm;
+    CallScreenVolumeView *m_volumeView;
 
     // call handling
     DialerControl *m_control;
