blob: d3522714cdf752721c7a755bc5ae121e411da167 [file] [log] [blame]
[email protected]51208252013-08-19 21:05:301// Copyright 2013 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.
4
5#include "chrome/browser/android/shortcut_helper.h"
6
7#include <jni.h>
8
9#include "base/android/jni_android.h"
lalitm45a03c72015-09-16 13:00:4310#include "base/android/jni_array.h"
[email protected]51208252013-08-19 21:05:3011#include "base/android/jni_string.h"
dominickn6509a4de2016-04-06 08:29:0612#include "base/bind.h"
13#include "base/callback.h"
pkotwicz206673142016-07-19 19:13:3014#include "base/command_line.h"
[email protected]51208252013-08-19 21:05:3015#include "base/strings/string16.h"
mlamouric679bbf2014-09-24 21:24:4916#include "base/strings/utf_string_conversions.h"
hanxi563f3532016-08-19 20:09:0117#include "chrome/browser/android/webapk/chrome_webapk_host.h"
hanxi070d10a2017-01-09 15:56:5018#include "chrome/browser/android/webapk/webapk_install_service.h"
lalitmd93c2ed2015-09-04 16:22:1219#include "chrome/browser/manifest/manifest_icon_downloader.h"
pkotwicz206673142016-07-19 19:13:3020#include "chrome/common/chrome_switches.h"
dfalcantaraaec56da2015-05-06 03:33:5621#include "content/public/browser/browser_thread.h"
[email protected]51208252013-08-19 21:05:3022#include "content/public/browser/web_contents.h"
[email protected]51208252013-08-19 21:05:3023#include "jni/ShortcutHelper_jni.h"
24#include "ui/gfx/android/java_bitmap.h"
mlamouribc6e8792015-10-22 20:41:1325#include "ui/gfx/color_analysis.h"
[email protected]51208252013-08-19 21:05:3026#include "url/gurl.h"
27
torne86560112016-08-04 15:59:0428using base::android::JavaParamRef;
29using base::android::ScopedJavaLocalRef;
mlamouric679bbf2014-09-24 21:24:4930using content::Manifest;
31
lalitm45a03c72015-09-16 13:00:4332namespace {
33
zpenge33ba852017-02-01 20:54:4234int g_ideal_homescreen_icon_size = -1;
35int g_minimum_homescreen_icon_size = -1;
36int g_ideal_splash_image_size = -1;
37int g_minimum_splash_image_size = -1;
38int g_ideal_badge_icon_size = -1;
lalitm45a03c72015-09-16 13:00:4339
zpenge33ba852017-02-01 20:54:4240int g_default_rgb_icon_value = 145;
mlamouribc6e8792015-10-22 20:41:1341
lalitm45a03c72015-09-16 13:00:4342// Retrieves and caches the ideal and minimum sizes of the Home screen icon
43// and the splash screen image.
44void GetHomescreenIconAndSplashImageSizes() {
45 JNIEnv* env = base::android::AttachCurrentThread();
46 ScopedJavaLocalRef<jintArray> java_size_array =
pkotwicz45fc42b62016-06-07 00:07:1047 Java_ShortcutHelper_getHomeScreenIconAndSplashImageSizes(env);
lalitm45a03c72015-09-16 13:00:4348 std::vector<int> sizes;
49 base::android::JavaIntArrayToIntVector(
50 env, java_size_array.obj(), &sizes);
51
52 // Check that the size returned is what is expected.
zpenge33ba852017-02-01 20:54:4253 DCHECK(sizes.size() == 5);
lalitm45a03c72015-09-16 13:00:4354
55 // This ordering must be kept up to date with the Java ShortcutHelper.
zpenge33ba852017-02-01 20:54:4256 g_ideal_homescreen_icon_size = sizes[0];
57 g_minimum_homescreen_icon_size = sizes[1];
58 g_ideal_splash_image_size = sizes[2];
59 g_minimum_splash_image_size = sizes[3];
60 g_ideal_badge_icon_size = sizes[4];
lalitm45a03c72015-09-16 13:00:4361
62 // Try to ensure that the data returned is sane.
zpenge33ba852017-02-01 20:54:4263 DCHECK(g_minimum_homescreen_icon_size <= g_ideal_homescreen_icon_size);
64 DCHECK(g_minimum_splash_image_size <= g_ideal_splash_image_size);
lalitm45a03c72015-09-16 13:00:4365}
66
67} // anonymous namespace
68
dfalcantaraaec56da2015-05-06 03:33:5669// static
pkotwiczc67e6ac2016-08-12 19:56:4470void ShortcutHelper::AddToLauncherWithSkBitmap(
pkotwicz879b1ed2016-08-06 00:48:2271 content::BrowserContext* browser_context,
pkotwicz206673142016-07-19 19:13:3072 const ShortcutInfo& info,
73 const std::string& webapp_id,
74 const SkBitmap& icon_bitmap,
75 const base::Closure& splash_image_callback) {
pkotwicz206673142016-07-19 19:13:3076 if (info.display == blink::WebDisplayModeStandalone ||
77 info.display == blink::WebDisplayModeFullscreen) {
pkotwiczc67e6ac2016-08-12 19:56:4478 AddWebappWithSkBitmap(info, webapp_id, icon_bitmap, splash_image_callback);
pkotwicz206673142016-07-19 19:13:3079 return;
80 }
pkotwiczc67e6ac2016-08-12 19:56:4481 AddShortcutWithSkBitmap(info, icon_bitmap);
pkotwicz206673142016-07-19 19:13:3082}
83
84// static
pkotwiczc67e6ac2016-08-12 19:56:4485void ShortcutHelper::InstallWebApkWithSkBitmap(
pkotwicz879b1ed2016-08-06 00:48:2286 content::BrowserContext* browser_context,
pkotwicz206673142016-07-19 19:13:3087 const ShortcutInfo& info,
hanxi9f38f742016-08-30 18:34:2088 const SkBitmap& icon_bitmap,
89 const WebApkInstaller::FinishCallback& callback) {
hanxi070d10a2017-01-09 15:56:5090 WebApkInstallService::Get(browser_context)
91 ->InstallAsync(info, icon_bitmap, callback);
pkotwicz206673142016-07-19 19:13:3092}
93
94// static
pkotwiczc67e6ac2016-08-12 19:56:4495void ShortcutHelper::AddWebappWithSkBitmap(
dfalcantara16e84de2015-02-03 22:07:4096 const ShortcutInfo& info,
lalitmd93c2ed2015-09-04 16:22:1297 const std::string& webapp_id,
dominickn6509a4de2016-04-06 08:29:0698 const SkBitmap& icon_bitmap,
99 const base::Closure& splash_image_callback) {
[email protected]51208252013-08-19 21:05:30100 // Send the data to the Java side to create the shortcut.
101 JNIEnv* env = base::android::AttachCurrentThread();
lalitmd93c2ed2015-09-04 16:22:12102 ScopedJavaLocalRef<jstring> java_webapp_id =
103 base::android::ConvertUTF8ToJavaString(env, webapp_id);
[email protected]51208252013-08-19 21:05:30104 ScopedJavaLocalRef<jstring> java_url =
dfalcantara16e84de2015-02-03 22:07:40105 base::android::ConvertUTF8ToJavaString(env, info.url.spec());
pkotwicz6bdfbe1b2016-07-08 00:26:43106 ScopedJavaLocalRef<jstring> java_scope_url =
107 base::android::ConvertUTF8ToJavaString(env, info.scope.spec());
lalitmf3ee51852015-07-21 18:13:11108 ScopedJavaLocalRef<jstring> java_user_title =
109 base::android::ConvertUTF16ToJavaString(env, info.user_title);
110 ScopedJavaLocalRef<jstring> java_name =
111 base::android::ConvertUTF16ToJavaString(env, info.name);
112 ScopedJavaLocalRef<jstring> java_short_name =
113 base::android::ConvertUTF16ToJavaString(env, info.short_name);
hanxi75ca9beb2016-11-18 16:22:59114 ScopedJavaLocalRef<jstring> java_best_icon_url =
115 base::android::ConvertUTF8ToJavaString(env, info.best_icon_url.spec());
[email protected]51208252013-08-19 21:05:30116 ScopedJavaLocalRef<jobject> java_bitmap;
mlamouric679bbf2014-09-24 21:24:49117 if (icon_bitmap.getSize())
118 java_bitmap = gfx::ConvertToJavaBitmap(&icon_bitmap);
[email protected]51208252013-08-19 21:05:30119
pkotwicz206673142016-07-19 19:13:30120 // The callback will need to be run after shortcut creation completes in order
121 // to download the splash image and save it to the WebappDataStorage. Create a
122 // copy of the callback here and send the pointer to Java, which will send it
123 // back once the asynchronous shortcut creation process finishes.
124 uintptr_t callback_pointer =
125 reinterpret_cast<uintptr_t>(new base::Closure(splash_image_callback));
dominickn6509a4de2016-04-06 08:29:06126
torne948f3662016-08-16 15:10:44127 Java_ShortcutHelper_addWebapp(env, java_webapp_id, java_url, java_scope_url,
128 java_user_title, java_name, java_short_name,
hanxi75ca9beb2016-11-18 16:22:59129 java_best_icon_url, java_bitmap, info.display,
torne948f3662016-08-16 15:10:44130 info.orientation, info.source, info.theme_color,
131 info.background_color, callback_pointer);
[email protected]51208252013-08-19 21:05:30132}
benwells840ae902015-02-17 21:13:28133
pkotwiczc67e6ac2016-08-12 19:56:44134void ShortcutHelper::AddShortcutWithSkBitmap(
pkotwicz206673142016-07-19 19:13:30135 const ShortcutInfo& info,
136 const SkBitmap& icon_bitmap) {
137 JNIEnv* env = base::android::AttachCurrentThread();
138 ScopedJavaLocalRef<jstring> java_url =
139 base::android::ConvertUTF8ToJavaString(env, info.url.spec());
140 ScopedJavaLocalRef<jstring> java_user_title =
141 base::android::ConvertUTF16ToJavaString(env, info.user_title);
142 ScopedJavaLocalRef<jobject> java_bitmap;
143 if (icon_bitmap.getSize())
144 java_bitmap = gfx::ConvertToJavaBitmap(&icon_bitmap);
145
torne948f3662016-08-16 15:10:44146 Java_ShortcutHelper_addShortcut(env, java_url, java_user_title, java_bitmap,
147 info.source);
pkotwicz206673142016-07-19 19:13:30148}
149
hanxi070d10a2017-01-09 15:56:50150void ShortcutHelper::ShowWebApkInstallInProgressToast() {
151 Java_ShortcutHelper_showWebApkInstallInProgressToast(
152 base::android::AttachCurrentThread());
153}
154
zpeng5d8fdfc2017-01-05 15:45:06155int ShortcutHelper::GetIdealHomescreenIconSizeInPx() {
zpenge33ba852017-02-01 20:54:42156 if (g_ideal_homescreen_icon_size == -1)
lalitm45a03c72015-09-16 13:00:43157 GetHomescreenIconAndSplashImageSizes();
zpenge33ba852017-02-01 20:54:42158 return g_ideal_homescreen_icon_size;
lalitm45a03c72015-09-16 13:00:43159}
160
zpeng5d8fdfc2017-01-05 15:45:06161int ShortcutHelper::GetMinimumHomescreenIconSizeInPx() {
zpenge33ba852017-02-01 20:54:42162 if (g_minimum_homescreen_icon_size == -1)
lalitm45a03c72015-09-16 13:00:43163 GetHomescreenIconAndSplashImageSizes();
zpenge33ba852017-02-01 20:54:42164 return g_minimum_homescreen_icon_size;
lalitm45a03c72015-09-16 13:00:43165}
166
zpeng5d8fdfc2017-01-05 15:45:06167int ShortcutHelper::GetIdealSplashImageSizeInPx() {
zpenge33ba852017-02-01 20:54:42168 if (g_ideal_splash_image_size == -1)
lalitm45a03c72015-09-16 13:00:43169 GetHomescreenIconAndSplashImageSizes();
zpenge33ba852017-02-01 20:54:42170 return g_ideal_splash_image_size;
lalitm45a03c72015-09-16 13:00:43171}
172
zpeng5d8fdfc2017-01-05 15:45:06173int ShortcutHelper::GetMinimumSplashImageSizeInPx() {
zpenge33ba852017-02-01 20:54:42174 if (g_minimum_splash_image_size == -1)
lalitm45a03c72015-09-16 13:00:43175 GetHomescreenIconAndSplashImageSizes();
zpenge33ba852017-02-01 20:54:42176 return g_minimum_splash_image_size;
177}
178
179int ShortcutHelper::GetIdealBadgeIconSizeInPx() {
180 if (g_ideal_badge_icon_size == -1)
181 GetHomescreenIconAndSplashImageSizes();
182 return g_ideal_badge_icon_size;
lalitm45a03c72015-09-16 13:00:43183}
184
lalitmd93c2ed2015-09-04 16:22:12185// static
186void ShortcutHelper::FetchSplashScreenImage(
187 content::WebContents* web_contents,
188 const GURL& image_url,
zpeng5d8fdfc2017-01-05 15:45:06189 const int ideal_splash_image_size_in_px,
190 const int minimum_splash_image_size_in_px,
dominickn6509a4de2016-04-06 08:29:06191 const std::string& webapp_id) {
lalitmd93c2ed2015-09-04 16:22:12192 // This is a fire and forget task. It is not vital for the splash screen image
193 // to be downloaded so if the downloader returns false there is no fallback.
194 ManifestIconDownloader::Download(
zpeng5d8fdfc2017-01-05 15:45:06195 web_contents, image_url, ideal_splash_image_size_in_px,
196 minimum_splash_image_size_in_px,
dominickn6509a4de2016-04-06 08:29:06197 base::Bind(&ShortcutHelper::StoreWebappSplashImage, webapp_id));
lalitmd93c2ed2015-09-04 16:22:12198}
199
200// static
dominickn6509a4de2016-04-06 08:29:06201void ShortcutHelper::StoreWebappSplashImage(
lalitmd93c2ed2015-09-04 16:22:12202 const std::string& webapp_id,
203 const SkBitmap& splash_image) {
204 if (splash_image.drawsNothing())
205 return;
206
207 JNIEnv* env = base::android::AttachCurrentThread();
208 ScopedJavaLocalRef<jstring> java_webapp_id =
209 base::android::ConvertUTF8ToJavaString(env, webapp_id);
210 ScopedJavaLocalRef<jobject> java_splash_image =
211 gfx::ConvertToJavaBitmap(&splash_image);
212
torne948f3662016-08-16 15:10:44213 Java_ShortcutHelper_storeWebappSplashImage(env, java_webapp_id,
214 java_splash_image);
lalitmd93c2ed2015-09-04 16:22:12215}
216
mlamouribc6e8792015-10-22 20:41:13217// static
pkotwicz5774087e2016-08-10 17:36:40218SkBitmap ShortcutHelper::FinalizeLauncherIconInBackground(
219 const SkBitmap& bitmap,
220 const GURL& url,
221 bool* is_generated) {
222 DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
mlamouribc6e8792015-10-22 20:41:13223
224 JNIEnv* env = base::android::AttachCurrentThread();
225 ScopedJavaLocalRef<jobject> result;
226 *is_generated = false;
227
228 if (!bitmap.isNull()) {
pkotwicz45fc42b62016-06-07 00:07:10229 if (Java_ShortcutHelper_isIconLargeEnoughForLauncher(env, bitmap.width(),
230 bitmap.height())) {
newta584b9e2015-10-29 22:29:43231 ScopedJavaLocalRef<jobject> java_bitmap =
232 gfx::ConvertToJavaBitmap(&bitmap);
torne948f3662016-08-16 15:10:44233 result =
234 Java_ShortcutHelper_createHomeScreenIconFromWebIcon(env, java_bitmap);
mlamouribc6e8792015-10-22 20:41:13235 }
236 }
237
238 if (result.is_null()) {
239 ScopedJavaLocalRef<jstring> java_url =
240 base::android::ConvertUTF8ToJavaString(env, url.spec());
zpenge33ba852017-02-01 20:54:42241 SkColor mean_color =
242 SkColorSetRGB(g_default_rgb_icon_value, g_default_rgb_icon_value,
243 g_default_rgb_icon_value);
mlamouribc6e8792015-10-22 20:41:13244
245 if (!bitmap.isNull())
246 mean_color = color_utils::CalculateKMeanColorOfBitmap(bitmap);
247
248 *is_generated = true;
newta584b9e2015-10-29 22:29:43249 result = Java_ShortcutHelper_generateHomeScreenIcon(
torne948f3662016-08-16 15:10:44250 env, java_url, SkColorGetR(mean_color), SkColorGetG(mean_color),
mlamouribc6e8792015-10-22 20:41:13251 SkColorGetB(mean_color));
252 }
253
pkotwicz964382b2016-08-04 01:24:55254 return result.obj()
torned64eb5132016-10-24 12:51:28255 ? gfx::CreateSkBitmapFromJavaBitmap(gfx::JavaBitmap(result))
pkotwicz964382b2016-08-04 01:24:55256 : SkBitmap();
mlamouribc6e8792015-10-22 20:41:13257}
258
pkotwiczcda82fe2016-07-08 18:56:54259// static
zpeng4bb58962016-10-04 02:42:29260std::string ShortcutHelper::QueryWebApkPackage(const GURL& url) {
261 JNIEnv* env = base::android::AttachCurrentThread();
262 ScopedJavaLocalRef<jstring> java_url =
263 base::android::ConvertUTF8ToJavaString(env, url.spec());
264 ScopedJavaLocalRef<jstring> java_webapk_package_name =
265 Java_ShortcutHelper_queryWebApkPackage(env, java_url);
266
267 std::string webapk_package_name = "";
268 if (java_webapk_package_name.obj()) {
269 webapk_package_name = base::android::ConvertJavaStringToUTF8(
270 env, java_webapk_package_name);
271 }
272 return webapk_package_name;
273}
274
275// static
hanxi070d10a2017-01-09 15:56:50276bool ShortcutHelper::IsWebApkInstalled(
277 content::BrowserContext* browser_context,
278 const GURL& start_url,
279 const GURL& manifest_url) {
280 return !QueryWebApkPackage(start_url).empty() ||
281 WebApkInstallService::Get(browser_context)
282 ->IsInstallInProgress(manifest_url);
pkotwiczcda82fe2016-07-08 18:56:54283}
284
pkotwicz47136bc2016-08-06 23:55:39285GURL ShortcutHelper::GetScopeFromURL(const GURL& url) {
286 JNIEnv* env = base::android::AttachCurrentThread();
287 ScopedJavaLocalRef<jstring> java_url =
288 base::android::ConvertUTF8ToJavaString(env, url.spec());
289 ScopedJavaLocalRef<jstring> java_scope_url =
torne948f3662016-08-16 15:10:44290 Java_ShortcutHelper_getScopeFromUrl(env, java_url);
pkotwicz47136bc2016-08-06 23:55:39291 return GURL(base::android::ConvertJavaStringToUTF16(env, java_scope_url));
292}
293
dominickn6509a4de2016-04-06 08:29:06294// Callback used by Java when the shortcut has been created.
295// |splash_image_callback| is a pointer to a base::Closure allocated in
pkotwiczc67e6ac2016-08-12 19:56:44296// AddShortcutWithSkBitmap, so reinterpret_cast it back and run it.
dominickn6509a4de2016-04-06 08:29:06297//
298// This callback should only ever be called when the shortcut was for a
299// webapp-capable site; otherwise, |splash_image_callback| will have never been
300// allocated and doesn't need to be run or deleted.
301void OnWebappDataStored(JNIEnv* env,
302 const JavaParamRef<jclass>& clazz,
303 jlong jsplash_image_callback) {
304 DCHECK(jsplash_image_callback);
305 base::Closure* splash_image_callback =
306 reinterpret_cast<base::Closure*>(jsplash_image_callback);
307 splash_image_callback->Run();
308 delete splash_image_callback;
309}
310
lalitm870920e2015-08-20 22:06:03311bool ShortcutHelper::RegisterShortcutHelper(JNIEnv* env) {
312 return RegisterNativesImpl(env);
benwells840ae902015-02-17 21:13:28313}