diff --git a/core/ajax/update.php b/core/ajax/update.php
index 55e8ab15ec22800be2aee0787a990577b21e2269..84d7a21209e4be4225776ab2e53d8e3fddcf90db 100644
--- a/core/ajax/update.php
+++ b/core/ajax/update.php
@@ -15,6 +15,14 @@ if (OC::checkUpgrade(false)) {
 	$updater->listen('\OC\Updater', 'dbUpgrade', function () use ($eventSource, $l) {
 		$eventSource->send('success', (string)$l->t('Updated database'));
 	});
+	$updater->listen('\OC\Updater', 'disabledApps', function ($appList) use ($eventSource, $l) {
+		$list = array();
+		foreach ($appList as $appId) {
+			$info = OC_App::getAppInfo($appId);
+			$list[] = $info['name'] . ' (' . $info['id'] . ')';
+		}
+		$eventSource->send('success', (string)$l->t('Disabled incompatible apps: %s', implode(', ', $list)));
+	});
 	$updater->listen('\OC\Updater', 'failure', function ($message) use ($eventSource) {
 		$eventSource->send('failure', $message);
 		$eventSource->close();
diff --git a/core/command/upgrade.php b/core/command/upgrade.php
index ed72d136e24b3c461dd4bcbafe029d80171b0065..8ce8ef9b6e5e4b9753bba37d6d2c1bb0c3f8e489 100644
--- a/core/command/upgrade.php
+++ b/core/command/upgrade.php
@@ -56,6 +56,9 @@ class Upgrade extends Command {
 			$updater->listen('\OC\Updater', 'dbUpgrade', function () use($output) {
 				$output->writeln('<info>Updated database</info>');
 			});
+			$updater->listen('\OC\Updater', 'disabledApps', function ($appList) use($output) {
+				$output->writeln('<info>Disabled incompatible apps: ' . implode(', ', $appList) . '</info>');
+			});
 
 			$updater->listen('\OC\Updater', 'failure', function ($message) use($output) {
 				$output->writeln($message);
diff --git a/core/css/styles.css b/core/css/styles.css
index 423c40f61847980eb9d5f7156874654b587b5427..c493941fed871e0608588c562937fbf3761472ad 100644
--- a/core/css/styles.css
+++ b/core/css/styles.css
@@ -370,6 +370,16 @@ input[type="submit"].enabled {
 	opacity: .6;
 }
 
+#body-login .update h2 {
+	font-weight: bold;
+	font-size: 18px;
+	margin-bottom: 30px;
+}
+
+#body-login .infogroup {
+	margin-bottom: 15px;
+}
+
 #body-login p#message img {
 	vertical-align: middle;
 	padding: 5px;
diff --git a/core/js/js.js b/core/js/js.js
index fde6018e9f4ea084e30f9b0c09501d56c609dea3..3c3efc469bfbffcaed5024bf349ca13727c01af4 100644
--- a/core/js/js.js
+++ b/core/js/js.js
@@ -175,9 +175,13 @@ var OC={
 	PERMISSION_DELETE:8,
 	PERMISSION_SHARE:16,
 	PERMISSION_ALL:31,
+	/* jshint camelcase: false */
 	webroot:oc_webroot,
 	appswebroots:(typeof oc_appswebroots !== 'undefined') ? oc_appswebroots:false,
 	currentUser:(typeof oc_current_user!=='undefined')?oc_current_user:false,
+	config: oc_config,
+	appConfig: oc_appconfig || {},
+	theme: oc_defaults || {},
 	coreApps:['', 'admin','log','search','settings','core','3rdparty'],
 	
 	/**
diff --git a/core/js/update.js b/core/js/update.js
index b1b7f6e37e81293f3932ca286b207169cbe879cc..cc0f541bd7985c9e9afd8bedb4f28e0106883a2a 100644
--- a/core/js/update.js
+++ b/core/js/update.js
@@ -1,26 +1,86 @@
-$(document).ready(function () {
-	var updateEventSource = new OC.EventSource(OC.webroot+'/core/ajax/update.php');
-	updateEventSource.listen('success', function(message) {
-		$('<span>').append(message).append('<br />').appendTo($('.update'));
-	});
-	updateEventSource.listen('error', function(message) {
-		$('<span>').addClass('error').append(message).append('<br />').appendTo($('.update'));
-		message = t('core', 'Please reload the page.');
-		$('<span>').addClass('error').append(message).append('<br />').appendTo($('.update'));
-		updateEventSource.close();
-	});
-	updateEventSource.listen('failure', function(message) {
-		$('<span>').addClass('error').append(message).append('<br />').appendTo($('.update'));
-		$('<span>')
-		.addClass('error bold')
-		.append('<br />')
-		.append(t('core', 'The update was unsuccessful. Please report this issue to the <a href="https://github.com/owncloud/core/issues" target="_blank">ownCloud community</a>.'))
-		.appendTo($('.update'));
-	});
-	updateEventSource.listen('done', function(message) {
-		$('<span>').addClass('bold').append('<br />').append(t('core', 'The update was successful. Redirecting you to ownCloud now.')).appendTo($('.update'));
-		setTimeout(function () {
-			window.location.href = OC.webroot;
-		}, 3000);
+/*
+ * Copyright (c) 2014
+ *
+ * This file is licensed under the Affero General Public License version 3
+ * or later.
+ *
+ * See the COPYING-README file.
+ *
+ */
+
+(function() {
+	OC.Update = {
+		_started : false,
+
+		/**
+		 * Start the upgrade process.
+		 *
+		 * @param $el progress list element
+		 */
+		start: function($el) {
+			if (this._started) {
+				return;
+			}
+
+			this.$el = $el;
+
+			this._started = true;
+			this.addMessage(t(
+				'core',
+				'Updating {productName} to version {version}, this may take a while.', {
+					productName: OC.theme.name,
+					version: OC.config.versionstring
+				}),
+				'bold'
+			).append('<br />'); // FIXME: these should be ul/li with CSS paddings!
+
+			var updateEventSource = new OC.EventSource(OC.webroot+'/core/ajax/update.php');
+			updateEventSource.listen('success', function(message) {
+				$('<span>').append(message).append('<br />').appendTo($el);
+			});
+			updateEventSource.listen('error', function(message) {
+				$('<span>').addClass('error').append(message).append('<br />').appendTo($el);
+				message = t('core', 'Please reload the page.');
+				$('<span>').addClass('error').append(message).append('<br />').appendTo($el);
+				updateEventSource.close();
+			});
+			updateEventSource.listen('failure', function(message) {
+				$('<span>').addClass('error').append(message).append('<br />').appendTo($el);
+				$('<span>')
+				.addClass('error bold')
+				.append('<br />')
+				.append(t('core', 'The update was unsuccessful.' +
+					'Please report this issue to the ' +
+					'<a href="https://github.com/owncloud/core/issues" target="_blank">ownCloud community</a>.'))
+				.appendTo($el);
+			});
+			updateEventSource.listen('done', function() {
+				// FIXME: use product name
+				$('<span>').addClass('bold')
+					.append('<br />')
+					.append(t('core', 'The update was successful. Redirecting you to ownCloud now.'))
+					.appendTo($el);
+				setTimeout(function () {
+					OC.redirect(OC.webroot);
+				}, 3000);
+			});
+		},
+
+		addMessage: function(message, className) {
+			var $span = $('<span>');
+			$span.addClass(className).append(message).append('<br />').appendTo(this.$el);
+			return $span;
+		}
+	};
+
+})();
+
+$(document).ready(function() {
+	$('.updateButton').on('click', function() {
+		var $progressEl = $('.updateProgress');
+		$progressEl.removeClass('hidden');
+		$('.updateOverview').addClass('hidden');
+		OC.Update.start($progressEl);
+		return false;
 	});
 });
diff --git a/core/templates/update.admin.php b/core/templates/update.admin.php
index a652d5f195a4830651c291f20a8fbad036d5048d..a09e2d07bf473475b75b59e7ca2bb754de195fc2 100644
--- a/core/templates/update.admin.php
+++ b/core/templates/update.admin.php
@@ -1,6 +1,27 @@
-<ul>
-	<li class='update'>
-		<?php p($l->t('Updating ownCloud to version %s, this may take a while.',
-			array($_['version']))); ?><br /><br />
-	</li>
-</ul>
+<div class="update">
+	<div class="updateOverview">
+		<h2 class="title bold"><?php p($l->t('%s will be updated to version %s.',
+			array($_['productName'], $_['version']))); ?></h2>
+		<?php if (!empty($_['appList'])) { ?>
+		<div class="infogroup">
+			<span class="bold"><?php p($l->t('The following apps will be disabled:')) ?></span>
+			<ul class="content appList">
+				<?php foreach ($_['appList'] as $appInfo) { ?>
+				<li><?php p($appInfo['name']) ?> (<?php p($appInfo['id']) ?>)</li>
+				<?php } ?>
+			</ul>
+		</div>
+		<?php } ?>
+		<?php if (!empty($_['oldTheme'])) { ?>
+		<div class="infogroup bold">
+			<?php p($l->t('The theme %s has been disabled.', array($_['oldTheme']))) ?>
+		</div>
+		<?php } ?>
+		<div class="infogroup bold">
+			<?php p($l->t('Please make sure that the database, the config folder and the data folder have been backed up before proceeding.')) ?>
+		</div>
+		<input class="updateButton" type="button" value="<?php p($l->t('Start update')) ?>">
+	</div>
+
+	<div class="updateProgress hidden"></div>
+</div>
diff --git a/lib/base.php b/lib/base.php
index 63df94319f6fc2c0897af65ca17fbe6282585521..882b587a6fd2722b42ca6d3cb7a5f595edc40008 100644
--- a/lib/base.php
+++ b/lib/base.php
@@ -284,11 +284,26 @@ class OC {
 	public static function checkUpgrade($showTemplate = true) {
 		if (self::needUpgrade()) {
 			if ($showTemplate && !OC_Config::getValue('maintenance', false)) {
+				$version = OC_Util::getVersion();
+				$oldTheme = OC_Config::getValue('theme');
 				OC_Config::setValue('theme', '');
 				OC_Util::addScript('config'); // needed for web root
 				OC_Util::addScript('update');
 				$tmpl = new OC_Template('', 'update.admin', 'guest');
 				$tmpl->assign('version', OC_Util::getVersionString());
+
+				// get third party apps
+				$apps = OC_App::getEnabledApps();
+				$incompatibleApps = array();
+				foreach ($apps as $appId) {
+					$info = OC_App::getAppInfo($appId);
+					if(!OC_App::isAppCompatible($version, $info)) {
+						$incompatibleApps[] = $info;
+					}
+				}
+				$tmpl->assign('appList', $incompatibleApps);
+				$tmpl->assign('productName', 'ownCloud'); // for now
+				$tmpl->assign('oldTheme', $oldTheme);
 				$tmpl->printPage();
 				exit();
 			} else {
diff --git a/lib/private/app.php b/lib/private/app.php
index 50065197eb4ef395df2f8d68f55b38fde37e32f6..ea0453e58eaa47d63555f8d0d1db9e2bb93ba54a 100644
--- a/lib/private/app.php
+++ b/lib/private/app.php
@@ -889,8 +889,14 @@ class OC_App{
 	 * ownCloud version. disable them if not.
 	 * This is important if you upgrade ownCloud and have non ported 3rd
 	 * party apps installed.
+	 *
+	 * @param array $apps optional app id list to check, uses all enabled apps
+	 * when not specified
+	 *
+	 * @return array containing the list of ids of the disabled apps
 	 */
 	public static function checkAppsRequirements($apps = array()) {
+		$disabledApps = array();
 		if (empty($apps)) {
 			$apps = OC_App::getEnabledApps();
 		}
@@ -905,8 +911,10 @@ class OC_App{
 					OC_Log::ERROR);
 				OC_App::disable( $app );
 				OC_Hook::emit('update', 'success', 'Disabled '.$info['name'].' app because it is not compatible');
+				$disabledApps[] = $app;
 			}
 		}
+		return $disabledApps;
 	}
 
 	/**
diff --git a/lib/private/updater.php b/lib/private/updater.php
index d8694ac6ed5dfdd37abf840f740714c7d59f4c8b..58d3cab73aa0a0e8ce65a4d9e5944d34a5fd76fc 100644
--- a/lib/private/updater.php
+++ b/lib/private/updater.php
@@ -134,7 +134,10 @@ class Updater extends BasicEmitter {
 			$this->emit('\OC\Updater', 'failure', array($exception->getMessage()));
 		}
 		\OC_Config::setValue('version', implode('.', \OC_Util::getVersion()));
-		\OC_App::checkAppsRequirements();
+		$disabledApps = \OC_App::checkAppsRequirements();
+		if (!empty($disabledApps)) {
+			$this->emit('\OC\Updater', 'disabledApps', array($disabledApps));
+		}
 		// load all apps to also upgrade enabled apps
 		\OC_App::loadApps();