15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "chrome/browser/ui/ash/launcher/launcher_favicon_loader.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "ash/shelf/shelf_constants.h"
8c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)#include "base/memory/scoped_ptr.h"
97d4cd473f85ac64c3747c96c277f9e506a0d2246Torne (Richard Coles)#include "base/strings/stringprintf.h"
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/browser.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "chrome/browser/ui/tabs/tab_strip_model.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/test/base/in_process_browser_test.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/test/base/ui_test_utils.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/web_contents.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/web_contents_observer.h"
165d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "third_party/skia/include/core/SkBitmap.h"
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
18c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)using content::WebContents;
19c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)using content::WebContentsObserver;
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace {
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Observer class to determine when favicons have completed loading.
24c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)class ContentsObserver : public WebContentsObserver {
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
26c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  explicit ContentsObserver(WebContents* web_contents)
27c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      : WebContentsObserver(web_contents),
28c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        loaded_(false),
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        got_favicons_(false) {
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~ContentsObserver() {}
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Reset() {
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    got_favicons_ = false;
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
38c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  bool loaded() const { return loaded_; }
39c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  bool got_favicons() const { return got_favicons_; }
40c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
41c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // WebContentsObserver overrides.
42116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch  virtual void DidFinishLoad(content::RenderFrameHost* render_frame_host,
43116680a4aac90f2aa7413d9095a592090648e557Ben Murdoch                             const GURL& validated_url) OVERRIDE {
44c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    loaded_ = true;
45c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
46c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
47010d83a9304c5a91596085d917d248abff47903aTorne (Richard Coles)  virtual void DidUpdateFaviconURL(
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      const std::vector<content::FaviconURL>& candidates) OVERRIDE {
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (!candidates.empty())
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      got_favicons_ = true;
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private:
54c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  bool loaded_;
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool got_favicons_;
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
60c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)class LauncherFaviconLoaderBrowsertest
61c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    : public InProcessBrowserTest,
62c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      public LauncherFaviconLoader::Delegate {
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
64c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  LauncherFaviconLoaderBrowsertest() : favicon_updated_(false) {
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~LauncherFaviconLoaderBrowsertest() {
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
70c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  virtual void SetUpOnMainThread() OVERRIDE {
71c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    WebContents* web_contents =
72c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        browser()->tab_strip_model()->GetActiveWebContents();
73c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    contents_observer_.reset(new ContentsObserver(web_contents));
74c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    favicon_loader_.reset(new LauncherFaviconLoader(this, web_contents));
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
77c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  // LauncherFaviconLoader::Delegate overrides:
78c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  virtual void FaviconUpdated() OVERRIDE {
79c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    favicon_updated_ = true;
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
82c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) protected:
83c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  bool NavigateTo(const char* url) {
84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    std::string url_path = base::StringPrintf("files/ash/launcher/%s", url);
85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    ui_test_utils::NavigateToURL(browser(), test_server()->GetURL(url_path));
86c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return true;
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
89c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  bool WaitForContentsLoaded() {
90c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const int64 max_seconds = 10;
91c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    base::Time start_time = base::Time::Now();
92c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    while (!(contents_observer_->loaded() &&
93c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)             contents_observer_->got_favicons())) {
94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      content::RunAllPendingInMessageLoop();
95c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      base::TimeDelta delta = base::Time::Now() - start_time;
96c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      if (delta.InSeconds() >= max_seconds) {
97c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        LOG(ERROR) << " WaitForContentsLoaded timed out.";
98c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        return false;
99c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)      }
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
101c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    return true;
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
104c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  bool WaitForFaviconUpdated() {
105c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    const int64 max_seconds = 10;
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    base::Time start_time = base::Time::Now();
107c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    while (favicon_loader_->HasPendingDownloads()) {
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      content::RunAllPendingInMessageLoop();
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::TimeDelta delta = base::Time::Now() - start_time;
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      if (delta.InSeconds() >= max_seconds) {
111c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)        LOG(ERROR) << " WaitForFaviconDownlads timed out.";
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        return false;
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      }
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
118c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  void ResetDownloads() {
119c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)    contents_observer_->Reset();
120c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  }
121c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
122c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  bool favicon_updated_;
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  scoped_ptr<ContentsObserver> contents_observer_;
124c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  scoped_ptr<LauncherFaviconLoader> favicon_loader_;
125c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
126c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) private:
127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(LauncherFaviconLoaderBrowsertest);
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IN_PROC_BROWSER_TEST_F(LauncherFaviconLoaderBrowsertest, SmallLauncherIcon) {
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(test_server()->Start());
132c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_TRUE(NavigateTo("launcher-smallfavicon.html"));
133c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EXPECT_TRUE(WaitForContentsLoaded());
134c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EXPECT_TRUE(WaitForFaviconUpdated());
135c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // No large favicons specified, bitmap should be empty.
137c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EXPECT_TRUE(favicon_loader_->GetFavicon().empty());
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IN_PROC_BROWSER_TEST_F(LauncherFaviconLoaderBrowsertest, LargeLauncherIcon) {
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(test_server()->Start());
142c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_TRUE(NavigateTo("launcher-largefavicon.html"));
143c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EXPECT_TRUE(WaitForContentsLoaded());
144c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EXPECT_TRUE(WaitForFaviconUpdated());
145c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
146c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EXPECT_FALSE(favicon_loader_->GetFavicon().empty());
147c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EXPECT_EQ(128, favicon_loader_->GetFavicon().height());
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IN_PROC_BROWSER_TEST_F(LauncherFaviconLoaderBrowsertest, ManyLauncherIcons) {
1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(test_server()->Start());
152c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_TRUE(NavigateTo("launcher-manyfavicon.html"));
153c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EXPECT_TRUE(WaitForContentsLoaded());
154c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EXPECT_TRUE(WaitForFaviconUpdated());
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
156c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EXPECT_FALSE(favicon_loader_->GetFavicon().empty());
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // When multiple favicons are present, the correctly sized icon should be
158a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  // chosen. The icons are sized assuming ash::kShelfSize < 128.
159a02191e04bc25c4935f804f2c080ae28663d096dBen Murdoch  EXPECT_GT(128, ash::kShelfSize);
160c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EXPECT_EQ(48, favicon_loader_->GetFavicon().height());
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)IN_PROC_BROWSER_TEST_F(LauncherFaviconLoaderBrowsertest, ChangeLauncherIcons) {
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_TRUE(test_server()->Start());
165c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_TRUE(NavigateTo("launcher-manyfavicon.html"));
166c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EXPECT_TRUE(WaitForContentsLoaded());
167c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EXPECT_TRUE(WaitForFaviconUpdated());
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
169c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EXPECT_FALSE(favicon_loader_->GetFavicon().empty());
170c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EXPECT_EQ(48, favicon_loader_->GetFavicon().height());
1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_NO_FATAL_FAILURE(ResetDownloads());
1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
173c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_TRUE(NavigateTo("launcher-smallfavicon.html"));
174c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_TRUE(WaitForContentsLoaded());
175c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EXPECT_TRUE(WaitForFaviconUpdated());
176c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
177c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EXPECT_TRUE(favicon_loader_->GetFavicon().empty());
1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ASSERT_NO_FATAL_FAILURE(ResetDownloads());
1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
180c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_TRUE(NavigateTo("launcher-largefavicon.html"));
181c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  ASSERT_TRUE(WaitForContentsLoaded());
182c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EXPECT_TRUE(WaitForFaviconUpdated());
183c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)
184c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EXPECT_FALSE(favicon_loader_->GetFavicon().empty());
185c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)  EXPECT_EQ(128, favicon_loader_->GetFavicon().height());
1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
187