| // Copyright 2024 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/webapps/webapps_client_android.h" |
| |
| #include "base/logging.h" |
| #include "base/no_destructor.h" |
| #include "base/task/task_traits.h" |
| #include "base/task/thread_pool.h" |
| #include "build/build_config.h" |
| #include "chrome/browser/android/shortcut_helper.h" |
| #include "chrome/browser/android/tab_android.h" |
| #include "chrome/browser/android/tab_web_contents_delegate_android.h" |
| #include "chrome/browser/android/webapk/webapk_install_service.h" |
| #include "chrome/browser/android/webapk/webapk_install_service_factory.h" |
| #include "chrome/browser/feature_engagement/tracker_factory.h" |
| #include "chrome/common/url_constants.h" |
| #include "components/feature_engagement/public/event_constants.h" |
| #include "components/feature_engagement/public/tracker.h" |
| #include "components/infobars/content/content_infobar_manager.h" |
| #include "components/security_state/content/security_state_tab_helper.h" |
| #include "components/webapps/browser/android/add_to_homescreen_params.h" |
| #include "components/webapps/browser/android/app_banner_manager_android.h" |
| #include "components/webapps/browser/android/webapps_utils.h" |
| #include "components/webapps/browser/features.h" |
| #include "components/webapps/browser/installable/installable_metrics.h" |
| #include "components/webapps/common/web_app_id.h" |
| #include "content/public/browser/web_contents.h" |
| #include "url/origin.h" |
| |
| namespace webapps { |
| namespace { |
| bool IsWebApkInstalled(const GURL& start_url) { |
| return WebappsUtils::IsWebApkInstalled(start_url); |
| } |
| } // namespace |
| |
| // static |
| void WebappsClientAndroid::CreateSingleton() { |
| static base::NoDestructor<WebappsClientAndroid> instance; |
| instance.get(); |
| } |
| |
| WebappInstallSource WebappsClientAndroid::GetInstallSource( |
| content::WebContents* web_contents, |
| InstallTrigger trigger) { |
| auto* delegate = static_cast<android::TabWebContentsDelegateAndroid*>( |
| web_contents->GetDelegate()); |
| bool is_custom_tab = delegate->IsCustomTab(); |
| |
| switch (trigger) { |
| case InstallTrigger::AMBIENT_BADGE: |
| return is_custom_tab ? WebappInstallSource::AMBIENT_BADGE_CUSTOM_TAB |
| : WebappInstallSource::AMBIENT_BADGE_BROWSER_TAB; |
| case InstallTrigger::API: |
| return is_custom_tab ? WebappInstallSource::API_CUSTOM_TAB |
| : WebappInstallSource::API_BROWSER_TAB; |
| case InstallTrigger::AUTOMATIC_PROMPT: |
| return is_custom_tab ? WebappInstallSource::AUTOMATIC_PROMPT_CUSTOM_TAB |
| : WebappInstallSource::AUTOMATIC_PROMPT_BROWSER_TAB; |
| case InstallTrigger::MENU: |
| return is_custom_tab ? WebappInstallSource::MENU_CUSTOM_TAB |
| : WebappInstallSource::MENU_BROWSER_TAB; |
| // Create shortcut does not exist on Android, so it doesn't apply to custom |
| // tab. |
| case InstallTrigger::CREATE_SHORTCUT: |
| DCHECK(!is_custom_tab); |
| return WebappInstallSource::MENU_CREATE_SHORTCUT; |
| } |
| NOTREACHED(); |
| } |
| |
| AppBannerManager* WebappsClientAndroid::GetAppBannerManager( |
| content::WebContents* web_contents) { |
| return AppBannerManagerAndroid::FromWebContents(web_contents); |
| } |
| |
| void WebappsClientAndroid::DoesNewWebAppConflictWithExistingInstallation( |
| content::BrowserContext* browser_context, |
| const GURL& start_url, |
| const ManifestId& manifest_id, |
| WebAppInstallationConflictCallback callback) const { |
| // Also check if a WebAPK is currently being installed. Installation may take |
| // some time, so ensure we don't accidentally allow a new installation whilst |
| // one is in flight for the current site. |
| const bool is_installation_in_progress = |
| IsInstallationInProgress(browser_context, manifest_id); |
| if (is_installation_in_progress) { |
| std::move(callback).Run(/* does_conflict= */ true); |
| return; |
| } |
| if (!base::FeatureList::IsEnabled( |
| webapps::features::kCheckWebAppExistenceAsync)) { |
| std::move(callback).Run( |
| /* does_conflict= */ WebappsUtils::IsWebApkInstalled(start_url)); |
| return; |
| } |
| |
| base::ThreadPool::PostTaskAndReplyWithResult( |
| FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_VISIBLE}, |
| base::BindOnce(&IsWebApkInstalled, start_url), std::move(callback)); |
| } |
| |
| bool WebappsClientAndroid::IsInAppBrowsingContext( |
| content::WebContents* web_contents) const { |
| return false; |
| } |
| bool WebappsClientAndroid::IsAppPartiallyInstalledForSiteUrl( |
| content::BrowserContext* browsing_context, |
| const GURL& site_url) const { |
| return false; |
| } |
| bool WebappsClientAndroid::IsAppFullyInstalledForSiteUrl( |
| content::BrowserContext* browsing_context, |
| const GURL& site_url) const { |
| return false; |
| } |
| bool WebappsClientAndroid::IsUrlControlledBySeenManifest( |
| content::BrowserContext* browsing_context, |
| const GURL& site_url) const { |
| return false; |
| } |
| |
| void WebappsClientAndroid::OnManifestSeen( |
| content::BrowserContext* browsing_context, |
| const blink::mojom::Manifest& manifest) const {} |
| |
| void WebappsClientAndroid::SaveInstallationDismissedForMl( |
| content::BrowserContext* browsing_context, |
| const GURL& manifest_id) const { |
| } |
| void WebappsClientAndroid::SaveInstallationIgnoredForMl( |
| content::BrowserContext* browsing_context, |
| const GURL& manifest_id) const { |
| } |
| void WebappsClientAndroid::SaveInstallationAcceptedForMl( |
| content::BrowserContext* browsing_context, |
| const GURL& manifest_id) const { |
| } |
| bool WebappsClientAndroid::IsMlPromotionBlockedByHistoryGuardrail( |
| content::BrowserContext* browsing_context, |
| const GURL& manifest_id) const { |
| return false; |
| } |
| |
| segmentation_platform::SegmentationPlatformService* |
| WebappsClientAndroid::GetSegmentationPlatformService( |
| content::BrowserContext* browsing_context) const { |
| // TODO(crbug.com/40269982): Implement. |
| // Note: By returning a non-nullptr, all of the Ml code (after metrics |
| // gathering) in `MlInstallabilityPromoter` will execute, including requesting |
| // classifiction & eventually calling `OnMlInstallPrediction` above. Make sure |
| // that the contract of that class is being followed appropriately, and the ML |
| // parts are correct. |
| return nullptr; |
| } |
| |
| bool WebappsClientAndroid::IsInstallationInProgress( |
| content::WebContents* web_contents, |
| const GURL& manifest_id) { |
| return IsInstallationInProgress(web_contents->GetBrowserContext(), |
| manifest_id); |
| } |
| |
| bool WebappsClientAndroid::CanShowAppBanners( |
| const content::WebContents* web_contents) { |
| TabAndroid* tab = TabAndroid::FromWebContents(web_contents); |
| return tab && static_cast<android::TabWebContentsDelegateAndroid*>( |
| tab->web_contents()->GetDelegate()) |
| ->CanShowAppBanners(); |
| } |
| |
| void WebappsClientAndroid::OnWebApkInstallInitiatedFromAppMenu( |
| content::WebContents* web_contents) { |
| DVLOG(2) << "Sending event: IPH used for Installing PWA"; |
| feature_engagement::Tracker* tracker = |
| feature_engagement::TrackerFactory::GetForBrowserContext( |
| web_contents->GetBrowserContext()); |
| tracker->NotifyEvent(feature_engagement::events::kPwaInstallMenuSelected); |
| } |
| |
| void WebappsClientAndroid::InstallWebApk(content::WebContents* web_contents, |
| const AddToHomescreenParams& params) { |
| WebApkInstallServiceFactory::GetForBrowserContext( |
| web_contents->GetBrowserContext()) |
| ->InstallAsync(web_contents, *(params.shortcut_info), params.primary_icon, |
| params.install_source); |
| } |
| |
| void WebappsClientAndroid::InstallShortcut( |
| content::WebContents* web_contents, |
| const AddToHomescreenParams& params) { |
| ShortcutHelper::AddToLauncherWithSkBitmap( |
| web_contents, *(params.shortcut_info), params.primary_icon, |
| params.installable_status); |
| } |
| |
| bool WebappsClientAndroid::IsInstallationInProgress( |
| content::BrowserContext* browser_context, |
| const GURL& manifest_id) const { |
| return WebApkInstallServiceFactory::GetForBrowserContext(browser_context) |
| ->IsInstallInProgress(manifest_id); |
| } |
| |
| } // namespace webapps |