1 // Copyright 2012 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/tab_web_contents_delegate_android.h"
6 
7 #include <stddef.h>
8 
9 #include <memory>
10 #include <string>
11 #include <utility>
12 #include <vector>
13 
14 #include "base/android/jni_android.h"
15 #include "base/android/jni_string.h"
16 #include "base/bind.h"
17 #include "base/command_line.h"
18 #include "base/metrics/histogram_macros.h"
19 #include "base/optional.h"
20 #include "base/rand_util.h"
21 #include "chrome/android/chrome_jni_headers/TabWebContentsDelegateAndroidImpl_jni.h"
22 #include "chrome/browser/android/hung_renderer_infobar_delegate.h"
23 #include "chrome/browser/android/tab_android.h"
24 #include "chrome/browser/banners/app_banner_manager_android.h"
25 #include "chrome/browser/browser_process.h"
26 #include "chrome/browser/content_settings/host_content_settings_map_factory.h"
27 #include "chrome/browser/content_settings/sound_content_setting_observer.h"
28 #include "chrome/browser/data_reduction_proxy/data_reduction_proxy_tab_helper.h"
29 #include "chrome/browser/file_select_helper.h"
30 #include "chrome/browser/flags/android/cached_feature_flags.h"
31 #include "chrome/browser/flags/android/chrome_feature_list.h"
32 #include "chrome/browser/history/history_tab_helper.h"
33 #include "chrome/browser/infobars/infobar_service.h"
34 #include "chrome/browser/installable/installed_webapp_bridge.h"
35 #include "chrome/browser/installable/installed_webapp_geolocation_context.h"
36 #include "chrome/browser/media/protected_media_identifier_permission_context.h"
37 #include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h"
38 #include "chrome/browser/password_manager/chrome_password_manager_client.h"
39 #include "chrome/browser/picture_in_picture/picture_in_picture_window_manager.h"
40 #include "chrome/browser/prefetch/no_state_prefetch/prerender_manager_factory.h"
41 #include "chrome/browser/profiles/profile.h"
42 #include "chrome/browser/safe_browsing/safe_browsing_navigation_observer.h"
43 #include "chrome/browser/ssl/security_state_tab_helper.h"
44 #include "chrome/browser/ui/android/infobars/chrome_confirm_infobar.h"
45 #include "chrome/browser/ui/android/infobars/framebust_block_infobar.h"
46 #include "chrome/browser/ui/android/tab_model/tab_model_list.h"
47 #include "chrome/browser/ui/autofill/chrome_autofill_client.h"
48 #include "chrome/browser/ui/blocked_content/chrome_popup_navigation_delegate.h"
49 #include "chrome/browser/ui/browser_navigator_params.h"
50 #include "chrome/browser/ui/interventions/framebust_block_message_delegate.h"
51 #include "chrome/browser/ui/prefs/prefs_tab_helper.h"
52 #include "chrome/browser/ui/tab_helpers.h"
53 #include "chrome/browser/vr/vr_tab_helper.h"
54 #include "chrome/common/chrome_switches.h"
55 #include "chrome/common/url_constants.h"
56 #include "components/autofill/content/browser/content_autofill_driver_factory.h"
57 #include "components/blocked_content/popup_blocker.h"
58 #include "components/blocked_content/popup_tracker.h"
59 #include "components/browser_ui/sms/android/sms_infobar.h"
60 #include "components/browser_ui/util/android/url_constants.h"
61 #include "components/find_in_page/find_notification_details.h"
62 #include "components/find_in_page/find_tab_helper.h"
63 #include "components/infobars/core/infobar.h"
64 #include "components/javascript_dialogs/app_modal_dialog_manager.h"
65 #include "components/javascript_dialogs/tab_modal_dialog_manager.h"
66 #include "components/navigation_interception/intercept_navigation_delegate.h"
67 #include "components/no_state_prefetch/browser/prerender_manager.h"
68 #include "components/paint_preview/buildflags/buildflags.h"
69 #include "components/security_state/content/content_utils.h"
70 #include "content/public/browser/file_select_listener.h"
71 #include "content/public/browser/navigation_entry.h"
72 #include "content/public/browser/render_frame_host.h"
73 #include "content/public/browser/render_process_host.h"
74 #include "content/public/browser/render_view_host.h"
75 #include "content/public/browser/security_style_explanations.h"
76 #include "content/public/browser/web_contents.h"
77 #include "third_party/blink/public/common/mediastream/media_stream_request.h"
78 #include "third_party/blink/public/mojom/frame/blocked_navigation_types.mojom.h"
79 #include "third_party/blink/public/mojom/window_features/window_features.mojom.h"
80 #include "ui/gfx/geometry/rect.h"
81 #include "ui/gfx/geometry/rect_f.h"
82 #include "url/origin.h"
83 
84 #if BUILDFLAG(ENABLE_PRINTING)
85 #include "components/printing/browser/print_composite_client.h"
86 #endif
87 
88 #if BUILDFLAG(ENABLE_PAINT_PREVIEW)
89 #include "components/paint_preview/browser/paint_preview_client.h"
90 #endif
91 
92 using base::android::AttachCurrentThread;
93 using base::android::JavaParamRef;
94 using base::android::JavaRef;
95 using base::android::ScopedJavaLocalRef;
96 using blink::mojom::FileChooserParams;
97 using content::WebContents;
98 
99 namespace {
100 
101 ScopedJavaLocalRef<jobject>
JNI_TabWebContentsDelegateAndroidImpl_CreateJavaRectF(JNIEnv * env,const gfx::RectF & rect)102 JNI_TabWebContentsDelegateAndroidImpl_CreateJavaRectF(JNIEnv* env,
103                                                       const gfx::RectF& rect) {
104   return ScopedJavaLocalRef<jobject>(
105       Java_TabWebContentsDelegateAndroidImpl_createRectF(
106           env, rect.x(), rect.y(), rect.right(), rect.bottom()));
107 }
108 
109 ScopedJavaLocalRef<jobject>
JNI_TabWebContentsDelegateAndroidImpl_CreateJavaRect(JNIEnv * env,const gfx::Rect & rect)110 JNI_TabWebContentsDelegateAndroidImpl_CreateJavaRect(JNIEnv* env,
111                                                      const gfx::Rect& rect) {
112   return ScopedJavaLocalRef<jobject>(
113       Java_TabWebContentsDelegateAndroidImpl_createRect(
114           env, static_cast<int>(rect.x()), static_cast<int>(rect.y()),
115           static_cast<int>(rect.right()), static_cast<int>(rect.bottom())));
116 }
117 
FindHungRendererInfoBar(InfoBarService * infobar_service)118 infobars::InfoBar* FindHungRendererInfoBar(InfoBarService* infobar_service) {
119   DCHECK(infobar_service);
120   for (size_t i = 0; i < infobar_service->infobar_count(); ++i) {
121     infobars::InfoBar* infobar = infobar_service->infobar_at(i);
122     if (infobar->delegate()->AsHungRendererInfoBarDelegate())
123       return infobar;
124   }
125   return nullptr;
126 }
127 
ShowFramebustBlockInfobarInternal(content::WebContents * web_contents,const GURL & url)128 void ShowFramebustBlockInfobarInternal(content::WebContents* web_contents,
129                                        const GURL& url) {
130   auto intervention_outcome =
131       [](FramebustBlockMessageDelegate::InterventionOutcome outcome) {
132         UMA_HISTOGRAM_ENUMERATION("WebCore.Framebust.InterventionOutcome",
133                                   outcome);
134       };
135   FramebustBlockInfoBar::Show(
136       web_contents,
137       std::make_unique<FramebustBlockMessageDelegate>(
138           web_contents, url, base::BindOnce(intervention_outcome)));
139 }
140 
141 }  // anonymous namespace
142 
143 namespace android {
144 
TabWebContentsDelegateAndroid(JNIEnv * env,jobject obj)145 TabWebContentsDelegateAndroid::TabWebContentsDelegateAndroid(JNIEnv* env,
146                                                                    jobject obj)
147     : WebContentsDelegateAndroid(env, obj) {
148 }
149 
150 TabWebContentsDelegateAndroid::~TabWebContentsDelegateAndroid() = default;
151 
PortalWebContentsCreated(content::WebContents * portal_contents)152 void TabWebContentsDelegateAndroid::PortalWebContentsCreated(
153     content::WebContents* portal_contents) {
154   WebContentsDelegateAndroid::PortalWebContentsCreated(portal_contents);
155 
156   // This is a subset of the tab helpers that would be attached by
157   // TabAndroid::AttachTabHelpers.
158   //
159   // TODO(jbroman): This doesn't adequately handle all of the tab helpers that
160   // might be wanted here, and there are also likely to be issues with tab
161   // helpers that are unprepared for portal activation to transition them.
162   // See https://crbug.com/1042323
163   autofill::ChromeAutofillClient::CreateForWebContents(portal_contents);
164   autofill::ContentAutofillDriverFactory::CreateForWebContentsAndDelegate(
165       portal_contents,
166       autofill::ChromeAutofillClient::FromWebContents(portal_contents),
167       g_browser_process->GetApplicationLocale(),
168       autofill::AutofillManager::ENABLE_AUTOFILL_DOWNLOAD_MANAGER);
169   ChromePasswordManagerClient::CreateForWebContentsWithAutofillClient(
170       portal_contents,
171       autofill::ChromeAutofillClient::FromWebContents(portal_contents));
172   HistoryTabHelper::CreateForWebContents(portal_contents);
173   InfoBarService::CreateForWebContents(portal_contents);
174   PrefsTabHelper::CreateForWebContents(portal_contents);
175   DataReductionProxyTabHelper::CreateForWebContents(portal_contents);
176   safe_browsing::SafeBrowsingNavigationObserver::MaybeCreateForWebContents(
177       portal_contents);
178 }
179 
RunFileChooser(content::RenderFrameHost * render_frame_host,scoped_refptr<content::FileSelectListener> listener,const FileChooserParams & params)180 void TabWebContentsDelegateAndroid::RunFileChooser(
181     content::RenderFrameHost* render_frame_host,
182     scoped_refptr<content::FileSelectListener> listener,
183     const FileChooserParams& params) {
184   if (vr::VrTabHelper::IsUiSuppressedInVr(
185           WebContents::FromRenderFrameHost(render_frame_host),
186           vr::UiSuppressedElement::kFileChooser)) {
187     listener->FileSelectionCanceled();
188     return;
189   }
190   FileSelectHelper::RunFileChooser(render_frame_host, std::move(listener),
191                                    params);
192 }
193 
CreateSmsPrompt(content::RenderFrameHost * host,const url::Origin & origin,const std::string & one_time_code,base::OnceClosure on_confirm,base::OnceClosure on_cancel)194 void TabWebContentsDelegateAndroid::CreateSmsPrompt(
195     content::RenderFrameHost* host,
196     const url::Origin& origin,
197     const std::string& one_time_code,
198     base::OnceClosure on_confirm,
199     base::OnceClosure on_cancel) {
200   auto* web_contents = content::WebContents::FromRenderFrameHost(host);
201   sms::SmsInfoBar::Create(
202       web_contents, InfoBarService::FromWebContents(web_contents),
203       ChromeConfirmInfoBar::GetResourceIdMapper(), origin, one_time_code,
204       std::move(on_confirm), std::move(on_cancel));
205 }
206 
ShouldFocusLocationBarByDefault(WebContents * source)207 bool TabWebContentsDelegateAndroid::ShouldFocusLocationBarByDefault(
208     WebContents* source) {
209   content::NavigationEntry* entry = source->GetController().GetActiveEntry();
210   if (entry) {
211     GURL url = entry->GetURL();
212     GURL virtual_url = entry->GetVirtualURL();
213     if ((url.SchemeIs(browser_ui::kChromeUINativeScheme) &&
214          url.host_piece() == chrome::kChromeUINewTabHost) ||
215         (virtual_url.SchemeIs(browser_ui::kChromeUINativeScheme) &&
216          virtual_url.host_piece() == chrome::kChromeUINewTabHost)) {
217       return true;
218     }
219   }
220   return false;
221 }
222 
GetDisplayMode(const WebContents * web_contents)223 blink::mojom::DisplayMode TabWebContentsDelegateAndroid::GetDisplayMode(
224     const WebContents* web_contents) {
225   JNIEnv* env = base::android::AttachCurrentThread();
226 
227   ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
228   if (obj.is_null())
229     return blink::mojom::DisplayMode::kUndefined;
230 
231   return static_cast<blink::mojom::DisplayMode>(
232       Java_TabWebContentsDelegateAndroidImpl_getDisplayMode(env, obj));
233 }
234 
FindReply(WebContents * web_contents,int request_id,int number_of_matches,const gfx::Rect & selection_rect,int active_match_ordinal,bool final_update)235 void TabWebContentsDelegateAndroid::FindReply(
236     WebContents* web_contents,
237     int request_id,
238     int number_of_matches,
239     const gfx::Rect& selection_rect,
240     int active_match_ordinal,
241     bool final_update) {
242   find_in_page::FindTabHelper* find_tab_helper =
243       find_in_page::FindTabHelper::FromWebContents(web_contents);
244   if (!find_result_observer_.IsObserving(find_tab_helper))
245     find_result_observer_.Add(find_tab_helper);
246 
247   find_tab_helper->HandleFindReply(request_id,
248                                    number_of_matches,
249                                    selection_rect,
250                                    active_match_ordinal,
251                                    final_update);
252 }
253 
FindMatchRectsReply(WebContents * web_contents,int version,const std::vector<gfx::RectF> & rects,const gfx::RectF & active_rect)254 void TabWebContentsDelegateAndroid::FindMatchRectsReply(
255     WebContents* web_contents,
256     int version,
257     const std::vector<gfx::RectF>& rects,
258     const gfx::RectF& active_rect) {
259   JNIEnv* env = base::android::AttachCurrentThread();
260   ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
261   if (obj.is_null())
262     return;
263 
264   // Create the details object.
265   ScopedJavaLocalRef<jobject> details_object =
266       Java_TabWebContentsDelegateAndroidImpl_createFindMatchRectsDetails(
267           env, version, rects.size(),
268           JNI_TabWebContentsDelegateAndroidImpl_CreateJavaRectF(env,
269                                                                 active_rect));
270 
271   // Add the rects
272   for (size_t i = 0; i < rects.size(); ++i) {
273     Java_TabWebContentsDelegateAndroidImpl_setMatchRectByIndex(
274         env, details_object, i,
275         JNI_TabWebContentsDelegateAndroidImpl_CreateJavaRectF(env, rects[i]));
276   }
277 
278   Java_TabWebContentsDelegateAndroidImpl_onFindMatchRectsAvailable(
279       env, obj, details_object);
280 }
281 
282 content::JavaScriptDialogManager*
GetJavaScriptDialogManager(WebContents * source)283 TabWebContentsDelegateAndroid::GetJavaScriptDialogManager(
284     WebContents* source) {
285   // For VR, we use app modal since the dialog view will cover the location bar.
286   if (!vr::VrTabHelper::IsInVr(source)) {
287     return javascript_dialogs::TabModalDialogManager::FromWebContents(source);
288   }
289   return javascript_dialogs::AppModalDialogManager::GetInstance();
290 }
291 
AdjustPreviewsStateForNavigation(content::WebContents * web_contents,blink::PreviewsState * previews_state)292 void TabWebContentsDelegateAndroid::AdjustPreviewsStateForNavigation(
293     content::WebContents* web_contents,
294     blink::PreviewsState* previews_state) {
295   if (GetDisplayMode(web_contents) != blink::mojom::DisplayMode::kBrowser) {
296     *previews_state = blink::PreviewsTypes::PREVIEWS_OFF;
297   }
298 }
299 
RequestMediaAccessPermission(content::WebContents * web_contents,const content::MediaStreamRequest & request,content::MediaResponseCallback callback)300 void TabWebContentsDelegateAndroid::RequestMediaAccessPermission(
301     content::WebContents* web_contents,
302     const content::MediaStreamRequest& request,
303     content::MediaResponseCallback callback) {
304   MediaCaptureDevicesDispatcher::GetInstance()->ProcessMediaAccessRequest(
305       web_contents, request, std::move(callback), nullptr);
306 }
307 
CheckMediaAccessPermission(content::RenderFrameHost * render_frame_host,const GURL & security_origin,blink::mojom::MediaStreamType type)308 bool TabWebContentsDelegateAndroid::CheckMediaAccessPermission(
309     content::RenderFrameHost* render_frame_host,
310     const GURL& security_origin,
311     blink::mojom::MediaStreamType type) {
312   return MediaCaptureDevicesDispatcher::GetInstance()
313       ->CheckMediaAccessPermission(render_frame_host, security_origin, type);
314 }
315 
SetOverlayMode(bool use_overlay_mode)316 void TabWebContentsDelegateAndroid::SetOverlayMode(bool use_overlay_mode) {
317   JNIEnv* env = base::android::AttachCurrentThread();
318   ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
319   if (obj.is_null())
320     return;
321 
322   Java_TabWebContentsDelegateAndroidImpl_setOverlayMode(env, obj,
323                                                         use_overlay_mode);
324 }
325 
RequestPpapiBrokerPermission(WebContents * web_contents,const GURL & url,const base::FilePath & plugin_path,base::OnceCallback<void (bool)> callback)326 void TabWebContentsDelegateAndroid::RequestPpapiBrokerPermission(
327     WebContents* web_contents,
328     const GURL& url,
329     const base::FilePath& plugin_path,
330     base::OnceCallback<void(bool)> callback) {
331   std::move(callback).Run(false);
332 }
333 
OpenURLFromTab(WebContents * source,const content::OpenURLParams & params)334 WebContents* TabWebContentsDelegateAndroid::OpenURLFromTab(
335     WebContents* source,
336     const content::OpenURLParams& params) {
337   WindowOpenDisposition disposition = params.disposition;
338   if (!source || (disposition != WindowOpenDisposition::CURRENT_TAB &&
339                   disposition != WindowOpenDisposition::NEW_FOREGROUND_TAB &&
340                   disposition != WindowOpenDisposition::NEW_BACKGROUND_TAB &&
341                   disposition != WindowOpenDisposition::OFF_THE_RECORD &&
342                   disposition != WindowOpenDisposition::NEW_POPUP &&
343                   disposition != WindowOpenDisposition::NEW_WINDOW)) {
344     // We can't handle this here.  Give the parent a chance.
345     return WebContentsDelegateAndroid::OpenURLFromTab(source, params);
346   }
347 
348   Profile* profile = Profile::FromBrowserContext(source->GetBrowserContext());
349   NavigateParams nav_params(profile, params.url, params.transition);
350   nav_params.FillNavigateParamsFromOpenURLParams(params);
351   nav_params.source_contents = source;
352   nav_params.window_action = NavigateParams::SHOW_WINDOW;
353   auto popup_delegate =
354       std::make_unique<ChromePopupNavigationDelegate>(std::move(nav_params));
355   if (blocked_content::ConsiderForPopupBlocking(params.disposition)) {
356     popup_delegate.reset(static_cast<ChromePopupNavigationDelegate*>(
357         blocked_content::MaybeBlockPopup(
358             source, nullptr, std::move(popup_delegate), &params,
359             blink::mojom::WindowFeatures(),
360             HostContentSettingsMapFactory::GetForProfile(
361                 source->GetBrowserContext()))
362             .release()));
363     if (!popup_delegate)
364       return nullptr;
365   }
366 
367   if (disposition == WindowOpenDisposition::CURRENT_TAB) {
368     // Ask the parent to handle in-place opening.
369     return WebContentsDelegateAndroid::OpenURLFromTab(source, params);
370   }
371 
372   popup_delegate->nav_params()->created_with_opener = true;
373   TabModelList::HandlePopupNavigation(popup_delegate->nav_params());
374   return nullptr;
375 }
376 
ShouldResumeRequestsForCreatedWindow()377 bool TabWebContentsDelegateAndroid::ShouldResumeRequestsForCreatedWindow() {
378   JNIEnv* env = base::android::AttachCurrentThread();
379   ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
380   if (obj.is_null())
381     return true;
382 
383   return Java_TabWebContentsDelegateAndroidImpl_shouldResumeRequestsForCreatedWindow(
384       env, obj);
385 }
386 
AddNewContents(WebContents * source,std::unique_ptr<WebContents> new_contents,const GURL & target_url,WindowOpenDisposition disposition,const gfx::Rect & initial_rect,bool user_gesture,bool * was_blocked)387 void TabWebContentsDelegateAndroid::AddNewContents(
388     WebContents* source,
389     std::unique_ptr<WebContents> new_contents,
390     const GURL& target_url,
391     WindowOpenDisposition disposition,
392     const gfx::Rect& initial_rect,
393     bool user_gesture,
394     bool* was_blocked) {
395   // No code for this yet.
396   DCHECK_NE(disposition, WindowOpenDisposition::SAVE_TO_DISK);
397   // Can't create a new contents for the current tab - invalid case.
398   DCHECK_NE(disposition, WindowOpenDisposition::CURRENT_TAB);
399 
400   // At this point the |new_contents| is beyond the popup blocker, but we use
401   // the same logic for determining if the popup tracker needs to be attached.
402   if (source && blocked_content::ConsiderForPopupBlocking(disposition)) {
403     blocked_content::PopupTracker::CreateForWebContents(new_contents.get(),
404                                                         source, disposition);
405   }
406 
407   TabHelpers::AttachTabHelpers(new_contents.get());
408 
409   JNIEnv* env = AttachCurrentThread();
410   ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
411   bool handled = false;
412   if (!obj.is_null()) {
413     ScopedJavaLocalRef<jobject> jsource;
414     if (source)
415       jsource = source->GetJavaWebContents();
416     ScopedJavaLocalRef<jobject> jnew_contents;
417     if (new_contents)
418       jnew_contents = new_contents->GetJavaWebContents();
419 
420     handled = Java_TabWebContentsDelegateAndroidImpl_addNewContents(
421         env, obj, jsource, jnew_contents, static_cast<jint>(disposition),
422         nullptr, user_gesture);
423   }
424 
425   if (was_blocked)
426     *was_blocked = !handled;
427 
428   // When handled is |true|, ownership has been passed to java, which in turn
429   // creates a new TabAndroid instance to own the WebContents.
430   if (handled)
431     new_contents.release();
432 }
433 
GetSecurityStyle(WebContents * web_contents,content::SecurityStyleExplanations * security_style_explanations)434 blink::SecurityStyle TabWebContentsDelegateAndroid::GetSecurityStyle(
435     WebContents* web_contents,
436     content::SecurityStyleExplanations* security_style_explanations) {
437   SecurityStateTabHelper* helper =
438       SecurityStateTabHelper::FromWebContents(web_contents);
439   DCHECK(helper);
440   return security_state::GetSecurityStyle(helper->GetSecurityLevel(),
441                                           *helper->GetVisibleSecurityState(),
442                                           security_style_explanations);
443 }
444 
OnDidBlockNavigation(content::WebContents * web_contents,const GURL & blocked_url,const GURL & initiator_url,blink::mojom::NavigationBlockedReason reason)445 void TabWebContentsDelegateAndroid::OnDidBlockNavigation(
446     content::WebContents* web_contents,
447     const GURL& blocked_url,
448     const GURL& initiator_url,
449     blink::mojom::NavigationBlockedReason reason) {
450   ShowFramebustBlockInfobarInternal(web_contents, blocked_url);
451 }
452 
UpdateUserGestureCarryoverInfo(content::WebContents * web_contents)453 void TabWebContentsDelegateAndroid::UpdateUserGestureCarryoverInfo(
454     content::WebContents* web_contents) {
455   auto* intercept_navigation_delegate =
456       navigation_interception::InterceptNavigationDelegate::Get(web_contents);
457   if (intercept_navigation_delegate)
458     intercept_navigation_delegate->UpdateLastUserGestureCarryoverTimestamp();
459 }
460 
461 content::PictureInPictureResult
EnterPictureInPicture(content::WebContents * web_contents,const viz::SurfaceId & surface_id,const gfx::Size & natural_size)462 TabWebContentsDelegateAndroid::EnterPictureInPicture(
463     content::WebContents* web_contents,
464     const viz::SurfaceId& surface_id,
465     const gfx::Size& natural_size) {
466   return PictureInPictureWindowManager::GetInstance()->EnterPictureInPicture(
467       web_contents, surface_id, natural_size);
468 }
469 
ExitPictureInPicture()470 void TabWebContentsDelegateAndroid::ExitPictureInPicture() {
471   PictureInPictureWindowManager::GetInstance()->ExitPictureInPicture();
472 }
473 
474 std::unique_ptr<content::WebContents>
ActivatePortalWebContents(content::WebContents * predecessor_contents,std::unique_ptr<content::WebContents> portal_contents)475 TabWebContentsDelegateAndroid::ActivatePortalWebContents(
476     content::WebContents* predecessor_contents,
477     std::unique_ptr<content::WebContents> portal_contents) {
478   const bool is_loading = portal_contents->IsLoading();
479   return TabAndroid::FromWebContents(predecessor_contents)
480       ->SwapWebContents(std::move(portal_contents),
481                         /* did_start_load */ true,
482                         /* did_finish_load */ !is_loading);
483 }
484 
485 device::mojom::GeolocationContext*
GetInstalledWebappGeolocationContext()486 TabWebContentsDelegateAndroid::GetInstalledWebappGeolocationContext() {
487   if (!IsInstalledWebappDelegateGeolocation())
488     return nullptr;
489 
490   if (!installed_webapp_geolocation_context_) {
491     installed_webapp_geolocation_context_ =
492         std::make_unique<InstalledWebappGeolocationContext>();
493   }
494   return installed_webapp_geolocation_context_.get();
495 }
496 
497 #if BUILDFLAG(ENABLE_PRINTING)
PrintCrossProcessSubframe(content::WebContents * web_contents,const gfx::Rect & rect,int document_cookie,content::RenderFrameHost * subframe_host) const498 void TabWebContentsDelegateAndroid::PrintCrossProcessSubframe(
499     content::WebContents* web_contents,
500     const gfx::Rect& rect,
501     int document_cookie,
502     content::RenderFrameHost* subframe_host) const {
503   auto* client = printing::PrintCompositeClient::FromWebContents(web_contents);
504   if (client)
505     client->PrintCrossProcessSubframe(rect, document_cookie, subframe_host);
506 }
507 #endif
508 
509 #if BUILDFLAG(ENABLE_PAINT_PREVIEW)
CapturePaintPreviewOfSubframe(content::WebContents * web_contents,const gfx::Rect & rect,const base::UnguessableToken & guid,content::RenderFrameHost * render_frame_host)510 void TabWebContentsDelegateAndroid::CapturePaintPreviewOfSubframe(
511     content::WebContents* web_contents,
512     const gfx::Rect& rect,
513     const base::UnguessableToken& guid,
514     content::RenderFrameHost* render_frame_host) {
515   auto* client =
516       paint_preview::PaintPreviewClient::FromWebContents(web_contents);
517   if (client)
518     client->CaptureSubframePaintPreview(guid, rect, render_frame_host);
519 }
520 #endif
521 
OnFindResultAvailable(WebContents * web_contents)522 void TabWebContentsDelegateAndroid::OnFindResultAvailable(
523     WebContents* web_contents) {
524   JNIEnv* env = base::android::AttachCurrentThread();
525   ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
526   if (obj.is_null())
527     return;
528 
529   const find_in_page::FindNotificationDetails& find_result =
530       find_in_page::FindTabHelper::FromWebContents(web_contents)->find_result();
531 
532   ScopedJavaLocalRef<jobject> selection_rect =
533       JNI_TabWebContentsDelegateAndroidImpl_CreateJavaRect(
534           env, find_result.selection_rect());
535 
536   // Create the details object.
537   ScopedJavaLocalRef<jobject> details_object =
538       Java_TabWebContentsDelegateAndroidImpl_createFindNotificationDetails(
539           env, find_result.number_of_matches(), selection_rect,
540           find_result.active_match_ordinal(), find_result.final_update());
541 
542   Java_TabWebContentsDelegateAndroidImpl_onFindResultAvailable(env, obj,
543                                                                details_object);
544 }
545 
OnFindTabHelperDestroyed(find_in_page::FindTabHelper * helper)546 void TabWebContentsDelegateAndroid::OnFindTabHelperDestroyed(
547     find_in_page::FindTabHelper* helper) {
548   find_result_observer_.Remove(helper);
549 }
550 
ShouldEnableEmbeddedMediaExperience() const551 bool TabWebContentsDelegateAndroid::ShouldEnableEmbeddedMediaExperience()
552     const {
553   JNIEnv* env = base::android::AttachCurrentThread();
554   ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
555   if (obj.is_null())
556     return false;
557   return Java_TabWebContentsDelegateAndroidImpl_shouldEnableEmbeddedMediaExperience(
558       env, obj);
559 }
560 
IsPictureInPictureEnabled() const561 bool TabWebContentsDelegateAndroid::IsPictureInPictureEnabled() const {
562   JNIEnv* env = base::android::AttachCurrentThread();
563   ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
564   if (obj.is_null())
565     return false;
566   return Java_TabWebContentsDelegateAndroidImpl_isPictureInPictureEnabled(env,
567                                                                           obj);
568 }
569 
IsNightModeEnabled() const570 bool TabWebContentsDelegateAndroid::IsNightModeEnabled() const {
571   JNIEnv* env = base::android::AttachCurrentThread();
572   ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
573   if (obj.is_null())
574     return false;
575   return Java_TabWebContentsDelegateAndroidImpl_isNightModeEnabled(env, obj);
576 }
577 
CanShowAppBanners() const578 bool TabWebContentsDelegateAndroid::CanShowAppBanners() const {
579   JNIEnv* env = base::android::AttachCurrentThread();
580   ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
581   if (obj.is_null())
582     return false;
583   return Java_TabWebContentsDelegateAndroidImpl_canShowAppBanners(env, obj);
584 }
585 
GetManifestScope() const586 const GURL TabWebContentsDelegateAndroid::GetManifestScope() const {
587   JNIEnv* env = base::android::AttachCurrentThread();
588   ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
589   if (obj.is_null())
590     return GURL();
591   const JavaRef<jstring>& scope =
592       Java_TabWebContentsDelegateAndroidImpl_getManifestScope(env, obj);
593   return scope.is_null() ? GURL()
594                          : GURL(base::android::ConvertJavaStringToUTF8(scope));
595 }
596 
IsCustomTab() const597 bool TabWebContentsDelegateAndroid::IsCustomTab() const {
598   JNIEnv* env = base::android::AttachCurrentThread();
599   ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
600   if (obj.is_null())
601     return false;
602   return Java_TabWebContentsDelegateAndroidImpl_isCustomTab(env, obj);
603 }
604 
IsInstalledWebappDelegateGeolocation() const605 bool TabWebContentsDelegateAndroid::IsInstalledWebappDelegateGeolocation()
606     const {
607   if (!base::FeatureList::IsEnabled(
608           chrome::android::kTrustedWebActivityLocationDelegation)) {
609     return false;
610   }
611 
612   JNIEnv* env = base::android::AttachCurrentThread();
613   ScopedJavaLocalRef<jobject> obj = GetJavaDelegate(env);
614   if (obj.is_null())
615     return false;
616   return Java_TabWebContentsDelegateAndroidImpl_isInstalledWebappDelegateGeolocation(
617       env, obj);
618 }
619 
620 }  // namespace android
621 
JNI_TabWebContentsDelegateAndroidImpl_OnRendererUnresponsive(JNIEnv * env,const JavaParamRef<jobject> & java_web_contents)622 void JNI_TabWebContentsDelegateAndroidImpl_OnRendererUnresponsive(
623     JNIEnv* env,
624     const JavaParamRef<jobject>& java_web_contents) {
625   // Rate limit the number of stack dumps so we don't overwhelm our crash
626   // reports.
627   content::WebContents* web_contents =
628       content::WebContents::FromJavaWebContents(java_web_contents);
629   if (base::RandDouble() < 0.01)
630     web_contents->GetMainFrame()->GetProcess()->DumpProcessStack();
631 
632   if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
633           switches::kEnableHungRendererInfoBar)) {
634     return;
635   }
636 
637   InfoBarService* infobar_service =
638       InfoBarService::FromWebContents(web_contents);
639   DCHECK(!FindHungRendererInfoBar(infobar_service));
640   HungRendererInfoBarDelegate::Create(
641       infobar_service, web_contents->GetMainFrame()->GetProcess());
642 }
643 
JNI_TabWebContentsDelegateAndroidImpl_OnRendererResponsive(JNIEnv * env,const JavaParamRef<jobject> & java_web_contents)644 void JNI_TabWebContentsDelegateAndroidImpl_OnRendererResponsive(
645     JNIEnv* env,
646     const JavaParamRef<jobject>& java_web_contents) {
647   content::WebContents* web_contents =
648           content::WebContents::FromJavaWebContents(java_web_contents);
649   InfoBarService* infobar_service =
650       InfoBarService::FromWebContents(web_contents);
651   infobars::InfoBar* hung_renderer_infobar =
652       FindHungRendererInfoBar(infobar_service);
653   if (!hung_renderer_infobar)
654     return;
655 
656   hung_renderer_infobar->delegate()
657       ->AsHungRendererInfoBarDelegate()
658       ->OnRendererResponsive();
659   infobar_service->RemoveInfoBar(hung_renderer_infobar);
660 }
661 
JNI_TabWebContentsDelegateAndroidImpl_ShowFramebustBlockInfoBar(JNIEnv * env,const JavaParamRef<jobject> & java_web_contents,const JavaParamRef<jstring> & java_url)662 void JNI_TabWebContentsDelegateAndroidImpl_ShowFramebustBlockInfoBar(
663     JNIEnv* env,
664     const JavaParamRef<jobject>& java_web_contents,
665     const JavaParamRef<jstring>& java_url) {
666   GURL url(base::android::ConvertJavaStringToUTF16(env, java_url));
667   content::WebContents* web_contents =
668       content::WebContents::FromJavaWebContents(java_web_contents);
669   ShowFramebustBlockInfobarInternal(web_contents, url);
670 }
671