Skip to content

Commit

Permalink
[win8] Show a prompt before relaunching Chrome in Windows 8 mode whil…
Browse files Browse the repository at this point in the history
…e packaged apps are running.

Introduces ShellWindowRegistry::IsShellWindowRegisteredInAnyProfile to
help determine if packaged apps are currently running. Intercepts the
IDC_WIN8_METRO_RESTART command and shows a modal dialog box if packaged
apps are running to confirm that the user is OK with their packaged
apps closing. Ensures apps with a relaunch handler are not relaunched
when restarting in metro mode.

BUG=222297
TEST=Launch a packaged app in desktop mode and select 'Relaunch Chrome
in Windows 8 mode' from the hotdog menu. A prompt should appear
confirming that your Chrome apps will close if you continue. If no
packaged apps are running, no prompt should appear.

Review URL: https://chromiumcodereview.appspot.com/12566039

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@192240 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
tapted@chromium.org committed Apr 4, 2013
1 parent bda506c commit 24ced7d
Show file tree
Hide file tree
Showing 16 changed files with 176 additions and 36 deletions.
18 changes: 18 additions & 0 deletions apps/app_restore_service.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@
#include "content/public/browser/notification_service.h"
#include "content/public/browser/notification_types.h"

#if defined(OS_WIN)
#include "win8/util/win8_util.h"
#endif

using extensions::AppEventRouter;
using extensions::Extension;
using extensions::ExtensionHost;
Expand All @@ -26,6 +30,20 @@ using extensions::ExtensionSystem;

