diff --git a/src/plugins/coreplugin/messagemanager.cpp b/src/plugins/coreplugin/messagemanager.cpp
index 6252d119d48c88d4d60b4e9274032bc3f6d5e049..7ff9cee01cdf6bd03e9857fb72dbd1855a80248f 100644
--- a/src/plugins/coreplugin/messagemanager.cpp
+++ b/src/plugins/coreplugin/messagemanager.cpp
@@ -82,3 +82,14 @@ void MessageManager::printToOutputPane(const QString &text, bool bringToForegrou
         m_messageOutputWindow->popup(false);
     m_messageOutputWindow->append(text);
 }
+
+void MessageManager::printToOutputPanePopup(const QString &text)
+{
+    printToOutputPane(text, true);
+}
+
+void MessageManager::printToOutputPane(const QString &text)
+{
+    printToOutputPane(text, false);
+}
+
diff --git a/src/plugins/coreplugin/messagemanager.h b/src/plugins/coreplugin/messagemanager.h
index 664269cda67b8ed1e7c49c6b1f1a0d98fdf32e39..4191145cd88f197db18bb220fbe63ba110607530 100644
--- a/src/plugins/coreplugin/messagemanager.h
+++ b/src/plugins/coreplugin/messagemanager.h
@@ -55,7 +55,9 @@ public:
     void showOutputPane();
 
 public slots:
-    void printToOutputPane(const QString &text, bool bringToForeground = true);
+    void printToOutputPane(const QString &text, bool bringToForeground);
+    void printToOutputPanePopup(const QString &text); // pops up
+    void printToOutputPane(const QString &text);
 
 private:
     Internal::MessageOutputWindow *m_messageOutputWindow;
diff --git a/src/plugins/debugger/gdb/gdb.pri b/src/plugins/debugger/gdb/gdb.pri
index e7763cecb6f939efe2862d7bb3cc3adada4438d7..19f453ba7d6512fa22b509bf763c42f1c67470c3 100644
--- a/src/plugins/debugger/gdb/gdb.pri
+++ b/src/plugins/debugger/gdb/gdb.pri
@@ -19,6 +19,7 @@ HEADERS += \
     $$PWD/termgdbadapter.h \
     $$PWD/remotegdbadapter.h \
     $$PWD/trkgdbadapter.h \
+    $$PWD/s60debuggerbluetoothstarter.h
 
 SOURCES += \
     $$PWD/gdbmi.cpp \
@@ -34,6 +35,7 @@ SOURCES += \
     $$PWD/termgdbadapter.cpp \
     $$PWD/remotegdbadapter.cpp \
     $$PWD/trkgdbadapter.cpp \
+    $$PWD/s60debuggerbluetoothstarter.cpp
 
 FORMS +=  $$PWD/gdboptionspage.ui \
 $$PWD/trkoptionswidget.ui
diff --git a/src/plugins/debugger/gdb/s60debuggerbluetoothstarter.cpp b/src/plugins/debugger/gdb/s60debuggerbluetoothstarter.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b1d34f4ff3a87bdcc53b169546713161169605ea
--- /dev/null
+++ b/src/plugins/debugger/gdb/s60debuggerbluetoothstarter.cpp
@@ -0,0 +1,51 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "s60debuggerbluetoothstarter.h"
+#include "debuggermanager.h"
+
+namespace Debugger {
+namespace Internal {
+
+S60DebuggerBluetoothStarter::S60DebuggerBluetoothStarter(const  TrkDevicePtr& trkDevice, QObject *parent) :
+    trk::AbstractBluetoothStarter(trkDevice, parent)
+{
+}
+
+trk::BluetoothListener *S60DebuggerBluetoothStarter::createListener()
+{
+    DebuggerManager *dm = DebuggerManager::instance();
+    trk::BluetoothListener *rc = new trk::BluetoothListener(dm);
+    rc->setMode(trk::BluetoothListener::Listen);
+    connect(rc, SIGNAL(message(QString)), dm, SLOT(showDebuggerOutput(QString)));
+    return rc;
+}
+
+} // namespace Internal
+} // namespace Debugger
diff --git a/src/plugins/debugger/gdb/s60debuggerbluetoothstarter.h b/src/plugins/debugger/gdb/s60debuggerbluetoothstarter.h
new file mode 100644
index 0000000000000000000000000000000000000000..216ab80a4b9ad184d9905c056266733e4ae7208d
--- /dev/null
+++ b/src/plugins/debugger/gdb/s60debuggerbluetoothstarter.h
@@ -0,0 +1,55 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef S60DEBUGGERBLUETOOTHSTARTER_H
+#define S60DEBUGGERBLUETOOTHSTARTER_H
+
+#include "bluetoothlistener.h"
+
+namespace Debugger {
+namespace Internal {
+
+/* S60DebuggerBluetoothStarter: Creates a listener in 'Listen' mode
+ * parented on the Debugger manager which outputs to the debugger window.
+ * Note: This is a "last resort" starter, normally, the run configuration
+ * should have already started a listener. */
+
+class S60DebuggerBluetoothStarter : public trk::AbstractBluetoothStarter
+{
+public:
+    explicit S60DebuggerBluetoothStarter(const TrkDevicePtr& trkDevice, QObject *parent = 0);
+
+protected:
+    virtual trk::BluetoothListener *createListener();
+};
+
+} // namespace Internal
+} // namespace Debugger
+
+#endif // S60DEBUGGERBLUETOOTHSTARTER_H
diff --git a/src/plugins/qt4projectmanager/qt-s60/qt-s60.pri b/src/plugins/qt4projectmanager/qt-s60/qt-s60.pri
index 8a445fa8de578c6b335aa91a6b92807cff03d119..c1f2e8576524b7d938321d4dd4525cf37db6d7e9 100644
--- a/src/plugins/qt4projectmanager/qt-s60/qt-s60.pri
+++ b/src/plugins/qt4projectmanager/qt-s60/qt-s60.pri
@@ -10,7 +10,9 @@
         $$PWD/s60devicerunconfiguration.cpp \
         $$PWD/s60devicerunconfigurationwidget.cpp \
         $$PWD/serialdevicelister.cpp \
-        $$PWD/rvcttoolchain.cpp
+        $$PWD/rvcttoolchain.cpp \
+        $$PWD/s60runconfigbluetoothstarter.cpp
+
     HEADERS += $$PWD/s60devices.h \
         $$PWD/s60devicespreferencepane.h \
         $$PWD/s60manager.h \
@@ -20,7 +22,9 @@
         $$PWD/s60devicerunconfiguration.h \
         $$PWD/s60devicerunconfigurationwidget.h \
         $$PWD/serialdevicelister.h \
-        $$PWD/rvcttoolchain.h
+        $$PWD/rvcttoolchain.h \
+        $$PWD/s60runconfigbluetoothstarter.h
+
     FORMS += $$PWD/s60devicespreferencepane.ui
     OTHER_FILES += $$PWD/qt-s60-todo.txt
     include(../../../shared/trk/trk.pri)||error("could not include trk.pri")
diff --git a/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.cpp b/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.cpp
index 64b1ee120cf3b19683c80b6ed44df79caccc4b74..9ab5d93b3b7047586b3659a0ac1dd4b8212c1af1 100644
--- a/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.cpp
+++ b/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfiguration.cpp
@@ -34,6 +34,8 @@
 #include "profilereader.h"
 #include "s60manager.h"
 #include "s60devices.h"
+#include "s60runconfigbluetoothstarter.h"
+#include "bluetoothlistener_gui.h"
 #include "serialdevicelister.h"
 
 #include <coreplugin/icore.h>
