Home | History | Annotate | Download | only in apps
      1 // Copyright 2013 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "apps/launcher.h"
      6 #include "apps/shell_window.h"
      7 #include "apps/shell_window_registry.h"
      8 #include "apps/ui/native_app_window.h"
      9 #include "base/bind.h"
     10 #include "base/command_line.h"
     11 #include "base/file_util.h"
     12 #include "base/files/scoped_temp_dir.h"
     13 #include "base/prefs/pref_service.h"
     14 #include "base/stl_util.h"
     15 #include "base/strings/utf_string_conversions.h"
     16 #include "chrome/app/chrome_command_ids.h"
     17 #include "chrome/browser/apps/app_browsertest_util.h"
     18 #include "chrome/browser/automation/automation_util.h"
     19 #include "chrome/browser/chrome_notification_types.h"
     20 #include "chrome/browser/devtools/devtools_window.h"
     21 #include "chrome/browser/extensions/api/permissions/permissions_api.h"
     22 #include "chrome/browser/extensions/component_loader.h"
     23 #include "chrome/browser/extensions/extension_browsertest.h"
     24 #include "chrome/browser/extensions/extension_service.h"
     25 #include "chrome/browser/extensions/extension_system.h"
     26 #include "chrome/browser/extensions/extension_test_message_listener.h"
     27 #include "chrome/browser/tab_contents/render_view_context_menu.h"
     28 #include "chrome/browser/ui/browser.h"
     29 #include "chrome/browser/ui/extensions/application_launch.h"
     30 #include "chrome/browser/ui/tabs/tab_strip_model.h"
     31 #include "chrome/browser/ui/webui/print_preview/print_preview_ui.h"
     32 #include "chrome/common/chrome_switches.h"
     33 #include "chrome/common/extensions/api/app_runtime.h"
     34 #include "chrome/common/pref_names.h"
     35 #include "chrome/common/url_constants.h"
     36 #include "chrome/test/base/test_switches.h"
     37 #include "chrome/test/base/ui_test_utils.h"
     38 #include "components/user_prefs/pref_registry_syncable.h"
     39 #include "components/web_modal/web_contents_modal_dialog_manager.h"
     40 #include "content/public/browser/devtools_agent_host.h"
     41 #include "content/public/browser/render_process_host.h"
     42 #include "content/public/browser/render_widget_host_view.h"
     43 #include "content/public/browser/web_contents_view.h"
     44 #include "content/public/test/test_utils.h"
     45 #include "extensions/browser/event_router.h"
     46 #include "net/test/embedded_test_server/embedded_test_server.h"
     47 #include "url/gurl.h"
     48 
     49 #if defined(OS_CHROMEOS)
     50 #include "base/memory/scoped_ptr.h"
     51 #include "chrome/browser/chromeos/login/mock_user_manager.h"
     52 #include "chrome/browser/chromeos/login/user_manager.h"
     53 #include "chromeos/dbus/dbus_thread_manager.h"
     54 #include "chromeos/dbus/fake_dbus_thread_manager.h"
     55 #include "chromeos/dbus/fake_power_manager_client.h"
     56 #endif
     57 
     58 using apps::ShellWindow;
     59 using apps::ShellWindowRegistry;
     60 using content::WebContents;
     61 using web_modal::WebContentsModalDialogManager;
     62 
     63 namespace extensions {
     64 
     65 namespace app_runtime = api::app_runtime;
     66 
     67 namespace {
     68 
     69 // Non-abstract RenderViewContextMenu class.
     70 class PlatformAppContextMenu : public RenderViewContextMenu {
     71  public:
     72   PlatformAppContextMenu(WebContents* web_contents,
     73                          const content::ContextMenuParams& params)
     74       : RenderViewContextMenu(web_contents, params) {}
     75 
     76   bool HasCommandWithId(int command_id) {
     77     return menu_model_.GetIndexOfCommandId(command_id) != -1;
     78   }
     79 
     80  protected:
     81   // RenderViewContextMenu implementation.
     82   virtual bool GetAcceleratorForCommandId(
     83       int command_id,
     84       ui::Accelerator* accelerator) OVERRIDE {
     85     return false;
     86   }
     87   virtual void PlatformInit() OVERRIDE {}
     88   virtual void PlatformCancel() OVERRIDE {}
     89 };
     90 
     91 // This class keeps track of tabs as they are added to the browser. It will be
     92 // "done" (i.e. won't block on Wait()) once |observations| tabs have been added.
     93 class TabsAddedNotificationObserver
     94     : public content::WindowedNotificationObserver {
     95  public:
     96   explicit TabsAddedNotificationObserver(size_t observations)
     97       : content::WindowedNotificationObserver(
     98             chrome::NOTIFICATION_TAB_ADDED,
     99             content::NotificationService::AllSources()),
    100         observations_(observations) {
    101   }
    102 
    103   virtual void Observe(int type,
    104                        const content::NotificationSource& source,
    105                        const content::NotificationDetails& details) OVERRIDE {
    106     observed_tabs_.push_back(
    107         content::Details<WebContents>(details).ptr());
    108     if (observed_tabs_.size() == observations_)
    109       content::WindowedNotificationObserver::Observe(type, source, details);
    110   }
    111 
    112   const std::vector<content::WebContents*>& tabs() { return observed_tabs_; }
    113 
    114  private:
    115   size_t observations_;
    116   std::vector<content::WebContents*> observed_tabs_;
    117 
    118   DISALLOW_COPY_AND_ASSIGN(TabsAddedNotificationObserver);
    119 };
    120 
    121 class ScopedPreviewTestingDelegate : PrintPreviewUI::TestingDelegate {
    122  public:
    123   explicit ScopedPreviewTestingDelegate(bool auto_cancel)
    124       : auto_cancel_(auto_cancel),
    125         total_page_count_(1),
    126         rendered_page_count_(0) {
    127     PrintPreviewUI::SetDelegateForTesting(this);
    128   }
    129 
    130   ~ScopedPreviewTestingDelegate() {
    131     PrintPreviewUI::SetDelegateForTesting(NULL);
    132   }
    133 
    134   // PrintPreviewUI::TestingDelegate implementation.
    135   virtual bool IsAutoCancelEnabled() OVERRIDE {
    136     return auto_cancel_;
    137   }
    138 
    139   // PrintPreviewUI::TestingDelegate implementation.
    140   virtual void DidGetPreviewPageCount(int page_count) OVERRIDE {
    141     total_page_count_ = page_count;
    142   }
    143 
    144   // PrintPreviewUI::TestingDelegate implementation.
    145   virtual void DidRenderPreviewPage(const content::WebContents& preview_dialog)
    146       OVERRIDE {
    147     dialog_size_ = preview_dialog.GetView()->GetContainerSize();
    148     ++rendered_page_count_;
    149     CHECK(rendered_page_count_ <= total_page_count_);
    150     if (waiting_runner_ && rendered_page_count_ == total_page_count_) {
    151       waiting_runner_->Quit();
    152     }
    153   }
    154 
    155   void WaitUntilPreviewIsReady() {
    156     CHECK(!waiting_runner_);
    157     if (rendered_page_count_ < total_page_count_) {
    158       waiting_runner_ = new content::MessageLoopRunner;
    159       waiting_runner_->Run();
    160       waiting_runner_ = NULL;
    161     }
    162   }
    163 
    164   gfx::Size dialog_size() {
    165     return dialog_size_;
    166   }
    167 
    168  private:
    169   bool auto_cancel_;
    170   int total_page_count_;
    171   int rendered_page_count_;
    172   scoped_refptr<content::MessageLoopRunner> waiting_runner_;
    173   gfx::Size dialog_size_;
    174 };
    175 
    176 #if !defined(OS_CHROMEOS) && !defined(OS_WIN)
    177 bool CopyTestDataAndSetCommandLineArg(
    178     const base::FilePath& test_data_file,
    179     const base::FilePath& temp_dir,
    180     const char* filename) {
    181   base::FilePath path = temp_dir.AppendASCII(
    182       filename).NormalizePathSeparators();
    183   if (!(base::CopyFile(test_data_file, path)))
    184     return false;
    185 
    186   CommandLine* command_line = CommandLine::ForCurrentProcess();
    187   command_line->AppendArgPath(path);
    188   return true;
    189 }
    190 #endif  // !defined(OS_CHROMEOS) && !defined(OS_WIN)
    191 
    192 #if !defined(OS_CHROMEOS)
    193 const char kTestFilePath[] = "platform_apps/launch_files/test.txt";
    194 #endif
    195 
    196 }  // namespace
    197 
    198 // Tests that CreateShellWindow doesn't crash if you close it straight away.
    199 // LauncherPlatformAppBrowserTest relies on this behaviour, but is only run for
    200 // ash, so we test that it works here.
    201 IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, CreateAndCloseShellWindow) {
    202   const Extension* extension = LoadAndLaunchPlatformApp("minimal");
    203   ShellWindow* window = CreateShellWindow(extension);
    204   CloseShellWindow(window);
    205 }
    206 
    207 // Tests that platform apps received the "launch" event when launched.
    208 IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, OnLaunchedEvent) {
    209   ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch")) << message_;
    210 }
    211 
    212 // Tests that platform apps cannot use certain disabled window properties, but
    213 // can override them and then use them.
    214 IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, DisabledWindowProperties) {
    215   ASSERT_TRUE(RunPlatformAppTest("platform_apps/disabled_window_properties"))
    216       << message_;
    217 }
    218 
    219 IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, EmptyContextMenu) {
    220   ExtensionTestMessageListener launched_listener("Launched", false);
    221   LoadAndLaunchPlatformApp("minimal");
    222 
    223   ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
    224 
    225   // The empty app doesn't add any context menu items, so its menu should
    226   // only include the developer tools.
    227   WebContents* web_contents = GetFirstShellWindowWebContents();
    228   ASSERT_TRUE(web_contents);
    229   content::ContextMenuParams params;
    230   scoped_ptr<PlatformAppContextMenu> menu;
    231   menu.reset(new PlatformAppContextMenu(web_contents, params));
    232   menu->Init();
    233   ASSERT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_INSPECTELEMENT));
    234   ASSERT_TRUE(
    235       menu->HasCommandWithId(IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE));
    236   ASSERT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP));
    237   ASSERT_FALSE(menu->HasCommandWithId(IDC_BACK));
    238   ASSERT_FALSE(menu->HasCommandWithId(IDC_SAVE_PAGE));
    239 }
    240 
    241 IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, AppWithContextMenu) {
    242   ExtensionTestMessageListener launched_listener("Launched", false);
    243   LoadAndLaunchPlatformApp("context_menu");
    244 
    245   // Wait for the extension to tell us it's initialized its context menus and
    246   // launched a window.
    247   ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
    248 
    249   // The context_menu app has two context menu items. These, along with a
    250   // separator and the developer tools, is all that should be in the menu.
    251   WebContents* web_contents = GetFirstShellWindowWebContents();
    252   ASSERT_TRUE(web_contents);
    253   content::ContextMenuParams params;
    254   scoped_ptr<PlatformAppContextMenu> menu;
    255   menu.reset(new PlatformAppContextMenu(web_contents, params));
    256   menu->Init();
    257   ASSERT_TRUE(menu->HasCommandWithId(IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST));
    258   ASSERT_TRUE(menu->HasCommandWithId(IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST + 1));
    259   ASSERT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_INSPECTELEMENT));
    260   ASSERT_TRUE(
    261       menu->HasCommandWithId(IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE));
    262   ASSERT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP));
    263   ASSERT_FALSE(menu->HasCommandWithId(IDC_BACK));
    264   ASSERT_FALSE(menu->HasCommandWithId(IDC_SAVE_PAGE));
    265   ASSERT_FALSE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_UNDO));
    266 }
    267 
    268 IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, InstalledAppWithContextMenu) {
    269   ExtensionTestMessageListener launched_listener("Launched", false);
    270   InstallAndLaunchPlatformApp("context_menu");
    271 
    272   // Wait for the extension to tell us it's initialized its context menus and
    273   // launched a window.
    274   ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
    275 
    276   // The context_menu app has two context menu items. For an installed app
    277   // these are all that should be in the menu.
    278   WebContents* web_contents = GetFirstShellWindowWebContents();
    279   ASSERT_TRUE(web_contents);
    280   content::ContextMenuParams params;
    281   scoped_ptr<PlatformAppContextMenu> menu;
    282   menu.reset(new PlatformAppContextMenu(web_contents, params));
    283   menu->Init();
    284   ASSERT_TRUE(menu->HasCommandWithId(IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST));
    285   ASSERT_TRUE(menu->HasCommandWithId(IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST + 1));
    286   ASSERT_FALSE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_INSPECTELEMENT));
    287   ASSERT_FALSE(
    288       menu->HasCommandWithId(IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE));
    289   ASSERT_FALSE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP));
    290   ASSERT_FALSE(menu->HasCommandWithId(IDC_BACK));
    291   ASSERT_FALSE(menu->HasCommandWithId(IDC_SAVE_PAGE));
    292   ASSERT_FALSE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_UNDO));
    293 }
    294 
    295 IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, AppWithContextMenuTextField) {
    296   ExtensionTestMessageListener launched_listener("Launched", false);
    297   LoadAndLaunchPlatformApp("context_menu");
    298 
    299   // Wait for the extension to tell us it's initialized its context menus and
    300   // launched a window.
    301   ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
    302 
    303   // The context_menu app has one context menu item. This, along with a
    304   // separator and the developer tools, is all that should be in the menu.
    305   WebContents* web_contents = GetFirstShellWindowWebContents();
    306   ASSERT_TRUE(web_contents);
    307   content::ContextMenuParams params;
    308   params.is_editable = true;
    309   scoped_ptr<PlatformAppContextMenu> menu;
    310   menu.reset(new PlatformAppContextMenu(web_contents, params));
    311   menu->Init();
    312   ASSERT_TRUE(menu->HasCommandWithId(IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST));
    313   ASSERT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_INSPECTELEMENT));
    314   ASSERT_TRUE(
    315       menu->HasCommandWithId(IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE));
    316   ASSERT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP));
    317   ASSERT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_UNDO));
    318   ASSERT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_COPY));
    319   ASSERT_FALSE(menu->HasCommandWithId(IDC_BACK));
    320   ASSERT_FALSE(menu->HasCommandWithId(IDC_SAVE_PAGE));
    321 }
    322 
    323 IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, AppWithContextMenuSelection) {
    324   ExtensionTestMessageListener launched_listener("Launched", false);
    325   LoadAndLaunchPlatformApp("context_menu");
    326 
    327   // Wait for the extension to tell us it's initialized its context menus and
    328   // launched a window.
    329   ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
    330 
    331   // The context_menu app has one context menu item. This, along with a
    332   // separator and the developer tools, is all that should be in the menu.
    333   WebContents* web_contents = GetFirstShellWindowWebContents();
    334   ASSERT_TRUE(web_contents);
    335   content::ContextMenuParams params;
    336   params.selection_text = ASCIIToUTF16("Hello World");
    337   scoped_ptr<PlatformAppContextMenu> menu;
    338   menu.reset(new PlatformAppContextMenu(web_contents, params));
    339   menu->Init();
    340   ASSERT_TRUE(menu->HasCommandWithId(IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST));
    341   ASSERT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_INSPECTELEMENT));
    342   ASSERT_TRUE(
    343       menu->HasCommandWithId(IDC_CONTENT_CONTEXT_INSPECTBACKGROUNDPAGE));
    344   ASSERT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_RELOAD_PACKAGED_APP));
    345   ASSERT_FALSE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_UNDO));
    346   ASSERT_TRUE(menu->HasCommandWithId(IDC_CONTENT_CONTEXT_COPY));
    347   ASSERT_FALSE(menu->HasCommandWithId(IDC_BACK));
    348   ASSERT_FALSE(menu->HasCommandWithId(IDC_SAVE_PAGE));
    349 }
    350 
    351 IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, AppWithContextMenuClicked) {
    352   ExtensionTestMessageListener launched_listener("Launched", false);
    353   LoadAndLaunchPlatformApp("context_menu_click");
    354 
    355   // Wait for the extension to tell us it's initialized its context menus and
    356   // launched a window.
    357   ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
    358 
    359   // Test that the menu item shows up
    360   WebContents* web_contents = GetFirstShellWindowWebContents();
    361   ASSERT_TRUE(web_contents);
    362   content::ContextMenuParams params;
    363   params.page_url = GURL("http://foo.bar");
    364   scoped_ptr<PlatformAppContextMenu> menu;
    365   menu.reset(new PlatformAppContextMenu(web_contents, params));
    366   menu->Init();
    367   ASSERT_TRUE(menu->HasCommandWithId(IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST));
    368 
    369   // Execute the menu item
    370   ExtensionTestMessageListener onclicked_listener("onClicked fired for id1",
    371                                                   false);
    372   menu->ExecuteCommand(IDC_EXTENSIONS_CONTEXT_CUSTOM_FIRST, 0);
    373 
    374   ASSERT_TRUE(onclicked_listener.WaitUntilSatisfied());
    375 }
    376 
    377 #if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA)
    378 // TODO(erg): linux_aura bringup: http://crbug.com/163931
    379 #define MAYBE_DisallowNavigation DISABLED_DisallowNavigation
    380 #else
    381 #define MAYBE_DisallowNavigation DisallowNavigation
    382 #endif
    383 
    384 IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, MAYBE_DisallowNavigation) {
    385   TabsAddedNotificationObserver observer(2);
    386 
    387   ASSERT_TRUE(StartEmbeddedTestServer());
    388   ASSERT_TRUE(RunPlatformAppTest("platform_apps/navigation")) << message_;
    389 
    390   observer.Wait();
    391   ASSERT_EQ(2U, observer.tabs().size());
    392   EXPECT_EQ(std::string(chrome::kExtensionInvalidRequestURL),
    393             observer.tabs()[0]->GetURL().spec());
    394   EXPECT_EQ("http://chromium.org/",
    395             observer.tabs()[1]->GetURL().spec());
    396 }
    397 
    398 IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, Iframes) {
    399   ASSERT_TRUE(StartEmbeddedTestServer());
    400   ASSERT_TRUE(RunPlatformAppTest("platform_apps/iframes")) << message_;
    401 }
    402 
    403 // Tests that localStorage and WebSQL are disabled for platform apps.
    404 IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, DisallowStorage) {
    405   ASSERT_TRUE(RunPlatformAppTest("platform_apps/storage")) << message_;
    406 }
    407 
    408 IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, Restrictions) {
    409   ASSERT_TRUE(RunPlatformAppTest("platform_apps/restrictions")) << message_;
    410 }
    411 
    412 // Tests that extensions can't use platform-app-only APIs.
    413 IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, PlatformAppsOnly) {
    414   ASSERT_TRUE(RunExtensionTestIgnoreManifestWarnings(
    415       "platform_apps/apps_only")) << message_;
    416 }
    417 
    418 // Tests that platform apps have isolated storage by default.
    419 IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, Isolation) {
    420   ASSERT_TRUE(StartEmbeddedTestServer());
    421 
    422   // Load a (non-app) page under the "localhost" origin that sets a cookie.
    423   GURL set_cookie_url = embedded_test_server()->GetURL(
    424       "/extensions/platform_apps/isolation/set_cookie.html");
    425   GURL::Replacements replace_host;
    426   std::string host_str("localhost");  // Must stay in scope with replace_host.
    427   replace_host.SetHostStr(host_str);
    428   set_cookie_url = set_cookie_url.ReplaceComponents(replace_host);
    429 
    430   ui_test_utils::NavigateToURLWithDisposition(
    431       browser(), set_cookie_url,
    432       CURRENT_TAB, ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
    433 
    434   // Make sure the cookie is set.
    435   int cookie_size;
    436   std::string cookie_value;
    437   automation_util::GetCookies(
    438       set_cookie_url,
    439       browser()->tab_strip_model()->GetWebContentsAt(0),
    440       &cookie_size,
    441       &cookie_value);
    442   ASSERT_EQ("testCookie=1", cookie_value);
    443 
    444   // Let the platform app request the same URL, and make sure that it doesn't
    445   // see the cookie.
    446   ASSERT_TRUE(RunPlatformAppTest("platform_apps/isolation")) << message_;
    447 }
    448 
    449 // See crbug.com/248441
    450 #if defined(OS_WIN)
    451 #define MAYBE_ExtensionWindowingApis DISABLED_ExtensionWindowingApis
    452 #else
    453 #define MAYBE_ExtensionWindowingApis ExtensionWindowingApis
    454 #endif
    455 
    456 IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, MAYBE_ExtensionWindowingApis) {
    457   // Initially there should be just the one browser window visible to the
    458   // extensions API.
    459   const Extension* extension = LoadExtension(
    460       test_data_dir_.AppendASCII("common/background_page"));
    461   ASSERT_EQ(1U, RunGetWindowsFunctionForExtension(extension));
    462 
    463   // And no shell windows.
    464   ASSERT_EQ(0U, GetShellWindowCount());
    465 
    466   // Launch a platform app that shows a window.
    467   ExtensionTestMessageListener launched_listener("Launched", false);
    468   LoadAndLaunchPlatformApp("minimal");
    469   ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
    470   ASSERT_EQ(1U, GetShellWindowCount());
    471   int shell_window_id = GetFirstShellWindow()->session_id().id();
    472 
    473   // But it's not visible to the extensions API, it still thinks there's just
    474   // one browser window.
    475   ASSERT_EQ(1U, RunGetWindowsFunctionForExtension(extension));
    476   // It can't look it up by ID either
    477   ASSERT_FALSE(RunGetWindowFunctionForExtension(shell_window_id, extension));
    478 
    479   // The app can also only see one window (its own).
    480   // TODO(jeremya): add an extension function to get a shell window by ID, and
    481   // to get a list of all the shell windows, so we can test this.
    482 
    483   // Launch another platform app that also shows a window.
    484   ExtensionTestMessageListener launched_listener2("Launched", false);
    485   LoadAndLaunchPlatformApp("context_menu");
    486   ASSERT_TRUE(launched_listener2.WaitUntilSatisfied());
    487 
    488   // There are two total shell windows, but each app can only see its own.
    489   ASSERT_EQ(2U, GetShellWindowCount());
    490   // TODO(jeremya): as above, this requires more extension functions.
    491 }
    492 
    493 // ChromeOS does not support passing arguments on the command line, so the tests
    494 // that rely on this functionality are disabled.
    495 #if !defined(OS_CHROMEOS)
    496 // Tests that command line parameters get passed through to platform apps
    497 // via launchData correctly when launching with a file.
    498 // TODO(benwells/jeremya): tests need a way to specify a handler ID.
    499 IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithFile) {
    500   SetCommandLineArg(kTestFilePath);
    501   ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_file"))
    502       << message_;
    503 }
    504 
    505 // Tests that relative paths can be passed through to the platform app.
    506 // This test doesn't use the normal test infrastructure as it needs to open
    507 // the application differently to all other platform app tests, by setting
    508 // the AppLaunchParams.current_directory field.
    509 IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithRelativeFile) {
    510   // Setup the command line
    511   ClearCommandLineArgs();
    512   CommandLine* command_line = CommandLine::ForCurrentProcess();
    513   base::FilePath relative_test_doc =
    514       base::FilePath::FromUTF8Unsafe(kTestFilePath);
    515   relative_test_doc = relative_test_doc.NormalizePathSeparators();
    516   command_line->AppendArgPath(relative_test_doc);
    517 
    518   // Load the extension
    519   ResultCatcher catcher;
    520   const Extension* extension = LoadExtension(
    521       test_data_dir_.AppendASCII("platform_apps/launch_file"));
    522   ASSERT_TRUE(extension);
    523 
    524   // Run the test
    525   AppLaunchParams params(
    526       browser()->profile(), extension, LAUNCH_CONTAINER_NONE, NEW_WINDOW);
    527   params.command_line = CommandLine::ForCurrentProcess();
    528   params.current_directory = test_data_dir_;
    529   OpenApplication(params);
    530 
    531   if (!catcher.GetNextResult()) {
    532     message_ = catcher.message();
    533     ASSERT_TRUE(0);
    534   }
    535 }
    536 
    537 // Tests that launch data is sent through if the file extension matches.
    538 IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithFileExtension) {
    539   SetCommandLineArg(kTestFilePath);
    540   ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_file_by_extension"))
    541       << message_;
    542 }
    543 
    544 #if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA)
    545 // TODO(erg): linux_aura bringup: http://crbug.com/163931
    546 #define MAYBE_LaunchWithFileExtensionAndMimeType DISABLED_LaunchWithFileExtensionAndMimeType
    547 #else
    548 #define MAYBE_LaunchWithFileExtensionAndMimeType LaunchWithFileExtensionAndMimeType
    549 #endif
    550 
    551 // Tests that launch data is sent through if the file extension and MIME type
    552 // both match.
    553 IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest,
    554                        MAYBE_LaunchWithFileExtensionAndMimeType) {
    555   SetCommandLineArg(kTestFilePath);
    556   ASSERT_TRUE(RunPlatformAppTest(
    557       "platform_apps/launch_file_by_extension_and_type")) << message_;
    558 }
    559 
    560 // Tests that launch data is sent through for a file with no extension if a
    561 // handler accepts "".
    562 IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithFileWithoutExtension) {
    563   SetCommandLineArg("platform_apps/launch_files/test");
    564   ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_file_with_no_extension"))
    565       << message_;
    566 }
    567 
    568 #if !defined(OS_WIN)
    569 // Tests that launch data is sent through for a file with an empty extension if
    570 // a handler accepts "".
    571 IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithFileEmptyExtension) {
    572   base::ScopedTempDir temp_dir;
    573   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
    574   ClearCommandLineArgs();
    575   ASSERT_TRUE(CopyTestDataAndSetCommandLineArg(
    576       test_data_dir_.AppendASCII(kTestFilePath),
    577       temp_dir.path(),
    578       "test."));
    579   ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_file_with_no_extension"))
    580       << message_;
    581 }
    582 
    583 // Tests that launch data is sent through for a file with an empty extension if
    584 // a handler accepts *.
    585 IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest,
    586                        LaunchWithFileEmptyExtensionAcceptAny) {
    587   base::ScopedTempDir temp_dir;
    588   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
    589   ClearCommandLineArgs();
    590   ASSERT_TRUE(CopyTestDataAndSetCommandLineArg(
    591       test_data_dir_.AppendASCII(kTestFilePath),
    592       temp_dir.path(),
    593       "test."));
    594   ASSERT_TRUE(RunPlatformAppTest(
    595       "platform_apps/launch_file_with_any_extension")) << message_;
    596 }
    597 #endif
    598 
    599 // Tests that launch data is sent through for a file with no extension if a
    600 // handler accepts *.
    601 IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest,
    602                        LaunchWithFileWithoutExtensionAcceptAny) {
    603   SetCommandLineArg("platform_apps/launch_files/test");
    604   ASSERT_TRUE(RunPlatformAppTest(
    605       "platform_apps/launch_file_with_any_extension")) << message_;
    606 }
    607 
    608 // Tests that launch data is sent through for a file with an extension if a
    609 // handler accepts *.
    610 IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest,
    611                        LaunchWithFileAcceptAnyExtension) {
    612   SetCommandLineArg(kTestFilePath);
    613   ASSERT_TRUE(RunPlatformAppTest(
    614       "platform_apps/launch_file_with_any_extension")) << message_;
    615 }
    616 
    617 // Tests that no launch data is sent through if the file has the wrong
    618 // extension.
    619 IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithWrongExtension) {
    620   SetCommandLineArg(kTestFilePath);
    621   ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_wrong_extension"))
    622       << message_;
    623 }
    624 
    625 // Tests that no launch data is sent through if the file has no extension but
    626 // the handler requires a specific extension.
    627 IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithWrongEmptyExtension) {
    628   SetCommandLineArg("platform_apps/launch_files/test");
    629   ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_wrong_extension"))
    630       << message_;
    631 }
    632 
    633 // Tests that no launch data is sent through if the file is of the wrong MIME
    634 // type.
    635 IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithWrongType) {
    636   SetCommandLineArg(kTestFilePath);
    637   ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_wrong_type"))
    638       << message_;
    639 }
    640 
    641 // Tests that no launch data is sent through if the platform app does not
    642 // provide an intent.
    643 IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithNoIntent) {
    644   SetCommandLineArg(kTestFilePath);
    645   ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_no_intent"))
    646       << message_;
    647 }
    648 
    649 // Tests that launch data is sent through with the MIME type set to
    650 // application/octet-stream if the file MIME type cannot be read.
    651 IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchNoType) {
    652   SetCommandLineArg("platform_apps/launch_files/test.unknownextension");
    653   ASSERT_TRUE(RunPlatformAppTest(
    654       "platform_apps/launch_application_octet_stream")) << message_;
    655 }
    656 
    657 // Tests that no launch data is sent through if the file does not exist.
    658 IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchNoFile) {
    659   SetCommandLineArg("platform_apps/launch_files/doesnotexist.txt");
    660   ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_invalid"))
    661       << message_;
    662 }
    663 
    664 // Tests that no launch data is sent through if the argument is a directory.
    665 IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithDirectory) {
    666   SetCommandLineArg("platform_apps/launch_files");
    667   ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_invalid"))
    668       << message_;
    669 }
    670 
    671 // Tests that no launch data is sent through if there are no arguments passed
    672 // on the command line
    673 IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchWithNothing) {
    674   ClearCommandLineArgs();
    675   ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_nothing"))
    676       << message_;
    677 }
    678 
    679 // Test that platform apps can use the chrome.fileSystem.getDisplayPath
    680 // function to get the native file system path of a file they are launched with.
    681 IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, GetDisplayPath) {
    682   SetCommandLineArg(kTestFilePath);
    683   ASSERT_TRUE(RunPlatformAppTest("platform_apps/get_display_path"))
    684       << message_;
    685 }
    686 
    687 // Tests that the file is created if the file does not exist and the app has the
    688 // fileSystem.write permission.
    689 IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, LaunchNewFile) {
    690   base::ScopedTempDir temp_dir;
    691   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
    692   ClearCommandLineArgs();
    693   CommandLine* command_line = CommandLine::ForCurrentProcess();
    694   command_line->AppendArgPath(temp_dir.path().AppendASCII("new_file.txt"));
    695   ASSERT_TRUE(RunPlatformAppTest("platform_apps/launch_new_file")) << message_;
    696 }
    697 
    698 #endif  // !defined(OS_CHROMEOS)
    699 
    700 IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, OpenLink) {
    701   ASSERT_TRUE(StartEmbeddedTestServer());
    702   content::WindowedNotificationObserver observer(
    703       chrome::NOTIFICATION_TAB_ADDED,
    704       content::Source<content::WebContentsDelegate>(browser()));
    705   LoadAndLaunchPlatformApp("open_link");
    706   observer.Wait();
    707   ASSERT_EQ(2, browser()->tab_strip_model()->count());
    708 }
    709 
    710 IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, MutationEventsDisabled) {
    711   ASSERT_TRUE(RunPlatformAppTest("platform_apps/mutation_events")) << message_;
    712 }
    713 
    714 // This appears to be unreliable on linux.
    715 // TODO(stevenjb): Investigate and enable
    716 #if defined(OS_LINUX) && !defined(USE_ASH)
    717 #define MAYBE_ShellWindowRestoreState DISABLED_ShellWindowRestoreState
    718 #else
    719 #define MAYBE_ShellWindowRestoreState ShellWindowRestoreState
    720 #endif
    721 IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest,
    722                        MAYBE_ShellWindowRestoreState) {
    723   ASSERT_TRUE(RunPlatformAppTest("platform_apps/restore_state"));
    724 }
    725 
    726 IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest,
    727                        ShellWindowAdjustBoundsToBeVisibleOnScreen) {
    728   const Extension* extension = LoadAndLaunchPlatformApp("minimal");
    729   ShellWindow* window = CreateShellWindow(extension);
    730 
    731   // The screen bounds didn't change, the cached bounds didn't need to adjust.
    732   gfx::Rect cached_bounds(80, 100, 400, 400);
    733   gfx::Rect cached_screen_bounds(0, 0, 1600, 900);
    734   gfx::Rect current_screen_bounds(0, 0, 1600, 900);
    735   gfx::Size minimum_size(200, 200);
    736   gfx::Rect bounds;
    737   CallAdjustBoundsToBeVisibleOnScreenForShellWindow(window,
    738                                                     cached_bounds,
    739                                                     cached_screen_bounds,
    740                                                     current_screen_bounds,
    741                                                     minimum_size,
    742                                                     &bounds);
    743   EXPECT_EQ(bounds, cached_bounds);
    744 
    745   // We have an empty screen bounds, the cached bounds didn't need to adjust.
    746   gfx::Rect empty_screen_bounds;
    747   CallAdjustBoundsToBeVisibleOnScreenForShellWindow(window,
    748                                                     cached_bounds,
    749                                                     empty_screen_bounds,
    750                                                     current_screen_bounds,
    751                                                     minimum_size,
    752                                                     &bounds);
    753   EXPECT_EQ(bounds, cached_bounds);
    754 
    755   // Cached bounds is completely off the new screen bounds in horizontal
    756   // locations. Expect to reposition the bounds.
    757   gfx::Rect horizontal_out_of_screen_bounds(-800, 100, 400, 400);
    758   CallAdjustBoundsToBeVisibleOnScreenForShellWindow(
    759       window,
    760       horizontal_out_of_screen_bounds,
    761       gfx::Rect(-1366, 0, 1600, 900),
    762       current_screen_bounds,
    763       minimum_size,
    764       &bounds);
    765   EXPECT_EQ(bounds, gfx::Rect(0, 100, 400, 400));
    766 
    767   // Cached bounds is completely off the new screen bounds in vertical
    768   // locations. Expect to reposition the bounds.
    769   gfx::Rect vertical_out_of_screen_bounds(10, 1000, 400, 400);
    770   CallAdjustBoundsToBeVisibleOnScreenForShellWindow(
    771       window,
    772       vertical_out_of_screen_bounds,
    773       gfx::Rect(-1366, 0, 1600, 900),
    774       current_screen_bounds,
    775       minimum_size,
    776       &bounds);
    777   EXPECT_EQ(bounds, gfx::Rect(10, 500, 400, 400));
    778 
    779   // From a large screen resulotion to a small one. Expect it fit on screen.
    780   gfx::Rect big_cache_bounds(10, 10, 1000, 1000);
    781   CallAdjustBoundsToBeVisibleOnScreenForShellWindow(
    782       window,
    783       big_cache_bounds,
    784       gfx::Rect(0, 0, 1600, 1000),
    785       gfx::Rect(0, 0, 800, 600),
    786       minimum_size,
    787       &bounds);
    788   EXPECT_EQ(bounds, gfx::Rect(0, 0, 800, 600));
    789 
    790   // Don't resize the bounds smaller than minimum size, when the minimum size is
    791   // larger than the screen.
    792   CallAdjustBoundsToBeVisibleOnScreenForShellWindow(
    793       window,
    794       big_cache_bounds,
    795       gfx::Rect(0, 0, 1600, 1000),
    796       gfx::Rect(0, 0, 800, 600),
    797       gfx::Size(900, 900),
    798       &bounds);
    799   EXPECT_EQ(bounds, gfx::Rect(0, 0, 900, 900));
    800 }
    801 
    802 namespace {
    803 
    804 class PlatformAppDevToolsBrowserTest : public PlatformAppBrowserTest {
    805  protected:
    806   enum TestFlags {
    807     RELAUNCH = 0x1,
    808     HAS_ID = 0x2,
    809   };
    810   // Runs a test inside a harness that opens DevTools on a shell window.
    811   void RunTestWithDevTools(const char* name, int test_flags);
    812 };
    813 
    814 void PlatformAppDevToolsBrowserTest::RunTestWithDevTools(
    815     const char* name, int test_flags) {
    816   using content::DevToolsAgentHost;
    817   ExtensionTestMessageListener launched_listener("Launched", false);
    818   const Extension* extension = LoadAndLaunchPlatformApp(name);
    819   ASSERT_TRUE(extension);
    820   ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
    821   ShellWindow* window = GetFirstShellWindow();
    822   ASSERT_TRUE(window);
    823   ASSERT_EQ(window->window_key().empty(), (test_flags & HAS_ID) == 0);
    824   content::RenderViewHost* rvh = window->web_contents()->GetRenderViewHost();
    825   ASSERT_TRUE(rvh);
    826 
    827   // Ensure no DevTools open for the ShellWindow, then open one.
    828   ASSERT_FALSE(DevToolsAgentHost::HasFor(rvh));
    829   DevToolsWindow* devtools_window = DevToolsWindow::OpenDevToolsWindow(rvh);
    830   content::WindowedNotificationObserver loaded_observer(
    831       content::NOTIFICATION_LOAD_STOP,
    832       content::Source<content::NavigationController>(
    833           &devtools_window->web_contents()->GetController()));
    834   loaded_observer.Wait();
    835   ASSERT_TRUE(DevToolsAgentHost::HasFor(rvh));
    836 
    837   if (test_flags & RELAUNCH) {
    838     // Close the ShellWindow, and ensure it is gone.
    839     CloseShellWindow(window);
    840     ASSERT_FALSE(GetFirstShellWindow());
    841 
    842     // Relaunch the app and get a new ShellWindow.
    843     content::WindowedNotificationObserver app_loaded_observer(
    844         content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
    845         content::NotificationService::AllSources());
    846     OpenApplication(AppLaunchParams(
    847         browser()->profile(), extension, LAUNCH_CONTAINER_NONE, NEW_WINDOW));
    848     app_loaded_observer.Wait();
    849     window = GetFirstShellWindow();
    850     ASSERT_TRUE(window);
    851 
    852     // DevTools should have reopened with the relaunch.
    853     rvh = window->web_contents()->GetRenderViewHost();
    854     ASSERT_TRUE(rvh);
    855     ASSERT_TRUE(DevToolsAgentHost::HasFor(rvh));
    856   }
    857 }
    858 
    859 }  // namespace
    860 
    861 // http://crbug.com/246634
    862 #if defined(OS_CHROMEOS)
    863 #define MAYBE_ReOpenedWithID DISABLED_ReOpenedWithID
    864 #else
    865 #define MAYBE_ReOpenedWithID ReOpenedWithID
    866 #endif
    867 IN_PROC_BROWSER_TEST_F(PlatformAppDevToolsBrowserTest, MAYBE_ReOpenedWithID) {
    868 #if defined(OS_WIN) && defined(USE_ASH)
    869   // Disable this test in Metro+Ash for now (http://crbug.com/262796).
    870   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
    871     return;
    872 #endif
    873   RunTestWithDevTools("minimal_id", RELAUNCH | HAS_ID);
    874 }
    875 
    876 // http://crbug.com/246999
    877 #if defined(OS_CHROMEOS) || defined(OS_WIN)
    878 #define MAYBE_ReOpenedWithURL DISABLED_ReOpenedWithURL
    879 #else
    880 #define MAYBE_ReOpenedWithURL ReOpenedWithURL
    881 #endif
    882 IN_PROC_BROWSER_TEST_F(PlatformAppDevToolsBrowserTest, MAYBE_ReOpenedWithURL) {
    883   RunTestWithDevTools("minimal", RELAUNCH);
    884 }
    885 
    886 // Test that showing a permission request as a constrained window works and is
    887 // correctly parented.
    888 #if defined(OS_MACOSX)
    889 #define MAYBE_ConstrainedWindowRequest DISABLED_ConstrainedWindowRequest
    890 #else
    891 // TODO(sail): Enable this on other platforms once http://crbug.com/95455 is
    892 // fixed.
    893 #define MAYBE_ConstrainedWindowRequest DISABLED_ConstrainedWindowRequest
    894 #endif
    895 
    896 IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, MAYBE_ConstrainedWindowRequest) {
    897   PermissionsRequestFunction::SetIgnoreUserGestureForTests(true);
    898   const Extension* extension =
    899       LoadAndLaunchPlatformApp("optional_permission_request");
    900   ASSERT_TRUE(extension) << "Failed to load extension.";
    901 
    902   WebContents* web_contents = GetFirstShellWindowWebContents();
    903   ASSERT_TRUE(web_contents);
    904 
    905   // Verify that the shell window has a dialog attached.
    906   WebContentsModalDialogManager* web_contents_modal_dialog_manager =
    907       WebContentsModalDialogManager::FromWebContents(web_contents);
    908   EXPECT_TRUE(web_contents_modal_dialog_manager->IsDialogActive());
    909 
    910   // Close the constrained window and wait for the reply to the permission
    911   // request.
    912   ExtensionTestMessageListener listener("PermissionRequestDone", false);
    913   WebContentsModalDialogManager::TestApi test_api(
    914       web_contents_modal_dialog_manager);
    915   test_api.CloseAllDialogs();
    916   ASSERT_TRUE(listener.WaitUntilSatisfied());
    917 }
    918 
    919 // Tests that an app calling chrome.runtime.reload will reload the app and
    920 // relaunch it if it was running.
    921 IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, ReloadRelaunches) {
    922   ExtensionTestMessageListener launched_listener("Launched", true);
    923   const Extension* extension = LoadAndLaunchPlatformApp("reload");
    924   ASSERT_TRUE(extension);
    925   ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
    926   ASSERT_TRUE(GetFirstShellWindow());
    927 
    928   // Now tell the app to reload itself
    929   ExtensionTestMessageListener launched_listener2("Launched", false);
    930   launched_listener.Reply("reload");
    931   ASSERT_TRUE(launched_listener2.WaitUntilSatisfied());
    932   ASSERT_TRUE(GetFirstShellWindow());
    933 }
    934 
    935 namespace {
    936 
    937 // Simple observer to check for NOTIFICATION_EXTENSION_INSTALLED events to
    938 // ensure installation does or does not occur in certain scenarios.
    939 class CheckExtensionInstalledObserver : public content::NotificationObserver {
    940  public:
    941   CheckExtensionInstalledObserver() : seen_(false) {
    942     registrar_.Add(this,
    943                    chrome::NOTIFICATION_EXTENSION_INSTALLED,
    944                    content::NotificationService::AllSources());
    945   }
    946 
    947   bool seen() const {
    948     return seen_;
    949   };
    950 
    951   // NotificationObserver:
    952   virtual void Observe(int type,
    953                        const content::NotificationSource& source,
    954                        const content::NotificationDetails& details) OVERRIDE {
    955     EXPECT_FALSE(seen_);
    956     seen_ = true;
    957   }
    958 
    959  private:
    960   bool seen_;
    961   content::NotificationRegistrar registrar_;
    962 };
    963 
    964 }  // namespace
    965 
    966 // Component App Test 1 of 3: ensure that the initial load of a component
    967 // extension utilizing a background page (e.g. a v2 platform app) has its
    968 // background page run and is launchable. Waits for the Launched response from
    969 // the script resource in the opened shell window.
    970 IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest,
    971                        PRE_PRE_ComponentAppBackgroundPage) {
    972   CheckExtensionInstalledObserver should_install;
    973 
    974   // Ensure that we wait until the background page is run (to register the
    975   // OnLaunched listener) before trying to open the application. This is similar
    976   // to LoadAndLaunchPlatformApp, but we want to load as a component extension.
    977   content::WindowedNotificationObserver app_loaded_observer(
    978       content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
    979       content::NotificationService::AllSources());
    980 
    981   const Extension* extension = LoadExtensionAsComponent(
    982       test_data_dir_.AppendASCII("platform_apps").AppendASCII("component"));
    983   ASSERT_TRUE(extension);
    984 
    985   app_loaded_observer.Wait();
    986   ASSERT_TRUE(should_install.seen());
    987 
    988   ExtensionTestMessageListener launched_listener("Launched", false);
    989   OpenApplication(AppLaunchParams(
    990       browser()->profile(), extension, LAUNCH_CONTAINER_NONE, NEW_WINDOW));
    991 
    992   ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
    993 }
    994 
    995 // Component App Test 2 of 3: ensure an installed component app can be launched
    996 // on a subsequent browser start, without requiring any install/upgrade logic
    997 // to be run, then perform setup for step 3.
    998 IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest,
    999                        PRE_ComponentAppBackgroundPage) {
   1000 
   1001   // Since the component app is now installed, re-adding it in the same profile
   1002   // should not cause it to be re-installed. Instead, we wait for the OnLaunched
   1003   // in a different observer (which would timeout if not the app was not
   1004   // previously installed properly) and then check this observer to make sure it
   1005   // never saw the NOTIFICATION_EXTENSION_INSTALLED event.
   1006   CheckExtensionInstalledObserver should_not_install;
   1007   const Extension* extension = LoadExtensionAsComponent(
   1008       test_data_dir_.AppendASCII("platform_apps").AppendASCII("component"));
   1009   ASSERT_TRUE(extension);
   1010 
   1011   ExtensionTestMessageListener launched_listener("Launched", false);
   1012   OpenApplication(AppLaunchParams(
   1013       browser()->profile(), extension, LAUNCH_CONTAINER_NONE, NEW_WINDOW));
   1014 
   1015   ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
   1016   ASSERT_FALSE(should_not_install.seen());
   1017 
   1018   // Simulate a "downgrade" from version 2 in the test manifest.json to 1.
   1019   ExtensionPrefs* extension_prefs =
   1020       extensions::ExtensionSystem::Get(browser()->profile())->
   1021       extension_service()->extension_prefs();
   1022 
   1023   // Clear the registered events to ensure they are updated.
   1024   extensions::ExtensionSystem::Get(browser()->profile())->event_router()->
   1025       SetRegisteredEvents(extension->id(), std::set<std::string>());
   1026 
   1027   DictionaryPrefUpdate update(extension_prefs->pref_service(),
   1028                               prefs::kExtensionsPref);
   1029   DictionaryValue* dict = update.Get();
   1030   std::string key(extension->id());
   1031   key += ".manifest.version";
   1032   dict->SetString(key, "1");
   1033 }
   1034 
   1035 // Component App Test 3 of 3: simulate a component extension upgrade that
   1036 // re-adds the OnLaunched event, and allows the app to be launched.
   1037 IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, ComponentAppBackgroundPage) {
   1038   CheckExtensionInstalledObserver should_install;
   1039   // Since we are forcing an upgrade, we need to wait for the load again.
   1040   content::WindowedNotificationObserver app_loaded_observer(
   1041       content::NOTIFICATION_LOAD_COMPLETED_MAIN_FRAME,
   1042       content::NotificationService::AllSources());
   1043 
   1044   const Extension* extension = LoadExtensionAsComponent(
   1045       test_data_dir_.AppendASCII("platform_apps").AppendASCII("component"));
   1046   ASSERT_TRUE(extension);
   1047   app_loaded_observer.Wait();
   1048   ASSERT_TRUE(should_install.seen());
   1049 
   1050   ExtensionTestMessageListener launched_listener("Launched", false);
   1051   OpenApplication(AppLaunchParams(
   1052       browser()->profile(), extension, LAUNCH_CONTAINER_NONE, NEW_WINDOW));
   1053 
   1054   ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
   1055 }
   1056 
   1057 // Flakes on Windows: http://crbug.com/171450
   1058 #if defined(OS_WIN)
   1059 #define MAYBE_Messaging DISABLED_Messaging
   1060 #else
   1061 #define MAYBE_Messaging Messaging
   1062 #endif
   1063 IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, MAYBE_Messaging) {
   1064   ExtensionApiTest::ResultCatcher result_catcher;
   1065   LoadAndLaunchPlatformApp("messaging/app2");
   1066   LoadAndLaunchPlatformApp("messaging/app1");
   1067   EXPECT_TRUE(result_catcher.GetNextResult());
   1068 }
   1069 
   1070 // TODO(linux_aura) http://crbug.com/163931
   1071 #if defined(OS_LINUX) && !defined(OS_CHROMEOS) && defined(USE_AURA)
   1072 #define MAYBE_WebContentsHasFocus DISABLED_WebContentsHasFocus
   1073 #else
   1074 // This test depends on focus and so needs to be in interactive_ui_tests.
   1075 // http://crbug.com/227041
   1076 #define MAYBE_WebContentsHasFocus DISABLED_WebContentsHasFocus
   1077 #endif
   1078 IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest, MAYBE_WebContentsHasFocus) {
   1079   ExtensionTestMessageListener launched_listener("Launched", true);
   1080   LoadAndLaunchPlatformApp("minimal");
   1081   ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
   1082 
   1083   EXPECT_EQ(1LU, GetShellWindowCount());
   1084   EXPECT_TRUE(GetFirstShellWindow()->web_contents()->
   1085       GetRenderWidgetHostView()->HasFocus());
   1086 }
   1087 
   1088 // The next three tests will only run automatically with Chrome branded builds
   1089 // because they require the PDF preview plug-in. To run these tests manually for
   1090 // Chromium (non-Chrome branded) builds in a development environment:
   1091 //
   1092 //   1) Remove "MAYBE_" in the first line of each test definition
   1093 //   2) Build Chromium browser_tests
   1094 //   3) Make a copy of the PDF plug-in from a recent version of Chrome (Canary
   1095 //      or a recent development build) to your Chromium build:
   1096 //      - On Linux and Chrome OS, copy /opt/google/chrome/libpdf.so to
   1097 //        <path-to-your-src>/out/Debug
   1098 //      - On OS X, copy PDF.plugin from
   1099 //        <recent-chrome-app-folder>/*/*/*/*/"Internet Plug-Ins" to
   1100 //        <path-to-your-src>/out/Debug/Chromium.app/*/*/*/*/"Internet Plug-Ins"
   1101 //   4) Run browser_tests with the --enable-print-preview flag
   1102 
   1103 #if !defined(GOOGLE_CHROME_BUILD) || \
   1104     (defined(GOOGLE_CHROME_BUILD) && (defined(OS_WIN) || defined(OS_LINUX)))
   1105 #define MAYBE_WindowDotPrintShouldBringUpPrintPreview \
   1106     DISABLED_WindowDotPrintShouldBringUpPrintPreview
   1107 #else
   1108 #define MAYBE_WindowDotPrintShouldBringUpPrintPreview \
   1109     WindowDotPrintShouldBringUpPrintPreview
   1110 #endif
   1111 
   1112 IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest,
   1113                        MAYBE_WindowDotPrintShouldBringUpPrintPreview) {
   1114   ScopedPreviewTestingDelegate preview_delegate(true);
   1115   ASSERT_TRUE(RunPlatformAppTest("platform_apps/print_api")) << message_;
   1116   preview_delegate.WaitUntilPreviewIsReady();
   1117 }
   1118 
   1119 #if !defined(GOOGLE_CHROME_BUILD)
   1120 #define MAYBE_ClosingWindowWhilePrintingShouldNotCrash \
   1121     DISABLED_ClosingWindowWhilePrintingShouldNotCrash
   1122 #else
   1123 #define MAYBE_ClosingWindowWhilePrintingShouldNotCrash \
   1124     ClosingWindowWhilePrintingShouldNotCrash
   1125 #endif
   1126 
   1127 // This test verifies that http://crbug.com/297179 is fixed.
   1128 IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest,
   1129                        MAYBE_ClosingWindowWhilePrintingShouldNotCrash) {
   1130   ScopedPreviewTestingDelegate preview_delegate(false);
   1131   ASSERT_TRUE(RunPlatformAppTest("platform_apps/print_api")) << message_;
   1132   preview_delegate.WaitUntilPreviewIsReady();
   1133   GetFirstShellWindow()->GetBaseWindow()->Close();
   1134 }
   1135 
   1136 // This test currently only passes on OS X (on other platforms the print preview
   1137 // dialog's size is limited by the size of the window being printed).
   1138 #if !defined(GOOGLE_CHROME_BUILD) || !defined(OS_MACOSX)
   1139 #define MAYBE_PrintPreviewShouldNotBeTooSmall \
   1140     DISABLED_PrintPreviewShouldNotBeTooSmall
   1141 #else
   1142 #define MAYBE_PrintPreviewShouldNotBeTooSmall \
   1143     PrintPreviewShouldNotBeTooSmall
   1144 #endif
   1145 
   1146 IN_PROC_BROWSER_TEST_F(PlatformAppBrowserTest,
   1147                        MAYBE_PrintPreviewShouldNotBeTooSmall) {
   1148   // Print preview dialogs with widths less than 410 pixels will have preview
   1149   // areas that are too small, and ones with heights less than 191 pixels will
   1150   // have vertical scrollers for their controls that are too small.
   1151   gfx::Size minimum_dialog_size(410, 191);
   1152   ScopedPreviewTestingDelegate preview_delegate(false);
   1153   ASSERT_TRUE(RunPlatformAppTest("platform_apps/print_api")) << message_;
   1154   preview_delegate.WaitUntilPreviewIsReady();
   1155   EXPECT_GE(preview_delegate.dialog_size().width(),
   1156             minimum_dialog_size.width());
   1157   EXPECT_GE(preview_delegate.dialog_size().height(),
   1158             minimum_dialog_size.height());
   1159   GetFirstShellWindow()->GetBaseWindow()->Close();
   1160 }
   1161 
   1162 
   1163 #if defined(OS_CHROMEOS)
   1164 
   1165 class PlatformAppIncognitoBrowserTest : public PlatformAppBrowserTest,
   1166                                         public ShellWindowRegistry::Observer {
   1167  public:
   1168   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
   1169     // Tell chromeos to launch in Guest mode, aka incognito.
   1170     command_line->AppendSwitch(switches::kIncognito);
   1171     PlatformAppBrowserTest::SetUpCommandLine(command_line);
   1172   }
   1173   virtual void SetUp() OVERRIDE {
   1174     // Make sure the file manager actually gets loaded.
   1175     ComponentLoader::EnableBackgroundExtensionsForTesting();
   1176     PlatformAppBrowserTest::SetUp();
   1177   }
   1178 
   1179   // ShellWindowRegistry::Observer implementation.
   1180   virtual void OnShellWindowAdded(ShellWindow* shell_window) OVERRIDE {
   1181     opener_app_ids_.insert(shell_window->extension()->id());
   1182   }
   1183   virtual void OnShellWindowIconChanged(ShellWindow* shell_window) OVERRIDE {}
   1184   virtual void OnShellWindowRemoved(ShellWindow* shell_window) OVERRIDE {}
   1185 
   1186  protected:
   1187   // A set of ids of apps we've seen open a shell window.
   1188   std::set<std::string> opener_app_ids_;
   1189 };
   1190 
   1191 IN_PROC_BROWSER_TEST_F(PlatformAppIncognitoBrowserTest, IncognitoComponentApp) {
   1192   // Get the file manager app.
   1193   const Extension* file_manager = extension_service()->GetExtensionById(
   1194       "hhaomjibdihmijegdhdafkllkbggdgoj", false);
   1195   ASSERT_TRUE(file_manager != NULL);
   1196   Profile* incognito_profile = profile()->GetOffTheRecordProfile();
   1197   ASSERT_TRUE(incognito_profile != NULL);
   1198 
   1199   // Wait until the file manager has had a chance to register its listener
   1200   // for the launch event.
   1201   EventRouter* router = ExtensionSystem::Get(incognito_profile)->event_router();
   1202   ASSERT_TRUE(router != NULL);
   1203   while (!router->ExtensionHasEventListener(
   1204       file_manager->id(), app_runtime::OnLaunched::kEventName)) {
   1205     content::RunAllPendingInMessageLoop();
   1206   }
   1207 
   1208   // Listen for new shell windows so we see the file manager app launch itself.
   1209   ShellWindowRegistry* registry = ShellWindowRegistry::Get(incognito_profile);
   1210   ASSERT_TRUE(registry != NULL);
   1211   registry->AddObserver(this);
   1212 
   1213   OpenApplication(AppLaunchParams(
   1214       incognito_profile, file_manager, 0, chrome::HOST_DESKTOP_TYPE_NATIVE));
   1215 
   1216   while (!ContainsKey(opener_app_ids_, file_manager->id())) {
   1217     content::RunAllPendingInMessageLoop();
   1218   }
   1219 }
   1220 
   1221 class RestartDeviceTest : public PlatformAppBrowserTest {
   1222  public:
   1223   RestartDeviceTest()
   1224       : power_manager_client_(NULL),
   1225         mock_user_manager_(NULL) {}
   1226   virtual ~RestartDeviceTest() {}
   1227 
   1228   // PlatformAppBrowserTest overrides
   1229   virtual void SetUpInProcessBrowserTestFixture() OVERRIDE {
   1230     PlatformAppBrowserTest::SetUpInProcessBrowserTestFixture();
   1231 
   1232     chromeos::FakeDBusThreadManager* dbus_manager =
   1233         new chromeos::FakeDBusThreadManager;
   1234     dbus_manager->SetFakeClients();
   1235     power_manager_client_ = new chromeos::FakePowerManagerClient;
   1236     dbus_manager->SetPowerManagerClient(
   1237         scoped_ptr<chromeos::PowerManagerClient>(power_manager_client_));
   1238     chromeos::DBusThreadManager::SetInstanceForTesting(dbus_manager);
   1239   }
   1240 
   1241   virtual void SetUpOnMainThread() OVERRIDE {
   1242     PlatformAppBrowserTest::SetUpOnMainThread();
   1243 
   1244     mock_user_manager_ = new chromeos::MockUserManager;
   1245     user_manager_enabler_.reset(
   1246         new chromeos::ScopedUserManagerEnabler(mock_user_manager_));
   1247 
   1248     EXPECT_CALL(*mock_user_manager_, IsUserLoggedIn())
   1249         .WillRepeatedly(testing::Return(true));
   1250     EXPECT_CALL(*mock_user_manager_, IsLoggedInAsKioskApp())
   1251         .WillRepeatedly(testing::Return(true));
   1252   }
   1253 
   1254   virtual void CleanUpOnMainThread() OVERRIDE {
   1255     user_manager_enabler_.reset();
   1256     PlatformAppBrowserTest::CleanUpOnMainThread();
   1257   }
   1258 
   1259   virtual void TearDownInProcessBrowserTestFixture() OVERRIDE {
   1260     PlatformAppBrowserTest::TearDownInProcessBrowserTestFixture();
   1261   }
   1262 
   1263   int request_restart_call_count() const {
   1264     return power_manager_client_->request_restart_call_count();
   1265   }
   1266 
   1267  private:
   1268   chromeos::FakePowerManagerClient* power_manager_client_;
   1269   chromeos::MockUserManager* mock_user_manager_;
   1270   scoped_ptr<chromeos::ScopedUserManagerEnabler> user_manager_enabler_;
   1271 
   1272   DISALLOW_COPY_AND_ASSIGN(RestartDeviceTest);
   1273 };
   1274 
   1275 // Tests that chrome.runtime.restart would request device restart in
   1276 // ChromeOS kiosk mode.
   1277 IN_PROC_BROWSER_TEST_F(RestartDeviceTest, Restart) {
   1278   ASSERT_EQ(0, request_restart_call_count());
   1279 
   1280   ExtensionTestMessageListener launched_listener("Launched", true);
   1281   const Extension* extension = LoadAndLaunchPlatformApp("restart_device");
   1282   ASSERT_TRUE(extension);
   1283   ASSERT_TRUE(launched_listener.WaitUntilSatisfied());
   1284 
   1285   launched_listener.Reply("restart");
   1286   ExtensionTestMessageListener restart_requested_listener("restartRequested",
   1287                                                           false);
   1288   ASSERT_TRUE(restart_requested_listener.WaitUntilSatisfied());
   1289 
   1290   EXPECT_EQ(1, request_restart_call_count());
   1291 }
   1292 
   1293 #endif  // defined(OS_CHROMEOS)
   1294 
   1295 
   1296 }  // namespace extensions
   1297