Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(149)

Side by Side Diff: chrome/browser/android/webapps/add_to_homescreen_data_fetcher.cc

Issue 2949993002: Don't ignore manifest icons for sites that don't have a service worker. (Closed)
Patch Set: Nits Created 3 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/android/webapps/add_to_homescreen_data_fetcher.h" 5 #include "chrome/browser/android/webapps/add_to_homescreen_data_fetcher.h"
6 6
7 #include <vector> 7 #include <vector>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/location.h" 10 #include "base/location.h"
(...skipping 14 matching lines...) Expand all
25 #include "content/public/browser/render_frame_host.h" 25 #include "content/public/browser/render_frame_host.h"
26 #include "content/public/browser/web_contents.h" 26 #include "content/public/browser/web_contents.h"
27 #include "content/public/common/manifest.h" 27 #include "content/public/common/manifest.h"
28 #include "third_party/WebKit/public/platform/modules/screen_orientation/WebScree nOrientationLockType.h" 28 #include "third_party/WebKit/public/platform/modules/screen_orientation/WebScree nOrientationLockType.h"
29 #include "ui/gfx/codec/png_codec.h" 29 #include "ui/gfx/codec/png_codec.h"
30 #include "ui/gfx/favicon_size.h" 30 #include "ui/gfx/favicon_size.h"
31 #include "url/gurl.h" 31 #include "url/gurl.h"
32 32
33 namespace { 33 namespace {
34 34
35 // The default number of milliseconds to wait for the data download to complete.
36 const int kDataTimeoutInMilliseconds = 4000;
37
38 // Looks up the original, online URL of the site requested. The URL from the 35 // Looks up the original, online URL of the site requested. The URL from the
39 // WebContents may be a distilled article which is not appropriate for a home 36 // WebContents may be a distilled article which is not appropriate for a home
40 // screen shortcut. 37 // screen shortcut.
41 GURL GetShortcutUrl(content::BrowserContext* browser_context, 38 GURL GetShortcutUrl(content::BrowserContext* browser_context,
42 const GURL& actual_url) { 39 const GURL& actual_url) {
43 return dom_distiller::url_utils::GetOriginalUrlFromDistillerUrl(actual_url); 40 return dom_distiller::url_utils::GetOriginalUrlFromDistillerUrl(actual_url);
44 } 41 }
45 42
46 InstallableParams ParamsToPerformInstallableCheck( 43 InstallableParams ParamsToPerformManifestAndIconFetch(
47 int ideal_icon_size_in_px, 44 int ideal_icon_size_in_px,
48 int minimum_icon_size_in_px, 45 int minimum_icon_size_in_px,
49 int badge_size_in_px, 46 int badge_size_in_px,
50 bool check_webapk_compatibility) { 47 bool check_webapk_compatibility) {
51 InstallableParams params; 48 InstallableParams params;
52 params.ideal_primary_icon_size_in_px = ideal_icon_size_in_px; 49 params.ideal_primary_icon_size_in_px = ideal_icon_size_in_px;
53 params.minimum_primary_icon_size_in_px = minimum_icon_size_in_px; 50 params.minimum_primary_icon_size_in_px = minimum_icon_size_in_px;
54 params.check_installable = check_webapk_compatibility;
55 params.fetch_valid_primary_icon = true; 51 params.fetch_valid_primary_icon = true;
56 if (check_webapk_compatibility) { 52 if (check_webapk_compatibility) {
53 params.fetch_valid_badge_icon = true;
57 params.ideal_badge_icon_size_in_px = badge_size_in_px; 54 params.ideal_badge_icon_size_in_px = badge_size_in_px;
58 params.minimum_badge_icon_size_in_px = badge_size_in_px; 55 params.minimum_badge_icon_size_in_px = badge_size_in_px;
59 params.fetch_valid_badge_icon = true;
60 } 56 }
61 return params; 57 return params;
62 } 58 }
63 59
60 InstallableParams ParamsToPerformInstallableCheck(
61 bool check_webapk_compatibility) {
62 InstallableParams params;
63 params.check_installable = check_webapk_compatibility;
64 return params;
65 }
66
64 } // namespace 67 } // namespace
65 68
66 AddToHomescreenDataFetcher::AddToHomescreenDataFetcher( 69 AddToHomescreenDataFetcher::AddToHomescreenDataFetcher(
67 content::WebContents* web_contents, 70 content::WebContents* web_contents,
68 int ideal_icon_size_in_px, 71 int ideal_icon_size_in_px,
69 int minimum_icon_size_in_px, 72 int minimum_icon_size_in_px,
70 int ideal_splash_image_size_in_px, 73 int ideal_splash_image_size_in_px,
71 int minimum_splash_image_size_in_px, 74 int minimum_splash_image_size_in_px,
72 int badge_size_in_px, 75 int badge_size_in_px,
76 int data_timeout_ms,
73 bool check_webapk_compatibility, 77 bool check_webapk_compatibility,
74 Observer* observer) 78 Observer* observer)
75 : content::WebContentsObserver(web_contents), 79 : content::WebContentsObserver(web_contents),
80 installable_manager_(InstallableManager::FromWebContents(web_contents)),
76 weak_observer_(observer), 81 weak_observer_(observer),
77 shortcut_info_(GetShortcutUrl(web_contents->GetBrowserContext(), 82 shortcut_info_(GetShortcutUrl(web_contents->GetBrowserContext(),
78 web_contents->GetLastCommittedURL())), 83 web_contents->GetLastCommittedURL())),
79 ideal_icon_size_in_px_(ideal_icon_size_in_px), 84 ideal_icon_size_in_px_(ideal_icon_size_in_px),
80 minimum_icon_size_in_px_(minimum_icon_size_in_px), 85 minimum_icon_size_in_px_(minimum_icon_size_in_px),
81 ideal_splash_image_size_in_px_(ideal_splash_image_size_in_px), 86 ideal_splash_image_size_in_px_(ideal_splash_image_size_in_px),
82 minimum_splash_image_size_in_px_(minimum_splash_image_size_in_px), 87 minimum_splash_image_size_in_px_(minimum_splash_image_size_in_px),
83 badge_size_in_px_(badge_size_in_px), 88 badge_size_in_px_(badge_size_in_px),
89 data_timeout_ms_(data_timeout_ms),
84 check_webapk_compatibility_(check_webapk_compatibility), 90 check_webapk_compatibility_(check_webapk_compatibility),
85 is_waiting_for_web_application_info_(true), 91 is_waiting_for_web_application_info_(true),
86 is_installable_check_complete_(false), 92 is_installable_check_complete_(false),
87 is_icon_saved_(false) { 93 is_icon_saved_(false) {
88 DCHECK(minimum_icon_size_in_px <= ideal_icon_size_in_px); 94 DCHECK(minimum_icon_size_in_px <= ideal_icon_size_in_px);
89 DCHECK(minimum_splash_image_size_in_px <= ideal_splash_image_size_in_px); 95 DCHECK(minimum_splash_image_size_in_px <= ideal_splash_image_size_in_px);
90 96
91 // Send a message to the renderer to retrieve information about the page. 97 // Send a message to the renderer to retrieve information about the page.
92 content::RenderFrameHost* main_frame = web_contents->GetMainFrame(); 98 content::RenderFrameHost* main_frame = web_contents->GetMainFrame();
93 main_frame->Send( 99 main_frame->Send(
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
128 case WebApplicationInfo::MOBILE_CAPABLE_APPLE: 134 case WebApplicationInfo::MOBILE_CAPABLE_APPLE:
129 base::RecordAction( 135 base::RecordAction(
130 base::UserMetricsAction("webapps.AddShortcut.AppShortcutApple")); 136 base::UserMetricsAction("webapps.AddShortcut.AppShortcutApple"));
131 break; 137 break;
132 case WebApplicationInfo::MOBILE_CAPABLE_UNSPECIFIED: 138 case WebApplicationInfo::MOBILE_CAPABLE_UNSPECIFIED:
133 base::RecordAction( 139 base::RecordAction(
134 base::UserMetricsAction("webapps.AddShortcut.Bookmark")); 140 base::UserMetricsAction("webapps.AddShortcut.Bookmark"));
135 break; 141 break;
136 } 142 }
137 143
138 InstallableManager::CreateForWebContents(web_contents());
139 InstallableManager* manager =
140 InstallableManager::FromWebContents(web_contents());
141 DCHECK(manager);
142
143 // Kick off a timeout for downloading data. If we haven't finished within the 144 // Kick off a timeout for downloading data. If we haven't finished within the
144 // timeout, fall back to using a dynamically-generated launcher icon. 145 // timeout, fall back to using a dynamically-generated launcher icon.
145 data_timeout_timer_.Start( 146 data_timeout_timer_.Start(
146 FROM_HERE, base::TimeDelta::FromMilliseconds(kDataTimeoutInMilliseconds), 147 FROM_HERE, base::TimeDelta::FromMilliseconds(data_timeout_ms_),
147 base::Bind(&AddToHomescreenDataFetcher::OnDataTimedout, this)); 148 base::Bind(&AddToHomescreenDataFetcher::OnDataTimedout, this));
148 149
149 manager->GetData( 150 installable_manager_->GetData(
150 ParamsToPerformInstallableCheck(ideal_icon_size_in_px_, 151 ParamsToPerformManifestAndIconFetch(
151 minimum_icon_size_in_px_, 152 ideal_icon_size_in_px_, minimum_icon_size_in_px_, badge_size_in_px_,
152 badge_size_in_px_, 153 check_webapk_compatibility_),
153 check_webapk_compatibility_), 154 base::Bind(&AddToHomescreenDataFetcher::OnDidGetManifestAndIcons, this));
154 base::Bind(&AddToHomescreenDataFetcher::OnDidPerformInstallableCheck,
155 this));
156 } 155 }
157 156
158 AddToHomescreenDataFetcher::~AddToHomescreenDataFetcher() { 157 AddToHomescreenDataFetcher::~AddToHomescreenDataFetcher() {
159 DCHECK(!weak_observer_); 158 DCHECK(!weak_observer_);
160 } 159 }
161 160
162 bool AddToHomescreenDataFetcher::OnMessageReceived( 161 bool AddToHomescreenDataFetcher::OnMessageReceived(
163 const IPC::Message& message, 162 const IPC::Message& message,
164 content::RenderFrameHost* sender) { 163 content::RenderFrameHost* sender) {
165 if (!is_waiting_for_web_application_info_) 164 if (!is_waiting_for_web_application_info_)
(...skipping 15 matching lines...) Expand all
181 return; 180 return;
182 181
183 if (!is_installable_check_complete_) { 182 if (!is_installable_check_complete_) {
184 is_installable_check_complete_ = true; 183 is_installable_check_complete_ = true;
185 if (check_webapk_compatibility_) 184 if (check_webapk_compatibility_)
186 weak_observer_->OnDidDetermineWebApkCompatibility(false); 185 weak_observer_->OnDidDetermineWebApkCompatibility(false);
187 weak_observer_->OnUserTitleAvailable(shortcut_info_.user_title); 186 weak_observer_->OnUserTitleAvailable(shortcut_info_.user_title);
188 } 187 }
189 188
190 badge_icon_.reset(); 189 badge_icon_.reset();
191 CreateLauncherIcon(SkBitmap()); 190 CreateLauncherIcon(raw_primary_icon_);
192 } 191 }
193 192
194 void AddToHomescreenDataFetcher::OnDidPerformInstallableCheck( 193 void AddToHomescreenDataFetcher::OnDidGetManifestAndIcons(
195 const InstallableData& data) { 194 const InstallableData& data) {
196 data_timeout_timer_.Stop();
197 badge_icon_.reset();
198
199 if (!web_contents() || !weak_observer_ || is_installable_check_complete_) 195 if (!web_contents() || !weak_observer_ || is_installable_check_complete_)
200 return; 196 return;
201 197
202 is_installable_check_complete_ = true;
203
204 bool webapk_compatible = false;
205 if (check_webapk_compatibility_) {
206 webapk_compatible = (data.error_code == NO_ERROR_DETECTED &&
207 AreWebManifestUrlsWebApkCompatible(data.manifest));
208 weak_observer_->OnDidDetermineWebApkCompatibility(webapk_compatible);
209
210 if (webapk_compatible) {
211 // WebAPKs are wholly defined by the Web Manifest. Ignore the <meta> tag
212 // data received in OnDidGetWebApplicationInfo().
213 shortcut_info_ = ShortcutInfo(GURL());
214 }
215 }
216
217 if (!data.manifest.IsEmpty()) { 198 if (!data.manifest.IsEmpty()) {
218 base::RecordAction(base::UserMetricsAction("webapps.AddShortcut.Manifest")); 199 base::RecordAction(base::UserMetricsAction("webapps.AddShortcut.Manifest"));
219 shortcut_info_.UpdateFromManifest(data.manifest); 200 shortcut_info_.UpdateFromManifest(data.manifest);
220 shortcut_info_.manifest_url = data.manifest_url; 201 shortcut_info_.manifest_url = data.manifest_url;
202 }
221 203
222 if (webapk_compatible) { 204 // Do this after updating from the manifest for the case where a site has
223 shortcut_info_.UpdateSource(ShortcutInfo::SOURCE_ADD_TO_HOMESCREEN_PWA); 205 // a manifest with name and standalone specified, but no icons.
206 if (data.manifest.IsEmpty() || !data.primary_icon) {
207 if (check_webapk_compatibility_)
208 weak_observer_->OnDidDetermineWebApkCompatibility(false);
209 weak_observer_->OnUserTitleAvailable(shortcut_info_.user_title);
210 data_timeout_timer_.Stop();
211 FetchFavicon();
212 return;
213 }
224 214
225 if (data.badge_icon && !data.badge_icon->drawsNothing()) { 215 raw_primary_icon_ = *data.primary_icon;
226 shortcut_info_.best_badge_icon_url = data.badge_icon_url; 216 shortcut_info_.best_primary_icon_url = data.primary_icon_url;
227 badge_icon_ = *data.badge_icon;
228 }
229 }
230 }
231 217
232 // Save the splash screen URL for the later download. 218 // Save the splash screen URL for the later download.
233 shortcut_info_.splash_image_url = 219 shortcut_info_.splash_image_url =
234 content::ManifestIconSelector::FindBestMatchingIcon( 220 content::ManifestIconSelector::FindBestMatchingIcon(
235 data.manifest.icons, ideal_splash_image_size_in_px_, 221 data.manifest.icons, ideal_splash_image_size_in_px_,
236 minimum_splash_image_size_in_px_, 222 minimum_splash_image_size_in_px_,
237 content::Manifest::Icon::IconPurpose::ANY); 223 content::Manifest::Icon::IconPurpose::ANY);
238 shortcut_info_.ideal_splash_image_size_in_px = ideal_splash_image_size_in_px_; 224 shortcut_info_.ideal_splash_image_size_in_px = ideal_splash_image_size_in_px_;
239 shortcut_info_.minimum_splash_image_size_in_px = 225 shortcut_info_.minimum_splash_image_size_in_px =
240 minimum_splash_image_size_in_px_; 226 minimum_splash_image_size_in_px_;
227 if (data.badge_icon) {
228 shortcut_info_.best_badge_icon_url = data.badge_icon_url;
229 badge_icon_ = *data.badge_icon;
230 }
231
232 installable_manager_->GetData(
233 ParamsToPerformInstallableCheck(check_webapk_compatibility_),
234 base::Bind(&AddToHomescreenDataFetcher::OnDidPerformInstallableCheck,
235 this));
236 }
237
238 void AddToHomescreenDataFetcher::OnDidPerformInstallableCheck(
239 const InstallableData& data) {
240 data_timeout_timer_.Stop();
241
242 if (!web_contents() || !weak_observer_ || is_installable_check_complete_)
243 return;
244
245 is_installable_check_complete_ = true;
246
247 bool webapk_compatible = false;
248 if (check_webapk_compatibility_) {
249 webapk_compatible = (data.error_code == NO_ERROR_DETECTED &&
250 AreWebManifestUrlsWebApkCompatible(data.manifest));
251 weak_observer_->OnDidDetermineWebApkCompatibility(webapk_compatible);
252 }
241 253
242 weak_observer_->OnUserTitleAvailable(shortcut_info_.user_title); 254 weak_observer_->OnUserTitleAvailable(shortcut_info_.user_title);
243 255 if (webapk_compatible) {
244 if (data.primary_icon) { 256 shortcut_info_.UpdateSource(ShortcutInfo::SOURCE_ADD_TO_HOMESCREEN_PWA);
245 shortcut_info_.best_primary_icon_url = data.primary_icon_url; 257 NotifyObserver(raw_primary_icon_);
246 258 } else {
247 if (webapk_compatible) 259 CreateLauncherIcon(raw_primary_icon_);
248 NotifyObserver(*data.primary_icon);
249 else
250 CreateLauncherIcon(*(data.primary_icon));
251 return;
252 } 260 }
253
254 FetchFavicon();
255 } 261 }
256 262
257 void AddToHomescreenDataFetcher::FetchFavicon() { 263 void AddToHomescreenDataFetcher::FetchFavicon() {
258 if (!web_contents() || !weak_observer_) 264 if (!web_contents() || !weak_observer_)
259 return; 265 return;
260 266
261 // Grab the best, largest icon we can find to represent this bookmark. 267 // Grab the best, largest icon we can find to represent this bookmark.
262 // TODO(dfalcantara): Try combining with the new BookmarksHandler once its 268 // TODO(dfalcantara): Try combining with the new BookmarksHandler once its
263 // rewrite is further along. 269 // rewrite is further along.
264 std::vector<int> icon_types{ 270 std::vector<int> icon_types{
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
297 CreateLauncherIconFromFaviconInBackground, 303 CreateLauncherIconFromFaviconInBackground,
298 base::Unretained(this), bitmap_result), 304 base::Unretained(this), bitmap_result),
299 base::BindOnce(&AddToHomescreenDataFetcher::NotifyObserver, 305 base::BindOnce(&AddToHomescreenDataFetcher::NotifyObserver,
300 base::RetainedRef(this))); 306 base::RetainedRef(this)));
301 } 307 }
302 308
303 SkBitmap AddToHomescreenDataFetcher::CreateLauncherIconFromFaviconInBackground( 309 SkBitmap AddToHomescreenDataFetcher::CreateLauncherIconFromFaviconInBackground(
304 const favicon_base::FaviconRawBitmapResult& bitmap_result) { 310 const favicon_base::FaviconRawBitmapResult& bitmap_result) {
305 base::ThreadRestrictions::AssertIOAllowed(); 311 base::ThreadRestrictions::AssertIOAllowed();
306 312
307 SkBitmap raw_icon;
308 if (bitmap_result.is_valid()) { 313 if (bitmap_result.is_valid()) {
309 gfx::PNGCodec::Decode(bitmap_result.bitmap_data->front(), 314 gfx::PNGCodec::Decode(bitmap_result.bitmap_data->front(),
310 bitmap_result.bitmap_data->size(), &raw_icon); 315 bitmap_result.bitmap_data->size(),
316 &raw_primary_icon_);
311 } 317 }
312 318
313 shortcut_info_.best_primary_icon_url = bitmap_result.icon_url; 319 shortcut_info_.best_primary_icon_url = bitmap_result.icon_url;
314 return CreateLauncherIconInBackground(raw_icon); 320 return CreateLauncherIconInBackground(raw_primary_icon_);
315 } 321 }
316 322
317 void AddToHomescreenDataFetcher::CreateLauncherIcon(const SkBitmap& raw_icon) { 323 void AddToHomescreenDataFetcher::CreateLauncherIcon(const SkBitmap& icon) {
pkotwicz 2017/06/27 15:48:19 |icon| looks unused
dominickn 2017/06/28 01:38:05 Whoops fixed.
318 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 324 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
319 325
320 // The user is waiting for the icon to be processed before they can proceed 326 // The user is waiting for the icon to be processed before they can proceed
321 // with add to homescreen. But if we shut down, there's no point starting the 327 // with add to homescreen. But if we shut down, there's no point starting the
322 // image processing. Use USER_VISIBLE with MayBlock and SKIP_ON_SHUTDOWN. 328 // image processing. Use USER_VISIBLE with MayBlock and SKIP_ON_SHUTDOWN.
323 base::PostTaskWithTraitsAndReplyWithResult( 329 base::PostTaskWithTraitsAndReplyWithResult(
324 FROM_HERE, 330 FROM_HERE,
325 {base::MayBlock(), base::TaskPriority::USER_VISIBLE, 331 {base::MayBlock(), base::TaskPriority::USER_VISIBLE,
326 base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}, 332 base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN},
327 base::BindOnce( 333 base::BindOnce(
328 &AddToHomescreenDataFetcher::CreateLauncherIconInBackground, 334 &AddToHomescreenDataFetcher::CreateLauncherIconInBackground,
329 base::Unretained(this), raw_icon), 335 base::Unretained(this), raw_primary_icon_),
330 base::BindOnce(&AddToHomescreenDataFetcher::NotifyObserver, 336 base::BindOnce(&AddToHomescreenDataFetcher::NotifyObserver,
331 base::RetainedRef(this))); 337 base::RetainedRef(this)));
332 } 338 }
333 339
334 SkBitmap AddToHomescreenDataFetcher::CreateLauncherIconInBackground( 340 SkBitmap AddToHomescreenDataFetcher::CreateLauncherIconInBackground(
335 const SkBitmap& raw_icon) { 341 const SkBitmap& icon) {
336 base::ThreadRestrictions::AssertIOAllowed(); 342 base::ThreadRestrictions::AssertIOAllowed();
337 343
338 SkBitmap primary_icon; 344 SkBitmap primary_icon;
339 bool is_generated = false; 345 bool is_generated = false;
340 if (weak_observer_) { 346 if (weak_observer_) {
341 primary_icon = weak_observer_->FinalizeLauncherIconInBackground( 347 primary_icon = weak_observer_->FinalizeLauncherIconInBackground(
342 raw_icon, shortcut_info_.url, &is_generated); 348 icon, shortcut_info_.url, &is_generated);
343 } 349 }
344 350
345 if (is_generated) 351 if (is_generated)
346 shortcut_info_.best_primary_icon_url = GURL(); 352 shortcut_info_.best_primary_icon_url = GURL();
347 353
348 return primary_icon; 354 return primary_icon;
349 } 355 }
350 356
351 void AddToHomescreenDataFetcher::NotifyObserver(const SkBitmap& primary_icon) { 357 void AddToHomescreenDataFetcher::NotifyObserver(const SkBitmap& primary_icon) {
352 DCHECK_CURRENTLY_ON(content::BrowserThread::UI); 358 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
353 if (!web_contents() || !weak_observer_ || is_icon_saved_) 359 if (!web_contents() || !weak_observer_ || is_icon_saved_)
pkotwicz 2017/06/27 15:48:20 Aside: |is_icon_saved_| should now always be false
dominickn 2017/06/28 01:38:05 Indeed. Removed.
354 return; 360 return;
355 361
356 is_icon_saved_ = true; 362 is_icon_saved_ = true;
357 primary_icon_ = primary_icon; 363 primary_icon_ = primary_icon;
358 weak_observer_->OnDataAvailable(shortcut_info_, primary_icon_, badge_icon_); 364 weak_observer_->OnDataAvailable(shortcut_info_, primary_icon_, badge_icon_);
359 } 365 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698