diff options
author | Torne (Richard Coles) <torne@google.com> | 2014-06-20 14:52:04 +0100 |
---|---|---|
committer | Torne (Richard Coles) <torne@google.com> | 2014-06-20 14:52:04 +0100 |
commit | f8ee788a64d60abd8f2d742a5fdedde054ecd910 (patch) | |
tree | 7dc14380200b953c64e0ccd16435cdbd1dbf1205 /apps | |
parent | fcbbbe23a38088a52492922075e71a419c4b01ec (diff) | |
download | chromium_org-f8ee788a64d60abd8f2d742a5fdedde054ecd910.tar.gz |
Merge from Chromium at DEPS revision 278205
This commit was generated by merge_to_master.py.
Change-Id: I23f1e7ea8c154ba72e7fb594436216f861f868ab
Diffstat (limited to 'apps')
23 files changed, 567 insertions, 56 deletions
diff --git a/apps/app_restore_service_browsertest.cc b/apps/app_restore_service_browsertest.cc index 1ba87e3da6..f66b1bed8b 100644 --- a/apps/app_restore_service_browsertest.cc +++ b/apps/app_restore_service_browsertest.cc @@ -125,14 +125,9 @@ IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, FileAccessIsSavedToPrefs) { FileSystemChooseEntryFunction::RegisterTempExternalFileSystemForTest( "temp", temp_directory.path()); - ExtensionTestMessageListener file_written_listener("fileWritten", false); - ExtensionTestMessageListener access_ok_listener( - "restartedFileAccessOK", false); - - const Extension* extension = - LoadAndLaunchPlatformApp("file_access_saved_to_prefs_test"); + const Extension* extension = LoadAndLaunchPlatformApp( + "file_access_saved_to_prefs_test", "fileWritten"); ASSERT_TRUE(extension); - file_written_listener.WaitUntilSatisfied(); SavedFilesService* saved_files_service = SavedFilesService::Get(profile()); @@ -170,14 +165,12 @@ IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, MAYBE_FileAccessIsRestored) { FileSystemChooseEntryFunction::RegisterTempExternalFileSystemForTest( "temp", temp_directory.path()); - ExtensionTestMessageListener file_written_listener("fileWritten", false); ExtensionTestMessageListener access_ok_listener( "restartedFileAccessOK", false); const Extension* extension = - LoadAndLaunchPlatformApp("file_access_restored_test"); + LoadAndLaunchPlatformApp("file_access_restored_test", "fileWritten"); ASSERT_TRUE(extension); - file_written_listener.WaitUntilSatisfied(); ExtensionPrefs* extension_prefs = ExtensionPrefs::Get(browser()->profile()); diff --git a/apps/app_shim/app_shim_interactive_uitest_mac.mm b/apps/app_shim/app_shim_interactive_uitest_mac.mm new file mode 100644 index 0000000000..1cfdf7953d --- /dev/null +++ b/apps/app_shim/app_shim_interactive_uitest_mac.mm @@ -0,0 +1,307 @@ +// Copyright 2014 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. + +#import <Cocoa/Cocoa.h> +#include <vector> + +#include "apps/app_shim/app_shim_handler_mac.h" +#include "apps/app_shim/app_shim_host_manager_mac.h" +#include "apps/app_shim/extension_app_shim_handler_mac.h" +#include "apps/switches.h" +#include "apps/ui/native_app_window.h" +#include "base/auto_reset.h" +#include "base/callback.h" +#include "base/files/file_path_watcher.h" +#include "base/mac/foundation_util.h" +#include "base/mac/launch_services_util.h" +#include "base/mac/scoped_nsobject.h" +#include "base/path_service.h" +#include "base/process/launch.h" +#include "base/strings/sys_string_conversions.h" +#include "base/test/test_timeouts.h" +#include "chrome/browser/apps/app_browsertest_util.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/extensions/extension_test_message_listener.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/web_applications/web_app_mac.h" +#include "chrome/common/chrome_paths.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/mac/app_mode_common.h" +#include "content/public/test/test_utils.h" +#include "extensions/browser/extension_registry.h" +#import "ui/events/test/cocoa_test_event_utils.h" + +namespace { + +// General end-to-end test for app shims. +class AppShimInteractiveTest : public extensions::PlatformAppBrowserTest { + protected: + AppShimInteractiveTest() + : auto_reset_(&g_app_shims_allow_update_and_launch_in_tests, true) {} + + private: + // Temporarily enable app shims. + base::AutoReset<bool> auto_reset_; + + DISALLOW_COPY_AND_ASSIGN(AppShimInteractiveTest); +}; + +// Watches for changes to a file. This is designed to be used from the the UI +// thread. +class WindowedFilePathWatcher + : public base::RefCountedThreadSafe<WindowedFilePathWatcher> { + public: + WindowedFilePathWatcher(const base::FilePath& path) : observed_(false) { + content::BrowserThread::PostTask( + content::BrowserThread::FILE, + FROM_HERE, + base::Bind(&WindowedFilePathWatcher::Watch, this, path)); + } + + void Wait() { + if (observed_) + return; + + run_loop_.reset(new base::RunLoop); + run_loop_->Run(); + } + + protected: + friend class base::RefCountedThreadSafe<WindowedFilePathWatcher>; + virtual ~WindowedFilePathWatcher() {} + + void Watch(const base::FilePath& path) { + watcher_.Watch( + path, false, base::Bind(&WindowedFilePathWatcher::Observe, this)); + } + + void Observe(const base::FilePath& path, bool error) { + content::BrowserThread::PostTask( + content::BrowserThread::UI, + FROM_HERE, + base::Bind(&WindowedFilePathWatcher::StopRunLoop, this)); + } + + void StopRunLoop() { + observed_ = true; + if (run_loop_.get()) + run_loop_->Quit(); + } + + private: + base::FilePathWatcher watcher_; + bool observed_; + scoped_ptr<base::RunLoop> run_loop_; + + DISALLOW_COPY_AND_ASSIGN(WindowedFilePathWatcher); +}; + +// Watches for an app shim to connect. +class WindowedAppShimLaunchObserver : public apps::AppShimHandler { + public: + WindowedAppShimLaunchObserver(const std::string& app_id) + : app_mode_id_(app_id), + observed_(false) { + apps::AppShimHandler::RegisterHandler(app_id, this); + } + + void Wait() { + if (observed_) + return; + + run_loop_.reset(new base::RunLoop); + run_loop_->Run(); + } + + // AppShimHandler overrides: + virtual void OnShimLaunch(Host* host, + apps::AppShimLaunchType launch_type, + const std::vector<base::FilePath>& files) OVERRIDE { + // Remove self and pass through to the default handler. + apps::AppShimHandler::RemoveHandler(app_mode_id_); + apps::AppShimHandler::GetForAppMode(app_mode_id_) + ->OnShimLaunch(host, launch_type, files); + observed_ = true; + if (run_loop_.get()) + run_loop_->Quit(); + } + virtual void OnShimClose(Host* host) OVERRIDE {} + virtual void OnShimFocus(Host* host, + apps::AppShimFocusType focus_type, + const std::vector<base::FilePath>& files) OVERRIDE {} + virtual void OnShimSetHidden(Host* host, bool hidden) OVERRIDE {} + virtual void OnShimQuit(Host* host) OVERRIDE {} + + private: + std::string app_mode_id_; + bool observed_; + scoped_ptr<base::RunLoop> run_loop_; + + DISALLOW_COPY_AND_ASSIGN(WindowedAppShimLaunchObserver); +}; + +NSString* GetBundleID(const base::FilePath& shim_path) { + base::FilePath plist_path = shim_path.Append("Contents").Append("Info.plist"); + NSMutableDictionary* plist = [NSMutableDictionary + dictionaryWithContentsOfFile:base::mac::FilePathToNSString(plist_path)]; + return [plist objectForKey:base::mac::CFToNSCast(kCFBundleIdentifierKey)]; +} + +bool HasAppShimHost(Profile* profile, const std::string& app_id) { + return g_browser_process->platform_part() + ->app_shim_host_manager() + ->extension_app_shim_handler() + ->FindHost(profile, app_id); +} + +} // namespace + +// Watches for NSNotifications from the shared workspace. +@interface WindowedNSNotificationObserver : NSObject { + @private + base::scoped_nsobject<NSString> bundleId_; + BOOL notificationReceived_; + scoped_ptr<base::RunLoop> runLoop_; +} + +- (id)initForNotification:(NSString*)name + andBundleId:(NSString*)bundleId; +- (void)observe:(NSNotification*)notification; +- (void)wait; +@end + +@implementation WindowedNSNotificationObserver + +- (id)initForNotification:(NSString*)name + andBundleId:(NSString*)bundleId { + if (self = [super init]) { + bundleId_.reset([[bundleId copy] retain]); + [[[NSWorkspace sharedWorkspace] notificationCenter] + addObserver:self + selector:@selector(observe:) + name:name + object:nil]; + } + return self; +} + +- (void)observe:(NSNotification*)notification { + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); + + NSRunningApplication* application = + [[notification userInfo] objectForKey:NSWorkspaceApplicationKey]; + if (![[application bundleIdentifier] isEqualToString:bundleId_]) + return; + + [[[NSWorkspace sharedWorkspace] notificationCenter] removeObserver:self]; + notificationReceived_ = YES; + if (runLoop_.get()) + runLoop_->Quit(); +} + +- (void)wait { + if (notificationReceived_) + return; + + runLoop_.reset(new base::RunLoop); + runLoop_->Run(); +} + +@end + +namespace apps { + +// Shims require static libraries http://crbug.com/386024. +#if defined(COMPONENT_BUILD) +#define MAYBE_Launch DISABLED_Launch +#else +#define MAYBE_Launch Launch +#endif + +// Test that launching the shim for an app starts the app, and vice versa. +// These two cases are combined because the time to run the test is dominated +// by loading the extension and creating the shim. +IN_PROC_BROWSER_TEST_F(AppShimInteractiveTest, MAYBE_Launch) { + // Install the app. + const extensions::Extension* app = InstallPlatformApp("minimal"); + + // Use a WebAppShortcutCreator to get the path. + web_app::WebAppShortcutCreator shortcut_creator( + web_app::GetWebAppDataDirectory(profile()->GetPath(), app->id(), GURL()), + web_app::ShortcutInfoForExtensionAndProfile(app, profile()), + extensions::FileHandlersInfo()); + base::FilePath shim_path = shortcut_creator.GetInternalShortcutPath(); + EXPECT_FALSE(base::PathExists(shim_path)); + + // Create the internal app shim by simulating an app update. FilePathWatcher + // is used to wait for file operations on the shim to be finished before + // attempting to launch it. Since all of the file operations are done in the + // same event on the FILE thread, everything will be done by the time the + // watcher's callback is executed. + scoped_refptr<WindowedFilePathWatcher> file_watcher = + new WindowedFilePathWatcher(shim_path); + web_app::UpdateAllShortcuts(base::string16(), profile(), app); + file_watcher->Wait(); + NSString* bundle_id = GetBundleID(shim_path); + + // Case 1: Launch the shim, it should start the app. + { + ExtensionTestMessageListener launched_listener("Launched", false); + CommandLine shim_cmdline(CommandLine::NO_PROGRAM); + shim_cmdline.AppendSwitch(app_mode::kLaunchedForTest); + ProcessSerialNumber shim_psn; + ASSERT_TRUE(base::mac::OpenApplicationWithPath( + shim_path, shim_cmdline, kLSLaunchDefaults, &shim_psn)); + ASSERT_TRUE(launched_listener.WaitUntilSatisfied()); + + ASSERT_TRUE(GetFirstAppWindow()); + EXPECT_TRUE(HasAppShimHost(profile(), app->id())); + + // If the window is closed, the shim should quit. + pid_t shim_pid; + EXPECT_EQ(noErr, GetProcessPID(&shim_psn, &shim_pid)); + GetFirstAppWindow()->GetBaseWindow()->Close(); + ASSERT_TRUE( + base::WaitForSingleProcess(shim_pid, TestTimeouts::action_timeout())); + + EXPECT_FALSE(GetFirstAppWindow()); + EXPECT_FALSE(HasAppShimHost(profile(), app->id())); + } + + // Case 2: Launch the app, it should start the shim. + { + base::scoped_nsobject<WindowedNSNotificationObserver> ns_observer; + ns_observer.reset([[WindowedNSNotificationObserver alloc] + initForNotification:NSWorkspaceDidLaunchApplicationNotification + andBundleId:bundle_id]); + WindowedAppShimLaunchObserver observer(app->id()); + LaunchPlatformApp(app); + [ns_observer wait]; + observer.Wait(); + + EXPECT_TRUE(GetFirstAppWindow()); + EXPECT_TRUE(HasAppShimHost(profile(), app->id())); + + // Quitting the shim will eventually cause it to quit. It actually + // intercepts the -terminate, sends an AppShimHostMsg_QuitApp to Chrome, + // and returns NSTerminateLater. Chrome responds by closing all windows of + // the app. Once all windows are closed, Chrome closes the IPC channel, + // which causes the shim to actually terminate. + NSArray* running_shim = [NSRunningApplication + runningApplicationsWithBundleIdentifier:bundle_id]; + ASSERT_EQ(1u, [running_shim count]); + + ns_observer.reset([[WindowedNSNotificationObserver alloc] + initForNotification:NSWorkspaceDidTerminateApplicationNotification + andBundleId:bundle_id]); + [base::mac::ObjCCastStrict<NSRunningApplication>( + [running_shim objectAtIndex:0]) terminate]; + [ns_observer wait]; + + EXPECT_FALSE(GetFirstAppWindow()); + EXPECT_FALSE(HasAppShimHost(profile(), app->id())); + } +} + +} // namespace apps diff --git a/apps/app_shim/chrome_main_app_mode_mac.mm b/apps/app_shim/chrome_main_app_mode_mac.mm index 1092142733..18b8f9e1cf 100644 --- a/apps/app_shim/chrome_main_app_mode_mac.mm +++ b/apps/app_shim/chrome_main_app_mode_mac.mm @@ -155,7 +155,7 @@ AppShimController::AppShimController() AppShimController::~AppShimController() { // Un-set the delegate since NSApplication does not retain it. - [NSApp setDelegate:nil]; + [[NSApplication sharedApplication] setDelegate:nil]; } void AppShimController::OnPingChromeReply(bool success) { @@ -611,7 +611,11 @@ int ChromeAppModeStart(const app_mode::ChromeAppModeInfo* info) { main_message_loop.set_thread_name("MainThread"); base::PlatformThread::SetName("CrAppShimMain"); - if (pid == -1) { + // In tests, launching Chrome does nothing, and we won't get a ping response, + // so just assume the socket exists. + if (pid == -1 && + !CommandLine::ForCurrentProcess()->HasSwitch( + app_mode::kLaunchedForTest)) { // Launch Chrome if it isn't already running. ProcessSerialNumber psn; CommandLine command_line(CommandLine::NO_PROGRAM); diff --git a/apps/app_window.cc b/apps/app_window.cc index dbc28f759a..814d2e0ae8 100644 --- a/apps/app_window.cc +++ b/apps/app_window.cc @@ -157,6 +157,8 @@ AppWindow::CreateParams::CreateParams() : window_type(AppWindow::WINDOW_TYPE_DEFAULT), frame(AppWindow::FRAME_CHROME), has_frame_color(false), + active_frame_color(SK_ColorBLACK), + inactive_frame_color(SK_ColorBLACK), transparent_background(false), creator_process_id(0), state(ui::SHOW_STATE_DEFAULT), diff --git a/apps/apps.gypi b/apps/apps.gypi index 2940bce1fa..e2b4e7e712 100644 --- a/apps/apps.gypi +++ b/apps/apps.gypi @@ -94,7 +94,9 @@ ['enable_extensions==0', { 'sources/': [ - ['exclude', '^apps/'], + ['exclude', '.*'], + ['include', 'ui/web_contents_sizer\.cc$'], + ['include', 'ui/web_contents_sizer\.mm$'], ], } ], diff --git a/apps/launcher.cc b/apps/launcher.cc index 8cfbee970f..72ed7888f1 100644 --- a/apps/launcher.cc +++ b/apps/launcher.cc @@ -411,9 +411,9 @@ void LaunchPlatformAppWithCommandLine(Profile* profile, #if defined(OS_WIN) base::CommandLine::StringType about_blank_url( - base::ASCIIToWide(content::kAboutBlankURL)); + base::ASCIIToWide(url::kAboutBlankURL)); #else - base::CommandLine::StringType about_blank_url(content::kAboutBlankURL); + base::CommandLine::StringType about_blank_url(url::kAboutBlankURL); #endif CommandLine::StringVector args = command_line.GetArgs(); // Browser tests will add about:blank to the command line. This should diff --git a/apps/shell/app/shell_main_delegate.cc b/apps/shell/app/shell_main_delegate.cc index b8f835d1ae..2a9cd1439f 100644 --- a/apps/shell/app/shell_main_delegate.cc +++ b/apps/shell/app/shell_main_delegate.cc @@ -8,6 +8,7 @@ #include "apps/shell/browser/shell_content_browser_client.h" #include "apps/shell/common/shell_content_client.h" #include "apps/shell/renderer/shell_content_renderer_client.h" +#include "apps/shell/renderer/shell_renderer_main_delegate.h" #include "base/command_line.h" #include "base/files/file_path.h" #include "base/logging.h" @@ -73,7 +74,8 @@ content::ContentBrowserClient* ShellMainDelegate::CreateContentBrowserClient() { content::ContentRendererClient* ShellMainDelegate::CreateContentRendererClient() { - renderer_client_.reset(new ShellContentRendererClient); + renderer_client_.reset( + new ShellContentRendererClient(CreateShellRendererMainDelegate())); return renderer_client_.get(); } @@ -81,6 +83,11 @@ ShellBrowserMainDelegate* ShellMainDelegate::CreateShellBrowserMainDelegate() { return new DefaultShellBrowserMainDelegate(); } +scoped_ptr<ShellRendererMainDelegate> +ShellMainDelegate::CreateShellRendererMainDelegate() { + return scoped_ptr<ShellRendererMainDelegate>(); +} + // static bool ShellMainDelegate::ProcessNeedsResourceBundle( const std::string& process_type) { diff --git a/apps/shell/app/shell_main_delegate.h b/apps/shell/app/shell_main_delegate.h index 45ba122f32..594f7634da 100644 --- a/apps/shell/app/shell_main_delegate.h +++ b/apps/shell/app/shell_main_delegate.h @@ -18,6 +18,7 @@ class ContentRendererClient; namespace apps { class ShellBrowserMainDelegate; +class ShellRendererMainDelegate; class ShellMainDelegate : public content::ContentMainDelegate { public: @@ -35,6 +36,10 @@ class ShellMainDelegate : public content::ContentMainDelegate { // The created object is owned by ShellBrowserMainParts. virtual ShellBrowserMainDelegate* CreateShellBrowserMainDelegate(); + // The returned object is owned by ShellContentRendererClient. + virtual scoped_ptr<ShellRendererMainDelegate> + CreateShellRendererMainDelegate(); + private: // |process_type| is zygote, renderer, utility, etc. Returns true if the // process needs data from resources.pak. diff --git a/apps/shell/app_shell.gyp b/apps/shell/app_shell.gyp index bd5b26a38d..8b2996cf1d 100644 --- a/apps/shell/app_shell.gyp +++ b/apps/shell/app_shell.gyp @@ -103,10 +103,13 @@ 'browser/api/shell/shell_api.h', 'browser/default_shell_browser_main_delegate.cc', 'browser/default_shell_browser_main_delegate.h', + 'browser/default_shell_app_window_controller.cc', + 'browser/default_shell_app_window_controller.h', 'browser/shell_app_sorting.cc', 'browser/shell_app_sorting.h', 'browser/shell_app_window.cc', 'browser/shell_app_window.h', + 'browser/shell_app_window_controller.h', 'browser/shell_browser_context.cc', 'browser/shell_browser_context.h', 'browser/shell_browser_main_delegate.h', @@ -143,6 +146,7 @@ 'renderer/shell_dispatcher_delegate.h', 'renderer/shell_extensions_renderer_client.cc', 'renderer/shell_extensions_renderer_client.h', + 'renderer/shell_renderer_main_delegate.h', ], 'conditions': [ ['chromeos==1', { diff --git a/apps/shell/browser/default_shell_app_window_controller.cc b/apps/shell/browser/default_shell_app_window_controller.cc new file mode 100644 index 0000000000..3ec5b6bc84 --- /dev/null +++ b/apps/shell/browser/default_shell_app_window_controller.cc @@ -0,0 +1,45 @@ +// Copyright 2014 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 "apps/shell/browser/default_shell_app_window_controller.h" + +#include "apps/shell/browser/shell_app_window.h" +#include "apps/shell/browser/shell_desktop_controller.h" +#include "base/logging.h" +#include "ui/aura/window.h" +#include "ui/aura/window_tree_host.h" + +namespace apps { + +DefaultShellAppWindowController::DefaultShellAppWindowController( + ShellDesktopController* shell_desktop_controller) + : shell_desktop_controller_(shell_desktop_controller) { + DCHECK(shell_desktop_controller_); +} + +DefaultShellAppWindowController::~DefaultShellAppWindowController() { + // The app window must be explicitly closed before desktop teardown. + DCHECK(!app_window_); +} + +ShellAppWindow* DefaultShellAppWindowController::CreateAppWindow( + content::BrowserContext* context) { + aura::Window* root_window = shell_desktop_controller_->host()->window(); + + app_window_.reset(new ShellAppWindow); + app_window_->Init(context, root_window->bounds().size()); + + // Attach the web contents view to our window hierarchy. + aura::Window* content = app_window_->GetNativeWindow(); + root_window->AddChild(content); + content->Show(); + + return app_window_.get(); +} + +void DefaultShellAppWindowController::CloseAppWindows() { + app_window_.reset(); +} + +} // namespace apps diff --git a/apps/shell/browser/default_shell_app_window_controller.h b/apps/shell/browser/default_shell_app_window_controller.h new file mode 100644 index 0000000000..36dccd834d --- /dev/null +++ b/apps/shell/browser/default_shell_app_window_controller.h @@ -0,0 +1,40 @@ +// Copyright 2014 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 APPS_SHELL_BROWSER_DEFAULT_SHELL_APP_WINDOW_CONTROLLER_H_ +#define APPS_SHELL_BROWSER_DEFAULT_SHELL_APP_WINDOW_CONTROLLER_H_ + +#include "apps/shell/browser/shell_app_window_controller.h" +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" + +namespace apps { + +class ShellDesktopController; + +// The default shell app window controller for app_shell. It manages only one +// app_window. +class DefaultShellAppWindowController : public ShellAppWindowController { + public: + explicit DefaultShellAppWindowController( + ShellDesktopController* shell_desktop_controller); + virtual ~DefaultShellAppWindowController(); + + // ShellAppWindowController implementation. + virtual ShellAppWindow* CreateAppWindow( + content::BrowserContext* context) OVERRIDE; + virtual void CloseAppWindows() OVERRIDE; + + private: + ShellDesktopController* shell_desktop_controller_; // Not owned + + // The desktop supports a single app window. + scoped_ptr<ShellAppWindow> app_window_; + + DISALLOW_COPY_AND_ASSIGN(DefaultShellAppWindowController); +}; + +} // namespace apps + +#endif // APPS_SHELL_BROWSER_DEFAULT_SHELL_APP_WINDOW_CONTROLLER_H_ diff --git a/apps/shell/browser/default_shell_browser_main_delegate.cc b/apps/shell/browser/default_shell_browser_main_delegate.cc index 3efabbb36d..977c07eed4 100644 --- a/apps/shell/browser/default_shell_browser_main_delegate.cc +++ b/apps/shell/browser/default_shell_browser_main_delegate.cc @@ -4,6 +4,7 @@ #include "apps/shell/browser/default_shell_browser_main_delegate.h" +#include "apps/shell/browser/default_shell_app_window_controller.h" #include "apps/shell/browser/shell_desktop_controller.h" #include "apps/shell/browser/shell_extension_system.h" #include "base/command_line.h" @@ -29,7 +30,9 @@ void DefaultShellBrowserMainDelegate::Start( extensions::ShellExtensionSystem* extension_system = static_cast<extensions::ShellExtensionSystem*>( extensions::ExtensionSystem::Get(browser_context)); - extension_system->LoadAndLaunchApp(app_absolute_dir); + if (!extension_system->LoadApp(app_absolute_dir)) + return; + extension_system->LaunchApp(); } else { LOG(ERROR) << "--" << kAppSwitch << " unset; boredom is in your future"; } @@ -40,7 +43,9 @@ void DefaultShellBrowserMainDelegate::Shutdown() { ShellDesktopController* DefaultShellBrowserMainDelegate::CreateDesktopController() { - return new ShellDesktopController(); + ShellDesktopController* desktop = new ShellDesktopController(); + desktop->SetAppWindowController(new DefaultShellAppWindowController(desktop)); + return desktop; } } // namespace apps diff --git a/apps/shell/browser/shell_app_window_controller.h b/apps/shell/browser/shell_app_window_controller.h new file mode 100644 index 0000000000..13dd982097 --- /dev/null +++ b/apps/shell/browser/shell_app_window_controller.h @@ -0,0 +1,30 @@ +// Copyright 2014 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 APPS_SHELL_BROWSER_SHELL_APP_WINDOW_CONTROLLER_H_ +#define APPS_SHELL_BROWSER_SHELL_APP_WINDOW_CONTROLLER_H_ + +namespace content { +class BrowserContext; +} + +namespace apps { + +class ShellAppWindow; + +class ShellAppWindowController { + public: + virtual ~ShellAppWindowController() {} + + // Creates a new app window and adds it to the desktop. This class should + // maintain the ownership of the window. + virtual ShellAppWindow* CreateAppWindow(content::BrowserContext* context) = 0; + + // Closes and destroys the app windows. + virtual void CloseAppWindows() = 0; +}; + +} // namespace apps + +#endif // APPS_SHELL_BROWSER_SHELL_APP_WINDOW_CONTROLLER_H_ diff --git a/apps/shell/browser/shell_browser_main_parts.cc b/apps/shell/browser/shell_browser_main_parts.cc index 3dbfb7c06f..7c1d2938a1 100644 --- a/apps/shell/browser/shell_browser_main_parts.cc +++ b/apps/shell/browser/shell_browser_main_parts.cc @@ -19,6 +19,7 @@ #include "extensions/browser/browser_context_keyed_service_factories.h" #include "extensions/browser/extension_system.h" #include "ui/aura/window_tree_host.h" +#include "ui/base/ime/input_method_initializer.h" #include "ui/base/resource/resource_bundle.h" #if defined(OS_CHROMEOS) @@ -64,6 +65,9 @@ void ShellBrowserMainParts::PostMainMessageLoopStart() { #if defined(OS_CHROMEOS) chromeos::DBusThreadManager::Initialize(); network_controller_.reset(new ShellNetworkController); +#else + // Non-Chrome OS platforms are for developer convenience, so use a test IME. + ui::InitializeInputMethodForTesting(); #endif } diff --git a/apps/shell/browser/shell_desktop_controller.cc b/apps/shell/browser/shell_desktop_controller.cc index 396758f6dd..2db85b792b 100644 --- a/apps/shell/browser/shell_desktop_controller.cc +++ b/apps/shell/browser/shell_desktop_controller.cc @@ -4,7 +4,7 @@ #include "apps/shell/browser/shell_desktop_controller.h" -#include "apps/shell/browser/shell_app_window.h" +#include "apps/shell/browser/shell_app_window_controller.h" #include "content/public/browser/context_factory.h" #include "ui/aura/client/cursor_client.h" #include "ui/aura/client/default_capture_client.h" @@ -173,8 +173,7 @@ ShellDesktopController::ShellDesktopController() { } ShellDesktopController::~ShellDesktopController() { - // The app window must be explicitly closed before desktop teardown. - DCHECK(!app_window_); + app_window_controller_.reset(); g_instance = NULL; DestroyRootWindow(); aura::Env::DeleteInstance(); @@ -185,22 +184,20 @@ ShellDesktopController* ShellDesktopController::instance() { return g_instance; } +void ShellDesktopController::SetAppWindowController( + ShellAppWindowController* app_window_controller) { + app_window_controller_.reset(app_window_controller); +} + ShellAppWindow* ShellDesktopController::CreateAppWindow( content::BrowserContext* context) { - aura::Window* root_window = host_->window(); - - app_window_.reset(new ShellAppWindow); - app_window_->Init(context, root_window->bounds().size()); - - // Attach the web contents view to our window hierarchy. - aura::Window* content = app_window_->GetNativeWindow(); - root_window->AddChild(content); - content->Show(); - - return app_window_.get(); + return app_window_controller_->CreateAppWindow(context); } -void ShellDesktopController::CloseAppWindow() { app_window_.reset(); } +void ShellDesktopController::CloseAppWindows() { + if (app_window_controller_) + app_window_controller_->CloseAppWindows(); +} aura::Window* ShellDesktopController::GetDefaultParent( aura::Window* context, @@ -221,7 +218,7 @@ void ShellDesktopController::OnDisplayModeChanged( void ShellDesktopController::OnHostCloseRequested( const aura::WindowTreeHost* host) { DCHECK_EQ(host_.get(), host); - CloseAppWindow(); + CloseAppWindows(); base::MessageLoop::current()->PostTask(FROM_HERE, base::MessageLoop::QuitClosure()); } @@ -235,7 +232,7 @@ void ShellDesktopController::CreateRootWindow() { // Set up basic pieces of ui::wm. gfx::Size size = GetPrimaryDisplaySize(); if (size.IsEmpty()) - size = gfx::Size(800, 600); + size = gfx::Size(1366, 768); host_.reset(aura::WindowTreeHost::Create(gfx::Rect(size))); host_->InitHost(); diff --git a/apps/shell/browser/shell_desktop_controller.h b/apps/shell/browser/shell_desktop_controller.h index 2c5b846367..ebededfc59 100644 --- a/apps/shell/browser/shell_desktop_controller.h +++ b/apps/shell/browser/shell_desktop_controller.h @@ -49,6 +49,7 @@ class UserActivityDetector; namespace apps { class ShellAppWindow; +class ShellAppWindowController; // Handles desktop-related tasks for app_shell. class ShellDesktopController : public aura::client::WindowTreeClient, @@ -72,12 +73,16 @@ class ShellDesktopController : public aura::client::WindowTreeClient, // Creates the window that hosts the app. void CreateRootWindow(); + // Sets the controller to create/close the app windows. Takes the ownership of + // |app_window_controller|. + void SetAppWindowController(ShellAppWindowController* app_window_controller); + // Creates a new app window and adds it to the desktop. The desktop maintains // ownership of the window. ShellAppWindow* CreateAppWindow(content::BrowserContext* context); - // Closes and destroys the app window. - void CloseAppWindow(); + // Closes and destroys the app windows. + void CloseAppWindows(); // Overridden from aura::client::WindowTreeClient: virtual aura::Window* GetDefaultParent(aura::Window* context, @@ -130,7 +135,7 @@ class ShellDesktopController : public aura::client::WindowTreeClient, #endif // The desktop supports a single app window. - scoped_ptr<ShellAppWindow> app_window_; + scoped_ptr<ShellAppWindowController> app_window_controller_; DISALLOW_COPY_AND_ASSIGN(ShellDesktopController); }; diff --git a/apps/shell/browser/shell_extension_system.cc b/apps/shell/browser/shell_extension_system.cc index 7d56884fcf..3d2cbc5d34 100644 --- a/apps/shell/browser/shell_extension_system.cc +++ b/apps/shell/browser/shell_extension_system.cc @@ -37,21 +37,21 @@ ShellExtensionSystem::ShellExtensionSystem(BrowserContext* browser_context) ShellExtensionSystem::~ShellExtensionSystem() { } -bool ShellExtensionSystem::LoadAndLaunchApp(const base::FilePath& app_dir) { +bool ShellExtensionSystem::LoadApp(const base::FilePath& app_dir) { // app_shell only supports unpacked extensions. // NOTE: If you add packed extension support consider removing the flag // FOLLOW_SYMLINKS_ANYWHERE below. Packed extensions should not have symlinks. CHECK(base::DirectoryExists(app_dir)) << app_dir.AsUTF8Unsafe(); int load_flags = Extension::FOLLOW_SYMLINKS_ANYWHERE; std::string load_error; - scoped_refptr<Extension> extension = file_util::LoadExtension( + extension_ = file_util::LoadExtension( app_dir, Manifest::COMMAND_LINE, load_flags, &load_error); - if (!extension) { + if (!extension_) { LOG(ERROR) << "Loading extension at " << app_dir.value() << " failed with: " << load_error; return false; } - app_id_ = extension->id(); + app_id_ = extension_->id(); // TODO(jamescook): We may want to do some of these things here: // * Create a PermissionsUpdater. @@ -60,14 +60,14 @@ bool ShellExtensionSystem::LoadAndLaunchApp(const base::FilePath& app_dir) { // * Call ExtensionPrefs::OnExtensionInstalled(). // * Send NOTIFICATION_EXTENSION_INSTALLED_DEPRECATED. - ExtensionRegistry::Get(browser_context_)->AddEnabled(extension); + ExtensionRegistry::Get(browser_context_)->AddEnabled(extension_); - RegisterExtensionWithRequestContexts(extension); + RegisterExtensionWithRequestContexts(extension_); content::NotificationService::current()->Notify( chrome::NOTIFICATION_EXTENSION_LOADED_DEPRECATED, content::Source<BrowserContext>(browser_context_), - content::Details<const Extension>(extension)); + content::Details<const Extension>(extension_)); // Inform the rest of the extensions system to start. ready_.Signal(); @@ -75,11 +75,14 @@ bool ShellExtensionSystem::LoadAndLaunchApp(const base::FilePath& app_dir) { chrome::NOTIFICATION_EXTENSIONS_READY, content::Source<BrowserContext>(browser_context_), content::NotificationService::NoDetails()); + return true; +} +void ShellExtensionSystem::LaunchApp() { // Send the onLaunched event. - apps::ShellAPI::DispatchOnLaunchedEvent(event_router_.get(), extension.get()); - - return true; + DCHECK(extension_.get()); + apps::ShellAPI::DispatchOnLaunchedEvent(event_router_.get(), + extension_.get()); } void ShellExtensionSystem::Shutdown() { @@ -180,4 +183,10 @@ ContentVerifier* ShellExtensionSystem::content_verifier() { return NULL; } +scoped_ptr<ExtensionSet> ShellExtensionSystem::GetDependentExtensions( + const Extension* extension) { + scoped_ptr<ExtensionSet> empty(new ExtensionSet()); + return empty.PassAs<ExtensionSet>(); +} + } // namespace extensions diff --git a/apps/shell/browser/shell_extension_system.h b/apps/shell/browser/shell_extension_system.h index a287d2d1fb..c451eddda5 100644 --- a/apps/shell/browser/shell_extension_system.h +++ b/apps/shell/browser/shell_extension_system.h @@ -36,13 +36,17 @@ class ShellExtensionSystem : public ExtensionSystem { explicit ShellExtensionSystem(content::BrowserContext* browser_context); virtual ~ShellExtensionSystem(); - // Loads an unpacked application from a directory and attempts to launch it. - // Returns true on success. - bool LoadAndLaunchApp(const base::FilePath& app_dir); + // Loads an unpacked application from a directory. Returns true on success. + bool LoadApp(const base::FilePath& app_dir); + + // Launch the currently loaded app. + void LaunchApp(); // KeyedService implementation: virtual void Shutdown() OVERRIDE; + scoped_refptr<Extension> extension() { return extension_; } + // ExtensionSystem implementation: virtual void InitForRegularProfile(bool extensions_enabled) OVERRIDE; virtual ExtensionService* extension_service() OVERRIDE; @@ -68,6 +72,8 @@ class ShellExtensionSystem : public ExtensionSystem { const UnloadedExtensionInfo::Reason reason) OVERRIDE; virtual const OneShotEvent& ready() const OVERRIDE; virtual ContentVerifier* content_verifier() OVERRIDE; + virtual scoped_ptr<ExtensionSet> GetDependentExtensions( + const Extension* extension) OVERRIDE; private: content::BrowserContext* browser_context_; // Not owned. @@ -75,6 +81,8 @@ class ShellExtensionSystem : public ExtensionSystem { // Extension ID for the app. std::string app_id_; + scoped_refptr<Extension> extension_; + // Data to be accessed on the IO thread. Must outlive process_manager_. scoped_refptr<InfoMap> info_map_; diff --git a/apps/shell/browser/shell_network_controller_chromeos.cc b/apps/shell/browser/shell_network_controller_chromeos.cc index 4280765930..e1bf209fec 100644 --- a/apps/shell/browser/shell_network_controller_chromeos.cc +++ b/apps/shell/browser/shell_network_controller_chromeos.cc @@ -125,7 +125,7 @@ void ShellNetworkController::ConnectIfUnconnected() { return; chromeos::NetworkStateHandler::NetworkStateList state_list; - handler->network_state_handler()->GetNetworkListByType( + handler->network_state_handler()->GetVisibleNetworkListByType( chromeos::NetworkTypePattern::WiFi(), &state_list); for (chromeos::NetworkStateHandler::NetworkStateList::const_iterator it = state_list.begin(); it != state_list.end(); ++it) { diff --git a/apps/shell/renderer/shell_content_renderer_client.cc b/apps/shell/renderer/shell_content_renderer_client.cc index e0217fd2c7..70e0698ce5 100644 --- a/apps/shell/renderer/shell_content_renderer_client.cc +++ b/apps/shell/renderer/shell_content_renderer_client.cc @@ -7,6 +7,7 @@ #include "apps/shell/common/shell_extensions_client.h" #include "apps/shell/renderer/shell_dispatcher_delegate.h" #include "apps/shell/renderer/shell_extensions_renderer_client.h" +#include "apps/shell/renderer/shell_renderer_main_delegate.h" #include "content/public/renderer/render_frame.h" #include "content/public/renderer/render_frame_observer.h" #include "content/public/renderer/render_frame_observer_tracker.h" @@ -58,7 +59,10 @@ void ShellFrameHelper::WillReleaseScriptContext(v8::Handle<v8::Context> context, } // namespace -ShellContentRendererClient::ShellContentRendererClient() {} +ShellContentRendererClient::ShellContentRendererClient( + scoped_ptr<ShellRendererMainDelegate> delegate) + : delegate_(delegate.Pass()) { +} ShellContentRendererClient::~ShellContentRendererClient() {} @@ -80,6 +84,8 @@ void ShellContentRendererClient::RenderThreadStarted() { // TODO(jamescook): Init WebSecurityPolicy for chrome-extension: schemes. // See ChromeContentRendererClient for details. + if (delegate_) + delegate_->OnThreadStarted(thread); } void ShellContentRendererClient::RenderFrameCreated( @@ -91,6 +97,8 @@ void ShellContentRendererClient::RenderFrameCreated( void ShellContentRendererClient::RenderViewCreated( content::RenderView* render_view) { new extensions::ExtensionHelper(render_view, extension_dispatcher_.get()); + if (delegate_) + delegate_->OnViewCreated(render_view); } bool ShellContentRendererClient::WillSendRequest( diff --git a/apps/shell/renderer/shell_content_renderer_client.h b/apps/shell/renderer/shell_content_renderer_client.h index 506704c693..9f7aee2e22 100644 --- a/apps/shell/renderer/shell_content_renderer_client.h +++ b/apps/shell/renderer/shell_content_renderer_client.h @@ -19,11 +19,13 @@ namespace apps { class ShellExtensionsClient; class ShellExtensionsRendererClient; +class ShellRendererMainDelegate; // Renderer initialization and runtime support for app_shell. class ShellContentRendererClient : public content::ContentRendererClient { public: - ShellContentRendererClient(); + explicit ShellContentRendererClient( + scoped_ptr<ShellRendererMainDelegate> delegate); virtual ~ShellContentRendererClient(); // content::ContentRendererClient implementation: @@ -42,6 +44,7 @@ class ShellContentRendererClient : public content::ContentRendererClient { virtual bool ShouldEnableSiteIsolationPolicy() const OVERRIDE; private: + scoped_ptr<ShellRendererMainDelegate> delegate_; scoped_ptr<ShellExtensionsClient> extensions_client_; scoped_ptr<ShellExtensionsRendererClient> extensions_renderer_client_; scoped_ptr<extensions::DispatcherDelegate> extension_dispatcher_delegate_; diff --git a/apps/shell/renderer/shell_renderer_main_delegate.h b/apps/shell/renderer/shell_renderer_main_delegate.h new file mode 100644 index 0000000000..604b6c7288 --- /dev/null +++ b/apps/shell/renderer/shell_renderer_main_delegate.h @@ -0,0 +1,30 @@ +// Copyright 2014 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 APPS_SHELL_RENDERER_SHELL_RENDERER_MAIN_DELEGATE_H_ +#define APPS_SHELL_RENDERER_SHELL_RENDERER_MAIN_DELEGATE_H_ + +namespace content { +class RenderThread; +class RenderView; +} + +namespace apps { + +class ShellRendererMainDelegate { + public: + virtual ~ShellRendererMainDelegate() {} + + // Called when |thread| is started, after the extensions subsystem has been + // initialized for |thread|. + virtual void OnThreadStarted(content::RenderThread* thread) = 0; + + // Called for each RenderView created in the renderer process, after the + // extension related code has been initialized for the view. + virtual void OnViewCreated(content::RenderView* view) = 0; +}; + +} // namespace apps + +#endif // APPS_SHELL_RENDERER_SHELL_RENDERER_MAIN_DELEGATE_H_ diff --git a/apps/shell/test/shell_test.cc b/apps/shell/test/shell_test.cc index 3d2cfeec0d..c5ca5df71a 100644 --- a/apps/shell/test/shell_test.cc +++ b/apps/shell/test/shell_test.cc @@ -43,11 +43,14 @@ void AppShellTest::RunTestOnMainThreadLoop() { TearDownOnMainThread(); // Clean up the app window. - ShellDesktopController::instance()->CloseAppWindow(); + ShellDesktopController::instance()->CloseAppWindows(); } bool AppShellTest::LoadAndLaunchApp(const base::FilePath& app_dir) { - return extension_system_->LoadAndLaunchApp(app_dir); + bool loaded = extension_system_->LoadApp(app_dir); + if (loaded) + extension_system_->LaunchApp(); + return loaded; } } // namespace apps |