Skip to content

Commit

Permalink
Don't send onLaunched to apps with only hidden windows when they reload.
Browse files Browse the repository at this point in the history
This also stops apps with only hidden windows getting sent the
onLaunched if they don't listen to onRestarted and the system is
restarted.

BUG=268755

Review URL: https://codereview.chromium.org/270273002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@270614 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
benwells@chromium.org committed May 15, 2014
1 parent 4e53cb3 commit 7aadf69
Show file tree
Hide file tree
Showing 13 changed files with 185 additions and 58 deletions.
39 changes: 26 additions & 13 deletions apps/app_lifetime_monitor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -77,25 +77,24 @@ void AppLifetimeMonitor::Observe(int type,
}
}

void AppLifetimeMonitor::OnAppWindowAdded(AppWindow* app_window) {
void AppLifetimeMonitor::OnAppWindowRemoved(AppWindow* app_window) {
if (!HasVisibleAppWindows(app_window))
NotifyAppDeactivated(app_window->extension_id());
}

void AppLifetimeMonitor::OnAppWindowHidden(AppWindow* app_window) {
if (!HasVisibleAppWindows(app_window))
NotifyAppDeactivated(app_window->extension_id());
}

void AppLifetimeMonitor::OnAppWindowShown(AppWindow* app_window) {
if (app_window->window_type() != AppWindow::WINDOW_TYPE_DEFAULT)
return;

AppWindowRegistry::AppWindowList windows =
AppWindowRegistry::Get(app_window->browser_context())
->GetAppWindowsForApp(app_window->extension_id());
if (windows.size() == 1)
if (HasVisibleAppWindows(app_window))
NotifyAppActivated(app_window->extension_id());
}

void AppLifetimeMonitor::OnAppWindowRemoved(AppWindow* app_window) {
AppWindowRegistry::AppWindowList windows =
AppWindowRegistry::Get(app_window->browser_context())
->GetAppWindowsForApp(app_window->extension_id());
if (windows.empty())
NotifyAppDeactivated(app_window->extension_id());
}

void AppLifetimeMonitor::Shutdown() {
AppWindowRegistry* app_window_registry =
AppWindowRegistry::Factory::GetForBrowserContext(profile_,
Expand All @@ -104,6 +103,20 @@ void AppLifetimeMonitor::Shutdown() {
app_window_registry->RemoveObserver(this);
}

bool AppLifetimeMonitor::HasVisibleAppWindows(AppWindow* app_window) const {
AppWindowRegistry::AppWindowList windows =
AppWindowRegistry::Get(app_window->browser_context())
->GetAppWindowsForApp(app_window->extension_id());

for (AppWindowRegistry::AppWindowList::const_iterator i = windows.begin();
i != windows.end();
++i) {
if (!(*i)->is_hidden())
return true;
}
return false;
}

void AppLifetimeMonitor::NotifyAppStart(const std::string& app_id) {
FOR_EACH_OBSERVER(Observer, observers_, OnAppStart(profile_, app_id));
}
Expand Down
5 changes: 4 additions & 1 deletion apps/app_lifetime_monitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,15 @@ class AppLifetimeMonitor : public KeyedService,
const content::NotificationDetails& details) OVERRIDE;

// AppWindowRegistry::Observer overrides:
virtual void OnAppWindowAdded(AppWindow* app_window) OVERRIDE;
virtual void OnAppWindowRemoved(AppWindow* app_window) OVERRIDE;
virtual void OnAppWindowHidden(apps::AppWindow* app_window) OVERRIDE;
virtual void OnAppWindowShown(apps::AppWindow* app_window) OVERRIDE;

// KeyedService overrides:
virtual void Shutdown() OVERRIDE;

bool HasVisibleAppWindows(apps::AppWindow* app_window) const;

void NotifyAppStart(const std::string& app_id);
void NotifyAppActivated(const std::string& app_id);
void NotifyAppDeactivated(const std::string& app_id);
Expand Down
10 changes: 3 additions & 7 deletions apps/app_load_service.cc
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,10 @@ void AppLoadService::Observe(int type,
if (!unload_info->extension->is_platform_app())
break;

extensions::ExtensionPrefs* extension_prefs =
extensions::ExtensionPrefs::Get(profile_);
if (WasUnloadedForReload(*unload_info) &&
HasAppWindows(unload_info->extension->id()) &&
extension_prefs->IsActive(unload_info->extension->id()) &&
!HasPostReloadAction(unload_info->extension->id())) {
post_reload_actions_[unload_info->extension->id()].action_type = LAUNCH;
}
Expand All @@ -127,12 +129,6 @@ void AppLoadService::Observe(int type,
}
}

bool AppLoadService::HasAppWindows(const std::string& extension_id) {
return !AppWindowRegistry::Get(profile_)
->GetAppWindowsForApp(extension_id)
.empty();
}

bool AppLoadService::WasUnloadedForReload(
const extensions::UnloadedExtensionInfo& unload_info) {
if (unload_info.reason == extensions::UnloadedExtensionInfo::REASON_DISABLE) {
Expand Down
1 change: 0 additions & 1 deletion apps/app_load_service.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ class AppLoadService : public KeyedService,
const content::NotificationSource& source,
const content::NotificationDetails& details) OVERRIDE;

bool HasAppWindows(const std::string& extension_id);
bool WasUnloadedForReload(
const extensions::UnloadedExtensionInfo& unload_info);
bool HasPostReloadAction(const std::string& extension_id);
Expand Down
54 changes: 54 additions & 0 deletions apps/app_restore_service_browsertest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,60 @@ IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, RunningAppsAreRecorded) {
restart_listener.WaitUntilSatisfied();
}

// Tests that apps are recorded in the preferences as active when and only when
// they have visible windows.
IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, ActiveAppsAreRecorded) {
ExtensionTestMessageListener ready_listener("ready", true);
const Extension* extension =
LoadExtension(test_data_dir_.AppendASCII("platform_apps/active_test"));
ASSERT_TRUE(extension);
ExtensionPrefs* extension_prefs = ExtensionPrefs::Get(browser()->profile());
ASSERT_TRUE(ready_listener.WaitUntilSatisfied());

// Open a visible window and check the app is marked active.
ready_listener.Reply("create");
ready_listener.Reset();
ASSERT_TRUE(ready_listener.WaitUntilSatisfied());
ASSERT_TRUE(extension_prefs->IsActive(extension->id()));

// Close the window, then open a minimized window and check the app is active.
ready_listener.Reply("closeLastWindow");
ready_listener.Reset();
ASSERT_TRUE(ready_listener.WaitUntilSatisfied());
ready_listener.Reply("createMinimized");
ready_listener.Reset();
ASSERT_TRUE(ready_listener.WaitUntilSatisfied());
ASSERT_TRUE(extension_prefs->IsActive(extension->id()));

// Close the window, then open a hidden window and check the app is not
// marked active.
ready_listener.Reply("closeLastWindow");
ready_listener.Reset();
ASSERT_TRUE(ready_listener.WaitUntilSatisfied());
ready_listener.Reply("createHidden");
ready_listener.Reset();
ASSERT_TRUE(ready_listener.WaitUntilSatisfied());
ASSERT_FALSE(extension_prefs->IsActive(extension->id()));

// Open another window and check the app is marked active.
ready_listener.Reply("create");
ready_listener.Reset();
ASSERT_TRUE(ready_listener.WaitUntilSatisfied());
ASSERT_TRUE(extension_prefs->IsActive(extension->id()));

// Close the visible window and check the app has been marked inactive.
ready_listener.Reply("closeLastWindow");
ready_listener.Reset();
ASSERT_TRUE(ready_listener.WaitUntilSatisfied());
ASSERT_FALSE(extension_prefs->IsActive(extension->id()));

// Close the last window and exit.
ready_listener.Reply("closeLastWindow");
ready_listener.Reset();
ASSERT_TRUE(ready_listener.WaitUntilSatisfied());
ready_listener.Reply("exit");
}

IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, FileAccessIsSavedToPrefs) {
content::WindowedNotificationObserver extension_suspended(
chrome::NOTIFICATION_EXTENSION_HOST_DESTROYED,
Expand Down
16 changes: 9 additions & 7 deletions apps/app_window.cc
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@ AppWindow::AppWindow(BrowserContext* context,
fullscreen_types_(FULLSCREEN_TYPE_NONE),
show_on_first_paint_(false),
first_paint_complete_(false),
is_hidden_(false),
cached_always_on_top_(false) {
extensions::ExtensionsBrowserClient* client =
extensions::ExtensionsBrowserClient::Get();
Expand Down Expand Up @@ -279,6 +280,11 @@ void AppWindow::Init(const GURL& url,

native_app_window_.reset(delegate_->CreateNativeAppWindow(this, new_params));

// Prevent the browser process from shutting down while this window exists.
AppsClient::Get()->IncrementKeepAliveCount();
UpdateExtensionAppIcon();
AppWindowRegistry::Get(browser_context_)->AddAppWindow(this);

if (new_params.hidden) {
// Although the window starts hidden by default, calling Hide() here
// notifies observers of the window being hidden.
Expand Down Expand Up @@ -330,13 +336,6 @@ void AppWindow::Init(const GURL& url,
initial_bounds.Inset(frame_insets);
apps::ResizeWebContents(web_contents, initial_bounds.size());
}

// Prevent the browser process from shutting down while this window is open.
AppsClient::Get()->IncrementKeepAliveCount();

UpdateExtensionAppIcon();

AppWindowRegistry::Get(browser_context_)->AddAppWindow(this);
}

AppWindow::~AppWindow() {
Expand Down Expand Up @@ -678,6 +677,8 @@ void AppWindow::SetContentSizeConstraints(const gfx::Size& min_size,
}

void AppWindow::Show(ShowType show_type) {
is_hidden_ = false;

if (CommandLine::ForCurrentProcess()->HasSwitch(
switches::kEnableAppsShowOnFirstPaint)) {
show_on_first_paint_ = true;
Expand All @@ -704,6 +705,7 @@ void AppWindow::Hide() {
// there was a non-empty paint. It should have no effect in a non-racy
// scenario where the application is hiding then showing a window: the second
// show will not be delayed.
is_hidden_ = true;
show_on_first_paint_ = false;
GetBaseWindow()->Hide();
AppWindowRegistry::Get(browser_context_)->AppWindowHidden(this);
Expand Down
9 changes: 9 additions & 0 deletions apps/app_window.h
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,7 @@ class AppWindow : public content::NotificationObserver,
const GURL& app_icon_url() const { return app_icon_url_; }
const gfx::Image& badge_icon() const { return badge_icon_; }
const GURL& badge_icon_url() const { return badge_icon_url_; }
bool is_hidden() const { return is_hidden_; }

const extensions::Extension* GetExtension() const;
NativeAppWindow* GetBaseWindow();
Expand Down Expand Up @@ -518,6 +519,14 @@ class AppWindow : public content::NotificationObserver,
// The first visually non-empty paint has completed.
bool first_paint_complete_;

// Whether the window is hidden or not. Hidden in this context means actively
// by the chrome.app.window API, not in an operating system context. For
// example windows which are minimized are not hidden, and windows which are
// part of a hidden app on OS X are not hidden. Windows which were created
// with the |hidden| flag set to true, or which have been programmatically
// hidden, are considered hidden.
bool is_hidden_;

// Whether the delayed Show() call was for an active or inactive window.
ShowType delayed_show_type_;

Expand Down
3 changes: 0 additions & 3 deletions chrome/browser/ui/cocoa/apps/native_app_window_cocoa.h
Original file line number Diff line number Diff line change
Expand Up @@ -181,9 +181,6 @@ class NativeAppWindowCocoa : public apps::NativeAppWindow,

bool has_frame_;

// Whether this window is hidden according to the app.window API. This is set
// by Hide, Show, and ShowInactive.
bool is_hidden_;
// Whether this window last became hidden due to a request to hide the entire
// app, e.g. via the dock menu or Cmd+H. This is set by Hide/ShowWithApp.
bool is_hidden_with_app_;
Expand Down
7 changes: 1 addition & 6 deletions chrome/browser/ui/cocoa/apps/native_app_window_cocoa.mm
Original file line number Diff line number Diff line change
Expand Up @@ -298,7 +298,6 @@ - (void)setMouseDownCanMoveWindow:(BOOL)can_move;
const AppWindow::CreateParams& params)
: app_window_(app_window),
has_frame_(params.frame == AppWindow::FRAME_CHROME),
is_hidden_(false),
is_hidden_with_app_(false),
is_maximized_(false),
is_fullscreen_(false),
Expand Down Expand Up @@ -535,8 +534,6 @@ - (void)setMouseDownCanMoveWindow:(BOOL)can_move;
}

void NativeAppWindowCocoa::Show() {
is_hidden_ = false;

if (is_hidden_with_app_) {
// If there is a shim to gently request attention, return here. Otherwise
// show the window as usual.
Expand All @@ -551,12 +548,10 @@ - (void)setMouseDownCanMoveWindow:(BOOL)can_move;
}

void NativeAppWindowCocoa::ShowInactive() {
is_hidden_ = false;
[window() orderFront:window_controller_];
}

void NativeAppWindowCocoa::Hide() {
is_hidden_ = true;
HideWithoutMarkingHidden();
}

Expand Down Expand Up @@ -868,7 +863,7 @@ - (void)setMouseDownCanMoveWindow:(BOOL)can_move;

void NativeAppWindowCocoa::ShowWithApp() {
is_hidden_with_app_ = false;
if (!is_hidden_)
if (!app_window_->is_hidden())
ShowInactive();
}

Expand Down
45 changes: 25 additions & 20 deletions chrome/browser/ui/cocoa/apps/native_app_window_cocoa_browsertest.mm
Original file line number Diff line number Diff line change
Expand Up @@ -52,58 +52,63 @@ void SetUpAppWithWindows(int num_windows) {
SetUpAppWithWindows(2);
apps::AppWindowRegistry::AppWindowList windows =
apps::AppWindowRegistry::Get(profile())->app_windows();
apps::NativeAppWindow* window = windows.front()->GetBaseWindow();
NSWindow* ns_window = window->GetNativeWindow();
apps::NativeAppWindow* other_window = windows.back()->GetBaseWindow();
NSWindow* other_ns_window = other_window->GetNativeWindow();

apps::AppWindow* app_window = windows.front();
apps::NativeAppWindow* native_window = app_window->GetBaseWindow();
NSWindow* ns_window = native_window->GetNativeWindow();

apps::AppWindow* other_app_window = windows.back();
apps::NativeAppWindow* other_native_window =
other_app_window->GetBaseWindow();
NSWindow* other_ns_window = other_native_window->GetNativeWindow();

// Normal Hide/Show.
window->Hide();
app_window->Hide();
EXPECT_FALSE([ns_window isVisible]);
window->Show();
app_window->Show(apps::AppWindow::SHOW_ACTIVE);
EXPECT_TRUE([ns_window isVisible]);

// Normal Hide/ShowWithApp.
window->HideWithApp();
native_window->HideWithApp();
EXPECT_FALSE([ns_window isVisible]);
window->ShowWithApp();
native_window->ShowWithApp();
EXPECT_TRUE([ns_window isVisible]);

// HideWithApp, Hide, ShowWithApp does not show.
window->HideWithApp();
window->Hide();
window->ShowWithApp();
native_window->HideWithApp();
app_window->Hide();
native_window->ShowWithApp();
EXPECT_FALSE([ns_window isVisible]);

// Hide, HideWithApp, ShowWithApp does not show.
window->HideWithApp();
window->ShowWithApp();
native_window->HideWithApp();
native_window->ShowWithApp();
EXPECT_FALSE([ns_window isVisible]);

// Return to shown state.
window->Show();
app_window->Show(apps::AppWindow::SHOW_ACTIVE);
EXPECT_TRUE([ns_window isVisible]);

// HideWithApp the other window.
EXPECT_TRUE([other_ns_window isVisible]);
other_window->HideWithApp();
other_native_window->HideWithApp();
EXPECT_FALSE([other_ns_window isVisible]);

// HideWithApp, Show shows all windows for this app.
window->HideWithApp();
native_window->HideWithApp();
EXPECT_FALSE([ns_window isVisible]);
window->Show();
app_window->Show(apps::AppWindow::SHOW_ACTIVE);
EXPECT_TRUE([ns_window isVisible]);
EXPECT_TRUE([other_ns_window isVisible]);

// Hide the other window.
other_window->Hide();
other_app_window->Hide();
EXPECT_FALSE([other_ns_window isVisible]);

// HideWithApp, ShowWithApp does not show the other window.
window->HideWithApp();
native_window->HideWithApp();
EXPECT_FALSE([ns_window isVisible]);
window->ShowWithApp();
native_window->ShowWithApp();
EXPECT_TRUE([ns_window isVisible]);
EXPECT_FALSE([other_ns_window isVisible]);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<!-- This file intentionally left blank. -->
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "Platform App Active Test",
"version": "1",
"manifest_version": 2,
"app": {
"background": {
"scripts": ["test.js"]
}
}
}
Loading

0 comments on commit 7aadf69

Please sign in to comment.