@@ -572,6 +574,21 @@ void S60DeviceRunControlBase::signsisProcessFinished()
     initLauncher(runFileName, m_launcher);
     emit addToOutputWindow(this, tr("Package: %1\nDeploying application to '%2'...").arg(lsFile(copySrc), m_serialPortFriendlyName));
     QString errorMessage;
+    // Prompt the user to start up the Blue tooth connection
+    if (m_communicationType == BlueToothCommunication) {
+        S60RunConfigBluetoothStarter starter(m_launcher->trkDevice());
+        switch (trk::startBluetoothGui(starter, 0, &errorMessage)) {
+        case trk::BluetoothGuiConnected:
+            break;
+        case trk::BluetoothGuiCanceled:
+        case trk::BluetoothGuiError:
+            delete m_launcher;
+            m_launcher = 0;
+            error(this, errorMessage);
+            emit finished();
+            return;
+        };
+    }
     if (!m_launcher->startServer(&errorMessage)) {
         delete m_launcher;
         m_launcher = 0;
diff --git a/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfigurationwidget.cpp b/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfigurationwidget.cpp
index c0964e6fbb9238c2b1a39bb65e781b882c09890d..71369923abd07ef06ee96130c8a293b5468b5092 100644
--- a/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfigurationwidget.cpp
+++ b/src/plugins/qt4projectmanager/qt-s60/s60devicerunconfigurationwidget.cpp
@@ -29,8 +29,12 @@
 
 #include "s60devicerunconfigurationwidget.h"
 #include "s60devicerunconfiguration.h"
+#include "s60runconfigbluetoothstarter.h"
+#include "bluetoothlistener_gui.h"
 #include "s60manager.h"
 #include "launcher.h"
+#include "bluetoothlistener.h"
+#include "bluetoothlistener_gui.h"
 #include "serialdevicelister.h"
 
 #include <utils/detailswidget.h>
@@ -278,6 +282,7 @@ void S60DeviceRunConfigurationWidget::setDeviceInfoLabel(const QString &message,
                                      QString(QLatin1String("background-color: red;")) :
                                      QString());
     m_deviceInfoLabel->setText(message);
+    m_deviceInfoLabel->adjustSize();
 }
 
 void S60DeviceRunConfigurationWidget::updateDeviceInfo()
