| 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 |