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 #include <limits> |
9 | 9 |
10 #include "base/android/jni_android.h" | 10 #include "base/android/jni_android.h" |
11 #include "base/android/jni_string.h" | 11 #include "base/android/jni_string.h" |
12 #include "base/basictypes.h" | 12 #include "base/basictypes.h" |
13 #include "base/location.h" | 13 #include "base/location.h" |
14 #include "base/strings/string16.h" | 14 #include "base/strings/string16.h" |
15 #include "base/strings/utf_string_conversions.h" | 15 #include "base/strings/utf_string_conversions.h" |
16 #include "base/task/cancelable_task_tracker.h" | 16 #include "base/task/cancelable_task_tracker.h" |
17 #include "base/threading/worker_pool.h" | 17 #include "base/threading/worker_pool.h" |
| 18 #include "chrome/browser/android/manifest_icon_selector.h" |
18 #include "chrome/browser/android/tab_android.h" | 19 #include "chrome/browser/android/tab_android.h" |
19 #include "chrome/browser/favicon/favicon_service.h" | 20 #include "chrome/browser/favicon/favicon_service.h" |
20 #include "chrome/browser/favicon/favicon_service_factory.h" | 21 #include "chrome/browser/favicon/favicon_service_factory.h" |
21 #include "chrome/browser/profiles/profile.h" | 22 #include "chrome/browser/profiles/profile.h" |
22 #include "chrome/common/chrome_constants.h" | 23 #include "chrome/common/chrome_constants.h" |
23 #include "chrome/common/render_messages.h" | 24 #include "chrome/common/render_messages.h" |
24 #include "chrome/common/web_application_info.h" | 25 #include "chrome/common/web_application_info.h" |
25 #include "components/dom_distiller/core/url_utils.h" | 26 #include "components/dom_distiller/core/url_utils.h" |
26 #include "content/public/browser/user_metrics.h" | 27 #include "content/public/browser/user_metrics.h" |
27 #include "content/public/browser/web_contents.h" | 28 #include "content/public/browser/web_contents.h" |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
108 case WebApplicationInfo::MOBILE_CAPABLE_UNSPECIFIED: | 109 case WebApplicationInfo::MOBILE_CAPABLE_UNSPECIFIED: |
109 content::RecordAction( | 110 content::RecordAction( |
110 base::UserMetricsAction("webapps.AddShortcut.Bookmark")); | 111 base::UserMetricsAction("webapps.AddShortcut.Bookmark")); |
111 break; | 112 break; |
112 } | 113 } |
113 | 114 |
114 web_contents()->GetManifest(base::Bind(&ShortcutHelper::OnDidGetManifest, | 115 web_contents()->GetManifest(base::Bind(&ShortcutHelper::OnDidGetManifest, |
115 weak_ptr_factory_.GetWeakPtr())); | 116 weak_ptr_factory_.GetWeakPtr())); |
116 } | 117 } |
117 | 118 |
118 bool ShortcutHelper::IconSizesContainsPreferredSize( | |
119 const std::vector<gfx::Size>& sizes) const { | |
120 for (size_t i = 0; i < sizes.size(); ++i) { | |
121 if (sizes[i].height() != sizes[i].width()) | |
122 continue; | |
123 if (sizes[i].width() == preferred_icon_size_in_px_) | |
124 return true; | |
125 } | |
126 | |
127 return false; | |
128 } | |
129 | |
130 bool ShortcutHelper::IconSizesContainsAny( | |
131 const std::vector<gfx::Size>& sizes) const { | |
132 for (size_t i = 0; i < sizes.size(); ++i) { | |
133 if (sizes[i].IsEmpty()) | |
134 return true; | |
135 } | |
136 | |
137 return false; | |
138 } | |
139 | |
140 GURL ShortcutHelper::FindBestMatchingIcon( | |
141 const std::vector<Manifest::Icon>& icons, float density) const { | |
142 GURL url; | |
143 int best_delta = std::numeric_limits<int>::min(); | |
144 | |
145 for (size_t i = 0; i < icons.size(); ++i) { | |
146 if (icons[i].density != density) | |
147 continue; | |
148 | |
149 const std::vector<gfx::Size>& sizes = icons[i].sizes; | |
150 for (size_t j = 0; j < sizes.size(); ++j) { | |
151 if (sizes[j].height() != sizes[j].width()) | |
152 continue; | |
153 int delta = sizes[j].width() - preferred_icon_size_in_px_; | |
154 if (delta == 0) | |
155 return icons[i].src; | |
156 if (best_delta > 0 && delta < 0) | |
157 continue; | |
158 if ((best_delta > 0 && delta < best_delta) || | |
159 (best_delta < 0 && delta > best_delta)) { | |
160 url = icons[i].src; | |
161 best_delta = delta; | |
162 } | |
163 } | |
164 } | |
165 | |
166 return url; | |
167 } | |
168 | |
169 // static | |
170 std::vector<Manifest::Icon> ShortcutHelper::FilterIconsByType( | |
171 const std::vector<Manifest::Icon>& icons) { | |
172 std::vector<Manifest::Icon> result; | |
173 | |
174 for (size_t i = 0; i < icons.size(); ++i) { | |
175 if (icons[i].type.is_null() || | |
176 net::IsSupportedImageMimeType( | |
177 base::UTF16ToUTF8(icons[i].type.string()))) { | |
178 result.push_back(icons[i]); | |
179 } | |
180 } | |
181 | |
182 return result; | |
183 } | |
184 | |
185 GURL ShortcutHelper::FindBestMatchingIcon( | |
186 const std::vector<Manifest::Icon>& unfiltered_icons) const { | |
187 const float device_scale_factor = | |
188 gfx::Screen::GetScreenFor(web_contents()->GetNativeView())-> | |
189 GetPrimaryDisplay().device_scale_factor(); | |
190 | |
191 GURL url; | |
192 std::vector<Manifest::Icon> icons = FilterIconsByType(unfiltered_icons); | |
193 | |
194 // The first pass is to find the ideal icon. That icon is of the right size | |
195 // with the default density or the device's density. | |
196 for (size_t i = 0; i < icons.size(); ++i) { | |
197 if (icons[i].density == device_scale_factor && | |
198 IconSizesContainsPreferredSize(icons[i].sizes)) { | |
199 return icons[i].src; | |
200 } | |
201 | |
202 // If there is an icon with the right size but not the right density, keep | |
203 // it on the side and only use it if nothing better is found. | |
204 if (icons[i].density == Manifest::Icon::kDefaultDensity && | |
205 IconSizesContainsPreferredSize(icons[i].sizes)) { | |
206 url = icons[i].src; | |
207 } | |
208 } | |
209 | |
210 // The second pass is to find an icon with 'any'. The current device scale | |
211 // factor is preferred. Otherwise, the default scale factor is used. | |
212 for (size_t i = 0; i < icons.size(); ++i) { | |
213 if (icons[i].density == device_scale_factor && | |
214 IconSizesContainsAny(icons[i].sizes)) { | |
215 return icons[i].src; | |
216 } | |
217 | |
218 // If there is an icon with 'any' but not the right density, keep it on the | |
219 // side and only use it if nothing better is found. | |
220 if (icons[i].density == Manifest::Icon::kDefaultDensity && | |
221 IconSizesContainsAny(icons[i].sizes)) { | |
222 url = icons[i].src; | |
223 } | |
224 } | |
225 | |
226 // The last pass will try to find the best suitable icon for the device's | |
227 // scale factor. If none, another pass will be run using kDefaultDensity. | |
228 if (!url.is_valid()) | |
229 url = FindBestMatchingIcon(icons, device_scale_factor); | |
230 if (!url.is_valid()) | |
231 url = FindBestMatchingIcon(icons, Manifest::Icon::kDefaultDensity); | |
232 | |
233 return url; | |
234 } | |
235 | |
236 void ShortcutHelper::OnDidGetManifest(const content::Manifest& manifest) { | 119 void ShortcutHelper::OnDidGetManifest(const content::Manifest& manifest) { |
237 if (!manifest.IsEmpty()) { | 120 if (!manifest.IsEmpty()) { |
238 content::RecordAction( | 121 content::RecordAction( |
239 base::UserMetricsAction("webapps.AddShortcut.Manifest")); | 122 base::UserMetricsAction("webapps.AddShortcut.Manifest")); |
240 } | 123 } |
241 | 124 |
242 // Set the title based on the manifest value, if any. | 125 // Set the title based on the manifest value, if any. |
243 if (!manifest.short_name.is_null()) | 126 if (!manifest.short_name.is_null()) |
244 title_ = manifest.short_name.string(); | 127 title_ = manifest.short_name.string(); |
245 else if (!manifest.name.is_null()) | 128 else if (!manifest.name.is_null()) |
(...skipping 16 matching lines...) Expand all Loading... |
262 | 145 |
263 // Set the orientation based on the manifest value, if any. | 146 // Set the orientation based on the manifest value, if any. |
264 if (manifest.orientation != blink::WebScreenOrientationLockDefault) { | 147 if (manifest.orientation != blink::WebScreenOrientationLockDefault) { |
265 // Ignore the orientation if the display mode is different from | 148 // Ignore the orientation if the display mode is different from |
266 // 'standalone'. | 149 // 'standalone'. |
267 // TODO(mlamouri): send a message to the developer console about this. | 150 // TODO(mlamouri): send a message to the developer console about this. |
268 if (display_ == content::Manifest::DISPLAY_MODE_STANDALONE) | 151 if (display_ == content::Manifest::DISPLAY_MODE_STANDALONE) |
269 orientation_ = manifest.orientation; | 152 orientation_ = manifest.orientation; |
270 } | 153 } |
271 | 154 |
272 GURL icon_src = FindBestMatchingIcon(manifest.icons); | 155 GURL icon_src = ManifestIconSelector::FindBestMatchingIcon( |
| 156 manifest.icons, |
| 157 kPreferredIconSizeInDp, |
| 158 gfx::Screen::GetScreenFor(web_contents()->GetNativeView())); |
273 if (icon_src.is_valid()) { | 159 if (icon_src.is_valid()) { |
274 web_contents()->DownloadImage(icon_src, | 160 web_contents()->DownloadImage(icon_src, |
275 false, | 161 false, |
276 preferred_icon_size_in_px_, | 162 preferred_icon_size_in_px_, |
277 base::Bind(&ShortcutHelper::OnDidDownloadIcon, | 163 base::Bind(&ShortcutHelper::OnDidDownloadIcon, |
278 weak_ptr_factory_.GetWeakPtr())); | 164 weak_ptr_factory_.GetWeakPtr())); |
279 manifest_icon_status_ = MANIFEST_ICON_STATUS_FETCHING; | 165 manifest_icon_status_ = MANIFEST_ICON_STATUS_FETCHING; |
280 } | 166 } |
281 | 167 |
282 // The ShortcutHelper is now able to notify its Java counterpart that it is | 168 // The ShortcutHelper is now able to notify its Java counterpart that it is |
(...skipping 200 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
483 base::android::GetApplicationContext(), | 369 base::android::GetApplicationContext(), |
484 java_url.obj(), | 370 java_url.obj(), |
485 java_title.obj(), | 371 java_title.obj(), |
486 java_bitmap.obj(), | 372 java_bitmap.obj(), |
487 r_value, | 373 r_value, |
488 g_value, | 374 g_value, |
489 b_value, | 375 b_value, |
490 display == content::Manifest::DISPLAY_MODE_STANDALONE, | 376 display == content::Manifest::DISPLAY_MODE_STANDALONE, |
491 orientation); | 377 orientation); |
492 } | 378 } |
OLD | NEW |