namespace apps {

// static
bool AppRestoreService::ShouldRestoreApps(bool is_browser_restart) {
bool should_restore_apps = is_browser_restart;
#if defined(OS_CHROMEOS)
// Chromeos always restarts apps, even if it was a regular shutdown.
should_restore_apps = true;
#elif defined(OS_WIN)
// Packaged apps are not supported in Metro mode, so don't try to start them.
if (win8::IsSingleWindowMetroMode())
should_restore_apps = false;
#endif
return should_restore_apps;
}

AppRestoreService::AppRestoreService(Profile* profile)
: profile_(profile) {
registrar_.Add(
Expand Down
4 changes: 4 additions & 0 deletions apps/app_restore_service.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ namespace apps {
class AppRestoreService : public ProfileKeyedService,
public content::NotificationObserver {
public:
// Returns true if apps should be restored on the current platform, given
// whether this new browser process launched due to a restart.
static bool ShouldRestoreApps(bool is_browser_restart);

explicit AppRestoreService(Profile* profile);

// Restart apps that need to be restarted and clear the "running" preference
Expand Down
4 changes: 4 additions & 0 deletions chrome/app/generated_resources.grd
Original file line number Diff line number Diff line change
Expand Up @@ -14920,6 +14920,10 @@ Some features may be unavailable. Please check that the profile exists and you
desc="Infobar button 'no' text to cancel prompt to relaunch in deskop mode to use Chrome Apps">
No, stay in Windows 8 mode
</message>
<message name="IDS_WIN8_PROMPT_TO_CLOSE_APPS_FOR_METRO"
desc="Modal message box prompt shown to the user after requesting to relaunch in Windows 8 mode while packaged apps are running, which will require all packaged apps to be closed. Dialog is shown with choices: OK, Cancel.">
Relaunching in Windows 8 mode will close your Chrome apps.
</message>

<!-- Media Galleries. -->
<message name="IDS_MEDIA_GALLERIES_DIALOG_HEADER" desc="Header for media gallery permissions dialog.">
Expand Down
47 changes: 39 additions & 8 deletions chrome/browser/extensions/shell_window_registry.cc
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ ShellWindowRegistry::~ShellWindowRegistry() {}

// static
ShellWindowRegistry* ShellWindowRegistry::Get(Profile* profile) {
return Factory::GetForProfile(profile);
return Factory::GetForProfile(profile, true /* create */);
}

void ShellWindowRegistry::AddShellWindow(ShellWindow* shell_window) {
Expand Down Expand Up @@ -153,11 +153,13 @@ ShellWindow* ShellWindowRegistry::GetShellWindowForNativeWindowAnyProfile(
gfx::NativeWindow window) {
std::vector<Profile*> profiles =
g_browser_process->profile_manager()->GetLoadedProfiles();
for (std::vector<Profile*>::const_iterator i(profiles.begin());
i < profiles.end(); ++i) {
extensions::ShellWindowRegistry* registry =
extensions::ShellWindowRegistry::Get(*i);
DCHECK(registry);
for (std::vector<Profile*>::const_iterator i = profiles.begin();
i != profiles.end(); ++i) {
ShellWindowRegistry* registry = Factory::GetForProfile(*i,
false /* create */);
if (!registry)
continue;

ShellWindow* shell_window = registry->GetShellWindowForNativeWindow(window);
if (shell_window)
return shell_window;
Expand All @@ -166,6 +168,35 @@ ShellWindow* ShellWindowRegistry::GetShellWindowForNativeWindowAnyProfile(
return NULL;
}

// static
bool ShellWindowRegistry::IsShellWindowRegisteredInAnyProfile(
int window_type_mask) {
std::vector<Profile*> profiles =
g_browser_process->profile_manager()->GetLoadedProfiles();
for (std::vector<Profile*>::const_iterator i = profiles.begin();
i != profiles.end(); ++i) {
ShellWindowRegistry* registry = Factory::GetForProfile(*i,
false /* create */);
if (!registry)
continue;

const ShellWindowSet& shell_windows = registry->shell_windows();
if (shell_windows.empty())
continue;

if (window_type_mask == 0)
return true;

for (const_iterator j = shell_windows.begin(); j != shell_windows.end();
++j) {
if ((*j)->window_type() & window_type_mask)
return true;
}
}

return false;
}

void ShellWindowRegistry::Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
Expand All @@ -192,9 +223,9 @@ void ShellWindowRegistry::Observe(int type,

// static
ShellWindowRegistry* ShellWindowRegistry::Factory::GetForProfile(
Profile* profile) {
Profile* profile, bool create) {
return static_cast<ShellWindowRegistry*>(
GetInstance()->GetServiceForProfile(profile, true));
GetInstance()->GetServiceForProfile(profile, create));
}

ShellWindowRegistry::Factory* ShellWindowRegistry::Factory::GetInstance() {
Expand Down
7 changes: 6 additions & 1 deletion chrome/browser/extensions/shell_window_registry.h
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,11 @@ class ShellWindowRegistry : public ProfileKeyedService,
static ShellWindow* GetShellWindowForNativeWindowAnyProfile(
gfx::NativeWindow window);

// Returns true if the number of shell windows registered across all profiles
// is non-zero. |window_type_mask| is a bitwise OR filter of
// ShellWindow::WindowType, or 0 for any window type.
static bool IsShellWindowRegisteredInAnyProfile(int window_type_mask);

protected:
// content::NotificationObserver:
virtual void Observe(int type,
Expand All @@ -103,7 +108,7 @@ class ShellWindowRegistry : public ProfileKeyedService,
private:
class Factory : public ProfileKeyedServiceFactory {
public:
static ShellWindowRegistry* GetForProfile(Profile* profile);
static ShellWindowRegistry* GetForProfile(Profile* profile, bool create);

static Factory* GetInstance();
private:
Expand Down
15 changes: 10 additions & 5 deletions chrome/browser/ui/browser_command_controller.cc
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
#if defined(OS_WIN)
#include "base/win/metro.h"
#include "base/win/windows_version.h"
#include "chrome/browser/ui/extensions/apps_metro_handler_win.h"
#endif

#if defined(USE_ASH)
Expand Down Expand Up @@ -87,17 +88,17 @@ bool HasInternalURL(const NavigationEntry* entry) {
// 6- If we are not the default exit.
//
// Note: this class deletes itself.
class SwichToMetroUIHandler
class SwitchToMetroUIHandler
: public ShellIntegration::DefaultWebClientObserver {
public:
SwichToMetroUIHandler()
SwitchToMetroUIHandler()
: ALLOW_THIS_IN_INITIALIZER_LIST(default_browser_worker_(
new ShellIntegration::DefaultBrowserWorker(this))),
first_check_(true) {
default_browser_worker_->StartCheckIsDefault();
}

virtual ~SwichToMetroUIHandler() {
virtual ~SwitchToMetroUIHandler() {
default_browser_worker_->ObserverDestroyed();
}

Expand Down Expand Up @@ -140,7 +141,7 @@ class SwichToMetroUIHandler
scoped_refptr<ShellIntegration::DefaultBrowserWorker> default_browser_worker_;
bool first_check_;

DISALLOW_COPY_AND_ASSIGN(SwichToMetroUIHandler);
DISALLOW_COPY_AND_ASSIGN(SwitchToMetroUIHandler);
};
#endif // defined(OS_WIN)

Expand Down Expand Up @@ -447,7 +448,11 @@ void BrowserCommandController::ExecuteCommandWithDisposition(
content::RecordAction(content::UserMetricsAction("Win8DesktopRestart"));
break;
case IDC_WIN8_METRO_RESTART:
new SwichToMetroUIHandler;
if (!chrome::VerifySwitchToMetroForApps(window()->GetNativeWindow()))
break;

// SwitchToMetroUIHandler deletes itself.
new SwitchToMetroUIHandler;
content::RecordAction(content::UserMetricsAction("Win8MetroRestart"));
break;
#endif
Expand Down
3 changes: 3 additions & 0 deletions chrome/browser/ui/cocoa/simple_message_box_mac.mm
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ MessageBoxResult ShowMessageBox(gfx::NativeWindow parent,
const string16& title,
const string16& message,
MessageBoxType type) {
if (type == MESSAGE_BOX_TYPE_OK_CANCEL)
NOTIMPLEMENTED();

startup_metric_utils::SetNonBrowserUIDisplayed();

// Ignore the title; it's the window title on other platforms and ignorable.
Expand Down
31 changes: 31 additions & 0 deletions chrome/browser/ui/extensions/apps_metro_handler_win.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ui/extensions/apps_metro_handler_win.h"

#include "chrome/browser/extensions/shell_window_registry.h"
#include "chrome/browser/ui/extensions/shell_window.h"
#include "chrome/browser/ui/simple_message_box.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "ui/base/l10n/l10n_util.h"

namespace chrome {

bool VerifySwitchToMetroForApps(gfx::NativeWindow parent_window) {
if (!extensions::ShellWindowRegistry::IsShellWindowRegisteredInAnyProfile(
ShellWindow::WINDOW_TYPE_DEFAULT)) {
return true;
}

MessageBoxResult result = ShowMessageBox(
parent_window,
l10n_util::GetStringUTF16(IDS_PRODUCT_NAME),
l10n_util::GetStringUTF16(IDS_WIN8_PROMPT_TO_CLOSE_APPS_FOR_METRO),
MESSAGE_BOX_TYPE_OK_CANCEL);

return result == MESSAGE_BOX_RESULT_YES;
}

} // namespace chrome
20 changes: 20 additions & 0 deletions chrome/browser/ui/extensions/apps_metro_handler_win.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_BROWSER_UI_EXTENSIONS_APPS_METRO_HANDLER_WIN_H_
#define CHROME_BROWSER_UI_EXTENSIONS_APPS_METRO_HANDLER_WIN_H_

#include "ui/gfx/native_widget_types.h"

namespace chrome {

// Check if there are apps running and if not, return true. Otherwise, Show a
// modal dialog on |parent| asking whether the user is OK with their packaged
// apps closing, in order to relaunch to metro mode. Returns true if the user
// clicks OK.
bool VerifySwitchToMetroForApps(gfx::NativeWindow parent);

} // namespace chrome

#endif // CHROME_BROWSER_UI_EXTENSIONS_APPS_METRO_HANDLER_WIN_H_
7 changes: 4 additions & 3 deletions chrome/browser/ui/extensions/shell_window.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,10 @@ class ShellWindow : public content::NotificationObserver,
public extensions::ExtensionKeybindingRegistry::Delegate {
public:
enum WindowType {
WINDOW_TYPE_DEFAULT, // Default shell window
WINDOW_TYPE_PANEL, // OS controlled panel window (Ash only)
WINDOW_TYPE_V1_PANEL, // For apps v1 support in Ash; deprecate with v1 apps
WINDOW_TYPE_DEFAULT = 1 << 0, // Default shell window.
WINDOW_TYPE_PANEL = 1 << 1, // OS controlled panel window (Ash only).
WINDOW_TYPE_V1_PANEL = 1 << 2, // For apps v1 support in Ash; deprecate
// with v1 apps.
};

enum Frame {
Expand Down
3 changes: 3 additions & 0 deletions chrome/browser/ui/gtk/simple_message_box_gtk.cc
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ MessageBoxResult ShowMessageBox(gfx::NativeWindow parent,
const string16& title,
const string16& message,
MessageBoxType type) {
if (type == MESSAGE_BOX_TYPE_OK_CANCEL)
NOTIMPLEMENTED();

GtkMessageType gtk_message_type = GTK_MESSAGE_OTHER;
GtkButtonsType gtk_buttons_type = GTK_BUTTONS_OK;
if (type == MESSAGE_BOX_TYPE_QUESTION) {
Expand Down
14 changes: 7 additions & 7 deletions chrome/browser/ui/simple_message_box.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,20 @@
namespace chrome {

enum MessageBoxResult {
MESSAGE_BOX_RESULT_NO = 0,
MESSAGE_BOX_RESULT_YES = 1,
MESSAGE_BOX_RESULT_NO = 0, // User chose NO or CANCEL.
MESSAGE_BOX_RESULT_YES = 1, // User chose YES or OK.
};

enum MessageBoxType {
MESSAGE_BOX_TYPE_INFORMATION,
MESSAGE_BOX_TYPE_WARNING,
MESSAGE_BOX_TYPE_QUESTION,
MESSAGE_BOX_TYPE_INFORMATION, // Shows an OK button.
MESSAGE_BOX_TYPE_WARNING, // Shows an OK button.
MESSAGE_BOX_TYPE_QUESTION, // Shows YES and NO buttons.
MESSAGE_BOX_TYPE_OK_CANCEL, // Shows OK and CANCEL buttons (Windows only).
};

// Shows a dialog box with the given |title| and |message|. If |parent| is
// non-NULL, the box will be made modal to the |parent|, except on Mac, where it
// is always app-modal. If |type| is MESSAGE_BOX_TYPE_QUESTION, the box will
// have YES and NO buttons; otherwise it will have an OK button.
// is always app-modal.
//
// NOTE: In general, you should avoid this since it's usually poor UI.
// We have a variety of other surfaces such as wrench menu notifications and
Expand Down
13 changes: 5 additions & 8 deletions chrome/browser/ui/startup/startup_browser_creator_impl.cc
Original file line number Diff line number Diff line change
Expand Up @@ -647,17 +647,14 @@ bool StartupBrowserCreatorImpl::ProcessStartupURLs(
else if (pref.type == SessionStartupPref::DEFAULT)
VLOG(1) << "Pref: default";

apps::AppRestoreService* service =
apps::AppRestoreService* restore_service =
apps::AppRestoreServiceFactory::GetForProfile(profile_);
// NULL in incognito mode.
if (service) {
bool should_restore_apps = StartupBrowserCreator::WasRestarted();
#if defined(OS_CHROMEOS)
// Chromeos always restarts apps, even if it was a regular shutdown.
should_restore_apps = true;
#endif
service->HandleStartup(should_restore_apps);
if (restore_service) {
restore_service->HandleStartup(apps::AppRestoreService::ShouldRestoreApps(
StartupBrowserCreator::WasRestarted()));
}

if (pref.type == SessionStartupPref::LAST) {
if (profile_->GetLastSessionExitType() == Profile::EXIT_CRASHED &&
!command_line_.HasSwitch(switches::kRestoreLastSession)) {
Expand Down
11 changes: 10 additions & 1 deletion chrome/browser/ui/views/simple_message_box_views.cc
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,11 @@ SimpleMessageBoxViews::SimpleMessageBoxViews(const string16& title,
}

int SimpleMessageBoxViews::GetDialogButtons() const {
if (type_ == MESSAGE_BOX_TYPE_QUESTION)
if (type_ == MESSAGE_BOX_TYPE_QUESTION ||
type_ == MESSAGE_BOX_TYPE_OK_CANCEL) {
return ui::DIALOG_BUTTON_OK | ui::DIALOG_BUTTON_CANCEL;
}

return ui::DIALOG_BUTTON_OK;
}

Expand All @@ -103,6 +106,12 @@ string16 SimpleMessageBoxViews::GetDialogButtonLabel(
IDS_CONFIRM_MESSAGEBOX_YES_BUTTON_LABEL :
IDS_CONFIRM_MESSAGEBOX_NO_BUTTON_LABEL);
}

if (type_ == MESSAGE_BOX_TYPE_OK_CANCEL) {
return l10n_util::GetStringUTF16((button == ui::DIALOG_BUTTON_OK) ?
IDS_OK : IDS_CANCEL);
}

return l10n_util::GetStringUTF16(IDS_OK);
}

Expand Down
13 changes: 10 additions & 3 deletions chrome/browser/ui/views/simple_message_box_win.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,18 @@ MessageBoxResult ShowMessageBox(gfx::NativeWindow parent,
parent = ui::GetWindowToParentTo(true);

UINT flags = MB_SETFOREGROUND;
flags |= ((type == MESSAGE_BOX_TYPE_QUESTION) ? MB_YESNO : MB_OK);
if (type == MESSAGE_BOX_TYPE_QUESTION) {
flags |= MB_YESNO;
} else if (type == MESSAGE_BOX_TYPE_OK_CANCEL) {
flags |= MB_OKCANCEL;
} else {
flags |= MB_OK;
}
flags |= ((type == MESSAGE_BOX_TYPE_INFORMATION) ?
MB_ICONINFORMATION : MB_ICONWARNING);
return (ui::MessageBox(parent, message, title, flags) == IDNO) ?
MESSAGE_BOX_RESULT_NO : MESSAGE_BOX_RESULT_YES;
int result = ui::MessageBox(parent, message, title, flags);
return (result == IDYES || result == IDOK) ?
MESSAGE_BOX_RESULT_YES : MESSAGE_BOX_RESULT_NO;
}

} // namespace chrome
2 changes: 2 additions & 0 deletions chrome/chrome_browser_ui.gypi
Original file line number Diff line number Diff line change
Expand Up @@ -868,6 +868,8 @@
'browser/ui/extensions/app_metro_infobar_delegate_win.h',
'browser/ui/extensions/application_launch.cc',
'browser/ui/extensions/application_launch.h',
'browser/ui/extensions/apps_metro_handler_win.cc',
'browser/ui/extensions/apps_metro_handler_win.h',
'browser/ui/extensions/extension_install_ui_default.cc',
'browser/ui/extensions/extension_install_ui_default.h',
'browser/ui/extensions/extension_enable_flow.cc',
Expand Down

0 comments on commit 24ced7d

Please sign in to comment.