blob: 09a2f51dd9aeba802722de96f4821796ca9240e8 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/extensions/bookmark_app_helper.h"
#include "base/run_loop.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/app/chrome_command_ids.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_commands.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/ui/test/test_browser_dialog.h"
#include "chrome/common/render_messages.h"
#include "content/public/browser/browser_message_filter.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_widget_host.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/web_contents.h"
namespace extensions {
namespace {
content::RenderWidgetHost* GetActiveRenderWidgetHost(Browser* browser) {
return browser->tab_strip_model()
->GetActiveWebContents()
->GetRenderWidgetHostView()
->GetRenderWidgetHost();
}
// Extends BookmarkAppHelper to see the call to OnIconsDownloaded.
class TestBookmarkAppHelper : public BookmarkAppHelper {
public:
TestBookmarkAppHelper(Profile* profile,
WebApplicationInfo web_app_info,
content::WebContents* contents,
base::Closure on_icons_downloaded_closure)
: BookmarkAppHelper(profile, web_app_info, contents),
on_icons_downloaded_closure_(on_icons_downloaded_closure) {}
// TestBookmarkAppHelper:
void OnIconsDownloaded(
bool success,
const std::map<GURL, std::vector<SkBitmap>>& bitmaps) override {
on_icons_downloaded_closure_.Run();
BookmarkAppHelper::OnIconsDownloaded(success, bitmaps);
}
private:
base::Closure on_icons_downloaded_closure_;
DISALLOW_COPY_AND_ASSIGN(TestBookmarkAppHelper);
};
// Intercepts the ChromeFrameHostMsg_DidGetWebApplicationInfo that would usually
// get sent to extensions::TabHelper to create a BookmarkAppHelper that lets us
// detect when icons are downloaded and the dialog is ready to show.
class WebAppReadyMsgWatcher : public content::BrowserMessageFilter {
public:
explicit WebAppReadyMsgWatcher(Browser* browser)
: BrowserMessageFilter(ChromeMsgStart), browser_(browser) {}
content::WebContents* web_contents() {
return browser_->tab_strip_model()->GetActiveWebContents();
}
void OnDidGetWebApplicationInfo(const WebApplicationInfo& const_info) {
WebApplicationInfo info = const_info;
// Mimic extensions::TabHelper for fields missing from the manifest.
if (info.app_url.is_empty())
info.app_url = web_contents()->GetURL();
if (info.title.empty())
info.title = web_contents()->GetTitle();
if (info.title.empty())
info.title = base::UTF8ToUTF16(info.app_url.spec());
bookmark_app_helper_ = base::MakeUnique<TestBookmarkAppHelper>(
browser_->profile(), info, web_contents(), quit_closure_);
bookmark_app_helper_->Create(
base::Bind(&WebAppReadyMsgWatcher::FinishCreateBookmarkApp, this));
}
void FinishCreateBookmarkApp(const Extension* extension,
const WebApplicationInfo& web_app_info) {
// ~WebAppReadyMsgWatcher() is called on the IO thread, but
// |bookmark_app_helper_| must be destroyed on the UI thread.
bookmark_app_helper_.reset();
}
void Wait() {
base::RunLoop run_loop;
quit_closure_ = run_loop.QuitClosure();
run_loop.Run();
}
// BrowserMessageFilter:
void OverrideThreadForMessage(const IPC::Message& message,
content::BrowserThread::ID* thread) override {
if (message.type() == ChromeFrameHostMsg_DidGetWebApplicationInfo::ID)
*thread = content::BrowserThread::UI;
}
bool OnMessageReceived(const IPC::Message& message) override {
bool handled = true;
IPC_BEGIN_MESSAGE_MAP(WebAppReadyMsgWatcher, message)
IPC_MESSAGE_HANDLER(ChromeFrameHostMsg_DidGetWebApplicationInfo,
OnDidGetWebApplicationInfo)
IPC_MESSAGE_UNHANDLED(handled = false)
IPC_END_MESSAGE_MAP()
return handled;
}
private:
~WebAppReadyMsgWatcher() override {}
Browser* browser_;
base::Closure quit_closure_;
std::unique_ptr<TestBookmarkAppHelper> bookmark_app_helper_;
DISALLOW_COPY_AND_ASSIGN(WebAppReadyMsgWatcher);
};
} // namespace
class BookmarkAppHelperTest : public DialogBrowserTest {
public:
BookmarkAppHelperTest() {}
// DialogBrowserTest:
void ShowDialog(const std::string& name) override {
ASSERT_TRUE(embedded_test_server()->Start());
AddTabAtIndex(
1,
GURL(embedded_test_server()->GetURL("/favicon/page_with_favicon.html")),
ui::PAGE_TRANSITION_LINK);
scoped_refptr<WebAppReadyMsgWatcher> filter =
new WebAppReadyMsgWatcher(browser());
GetActiveRenderWidgetHost(browser())->GetProcess()->AddFilter(filter.get());
chrome::ExecuteCommand(browser(), IDC_CREATE_HOSTED_APP);
filter->Wait();
}
private:
DISALLOW_COPY_AND_ASSIGN(BookmarkAppHelperTest);
};
IN_PROC_BROWSER_TEST_F(BookmarkAppHelperTest, InvokeDialog_create) {
RunDialog();
}
} // namespace extensions