diff --git a/src/plugins/remotelinux/genericlinuxdeviceconfigurationfactory.cpp b/src/plugins/remotelinux/genericlinuxdeviceconfigurationfactory.cpp
index afb8be699d2c3c286b2118b0b3fab18fcc065aa8..334cb4db94edd238a567693c0c2e083634c61921 100644
--- a/src/plugins/remotelinux/genericlinuxdeviceconfigurationfactory.cpp
+++ b/src/plugins/remotelinux/genericlinuxdeviceconfigurationfactory.cpp
@@ -32,19 +32,15 @@
 #include "genericlinuxdeviceconfigurationfactory.h"
 
 #include "genericlinuxdeviceconfigurationwizard.h"
-#include "maemoconfigtestdialog.h"
+#include "linuxdevicetestdialog.h"
 #include "maemoremoteprocessesdialog.h"
 #include "publickeydeploymentdialog.h"
+#include "remotelinux_constants.h"
 
 #include <utils/qtcassert.h>
 
 namespace RemoteLinux {
 namespace Internal {
-namespace {
-const char * const TestDeviceActionId = "TestDeviceAction";
-const char * const DeployKeyToDeviceActionId = "DeployKeyToDeviceAction";
-const char * const RemoteProcessesActionId = "RemoteProcessesAction";
-} // anonymous namespace;
 
 GenericLinuxDeviceConfigurationFactory::GenericLinuxDeviceConfigurationFactory(QObject *parent)
     : ILinuxDeviceConfigurationFactory(parent)
@@ -74,18 +70,20 @@ QString GenericLinuxDeviceConfigurationFactory::displayNameForOsType(const QStri
 
 QStringList GenericLinuxDeviceConfigurationFactory::supportedDeviceActionIds() const
 {
-    return QStringList() << QLatin1String(TestDeviceActionId)
-        << QLatin1String(DeployKeyToDeviceActionId) << QLatin1String(RemoteProcessesActionId);
+    return QStringList() << QLatin1String(Constants::GenericTestDeviceActionId)
+        << QLatin1String(Constants::GenericDeployKeyToDeviceActionId)
+        << QLatin1String(Constants::GenericRemoteProcessesActionId);
 }
 
 QString GenericLinuxDeviceConfigurationFactory::displayNameForActionId(const QString &actionId) const
 {
     Q_ASSERT(supportedDeviceActionIds().contains(actionId));
-    if (actionId == QLatin1String(TestDeviceActionId))
+
+    if (actionId == QLatin1String(Constants::GenericTestDeviceActionId))
         return tr("Test");
-    if (actionId == QLatin1String(RemoteProcessesActionId))
+    if (actionId == QLatin1String(Constants::GenericRemoteProcessesActionId))
         return tr("Remote Processes");
-    if (actionId == QLatin1String(DeployKeyToDeviceActionId))
+    if (actionId == QLatin1String(Constants::GenericDeployKeyToDeviceActionId))
         return tr("Deploy Public Key");
     return QString(); // Can't happen.
 }
@@ -94,11 +92,14 @@ QDialog *GenericLinuxDeviceConfigurationFactory::createDeviceAction(const QStrin
     const LinuxDeviceConfiguration::ConstPtr &deviceConfig, QWidget *parent) const
 {
     Q_ASSERT(supportedDeviceActionIds().contains(actionId));
-    if (actionId == QLatin1String(TestDeviceActionId))
-        return new MaemoConfigTestDialog(deviceConfig, parent);
-    if (actionId == QLatin1String(RemoteProcessesActionId))
+
+    if (actionId == QLatin1String(Constants::GenericTestDeviceActionId)) {
+        return new LinuxDeviceTestDialog(deviceConfig, new GenericLinuxDeviceTester(parent),
+            parent);
+    }
+    if (actionId == QLatin1String(Constants::GenericRemoteProcessesActionId))
         return new MaemoRemoteProcessesDialog(deviceConfig, parent);
-    if (actionId == QLatin1String(DeployKeyToDeviceActionId))
+    if (actionId == QLatin1String(Constants::GenericDeployKeyToDeviceActionId))
         return new PublicKeyDeploymentDialog(deviceConfig, parent);
     return 0; // Can't happen.
 }
diff --git a/src/plugins/remotelinux/genericlinuxdeviceconfigurationwizard.cpp b/src/plugins/remotelinux/genericlinuxdeviceconfigurationwizard.cpp
index 74111352fdfe56f71b0409b4647e57f137fba452..ef16abe69b624ec9978dedad184de49054d782c1 100644
--- a/src/plugins/remotelinux/genericlinuxdeviceconfigurationwizard.cpp
+++ b/src/plugins/remotelinux/genericlinuxdeviceconfigurationwizard.cpp
@@ -31,7 +31,8 @@
 #include "genericlinuxdeviceconfigurationwizard.h"
 
 #include "genericlinuxdeviceconfigurationwizardpages.h"
-#include "maemoconfigtestdialog.h"
+#include "linuxdevicetestdialog.h"
+#include "linuxdevicetester.h"
 
 using namespace Utils;
 
@@ -84,7 +85,7 @@ LinuxDeviceConfiguration::Ptr GenericLinuxDeviceConfigurationWizard::deviceConfi
     LinuxDeviceConfiguration::Ptr devConf = LinuxDeviceConfiguration::create(m_d->setupPage.configurationName(),
         LinuxDeviceConfiguration::GenericLinuxOsType, LinuxDeviceConfiguration::Physical,
         PortList::fromString(QLatin1String("10000-10100")), sshParams);
-    Internal::MaemoConfigTestDialog dlg(devConf, this);
+    LinuxDeviceTestDialog dlg(devConf, new GenericLinuxDeviceTester(this), this);
     dlg.exec();
     return devConf;
 }
diff --git a/src/plugins/remotelinux/linuxdevicetestdialog.cpp b/src/plugins/remotelinux/linuxdevicetestdialog.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..2639a9ce7e590d9d11f83742c6975da86e2e9be8
--- /dev/null
+++ b/src/plugins/remotelinux/linuxdevicetestdialog.cpp
@@ -0,0 +1,92 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at info@qt.nokia.com.
+**
+**************************************************************************/
+#include "linuxdevicetestdialog.h"
+#include "ui_linuxdevicetestdialog.h"
+
+#include <QtGui/QPushButton>
+
+namespace RemoteLinux {
+
+LinuxDeviceTestDialog::LinuxDeviceTestDialog(const QSharedPointer<const LinuxDeviceConfiguration> &deviceConfiguration,
+        AbstractLinuxDeviceTester *deviceTester, QWidget *parent)
+    : QDialog(parent),
+      m_ui(new Ui::LinuxDeviceTestDialog),
+      m_deviceTester(deviceTester),
+      m_finished(false)
+{
+    m_ui->setupUi(this);
+
+    connect(m_deviceTester, SIGNAL(progressMessage(QString)), SLOT(handleProgressMessage(QString)));
+    connect(m_deviceTester, SIGNAL(errorMessage(QString)), SLOT(handleErrorMessage(QString)));
+    connect(m_deviceTester, SIGNAL(finished(RemoteLinux::AbstractLinuxDeviceTester::TestResult)),
+        SLOT(handleTestFinished(RemoteLinux::AbstractLinuxDeviceTester::TestResult)));
+    m_deviceTester->testDevice(deviceConfiguration);
+}
+
+LinuxDeviceTestDialog::~LinuxDeviceTestDialog()
+{
+    delete m_ui;
+}
+
+void LinuxDeviceTestDialog::reject()
+{
+    if (!m_finished)
+        m_deviceTester->stopTest();
+    QDialog::reject();
+}
+
+void LinuxDeviceTestDialog::handleProgressMessage(const QString &message)
+{
+    m_ui->textEdit->appendPlainText(message);
+}
+
+void LinuxDeviceTestDialog::handleErrorMessage(const QString &message)
+{
+    m_ui->textEdit->appendHtml(QLatin1String("<font color=\"red\">") + message
+        + QLatin1String("</font><p/><p/>"));
+}
+
+void LinuxDeviceTestDialog::handleTestFinished(AbstractLinuxDeviceTester::TestResult result)
+{
+    m_finished = true;
+    m_ui->buttonBox->button(QDialogButtonBox::Cancel)->setText(tr("Close"));
+
+    if (result == AbstractLinuxDeviceTester::TestSuccess) {
+        m_ui->textEdit->appendHtml(QLatin1String("<b><font color=\"blue\">")
+            + tr("Device test finished successfully.") + QLatin1String("</font></b>"));
+    } else {
+        m_ui->textEdit->appendHtml(QLatin1String("<b><font color=\"red\">")
+            + tr("Device test failed.") + QLatin1String("</font></b><p/>"));
+    }
+}
+
+} // namespace RemoteLinux
diff --git a/src/plugins/remotelinux/linuxdevicetestdialog.h b/src/plugins/remotelinux/linuxdevicetestdialog.h
new file mode 100644
index 0000000000000000000000000000000000000000..e14814a9eeb9aab930c7c98abded3a1c29d0a3f2
--- /dev/null
+++ b/src/plugins/remotelinux/linuxdevicetestdialog.h
@@ -0,0 +1,71 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at info@qt.nokia.com.
+**
+**************************************************************************/
+#ifndef DEFAULTDEVICETESTDIALOG_H
+#define DEFAULTDEVICETESTDIALOG_H
+
+#include "linuxdevicetester.h"
+#include "remotelinux_export.h"
+
+#include <QtGui/QDialog>
+
+QT_BEGIN_NAMESPACE
+namespace Ui {
+class LinuxDeviceTestDialog;
+}
+QT_END_NAMESPACE
+
+namespace RemoteLinux {
+
+class REMOTELINUX_EXPORT LinuxDeviceTestDialog : public QDialog
+{
+    Q_OBJECT
+public:
+    explicit LinuxDeviceTestDialog(const QSharedPointer<const LinuxDeviceConfiguration> &deviceConfiguration,
+        AbstractLinuxDeviceTester * deviceTester, QWidget *parent = 0);
+    ~LinuxDeviceTestDialog();
+
+    void reject();
+
+private slots:
+    void handleProgressMessage(const QString &message);
+    void handleErrorMessage(const QString &message);
+    void handleTestFinished(RemoteLinux::AbstractLinuxDeviceTester::TestResult result);
+
+private:
+    Ui::LinuxDeviceTestDialog * const m_ui;
+    AbstractLinuxDeviceTester * const m_deviceTester;
+    bool m_finished;
+};
+
+} // namespace RemoteLinux
+
+#endif // DEFAULTDEVICETESTDIALOG_H
diff --git a/src/plugins/remotelinux/linuxdevicetestdialog.ui b/src/plugins/remotelinux/linuxdevicetestdialog.ui
new file mode 100644
index 0000000000000000000000000000000000000000..2bde24ad0901fdecea707a4608019282c06e48b4
--- /dev/null
+++ b/src/plugins/remotelinux/linuxdevicetestdialog.ui
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>LinuxDeviceTestDialog</class>
+ <widget class="QDialog" name="LinuxDeviceTestDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>607</width>
+    <height>580</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Device Test</string>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <widget class="QPlainTextEdit" name="textEdit">
+     <property name="readOnly">
+      <bool>true</bool>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="QDialogButtonBox" name="buttonBox">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="standardButtons">
+      <set>QDialogButtonBox::Cancel</set>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources/>
+ <connections>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>accepted()</signal>
+   <receiver>LinuxDeviceTestDialog</receiver>
+   <slot>accept()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>248</x>
+     <y>254</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>157</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+  <connection>
+   <sender>buttonBox</sender>
+   <signal>rejected()</signal>
+   <receiver>LinuxDeviceTestDialog</receiver>
+   <slot>reject()</slot>
+   <hints>
+    <hint type="sourcelabel">
+     <x>316</x>
+     <y>260</y>
+    </hint>
+    <hint type="destinationlabel">
+     <x>286</x>
+     <y>274</y>
+    </hint>
+   </hints>
+  </connection>
+ </connections>
+</ui>
diff --git a/src/plugins/remotelinux/linuxdevicetester.cpp b/src/plugins/remotelinux/linuxdevicetester.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..3c0c6c98a27b960dd61362157bb9fbc900d3fc67
--- /dev/null
+++ b/src/plugins/remotelinux/linuxdevicetester.cpp
@@ -0,0 +1,220 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at info@qt.nokia.com.
+**
+**************************************************************************/
+#include "linuxdevicetester.h"
+
+#include "linuxdeviceconfiguration.h"
+#include "maemousedportsgatherer.h"
+
+#include <utils/qtcassert.h>
+#include <utils/ssh/sshremoteprocess.h>
+#include <utils/ssh/sshconnection.h>
+
+using namespace Utils;
+
+namespace RemoteLinux {
+namespace Internal {
+namespace {
+
+enum State { Inactive, Connecting, RunningUname, TestingPorts };
+
+} // anonymous namespace
+
+class GenericLinuxDeviceTesterPrivate
+{
+public:
+    GenericLinuxDeviceTesterPrivate() : state(Inactive) {}
+
+    LinuxDeviceConfiguration::ConstPtr deviceConfiguration;
+    SshConnection::Ptr connection;
+    SshRemoteProcess::Ptr process;
+    MaemoUsedPortsGatherer portsGatherer;
+    QByteArray remoteStdout;
+    QByteArray remoteStderr;
+    State state;
+};
+
+} // namespace Internal
+
+using namespace Internal;
+
+AbstractLinuxDeviceTester::AbstractLinuxDeviceTester(QObject *parent) : QObject(parent)
+{
+}
+
+
+GenericLinuxDeviceTester::GenericLinuxDeviceTester(QObject *parent)
+    : AbstractLinuxDeviceTester(parent), m_d(new GenericLinuxDeviceTesterPrivate)
+{
+}
+
+GenericLinuxDeviceTester::~GenericLinuxDeviceTester()
+{
+    delete m_d;
+}
+
+void GenericLinuxDeviceTester::testDevice(const LinuxDeviceConfiguration::ConstPtr &deviceConfiguration)
+{
+    QTC_ASSERT(m_d->state == Inactive, return);
+
+    m_d->deviceConfiguration = deviceConfiguration;
+    m_d->connection = SshConnection::create(deviceConfiguration->sshParameters());
+    connect(m_d->connection.data(), SIGNAL(connected()), SLOT(handleConnected()));
+    connect(m_d->connection.data(), SIGNAL(error(Utils::SshError)),
+        SLOT(handleConnectionFailure()));
+
+    emit progressMessage(tr("Connecting to host..."));
+    m_d->state = Connecting;
+    m_d->connection->connectToHost();
+}
+
+void GenericLinuxDeviceTester::stopTest()
+{
+    QTC_ASSERT(m_d->state != Inactive, return);
+
+    switch (m_d->state) {
+    case Connecting:
+        m_d->connection->disconnectFromHost();
+        break;
+    case TestingPorts:
+        m_d->portsGatherer.stop();
+        break;
+    case RunningUname:
+        m_d->process->closeChannel();
+        break;
+    case Inactive:
+        break;
+    }
+
+    setFinished(TestFailure);
+}
+
+SshConnection::Ptr GenericLinuxDeviceTester::connection() const
+{
+    return m_d->connection;
+}
+
+void GenericLinuxDeviceTester::handleConnected()
+{
+    QTC_ASSERT(m_d->state == Connecting, return);
+
+    m_d->process = m_d->connection->createRemoteProcess("uname -rsm");
+    connect(m_d->process.data(), SIGNAL(outputAvailable(QByteArray)),
+        SLOT(handleRemoteStdOut(QByteArray)));
+    connect(m_d->process.data(), SIGNAL(errorOutputAvailable(QByteArray)),
+        SLOT(handleRemoteStdErr(QByteArray)));
+    connect(m_d->process.data(), SIGNAL(closed(int)), SLOT(handleProcessFinished(int)));
+
+    emit progressMessage("Checking kernel version...");
+    m_d->state = RunningUname;
+    m_d->process->start();
+}
+
+void GenericLinuxDeviceTester::handleConnectionFailure()
+{
+    QTC_ASSERT(m_d->state != Inactive, return);
+
+    emit errorMessage(tr("SSH connection failure: %1").arg(m_d->connection->errorString()));
+    setFinished(TestFailure);
+}
+
+void GenericLinuxDeviceTester::handleRemoteStdOut(const QByteArray &data)
+{
+    QTC_ASSERT(m_d->state == RunningUname, return);
+
+    m_d->remoteStdout += data;
+}
+
+void GenericLinuxDeviceTester::handleRemoteStdErr(const QByteArray &data)
+{
+    QTC_ASSERT(m_d->state == RunningUname, return);
+
+    m_d->remoteStderr += data;
+}
+
+void GenericLinuxDeviceTester::handleProcessFinished(int exitStatus)
+{
+    QTC_ASSERT(m_d->state == RunningUname, return);
+
+    if (exitStatus != SshRemoteProcess::ExitedNormally || m_d->process->exitCode() != 0) {
+        if (!m_d->remoteStderr.isEmpty())
+            emit errorMessage(tr("uname failed: %1").arg(QString::fromUtf8(m_d->remoteStderr)));
+        else
+            emit errorMessage(tr("uname failed."));
+    } else {
+        emit progressMessage(QString::fromUtf8(m_d->remoteStdout));
+    }
+
+    connect(&m_d->portsGatherer, SIGNAL(error(QString)), SLOT(handlePortsGatheringError(QString)));
+    connect(&m_d->portsGatherer, SIGNAL(portListReady()), SLOT(handlePortListReady()));
+
+    emit progressMessage(QLatin1String("")
+        + tr("Checking if specified ports are available..."));
+    m_d->state = TestingPorts;
+    m_d->portsGatherer.start(m_d->connection, m_d->deviceConfiguration);
+}
+
+void GenericLinuxDeviceTester::handlePortsGatheringError(const QString &message)
+{
+    QTC_ASSERT(m_d->state == TestingPorts, return);
+
+    emit errorMessage(tr("Error gathering ports: %1").arg(message));
+    setFinished(TestFailure);
+}
+
+void GenericLinuxDeviceTester::handlePortListReady()
+{
+    QTC_ASSERT(m_d->state == TestingPorts, return);
+
+    if (m_d->portsGatherer.usedPorts().isEmpty()) {
+        emit progressMessage("All specified ports are available.\n");
+    } else {
+        QString portList;
+        foreach (const int port, m_d->portsGatherer.usedPorts())
+            portList += QString::number(port) + QLatin1String(", ");
+        portList.remove(portList.count() - 2, 2);
+        emit errorMessage(tr("The following specified ports are currently in use: %1")
+            .arg(portList));
+    }
+    setFinished(TestSuccess);
+}
+
+void GenericLinuxDeviceTester::setFinished(TestResult result)
+{
+    m_d->state = Inactive;
+    m_d->remoteStdout.clear();
+    m_d->remoteStderr.clear();
+    disconnect(m_d->connection.data(), 0, this, 0);
+    disconnect(&m_d->portsGatherer, 0, this, 0);
+    emit finished(result);
+}
+
+} // namespace RemoteLinux
diff --git a/src/plugins/remotelinux/linuxdevicetester.h b/src/plugins/remotelinux/linuxdevicetester.h
new file mode 100644
index 0000000000000000000000000000000000000000..45b0f66c656953b8e0f1832cfa2f778858580a8c
--- /dev/null
+++ b/src/plugins/remotelinux/linuxdevicetester.h
@@ -0,0 +1,102 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at info@qt.nokia.com.
+**
+**************************************************************************/
+#ifndef LINUXDEVICETESTER_H
+#define LINUXDEVICETESTER_H
+
+#include "remotelinux_export.h"
+
+#include <QtCore/QObject>
+#include <QtCore/QSharedPointer>
+
+QT_FORWARD_DECLARE_CLASS(QString)
+
+namespace Utils {
+class SshConnection;
+}
+
+namespace RemoteLinux {
+class LinuxDeviceConfiguration;
+
+namespace Internal {
+class GenericLinuxDeviceTesterPrivate;
+} // namespace Internal
+
+class REMOTELINUX_EXPORT AbstractLinuxDeviceTester : public QObject
+{
+    Q_OBJECT
+    Q_DISABLE_COPY(AbstractLinuxDeviceTester)
+public:
+    enum TestResult { TestSuccess, TestFailure };
+
+    virtual void testDevice(const QSharedPointer<const LinuxDeviceConfiguration> &deviceConfiguration)=0;
+    virtual void stopTest()=0;
+
+signals:
+    void progressMessage(const QString &message);
+    void errorMessage(const QString &message);
+    void finished(RemoteLinux::AbstractLinuxDeviceTester::TestResult result);
+
+protected:
+    explicit AbstractLinuxDeviceTester(QObject *parent = 0);
+};
+
+
+class REMOTELINUX_EXPORT GenericLinuxDeviceTester : public AbstractLinuxDeviceTester
+{
+    Q_OBJECT
+public:
+    explicit GenericLinuxDeviceTester(QObject *parent = 0);
+    ~GenericLinuxDeviceTester();
+
+    void testDevice(const QSharedPointer<const LinuxDeviceConfiguration> &deviceConfiguration);
+    void stopTest();
+
+    QSharedPointer<Utils::SshConnection> connection() const;
+
+private slots:
+    void handleConnected();
+    void handleConnectionFailure();
+    void handleRemoteStdOut(const QByteArray &data);
+    void handleRemoteStdErr(const QByteArray &data);
+    void handleProcessFinished(int exitStatus);
+    void handlePortsGatheringError(const QString &message);
+    void handlePortListReady();
+
+private:
+    void setFinished(TestResult result);
+
+    Internal::GenericLinuxDeviceTesterPrivate * const m_d;
+};
+
+} // namespace RemoteLinux
+
+#endif // LINUXDEVICETESTER_H
diff --git a/src/plugins/remotelinux/maddedeviceconfigurationfactory.cpp b/src/plugins/remotelinux/maddedeviceconfigurationfactory.cpp
index 9f47ad8a389e9bbd607c466a89d15f0023e016d8..245e34f3831fed686f7cf93f5fefe6545b4c870f 100644
--- a/src/plugins/remotelinux/maddedeviceconfigurationfactory.cpp
+++ b/src/plugins/remotelinux/maddedeviceconfigurationfactory.cpp
@@ -31,15 +31,23 @@
 **************************************************************************/
 #include "maddedeviceconfigurationfactory.h"
 
+#include "maddedevicetester.h"
 #include "maemodeviceconfigwizard.h"
+#include "maemoremoteprocessesdialog.h"
+#include "publickeydeploymentdialog.h"
 
+#include <remotelinux/linuxdevicetestdialog.h>
+#include <remotelinux/remotelinux_constants.h>
 #include <utils/qtcassert.h>
 
 namespace RemoteLinux {
 namespace Internal {
+namespace {
+const char MaddeDeviceTestActionId[] = "Madde.DeviceTestAction";
+} // anonymous namespace
 
 MaddeDeviceConfigurationFactory::MaddeDeviceConfigurationFactory(QObject *parent)
-    : GenericLinuxDeviceConfigurationFactory(parent)
+    : ILinuxDeviceConfigurationFactory(parent)
 {
 }
 
@@ -70,5 +78,39 @@ QString MaddeDeviceConfigurationFactory::displayNameForOsType(const QString &osT
     return tr("Other MeeGo OS");
 }
 
+QStringList MaddeDeviceConfigurationFactory::supportedDeviceActionIds() const
+{
+    return QStringList() << QLatin1String(MaddeDeviceTestActionId)
+        << QLatin1String(Constants::GenericDeployKeyToDeviceActionId)
+        << QLatin1String(Constants::GenericRemoteProcessesActionId);
+}
+
+QString MaddeDeviceConfigurationFactory::displayNameForActionId(const QString &actionId) const
+{
+    Q_ASSERT(supportedDeviceActionIds().contains(actionId));
+
+    if (actionId == QLatin1String(MaddeDeviceTestActionId))
+        return tr("Test");
+    if (actionId == QLatin1String(Constants::GenericRemoteProcessesActionId))
+        return tr("Remote Processes");
+    if (actionId == QLatin1String(Constants::GenericDeployKeyToDeviceActionId))
+        return tr("Deploy Public Key");
+    return QString(); // Can't happen.
+}
+
+QDialog *MaddeDeviceConfigurationFactory::createDeviceAction(const QString &actionId,
+    const LinuxDeviceConfiguration::ConstPtr &deviceConfig, QWidget *parent) const
+{
+    Q_ASSERT(supportedDeviceActionIds().contains(actionId));
+
+    if (actionId == QLatin1String(MaddeDeviceTestActionId))
+        return new LinuxDeviceTestDialog(deviceConfig, new MaddeDeviceTester(parent), parent);
+    if (actionId == QLatin1String(Constants::GenericRemoteProcessesActionId))
+        return new MaemoRemoteProcessesDialog(deviceConfig, parent);
+    if (actionId == QLatin1String(Constants::GenericDeployKeyToDeviceActionId))
+        return new PublicKeyDeploymentDialog(deviceConfig, parent);
+    return 0; // Can't happen.
+}
+
 } // namespace Internal
 } // namespace RemoteLinux
diff --git a/src/plugins/remotelinux/maddedeviceconfigurationfactory.h b/src/plugins/remotelinux/maddedeviceconfigurationfactory.h
index 59cadcebfafa2d31bf603fbd6519cfa46b732b94..aa531f2c02bbb98404cdcde7f9394b8ff206f9b5 100644
--- a/src/plugins/remotelinux/maddedeviceconfigurationfactory.h
+++ b/src/plugins/remotelinux/maddedeviceconfigurationfactory.h
@@ -32,12 +32,12 @@
 #ifndef MADDEDEVICECONFIGURATIONFACTORY_H
 #define MADDEDEVICECONFIGURATIONFACTORY_H
 
-#include "genericlinuxdeviceconfigurationfactory.h"
+#include <remotelinux/linuxdeviceconfiguration.h>
 
 namespace RemoteLinux {
 namespace Internal {
 
-class MaddeDeviceConfigurationFactory : public GenericLinuxDeviceConfigurationFactory
+class MaddeDeviceConfigurationFactory : public RemoteLinux::ILinuxDeviceConfigurationFactory
 {
     Q_OBJECT
 public:
@@ -47,6 +47,10 @@ public:
     ILinuxDeviceConfigurationWizard *createWizard(QWidget *parent) const;
     bool supportsOsType(const QString &osType) const;
     QString displayNameForOsType(const QString &osType) const;
+    QStringList supportedDeviceActionIds() const;
+    QString displayNameForActionId(const QString &actionId) const;
+    QDialog *createDeviceAction(const QString &actionId,
+        const LinuxDeviceConfiguration::ConstPtr &deviceConfig, QWidget *parent) const;
 };
 
 } // namespace Internal
diff --git a/src/plugins/remotelinux/maddedevicetester.cpp b/src/plugins/remotelinux/maddedevicetester.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..937fa18550a6bcffdcdd15adb1bfc26e1e64b577
--- /dev/null
+++ b/src/plugins/remotelinux/maddedevicetester.cpp
@@ -0,0 +1,289 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at info@qt.nokia.com.
+**
+**************************************************************************/
+#include "maddedevicetester.h"
+
+#include "maemoglobal.h"
+
+#include <remotelinux/linuxdeviceconfiguration.h>
+#include <utils/qtcassert.h>
+#include <utils/ssh/sshremoteprocessrunner.h>
+
+#include <QtCore/QRegExp>
+
+using namespace Utils;
+
+namespace RemoteLinux {
+namespace Internal {
+namespace {
+const char QmlToolingDirectory[] = "/usr/lib/qt4/plugins/qmltooling";
+} // anonymous namespace
+
+MaddeDeviceTester::MaddeDeviceTester(QObject *parent)
+    : AbstractLinuxDeviceTester(parent),
+      m_genericTester(new GenericLinuxDeviceTester(this)),
+      m_state(Inactive)
+{
+}
+
+MaddeDeviceTester::~MaddeDeviceTester()
+{
+}
+
+void MaddeDeviceTester::testDevice(const LinuxDeviceConfiguration::ConstPtr &deviceConfiguration)
+{
+    QTC_ASSERT(m_state == Inactive, return);
+
+    m_deviceConfiguration = deviceConfiguration;
+    m_result = TestSuccess;
+
+    m_state = GenericTest;
+    connect(m_genericTester, SIGNAL(progressMessage(QString)), SIGNAL(progressMessage(QString)));
+    connect(m_genericTester, SIGNAL(errorMessage(QString)), SIGNAL(errorMessage(QString)));
+    connect(m_genericTester, SIGNAL(finished(RemoteLinux::AbstractLinuxDeviceTester::TestResult)),
+        SLOT(handleGenericTestFinished(RemoteLinux::AbstractLinuxDeviceTester::TestResult)));
+    m_genericTester->testDevice(deviceConfiguration);
+}
+
+void MaddeDeviceTester::stopTest()
+{
+    QTC_ASSERT(m_state != Inactive, return);
+
+    switch (m_state) {
+    case Inactive:
+        break;
+    case GenericTest:
+        m_genericTester->stopTest();
+        break;
+    case QtTest:
+    case MadDeveloperTest:
+    case QmlToolingTest:
+        m_processRunner->process()->closeChannel();
+        break;
+    }
+
+    m_result = TestFailure;
+    setFinished();
+}
+
+void MaddeDeviceTester::handleGenericTestFinished(TestResult result)
+{
+    QTC_ASSERT(m_state == GenericTest, return);
+
+    if (result == TestFailure) {
+        m_result = TestFailure;
+        setFinished();
+        return;
+    }
+
+    m_processRunner = SshRemoteProcessRunner::create(m_genericTester->connection());
+    connect(m_processRunner.data(), SIGNAL(connectionError(Utils::SshError)),
+        SLOT(handleConnectionError()));
+    connect(m_processRunner.data(), SIGNAL(processOutputAvailable(QByteArray)),
+        SLOT(handleStdout(QByteArray)));
+    connect(m_processRunner.data(), SIGNAL(processErrorOutputAvailable(QByteArray)),
+        SLOT(handleStderr(QByteArray)));
+    connect(m_processRunner.data(), SIGNAL(processClosed(int)), SLOT(handleProcessFinished(int)));
+
+    QString qtInfoCmd;
+    if (m_deviceConfiguration->osType() == LinuxDeviceConfiguration::MeeGoOsType) {
+        qtInfoCmd = QLatin1String("rpm -qa 'libqt*' --queryformat '%{NAME} %{VERSION}\\n'");
+    } else {
+        qtInfoCmd = QLatin1String("dpkg-query -W -f "
+            "'${Package} ${Version} ${Status}\n' 'libqt*' |grep ' installed$'");
+    }
+
+    emit progressMessage(tr("Checking for Qt libraries..."));
+    m_stdout.clear();
+    m_stderr.clear();
+    m_state = QtTest;
+    m_processRunner->run(qtInfoCmd.toUtf8());
+}
+
+void MaddeDeviceTester::handleConnectionError()
+{
+    QTC_ASSERT(m_state != Inactive, return);
+
+    emit errorMessage(tr("SSH connection error: %1")
+        .arg(m_processRunner->connection()->errorString()));
+    m_result = TestFailure;
+    setFinished();
+}
+
+void MaddeDeviceTester::handleStdout(const QByteArray &data)
+{
+    QTC_ASSERT(m_state == QtTest || m_state == MadDeveloperTest || m_state == QmlToolingTest,
+        return);
+
+    m_stdout += data;
+}
+
+void MaddeDeviceTester::handleStderr(const QByteArray &data)
+{
+    QTC_ASSERT(m_state == QtTest || m_state == MadDeveloperTest || m_state == QmlToolingTest,
+        return);
+
+    m_stderr += data;
+}
+
+void MaddeDeviceTester::handleProcessFinished(int exitStatus)
+{
+    switch (m_state) {
+    case QtTest:
+        handleQtTestFinished(exitStatus);
+        break;
+    case MadDeveloperTest:
+        handleMadDeveloperTestFinished(exitStatus);
+        break;
+    case QmlToolingTest:
+        handleQmlToolingTestFinished(exitStatus);
+        break;
+    default:
+        qWarning("%s: Unexpected state %d.", Q_FUNC_INFO, m_state);
+    }
+}
+
+void MaddeDeviceTester::handleQtTestFinished(int exitStatus)
+{
+    if (exitStatus != SshRemoteProcess::ExitedNormally
+            || m_processRunner->process()->exitCode() != 0) {
+        if (!m_stderr.isEmpty()) {
+            emit errorMessage(tr("Error checking for Qt libraries: %1")
+                .arg(QString::fromUtf8(m_stderr)));
+        } else {
+            emit errorMessage(tr("Error checking for Qt libraries."));
+        }
+
+        m_result = TestFailure;
+    } else {
+        emit progressMessage(processedQtLibsList());
+    }
+
+    m_stdout.clear();
+    m_stderr.clear();
+
+    emit progressMessage(QLatin1Char('\n') + tr("Checking for connectivity support..."));
+    m_state = MadDeveloperTest;
+    m_processRunner->run(QString(QLatin1String("test -x") + MaemoGlobal::devrootshPath()).toUtf8());
+}
+
+void MaddeDeviceTester::handleMadDeveloperTestFinished(int exitStatus)
+{
+    if (exitStatus != SshRemoteProcess::ExitedNormally) {
+        if (!m_stderr.isEmpty()) {
+            emit errorMessage(tr("Error checking for connectivity tool: %1")
+                .arg(QString::fromUtf8(m_stderr)));
+        } else {
+            emit errorMessage(tr("Error checking for connectivity tool."));
+        }
+        m_result = TestFailure;
+    } else if (m_processRunner->process()->exitCode() != 0) {
+        QString message = tr("Connectivity tool not installed on device. "
+            "Deployment will not be possible.");
+        if (m_deviceConfiguration->osType() == LinuxDeviceConfiguration::HarmattanOsType) {
+            message += tr("Please switch the device to developer mode "
+                "via Settings -> Security.\n");
+        }
+        emit errorMessage(message);
+        m_result = TestFailure;
+    } else {
+        emit progressMessage(tr("Connectivity tool present.\n"));
+    }
+
+    if (m_deviceConfiguration->osType() != LinuxDeviceConfiguration::HarmattanOsType) {
+        setFinished();
+        return;
+    }
+
+    m_stdout.clear();
+    m_stderr.clear();
+
+    emit progressMessage(tr("Checking for QML tooling support..."));
+    m_state = QmlToolingTest;
+    m_processRunner->run(QString(QLatin1String("test -d ")
+        + QLatin1String(QmlToolingDirectory)).toUtf8());
+}
+
+void MaddeDeviceTester::handleQmlToolingTestFinished(int exitStatus)
+{
+    if (exitStatus != SshRemoteProcess::ExitedNormally) {
+        if (!m_stderr.isEmpty()) {
+            emit errorMessage(tr("Error checking for QML tooling support: %1")
+                .arg(QString::fromUtf8(m_stderr)));
+        } else {
+            emit errorMessage(tr("Error checking for QML tooling support."));
+        }
+        m_result = TestFailure;
+    } else if (m_processRunner->process()->exitCode() != 0) {
+        emit errorMessage(tr("Missing directory '%1'. You will not be able to do "
+            "QML debugging on this device.").arg(QmlToolingDirectory));
+        m_result = TestFailure;
+    } else {
+        emit progressMessage(tr("QML tooling support present.\n"));
+    }
+
+    setFinished();
+}
+
+QString MaddeDeviceTester::processedQtLibsList()
+{
+    QString unfilteredLibs = QString::fromUtf8(m_stdout);
+    QString filteredLibs;
+    QString patternString;
+    if (m_deviceConfiguration->osType() == LinuxDeviceConfiguration::MeeGoOsType)
+        patternString = QLatin1String("(libqt\\S+) ((\\d+)\\.(\\d+)\\.(\\d+))");
+    else
+        patternString = QLatin1String("(\\S+) (\\S*(\\d+)\\.(\\d+)\\.(\\d+)\\S*) \\S+ \\S+ \\S+");
+    const QRegExp packagePattern(patternString);
+    int index = packagePattern.indexIn(unfilteredLibs);
+    if (index == -1)
+        return tr("No Qt packages installed.");
+
+    do {
+        filteredLibs += QLatin1String("    ") + packagePattern.cap(1) + QLatin1String(": ")
+            + packagePattern.cap(2) + QLatin1Char('\n');
+        index = packagePattern.indexIn(unfilteredLibs, index + packagePattern.cap(0).length());
+    } while (index != -1);
+    return filteredLibs;
+}
+
+ void MaddeDeviceTester::setFinished()
+{
+    m_state = Inactive;
+    disconnect(m_genericTester, 0, this, 0);
+    if (m_processRunner)
+        disconnect(m_processRunner.data(), 0, this, 0);
+    m_processRunner.clear();
+    emit finished(m_result);
+}
+
+} // namespace Internal
+} // namespace RemoteLinux
diff --git a/src/plugins/remotelinux/maddedevicetester.h b/src/plugins/remotelinux/maddedevicetester.h
new file mode 100644
index 0000000000000000000000000000000000000000..5a14c4c235177355aaae9fe9807374e73c65304f
--- /dev/null
+++ b/src/plugins/remotelinux/maddedevicetester.h
@@ -0,0 +1,85 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (info@qt.nokia.com)
+**
+**
+** GNU Lesser General Public License Usage
+**
+** 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.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** Other Usage
+**
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at info@qt.nokia.com.
+**
+**************************************************************************/
+#ifndef MADDEDEVICETESTER_H
+#define MADDEDEVICETESTER_H
+
+#include <remotelinux/linuxdevicetester.h>
+
+#include <QtCore/QByteArray>
+
+namespace Utils {
+class SshRemoteProcessRunner;
+}
+
+namespace RemoteLinux {
+namespace Internal {
+
+class MaddeDeviceTester : public RemoteLinux::AbstractLinuxDeviceTester
+{
+    Q_OBJECT
+public:
+    explicit MaddeDeviceTester(QObject *parent);
+    ~MaddeDeviceTester();
+
+    void testDevice(const QSharedPointer<const LinuxDeviceConfiguration> &deviceConfiguration);
+    void stopTest();
+
+private slots:
+    void handleGenericTestFinished(RemoteLinux::AbstractLinuxDeviceTester::TestResult result);
+    void handleConnectionError();
+    void handleStdout(const QByteArray &data);
+    void handleStderr(const QByteArray &data);
+    void handleProcessFinished(int exitStatus);
+
+private:
+    enum State { Inactive, GenericTest, QtTest, MadDeveloperTest, QmlToolingTest };
+
+    void handleQtTestFinished(int exitStatus);
+    void handleMadDeveloperTestFinished(int exitStatus);
+    void handleQmlToolingTestFinished(int exitStatus);
+
+    QString processedQtLibsList();
+    void setFinished();
+
+    RemoteLinux::GenericLinuxDeviceTester * const m_genericTester;
+    State m_state;
+    TestResult m_result;
+    QSharedPointer<Utils::SshRemoteProcessRunner> m_processRunner;
+    QSharedPointer<const LinuxDeviceConfiguration> m_deviceConfiguration;
+    QByteArray m_stdout;
+    QByteArray m_stderr;
+};
+
+} // namespace Internal
+} // namespace RemoteLinux
+
+#endif // MADDEDEVICETESTER_H
diff --git a/src/plugins/remotelinux/maemoconfigtestdialog.cpp b/src/plugins/remotelinux/maemoconfigtestdialog.cpp
deleted file mode 100644
index c13cc4405bed935cbbffa88fe0d71acc03d0f00a..0000000000000000000000000000000000000000
--- a/src/plugins/remotelinux/maemoconfigtestdialog.cpp
+++ /dev/null
@@ -1,333 +0,0 @@
-/**************************************************************************
-**
-** This file is part of Qt Creator
-**
-** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
-**
-** Contact: Nokia Corporation (info@qt.nokia.com)
-**
-** GNU Lesser General Public License Usage
-**
-** 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.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** Other Usage
-**
-** Alternatively, this file may be used in accordance with the terms and
-** conditions contained in a signed written agreement between you and Nokia.
-**
-** If you have questions regarding the use of this file, please contact
-** Nokia at info@qt.nokia.com.
-**
-**************************************************************************/
-
-#include "maemoconfigtestdialog.h"
-#include "ui_maemoconfigtestdialog.h"
-
-#include "linuxdeviceconfiguration.h"
-#include "maemoglobal.h"
-#include "maemousedportsgatherer.h"
-
-#include <utils/ssh/sshremoteprocessrunner.h>
-
-#include <QtGui/QPalette>
-#include <QtGui/QPushButton>
-
-using namespace Utils;
-
-namespace RemoteLinux {
-namespace Internal {
-namespace {
-const char QmlToolingDirectory[] = "/usr/lib/qt4/plugins/qmltooling";
-} // anonymous namespace
-
-MaemoConfigTestDialog::MaemoConfigTestDialog(const LinuxDeviceConfiguration::ConstPtr &config,
-        QWidget *parent)
-    : QDialog(parent)
-    , m_ui(new Ui_MaemoConfigTestDialog)
-    , m_config(config)
-    , m_portsGatherer(new MaemoUsedPortsGatherer(this))
-{
-    m_ui->setupUi(this);
-    m_closeButton = m_ui->buttonBox->button(QDialogButtonBox::Close);
-
-    connect(m_closeButton, SIGNAL(clicked()), SLOT(stopConfigTest()));
-    connect(m_portsGatherer, SIGNAL(error(QString)),
-        SLOT(handlePortListFailure(QString)));
-    connect(m_portsGatherer, SIGNAL(portListReady()),
-        SLOT(handlePortListReady()));
-
-    startConfigTest();
-}
-
-MaemoConfigTestDialog::~MaemoConfigTestDialog()
-{
-    stopConfigTest();
-}
-
-void MaemoConfigTestDialog::startConfigTest()
-{
-    if (m_testProcessRunner)
-        return;
-
-    m_currentTest = GeneralTest;
-    const QString testingText = m_config->type() == LinuxDeviceConfiguration::Emulator
-        ? tr("Testing configuration. This may take a while.")
-        : tr("Testing configuration...");
-    m_ui->testResultEdit->setPlainText(testingText);
-    m_closeButton->setText(tr("Stop Test"));
-
-    // We need to explicitly create the connection here, because the other
-    // constructor uses a managed connection, i.e. it might re-use an
-    // existing one, which we explicitly don't want here.
-    m_testProcessRunner = SshRemoteProcessRunner::create(SshConnection::create(m_config->sshParameters()));
-
-    connect(m_testProcessRunner.data(), SIGNAL(connectionError(Utils::SshError)),
-        this, SLOT(handleConnectionError()));
-    connect(m_testProcessRunner.data(), SIGNAL(processClosed(int)), this,
-        SLOT(handleTestProcessFinished(int)));
-    connect(m_testProcessRunner.data(),
-        SIGNAL(processOutputAvailable(QByteArray)), this,
-        SLOT(processSshOutput(QByteArray)));
-    const QLatin1String sysInfoCmd("uname -rsm");
-    QString command = sysInfoCmd;
-    QString qtInfoCmd;
-    switch (MaemoGlobal::packagingSystem(m_config->osType())) {
-    case MaemoGlobal::Rpm:
-        qtInfoCmd = QLatin1String("rpm -qa 'libqt*' "
-            "--queryformat '%{NAME} %{VERSION}\\n'");
-        break;
-    case MaemoGlobal::Dpkg:
-        qtInfoCmd = QLatin1String("dpkg-query -W -f "
-            "'${Package} ${Version} ${Status}\n' 'libqt*' |grep ' installed$'");
-        break;
-    default:
-        break;
-    }
-    if (!qtInfoCmd.isEmpty())
-        command += QLatin1String(" && ") + qtInfoCmd;
-    m_testProcessRunner->run(command.toUtf8());
-}
-
-void MaemoConfigTestDialog::handleConnectionError()
-{
-    if (!m_testProcessRunner)
-        return;
-    QString output = tr("Could not connect to host: %1")
-        .arg(m_testProcessRunner->connection()->errorString());
-    if (m_config->type() == LinuxDeviceConfiguration::Emulator)
-        output += tr("\nDid you start Qemu?");
-    m_ui->testResultEdit->setPlainText(output);
-    stopConfigTest();
-}
-
-void MaemoConfigTestDialog::handleTestProcessFinished(int exitStatus)
-{
-    if (!m_testProcessRunner)
-        return;
-
-    Q_ASSERT(exitStatus == SshRemoteProcess::FailedToStart
-        || exitStatus == SshRemoteProcess::KilledBySignal
-        || exitStatus == SshRemoteProcess::ExitedNormally);
-
-    switch (m_currentTest) {
-    case GeneralTest:
-        handleGeneralTestResult(exitStatus);
-        break;
-    case MadDeveloperTest:
-        handleMadDeveloperTestResult(exitStatus);
-        break;
-    case QmlToolingTest:
-        handleQmlToolingTestResult(exitStatus);
-        break;
-    default:
-        qDebug("%s: Unexpected test state %d.", Q_FUNC_INFO, m_currentTest);
-    }
-}
-
-void MaemoConfigTestDialog::handleGeneralTestResult(int exitStatus)
-{
-    if (exitStatus != SshRemoteProcess::ExitedNormally
-        || m_testProcessRunner->process()->exitCode() != 0) {
-        m_ui->testResultEdit->setPlainText(tr("Remote process failed: %1")
-            .arg(m_testProcessRunner->process()->errorString()));
-   } else {
-        const QString &output = parseTestOutput();
-        if (!m_qtVersionOk) {
-            m_ui->errorLabel->setText(tr("Qt version mismatch! "
-                " Expected Qt on device: 4.6.2 or later."));
-        }
-        m_ui->testResultEdit->setPlainText(output);
-    }
-
-    if (m_config->osType() == LinuxDeviceConfiguration::Maemo5OsType
-            || m_config->osType() == LinuxDeviceConfiguration::HarmattanOsType
-            || m_config->osType() == LinuxDeviceConfiguration::MeeGoOsType) {
-        m_currentTest = MadDeveloperTest;
-        disconnect(m_testProcessRunner.data(),
-            SIGNAL(processOutputAvailable(QByteArray)), this,
-            SLOT(processSshOutput(QByteArray)));
-        m_testProcessRunner->run("test -x "
-            + MaemoGlobal::devrootshPath().toUtf8());
-    } else {
-        testPorts();
-    }
-}
-
-void MaemoConfigTestDialog::handleMadDeveloperTestResult(int exitStatus)
-{
-    if (exitStatus != SshRemoteProcess::ExitedNormally) {
-        m_ui->testResultEdit->setPlainText(tr("Remote process failed: %1")
-            .arg(m_testProcessRunner->process()->errorString()));
-    } else if (m_testProcessRunner->process()->exitCode() != 0) {
-        QString errorMsg = m_ui->errorLabel->text() + QLatin1String("<br>")
-            + tr("%1 is not installed.<br>You will not be able to deploy "
-                 "to this device.")
-                .arg(MaemoGlobal::madDeveloperUiName(m_config->osType()));
-        if (m_config->osType() == LinuxDeviceConfiguration::HarmattanOsType) {
-            errorMsg += QLatin1String("<br>")
-                + tr("Please switch the device to developer mode via Settings -> Security.");
-        }
-        m_ui->errorLabel->setText(errorMsg);
-    }
-
-    if (m_config->osType() == LinuxDeviceConfiguration::HarmattanOsType) {
-        m_currentTest = QmlToolingTest;
-        m_testProcessRunner->run(QByteArray("test -d ") + QmlToolingDirectory);
-    } else {
-        testPorts();
-    }
-}
-
-void MaemoConfigTestDialog::handleQmlToolingTestResult(int exitStatus)
-{
-    if (exitStatus != SshRemoteProcess::ExitedNormally) {
-        m_ui->testResultEdit->setPlainText(tr("Remote process failed: %1")
-            .arg(m_testProcessRunner->process()->errorString()));
-    } else if (m_testProcessRunner->process()->exitCode() != 0) {
-        QString errorMsg = m_ui->errorLabel->text() + QLatin1String("<br>")
-            + tr("Missing directory '%1'. You will not be able to do QML debugging on this device.")
-                .arg(QmlToolingDirectory);
-        m_ui->errorLabel->setText(errorMsg);
-    }
-
-    testPorts();
-}
-
-void MaemoConfigTestDialog::handlePortListFailure(const QString &errMsg)
-{
-    m_ui->testResultEdit->appendPlainText(tr("Error retrieving list of used ports: %1")
-        .arg(errMsg));
-    finish();
-}
-
-void MaemoConfigTestDialog::handlePortListReady()
-{
-    const QList<int> &usedPorts = m_portsGatherer->usedPorts();
-    QString output;
-    if (usedPorts.isEmpty()) {
-        output = tr("All specified ports are available.");
-    } else {
-        output = tr("The following supposedly free ports are being used on the device:");
-        foreach (const int port, usedPorts)
-            output += QLatin1Char(' ') + QString::number(port);
-    }
-    m_ui->testResultEdit->appendPlainText(output);
-    finish();
-}
-
-void MaemoConfigTestDialog::testPorts()
-{
-    if (m_config->freePorts().hasMore())
-        m_portsGatherer->start(m_testProcessRunner->connection(), m_config);
-    else
-        finish();
-}
-
-void MaemoConfigTestDialog::finish()
-{
-    if (m_ui->errorLabel->text().isEmpty()) {
-        QPalette palette = m_ui->errorLabel->palette();
-        palette.setColor(m_ui->errorLabel->foregroundRole(),
-            QColor(QLatin1String("blue")));
-        m_ui->errorLabel->setPalette(palette);
-        m_ui->errorLabel->setText(tr("Device configuration okay."));
-    }
-    stopConfigTest();
-}
-
-void MaemoConfigTestDialog::stopConfigTest()
-{
-    if (m_testProcessRunner) {
-        disconnect(m_testProcessRunner.data(), 0, this, 0);
-        m_testProcessRunner = SshRemoteProcessRunner::Ptr();
-    }
-    m_deviceTestOutput.clear();
-    m_closeButton->setText(tr("Close"));
-}
-
-void MaemoConfigTestDialog::processSshOutput(const QByteArray &output)
-{
-    m_deviceTestOutput.append(QString::fromUtf8(output));
-}
-
-QString MaemoConfigTestDialog::parseTestOutput()
-{
-    m_qtVersionOk = false;
-
-    QString output;
-    const QRegExp unamePattern(QLatin1String("Linux (\\S+)\\s(\\S+)"));
-    int index = unamePattern.indexIn(m_deviceTestOutput);
-    if (index == -1) {
-        output = tr("Device configuration test failed: Unexpected output:\n%1")
-            .arg(m_deviceTestOutput);
-        return output;
-    }
-
-    output = tr("Hardware architecture: %1\n").arg(unamePattern.cap(2));
-    output.append(tr("Kernel version: %1\n").arg(unamePattern.cap(1)));
-
-    QString patternString;
-    switch (MaemoGlobal::packagingSystem(m_config->osType())) {
-    case MaemoGlobal::Rpm:
-        patternString = QLatin1String("(libqt\\S+) ((\\d+)\\.(\\d+)\\.(\\d+))");
-        break;
-    case MaemoGlobal::Dpkg:
-        patternString = QLatin1String("(\\S+) (\\S*(\\d+)\\.(\\d+)\\.(\\d+)\\S*) \\S+ \\S+ \\S+");
-        break;
-    default:
-        m_qtVersionOk = true;
-        return output;
-    }
-
-    const QRegExp packagePattern(patternString);
-    index = packagePattern.indexIn(m_deviceTestOutput);
-    if (index == -1) {
-        output.append(tr("No Qt packages installed."));
-        return output;
-    }
-
-    output.append(tr("List of installed Qt packages:") + QLatin1Char('\n'));
-    do {
-        output.append(QLatin1Char('\t') + packagePattern.cap(1) + QLatin1Char(' ')
-            + packagePattern.cap(2) + QLatin1Char('\n'));
-        index = packagePattern.indexIn(m_deviceTestOutput, index
-            + packagePattern.cap(0).length());
-        if (!m_qtVersionOk && QT_VERSION_CHECK(packagePattern.cap(3).toInt(),
-            packagePattern.cap(4).toInt(), packagePattern.cap(5).toInt()) >= 0x040602) {
-            m_qtVersionOk = true;
-        }
-    } while (index != -1);
-    return output;
-}
-
-} // namespace Internal
-} // namespace RemoteLinux
diff --git a/src/plugins/remotelinux/maemoconfigtestdialog.h b/src/plugins/remotelinux/maemoconfigtestdialog.h
deleted file mode 100644
index 262369ffb94b1d45d8a40b2aefa983b1c05f9d19..0000000000000000000000000000000000000000
--- a/src/plugins/remotelinux/maemoconfigtestdialog.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/**************************************************************************
-**
-** This file is part of Qt Creator
-**
-** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
-**
-** Contact: Nokia Corporation (info@qt.nokia.com)
-**
-** GNU Lesser General Public License Usage
-**
-** 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.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** Other Usage
-**
-** Alternatively, this file may be used in accordance with the terms and
-** conditions contained in a signed written agreement between you and Nokia.
-**
-** If you have questions regarding the use of this file, please contact
-** Nokia at info@qt.nokia.com.
-**
-**************************************************************************/
-
-#ifndef MAEMOCONFIGTESTDIALOG_H
-#define MAEMOCONFIGTESTDIALOG_H
-
-#include <QtCore/QSharedPointer>
-#include <QtGui/QDialog>
-
-QT_BEGIN_NAMESPACE
-class QPushButton;
-class Ui_MaemoConfigTestDialog;
-QT_END_NAMESPACE
-
-namespace Utils {
-    class SshRemoteProcessRunner;
-} // namespace Utils
-
-namespace RemoteLinux {
-class LinuxDeviceConfiguration;
-
-namespace Internal {
-class MaemoUsedPortsGatherer;
-
-/**
- * A dialog that runs a test of a device configuration.
- */
-class MaemoConfigTestDialog : public QDialog
-{
-    Q_OBJECT
-public:
-    explicit MaemoConfigTestDialog(const QSharedPointer<const LinuxDeviceConfiguration> &config,
-        QWidget *parent = 0);
-    ~MaemoConfigTestDialog();
-
-private slots:
-    void stopConfigTest();
-    void processSshOutput(const QByteArray &output);
-    void handleConnectionError();
-    void handleTestProcessFinished(int exitStatus);
-    void handlePortListReady();
-    void handlePortListFailure(const QString &errMsg);
-
-private:
-    void startConfigTest();
-    QString parseTestOutput();
-    void handleGeneralTestResult(int exitStatus);
-    void handleMadDeveloperTestResult(int exitStatus);
-    void handleQmlToolingTestResult(int exitStatus);
-    void testPorts();
-    void finish();
-
-    Ui_MaemoConfigTestDialog *m_ui;
-    QPushButton *m_closeButton;
-
-    const QSharedPointer<const LinuxDeviceConfiguration> m_config;
-    QSharedPointer<Utils::SshRemoteProcessRunner> m_testProcessRunner;
-    QString m_deviceTestOutput;
-    bool m_qtVersionOk;
-    MaemoUsedPortsGatherer *const m_portsGatherer;
-
-    enum DeviceTest { GeneralTest, MadDeveloperTest, QmlToolingTest };
-    DeviceTest m_currentTest;
-};
-
-} // namespace Internal
-} // namespace RemoteLinux
-
-#endif // MAEMOCONFIGTESTDIALOG_H
diff --git a/src/plugins/remotelinux/maemoconfigtestdialog.ui b/src/plugins/remotelinux/maemoconfigtestdialog.ui
deleted file mode 100644
index 9afda1b87f3735b31cbecbcd2c61f525bde81bad..0000000000000000000000000000000000000000
--- a/src/plugins/remotelinux/maemoconfigtestdialog.ui
+++ /dev/null
@@ -1,128 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>MaemoConfigTestDialog</class>
- <widget class="QDialog" name="MaemoConfigTestDialog">
-  <property name="geometry">
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>684</width>
-    <height>544</height>
-   </rect>
-  </property>
-  <property name="windowTitle">
-   <string>Device Configuration Test</string>
-  </property>
-  <layout class="QVBoxLayout" name="verticalLayout">
-   <item>
-    <widget class="QPlainTextEdit" name="testResultEdit">
-     <property name="readOnly">
-      <bool>true</bool>
-     </property>
-    </widget>
-   </item>
-   <item>
-    <layout class="QHBoxLayout" name="horizontalLayout">
-     <item>
-      <widget class="QLabel" name="errorLabel">
-       <property name="palette">
-        <palette>
-         <active>
-          <colorrole role="WindowText">
-           <brush brushstyle="SolidPattern">
-            <color alpha="255">
-             <red>255</red>
-             <green>0</green>
-             <blue>0</blue>
-            </color>
-           </brush>
-          </colorrole>
-         </active>
-         <inactive>
-          <colorrole role="WindowText">
-           <brush brushstyle="SolidPattern">
-            <color alpha="255">
-             <red>255</red>
-             <green>0</green>
-             <blue>0</blue>
-            </color>
-           </brush>
-          </colorrole>
-         </inactive>
-         <disabled>
-          <colorrole role="WindowText">
-           <brush brushstyle="SolidPattern">
-            <color alpha="255">
-             <red>120</red>
-             <green>120</green>
-             <blue>120</blue>
-            </color>
-           </brush>
-          </colorrole>
-         </disabled>
-        </palette>
-       </property>
-       <property name="text">
-        <string/>
-       </property>
-       <property name="textFormat">
-        <enum>Qt::RichText</enum>
-       </property>
-      </widget>
-     </item>
-     <item>
-      <widget class="QDialogButtonBox" name="buttonBox">
-       <property name="sizePolicy">
-        <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
-         <horstretch>0</horstretch>
-         <verstretch>0</verstretch>
-        </sizepolicy>
-       </property>
-       <property name="orientation">
-        <enum>Qt::Horizontal</enum>
-       </property>
-       <property name="standardButtons">
-        <set>QDialogButtonBox::Close</set>
-       </property>
-      </widget>
-     </item>
-    </layout>
-   </item>
-  </layout>
- </widget>
- <resources/>
- <connections>
-  <connection>
-   <sender>buttonBox</sender>
-   <signal>accepted()</signal>
-   <receiver>MaemoConfigTestDialog</receiver>
-   <slot>accept()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>248</x>
-     <y>254</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>157</x>
-     <y>274</y>
-    </hint>
-   </hints>
-  </connection>
-  <connection>
-   <sender>buttonBox</sender>
-   <signal>rejected()</signal>
-   <receiver>MaemoConfigTestDialog</receiver>
-   <slot>reject()</slot>
-   <hints>
-    <hint type="sourcelabel">
-     <x>316</x>
-     <y>260</y>
-    </hint>
-    <hint type="destinationlabel">
-     <x>286</x>
-     <y>274</y>
-    </hint>
-   </hints>
-  </connection>
- </connections>
-</ui>
diff --git a/src/plugins/remotelinux/maemodeviceconfigwizard.cpp b/src/plugins/remotelinux/maemodeviceconfigwizard.cpp
index 4ee65e3ab2ad641f66325de4437bae9438a3b370..551c467edd3833ee12a8af502f65197c28a3dc52 100644
--- a/src/plugins/remotelinux/maemodeviceconfigwizard.cpp
+++ b/src/plugins/remotelinux/maemodeviceconfigwizard.cpp
@@ -36,12 +36,12 @@
 #include "ui_maemodeviceconfigwizardreusekeyscheckpage.h"
 #include "ui_maemodeviceconfigwizardstartpage.h"
 
-#include "linuxdeviceconfigurations.h"
-#include "maemoconfigtestdialog.h"
+#include "maddedevicetester.h"
 #include "maemoglobal.h"
 #include "maemokeydeployer.h"
 
 #include <remotelinux/genericlinuxdeviceconfigurationwizardpages.h>
+#include <remotelinux/linuxdevicetestdialog.h>
 #include <utils/fileutils.h>
 #include <utils/ssh/sshkeygenerator.h>
 
@@ -575,7 +575,7 @@ LinuxDeviceConfiguration::Ptr MaemoDeviceConfigWizard::deviceConfiguration()
         d->wizardData.osType, d->wizardData.deviceType, PortList::fromString(freePortsSpec),
         sshParams);
     if (doTest) {
-        MaemoConfigTestDialog dlg(devConf, this);
+        LinuxDeviceTestDialog dlg(devConf, new MaddeDeviceTester(this), this);
         dlg.exec();
     }
     return devConf;
diff --git a/src/plugins/remotelinux/remotelinux.pro b/src/plugins/remotelinux/remotelinux.pro
index fbdfee95db5e3d7e4854249c1ea8a7edfbd71b19..c6b981421a9caf3fa3c34bfddee0c6bd3f3fe17a 100644
--- a/src/plugins/remotelinux/remotelinux.pro
+++ b/src/plugins/remotelinux/remotelinux.pro
@@ -7,7 +7,6 @@ include(remotelinux_dependencies.pri)
 HEADERS += \
     remotelinuxplugin.h \
     remotelinux_export.h \
-    maemoconfigtestdialog.h \
     maemoconstants.h \
     maemorunconfigurationwidget.h \
     maemoruncontrol.h \
@@ -92,11 +91,14 @@ HEADERS += \
     abstractpackagingstep.h \
     tarpackagecreationstep.h \
     remotelinuxpackageinstaller.h \
-    packageuploader.h
+    packageuploader.h \
+    linuxdevicetester.h \
+    maddedevicetester.h \
+    remotelinux_constants.h \
+    linuxdevicetestdialog.h
 
 SOURCES += \
     remotelinuxplugin.cpp \
-    maemoconfigtestdialog.cpp \
     maemorunconfigurationwidget.cpp \
     maemoruncontrol.cpp \
     maemorunfactories.cpp \
@@ -178,10 +180,12 @@ SOURCES += \
     abstractpackagingstep.cpp \
     tarpackagecreationstep.cpp \
     remotelinuxpackageinstaller.cpp \
-    packageuploader.cpp
+    packageuploader.cpp \
+    linuxdevicetester.cpp \
+    maddedevicetester.cpp \
+    linuxdevicetestdialog.cpp
 
 FORMS += \
-    maemoconfigtestdialog.ui \
     maemodeviceconfigurationssettingswidget.ui \
     maemosshconfigdialog.ui \
     maemopackagecreationwidget.ui \
@@ -199,7 +203,8 @@ FORMS += \
     maemodeviceconfigwizardkeydeploymentpage.ui \
     maemodeployconfigurationwidget.ui \
     linuxdevicefactoryselectiondialog.ui \
-    genericlinuxdeviceconfigurationwizardsetuppage.ui
+    genericlinuxdeviceconfigurationwizardsetuppage.ui \
+    linuxdevicetestdialog.ui
 
 RESOURCES += qt-maemo.qrc
 DEFINES += QT_NO_CAST_TO_ASCII
diff --git a/src/plugins/remotelinux/remotelinux_constants.h b/src/plugins/remotelinux/remotelinux_constants.h
new file mode 100644
index 0000000000000000000000000000000000000000..7e5f0a1a15ed6282600422471c30103a548d9bec
--- /dev/null
+++ b/src/plugins/remotelinux/remotelinux_constants.h
@@ -0,0 +1,14 @@
+#ifndef REMOTELINUX_CONSTANTS_H
+#define REMOTELINUX_CONSTANTS_H
+
+namespace RemoteLinux {
+namespace Constants {
+
+const char GenericTestDeviceActionId[] = "RemoteLinux.GenericTestDeviceAction";
+const char GenericDeployKeyToDeviceActionId[] = "RemoteLinux.GenericDeployKeyToDeviceAction";
+const char GenericRemoteProcessesActionId[] = "RemoteLinux.GenericRemoteProcessesAction";
+
+} // Constants
+} // RemoteLinux
+
+#endif // REMOTELINUX_CONSTANTS_H