@@ -290,12 +295,29 @@ void S60DeviceRunConfigurationWidget::updateDeviceInfo()
 
 bool S60DeviceRunConfigurationWidget::getDeviceInfo(QString *message)
 {
+    message->clear();
     // Do a launcher run with the ping protocol. Instantiate launcher on heap
     // as not to introduce delays when destructing a device with timeout
-    trk::Launcher *launcher = new trk::Launcher(trk::Launcher::ActionPingOnly, this);
+    trk::Launcher *launcher = new trk::Launcher(trk::Launcher::ActionPingOnly, QSharedPointer<trk::TrkDevice>(), this);
     const CommunicationDevice commDev = currentDevice();
     launcher->setSerialFrame(commDev.type == SerialPortCommunication);
     launcher->setTrkServerName(commDev.portName);
+    // Prompt the user to start
+    if (commDev.type == BlueToothCommunication) {
+        S60RunConfigBluetoothStarter starter(launcher->trkDevice());
+        starter.setDevice(launcher->trkServerName());
+        const trk::StartBluetoothGuiResult src = trk::startBluetoothGui(starter, this, message);
+        switch (src) {
+        case trk::BluetoothGuiConnected:
+            break;
+        case trk::BluetoothGuiCanceled:
+            launcher->deleteLater();
+            return true;
+        case trk::BluetoothGuiError:
+            launcher->deleteLater();
+            return false;
+        };
+    }
     if (!launcher->startServer(message)) {
         launcher->deleteLater();
         return false;
diff --git a/src/plugins/qt4projectmanager/qt-s60/s60runconfigbluetoothstarter.cpp b/src/plugins/qt4projectmanager/qt-s60/s60runconfigbluetoothstarter.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..305d917597d5de00feda6e2502dd2124eb1fb3b2
--- /dev/null
+++ b/src/plugins/qt4projectmanager/qt-s60/s60runconfigbluetoothstarter.cpp
@@ -0,0 +1,52 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "s60runconfigbluetoothstarter.h"
+
+#include <coreplugin/icore.h>
+#include <coreplugin/messagemanager.h>
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+S60RunConfigBluetoothStarter::S60RunConfigBluetoothStarter(const  TrkDevicePtr& trkDevice, QObject *parent) :
+    trk::AbstractBluetoothStarter(trkDevice, parent)
+{
+}
+
+trk::BluetoothListener *S60RunConfigBluetoothStarter::createListener()
+{
+    Core::ICore *core = Core::ICore::instance();
+    trk::BluetoothListener *rc = new trk::BluetoothListener(core);
+    rc->setMode(trk::BluetoothListener::Listen);
+    connect(rc, SIGNAL(message(QString)), core->messageManager(), SLOT(printToOutputPane(QString)));
+    return rc;
+}
+} // namespace Internal
+} // namespace Qt4ProjectManager
diff --git a/src/plugins/qt4projectmanager/qt-s60/s60runconfigbluetoothstarter.h b/src/plugins/qt4projectmanager/qt-s60/s60runconfigbluetoothstarter.h
new file mode 100644
index 0000000000000000000000000000000000000000..340f74082f46525b79e3c6f41adedb3da72a02ee
--- /dev/null
+++ b/src/plugins/qt4projectmanager/qt-s60/s60runconfigbluetoothstarter.h
@@ -0,0 +1,53 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef S60RUNCONFIGBLUETOOTHSTARTER_H
+#define S60RUNCONFIGBLUETOOTHSTARTER_H
+
+#include "bluetoothlistener.h"
+
+namespace Qt4ProjectManager {
+namespace Internal {
+
+/* S60RunConfigBluetoothStarter: Creates a listener in 'Listen' mode
+ * parented on the Qt Creator core which outputs to the message manager. */
+
+class S60RunConfigBluetoothStarter : public trk::AbstractBluetoothStarter
+{
+public:
+    explicit S60RunConfigBluetoothStarter(const TrkDevicePtr& trkDevice, QObject *parent = 0);
+
+protected:
+    virtual trk::BluetoothListener *createListener();
+};
+
+} // namespace Internal
+} // namespace Qt4ProjectManager
+
+#endif // S60RUNCONFIGBLUETOOTHSTARTER_H
diff --git a/src/shared/trk/bluetoothlistener.cpp b/src/shared/trk/bluetoothlistener.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..b395131ad39564e9090da62cd1dd95347b982f7c
--- /dev/null
+++ b/src/shared/trk/bluetoothlistener.cpp
@@ -0,0 +1,383 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "bluetoothlistener.h"
+#include "trkdevice.h"
+
+#include <QtCore/QDebug>
+#include <QtCore/QTimer>
+#include <QtCore/QEventLoop>
+
+#ifdef Q_OS_UNIX
+#   include <unistd.h>
+#   include <signal.h>
+#endif
+
+enum { debug = 0 };
+
+namespace trk {
+
+struct BluetoothListenerPrivate {
+    BluetoothListenerPrivate();
+    QString device;
+    QProcess process;
+    Q_PID pid;
+    bool printConsoleMessages;
+    BluetoothListener::Mode mode;
+};
+
+BluetoothListenerPrivate::BluetoothListenerPrivate() :
+    pid(0),
+    printConsoleMessages(false),
+    mode(BluetoothListener::Listen)
+{
+}
+
+BluetoothListener::BluetoothListener(QObject *parent) :
+    QObject(parent),
+    d(new BluetoothListenerPrivate)
+{
+    d->process.setProcessChannelMode(QProcess::MergedChannels);
+
+    connect(&d->process, SIGNAL(readyReadStandardError()),
+            this, SLOT(slotStdError()));
+    connect(&d->process, SIGNAL(readyReadStandardOutput()),
+            this, SLOT(slotStdOutput()));
+    connect(&d->process, SIGNAL(finished(int, QProcess::ExitStatus)),
+            this, SLOT(slotProcessFinished(int,QProcess::ExitStatus)));
+    connect(&d->process, SIGNAL(error(QProcess::ProcessError)),
+            this, SLOT(slotProcessError(QProcess::ProcessError)));
+}
+
+BluetoothListener::~BluetoothListener()
+{
+    const int trc = terminateProcess();
+    if (debug)
+        qDebug() << "~BluetoothListener: terminated" << trc;
+    delete d;
+}
+
+BluetoothListener::Mode BluetoothListener::mode() const
+{
+    return d->mode;
+}
+
+void BluetoothListener::setMode(Mode m)
+{
+    d->mode = m;
+}
+
+bool BluetoothListener::printConsoleMessages() const
+{
+    return d->printConsoleMessages;
+}
+
+void BluetoothListener::setPrintConsoleMessages(bool p)
+{
+    d->printConsoleMessages = p;
+}
+
+int BluetoothListener::terminateProcess()
+{
+    enum { TimeOutMS = 200 };
+    if (debug)
+        qDebug() << "terminateProcess" << d->process.pid() << d->process.state();
+    if (d->process.state() == QProcess::NotRunning)
+        return -1;
+    emitMessage(tr("%1: Stopping listener %2...").arg(d->device).arg(d->process.pid()));
+    // When listening, the process should terminate by itself after closing the connection
+    if (mode() == Listen && d->process.waitForFinished(TimeOutMS))
+        return 0;
+#ifdef Q_OS_UNIX
+    kill(d->process.pid(), SIGHUP); // Listens for SIGHUP
+    if (d->process.waitForFinished(TimeOutMS))
+        return 1;
+#endif
+    d->process.terminate();
+    if (d->process.waitForFinished(TimeOutMS))
+        return 2;
+    d->process.kill();
+    return 3;
+}
+
+bool BluetoothListener::start(const QString &device, QString *errorMessage)
+{
+    if (d->process.state() != QProcess::NotRunning) {
+        *errorMessage = QLatin1String("Internal error: Still running.");
+        return false;
+    }
+    d->device = device;
+    const QString binary = QLatin1String("rfcomm");
+    QStringList arguments;
+    arguments << QLatin1String("-r")
+              << (d->mode == Listen ? QLatin1String("listen") : QLatin1String("watch"))
+              << device << QString(QLatin1Char('1'));
+    if (debug)
+        qDebug() << binary << arguments;
+    emitMessage(tr("%1: Starting Bluetooth listener %2...").arg(device, binary));
+    d->pid = 0;
+    d->process.start(binary, arguments);
+    if (!d->process.waitForStarted()) {
+        *errorMessage = tr("Unable to run '%1': %2").arg(binary, d->process.errorString());
+        return false;
+    }
+    d->pid = d->process.pid(); // Forgets it after crash/termination
+    emitMessage(tr("%1: Bluetooth listener running (%2).").arg(device).arg(d->process.pid()));
+    return true;
+}
+
+void BluetoothListener::slotStdOutput()        
+{
+    emitMessage(QString::fromLocal8Bit(d->process.readAllStandardOutput()));
+}
+
+void BluetoothListener::emitMessage(const QString &m)
+{
+    if (d->printConsoleMessages || debug)
+        qDebug("%s\n", qPrintable(m));
+    emit message(m);
+}
+
+void BluetoothListener::slotStdError()
+{
+    emitMessage(QString::fromLocal8Bit(d->process.readAllStandardError()));
+}
+
+void BluetoothListener::slotProcessFinished(int ex, QProcess::ExitStatus state)
+{
+    switch (state) {
+    case QProcess::NormalExit:
+        emitMessage(tr("%1: Process %2 terminated with exit code %3.")
+                    .arg(d->device).arg(d->pid).arg(ex));
+        break;
+    case QProcess::CrashExit:
+        emitMessage(tr("%1: Process %2 crashed.").arg(d->device).arg(d->pid));
+        break;
+    }
+    emit terminated();
+}
+
+void BluetoothListener::slotProcessError(QProcess::ProcessError error)
+{
+    emitMessage(tr("%1: Process error %2: %3")
+        .arg(d->device).arg(error).arg(d->process.errorString()));
+}
+
+// --------------- AbstractBluetoothStarter
+struct AbstractBluetoothStarterPrivate {
+    explicit AbstractBluetoothStarterPrivate(const AbstractBluetoothStarter::TrkDevicePtr &d);
+
+    const AbstractBluetoothStarter::TrkDevicePtr trkDevice;
+    BluetoothListener *listener;
+    QTimer *timer;
+    int intervalMS;
+    int attempts;
+    int n;
+    QString device;    
+    QString errorString;
+    AbstractBluetoothStarter::State state;
+};
+
+AbstractBluetoothStarterPrivate::AbstractBluetoothStarterPrivate(const AbstractBluetoothStarter::TrkDevicePtr &d) :
+
+    trkDevice(d),
+    listener(0),
+    timer(0),
+    intervalMS(1000),
+    attempts(-1),
+    n(0),
+    device(QLatin1String("/dev/rfcomm0")),
+    state(AbstractBluetoothStarter::TimedOut)
+{
+}
+
+AbstractBluetoothStarter::AbstractBluetoothStarter(const TrkDevicePtr &trkDevice, QObject *parent) :
+    QObject(parent),
+    d(new AbstractBluetoothStarterPrivate(trkDevice))
+{
+}
+
+AbstractBluetoothStarter::~AbstractBluetoothStarter()
+{
+    stopTimer();
+    delete d;
+}
+
+void AbstractBluetoothStarter::stopTimer()
+{
+    if (d->timer && d->timer->isActive())
+        d->timer->stop();
+}
+
+AbstractBluetoothStarter::StartResult AbstractBluetoothStarter::start()
+{
+    if (state() == Running) {
+        d->errorString = QLatin1String("Internal error, attempt to re-start AbstractBluetoothStarter.\n");
+        return StartError;
+    }
+    // Before we instantiate timers, and such, try to open the device,
+    // which should succeed if another listener is already running in
+    // 'Watch' mode
+    if (d->trkDevice->open(d->device , &(d->errorString)))
+        return ConnectionSucceeded;
+    // Fire up the listener
+    d->n = 0;
+    d->listener = createListener();
+    if (!d->listener->start(d->device, &(d->errorString)))
+        return StartError;
+    // Start timer
+    if (!d->timer) {
+        d->timer = new QTimer;
+        connect(d->timer, SIGNAL(timeout()), this, SLOT(slotTimer()));
+    }
+    d->timer->setInterval(d->intervalMS);
+    d->timer->setSingleShot(false);
+    d->timer->start();
+    d->state = Running;
+    return Started;
+}
+
+AbstractBluetoothStarter::State AbstractBluetoothStarter::state() const
+{
+    return d->state;
+}
+
+int AbstractBluetoothStarter::intervalMS() const
+{
+    return d->intervalMS;
+}
+
+void AbstractBluetoothStarter::setIntervalMS(int i)
+{
+    d->intervalMS = i;
+    if (d->timer)
+        d->timer->setInterval(i);
+}
+
+int AbstractBluetoothStarter::attempts() const
+{
+    return d->attempts;
+}
+
+void AbstractBluetoothStarter::setAttempts(int a)
+{
+    d->attempts = a;
+}
+
+QString AbstractBluetoothStarter::device() const
+{
+    return d->device;
+}
+
+void AbstractBluetoothStarter::setDevice(const QString &dv)
+{
+    d->device = dv;
+}
+
+QString AbstractBluetoothStarter::errorString() const
+{
+    return d->errorString;
+}
+
+void AbstractBluetoothStarter::slotTimer()
+{
+    ++d->n;
+    // Check for timeout
+    if (d->attempts >= 0 && d->n >= d->attempts) {
+        stopTimer();
+        d->errorString = tr("%1: timed out after %n attempts using an interval of %2ms.", 0, d->n)
+                         .arg(d->device).arg(d->intervalMS);        
+        d->state = TimedOut;
+        emit timeout();
+    } else {
+        // Attempt n to connect?
+        if (d->trkDevice->open(d->device , &(d->errorString))) {
+            stopTimer();
+            const QString msg = tr("%1: Connection attempt %2 succeeded.").arg(d->device).arg(d->n);
+            d->listener->emitMessage(msg);
+            d->state = Connected;
+            emit connected();
+        } else {
+            const QString msg = tr("%1: Connection attempt %2 failed: %3 (retrying)...")
+                                .arg(d->device).arg(d->n).arg(d->errorString);
+            d->listener->emitMessage(msg);
+        }
+    }
+}
+
+// -------- ConsoleBluetoothStarter
+ConsoleBluetoothStarter::ConsoleBluetoothStarter(const TrkDevicePtr &trkDevice,
+                                  QObject *listenerParent,
+                                  QObject *parent) :
+    AbstractBluetoothStarter(trkDevice, parent),
+    m_listenerParent(listenerParent)
+{
+}
+
+BluetoothListener *ConsoleBluetoothStarter::createListener()
+{
+    BluetoothListener *rc = new BluetoothListener(m_listenerParent);
+    rc->setMode(BluetoothListener::Listen);
+    rc->setPrintConsoleMessages(true);
+    return rc;
+}
+
+bool ConsoleBluetoothStarter::startBluetooth(const TrkDevicePtr &trkDevice,
+                                             QObject *listenerParent,
+                                             const QString &device,
+                                             int attempts,
+                                             QString *errorMessage)
+{
+    // Set up a console starter to print to stdout.
+    ConsoleBluetoothStarter starter(trkDevice, listenerParent);
+    starter.setDevice(device);
+    starter.setAttempts(attempts);
+    switch (starter.start()) {
+    case Started:
+        break;
+    case ConnectionSucceeded:
+        return true;
+    case StartError:
+        *errorMessage = starter.errorString();
+        return false;
+    }
+    // Run the starter with an event loop. @ToDo: Implement
+    // some asynchronous keypress read to cancel.
+    QEventLoop eventLoop;
+    connect(&starter, SIGNAL(connected()), &eventLoop, SLOT(quit()));
+    connect(&starter, SIGNAL(timeout()), &eventLoop, SLOT(quit()));
+    eventLoop.exec(QEventLoop::ExcludeUserInputEvents);
+    if (starter.state() != AbstractBluetoothStarter::Connected) {
+        *errorMessage = starter.errorString();
+        return false;
+    }
+    return true;
+}
+
+} // namespace trk
diff --git a/src/shared/trk/bluetoothlistener.h b/src/shared/trk/bluetoothlistener.h
new file mode 100644
index 0000000000000000000000000000000000000000..581a32cde1a36cc8855a9bdaea4b8366a5fa0f5c
--- /dev/null
+++ b/src/shared/trk/bluetoothlistener.h
@@ -0,0 +1,174 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef BLUETOOTHLISTENER_H
+#define BLUETOOTHLISTENER_H
+
+#include <QtCore/QObject>
+#include <QtCore/QProcess>
+#include <QtCore/QSharedPointer>
+
+namespace trk {
+class TrkDevice;
+struct BluetoothListenerPrivate;
+struct AbstractBluetoothStarterPrivate;
+
+/* BluetoothListener: Starts a helper process watching connections on a
+ * Bluetooth device, Linux only:
+ * The rfcomm command is used. It process can be started in the background
+ * while connection attempts (TrkDevice::open()) are made in the foreground. */
+
+class BluetoothListener : public QObject
+{
+    Q_OBJECT
+    Q_DISABLE_COPY(BluetoothListener)
+public:
+    // The Mode property must be set before calling start().
+    enum Mode {
+        Listen, /* Terminate after client closed (read: Trk app
+                 * on the phone terminated or disconnected).*/
+        Watch   // Keep running, watch for next connection from client
+    };
+
+    explicit BluetoothListener(QObject *parent = 0);
+    virtual ~BluetoothListener();
+
+    Mode mode() const;
+    void setMode(Mode m);
+
+    bool start(const QString &device, QString *errorMessage);
+
+    // Print messages on the console.
+    bool printConsoleMessages() const;
+    void setPrintConsoleMessages(bool p);
+
+signals:
+    void terminated();
+    void message(const QString &);
+
+public slots:
+    void emitMessage(const QString &m); // accessed by starter
+
+private slots:
+    void slotStdOutput();
+    void slotStdError();
+    void slotProcessFinished(int, QProcess::ExitStatus);
+    void slotProcessError(QProcess::ProcessError error);
+
+private:
+    int terminateProcess();
+
+    BluetoothListenerPrivate *d;
+};
+
+/* AbstractBluetoothStarter: Repeatedly tries to open a trk device
+ * until a connection succeeds, allowing to do something else in the
+ * foreground (local event loop or asynchronous operation).
+ * Note that in case a Listener is already running in watch mode, it might
+ * also happen that connection succeeds immediately.
+ * Implementations must provide a factory function that creates and sets up the
+ * listener (mode, message connection, etc). */
+
+class AbstractBluetoothStarter : public QObject {
+    Q_OBJECT
+    Q_DISABLE_COPY(AbstractBluetoothStarter)
+public:
+   typedef QSharedPointer<TrkDevice> TrkDevicePtr;
+
+    enum State { Running, Connected, TimedOut };
+
+    virtual ~AbstractBluetoothStarter();
+
+    int intervalMS() const;
+    void setIntervalMS(int i);
+
+    int attempts() const;
+    void setAttempts(int a);
+
+    QString device() const;
+    void setDevice(const QString &);
+
+    State state() const;
+    QString errorString() const;
+
+    enum StartResult {
+        Started,               // Starter is now running.
+        ConnectionSucceeded,   /* Initial connection attempt succeeded,
+                                * no need to keep running. */
+        StartError             // Error occurred during start.
+    };
+
+    StartResult start();
+
+signals:
+    void connected();
+    void timeout();
+
+private slots:
+    void slotTimer();
+
+protected:
+    explicit AbstractBluetoothStarter(const TrkDevicePtr& trkDevice, QObject *parent = 0);
+    // Overwrite to create and parametrize the listener.
+    virtual BluetoothListener *createListener() = 0;
+
+private:
+    inline void stopTimer();
+
+    AbstractBluetoothStarterPrivate *d;
+};
+
+/* ConsoleBluetoothStarter: Convenience class for console processes. Creates a
+ * listener in "Listen" mode with the messages redirected to standard output. */
+
+class ConsoleBluetoothStarter : public AbstractBluetoothStarter {
+    Q_OBJECT
+    Q_DISABLE_COPY(ConsoleBluetoothStarter)
+public:
+
+    static bool startBluetooth(const TrkDevicePtr& trkDevice,
+                               QObject *listenerParent,
+                               const QString &device,
+                               int attempts,                               
+                               QString *errorMessage);
+
+protected:
+    virtual BluetoothListener *createListener();
+
+private:
+    explicit ConsoleBluetoothStarter(const TrkDevicePtr& trkDevice,
+                                      QObject *listenerParent,
+                                      QObject *parent = 0);
+
+    QObject *m_listenerParent;
+};
+
+} // namespace trk
+
+#endif // BLUETOOTHLISTENER_H
diff --git a/src/shared/trk/bluetoothlistener_gui.cpp b/src/shared/trk/bluetoothlistener_gui.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..9723a36d9d66d2c2d3dcb400edb8d66940b9aba5
--- /dev/null
+++ b/src/shared/trk/bluetoothlistener_gui.cpp
@@ -0,0 +1,74 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#include "bluetoothlistener_gui.h"
+#include "bluetoothlistener.h"
+
+#include <QtGui/QMessageBox>
+#include <QtGui/QPushButton>
+#include <QtCore/QCoreApplication>
+#include <QtCore/QDebug>
+
+namespace trk {
+
+StartBluetoothGuiResult
+    startBluetoothGui(AbstractBluetoothStarter &starter,
+                      QWidget *msgBoxParent,
+                      QString *errorMessage)
+{
+    errorMessage->clear();
+    switch (starter.start()) {
+    case AbstractBluetoothStarter::Started:
+        break;
+    case AbstractBluetoothStarter::ConnectionSucceeded:
+        return BluetoothGuiConnected;
+    case AbstractBluetoothStarter::StartError:
+        *errorMessage = starter.errorString();
+        return BluetoothGuiError;
+    }
+    // Run the starter with the event loop of a message box, close it
+    // with the finished signals.
+    const QString title = QCoreApplication::translate("trk::startBluetoothGui", "Waiting for Bluetooth Connection");
+    const QString message = QCoreApplication::translate("trk::startBluetoothGui", "Connecting to %1...").arg(starter.device());
+    QMessageBox messageBox(QMessageBox::Information, title, message, QMessageBox::Cancel, msgBoxParent);
+    QObject::connect(&starter, SIGNAL(connected()), &messageBox, SLOT(close()));
+    QObject::connect(&starter, SIGNAL(timeout()), &messageBox, SLOT(close()));
+    messageBox.exec();
+    // Only starter.state() is reliable here.
+    if (starter.state() == AbstractBluetoothStarter::Running) {
+        *errorMessage = QCoreApplication::translate("trk::startBluetoothGui", "Connection on %1 canceled.").arg(starter.device());
+        return BluetoothGuiCanceled;
+    }
+    if (starter.state() != AbstractBluetoothStarter::Connected) {
+        *errorMessage = starter.errorString();
+        return BluetoothGuiError;
+    }
+    return BluetoothGuiConnected;
+}
+} // namespace trk
diff --git a/src/shared/trk/bluetoothlistener_gui.h b/src/shared/trk/bluetoothlistener_gui.h
new file mode 100644
index 0000000000000000000000000000000000000000..2a7c57e291ae53ec7d3bdf53fcac0e4b4cb60d26
--- /dev/null
+++ b/src/shared/trk/bluetoothlistener_gui.h
@@ -0,0 +1,58 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef BLUETOOTHLISTENER_GUI_H
+#define BLUETOOTHLISTENER_GUI_H
+
+#include <QtCore/QtGlobal>
+
+QT_BEGIN_NAMESPACE
+class QWidget;
+QT_END_NAMESPACE
+
+namespace trk {
+    class AbstractBluetoothStarter;
+
+    /* startBluetoothGui(): Prompt the user to start a Bluetooth
+     * connection with a message box he can cancel. Pass in
+     * the starter with device and parameters set up.  */
+
+    enum StartBluetoothGuiResult {
+        BluetoothGuiConnected,
+        BluetoothGuiCanceled,
+        BluetoothGuiError
+    };
+
+    StartBluetoothGuiResult
+        startBluetoothGui(AbstractBluetoothStarter &starter,
+                          QWidget *msgBoxParent,
+                          QString *errorMessage);
+} // namespace trk
+
+#endif // BLUETOOTHLISTENER_GUI_H
diff --git a/src/shared/trk/launcher.cpp b/src/shared/trk/launcher.cpp
index cff53c02a1831e1492895b4138b1de53e3852056..f066ab4864fac3ff5799e4ba9aeb9ec2f0d72f0f 100644
--- a/src/shared/trk/launcher.cpp
+++ b/src/shared/trk/launcher.cpp
@@ -30,6 +30,7 @@
 #include "launcher.h"
 #include "trkutils.h"
 #include "trkdevice.h"
