Avi Drissman | 4e1b7bc3 | 2022-09-15 14:03:50 | [diff] [blame] | 1 | // Copyright 2017 The Chromium Authors |
liberato | a8da3b5 | 2017-05-02 20:23:51 | [diff] [blame] | 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 "content/browser/android/dialog_overlay_impl.h" |
| 6 | |
Victor Hugo Vianna Silva | 94fdad2 | 2025-03-18 19:51:13 | [diff] [blame] | 7 | #include <variant> |
| 8 | |
danakj | c027008 | 2020-09-15 22:28:00 | [diff] [blame] | 9 | #include "content/browser/renderer_host/render_frame_host_impl.h" |
Michael Thiessen | c5c4fef | 2017-08-29 16:42:04 | [diff] [blame] | 10 | #include "content/browser/renderer_host/render_widget_host_view_base.h" |
Jinsuk Kim | d5d29a2 | 2017-08-29 01:39:44 | [diff] [blame] | 11 | #include "content/browser/web_contents/web_contents_impl.h" |
Gabriel Charette | c738e958 | 2019-11-01 18:31:33 | [diff] [blame] | 12 | #include "content/public/browser/browser_task_traits.h" |
Gabriel Charette | 790754c | 2018-03-16 21:32:59 | [diff] [blame] | 13 | #include "content/public/browser/browser_thread.h" |
Richard Knoll | ba18275 | 2021-06-01 10:49:55 | [diff] [blame] | 14 | #include "content/public/browser/content_browser_client.h" |
Thomas Guilbert | 0267a42c | 2017-08-02 08:08:33 | [diff] [blame] | 15 | #include "content/public/browser/web_contents_delegate.h" |
Richard Knoll | ba18275 | 2021-06-01 10:49:55 | [diff] [blame] | 16 | #include "content/public/common/content_client.h" |
liberato | a8da3b5 | 2017-05-02 20:23:51 | [diff] [blame] | 17 | #include "gpu/ipc/common/gpu_surface_tracker.h" |
Frank Liberato | d66bd924 | 2020-11-20 21:05:46 | [diff] [blame] | 18 | #include "media/mojo/mojom/android_overlay.mojom.h" |
Frank Liberato | 13bde9e | 2021-02-28 20:46:00 | [diff] [blame] | 19 | #include "mojo/public/cpp/bindings/sync_call_restrictions.h" |
Jinsuk Kim | d5d29a2 | 2017-08-29 01:39:44 | [diff] [blame] | 20 | #include "ui/android/view_android_observer.h" |
liberato | a8da3b5 | 2017-05-02 20:23:51 | [diff] [blame] | 21 | #include "ui/android/window_android.h" |
| 22 | |
Andrew Grieve | ecb885bb | 2024-05-29 18:14:19 | [diff] [blame] | 23 | // Must come after all headers that specialize FromJniType() / ToJniType(). |
| 24 | #include "content/public/android/content_jni_headers/DialogOverlayImpl_jni.h" |
| 25 | |
liberato | a8da3b5 | 2017-05-02 20:23:51 | [diff] [blame] | 26 | using base::android::AttachCurrentThread; |
| 27 | using base::android::JavaParamRef; |
| 28 | using base::android::ScopedJavaLocalRef; |
| 29 | |
| 30 | namespace content { |
| 31 | |
Daniel Bratell | 7aacf95 | 2017-11-21 17:51:25 | [diff] [blame] | 32 | static jlong JNI_DialogOverlayImpl_Init(JNIEnv* env, |
| 33 | const JavaParamRef<jobject>& obj, |
| 34 | jlong high, |
| 35 | jlong low, |
| 36 | jboolean power_efficient) { |
liberato | a8da3b5 | 2017-05-02 20:23:51 | [diff] [blame] | 37 | DCHECK_CURRENTLY_ON(BrowserThread::UI); |
Thomas Guilbert | 2d5ef44 | 2017-07-13 00:12:55 | [diff] [blame] | 38 | |
Arthur Sonzogni | c686e8f | 2024-01-11 08:36:37 | [diff] [blame] | 39 | std::optional<base::UnguessableToken> token = |
Andrew Williams | 228be95c | 2023-01-26 15:13:01 | [diff] [blame] | 40 | base::UnguessableToken::Deserialize(high, low); |
Andrew Williams | c07db02 | 2023-01-24 13:38:52 | [diff] [blame] | 41 | if (!token.has_value()) { |
Andrew Williams | 068e698 | 2022-12-29 01:46:55 | [diff] [blame] | 42 | return 0; |
| 43 | } |
| 44 | |
Thomas Guilbert | 2d5ef44 | 2017-07-13 00:12:55 | [diff] [blame] | 45 | RenderFrameHostImpl* rfhi = |
Andrew Williams | c07db02 | 2023-01-24 13:38:52 | [diff] [blame] | 46 | content::RenderFrameHostImpl::FromOverlayRoutingToken(token.value()); |
Thomas Guilbert | 2d5ef44 | 2017-07-13 00:12:55 | [diff] [blame] | 47 | |
| 48 | if (!rfhi) |
| 49 | return 0; |
| 50 | |
Daniel Cheng | 714f621 | 2022-01-13 19:29:09 | [diff] [blame] | 51 | // If the RenderFrameHost does not have a live RenderFrame, immediately bail |
| 52 | // out: not only is there nothing to do, the `RenderFrameDeleted()` |
| 53 | // notification to clean up the overlay would never be called. |
| 54 | if (!rfhi->IsRenderFrameLive()) |
| 55 | return 0; |
| 56 | |
Thomas Guilbert | 2d5ef44 | 2017-07-13 00:12:55 | [diff] [blame] | 57 | WebContentsImpl* web_contents_impl = static_cast<WebContentsImpl*>( |
| 58 | content::WebContents::FromRenderFrameHost(rfhi)); |
| 59 | |
| 60 | // If the overlay would not be immediately used, fail the request. |
Sreeja Kamishetty | e49854f8 | 2021-06-02 00:52:03 | [diff] [blame] | 61 | if (!rfhi->IsActive() || !web_contents_impl || web_contents_impl->IsHidden()) |
Thomas Guilbert | 2d5ef44 | 2017-07-13 00:12:55 | [diff] [blame] | 62 | return 0; |
| 63 | |
[email protected] | d57bc41 | 2017-08-09 20:30:11 | [diff] [blame] | 64 | // Dialog-based overlays are not supported for persistent video. |
John Abd-El-Malek | 74f0b95c | 2021-04-05 06:24:02 | [diff] [blame] | 65 | if (web_contents_impl->has_persistent_video()) |
[email protected] | d57bc41 | 2017-08-09 20:30:11 | [diff] [blame] | 66 | return 0; |
| 67 | |
[email protected] | e62e7ebf | 2017-09-21 17:14:41 | [diff] [blame] | 68 | // If we require a power-efficient overlay, then approximate that with "is |
| 69 | // fullscreen". The reason is that we want to be somewhat sure that we don't |
| 70 | // have more layers than HWC can support, else SurfaceFlinger will fall back |
| 71 | // to GLES composition. In fullscreen mode, the android status bar is hidden, |
| 72 | // as is the nav bar (if present). The chrome activity surface also gets |
| 73 | // hidden when possible. |
| 74 | if (power_efficient && !web_contents_impl->IsFullscreen()) |
| 75 | return 0; |
| 76 | |
Richard Knoll | ba18275 | 2021-06-01 10:49:55 | [diff] [blame] | 77 | bool observe_container_view = |
| 78 | GetContentClient() |
| 79 | ->browser() |
| 80 | ->ShouldObserveContainerViewLocationForDialogOverlays(); |
| 81 | |
| 82 | return reinterpret_cast<jlong>(new DialogOverlayImpl( |
| 83 | obj, rfhi, web_contents_impl, power_efficient, observe_container_view)); |
liberato | a8da3b5 | 2017-05-02 20:23:51 | [diff] [blame] | 84 | } |
| 85 | |
| 86 | DialogOverlayImpl::DialogOverlayImpl(const JavaParamRef<jobject>& obj, |
Thomas Guilbert | 2d5ef44 | 2017-07-13 00:12:55 | [diff] [blame] | 87 | RenderFrameHostImpl* rfhi, |
[email protected] | e62e7ebf | 2017-09-21 17:14:41 | [diff] [blame] | 88 | WebContents* web_contents, |
Richard Knoll | ba18275 | 2021-06-01 10:49:55 | [diff] [blame] | 89 | bool power_efficient, |
| 90 | bool observe_container_view) |
[email protected] | e62e7ebf | 2017-09-21 17:14:41 | [diff] [blame] | 91 | : WebContentsObserver(web_contents), |
| 92 | rfhi_(rfhi), |
Andrei Pascovici | b478402 | 2018-09-06 14:41:22 | [diff] [blame] | 93 | power_efficient_(power_efficient), |
Richard Knoll | ba18275 | 2021-06-01 10:49:55 | [diff] [blame] | 94 | observed_window_android_(false), |
| 95 | observe_container_view_(observe_container_view) { |
liberato | a8da3b5 | 2017-05-02 20:23:51 | [diff] [blame] | 96 | DCHECK_CURRENTLY_ON(BrowserThread::UI); |
Thomas Guilbert | 2d5ef44 | 2017-07-13 00:12:55 | [diff] [blame] | 97 | DCHECK(rfhi_); |
liberato | a8da3b5 | 2017-05-02 20:23:51 | [diff] [blame] | 98 | |
| 99 | JNIEnv* env = AttachCurrentThread(); |
| 100 | obj_ = JavaObjectWeakGlobalRef(env, obj); |
| 101 | |
Carlos Caballero | daf65cf6d | 2021-03-29 10:30:00 | [diff] [blame] | 102 | // Make sure RenderFrameDeleted will be called on RFH and thus we will clean |
| 103 | // up. |
Nasko Oskov | 2511af42 | 2022-05-25 20:18:45 | [diff] [blame] | 104 | CHECK(rfhi_->IsRenderFrameLive()); |
Jinsuk Kim | d5d29a2 | 2017-08-29 01:39:44 | [diff] [blame] | 105 | web_contents->GetNativeView()->AddObserver(this); |
[email protected] | 251fe52 | 2017-07-11 00:54:06 | [diff] [blame] | 106 | |
| 107 | // Note that we're not allowed to call back into |obj| before it calls |
| 108 | // CompleteInit. However, the observer won't actually call us back until the |
| 109 | // token changes. As long as the java side calls us from the ui thread before |
| 110 | // returning, we won't send a callback before then. |
| 111 | } |
| 112 | |
Andrew Grieve | ab2c915 | 2025-07-02 19:53:13 | [diff] [blame] | 113 | void DialogOverlayImpl::CompleteInit(JNIEnv* env) { |
[email protected] | 251fe52 | 2017-07-11 00:54:06 | [diff] [blame] | 114 | DCHECK_CURRENTLY_ON(BrowserThread::UI); |
Thomas Guilbert | 0267a42c | 2017-08-02 08:08:33 | [diff] [blame] | 115 | |
Thomas Guilbert | 50d8da4 | 2017-08-28 21:34:29 | [diff] [blame] | 116 | WebContentsDelegate* delegate = web_contents()->GetDelegate(); |
| 117 | |
| 118 | if (!delegate) { |
| 119 | Stop(); |
| 120 | return; |
| 121 | } |
| 122 | |
Andrew Grieve | ab2c915 | 2025-07-02 19:53:13 | [diff] [blame] | 123 | ScopedJavaLocalRef<jobject> obj = obj_.get(env); |
| 124 | |
Thomas Guilbert | 0267a42c | 2017-08-02 08:08:33 | [diff] [blame] | 125 | // Note: It's ok to call SetOverlayMode() directly here, because there can be |
| 126 | // at most one overlay alive at the time. This logic needs to be updated if |
| 127 | // ever AndroidOverlayProviderImpl.MAX_OVERLAYS > 1. |
Thomas Guilbert | 50d8da4 | 2017-08-28 21:34:29 | [diff] [blame] | 128 | delegate->SetOverlayMode(true); |
Thomas Guilbert | 0267a42c | 2017-08-02 08:08:33 | [diff] [blame] | 129 | |
Yuchen Liu | 2dce3f9 | 2022-11-22 21:48:20 | [diff] [blame] | 130 | Java_DialogOverlayImpl_onWebContents(env, obj, |
| 131 | web_contents()->GetJavaWebContents()); |
| 132 | |
[email protected] | 251fe52 | 2017-07-11 00:54:06 | [diff] [blame] | 133 | // Send the initial token, if there is one. The observer will notify us about |
| 134 | // changes only. |
Jinsuk Kim | d5d29a2 | 2017-08-29 01:39:44 | [diff] [blame] | 135 | if (auto* window = web_contents()->GetNativeView()->GetWindowAndroid()) { |
Andrei Pascovici | b478402 | 2018-09-06 14:41:22 | [diff] [blame] | 136 | RegisterWindowObserverIfNeeded(window); |
Erin Yan | 7b5ad68 | 2022-07-19 21:17:55 | [diff] [blame] | 137 | Java_DialogOverlayImpl_onWindowAndroid(env, obj, window->GetJavaObject()); |
liberato | a8da3b5 | 2017-05-02 20:23:51 | [diff] [blame] | 138 | } |
Richard Knoll | ba18275 | 2021-06-01 10:49:55 | [diff] [blame] | 139 | |
| 140 | // Pass up a reference to the container view so we can observe its location. |
| 141 | // The observer will notify us if there is none yet. |
| 142 | StartObservingContainerView(); |
liberato | a8da3b5 | 2017-05-02 20:23:51 | [diff] [blame] | 143 | } |
| 144 | |
| 145 | DialogOverlayImpl::~DialogOverlayImpl() { |
| 146 | DCHECK_CURRENTLY_ON(BrowserThread::UI); |
liberato | a8da3b5 | 2017-05-02 20:23:51 | [diff] [blame] | 147 | } |
| 148 | |
Thomas Guilbert | 2d5ef44 | 2017-07-13 00:12:55 | [diff] [blame] | 149 | void DialogOverlayImpl::Stop() { |
Andrei Pascovici | b478402 | 2018-09-06 14:41:22 | [diff] [blame] | 150 | UnregisterCallbacksIfNeeded(); |
Thomas Guilbert | 2d5ef44 | 2017-07-13 00:12:55 | [diff] [blame] | 151 | |
| 152 | JNIEnv* env = AttachCurrentThread(); |
| 153 | ScopedJavaLocalRef<jobject> obj = obj_.get(env); |
| 154 | if (!obj.is_null()) |
Torne (Richard Coles) | 6a1426cb | 2017-07-28 15:53:36 | [diff] [blame] | 155 | Java_DialogOverlayImpl_onDismissed(env, obj); |
Thomas Guilbert | 2d5ef44 | 2017-07-13 00:12:55 | [diff] [blame] | 156 | |
| 157 | obj_.reset(); |
| 158 | } |
| 159 | |
Andrew Grieve | ab2c915 | 2025-07-02 19:53:13 | [diff] [blame] | 160 | void DialogOverlayImpl::Destroy(JNIEnv* env) { |
liberato | a8da3b5 | 2017-05-02 20:23:51 | [diff] [blame] | 161 | DCHECK_CURRENTLY_ON(BrowserThread::UI); |
Andrei Pascovici | b478402 | 2018-09-06 14:41:22 | [diff] [blame] | 162 | UnregisterCallbacksIfNeeded(); |
liberato | a8da3b5 | 2017-05-02 20:23:51 | [diff] [blame] | 163 | // We delete soon since this might be part of an onDismissed callback. |
Gabriel Charette | e7cdc5cd | 2020-05-27 23:35:05 | [diff] [blame] | 164 | GetUIThreadTaskRunner({})->DeleteSoon(FROM_HERE, this); |
liberato | a8da3b5 | 2017-05-02 20:23:51 | [diff] [blame] | 165 | } |
| 166 | |
[email protected] | d6c1792 | 2017-06-26 18:48:06 | [diff] [blame] | 167 | void DialogOverlayImpl::GetCompositorOffset( |
| 168 | JNIEnv* env, |
[email protected] | d6c1792 | 2017-06-26 18:48:06 | [diff] [blame] | 169 | const base::android::JavaParamRef<jobject>& rect) { |
Jinsuk Kim | d5d29a2 | 2017-08-29 01:39:44 | [diff] [blame] | 170 | gfx::Point point = |
[email protected] | a11aa72 | 2017-08-30 21:07:43 | [diff] [blame] | 171 | web_contents()->GetNativeView()->GetLocationOfContainerViewInWindow(); |
[email protected] | d6c1792 | 2017-06-26 18:48:06 | [diff] [blame] | 172 | |
Torne (Richard Coles) | 6a1426cb | 2017-07-28 15:53:36 | [diff] [blame] | 173 | Java_DialogOverlayImpl_receiveCompositorOffset(env, rect, point.x(), |
[email protected] | 251fe52 | 2017-07-11 00:54:06 | [diff] [blame] | 174 | point.y()); |
[email protected] | d6c1792 | 2017-06-26 18:48:06 | [diff] [blame] | 175 | } |
| 176 | |
Andrei Pascovici | b478402 | 2018-09-06 14:41:22 | [diff] [blame] | 177 | void DialogOverlayImpl::UnregisterCallbacksIfNeeded() { |
liberato | a8da3b5 | 2017-05-02 20:23:51 | [diff] [blame] | 178 | DCHECK_CURRENTLY_ON(BrowserThread::UI); |
Jinsuk Kim | d5d29a2 | 2017-08-29 01:39:44 | [diff] [blame] | 179 | |
| 180 | if (!rfhi_) |
liberato | a8da3b5 | 2017-05-02 20:23:51 | [diff] [blame] | 181 | return; |
| 182 | |
Richard Knoll | ba18275 | 2021-06-01 10:49:55 | [diff] [blame] | 183 | // No need to track the container view location anymore. |
| 184 | StopObservingContainerView(); |
| 185 | |
Thomas Guilbert | 0267a42c | 2017-08-02 08:08:33 | [diff] [blame] | 186 | // We clear overlay mode here rather than in Destroy(), because we may have |
| 187 | // been called via a WebContentsDestroyed() event, and this might be the last |
| 188 | // opportunity we have to access web_contents(). |
Thomas Guilbert | 50d8da4 | 2017-08-28 21:34:29 | [diff] [blame] | 189 | WebContentsDelegate* delegate = web_contents()->GetDelegate(); |
| 190 | if (delegate) |
| 191 | delegate->SetOverlayMode(false); |
Andrei Pascovici | b478402 | 2018-09-06 14:41:22 | [diff] [blame] | 192 | if (observed_window_android_) { |
| 193 | auto* window_android = web_contents()->GetNativeView()->GetWindowAndroid(); |
| 194 | if (window_android) |
| 195 | window_android->RemoveObserver(this); |
| 196 | observed_window_android_ = false; |
| 197 | } |
Jinsuk Kim | d5d29a2 | 2017-08-29 01:39:44 | [diff] [blame] | 198 | web_contents()->GetNativeView()->RemoveObserver(this); |
Thomas Guilbert | 2d5ef44 | 2017-07-13 00:12:55 | [diff] [blame] | 199 | rfhi_ = nullptr; |
liberato | a8da3b5 | 2017-05-02 20:23:51 | [diff] [blame] | 200 | } |
| 201 | |
Thomas Guilbert | 2d5ef44 | 2017-07-13 00:12:55 | [diff] [blame] | 202 | void DialogOverlayImpl::RenderFrameDeleted(RenderFrameHost* render_frame_host) { |
| 203 | DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 204 | if (render_frame_host == rfhi_) |
| 205 | Stop(); |
| 206 | } |
| 207 | |
| 208 | void DialogOverlayImpl::RenderFrameHostChanged(RenderFrameHost* old_host, |
| 209 | RenderFrameHost* new_host) { |
| 210 | DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 211 | if (old_host == rfhi_) |
| 212 | Stop(); |
| 213 | } |
| 214 | |
Francois Doray | fe4a177 | 2018-02-17 04:17:09 | [diff] [blame] | 215 | void DialogOverlayImpl::OnVisibilityChanged(content::Visibility visibility) { |
Thomas Guilbert | 2d5ef44 | 2017-07-13 00:12:55 | [diff] [blame] | 216 | DCHECK_CURRENTLY_ON(BrowserThread::UI); |
Francois Doray | fe4a177 | 2018-02-17 04:17:09 | [diff] [blame] | 217 | if (visibility == content::Visibility::HIDDEN) |
| 218 | Stop(); |
Thomas Guilbert | 2d5ef44 | 2017-07-13 00:12:55 | [diff] [blame] | 219 | } |
| 220 | |
Andrei Pascovici | b478402 | 2018-09-06 14:41:22 | [diff] [blame] | 221 | void DialogOverlayImpl::OnRootWindowVisibilityChanged(bool visible) { |
| 222 | if (!visible) |
| 223 | Stop(); |
| 224 | } |
| 225 | |
Thomas Guilbert | 2d5ef44 | 2017-07-13 00:12:55 | [diff] [blame] | 226 | void DialogOverlayImpl::WebContentsDestroyed() { |
| 227 | DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 228 | Stop(); |
liberato | a8da3b5 | 2017-05-02 20:23:51 | [diff] [blame] | 229 | } |
| 230 | |
Muyao Xu | db226be5 | 2023-12-01 04:23:09 | [diff] [blame] | 231 | void DialogOverlayImpl::DidToggleFullscreenModeForTab(bool entered_fullscreen, |
| 232 | bool will_cause_resize) { |
[email protected] | e62e7ebf | 2017-09-21 17:14:41 | [diff] [blame] | 233 | DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 234 | |
| 235 | // If the caller doesn't care about power-efficient overlays, then don't send |
| 236 | // any callbacks about state change. |
| 237 | if (!power_efficient_) |
| 238 | return; |
| 239 | |
| 240 | JNIEnv* env = AttachCurrentThread(); |
| 241 | ScopedJavaLocalRef<jobject> obj = obj_.get(env); |
| 242 | if (!obj.is_null()) |
| 243 | Java_DialogOverlayImpl_onPowerEfficientState(env, obj, entered_fullscreen); |
| 244 | } |
| 245 | |
liberato | a8da3b5 | 2017-05-02 20:23:51 | [diff] [blame] | 246 | void DialogOverlayImpl::OnAttachedToWindow() { |
| 247 | DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 248 | JNIEnv* env = AttachCurrentThread(); |
| 249 | |
Erin Yan | 7b5ad68 | 2022-07-19 21:17:55 | [diff] [blame] | 250 | auto* window = web_contents()->GetNativeView()->GetWindowAndroid(); |
| 251 | if (window) |
Andrei Pascovici | b478402 | 2018-09-06 14:41:22 | [diff] [blame] | 252 | RegisterWindowObserverIfNeeded(window); |
Erin Yan | 7b5ad68 | 2022-07-19 21:17:55 | [diff] [blame] | 253 | |
liberato | a8da3b5 | 2017-05-02 20:23:51 | [diff] [blame] | 254 | ScopedJavaLocalRef<jobject> obj = obj_.get(env); |
| 255 | if (!obj.is_null()) |
Erin Yan | 7b5ad68 | 2022-07-19 21:17:55 | [diff] [blame] | 256 | Java_DialogOverlayImpl_onWindowAndroid(env, obj, window->GetJavaObject()); |
Richard Knoll | ba18275 | 2021-06-01 10:49:55 | [diff] [blame] | 257 | |
| 258 | StartObservingContainerView(); |
liberato | a8da3b5 | 2017-05-02 20:23:51 | [diff] [blame] | 259 | } |
| 260 | |
| 261 | void DialogOverlayImpl::OnDetachedFromWindow() { |
| 262 | JNIEnv* env = AttachCurrentThread(); |
| 263 | ScopedJavaLocalRef<jobject> obj = obj_.get(env); |
| 264 | if (!obj.is_null()) |
Erin Yan | 7b5ad68 | 2022-07-19 21:17:55 | [diff] [blame] | 265 | Java_DialogOverlayImpl_onWindowAndroid(env, obj, nullptr); |
Andrei Pascovici | 17d5845e | 2018-09-20 22:09:07 | [diff] [blame] | 266 | Stop(); |
liberato | a8da3b5 | 2017-05-02 20:23:51 | [diff] [blame] | 267 | } |
| 268 | |
Andrei Pascovici | b478402 | 2018-09-06 14:41:22 | [diff] [blame] | 269 | void DialogOverlayImpl::RegisterWindowObserverIfNeeded( |
| 270 | ui::WindowAndroid* window) { |
| 271 | if (!observed_window_android_) { |
| 272 | observed_window_android_ = true; |
| 273 | window->AddObserver(this); |
| 274 | } |
| 275 | } |
| 276 | |
Richard Knoll | ba18275 | 2021-06-01 10:49:55 | [diff] [blame] | 277 | void DialogOverlayImpl::StartObservingContainerView() { |
| 278 | ObserveContainerViewIfNeeded( |
| 279 | web_contents()->GetNativeView()->GetContainerView()); |
| 280 | } |
| 281 | |
| 282 | void DialogOverlayImpl::StopObservingContainerView() { |
| 283 | ObserveContainerViewIfNeeded(/*container_view=*/nullptr); |
| 284 | } |
| 285 | |
| 286 | void DialogOverlayImpl::ObserveContainerViewIfNeeded( |
| 287 | const ScopedJavaLocalRef<jobject>& container_view) { |
| 288 | if (!observe_container_view_) |
| 289 | return; |
| 290 | |
| 291 | JNIEnv* env = AttachCurrentThread(); |
| 292 | ScopedJavaLocalRef<jobject> obj = obj_.get(env); |
| 293 | if (!obj.is_null()) |
| 294 | Java_DialogOverlayImpl_observeContainerView(env, obj, container_view); |
| 295 | } |
| 296 | |
Frank Liberato | 13bde9e | 2021-02-28 20:46:00 | [diff] [blame] | 297 | // Helper class that has permission to talk to SyncCallRestrictions. Rather |
| 298 | // than friend the function directly, which has an odd signature, friend a class |
| 299 | // that knows how to do the work. |
| 300 | class AndroidOverlaySyncHelper { |
| 301 | public: |
| 302 | static void MakeSyncCall(media::mojom::AndroidOverlayClient* remote) { |
| 303 | mojo::SyncCallRestrictions::ScopedAllowSyncCall scoped_allow; |
| 304 | remote->OnSynchronouslyDestroyed(); |
| 305 | } |
| 306 | }; |
| 307 | |
Frank Liberato | d66bd924 | 2020-11-20 21:05:46 | [diff] [blame] | 308 | static void JNI_DialogOverlayImpl_NotifyDestroyedSynchronously( |
| 309 | JNIEnv* env, |
Ken Rockot | 8e8c8c8 | 2022-03-04 18:21:38 | [diff] [blame] | 310 | jlong message_pipe_handle) { |
Frank Liberato | d66bd924 | 2020-11-20 21:05:46 | [diff] [blame] | 311 | mojo::MessagePipeHandle handle(message_pipe_handle); |
Frank Liberato | 46246e0 | 2020-12-08 22:46:48 | [diff] [blame] | 312 | mojo::ScopedMessagePipeHandle scoped_handle(handle); |
Frank Liberato | d66bd924 | 2020-11-20 21:05:46 | [diff] [blame] | 313 | mojo::Remote<media::mojom::AndroidOverlayClient> remote( |
| 314 | mojo::PendingRemote<media::mojom::AndroidOverlayClient>( |
| 315 | std::move(scoped_handle), |
| 316 | media::mojom::AndroidOverlayClient::Version_)); |
Frank Liberato | 13bde9e | 2021-02-28 20:46:00 | [diff] [blame] | 317 | // This prevents crashes, though it's unclear how we'd have a null remote. |
| 318 | // https://crbug.com/1155313 . |
Frank Liberato | 72a96aa | 2020-12-15 18:49:45 | [diff] [blame] | 319 | if (!remote.is_bound()) |
| 320 | return; |
Frank Liberato | 13bde9e | 2021-02-28 20:46:00 | [diff] [blame] | 321 | AndroidOverlaySyncHelper::MakeSyncCall(remote.get()); |
Frank Liberato | d66bd924 | 2020-11-20 21:05:46 | [diff] [blame] | 322 | // Note that we don't take back the mojo message pipe. We let it close when |
| 323 | // `remote` goes out of scope. |
| 324 | } |
| 325 | |
Daniel Bratell | 7aacf95 | 2017-11-21 17:51:25 | [diff] [blame] | 326 | static jint JNI_DialogOverlayImpl_RegisterSurface( |
| 327 | JNIEnv* env, |
Daniel Bratell | 7aacf95 | 2017-11-21 17:51:25 | [diff] [blame] | 328 | const JavaParamRef<jobject>& surface) { |
liberato | a8da3b5 | 2017-05-02 20:23:51 | [diff] [blame] | 329 | DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 330 | return gpu::GpuSurfaceTracker::Get()->AddSurfaceForNativeWidget( |
Kartar Singh | 169f1757 | 2024-09-18 13:01:59 | [diff] [blame] | 331 | gpu::SurfaceRecord(gl::ScopedJavaSurface(surface, /*auto_release=*/false), |
| 332 | /*can_be_used_with_surface_control=*/false)); |
liberato | a8da3b5 | 2017-05-02 20:23:51 | [diff] [blame] | 333 | } |
| 334 | |
Daniel Bratell | 7aacf95 | 2017-11-21 17:51:25 | [diff] [blame] | 335 | static void JNI_DialogOverlayImpl_UnregisterSurface( |
liberato | a8da3b5 | 2017-05-02 20:23:51 | [diff] [blame] | 336 | JNIEnv* env, |
liberato | a8da3b5 | 2017-05-02 20:23:51 | [diff] [blame] | 337 | jint surface_id) { |
| 338 | DCHECK_CURRENTLY_ON(BrowserThread::UI); |
| 339 | gpu::GpuSurfaceTracker::Get()->RemoveSurface(surface_id); |
| 340 | } |
| 341 | |
Daniel Bratell | 7aacf95 | 2017-11-21 17:51:25 | [diff] [blame] | 342 | static ScopedJavaLocalRef<jobject> |
| 343 | JNI_DialogOverlayImpl_LookupSurfaceForTesting( |
[email protected] | 251fe52 | 2017-07-11 00:54:06 | [diff] [blame] | 344 | JNIEnv* env, |
[email protected] | 251fe52 | 2017-07-11 00:54:06 | [diff] [blame] | 345 | jint surfaceId) { |
Kartar Singh | 169f1757 | 2024-09-18 13:01:59 | [diff] [blame] | 346 | auto surface_record = |
| 347 | gpu::GpuSurfaceTracker::Get()->AcquireJavaSurface(surfaceId); |
Victor Hugo Vianna Silva | 94fdad2 | 2025-03-18 19:51:13 | [diff] [blame] | 348 | if (!std::holds_alternative<gl::ScopedJavaSurface>( |
Kartar Singh | 169f1757 | 2024-09-18 13:01:59 | [diff] [blame] | 349 | surface_record.surface_variant)) { |
Bo Liu | 30286a8 | 2022-12-16 22:13:38 | [diff] [blame] | 350 | return nullptr; |
| 351 | } |
| 352 | return ScopedJavaLocalRef<jobject>( |
Victor Hugo Vianna Silva | 94fdad2 | 2025-03-18 19:51:13 | [diff] [blame] | 353 | std::get<gl::ScopedJavaSurface>(surface_record.surface_variant) |
Kartar Singh | 169f1757 | 2024-09-18 13:01:59 | [diff] [blame] | 354 | .j_surface()); |
[email protected] | 251fe52 | 2017-07-11 00:54:06 | [diff] [blame] | 355 | } |
| 356 | |
liberato | a8da3b5 | 2017-05-02 20:23:51 | [diff] [blame] | 357 | } // namespace content |