blob: 26000d260338a4c30d0821f095c6efadd7b11537 [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"
pkotwicz879b1ed2016-08-06 00:48:2217#include "chrome/browser/android/webapk/webapk_installer.h"
lalitmd93c2ed2015-09-04 16:22:1218#include "chrome/browser/manifest/manifest_icon_downloader.h"
pkotwicz206673142016-07-19 19:13:3019#include "chrome/common/chrome_switches.h"
dfalcantaraaec56da2015-05-06 03:33:5620#include "content/public/browser/browser_thread.h"
[email protected]51208252013-08-19 21:05:3021#include "content/public/browser/web_contents.h"
[email protected]51208252013-08-19 21:05:3022#include "jni/ShortcutHelper_jni.h"
23#include "ui/gfx/android/java_bitmap.h"
mlamouribc6e8792015-10-22 20:41:1324#include "ui/gfx/color_analysis.h"
[email protected]51208252013-08-19 21:05:3025#include "url/gurl.h"
26
torne86560112016-08-04 15:59:0427using base::android::JavaParamRef;
28using base::android::ScopedJavaLocalRef;
mlamouric679bbf2014-09-24 21:24:4929using content::Manifest;
30
lalitm45a03c72015-09-16 13:00:4331namespace {
32
33static int kIdealHomescreenIconSize = -1;
34static int kMinimumHomescreenIconSize = -1;
35static int kIdealSplashImageSize = -1;
36static int kMinimumSplashImageSize = -1;
37
mlamouribc6e8792015-10-22 20:41:1338static int kDefaultRGBIconValue = 145;
39
lalitm45a03c72015-09-16 13:00:4340// Retrieves and caches the ideal and minimum sizes of the Home screen icon
41// and the splash screen image.
42void GetHomescreenIconAndSplashImageSizes() {
43 JNIEnv* env = base::android::AttachCurrentThread();
44 ScopedJavaLocalRef<jintArray> java_size_array =
pkotwicz45fc42b62016-06-07 00:07:1045 Java_ShortcutHelper_getHomeScreenIconAndSplashImageSizes(env);
lalitm45a03c72015-09-16 13:00:4346 std::vector<int> sizes;
47 base::android::JavaIntArrayToIntVector(
48 env, java_size_array.obj(), &sizes);
49
50 // Check that the size returned is what is expected.
51 DCHECK(sizes.size() == 4);
52
53 // This ordering must be kept up to date with the Java ShortcutHelper.
54 kIdealHomescreenIconSize = sizes[0];
55 kMinimumHomescreenIconSize = sizes[1];
56 kIdealSplashImageSize = sizes[2];
57 kMinimumSplashImageSize = sizes[3];
58
59 // Try to ensure that the data returned is sane.
60 DCHECK(kMinimumHomescreenIconSize <= kIdealHomescreenIconSize);
61 DCHECK(kMinimumSplashImageSize <= kIdealSplashImageSize);
62}
63
64} // anonymous namespace
65
dfalcantaraaec56da2015-05-06 03:33:5666// static
pkotwiczc67e6ac2016-08-12 19:56:4467void ShortcutHelper::AddToLauncherWithSkBitmap(
pkotwicz879b1ed2016-08-06 00:48:2268 content::BrowserContext* browser_context,
pkotwicz206673142016-07-19 19:13:3069 const ShortcutInfo& info,
70 const std::string& webapp_id,
71 const SkBitmap& icon_bitmap,
72 const base::Closure& splash_image_callback) {
pkotwicz206673142016-07-19 19:13:3073 if (info.display == blink::WebDisplayModeStandalone ||
74 info.display == blink::WebDisplayModeFullscreen) {
75 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
76 switches::kEnableWebApk)) {
pkotwiczc67e6ac2016-08-12 19:56:4477 InstallWebApkWithSkBitmap(browser_context, info, icon_bitmap);
pkotwicz206673142016-07-19 19:13:3078 return;
79 }
pkotwiczc67e6ac2016-08-12 19:56:4480 AddWebappWithSkBitmap(info, webapp_id, icon_bitmap, splash_image_callback);
pkotwicz206673142016-07-19 19:13:3081 return;
82 }
pkotwiczc67e6ac2016-08-12 19:56:4483 AddShortcutWithSkBitmap(info, icon_bitmap);
pkotwicz206673142016-07-19 19:13:3084}
85
86// static
pkotwiczc67e6ac2016-08-12 19:56:4487void ShortcutHelper::InstallWebApkWithSkBitmap(
pkotwicz879b1ed2016-08-06 00:48:2288 content::BrowserContext* browser_context,
pkotwicz206673142016-07-19 19:13:3089 const ShortcutInfo& info,
pkotwicz206673142016-07-19 19:13:3090 const SkBitmap& icon_bitmap) {
pkotwicz879b1ed2016-08-06 00:48:2291 // WebApkInstaller destroys itself when it is done.
92 WebApkInstaller* installer = new WebApkInstaller(info, icon_bitmap);
93 installer->InstallAsync(browser_context,
94 base::Bind(&ShortcutHelper::OnBuiltWebApk));
pkotwicz206673142016-07-19 19:13:3095}
96
97// static
pkotwiczc67e6ac2016-08-12 19:56:4498void ShortcutHelper::AddWebappWithSkBitmap(
dfalcantara16e84de2015-02-03 22:07:4099 const ShortcutInfo& info,
lalitmd93c2ed2015-09-04 16:22:12100 const std::string& webapp_id,
dominickn6509a4de2016-04-06 08:29:06101 const SkBitmap& icon_bitmap,
102 const base::Closure& splash_image_callback) {
[email protected]51208252013-08-19 21:05:30103 // Send the data to the Java side to create the shortcut.
104 JNIEnv* env = base::android::AttachCurrentThread();
lalitmd93c2ed2015-09-04 16:22:12105 ScopedJavaLocalRef<jstring> java_webapp_id =
106 base::android::ConvertUTF8ToJavaString(env, webapp_id);
[email protected]51208252013-08-19 21:05:30107 ScopedJavaLocalRef<jstring> java_url =
dfalcantara16e84de2015-02-03 22:07:40108 base::android::ConvertUTF8ToJavaString(env, info.url.spec());
pkotwicz6bdfbe1b2016-07-08 00:26:43109 ScopedJavaLocalRef<jstring> java_scope_url =
110 base::android::ConvertUTF8ToJavaString(env, info.scope.spec());
lalitmf3ee51852015-07-21 18:13:11111 ScopedJavaLocalRef<jstring> java_user_title =
112 base::android::ConvertUTF16ToJavaString(env, info.user_title);
113 ScopedJavaLocalRef<jstring> java_name =
114 base::android::ConvertUTF16ToJavaString(env, info.name);
115 ScopedJavaLocalRef<jstring> java_short_name =
116 base::android::ConvertUTF16ToJavaString(env, info.short_name);
pkotwiczb8c25a12016-07-01 20:54:55117 ScopedJavaLocalRef<jstring> java_icon_url =
118 base::android::ConvertUTF8ToJavaString(env, info.icon_url.spec());
[email protected]51208252013-08-19 21:05:30119 ScopedJavaLocalRef<jobject> java_bitmap;
mlamouric679bbf2014-09-24 21:24:49120 if (icon_bitmap.getSize())
121 java_bitmap = gfx::ConvertToJavaBitmap(&icon_bitmap);
[email protected]51208252013-08-19 21:05:30122
pkotwicz206673142016-07-19 19:13:30123 // The callback will need to be run after shortcut creation completes in order
124 // to download the splash image and save it to the WebappDataStorage. Create a
125 // copy of the callback here and send the pointer to Java, which will send it
126 // back once the asynchronous shortcut creation process finishes.
127 uintptr_t callback_pointer =
128 reinterpret_cast<uintptr_t>(new base::Closure(splash_image_callback));
dominickn6509a4de2016-04-06 08:29:06129
pkotwicz206673142016-07-19 19:13:30130 Java_ShortcutHelper_addWebapp(
mlamouri89ccc632014-09-16 19:29:58131 env,
lalitmd93c2ed2015-09-04 16:22:12132 java_webapp_id.obj(),
mlamouri89ccc632014-09-16 19:29:58133 java_url.obj(),
pkotwicz6bdfbe1b2016-07-08 00:26:43134 java_scope_url.obj(),
lalitmf3ee51852015-07-21 18:13:11135 java_user_title.obj(),
136 java_name.obj(),
137 java_short_name.obj(),
pkotwiczb8c25a12016-07-01 20:54:55138 java_icon_url.obj(),
mlamouri89ccc632014-09-16 19:29:58139 java_bitmap.obj(),
dominickn3f9ab132016-05-20 03:32:44140 info.display,
dominickn32fe3042015-07-07 22:42:50141 info.orientation,
lalitm2f5beca2015-08-12 10:53:43142 info.source,
lalitm4b2dde0a62015-08-19 22:35:32143 info.theme_color,
mlamouribc6e8792015-10-22 20:41:13144 info.background_color,
dominickn6509a4de2016-04-06 08:29:06145 callback_pointer);
[email protected]51208252013-08-19 21:05:30146}
benwells840ae902015-02-17 21:13:28147
pkotwiczc67e6ac2016-08-12 19:56:44148void ShortcutHelper::AddShortcutWithSkBitmap(
pkotwicz206673142016-07-19 19:13:30149 const ShortcutInfo& info,
150 const SkBitmap& icon_bitmap) {
151 JNIEnv* env = base::android::AttachCurrentThread();
152 ScopedJavaLocalRef<jstring> java_url =
153 base::android::ConvertUTF8ToJavaString(env, info.url.spec());
154 ScopedJavaLocalRef<jstring> java_user_title =
155 base::android::ConvertUTF16ToJavaString(env, info.user_title);
156 ScopedJavaLocalRef<jobject> java_bitmap;
157 if (icon_bitmap.getSize())
158 java_bitmap = gfx::ConvertToJavaBitmap(&icon_bitmap);
159
160 Java_ShortcutHelper_addShortcut(env, java_url.obj(), java_user_title.obj(),
161 java_bitmap.obj(), info.source);
162}
163
pkotwicz879b1ed2016-08-06 00:48:22164void ShortcutHelper::OnBuiltWebApk(bool success) {
165 if (success) {
166 DVLOG(1) << "Sent request to install WebAPK. Seems to have worked.";
167 } else {
168 LOG(ERROR) << "WebAPK install failed.";
169 }
170 // TODO(pkotwicz): Figure out what to do when installing WebAPK fails.
171 // (crbug.com/626950)
172}
173
lalitm45a03c72015-09-16 13:00:43174int ShortcutHelper::GetIdealHomescreenIconSizeInDp() {
175 if (kIdealHomescreenIconSize == -1)
176 GetHomescreenIconAndSplashImageSizes();
177 return kIdealHomescreenIconSize;
178}
179
180int ShortcutHelper::GetMinimumHomescreenIconSizeInDp() {
181 if (kMinimumHomescreenIconSize == -1)
182 GetHomescreenIconAndSplashImageSizes();
183 return kMinimumHomescreenIconSize;
184}
185
186int ShortcutHelper::GetIdealSplashImageSizeInDp() {
187 if (kIdealSplashImageSize == -1)
188 GetHomescreenIconAndSplashImageSizes();
189 return kIdealSplashImageSize;
190}
191
192int ShortcutHelper::GetMinimumSplashImageSizeInDp() {
193 if (kMinimumSplashImageSize == -1)
194 GetHomescreenIconAndSplashImageSizes();
195 return kMinimumSplashImageSize;
196}
197
lalitmd93c2ed2015-09-04 16:22:12198// static
199void ShortcutHelper::FetchSplashScreenImage(
200 content::WebContents* web_contents,
201 const GURL& image_url,
202 const int ideal_splash_image_size_in_dp,
lalitm45a03c72015-09-16 13:00:43203 const int minimum_splash_image_size_in_dp,
dominickn6509a4de2016-04-06 08:29:06204 const std::string& webapp_id) {
lalitmd93c2ed2015-09-04 16:22:12205 // This is a fire and forget task. It is not vital for the splash screen image
206 // to be downloaded so if the downloader returns false there is no fallback.
207 ManifestIconDownloader::Download(
dominickn6e400422016-03-25 02:02:47208 web_contents, image_url, ideal_splash_image_size_in_dp,
lalitm45a03c72015-09-16 13:00:43209 minimum_splash_image_size_in_dp,
dominickn6509a4de2016-04-06 08:29:06210 base::Bind(&ShortcutHelper::StoreWebappSplashImage, webapp_id));
lalitmd93c2ed2015-09-04 16:22:12211}
212
213// static
dominickn6509a4de2016-04-06 08:29:06214void ShortcutHelper::StoreWebappSplashImage(
lalitmd93c2ed2015-09-04 16:22:12215 const std::string& webapp_id,
216 const SkBitmap& splash_image) {
217 if (splash_image.drawsNothing())
218 return;
219
220 JNIEnv* env = base::android::AttachCurrentThread();
221 ScopedJavaLocalRef<jstring> java_webapp_id =
222 base::android::ConvertUTF8ToJavaString(env, webapp_id);
223 ScopedJavaLocalRef<jobject> java_splash_image =
224 gfx::ConvertToJavaBitmap(&splash_image);
225
dominickn6509a4de2016-04-06 08:29:06226 Java_ShortcutHelper_storeWebappSplashImage(
lalitmd93c2ed2015-09-04 16:22:12227 env,
lalitmd93c2ed2015-09-04 16:22:12228 java_webapp_id.obj(),
229 java_splash_image.obj());
230}
231
mlamouribc6e8792015-10-22 20:41:13232// static
pkotwicz5774087e2016-08-10 17:36:40233SkBitmap ShortcutHelper::FinalizeLauncherIconInBackground(
234 const SkBitmap& bitmap,
235 const GURL& url,
236 bool* is_generated) {
237 DCHECK(content::BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
mlamouribc6e8792015-10-22 20:41:13238
239 JNIEnv* env = base::android::AttachCurrentThread();
240 ScopedJavaLocalRef<jobject> result;
241 *is_generated = false;
242
243 if (!bitmap.isNull()) {
pkotwicz45fc42b62016-06-07 00:07:10244 if (Java_ShortcutHelper_isIconLargeEnoughForLauncher(env, bitmap.width(),
245 bitmap.height())) {
newta584b9e2015-10-29 22:29:43246 ScopedJavaLocalRef<jobject> java_bitmap =
247 gfx::ConvertToJavaBitmap(&bitmap);
248 result = Java_ShortcutHelper_createHomeScreenIconFromWebIcon(
pkotwicz45fc42b62016-06-07 00:07:10249 env, java_bitmap.obj());
mlamouribc6e8792015-10-22 20:41:13250 }
251 }
252
253 if (result.is_null()) {
254 ScopedJavaLocalRef<jstring> java_url =
255 base::android::ConvertUTF8ToJavaString(env, url.spec());
256 SkColor mean_color = SkColorSetRGB(
257 kDefaultRGBIconValue, kDefaultRGBIconValue, kDefaultRGBIconValue);
258
259 if (!bitmap.isNull())
260 mean_color = color_utils::CalculateKMeanColorOfBitmap(bitmap);
261
262 *is_generated = true;
newta584b9e2015-10-29 22:29:43263 result = Java_ShortcutHelper_generateHomeScreenIcon(
pkotwicz45fc42b62016-06-07 00:07:10264 env, java_url.obj(), SkColorGetR(mean_color), SkColorGetG(mean_color),
mlamouribc6e8792015-10-22 20:41:13265 SkColorGetB(mean_color));
266 }
267
pkotwicz964382b2016-08-04 01:24:55268 return result.obj()
269 ? gfx::CreateSkBitmapFromJavaBitmap(gfx::JavaBitmap(result.obj()))
270 : SkBitmap();
mlamouribc6e8792015-10-22 20:41:13271}
272
pkotwiczcda82fe2016-07-08 18:56:54273// static
274bool ShortcutHelper::IsWebApkInstalled(const GURL& url) {
275 JNIEnv* env = base::android::AttachCurrentThread();
276 ScopedJavaLocalRef<jstring> java_url =
277 base::android::ConvertUTF8ToJavaString(env, url.spec());
278 return Java_ShortcutHelper_isWebApkInstalled(env, java_url.obj());
279}
280
pkotwicz47136bc2016-08-06 23:55:39281GURL ShortcutHelper::GetScopeFromURL(const GURL& url) {
282 JNIEnv* env = base::android::AttachCurrentThread();
283 ScopedJavaLocalRef<jstring> java_url =
284 base::android::ConvertUTF8ToJavaString(env, url.spec());
285 ScopedJavaLocalRef<jstring> java_scope_url =
286 Java_ShortcutHelper_getScopeFromUrl(env, java_url.obj());
287 return GURL(base::android::ConvertJavaStringToUTF16(env, java_scope_url));
288}
289
dominickn6509a4de2016-04-06 08:29:06290// Callback used by Java when the shortcut has been created.
291// |splash_image_callback| is a pointer to a base::Closure allocated in
pkotwiczc67e6ac2016-08-12 19:56:44292// AddShortcutWithSkBitmap, so reinterpret_cast it back and run it.
dominickn6509a4de2016-04-06 08:29:06293//
294// This callback should only ever be called when the shortcut was for a
295// webapp-capable site; otherwise, |splash_image_callback| will have never been
296// allocated and doesn't need to be run or deleted.
297void OnWebappDataStored(JNIEnv* env,
298 const JavaParamRef<jclass>& clazz,
299 jlong jsplash_image_callback) {
300 DCHECK(jsplash_image_callback);
301 base::Closure* splash_image_callback =
302 reinterpret_cast<base::Closure*>(jsplash_image_callback);
303 splash_image_callback->Run();
304 delete splash_image_callback;
305}
306
lalitm870920e2015-08-20 22:06:03307bool ShortcutHelper::RegisterShortcutHelper(JNIEnv* env) {
308 return RegisterNativesImpl(env);
benwells840ae902015-02-17 21:13:28309}