+#include "bluetoothlistener.h"
 
 #include <QtCore/QTimer>
 #include <QtCore/QDateTime>
@@ -50,8 +51,9 @@ struct LauncherPrivate {
         int position;
     };
 
-    LauncherPrivate();
-    TrkDevice m_device;
+    explicit LauncherPrivate(const TrkDevicePtr &d);
+
+    TrkDevicePtr m_device;
     QString m_trkServerName;
     QByteArray m_trkReadBuffer;
 
@@ -65,21 +67,28 @@ struct LauncherPrivate {
     int m_verbose;
     Launcher::Actions m_startupActions;
     bool m_connected;
+    bool m_closeDevice;
 };
 
-LauncherPrivate::LauncherPrivate() :
+LauncherPrivate::LauncherPrivate(const TrkDevicePtr &d) :
+    m_device(d),
     m_verbose(0),
-    m_connected(false)
+    m_connected(false),
+    m_closeDevice(true)
 {
+    if (m_device.isNull())
+        m_device = TrkDevicePtr(new TrkDevice);
 }
 
-Launcher::Launcher(Actions startupActions, QObject *parent) :
+Launcher::Launcher(Actions startupActions,
+                   const TrkDevicePtr &dev,
+                   QObject *parent) :
     QObject(parent),
-    d(new LauncherPrivate)
+    d(new LauncherPrivate(dev))
 {
     d->m_startupActions = startupActions;
-    connect(&d->m_device, SIGNAL(messageReceived(trk::TrkResult)), this, SLOT(handleResult(trk::TrkResult)));
-    connect(this, SIGNAL(finished()), &d->m_device, SLOT(close()));
+    connect(d->m_device.data(), SIGNAL(messageReceived(trk::TrkResult)), this, SLOT(handleResult(trk::TrkResult)));    
+    connect(this, SIGNAL(finished()), d->m_device.data(), SLOT(close()));
 }
 
 Launcher::~Launcher()
