| // Copyright 2013 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/android/shortcut_helper.h" |
| |
| #include <jni.h> |
| #include <limits> |
| #include <string> |
| #include <utility> |
| |
| #include "base/android/jni_android.h" |
| #include "base/android/jni_array.h" |
| #include "base/android/jni_string.h" |
| #include "base/functional/bind.h" |
| #include "base/uuid.h" |
| #include "chrome/android/chrome_jni_headers/ShortcutHelper_jni.h" |
| #include "components/webapps/browser/android/shortcut_info.h" |
| #include "content/public/browser/manifest_icon_downloader.h" |
| #include "content/public/browser/web_contents.h" |
| #include "services/metrics/public/cpp/ukm_builders.h" |
| #include "ui/android/color_utils_android.h" |
| #include "ui/gfx/android/java_bitmap.h" |
| #include "url/gurl.h" |
| #include "url/origin.h" |
| |
| using base::android::JavaParamRef; |
| using base::android::ScopedJavaLocalRef; |
| |
| namespace { |
| |
| // Adds a shortcut which opens in a fullscreen window to the launcher. |
| void AddWebappWithSkBitmap(content::WebContents* web_contents, |
| const webapps::ShortcutInfo& info, |
| const std::string& webapp_id, |
| const SkBitmap& icon_bitmap) { |
| // Send the data to the Java side to create the shortcut. |
| JNIEnv* env = base::android::AttachCurrentThread(); |
| ScopedJavaLocalRef<jstring> java_webapp_id = |
| base::android::ConvertUTF8ToJavaString(env, webapp_id); |
| ScopedJavaLocalRef<jstring> java_url = |
| base::android::ConvertUTF8ToJavaString(env, info.url.spec()); |
| ScopedJavaLocalRef<jstring> java_scope_url = |
| base::android::ConvertUTF8ToJavaString(env, info.scope.spec()); |
| ScopedJavaLocalRef<jstring> java_user_title = |
| base::android::ConvertUTF16ToJavaString(env, info.user_title); |
| ScopedJavaLocalRef<jstring> java_name = |
| base::android::ConvertUTF16ToJavaString(env, info.name); |
| ScopedJavaLocalRef<jstring> java_short_name = |
| base::android::ConvertUTF16ToJavaString(env, info.short_name); |
| ScopedJavaLocalRef<jstring> java_best_primary_icon_url = |
| base::android::ConvertUTF8ToJavaString(env, |
| info.best_primary_icon_url.spec()); |
| ScopedJavaLocalRef<jobject> java_bitmap; |
| if (!icon_bitmap.drawsNothing()) |
| java_bitmap = gfx::ConvertToJavaBitmap(icon_bitmap); |
| |
| Java_ShortcutHelper_addWebapp( |
| env, java_webapp_id, java_url, java_scope_url, java_user_title, java_name, |
| java_short_name, java_best_primary_icon_url, java_bitmap, |
| info.is_primary_icon_maskable, static_cast<int>(info.display), |
| static_cast<int>(info.orientation), info.source, |
| ui::OptionalSkColorToJavaColor(info.theme_color), |
| ui::OptionalSkColorToJavaColor(info.background_color)); |
| |
| // Start downloading the splash image in parallel with the app install. |
| content::ManifestIconDownloader::Download( |
| web_contents, info.splash_image_url, info.ideal_splash_image_size_in_px, |
| info.minimum_splash_image_size_in_px, |
| /* maximum_icon_size_in_px= */ std::numeric_limits<int>::max(), |
| base::BindOnce(&ShortcutHelper::StoreWebappSplashImage, webapp_id)); |
| } |
| |
| // Adds a shortcut which opens in a browser tab to the launcher. |
| void AddShortcutWithSkBitmap(const webapps::ShortcutInfo& info, |
| const std::string& id, |
| const SkBitmap& icon_bitmap) { |
| JNIEnv* env = base::android::AttachCurrentThread(); |
| ScopedJavaLocalRef<jstring> java_id = |
| base::android::ConvertUTF8ToJavaString(env, id); |
| ScopedJavaLocalRef<jstring> java_url = |
| base::android::ConvertUTF8ToJavaString(env, info.url.spec()); |
| ScopedJavaLocalRef<jstring> java_user_title = |
| base::android::ConvertUTF16ToJavaString(env, info.user_title); |
| ScopedJavaLocalRef<jstring> java_best_primary_icon_url = |
| base::android::ConvertUTF8ToJavaString(env, |
| info.best_primary_icon_url.spec()); |
| ScopedJavaLocalRef<jobject> java_bitmap; |
| if (!icon_bitmap.drawsNothing()) |
| java_bitmap = gfx::ConvertToJavaBitmap(icon_bitmap); |
| Java_ShortcutHelper_addShortcut(env, java_id, java_url, java_user_title, |
| java_bitmap, info.is_primary_icon_maskable, |
| info.source, java_best_primary_icon_url); |
| } |
| |
| void RecordAddToHomeScreenUKM( |
| content::WebContents* web_contents, |
| const webapps::ShortcutInfo& info, |
| webapps::InstallableStatusCode installable_status) { |
| if (!web_contents) |
| return; |
| |
| ukm::SourceId source_id = |
| web_contents->GetPrimaryMainFrame()->GetPageUkmSourceId(); |
| ukm::builders::Webapp_AddToHomeScreen(source_id) |
| .SetDisplayMode(static_cast<int>(info.display)) |
| .SetShortcutReason(static_cast<int>(installable_status)) |
| .SetSameAsManifestStartUrl(info.url.spec() == |
| web_contents->GetLastCommittedURL().spec()) |
| .Record(ukm::UkmRecorder::Get()); |
| } |
| |
| } // anonymous namespace |
| |
| // static |
| void ShortcutHelper::AddToLauncherWithSkBitmap( |
| content::WebContents* web_contents, |
| const webapps::ShortcutInfo& info, |
| const SkBitmap& icon_bitmap, |
| webapps::InstallableStatusCode installable_status) { |
| RecordAddToHomeScreenUKM(web_contents, info, installable_status); |
| |
| std::string webapp_id = base::Uuid::GenerateRandomV4().AsLowercaseString(); |
| if (info.display == blink::mojom::DisplayMode::kStandalone || |
| info.display == blink::mojom::DisplayMode::kFullscreen || |
| info.display == blink::mojom::DisplayMode::kMinimalUi) { |
| AddWebappWithSkBitmap(web_contents, info, webapp_id, icon_bitmap); |
| return; |
| } |
| AddShortcutWithSkBitmap(info, webapp_id, icon_bitmap); |
| } |
| |
| // static |
| void ShortcutHelper::StoreWebappSplashImage(const std::string& webapp_id, |
| const SkBitmap& splash_image) { |
| if (splash_image.drawsNothing()) |
| return; |
| |
| JNIEnv* env = base::android::AttachCurrentThread(); |
| ScopedJavaLocalRef<jstring> java_webapp_id = |
| base::android::ConvertUTF8ToJavaString(env, webapp_id); |
| ScopedJavaLocalRef<jobject> java_splash_image = |
| gfx::ConvertToJavaBitmap(splash_image); |
| |
| Java_ShortcutHelper_storeWebappSplashImage(env, java_webapp_id, |
| java_splash_image); |
| } |
| |
| // static |
| bool ShortcutHelper::DoesOriginContainAnyInstalledWebApk(const GURL& origin) { |
| DCHECK_EQ(origin, origin.DeprecatedGetOriginAsURL()); |
| JNIEnv* env = base::android::AttachCurrentThread(); |
| base::android::ScopedJavaLocalRef<jstring> java_origin = |
| base::android::ConvertUTF8ToJavaString( |
| env, url::Origin::Create(origin).Serialize()); |
| return Java_ShortcutHelper_doesOriginContainAnyInstalledWebApk(env, |
| java_origin); |
| } |
| |
| bool ShortcutHelper::DoesOriginContainAnyInstalledTrustedWebActivity( |
| const GURL& origin) { |
| DCHECK_EQ(origin, origin.DeprecatedGetOriginAsURL()); |
| JNIEnv* env = base::android::AttachCurrentThread(); |
| base::android::ScopedJavaLocalRef<jstring> java_origin = |
| base::android::ConvertUTF8ToJavaString( |
| env, url::Origin::Create(origin).Serialize()); |
| return Java_ShortcutHelper_doesOriginContainAnyInstalledTwa(env, java_origin); |
| } |
| |
| std::set<GURL> ShortcutHelper::GetOriginsWithInstalledWebApksOrTwas() { |
| std::set<GURL> installed_origins; |
| JNIEnv* env = base::android::AttachCurrentThread(); |
| |
| base::android::ScopedJavaLocalRef<jobjectArray> j_installed_origins = |
| Java_ShortcutHelper_getOriginsWithInstalledWebApksOrTwas(env); |
| |
| if (j_installed_origins) { |
| std::vector<std::string> installed_origins_list; |
| base::android::AppendJavaStringArrayToStringVector(env, j_installed_origins, |
| &installed_origins_list); |
| for (auto& origin : installed_origins_list) |
| installed_origins.emplace(GURL(origin)); |
| } |
| return installed_origins; |
| } |
| |
| void ShortcutHelper::SetForceWebApkUpdate(const std::string& id) { |
| JNIEnv* env = base::android::AttachCurrentThread(); |
| Java_ShortcutHelper_setForceWebApkUpdate( |
| env, base::android::ConvertUTF8ToJavaString(env, id)); |
| } |