OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 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/shortcut_helper.h" | 5 #include "chrome/browser/android/shortcut_helper.h" |
6 | 6 |
7 #include <jni.h> | 7 #include <jni.h> |
| 8 #include <limits> |
8 | 9 |
9 #include "base/android/jni_android.h" | 10 #include "base/android/jni_android.h" |
10 #include "base/android/jni_string.h" | 11 #include "base/android/jni_string.h" |
11 #include "base/basictypes.h" | 12 #include "base/basictypes.h" |
12 #include "base/location.h" | 13 #include "base/location.h" |
13 #include "base/strings/string16.h" | 14 #include "base/strings/string16.h" |
| 15 #include "base/strings/utf_string_conversions.h" |
14 #include "base/task/cancelable_task_tracker.h" | 16 #include "base/task/cancelable_task_tracker.h" |
15 #include "base/threading/worker_pool.h" | 17 #include "base/threading/worker_pool.h" |
16 #include "chrome/browser/android/tab_android.h" | 18 #include "chrome/browser/android/tab_android.h" |
17 #include "chrome/browser/favicon/favicon_service.h" | 19 #include "chrome/browser/favicon/favicon_service.h" |
18 #include "chrome/browser/favicon/favicon_service_factory.h" | 20 #include "chrome/browser/favicon/favicon_service_factory.h" |
19 #include "chrome/common/chrome_constants.h" | 21 #include "chrome/common/chrome_constants.h" |
20 #include "chrome/common/render_messages.h" | 22 #include "chrome/common/render_messages.h" |
21 #include "chrome/common/web_application_info.h" | 23 #include "chrome/common/web_application_info.h" |
22 #include "content/public/browser/user_metrics.h" | 24 #include "content/public/browser/user_metrics.h" |
23 #include "content/public/browser/web_contents.h" | 25 #include "content/public/browser/web_contents.h" |
24 #include "content/public/browser/web_contents_observer.h" | 26 #include "content/public/browser/web_contents_observer.h" |
25 #include "content/public/common/frame_navigate_params.h" | 27 #include "content/public/common/frame_navigate_params.h" |
26 #include "content/public/common/manifest.h" | 28 #include "content/public/common/manifest.h" |
27 #include "jni/ShortcutHelper_jni.h" | 29 #include "jni/ShortcutHelper_jni.h" |
| 30 #include "net/base/mime_util.h" |
28 #include "ui/gfx/android/java_bitmap.h" | 31 #include "ui/gfx/android/java_bitmap.h" |
29 #include "ui/gfx/codec/png_codec.h" | 32 #include "ui/gfx/codec/png_codec.h" |
30 #include "ui/gfx/color_analysis.h" | 33 #include "ui/gfx/color_analysis.h" |
31 #include "ui/gfx/favicon_size.h" | 34 #include "ui/gfx/favicon_size.h" |
| 35 #include "ui/gfx/screen.h" |
32 #include "url/gurl.h" | 36 #include "url/gurl.h" |
33 | 37 |
| 38 using content::Manifest; |
| 39 |
| 40 // Android's preferred icon size in DP is 48, as defined in |
| 41 // http://developer.android.com/design/style/iconography.html |
| 42 const int ShortcutHelper::kPreferredIconSizeInDp = 48; |
| 43 |
34 jlong Initialize(JNIEnv* env, jobject obj, jlong tab_android_ptr) { | 44 jlong Initialize(JNIEnv* env, jobject obj, jlong tab_android_ptr) { |
35 TabAndroid* tab = reinterpret_cast<TabAndroid*>(tab_android_ptr); | 45 TabAndroid* tab = reinterpret_cast<TabAndroid*>(tab_android_ptr); |
36 | 46 |
37 ShortcutHelper* shortcut_helper = | 47 ShortcutHelper* shortcut_helper = |
38 new ShortcutHelper(env, obj, tab->web_contents()); | 48 new ShortcutHelper(env, obj, tab->web_contents()); |
39 shortcut_helper->Initialize(); | 49 shortcut_helper->Initialize(); |
40 | 50 |
41 return reinterpret_cast<intptr_t>(shortcut_helper); | 51 return reinterpret_cast<intptr_t>(shortcut_helper); |
42 } | 52 } |
43 | 53 |
44 ShortcutHelper::ShortcutHelper(JNIEnv* env, | 54 ShortcutHelper::ShortcutHelper(JNIEnv* env, |
45 jobject obj, | 55 jobject obj, |
46 content::WebContents* web_contents) | 56 content::WebContents* web_contents) |
47 : WebContentsObserver(web_contents), | 57 : WebContentsObserver(web_contents), |
48 java_ref_(env, obj), | 58 java_ref_(env, obj), |
49 url_(web_contents->GetURL()), | 59 url_(web_contents->GetURL()), |
50 display_(content::Manifest::DISPLAY_MODE_BROWSER), | 60 display_(content::Manifest::DISPLAY_MODE_BROWSER), |
51 orientation_(blink::WebScreenOrientationLockDefault), | 61 orientation_(blink::WebScreenOrientationLockDefault), |
| 62 add_shortcut_requested_(false), |
| 63 manifest_icon_status_(MANIFEST_ICON_STATUS_NONE), |
| 64 preferred_icon_size_in_px_(kPreferredIconSizeInDp * |
| 65 gfx::Screen::GetScreenFor(web_contents->GetNativeView())-> |
| 66 GetPrimaryDisplay().device_scale_factor()), |
52 weak_ptr_factory_(this) { | 67 weak_ptr_factory_(this) { |
53 } | 68 } |
54 | 69 |
55 void ShortcutHelper::Initialize() { | 70 void ShortcutHelper::Initialize() { |
56 // Send a message to the renderer to retrieve information about the page. | 71 // Send a message to the renderer to retrieve information about the page. |
57 Send(new ChromeViewMsg_GetWebApplicationInfo(routing_id())); | 72 Send(new ChromeViewMsg_GetWebApplicationInfo(routing_id())); |
58 } | 73 } |
59 | 74 |
60 ShortcutHelper::~ShortcutHelper() { | 75 ShortcutHelper::~ShortcutHelper() { |
61 } | 76 } |
(...skipping 28 matching lines...) Expand all Loading... |
90 case WebApplicationInfo::MOBILE_CAPABLE_UNSPECIFIED: | 105 case WebApplicationInfo::MOBILE_CAPABLE_UNSPECIFIED: |
91 content::RecordAction( | 106 content::RecordAction( |
92 base::UserMetricsAction("webapps.AddShortcut.Bookmark")); | 107 base::UserMetricsAction("webapps.AddShortcut.Bookmark")); |
93 break; | 108 break; |
94 } | 109 } |
95 | 110 |
96 web_contents()->GetManifest(base::Bind(&ShortcutHelper::OnDidGetManifest, | 111 web_contents()->GetManifest(base::Bind(&ShortcutHelper::OnDidGetManifest, |
97 weak_ptr_factory_.GetWeakPtr())); | 112 weak_ptr_factory_.GetWeakPtr())); |
98 } | 113 } |
99 | 114 |
| 115 bool ShortcutHelper::IconSizesContainsPreferredSize( |
| 116 const std::vector<gfx::Size>& sizes) const { |
| 117 for (size_t i = 0; i < sizes.size(); ++i) { |
| 118 if (sizes[i].height() != sizes[i].width()) |
| 119 continue; |
| 120 if (sizes[i].width() == preferred_icon_size_in_px_) |
| 121 return true; |
| 122 } |
| 123 |
| 124 return false; |
| 125 } |
| 126 |
| 127 bool ShortcutHelper::IconSizesContainsAny( |
| 128 const std::vector<gfx::Size>& sizes) const { |
| 129 for (size_t i = 0; i < sizes.size(); ++i) { |
| 130 if (sizes[i].IsEmpty()) |
| 131 return true; |
| 132 } |
| 133 |
| 134 return false; |
| 135 } |
| 136 |
| 137 GURL ShortcutHelper::FindBestMatchingIcon( |
| 138 const std::vector<Manifest::Icon>& icons, float density) const { |
| 139 GURL url; |
| 140 int best_delta = std::numeric_limits<int>::min(); |
| 141 |
| 142 for (size_t i = 0; i < icons.size(); ++i) { |
| 143 if (icons[i].density != density) |
| 144 continue; |
| 145 |
| 146 const std::vector<gfx::Size>& sizes = icons[i].sizes; |
| 147 for (size_t j = 0; j < sizes.size(); ++j) { |
| 148 if (sizes[j].height() != sizes[j].width()) |
| 149 continue; |
| 150 int delta = sizes[j].width() - preferred_icon_size_in_px_; |
| 151 if (delta == 0) |
| 152 return icons[i].src; |
| 153 if (best_delta > 0 && delta < 0) |
| 154 continue; |
| 155 if ((best_delta > 0 && delta < best_delta) || |
| 156 (best_delta < 0 && delta > best_delta)) { |
| 157 url = icons[i].src; |
| 158 best_delta = delta; |
| 159 } |
| 160 } |
| 161 } |
| 162 |
| 163 return url; |
| 164 } |
| 165 |
| 166 // static |
| 167 std::vector<Manifest::Icon> ShortcutHelper::FilterIconsByType( |
| 168 const std::vector<Manifest::Icon>& icons) { |
| 169 std::vector<Manifest::Icon> result; |
| 170 |
| 171 for (size_t i = 0; i < icons.size(); ++i) { |
| 172 if (icons[i].type.is_null() || |
| 173 net::IsSupportedImageMimeType( |
| 174 base::UTF16ToUTF8(icons[i].type.string()))) { |
| 175 result.push_back(icons[i]); |
| 176 } |
| 177 } |
| 178 |
| 179 return result; |
| 180 } |
| 181 |
| 182 GURL ShortcutHelper::FindBestMatchingIcon( |
| 183 const std::vector<Manifest::Icon>& unfiltered_icons) const { |
| 184 const float device_scale_factor = |
| 185 gfx::Screen::GetScreenFor(web_contents()->GetNativeView())-> |
| 186 GetPrimaryDisplay().device_scale_factor(); |
| 187 |
| 188 GURL url; |
| 189 std::vector<Manifest::Icon> icons = FilterIconsByType(unfiltered_icons); |
| 190 |
| 191 // The first pass is to find the ideal icon. That icon is of the right size |
| 192 // with the default density or the device's density. |
| 193 for (size_t i = 0; i < icons.size(); ++i) { |
| 194 if (icons[i].density == device_scale_factor && |
| 195 IconSizesContainsPreferredSize(icons[i].sizes)) { |
| 196 return icons[i].src; |
| 197 } |
| 198 |
| 199 // If there is an icon with the right size but not the right density, keep |
| 200 // it on the side and only use it if nothing better is found. |
| 201 if (icons[i].density == Manifest::Icon::kDefaultDensity && |
| 202 IconSizesContainsPreferredSize(icons[i].sizes)) { |
| 203 url = icons[i].src; |
| 204 } |
| 205 } |
| 206 |
| 207 // The second pass is to find an icon with 'any'. The current device scale |
| 208 // factor is preferred. Otherwise, the default scale factor is used. |
| 209 for (size_t i = 0; i < icons.size(); ++i) { |
| 210 if (icons[i].density == device_scale_factor && |
| 211 IconSizesContainsAny(icons[i].sizes)) { |
| 212 return icons[i].src; |
| 213 } |
| 214 |
| 215 // If there is an icon with 'any' but not the right density, keep it on the |
| 216 // side and only use it if nothing better is found. |
| 217 if (icons[i].density == Manifest::Icon::kDefaultDensity && |
| 218 IconSizesContainsAny(icons[i].sizes)) { |
| 219 url = icons[i].src; |
| 220 } |
| 221 } |
| 222 |
| 223 // The last pass will try to find the best suitable icon for the device's |
| 224 // scale factor. If none, another pass will be run using kDefaultDensity. |
| 225 if (!url.is_valid()) |
| 226 url = FindBestMatchingIcon(icons, device_scale_factor); |
| 227 if (!url.is_valid()) |
| 228 url = FindBestMatchingIcon(icons, Manifest::Icon::kDefaultDensity); |
| 229 |
| 230 return url; |
| 231 } |
| 232 |
100 void ShortcutHelper::OnDidGetManifest(const content::Manifest& manifest) { | 233 void ShortcutHelper::OnDidGetManifest(const content::Manifest& manifest) { |
101 // Set the title based on the manifest value, if any. | 234 // Set the title based on the manifest value, if any. |
102 if (!manifest.short_name.is_null()) | 235 if (!manifest.short_name.is_null()) |
103 title_ = manifest.short_name.string(); | 236 title_ = manifest.short_name.string(); |
104 else if (!manifest.name.is_null()) | 237 else if (!manifest.name.is_null()) |
105 title_ = manifest.name.string(); | 238 title_ = manifest.name.string(); |
106 | 239 |
107 // Set the url based on the manifest value, if any. | 240 // Set the url based on the manifest value, if any. |
108 if (manifest.start_url.is_valid()) | 241 if (manifest.start_url.is_valid()) |
109 url_ = manifest.start_url; | 242 url_ = manifest.start_url; |
(...skipping 11 matching lines...) Expand all Loading... |
121 | 254 |
122 // Set the orientation based on the manifest value, if any. | 255 // Set the orientation based on the manifest value, if any. |
123 if (manifest.orientation != blink::WebScreenOrientationLockDefault) { | 256 if (manifest.orientation != blink::WebScreenOrientationLockDefault) { |
124 // Ignore the orientation if the display mode is different from | 257 // Ignore the orientation if the display mode is different from |
125 // 'standalone'. | 258 // 'standalone'. |
126 // TODO(mlamouri): send a message to the developer console about this. | 259 // TODO(mlamouri): send a message to the developer console about this. |
127 if (display_ == content::Manifest::DISPLAY_MODE_STANDALONE) | 260 if (display_ == content::Manifest::DISPLAY_MODE_STANDALONE) |
128 orientation_ = manifest.orientation; | 261 orientation_ = manifest.orientation; |
129 } | 262 } |
130 | 263 |
| 264 GURL icon_src = FindBestMatchingIcon(manifest.icons); |
| 265 if (icon_src.is_valid()) { |
| 266 web_contents()->DownloadImage(icon_src, |
| 267 false, |
| 268 preferred_icon_size_in_px_, |
| 269 base::Bind(&ShortcutHelper::OnDidDownloadIcon, |
| 270 weak_ptr_factory_.GetWeakPtr())); |
| 271 manifest_icon_status_ = MANIFEST_ICON_STATUS_FETCHING; |
| 272 } |
| 273 |
131 // The ShortcutHelper is now able to notify its Java counterpart that it is | 274 // The ShortcutHelper is now able to notify its Java counterpart that it is |
132 // initialized. OnInitialized method is not conceptually part of getting the | 275 // initialized. OnInitialized method is not conceptually part of getting the |
133 // manifest data but it happens that the initialization is finalized when | 276 // manifest data but it happens that the initialization is finalized when |
134 // these data are available. | 277 // these data are available. |
135 JNIEnv* env = base::android::AttachCurrentThread(); | 278 JNIEnv* env = base::android::AttachCurrentThread(); |
136 ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env); | 279 ScopedJavaLocalRef<jobject> j_obj = java_ref_.get(env); |
137 ScopedJavaLocalRef<jstring> j_title = | 280 ScopedJavaLocalRef<jstring> j_title = |
138 base::android::ConvertUTF16ToJavaString(env, title_); | 281 base::android::ConvertUTF16ToJavaString(env, title_); |
139 | 282 |
140 Java_ShortcutHelper_onInitialized(env, j_obj.obj(), j_title.obj()); | 283 Java_ShortcutHelper_onInitialized(env, j_obj.obj(), j_title.obj()); |
141 } | 284 } |
142 | 285 |
| 286 void ShortcutHelper::OnDidDownloadIcon(int id, |
| 287 int http_status_code, |
| 288 const GURL& url, |
| 289 const std::vector<SkBitmap>& bitmaps, |
| 290 const std::vector<gfx::Size>& sizes) { |
| 291 // If getting the candidate manifest icon failed, the ShortcutHelper should |
| 292 // fallback to the favicon. |
| 293 // If the user already requested to add the shortcut, it will do so but use |
| 294 // the favicon instead. |
| 295 // Otherwise, it sets the state as if there was no manifest icon pending. |
| 296 if (bitmaps.empty()) { |
| 297 if (add_shortcut_requested_) |
| 298 AddShortcutUsingFavicon(); |
| 299 else |
| 300 manifest_icon_status_ = MANIFEST_ICON_STATUS_NONE; |
| 301 return; |
| 302 } |
| 303 |
| 304 // There might be multiple bitmaps returned. The one to pick is bigger or |
| 305 // equal to the preferred size. |bitmaps| is ordered from bigger to smaller. |
| 306 int preferred_bitmap_index = 0; |
| 307 for (size_t i = 0; i < bitmaps.size(); ++i) { |
| 308 if (bitmaps[i].height() < preferred_icon_size_in_px_) |
| 309 break; |
| 310 preferred_bitmap_index = i; |
| 311 } |
| 312 |
| 313 manifest_icon_ = bitmaps[preferred_bitmap_index]; |
| 314 manifest_icon_status_ = MANIFEST_ICON_STATUS_DONE; |
| 315 |
| 316 if (add_shortcut_requested_) |
| 317 AddShortcutUsingManifestIcon(); |
| 318 } |
| 319 |
143 void ShortcutHelper::TearDown(JNIEnv*, jobject) { | 320 void ShortcutHelper::TearDown(JNIEnv*, jobject) { |
144 Destroy(); | 321 Destroy(); |
145 } | 322 } |
146 | 323 |
147 void ShortcutHelper::Destroy() { | 324 void ShortcutHelper::Destroy() { |
148 delete this; | 325 delete this; |
149 } | 326 } |
150 | 327 |
151 void ShortcutHelper::AddShortcut( | 328 void ShortcutHelper::AddShortcut( |
152 JNIEnv* env, | 329 JNIEnv* env, |
153 jobject obj, | 330 jobject obj, |
154 jstring jtitle, | 331 jstring jtitle, |
155 jint launcher_large_icon_size) { | 332 jint launcher_large_icon_size) { |
| 333 add_shortcut_requested_ = true; |
| 334 |
156 base::string16 title = base::android::ConvertJavaStringToUTF16(env, jtitle); | 335 base::string16 title = base::android::ConvertJavaStringToUTF16(env, jtitle); |
157 if (!title.empty()) | 336 if (!title.empty()) |
158 title_ = title; | 337 title_ = title; |
159 | 338 |
| 339 switch (manifest_icon_status_) { |
| 340 case MANIFEST_ICON_STATUS_NONE: |
| 341 AddShortcutUsingFavicon(); |
| 342 break; |
| 343 case MANIFEST_ICON_STATUS_FETCHING: |
| 344 // ::OnDidDownloadIcon() will call AddShortcutUsingManifestIcon(). |
| 345 break; |
| 346 case MANIFEST_ICON_STATUS_DONE: |
| 347 AddShortcutUsingManifestIcon(); |
| 348 break; |
| 349 } |
| 350 } |
| 351 |
| 352 void ShortcutHelper::AddShortcutUsingManifestIcon() { |
| 353 // Stop observing so we don't get destroyed while doing the last steps. |
| 354 Observe(NULL); |
| 355 |
| 356 base::WorkerPool::PostTask( |
| 357 FROM_HERE, |
| 358 base::Bind(&ShortcutHelper::AddShortcutInBackgroundWithSkBitmap, |
| 359 url_, |
| 360 title_, |
| 361 display_, |
| 362 manifest_icon_, |
| 363 orientation_), |
| 364 true); |
| 365 |
| 366 Destroy(); |
| 367 } |
| 368 |
| 369 void ShortcutHelper::AddShortcutUsingFavicon() { |
160 Profile* profile = | 370 Profile* profile = |
161 Profile::FromBrowserContext(web_contents()->GetBrowserContext()); | 371 Profile::FromBrowserContext(web_contents()->GetBrowserContext()); |
162 | 372 |
163 // Grab the best, largest icon we can find to represent this bookmark. | 373 // Grab the best, largest icon we can find to represent this bookmark. |
164 // TODO(dfalcantara): Try combining with the new BookmarksHandler once its | 374 // TODO(dfalcantara): Try combining with the new BookmarksHandler once its |
165 // rewrite is further along. | 375 // rewrite is further along. |
166 std::vector<int> icon_types; | 376 std::vector<int> icon_types; |
167 icon_types.push_back(favicon_base::FAVICON); | 377 icon_types.push_back(favicon_base::FAVICON); |
168 icon_types.push_back(favicon_base::TOUCH_PRECOMPOSED_ICON | | 378 icon_types.push_back(favicon_base::TOUCH_PRECOMPOSED_ICON | |
169 favicon_base::TOUCH_ICON); | 379 favicon_base::TOUCH_ICON); |
170 FaviconService* favicon_service = FaviconServiceFactory::GetForProfile( | 380 FaviconService* favicon_service = FaviconServiceFactory::GetForProfile( |
171 profile, Profile::EXPLICIT_ACCESS); | 381 profile, Profile::EXPLICIT_ACCESS); |
172 | 382 |
173 // Using favicon if its size is not smaller than platform required size, | 383 // Using favicon if its size is not smaller than platform required size, |
174 // otherwise using the largest icon among all avaliable icons. | 384 // otherwise using the largest icon among all avaliable icons. |
175 int threshold_to_get_any_largest_icon = launcher_large_icon_size_ - 1; | 385 int threshold_to_get_any_largest_icon = preferred_icon_size_in_px_ - 1; |
176 favicon_service->GetLargestRawFaviconForPageURL(url_, icon_types, | 386 favicon_service->GetLargestRawFaviconForPageURL(url_, icon_types, |
177 threshold_to_get_any_largest_icon, | 387 threshold_to_get_any_largest_icon, |
178 base::Bind(&ShortcutHelper::FinishAddingShortcut, | 388 base::Bind(&ShortcutHelper::OnDidGetFavicon, |
179 base::Unretained(this)), | 389 base::Unretained(this)), |
180 &cancelable_task_tracker_); | 390 &cancelable_task_tracker_); |
181 } | 391 } |
182 | 392 |
183 void ShortcutHelper::FinishAddingShortcut( | 393 void ShortcutHelper::OnDidGetFavicon( |
184 const favicon_base::FaviconRawBitmapResult& bitmap_result) { | 394 const favicon_base::FaviconRawBitmapResult& bitmap_result) { |
185 icon_ = bitmap_result; | |
186 | |
187 // Stop observing so we don't get destroyed while doing the last steps. | 395 // Stop observing so we don't get destroyed while doing the last steps. |
188 Observe(NULL); | 396 Observe(NULL); |
189 | 397 |
190 base::WorkerPool::PostTask( | 398 base::WorkerPool::PostTask( |
191 FROM_HERE, | 399 FROM_HERE, |
192 base::Bind(&ShortcutHelper::AddShortcutInBackground, | 400 base::Bind(&ShortcutHelper::AddShortcutInBackgroundWithRawBitmap, |
193 url_, | 401 url_, |
194 title_, | 402 title_, |
195 display_, | 403 display_, |
196 icon_, | 404 bitmap_result, |
197 orientation_), | 405 orientation_), |
198 true); | 406 true); |
199 | 407 |
200 Destroy(); | 408 Destroy(); |
201 } | 409 } |
202 | 410 |
203 bool ShortcutHelper::OnMessageReceived(const IPC::Message& message) { | 411 bool ShortcutHelper::OnMessageReceived(const IPC::Message& message) { |
204 bool handled = true; | 412 bool handled = true; |
205 | 413 |
206 IPC_BEGIN_MESSAGE_MAP(ShortcutHelper, message) | 414 IPC_BEGIN_MESSAGE_MAP(ShortcutHelper, message) |
207 IPC_MESSAGE_HANDLER(ChromeViewHostMsg_DidGetWebApplicationInfo, | 415 IPC_MESSAGE_HANDLER(ChromeViewHostMsg_DidGetWebApplicationInfo, |
208 OnDidGetWebApplicationInfo) | 416 OnDidGetWebApplicationInfo) |
209 IPC_MESSAGE_UNHANDLED(handled = false) | 417 IPC_MESSAGE_UNHANDLED(handled = false) |
210 IPC_END_MESSAGE_MAP() | 418 IPC_END_MESSAGE_MAP() |
211 | 419 |
212 return handled; | 420 return handled; |
213 } | 421 } |
214 | 422 |
215 void ShortcutHelper::WebContentsDestroyed() { | 423 void ShortcutHelper::WebContentsDestroyed() { |
216 Destroy(); | 424 Destroy(); |
217 } | 425 } |
218 | 426 |
219 bool ShortcutHelper::RegisterShortcutHelper(JNIEnv* env) { | 427 bool ShortcutHelper::RegisterShortcutHelper(JNIEnv* env) { |
220 return RegisterNativesImpl(env); | 428 return RegisterNativesImpl(env); |
221 } | 429 } |
222 | 430 |
223 void ShortcutHelper::AddShortcutInBackground( | 431 void ShortcutHelper::AddShortcutInBackgroundWithRawBitmap( |
224 const GURL& url, | 432 const GURL& url, |
225 const base::string16& title, | 433 const base::string16& title, |
226 content::Manifest::DisplayMode display, | 434 content::Manifest::DisplayMode display, |
227 const favicon_base::FaviconRawBitmapResult& bitmap_result, | 435 const favicon_base::FaviconRawBitmapResult& bitmap_result, |
228 blink::WebScreenOrientationLockType orientation) { | 436 blink::WebScreenOrientationLockType orientation) { |
229 DCHECK(base::WorkerPool::RunsTasksOnCurrentThread()); | 437 DCHECK(base::WorkerPool::RunsTasksOnCurrentThread()); |
230 | 438 |
231 // Grab the average color from the bitmap. | 439 SkBitmap icon_bitmap; |
232 SkColor color = SK_ColorWHITE; | |
233 SkBitmap favicon_bitmap; | |
234 if (bitmap_result.is_valid()) { | 440 if (bitmap_result.is_valid()) { |
235 if (gfx::PNGCodec::Decode(bitmap_result.bitmap_data->front(), | 441 gfx::PNGCodec::Decode(bitmap_result.bitmap_data->front(), |
236 bitmap_result.bitmap_data->size(), | 442 bitmap_result.bitmap_data->size(), |
237 &favicon_bitmap)) | 443 &icon_bitmap); |
238 color = color_utils::CalculateKMeanColorOfBitmap(favicon_bitmap); | |
239 } | 444 } |
240 | 445 |
| 446 AddShortcutInBackgroundWithSkBitmap( |
| 447 url, title, display, icon_bitmap, orientation); |
| 448 } |
| 449 |
| 450 void ShortcutHelper::AddShortcutInBackgroundWithSkBitmap( |
| 451 const GURL& url, |
| 452 const base::string16& title, |
| 453 content::Manifest::DisplayMode display, |
| 454 const SkBitmap& icon_bitmap, |
| 455 blink::WebScreenOrientationLockType orientation) { |
| 456 DCHECK(base::WorkerPool::RunsTasksOnCurrentThread()); |
| 457 |
| 458 SkColor color = color_utils::CalculateKMeanColorOfBitmap(icon_bitmap); |
241 int r_value = SkColorGetR(color); | 459 int r_value = SkColorGetR(color); |
242 int g_value = SkColorGetG(color); | 460 int g_value = SkColorGetG(color); |
243 int b_value = SkColorGetB(color); | 461 int b_value = SkColorGetB(color); |
244 | 462 |
245 // Send the data to the Java side to create the shortcut. | 463 // Send the data to the Java side to create the shortcut. |
246 JNIEnv* env = base::android::AttachCurrentThread(); | 464 JNIEnv* env = base::android::AttachCurrentThread(); |
247 ScopedJavaLocalRef<jstring> java_url = | 465 ScopedJavaLocalRef<jstring> java_url = |
248 base::android::ConvertUTF8ToJavaString(env, url.spec()); | 466 base::android::ConvertUTF8ToJavaString(env, url.spec()); |
249 ScopedJavaLocalRef<jstring> java_title = | 467 ScopedJavaLocalRef<jstring> java_title = |
250 base::android::ConvertUTF16ToJavaString(env, title); | 468 base::android::ConvertUTF16ToJavaString(env, title); |
251 ScopedJavaLocalRef<jobject> java_bitmap; | 469 ScopedJavaLocalRef<jobject> java_bitmap; |
252 if (favicon_bitmap.getSize()) | 470 if (icon_bitmap.getSize()) |
253 java_bitmap = gfx::ConvertToJavaBitmap(&favicon_bitmap); | 471 java_bitmap = gfx::ConvertToJavaBitmap(&icon_bitmap); |
254 | 472 |
255 Java_ShortcutHelper_addShortcut( | 473 Java_ShortcutHelper_addShortcut( |
256 env, | 474 env, |
257 base::android::GetApplicationContext(), | 475 base::android::GetApplicationContext(), |
258 java_url.obj(), | 476 java_url.obj(), |
259 java_title.obj(), | 477 java_title.obj(), |
260 java_bitmap.obj(), | 478 java_bitmap.obj(), |
261 r_value, | 479 r_value, |
262 g_value, | 480 g_value, |
263 b_value, | 481 b_value, |
264 display == content::Manifest::DISPLAY_MODE_STANDALONE, | 482 display == content::Manifest::DISPLAY_MODE_STANDALONE, |
265 orientation); | 483 orientation); |
266 } | 484 } |
OLD | NEW |