@@ -98,6 +107,16 @@ void Launcher::setTrkServerName(const QString &name)
     d->m_trkServerName = name;
 }
 
+QString Launcher::trkServerName() const
+{
+    return d->m_trkServerName;
+}
+
+TrkDevicePtr Launcher::trkDevice() const
+{
+    return d->m_device;
+}
+
 void Launcher::setFileName(const QString &name)
 {
     d->m_fileName = name;
@@ -116,16 +135,28 @@ void Launcher::setInstallFileName(const QString &name)
 
 void Launcher::setSerialFrame(bool b)
 {
-    d->m_device.setSerialFrame(b);
+    d->m_device->setSerialFrame(b);
 }
 
 bool Launcher::serialFrame() const
 {
-    return d->m_device.serialFrame();
+    return d->m_device->serialFrame();
+}
+
+
+bool Launcher::closeDevice() const
+{
+    return d->m_closeDevice;
+}
+
+void Launcher::setCloseDevice(bool c)
+{
+    d->m_closeDevice = c;
 }
 
 bool Launcher::startServer(QString *errorMessage)
 {
+    errorMessage->clear();
     if (d->m_verbose) {
         const QString msg = QString::fromLatin1("Port=%1 Executable=%2 Package=%3 Remote Package=%4 Install file=%5")
                             .arg(d->m_trkServerName, d->m_fileName, d->m_copyState.sourceFileName, d->m_copyState.destinationFileName, d->m_installFileName);
@@ -148,15 +179,21 @@ bool Launcher::startServer(QString *errorMessage)
         qWarning("No remote executable given for running.");
         return false;
     }
-    if (!d->m_device.open(d->m_trkServerName, errorMessage))
+    if (!d->m_device->isOpen() && !d->m_device->open(d->m_trkServerName, errorMessage))
         return false;
-    d->m_device.sendTrkInitialPing();
-    d->m_device.sendTrkMessage(TrkDisconnect); // Disconnect, as trk might be still connected
-    d->m_device.sendTrkMessage(TrkSupported, TrkCallback(this, &Launcher::handleSupportMask));
-    d->m_device.sendTrkMessage(TrkCpuType, TrkCallback(this, &Launcher::handleCpuType));
-    d->m_device.sendTrkMessage(TrkVersions, TrkCallback(this, &Launcher::handleTrkVersion));
+    if (d->m_closeDevice) {
+        connect(this, SIGNAL(finished()), d->m_device.data(), SLOT(close()));
+    } else {
+        disconnect(this, SIGNAL(finished()), d->m_device.data(), 0);
+    }
+
+    d->m_device->sendTrkInitialPing();
+    d->m_device->sendTrkMessage(TrkDisconnect); // Disconnect, as trk might be still connected
+    d->m_device->sendTrkMessage(TrkSupported, TrkCallback(this, &Launcher::handleSupportMask));
+    d->m_device->sendTrkMessage(TrkCpuType, TrkCallback(this, &Launcher::handleCpuType));
+    d->m_device->sendTrkMessage(TrkVersions, TrkCallback(this, &Launcher::handleTrkVersion));
     if (d->m_startupActions != ActionPingOnly)
-        d->m_device.sendTrkMessage(TrkConnect, TrkCallback(this, &Launcher::handleConnect));
+        d->m_device->sendTrkMessage(TrkConnect, TrkCallback(this, &Launcher::handleConnect));
     return true;
 }
 
@@ -178,7 +215,7 @@ void Launcher::handleConnect(const TrkResult &result)
 void Launcher::setVerbose(int v)
 {
     d->m_verbose = v;
-    d->m_device.setVerbose(v);
+    d->m_device->setVerbose(v);
 }
 
 void Launcher::logMessage(const QString &msg)
@@ -193,7 +230,7 @@ void Launcher::terminate()
         QByteArray ba;
         appendShort(&ba, 0x0000, TargetByteOrder);
         appendInt(&ba, d->m_session.pid, TargetByteOrder);
-        d->m_device.sendTrkMessage(TrkDeleteItem, TrkCallback(this, &Launcher::handleRemoteProcessKilled), ba);
+        d->m_device->sendTrkMessage(TrkDeleteItem, TrkCallback(this, &Launcher::handleRemoteProcessKilled), ba);
     } else if (d->m_connected) {
         if (d->m_copyState.copyFileHandle)
             closeRemoteFile(true);
@@ -235,17 +272,17 @@ void Launcher::handleResult(const TrkResult &result)
 //            uint pid = extractInt(data + 4); // ProcessID: 4 bytes;
 //            uint tid = extractInt(data + 8); // ThreadID: 4 bytes
             //logMessage(prefix << "      ADDR: " << addr << " PID: " << pid << " TID: " << tid);
-            d->m_device.sendTrkAck(result.token);
+            d->m_device->sendTrkAck(result.token);
             break;
         }
         case TrkNotifyException: { // Notify Exception (obsolete)
             logMessage(prefix + "NOTE: EXCEPTION  " + str);
-            d->m_device.sendTrkAck(result.token);
+            d->m_device->sendTrkAck(result.token);
             break;
         }
         case TrkNotifyInternalError: { //
             logMessage(prefix + "NOTE: INTERNAL ERROR: " + str);
-            d->m_device.sendTrkAck(result.token);
+            d->m_device->sendTrkAck(result.token);
             break;
         }
 
