1 // Copyright 2014 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.
5 #include "chrome/browser/android/shortcut_helper.h"
7 #include "base/strings/utf_string_conversions.h"
8 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
9 #include "content/public/browser/web_contents.h"
10 #include "ui/gfx/screen.h"
11 #include "ui/gfx/screen_type_delegate.h"
13 // A dummy implementation of gfx::Screen, since ShortcutHelper needs access to
14 // a gfx::Display's device scale factor.
15 // This is inspired by web_contents_video_capture_device_unittest.cc
16 // A bug has been opened to merge all those mocks: http://crbug.com/417227
17 class FakeScreen
: public gfx::Screen
{
19 FakeScreen() : display_(0x1337, gfx::Rect(0, 0, 2560, 1440)) {
21 virtual ~FakeScreen() {}
23 void SetDisplayDeviceScaleFactor(float device_scale_factor
) {
24 display_
.set_device_scale_factor(device_scale_factor
);
27 // gfx::Screen implementation (only what's needed for testing).
28 virtual bool IsDIPEnabled() override
{ return true; }
29 virtual gfx::Point
GetCursorScreenPoint() override
{ return gfx::Point(); }
30 virtual gfx::NativeWindow
GetWindowUnderCursor() override
{ return NULL
; }
31 virtual gfx::NativeWindow
GetWindowAtScreenPoint(
32 const gfx::Point
& point
) override
{ return NULL
; }
33 virtual int GetNumDisplays() const override
{ return 1; }
34 virtual std::vector
<gfx::Display
> GetAllDisplays() const override
{
35 return std::vector
<gfx::Display
>(1, display_
);
37 virtual gfx::Display
GetDisplayNearestWindow(
38 gfx::NativeView view
) const override
{
41 virtual gfx::Display
GetDisplayNearestPoint(
42 const gfx::Point
& point
) const override
{
45 virtual gfx::Display
GetDisplayMatching(
46 const gfx::Rect
& match_rect
) const override
{
49 virtual gfx::Display
GetPrimaryDisplay() const override
{
52 virtual void AddObserver(gfx::DisplayObserver
* observer
) override
{}
53 virtual void RemoveObserver(gfx::DisplayObserver
* observer
) override
{}
56 gfx::Display display_
;
58 DISALLOW_COPY_AND_ASSIGN(FakeScreen
);
61 class ShortcutHelperTest
: public ChromeRenderViewHostTestHarness
{
63 ShortcutHelperTest() : shortcut_helper_(NULL
) {}
64 virtual ~ShortcutHelperTest() {}
66 static jobject
CreateShortcutHelperJava(JNIEnv
* env
) {
67 jclass clazz
= env
->FindClass("org/chromium/chrome/browser/ShortcutHelper");
68 jmethodID constructor
=
69 env
->GetMethodID(clazz
, "<init>",
70 "(Landroid/content/Context;"
71 "Lorg/chromium/chrome/browser/Tab;)V");
72 return env
->NewObject(clazz
, constructor
, jobject(), jobject());
75 void ResetShorcutHelper() {
77 delete shortcut_helper_
;
79 JNIEnv
* env
= base::android::AttachCurrentThread();
81 new ShortcutHelper(env
, CreateShortcutHelperJava(env
), web_contents());
84 virtual void SetUp() override
{
85 gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE
, &fake_screen_
);
86 ASSERT_EQ(&fake_screen_
, gfx::Screen::GetNativeScreen());
88 ChromeRenderViewHostTestHarness::SetUp();
93 virtual void TearDown() override
{
94 delete shortcut_helper_
;
95 shortcut_helper_
= NULL
;
97 ChromeRenderViewHostTestHarness::TearDown();
99 gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE
, NULL
);
102 GURL
FindBestMatchingIcon(const std::vector
<content::Manifest::Icon
>& icons
) {
103 return shortcut_helper_
->FindBestMatchingIcon(icons
);
106 void SetDisplayDeviceScaleFactor(float device_scale_factor
) {
107 fake_screen_
.SetDisplayDeviceScaleFactor(device_scale_factor
);
109 ResetShorcutHelper();
112 static int GetPreferredIconSizeInDp() {
113 return ShortcutHelper::kPreferredIconSizeInDp
;
116 static content::Manifest::Icon
CreateIcon(
117 const std::string
& url
,
118 const std::string
& type
,
120 const std::vector
<gfx::Size
> sizes
) {
121 content::Manifest::Icon icon
;
122 icon
.src
= GURL(url
);
124 icon
.type
= base::NullableString16(base::UTF8ToUTF16(type
), false);
125 icon
.density
= density
;
132 ShortcutHelper
* shortcut_helper_
;
133 FakeScreen fake_screen_
;
135 DISALLOW_COPY_AND_ASSIGN(ShortcutHelperTest
);
138 TEST_F(ShortcutHelperTest
, NoIcons
) {
139 // No icons should return the empty URL.
140 std::vector
<content::Manifest::Icon
> icons
;
141 GURL url
= FindBestMatchingIcon(icons
);
142 EXPECT_TRUE(url
.is_empty());
145 TEST_F(ShortcutHelperTest
, NoSizes
) {
146 // Icon with no sizes are ignored.
147 std::vector
<content::Manifest::Icon
> icons
;
149 CreateIcon("http://foo.com/icon.png", "", 1.0, std::vector
<gfx::Size
>()));
151 GURL url
= FindBestMatchingIcon(icons
);
152 EXPECT_TRUE(url
.is_empty());
155 TEST_F(ShortcutHelperTest
, MIMETypeFiltering
) {
156 // Icons with type specified to a MIME type that isn't a valid image MIME type
158 std::vector
<gfx::Size
> sizes
;
159 sizes
.push_back(gfx::Size(10, 10));
161 std::vector
<content::Manifest::Icon
> icons
;
163 CreateIcon("http://foo.com/icon.png", "image/foo_bar", 1.0, sizes
));
164 icons
.push_back(CreateIcon("http://foo.com/icon.png", "image/", 1.0, sizes
));
165 icons
.push_back(CreateIcon("http://foo.com/icon.png", "image/", 1.0, sizes
));
167 CreateIcon("http://foo.com/icon.png", "video/mp4", 1.0, sizes
));
169 GURL url
= FindBestMatchingIcon(icons
);
170 EXPECT_TRUE(url
.is_empty());
174 CreateIcon("http://foo.com/icon.png", "image/png", 1.0, sizes
));
175 url
= FindBestMatchingIcon(icons
);
176 EXPECT_EQ("http://foo.com/icon.png", url
.spec());
180 CreateIcon("http://foo.com/icon.png", "image/gif", 1.0, sizes
));
181 url
= FindBestMatchingIcon(icons
);
182 EXPECT_EQ("http://foo.com/icon.png", url
.spec());
186 CreateIcon("http://foo.com/icon.png", "image/jpeg", 1.0, sizes
));
187 url
= FindBestMatchingIcon(icons
);
188 EXPECT_EQ("http://foo.com/icon.png", url
.spec());
191 TEST_F(ShortcutHelperTest
, PreferredSizeOfCurrentDensityIsUsedFirst
) {
192 // This test has three icons each are marked with sizes set to the preferred
193 // icon size for the associated density.
194 std::vector
<gfx::Size
> sizes_1
;
195 sizes_1
.push_back(gfx::Size(GetPreferredIconSizeInDp(),
196 GetPreferredIconSizeInDp()));
198 std::vector
<gfx::Size
> sizes_2
;
199 sizes_2
.push_back(gfx::Size(GetPreferredIconSizeInDp() * 2,
200 GetPreferredIconSizeInDp() * 2));
202 std::vector
<gfx::Size
> sizes_3
;
203 sizes_3
.push_back(gfx::Size(GetPreferredIconSizeInDp() * 3,
204 GetPreferredIconSizeInDp() * 3));
206 std::vector
<content::Manifest::Icon
> icons
;
207 icons
.push_back(CreateIcon("http://foo.com/icon_x1.png", "", 1.0, sizes_1
));
208 icons
.push_back(CreateIcon("http://foo.com/icon_x2.png", "", 2.0, sizes_2
));
209 icons
.push_back(CreateIcon("http://foo.com/icon_x3.png", "", 3.0, sizes_3
));
211 SetDisplayDeviceScaleFactor(1.0f
);
212 GURL url
= FindBestMatchingIcon(icons
);
213 EXPECT_EQ("http://foo.com/icon_x1.png", url
.spec());
215 SetDisplayDeviceScaleFactor(2.0f
);
216 url
= FindBestMatchingIcon(icons
);
217 EXPECT_EQ("http://foo.com/icon_x2.png", url
.spec());
219 SetDisplayDeviceScaleFactor(3.0f
);
220 url
= FindBestMatchingIcon(icons
);
221 EXPECT_EQ("http://foo.com/icon_x3.png", url
.spec());
224 TEST_F(ShortcutHelperTest
, PreferredSizeOfDefaultDensityIsUsedSecond
) {
225 // This test has three icons. The first one is of density zero and is marked
226 // with three sizes which are the preferred icon size for density 1, 2 and 3.
227 // The icon for density 2 and 3 have a size set to 2x2 and 3x3.
228 // Regardless of the device scale factor, the icon of density 1 is going to be
229 // used because it matches the preferred size.
230 std::vector
<gfx::Size
> sizes_1
;
231 sizes_1
.push_back(gfx::Size(GetPreferredIconSizeInDp(),
232 GetPreferredIconSizeInDp()));
233 sizes_1
.push_back(gfx::Size(GetPreferredIconSizeInDp() * 2,
234 GetPreferredIconSizeInDp() * 2));
235 sizes_1
.push_back(gfx::Size(GetPreferredIconSizeInDp() * 3,
236 GetPreferredIconSizeInDp() * 3));
238 std::vector
<gfx::Size
> sizes_2
;
239 sizes_2
.push_back(gfx::Size(2, 2));
241 std::vector
<gfx::Size
> sizes_3
;
242 sizes_3
.push_back(gfx::Size(3, 3));
244 std::vector
<content::Manifest::Icon
> icons
;
245 icons
.push_back(CreateIcon("http://foo.com/icon_x1.png", "", 1.0, sizes_1
));
246 icons
.push_back(CreateIcon("http://foo.com/icon_x2.png", "", 2.0, sizes_2
));
247 icons
.push_back(CreateIcon("http://foo.com/icon_x3.png", "", 3.0, sizes_3
));
249 SetDisplayDeviceScaleFactor(1.0f
);
250 GURL url
= FindBestMatchingIcon(icons
);
251 EXPECT_EQ("http://foo.com/icon_x1.png", url
.spec());
253 SetDisplayDeviceScaleFactor(2.0f
);
254 url
= FindBestMatchingIcon(icons
);
255 EXPECT_EQ("http://foo.com/icon_x1.png", url
.spec());
257 SetDisplayDeviceScaleFactor(3.0f
);
258 url
= FindBestMatchingIcon(icons
);
259 EXPECT_EQ("http://foo.com/icon_x1.png", url
.spec());
262 TEST_F(ShortcutHelperTest
, DeviceDensityFirst
) {
263 // If there is no perfect icon but an icon of the current device density is
264 // present, it will be picked.
265 // This test has three icons each are marked with sizes set to the preferred
266 // icon size for the associated density.
267 std::vector
<gfx::Size
> sizes
;
268 sizes
.push_back(gfx::Size(2, 2));
270 std::vector
<content::Manifest::Icon
> icons
;
271 icons
.push_back(CreateIcon("http://foo.com/icon_x1.png", "", 1.0, sizes
));
272 icons
.push_back(CreateIcon("http://foo.com/icon_x2.png", "", 2.0, sizes
));
273 icons
.push_back(CreateIcon("http://foo.com/icon_x3.png", "", 3.0, sizes
));
275 SetDisplayDeviceScaleFactor(1.0f
);
276 GURL url
= FindBestMatchingIcon(icons
);
277 EXPECT_EQ("http://foo.com/icon_x1.png", url
.spec());
279 SetDisplayDeviceScaleFactor(2.0f
);
280 url
= FindBestMatchingIcon(icons
);
281 EXPECT_EQ("http://foo.com/icon_x2.png", url
.spec());
283 SetDisplayDeviceScaleFactor(3.0f
);
284 url
= FindBestMatchingIcon(icons
);
285 EXPECT_EQ("http://foo.com/icon_x3.png", url
.spec());
288 TEST_F(ShortcutHelperTest
, DeviceDensityFallback
) {
289 // If there is no perfect icon but and no icon of the current display density,
290 // an icon of density 1.0 will be used.
291 std::vector
<gfx::Size
> sizes
;
292 sizes
.push_back(gfx::Size(2, 2));
294 std::vector
<content::Manifest::Icon
> icons
;
295 icons
.push_back(CreateIcon("http://foo.com/icon_x1.png", "", 1.0, sizes
));
296 icons
.push_back(CreateIcon("http://foo.com/icon_x2.png", "", 2.0, sizes
));
298 SetDisplayDeviceScaleFactor(3.0f
);
299 GURL url
= FindBestMatchingIcon(icons
);
300 EXPECT_EQ("http://foo.com/icon_x1.png", url
.spec());
303 TEST_F(ShortcutHelperTest
, DoNotUseOtherDensities
) {
304 // If there are only icons of densities that are not the current display
305 // density or the default density, they are ignored.
306 std::vector
<gfx::Size
> sizes
;
307 sizes
.push_back(gfx::Size(2, 2));
309 std::vector
<content::Manifest::Icon
> icons
;
310 icons
.push_back(CreateIcon("http://foo.com/icon_x2.png", "", 2.0, sizes
));
312 SetDisplayDeviceScaleFactor(3.0f
);
313 GURL url
= FindBestMatchingIcon(icons
);
314 EXPECT_TRUE(url
.is_empty());
317 TEST_F(ShortcutHelperTest
, NotSquareIconsAreIgnored
) {
318 std::vector
<gfx::Size
> sizes
;
319 sizes
.push_back(gfx::Size(20, 2));
321 std::vector
<content::Manifest::Icon
> icons
;
322 icons
.push_back(CreateIcon("http://foo.com/icon.png", "", 1.0, sizes
));
324 GURL url
= FindBestMatchingIcon(icons
);
325 EXPECT_TRUE(url
.is_empty());
328 TEST_F(ShortcutHelperTest
, ClosestIconToPreferred
) {
329 // This test verifies ShortcutHelper::FindBestMatchingIcon by passing
330 // different icon sizes and checking which one is picked.
331 // The Device Scale Factor is 1.0 and the preferred icon size is returned by
332 // GetPreferredIconSizeInDp().
333 int very_small
= GetPreferredIconSizeInDp() / 4;
334 int small
= GetPreferredIconSizeInDp() / 2;
335 int bit_small
= GetPreferredIconSizeInDp() - 1;
336 int bit_big
= GetPreferredIconSizeInDp() + 1;
337 int big
= GetPreferredIconSizeInDp() * 2;
338 int very_big
= GetPreferredIconSizeInDp() * 4;
340 // (very_small, bit_small) => bit_small
342 std::vector
<gfx::Size
> sizes_1
;
343 sizes_1
.push_back(gfx::Size(very_small
, very_small
));
345 std::vector
<gfx::Size
> sizes_2
;
346 sizes_2
.push_back(gfx::Size(bit_small
, bit_small
));
348 std::vector
<content::Manifest::Icon
> icons
;
349 icons
.push_back(CreateIcon("http://foo.com/icon_no.png", "", 1.0, sizes_1
));
350 icons
.push_back(CreateIcon("http://foo.com/icon.png", "", 1.0, sizes_2
));
352 GURL url
= FindBestMatchingIcon(icons
);
353 EXPECT_EQ("http://foo.com/icon.png", url
.spec());
356 // (very_small, bit_small, smaller) => bit_small
358 std::vector
<gfx::Size
> sizes_1
;
359 sizes_1
.push_back(gfx::Size(very_small
, very_small
));
361 std::vector
<gfx::Size
> sizes_2
;
362 sizes_2
.push_back(gfx::Size(bit_small
, bit_small
));
364 std::vector
<gfx::Size
> sizes_3
;
365 sizes_3
.push_back(gfx::Size(small
, small
));
367 std::vector
<content::Manifest::Icon
> icons
;
368 icons
.push_back(CreateIcon("http://foo.com/icon_no.png", "", 1.0, sizes_1
));
369 icons
.push_back(CreateIcon("http://foo.com/icon.png", "", 1.0, sizes_2
));
370 icons
.push_back(CreateIcon("http://foo.com/icon_no.png", "", 1.0, sizes_3
));
372 GURL url
= FindBestMatchingIcon(icons
);
373 EXPECT_EQ("http://foo.com/icon.png", url
.spec());
376 // (very_big, big) => big
378 std::vector
<gfx::Size
> sizes_1
;
379 sizes_1
.push_back(gfx::Size(very_big
, very_big
));
381 std::vector
<gfx::Size
> sizes_2
;
382 sizes_2
.push_back(gfx::Size(big
, big
));
384 std::vector
<content::Manifest::Icon
> icons
;
385 icons
.push_back(CreateIcon("http://foo.com/icon_no.png", "", 1.0, sizes_1
));
386 icons
.push_back(CreateIcon("http://foo.com/icon.png", "", 1.0, sizes_2
));
388 GURL url
= FindBestMatchingIcon(icons
);
389 EXPECT_EQ("http://foo.com/icon.png", url
.spec());
392 // (very_big, big, bit_big) => bit_big
394 std::vector
<gfx::Size
> sizes_1
;
395 sizes_1
.push_back(gfx::Size(very_big
, very_big
));
397 std::vector
<gfx::Size
> sizes_2
;
398 sizes_2
.push_back(gfx::Size(big
, big
));
400 std::vector
<gfx::Size
> sizes_3
;
401 sizes_3
.push_back(gfx::Size(bit_big
, bit_big
));
403 std::vector
<content::Manifest::Icon
> icons
;
404 icons
.push_back(CreateIcon("http://foo.com/icon_no.png", "", 1.0, sizes_1
));
405 icons
.push_back(CreateIcon("http://foo.com/icon_no.png", "", 1.0, sizes_2
));
406 icons
.push_back(CreateIcon("http://foo.com/icon.png", "", 1.0, sizes_3
));
408 GURL url
= FindBestMatchingIcon(icons
);
409 EXPECT_EQ("http://foo.com/icon.png", url
.spec());
412 // (bit_small, very_big) => very_big
414 std::vector
<gfx::Size
> sizes_1
;
415 sizes_1
.push_back(gfx::Size(bit_small
, bit_small
));
417 std::vector
<gfx::Size
> sizes_2
;
418 sizes_2
.push_back(gfx::Size(very_big
, very_big
));
420 std::vector
<content::Manifest::Icon
> icons
;
421 icons
.push_back(CreateIcon("http://foo.com/icon_no.png", "", 1.0, sizes_1
));
422 icons
.push_back(CreateIcon("http://foo.com/icon.png", "", 1.0, sizes_2
));
424 GURL url
= FindBestMatchingIcon(icons
);
425 EXPECT_EQ("http://foo.com/icon.png", url
.spec());
428 // (bit_small, bit_big) => bit_big
430 std::vector
<gfx::Size
> sizes_1
;
431 sizes_1
.push_back(gfx::Size(bit_small
, bit_small
));
433 std::vector
<gfx::Size
> sizes_2
;
434 sizes_2
.push_back(gfx::Size(bit_big
, bit_big
));
436 std::vector
<content::Manifest::Icon
> icons
;
437 icons
.push_back(CreateIcon("http://foo.com/icon_no.png", "", 1.0, sizes_1
));
438 icons
.push_back(CreateIcon("http://foo.com/icon.png", "", 1.0, sizes_2
));
440 GURL url
= FindBestMatchingIcon(icons
);
441 EXPECT_EQ("http://foo.com/icon.png", url
.spec());
445 TEST_F(ShortcutHelperTest
, UseAnyIfNoPreferredSize
) {
446 // 'any' (ie. gfx::Size(0,0)) should be used if there is no icon of a
447 // preferred size. An icon with the current device scale factor is preferred
448 // over one with the default density.
450 // 'any' with preferred size => preferred size
452 std::vector
<gfx::Size
> sizes_1
;
453 sizes_1
.push_back(gfx::Size(GetPreferredIconSizeInDp(),
454 GetPreferredIconSizeInDp()));
455 std::vector
<gfx::Size
> sizes_2
;
456 sizes_2
.push_back(gfx::Size(0,0));
458 std::vector
<content::Manifest::Icon
> icons
;
459 icons
.push_back(CreateIcon("http://foo.com/icon.png", "", 1.0, sizes_1
));
460 icons
.push_back(CreateIcon("http://foo.com/icon_no.png", "", 1.0, sizes_2
));
462 GURL url
= FindBestMatchingIcon(icons
);
463 EXPECT_EQ("http://foo.com/icon.png", url
.spec());
466 // 'any' with nearly preferred size => any
468 std::vector
<gfx::Size
> sizes_1
;
469 sizes_1
.push_back(gfx::Size(GetPreferredIconSizeInDp() + 1,
470 GetPreferredIconSizeInDp() + 1));
471 std::vector
<gfx::Size
> sizes_2
;
472 sizes_2
.push_back(gfx::Size(0,0));
474 std::vector
<content::Manifest::Icon
> icons
;
475 icons
.push_back(CreateIcon("http://foo.com/icon_no.png", "", 1.0, sizes_1
));
476 icons
.push_back(CreateIcon("http://foo.com/icon.png", "", 1.0, sizes_2
));
478 GURL url
= FindBestMatchingIcon(icons
);
479 EXPECT_EQ("http://foo.com/icon.png", url
.spec());
482 // 'any' on default density and current density => current density.
484 std::vector
<gfx::Size
> sizes
;
485 sizes
.push_back(gfx::Size(0,0));
487 std::vector
<content::Manifest::Icon
> icons
;
488 icons
.push_back(CreateIcon("http://foo.com/icon_no.png", "", 1.0, sizes
));
489 icons
.push_back(CreateIcon("http://foo.com/icon.png", "", 3.0, sizes
));
491 SetDisplayDeviceScaleFactor(3.0f
);
492 GURL url
= FindBestMatchingIcon(icons
);
493 EXPECT_EQ("http://foo.com/icon.png", url
.spec());