blob: 13ae7b3dff65bc0ed30708acbd85871bd7affc59 [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
torneda6e7c9e2015-11-25 18:25:509#include "base/android/context_utils.h"
[email protected]51208252013-08-19 21:05:3010#include "base/android/jni_android.h"
lalitm45a03c72015-09-16 13:00:4311#include "base/android/jni_array.h"
[email protected]51208252013-08-19 21:05:3012#include "base/android/jni_string.h"
dominickn6509a4de2016-04-06 08:29:0613#include "base/bind.h"
14#include "base/callback.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"
lalitmd93c2ed2015-09-04 16:22:1217#include "chrome/browser/manifest/manifest_icon_downloader.h"
dfalcantaraaec56da2015-05-06 03:33:5618#include "content/public/browser/browser_thread.h"
[email protected]51208252013-08-19 21:05:3019#include "content/public/browser/web_contents.h"
[email protected]51208252013-08-19 21:05:3020#include "jni/ShortcutHelper_jni.h"
21#include "ui/gfx/android/java_bitmap.h"
mlamouribc6e8792015-10-22 20:41:1322#include "ui/gfx/color_analysis.h"
[email protected]51208252013-08-19 21:05:3023#include "url/gurl.h"
24
mlamouric679bbf2014-09-24 21:24:4925using content::Manifest;
26
lalitm45a03c72015-09-16 13:00:4327namespace {
28
29static int kIdealHomescreenIconSize = -1;
30static int kMinimumHomescreenIconSize = -1;
31static int kIdealSplashImageSize = -1;
32static int kMinimumSplashImageSize = -1;
33
mlamouribc6e8792015-10-22 20:41:1334static int kDefaultRGBIconValue = 145;
35
lalitm45a03c72015-09-16 13:00:4336// Retrieves and caches the ideal and minimum sizes of the Home screen icon
37// and the splash screen image.
38void GetHomescreenIconAndSplashImageSizes() {
39 JNIEnv* env = base::android::AttachCurrentThread();
40 ScopedJavaLocalRef<jintArray> java_size_array =
newta584b9e2015-10-29 22:29:4341 Java_ShortcutHelper_getHomeScreenIconAndSplashImageSizes(env,
lalitm45a03c72015-09-16 13:00:4342 base::android::GetApplicationContext());
43 std::vector<int> sizes;
44 base::android::JavaIntArrayToIntVector(
45 env, java_size_array.obj(), &sizes);
46
47 // Check that the size returned is what is expected.
48 DCHECK(sizes.size() == 4);
49
50 // This ordering must be kept up to date with the Java ShortcutHelper.
51 kIdealHomescreenIconSize = sizes[0];
52 kMinimumHomescreenIconSize = sizes[1];
53 kIdealSplashImageSize = sizes[2];
54 kMinimumSplashImageSize = sizes[3];
55
56 // Try to ensure that the data returned is sane.
57 DCHECK(kMinimumHomescreenIconSize <= kIdealHomescreenIconSize);
58 DCHECK(kMinimumSplashImageSize <= kIdealSplashImageSize);
59}
60
61} // anonymous namespace
62
dfalcantaraaec56da2015-05-06 03:33:5663// static
mlamouric679bbf2014-09-24 21:24:4964void ShortcutHelper::AddShortcutInBackgroundWithSkBitmap(
dfalcantara16e84de2015-02-03 22:07:4065 const ShortcutInfo& info,
lalitmd93c2ed2015-09-04 16:22:1266 const std::string& webapp_id,
dominickn6509a4de2016-04-06 08:29:0667 const SkBitmap& icon_bitmap,
68 const base::Closure& splash_image_callback) {
dfalcantaraaec56da2015-05-06 03:33:5669 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
[email protected]51208252013-08-19 21:05:3070
71 // Send the data to the Java side to create the shortcut.
72 JNIEnv* env = base::android::AttachCurrentThread();
lalitmd93c2ed2015-09-04 16:22:1273 ScopedJavaLocalRef<jstring> java_webapp_id =
74 base::android::ConvertUTF8ToJavaString(env, webapp_id);
[email protected]51208252013-08-19 21:05:3075 ScopedJavaLocalRef<jstring> java_url =
dfalcantara16e84de2015-02-03 22:07:4076 base::android::ConvertUTF8ToJavaString(env, info.url.spec());
lalitmf3ee51852015-07-21 18:13:1177 ScopedJavaLocalRef<jstring> java_user_title =
78 base::android::ConvertUTF16ToJavaString(env, info.user_title);
79 ScopedJavaLocalRef<jstring> java_name =
80 base::android::ConvertUTF16ToJavaString(env, info.name);
81 ScopedJavaLocalRef<jstring> java_short_name =
82 base::android::ConvertUTF16ToJavaString(env, info.short_name);
[email protected]51208252013-08-19 21:05:3083 ScopedJavaLocalRef<jobject> java_bitmap;
mlamouric679bbf2014-09-24 21:24:4984 if (icon_bitmap.getSize())
85 java_bitmap = gfx::ConvertToJavaBitmap(&icon_bitmap);
[email protected]51208252013-08-19 21:05:3086
dominickn6509a4de2016-04-06 08:29:0687 uintptr_t callback_pointer = 0;
88 bool is_webapp_capable = info.display == blink::WebDisplayModeStandalone;
89
90 if (is_webapp_capable) {
91 // The callback will need to be run after shortcut creation completes in
92 // order to download the splash image and save it to the WebappDataStorage.
93 // Create a copy of the callback here and send the pointer to Java, which
94 // will send it back once the asynchronous shortcut creation process
95 // finishes.
96 callback_pointer =
97 reinterpret_cast<uintptr_t>(new base::Closure(splash_image_callback));
98 }
99
mlamouri89ccc632014-09-16 19:29:58100 Java_ShortcutHelper_addShortcut(
101 env,
102 base::android::GetApplicationContext(),
lalitmd93c2ed2015-09-04 16:22:12103 java_webapp_id.obj(),
mlamouri89ccc632014-09-16 19:29:58104 java_url.obj(),
lalitmf3ee51852015-07-21 18:13:11105 java_user_title.obj(),
106 java_name.obj(),
107 java_short_name.obj(),
mlamouri89ccc632014-09-16 19:29:58108 java_bitmap.obj(),
dominickn6509a4de2016-04-06 08:29:06109 is_webapp_capable,
dominickn32fe3042015-07-07 22:42:50110 info.orientation,
lalitm2f5beca2015-08-12 10:53:43111 info.source,
lalitm4b2dde0a62015-08-19 22:35:32112 info.theme_color,
mlamouribc6e8792015-10-22 20:41:13113 info.background_color,
dominickn6509a4de2016-04-06 08:29:06114 info.is_icon_generated,
115 callback_pointer);
[email protected]51208252013-08-19 21:05:30116}
benwells840ae902015-02-17 21:13:28117
lalitm45a03c72015-09-16 13:00:43118int ShortcutHelper::GetIdealHomescreenIconSizeInDp() {
119 if (kIdealHomescreenIconSize == -1)
120 GetHomescreenIconAndSplashImageSizes();
121 return kIdealHomescreenIconSize;
122}
123
124int ShortcutHelper::GetMinimumHomescreenIconSizeInDp() {
125 if (kMinimumHomescreenIconSize == -1)
126 GetHomescreenIconAndSplashImageSizes();
127 return kMinimumHomescreenIconSize;
128}
129
130int ShortcutHelper::GetIdealSplashImageSizeInDp() {
131 if (kIdealSplashImageSize == -1)
132 GetHomescreenIconAndSplashImageSizes();
133 return kIdealSplashImageSize;
134}
135
136int ShortcutHelper::GetMinimumSplashImageSizeInDp() {
137 if (kMinimumSplashImageSize == -1)
138 GetHomescreenIconAndSplashImageSizes();
139 return kMinimumSplashImageSize;
140}
141
lalitmd93c2ed2015-09-04 16:22:12142// static
143void ShortcutHelper::FetchSplashScreenImage(
144 content::WebContents* web_contents,
145 const GURL& image_url,
146 const int ideal_splash_image_size_in_dp,
lalitm45a03c72015-09-16 13:00:43147 const int minimum_splash_image_size_in_dp,
dominickn6509a4de2016-04-06 08:29:06148 const std::string& webapp_id) {
lalitmd93c2ed2015-09-04 16:22:12149 // This is a fire and forget task. It is not vital for the splash screen image
150 // to be downloaded so if the downloader returns false there is no fallback.
151 ManifestIconDownloader::Download(
dominickn6e400422016-03-25 02:02:47152 web_contents, image_url, ideal_splash_image_size_in_dp,
lalitm45a03c72015-09-16 13:00:43153 minimum_splash_image_size_in_dp,
dominickn6509a4de2016-04-06 08:29:06154 base::Bind(&ShortcutHelper::StoreWebappSplashImage, webapp_id));
lalitmd93c2ed2015-09-04 16:22:12155}
156
157// static
dominickn6509a4de2016-04-06 08:29:06158void ShortcutHelper::StoreWebappSplashImage(
lalitmd93c2ed2015-09-04 16:22:12159 const std::string& webapp_id,
160 const SkBitmap& splash_image) {
161 if (splash_image.drawsNothing())
162 return;
163
164 JNIEnv* env = base::android::AttachCurrentThread();
165 ScopedJavaLocalRef<jstring> java_webapp_id =
166 base::android::ConvertUTF8ToJavaString(env, webapp_id);
167 ScopedJavaLocalRef<jobject> java_splash_image =
168 gfx::ConvertToJavaBitmap(&splash_image);
169
dominickn6509a4de2016-04-06 08:29:06170 Java_ShortcutHelper_storeWebappSplashImage(
lalitmd93c2ed2015-09-04 16:22:12171 env,
172 base::android::GetApplicationContext(),
173 java_webapp_id.obj(),
lalitmd93c2ed2015-09-04 16:22:12174 java_splash_image.obj());
175}
176
mlamouribc6e8792015-10-22 20:41:13177// static
178SkBitmap ShortcutHelper::FinalizeLauncherIcon(const SkBitmap& bitmap,
179 const GURL& url,
180 bool* is_generated) {
181 DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
182
183 JNIEnv* env = base::android::AttachCurrentThread();
184 ScopedJavaLocalRef<jobject> result;
185 *is_generated = false;
186
187 if (!bitmap.isNull()) {
mlamouribc6e8792015-10-22 20:41:13188 if (Java_ShortcutHelper_isIconLargeEnoughForLauncher(
newta584b9e2015-10-29 22:29:43189 env, base::android::GetApplicationContext(), bitmap.width(),
190 bitmap.height())) {
191 ScopedJavaLocalRef<jobject> java_bitmap =
192 gfx::ConvertToJavaBitmap(&bitmap);
193 result = Java_ShortcutHelper_createHomeScreenIconFromWebIcon(
mlamouribc6e8792015-10-22 20:41:13194 env, base::android::GetApplicationContext(), java_bitmap.obj());
195 }
196 }
197
198 if (result.is_null()) {
199 ScopedJavaLocalRef<jstring> java_url =
200 base::android::ConvertUTF8ToJavaString(env, url.spec());
201 SkColor mean_color = SkColorSetRGB(
202 kDefaultRGBIconValue, kDefaultRGBIconValue, kDefaultRGBIconValue);
203
204 if (!bitmap.isNull())
205 mean_color = color_utils::CalculateKMeanColorOfBitmap(bitmap);
206
207 *is_generated = true;
newta584b9e2015-10-29 22:29:43208 result = Java_ShortcutHelper_generateHomeScreenIcon(
mlamouribc6e8792015-10-22 20:41:13209 env, base::android::GetApplicationContext(), java_url.obj(),
210 SkColorGetR(mean_color), SkColorGetG(mean_color),
211 SkColorGetB(mean_color));
212 }
213
214 return gfx::CreateSkBitmapFromJavaBitmap(gfx::JavaBitmap(result.obj()));
215}
216
dominickn6509a4de2016-04-06 08:29:06217// Callback used by Java when the shortcut has been created.
218// |splash_image_callback| is a pointer to a base::Closure allocated in
219// AddShortcutInBackgroundWithSkBitmap, so reinterpret_cast it back and run it.
220//
221// This callback should only ever be called when the shortcut was for a
222// webapp-capable site; otherwise, |splash_image_callback| will have never been
223// allocated and doesn't need to be run or deleted.
224void OnWebappDataStored(JNIEnv* env,
225 const JavaParamRef<jclass>& clazz,
226 jlong jsplash_image_callback) {
227 DCHECK(jsplash_image_callback);
228 base::Closure* splash_image_callback =
229 reinterpret_cast<base::Closure*>(jsplash_image_callback);
230 splash_image_callback->Run();
231 delete splash_image_callback;
232}
233
lalitm870920e2015-08-20 22:06:03234bool ShortcutHelper::RegisterShortcutHelper(JNIEnv* env) {
235 return RegisterNativesImpl(env);
benwells840ae902015-02-17 21:13:28236}