@@ -278,8 +315,8 @@ void Launcher::handleResult(const TrkResult &result)
                 break;
             QByteArray ba;
             ba.append(result.data.mid(2, 8));
-            d->m_device.sendTrkMessage(TrkContinue, TrkCallback(), ba, "CONTINUE");
-            //d->m_device.sendTrkAck(result.token)
+            d->m_device->sendTrkMessage(TrkContinue, TrkCallback(), ba, "CONTINUE");
+            //d->m_device->sendTrkAck(result.token)
             break;
         }
         case TrkNotifyDeleted: { // NotifyDeleted
@@ -289,7 +326,7 @@ void Launcher::handleResult(const TrkResult &result)
             logMessage(QString::fromLatin1("%1 %2 UNLOAD: %3").
                        arg(QString::fromAscii(prefix)).arg(itemType ? QLatin1String("LIB") : QLatin1String("PROCESS")).
                        arg(name));
-            d->m_device.sendTrkAck(result.token);
+            d->m_device->sendTrkAck(result.token);
             if (itemType == 0 // process
                 && result.data.size() >= 10
                 && d->m_session.pid == extractInt(result.data.data() + 6)) {
@@ -299,17 +336,17 @@ void Launcher::handleResult(const TrkResult &result)
         }
         case TrkNotifyProcessorStarted: { // NotifyProcessorStarted
             logMessage(prefix + "NOTE: PROCESSOR STARTED: " + str);
-            d->m_device.sendTrkAck(result.token);
+            d->m_device->sendTrkAck(result.token);
             break;
         }
         case TrkNotifyProcessorStandBy: { // NotifyProcessorStandby
             logMessage(prefix + "NOTE: PROCESSOR STANDBY: " + str);
-            d->m_device.sendTrkAck(result.token);
+            d->m_device->sendTrkAck(result.token);
             break;
         }
         case TrkNotifyProcessorReset: { // NotifyProcessorReset
             logMessage(prefix + "NOTE: PROCESSOR RESET: " + str);
-            d->m_device.sendTrkAck(result.token);
+            d->m_device->sendTrkAck(result.token);
             break;
         }
         default: {
@@ -384,7 +421,7 @@ void Launcher::continueCopying(uint lastCopiedBlockSize)
         QByteArray ba;
         appendInt(&ba, d->m_copyState.copyFileHandle, TargetByteOrder);
         appendString(&ba, d->m_copyState.data->mid(d->m_copyState.position, 2048), TargetByteOrder, false);
-        d->m_device.sendTrkMessage(TrkWriteFile, TrkCallback(this, &Launcher::handleCopy), ba);
+        d->m_device->sendTrkMessage(TrkWriteFile, TrkCallback(this, &Launcher::handleCopy), ba);
     } else {
         closeRemoteFile();
     }
@@ -395,7 +432,7 @@ void Launcher::closeRemoteFile(bool failed)
     QByteArray ba;
     appendInt(&ba, d->m_copyState.copyFileHandle, TargetByteOrder);
     appendInt(&ba, QDateTime::currentDateTime().toTime_t(), TargetByteOrder);
-    d->m_device.sendTrkMessage(TrkCloseFile,
+    d->m_device->sendTrkMessage(TrkCloseFile,
                                failed ? TrkCallback() : TrkCallback(this, &Launcher::handleFileCopied),
                                ba);
     d->m_copyState.data.reset();
@@ -458,7 +495,7 @@ void Launcher::handleCreateProcess(const TrkResult &result)
     QByteArray ba;
     appendInt(&ba, d->m_session.pid);
     appendInt(&ba, d->m_session.tid);
-    d->m_device.sendTrkMessage(TrkContinue, TrkCallback(), ba, "CONTINUE");
+    d->m_device->sendTrkMessage(TrkContinue, TrkCallback(), ba, "CONTINUE");
 }
 
 void Launcher::handleWaitForFinished(const TrkResult &result)
@@ -496,7 +533,7 @@ void Launcher::cleanUp()
     appendByte(&ba, 0x00);
     appendByte(&ba, 0x00);
     appendInt(&ba, d->m_session.pid);
-    d->m_device.sendTrkMessage(TrkDeleteItem, TrkCallback(), ba, "Delete process");
+    d->m_device->sendTrkMessage(TrkDeleteItem, TrkCallback(), ba, "Delete process");
 
     //---TRK------------------------------------------------------
     //  Command: 0x80 Acknowledge
@@ -540,7 +577,7 @@ void Launcher::cleanUp()
 
 void Launcher::disconnectTrk()
 {
-    d->m_device.sendTrkMessage(TrkDisconnect, TrkCallback(this, &Launcher::handleWaitForFinished));
+    d->m_device->sendTrkMessage(TrkDisconnect, TrkCallback(this, &Launcher::handleWaitForFinished));
 }
 
 void Launcher::copyFileToRemote()
@@ -549,7 +586,7 @@ void Launcher::copyFileToRemote()
     QByteArray ba;
     appendByte(&ba, 0x10);
     appendString(&ba, d->m_copyState.destinationFileName.toLocal8Bit(), TargetByteOrder, false);
-    d->m_device.sendTrkMessage(TrkOpenFile, TrkCallback(this, &Launcher::handleFileCreation), ba);
+    d->m_device->sendTrkMessage(TrkOpenFile, TrkCallback(this, &Launcher::handleFileCreation), ba);
 }
 
 void Launcher::installRemotePackageSilently()
@@ -558,7 +595,7 @@ void Launcher::installRemotePackageSilently()
     QByteArray ba;
     appendByte(&ba, 'C');
     appendString(&ba, d->m_installFileName.toLocal8Bit(), TargetByteOrder, false);
-    d->m_device.sendTrkMessage(TrkInstallFile, TrkCallback(this, &Launcher::handleInstallPackageFinished), ba);
+    d->m_device->sendTrkMessage(TrkInstallFile, TrkCallback(this, &Launcher::handleInstallPackageFinished), ba);
 }
 
 void Launcher::handleInstallPackageFinished(const TrkResult &result)
@@ -586,7 +623,6 @@ void Launcher::startInferiorIfNeeded()
     appendByte(&ba, 0); // create new process
     appendByte(&ba, 0); // ?
     appendString(&ba, d->m_fileName.toLocal8Bit(), TargetByteOrder);
-    d->m_device.sendTrkMessage(TrkCreateItem, TrkCallback(this, &Launcher::handleCreateProcess), ba); // Create Item
-}
-
+    d->m_device->sendTrkMessage(TrkCreateItem, TrkCallback(this, &Launcher::handleCreateProcess), ba); // Create Item
 }
+} // namespace trk
diff --git a/src/shared/trk/launcher.h b/src/shared/trk/launcher.h
index 93f5d52923e6baeed1ba53090ede3f058329bbe5..2c4881de6d19caec8896647a1210d3758697eb25 100644
--- a/src/shared/trk/launcher.h
+++ b/src/shared/trk/launcher.h
@@ -29,8 +29,11 @@
 #ifndef LAUNCHER_H
 #define LAUNCHER_H
 
+#include "trkdevice.h"
+
 #include <QtCore/QObject>
 #include <QtCore/QVariant>
+#include <QtCore/QSharedPointer>
 
 namespace trk {
 
@@ -38,9 +41,12 @@ struct TrkResult;
 struct TrkMessage;
 struct LauncherPrivate;
 
+typedef QSharedPointer<TrkDevice> TrkDevicePtr;
+
 class Launcher : public QObject
 {
     Q_OBJECT
+    Q_DISABLE_COPY(Launcher)
 public:
     typedef void (Launcher::*TrkCallBack)(const TrkResult &);
 
@@ -56,10 +62,12 @@ public:
     };
 
     explicit Launcher(trk::Launcher::Actions startupActions = trk::Launcher::ActionPingOnly,
+                      const TrkDevicePtr &trkDevice = TrkDevicePtr(),
                       QObject *parent = 0);
     ~Launcher();
     void addStartupActions(trk::Launcher::Actions startupActions);
     void setTrkServerName(const QString &name);
+    QString trkServerName() const;
     void setFileName(const QString &name);
     void setCopyFileName(const QString &srcName, const QString &dstName);
     void setInstallFileName(const QString &name);
@@ -67,6 +75,11 @@ public:
     void setVerbose(int v);    
     void setSerialFrame(bool b);
     bool serialFrame() const;
+    // Close device or leave it open
+    bool closeDevice() const;
+    void setCloseDevice(bool c);
+
+    TrkDevicePtr trkDevice() const;
 
     // becomes valid after successful execution of ActionPingOnly
     QString deviceDescription(unsigned verbose = 0u) const;
diff --git a/src/shared/trk/trk.pri b/src/shared/trk/trk.pri
index 1564e4684dd08eecb3f319fc875838c45fbc7951..8965948f19488557d04a268d871e66bb65e22760 100644
--- a/src/shared/trk/trk.pri
+++ b/src/shared/trk/trk.pri
@@ -1,13 +1,20 @@
 INCLUDEPATH *= $$PWD
 
 # Input
-HEADERS += \
-    $$PWD/callback.h \
+HEADERS += $$PWD/callback.h \
     $$PWD/trkutils.h \
     $$PWD/trkdevice.h \
-    $$PWD/launcher.h
+    $$PWD/launcher.h \
+    $$PWD/bluetoothlistener.h
 
-SOURCES += \
-    $$PWD/trkutils.cpp \
+SOURCES += $$PWD/trkutils.cpp \
     $$PWD/trkdevice.cpp \
-    $$PWD/launcher.cpp
+    $$PWD/launcher.cpp \
+    $$PWD/bluetoothlistener.cpp
+
+contains(QT, gui) {
+   HEADERS += $$PWD/bluetoothlistener_gui.h
+    SOURCES += $$PWD/bluetoothlistener_gui.cpp
+} else {
+    message(Trk: Console ...)
+}
diff --git a/tests/manual/trklauncher/main.cpp b/tests/manual/trklauncher/main.cpp
index 65031e7cc5aab100945db92aa3708553f0f11a6f..e9847d33b8fb9a3a1dd4f7125ae257403573af27 100644
--- a/tests/manual/trklauncher/main.cpp
+++ b/tests/manual/trklauncher/main.cpp
@@ -1,13 +1,19 @@
 #include "launcher.h"
+#include "bluetoothlistener.h"
 
 #include <QtCore/QCoreApplication>
+#include <QtCore/QSharedPointer>
 #include <QtCore/QDebug>
 #include <QtCore/QStringList>
 
 static const char *usageC =
-"\nUsage: %1 <trk_port_name> [-v] [-i remote_sis_file | -I local_sis_file remote_sis_file] [<remote_executable_name>]\n"
+"\n"
+"Usage: %1 [options] <trk_port_name>\n"
+"       %1 [options] -i <trk_port_name> remote_sis_file\n"
+"       %1 [options] -I local_sis_file remote_sis_file] [<remote_executable_name>]\n"
 "\nOptions:\n    -v verbose\n"
-            "    -f turn serial message frame off\n\n"
+            "    -b Prompt for Bluetooth connect (Linux only)\n"
+            "    -f turn serial message frame off (Bluetooth)\n"
 "\nPing:\n"
 "%1 COM5\n"
 "\nRemote launch:\n"
@@ -27,74 +33,94 @@ static void usage()
     qWarning("%s", qPrintable(msg));
 }
 
-static bool parseArguments(const QStringList &arguments, trk::Launcher &launcher)
+typedef QSharedPointer<trk::Launcher> TrkLauncherPtr;
+
+// Parse arguments, return pointer or a null none.
+
+static inline TrkLauncherPtr createLauncher(trk::Launcher::Actions actions,
+                                            const QString &serverName,
+                                            bool serialFrame,
+                                            int verbosity)
+{
+    TrkLauncherPtr launcher(new trk::Launcher(actions));
+    launcher->setTrkServerName(serverName);
+    launcher->setSerialFrame(serialFrame);
+    launcher->setVerbose(verbosity);
+    return launcher;
+}
+
+static TrkLauncherPtr parseArguments(const QStringList &arguments, bool *bluetooth)
 {
     // Parse away options
     bool install = false;
     bool customInstall = false;
+    bool serialFrame = true;
     const int argCount = arguments.size();
     int verbosity = 0;
+    *bluetooth = false;
+    trk::Launcher::Actions actions = trk::Launcher::ActionPingOnly;
     int a = 1;
     for ( ; a < argCount; a++) {
         const QString option = arguments.at(a);
         if (!option.startsWith(QLatin1Char('-')))
             break;
         if (option.size() != 2)
-            return  false;
+            return TrkLauncherPtr();        
         switch (option.at(1).toAscii()) {
         case 'v':
             verbosity++;
             break;
         case 'f':
-            launcher.setSerialFrame(false);
-            break;verbosity++;
+            serialFrame = false;
+            break;
+        case 'b':
+            *bluetooth = true;
+            break;
         case 'i':
             install = true;
-            launcher.addStartupActions(trk::Launcher::ActionInstall);
+            actions = trk::Launcher::ActionInstall;
             break;
         case 'I':
             customInstall = true;
-            launcher.addStartupActions(trk::Launcher::ActionCopyInstall);
+            actions = trk::Launcher::ActionCopyInstall;
             break;
         default:
-            return false;
+            return TrkLauncherPtr();
         }
     }
-
-    launcher.setVerbose(verbosity);
     // Evaluate arguments
     const int remainingArgsCount = argCount - a;
-    if (remainingArgsCount == 1 && !install && !customInstall) {
-        launcher.setTrkServerName(arguments.at(a)); // ping
-        return true;
+    if (remainingArgsCount == 1 && !install && !customInstall) { // Ping
+        return createLauncher(actions, arguments.at(a), serialFrame, verbosity);
     }
     if (remainingArgsCount == 2 && !install && !customInstall) {
         // remote exec
-        launcher.addStartupActions(trk::Launcher::ActionRun);
-        launcher.setTrkServerName(arguments.at(a));
-        launcher.setFileName(arguments.at(a + 1));
-        return true;
+        TrkLauncherPtr launcher = createLauncher(actions, arguments.at(a), serialFrame, verbosity);
+        launcher->addStartupActions(trk::Launcher::ActionRun);
+        launcher->setFileName(arguments.at(a + 1));
+        return launcher;
     }
     if ((remainingArgsCount == 3 || remainingArgsCount == 2) && install && !customInstall) {
-        launcher.setTrkServerName(arguments.at(a)); // ping
-        launcher.setInstallFileName(arguments.at(a + 1));
+        TrkLauncherPtr launcher = createLauncher(actions, arguments.at(a), serialFrame, verbosity);
+        launcher->setInstallFileName(arguments.at(a + 1));
         if (remainingArgsCount == 3) {
-            launcher.addStartupActions(trk::Launcher::ActionRun);
-            launcher.setFileName(arguments.at(a + 2));
+            launcher->addStartupActions(trk::Launcher::ActionRun);
+            launcher->setFileName(arguments.at(a + 2));
         }
-        return true;
+        return launcher;
     }
     if ((remainingArgsCount == 4 || remainingArgsCount == 3) && !install && customInstall) {
-        launcher.setTrkServerName(arguments.at(a)); // ping
-        launcher.setCopyFileName(arguments.at(a + 1), arguments.at(a + 2));
-        launcher.setInstallFileName(arguments.at(a + 2));
+        TrkLauncherPtr launcher = createLauncher(actions, arguments.at(a), serialFrame, verbosity);
+        launcher->setTrkServerName(arguments.at(a)); // ping
+        launcher->setCopyFileName(arguments.at(a + 1), arguments.at(a + 2));
+        launcher->setInstallFileName(arguments.at(a + 2));
         if (remainingArgsCount == 4) {
-            launcher.addStartupActions(trk::Launcher::ActionRun);
-            launcher.setFileName(arguments.at(a + 3));
+            launcher->addStartupActions(trk::Launcher::ActionRun);
+            launcher->setFileName(arguments.at(a + 3));
         }
-        return true;
+        return launcher;
     }
-    return false;
+    return TrkLauncherPtr();
 }
 
 int main(int argc, char *argv[])
@@ -103,14 +129,23 @@ int main(int argc, char *argv[])
     QCoreApplication::setApplicationName(QLatin1String("trklauncher"));
     QCoreApplication::setOrganizationName(QLatin1String("Nokia"));
 
-    trk::Launcher launcher;
-    if (!parseArguments(app.arguments(), launcher)) {
+    bool bluetooth;
+    const TrkLauncherPtr launcher = parseArguments(app.arguments(), &bluetooth);
+    if (launcher.isNull()) {
         usage();
         return 1;
     }
-    QObject::connect(&launcher, SIGNAL(finished()), &app, SLOT(quit()));
+    QObject::connect(launcher.data(), SIGNAL(finished()), &app, SLOT(quit()));
+    // BLuetooth: Open with prompt
     QString errorMessage;
-    if (launcher.startServer(&errorMessage))
+    if (bluetooth && !trk::ConsoleBluetoothStarter::startBluetooth(launcher->trkDevice(),
+                                                     launcher.data(),
+                                                     launcher->trkServerName(),
+                                                     30, &errorMessage)) {
+        qWarning("%s\n", qPrintable(errorMessage));
+        return -1;
+    }
+    if (launcher->startServer(&errorMessage))
         return app.exec();
     qWarning("%s\n", qPrintable(errorMessage));
     return 4;
diff --git a/tests/manual/trklauncher/trklauncher.pro b/tests/manual/trklauncher/trklauncher.pro
index 73e7f7d781886070b57e033459941b25c4d234a3..943afde4ada2fde33c17e08c97ff4dedb55d095e 100644
--- a/tests/manual/trklauncher/trklauncher.pro
+++ b/tests/manual/trklauncher/trklauncher.pro
@@ -1,5 +1,5 @@
 TEMPLATE = app
 QT = core
+CONFIG += console
 include(../../../src/shared/trk/trk.pri)
-win32:CONFIG += console
 SOURCES += main.cpp