diff --git a/java/org/cef/CefClient.java b/java/org/cef/CefClient.java index 7bc56cf0..af7d39e2 100644 --- a/java/org/cef/CefClient.java +++ b/java/org/cef/CefClient.java @@ -14,7 +14,9 @@ import org.cef.callback.CefDragData; import org.cef.callback.CefFileDialogCallback; import org.cef.callback.CefJSDialogCallback; +import org.cef.callback.CefMediaAccessCallback; import org.cef.callback.CefMenuModel; +import org.cef.callback.CefPermissionPromptCallback; import org.cef.callback.CefPrintDialogCallback; import org.cef.callback.CefPrintJobCallback; import org.cef.handler.CefClientHandler; @@ -30,6 +32,7 @@ import org.cef.handler.CefKeyboardHandler; import org.cef.handler.CefLifeSpanHandler; import org.cef.handler.CefLoadHandler; +import org.cef.handler.CefPermissionHandler; import org.cef.handler.CefPrintHandler; import org.cef.handler.CefRenderHandler; import org.cef.handler.CefRequestHandler; @@ -70,7 +73,8 @@ public class CefClient extends CefClientHandler implements CefContextMenuHandler, CefDialogHandler, CefDisplayHandler, CefDownloadHandler, CefDragHandler, CefFindHandler, CefFocusHandler, CefFrameHandler, CefJSDialogHandler, CefKeyboardHandler, CefLifeSpanHandler, CefLoadHandler, - CefPrintHandler, CefRenderHandler, CefRequestHandler, CefWindowHandler { + CefPermissionHandler, CefPrintHandler, CefRenderHandler, CefRequestHandler, + CefWindowHandler { private HashMap browser_ = new HashMap(); private CefContextMenuHandler contextMenuHandler_ = null; private CefDialogHandler dialogHandler_ = null; @@ -84,6 +88,7 @@ public class CefClient extends CefClientHandler private CefKeyboardHandler keyboardHandler_ = null; private CefLifeSpanHandler lifeSpanHandler_ = null; private CefLoadHandler loadHandler_ = null; + private CefPermissionHandler permissionHandler_ = null; private CefPrintHandler printHandler_ = null; private CefRequestHandler requestHandler_ = null; private boolean isDisposed_ = false; @@ -239,6 +244,11 @@ protected CefLoadHandler getLoadHandler() { return this; } + @Override + protected CefPermissionHandler getPermissionHandler() { + return this; + } + @Override protected CefPrintHandler getPrintHandler() { return this; @@ -718,6 +728,7 @@ private void cleanupBrowser(int identifier) { removeKeyboardHandler(this); removeLifeSpanHandler(this); removeLoadHandler(this); + removePermissionHandler(this); removePrintHandler(this); removeRenderHandler(this); removeRequestHandler(this); @@ -766,6 +777,43 @@ public void onLoadError(CefBrowser browser, CefFrame frame, ErrorCode errorCode, loadHandler_.onLoadError(browser, frame, errorCode, errorText, failedUrl); } + // CefPermissionHandler + + public CefClient addPermissionHandler(CefPermissionHandler handler) { + if (permissionHandler_ == null) permissionHandler_ = handler; + return this; + } + + public void removePermissionHandler() { + permissionHandler_ = null; + } + + @Override + public boolean onRequestMediaAccessPermission(CefBrowser browser, CefFrame frame, + String requestingOrigin, int requestedPermissions, + CefMediaAccessCallback callback) { + if (permissionHandler_ != null && browser != null) + return permissionHandler_.onRequestMediaAccessPermission( + browser, frame, requestingOrigin, requestedPermissions, callback); + return false; + } + + @Override + public boolean onShowPermissionPrompt(CefBrowser browser, long promptId, + String requestingOrigin, int requestedPermissions, + CefPermissionPromptCallback callback) { + if (permissionHandler_ != null && browser != null) + return permissionHandler_.onShowPermissionPrompt( + browser, promptId, requestingOrigin, requestedPermissions, callback); + return false; + } + + @Override + public void onDismissPermissionPrompt(CefBrowser browser, long promptId, int result) { + if (permissionHandler_ != null && browser != null) + permissionHandler_.onDismissPermissionPrompt(browser, promptId, result); + } + // CefPrintHandler public CefClient addPrintHandler(CefPrintHandler handler) { diff --git a/java/org/cef/callback/CefMediaAccessCallback.java b/java/org/cef/callback/CefMediaAccessCallback.java new file mode 100644 index 00000000..b4437e2b --- /dev/null +++ b/java/org/cef/callback/CefMediaAccessCallback.java @@ -0,0 +1,28 @@ +// Copyright (c) 2026 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. + +package org.cef.callback; + +/** + * Callback interface used for asynchronous continuation of media access + * permission requests. + */ +public interface CefMediaAccessCallback { + /** + * Call to allow or deny media access. If this callback was initiated in + * response to a getUserMedia request then allowedPermissions must match + * the requestedPermissions passed to + * CefPermissionHandler.onRequestMediaAccessPermission. See + * CefPermissionHandler.MediaAccessPermissionType for the supported bit + * flags. + * + * @param allowedPermissions the permissions to allow. + */ + public void Continue(int allowedPermissions); + + /** + * Cancel the media access request. + */ + public void Cancel(); +} diff --git a/java/org/cef/callback/CefMediaAccessCallback_N.java b/java/org/cef/callback/CefMediaAccessCallback_N.java new file mode 100644 index 00000000..72fbe139 --- /dev/null +++ b/java/org/cef/callback/CefMediaAccessCallback_N.java @@ -0,0 +1,36 @@ +// Copyright (c) 2026 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. + +package org.cef.callback; + +class CefMediaAccessCallback_N extends CefNativeAdapter implements CefMediaAccessCallback { + CefMediaAccessCallback_N() {} + + @Override + protected void finalize() throws Throwable { + Cancel(); + super.finalize(); + } + + @Override + public void Continue(int allowedPermissions) { + try { + N_Continue(getNativeRef(null), allowedPermissions); + } catch (UnsatisfiedLinkError ule) { + ule.printStackTrace(); + } + } + + @Override + public void Cancel() { + try { + N_Cancel(getNativeRef(null)); + } catch (UnsatisfiedLinkError ule) { + ule.printStackTrace(); + } + } + + private final native void N_Continue(long self, int allowedPermissions); + private final native void N_Cancel(long self); +} diff --git a/java/org/cef/callback/CefPermissionPromptCallback.java b/java/org/cef/callback/CefPermissionPromptCallback.java new file mode 100644 index 00000000..1b45f6c8 --- /dev/null +++ b/java/org/cef/callback/CefPermissionPromptCallback.java @@ -0,0 +1,20 @@ +// Copyright (c) 2026 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. + +package org.cef.callback; + +/** + * Callback interface used for asynchronous continuation of permission + * prompts. + */ +public interface CefPermissionPromptCallback { + /** + * Complete the permissions request with the specified result. See + * CefPermissionHandler.PermissionRequestResult for the supported + * values. + * + * @param result the result to complete the request with. + */ + public void Continue(int result); +} diff --git a/java/org/cef/callback/CefPermissionPromptCallback_N.java b/java/org/cef/callback/CefPermissionPromptCallback_N.java new file mode 100644 index 00000000..5ac6ec15 --- /dev/null +++ b/java/org/cef/callback/CefPermissionPromptCallback_N.java @@ -0,0 +1,29 @@ +// Copyright (c) 2026 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. + +package org.cef.callback; + +import org.cef.handler.CefPermissionHandler; + +class CefPermissionPromptCallback_N + extends CefNativeAdapter implements CefPermissionPromptCallback { + CefPermissionPromptCallback_N() {} + + @Override + protected void finalize() throws Throwable { + Continue(CefPermissionHandler.PermissionRequestResult.IGNORE); + super.finalize(); + } + + @Override + public void Continue(int result) { + try { + N_Continue(getNativeRef(null), result); + } catch (UnsatisfiedLinkError ule) { + ule.printStackTrace(); + } + } + + private final native void N_Continue(long self, int result); +} diff --git a/java/org/cef/handler/CefClientHandler.java b/java/org/cef/handler/CefClientHandler.java index 1057cd1a..ac223501 100644 --- a/java/org/cef/handler/CefClientHandler.java +++ b/java/org/cef/handler/CefClientHandler.java @@ -179,6 +179,13 @@ protected void dispose() { */ abstract protected CefLoadHandler getLoadHandler(); + /** + * Return the handler for permission requests. + * This method is a callback method and is called by + * the native code. + */ + abstract protected CefPermissionHandler getPermissionHandler(); + /** * Return the handler for printing on Linux. If a print handler is not * provided then printing will not be supported on the Linux platform. @@ -313,6 +320,14 @@ protected void removeLoadHandler(CefLoadHandler h) { } } + protected void removePermissionHandler(CefPermissionHandler h) { + try { + N_removePermissionHandler(h); + } catch (UnsatisfiedLinkError err) { + err.printStackTrace(); + } + } + protected void removePrintHandler(CefPrintHandler h) { try { N_removePrintHandler(h); @@ -368,6 +383,7 @@ protected void removeWindowHandler(CefWindowHandler h) { private final native void N_removeKeyboardHandler(CefKeyboardHandler h); private final native void N_removeLifeSpanHandler(CefLifeSpanHandler h); private final native void N_removeLoadHandler(CefLoadHandler h); + private final native void N_removePermissionHandler(CefPermissionHandler h); private final native void N_removePrintHandler(CefPrintHandler h); private final native void N_removeMessageRouter(CefMessageRouter h); private final native void N_removeRenderHandler(CefRenderHandler h); diff --git a/java/org/cef/handler/CefPermissionHandler.java b/java/org/cef/handler/CefPermissionHandler.java new file mode 100644 index 00000000..b1da87e0 --- /dev/null +++ b/java/org/cef/handler/CefPermissionHandler.java @@ -0,0 +1,89 @@ +// Copyright (c) 2026 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. + +package org.cef.handler; + +import org.cef.browser.CefBrowser; +import org.cef.browser.CefFrame; +import org.cef.callback.CefMediaAccessCallback; +import org.cef.callback.CefPermissionPromptCallback; + +/** + * Implement this interface to handle events related to permission requests. + * The methods of this class will be called on the browser process UI thread. + */ +public interface CefPermissionHandler { + /** + * Media access permissions used by onRequestMediaAccessPermission. + */ + public static final class MediaAccessPermissionType { + public final static int PERMISSION_NONE = 0; + public final static int PERMISSION_DEVICE_AUDIO_CAPTURE = 1 << 0; + public final static int PERMISSION_DEVICE_VIDEO_CAPTURE = 1 << 1; + public final static int PERMISSION_DESKTOP_AUDIO_CAPTURE = 1 << 2; + public final static int PERMISSION_DESKTOP_VIDEO_CAPTURE = 1 << 3; + } + + /** + * Permission request results used by onDismissPermissionPrompt and + * CefPermissionPromptCallback.Continue. + */ + public static final class PermissionRequestResult { + /** Accept the permission request as an explicit user action. */ + public final static int ACCEPT = 0; + /** Deny the permission request as an explicit user action. */ + public final static int DENY = 1; + /** Dismiss the permission request as an explicit user action. */ + public final static int DISMISS = 2; + /** Ignore the permission request. */ + public final static int IGNORE = 3; + } + + /** + * Called when a page requests permission to access media. + * + * @param browser The corresponding browser. + * @param frame The corresponding frame. + * @param requestingOrigin the URL origin requesting permission. + * @param requestedPermissions a combination of values from + * MediaAccessPermissionType that represent the requested permissions. + * @param callback execute callback methods either in this method or at + * a later time to continue or cancel the request. + * @return true to handle the request, or false to proceed with default + * handling (deny the request). + */ + public boolean onRequestMediaAccessPermission(CefBrowser browser, CefFrame frame, + String requestingOrigin, int requestedPermissions, + CefMediaAccessCallback callback); + + /** + * Called when a page should show a permission prompt. + * + * @param browser The corresponding browser. + * @param promptId uniquely identifies the prompt. + * @param requestingOrigin the URL origin requesting permission. + * @param requestedPermissions a combination of CEF_PERMISSION_TYPE_* + * values (see cef_permission_request_types_t in CEF's cef_types.h) that + * represent the requested permissions. + * @param callback call Continue either in this method or at a later + * time to continue or cancel the request. + * @return true to handle the request, or false to proceed with default + * handling (CEF_PERMISSION_RESULT_IGNORE with Alloy style). + */ + public boolean onShowPermissionPrompt(CefBrowser browser, long promptId, + String requestingOrigin, int requestedPermissions, + CefPermissionPromptCallback callback); + + /** + * Called when a permission prompt handled via onShowPermissionPrompt is + * dismissed. promptId will match the value that was passed to + * onShowPermissionPrompt. This method will not be called if + * onShowPermissionPrompt returned false for promptId. + * + * @param browser The corresponding browser. + * @param promptId uniquely identifies the prompt. + * @param result one of the PermissionRequestResult values. + */ + public void onDismissPermissionPrompt(CefBrowser browser, long promptId, int result); +} diff --git a/java/org/cef/handler/CefPermissionHandlerAdapter.java b/java/org/cef/handler/CefPermissionHandlerAdapter.java new file mode 100644 index 00000000..8bc5e6b5 --- /dev/null +++ b/java/org/cef/handler/CefPermissionHandlerAdapter.java @@ -0,0 +1,34 @@ +// Copyright (c) 2026 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. + +package org.cef.handler; + +import org.cef.browser.CefBrowser; +import org.cef.browser.CefFrame; +import org.cef.callback.CefMediaAccessCallback; +import org.cef.callback.CefPermissionPromptCallback; + +/** + * An abstract adapter class for receiving permission events. + * The methods in this class are empty. + * This class exists as convenience for creating handler objects. + */ +public abstract class CefPermissionHandlerAdapter implements CefPermissionHandler { + @Override + public boolean onRequestMediaAccessPermission(CefBrowser browser, CefFrame frame, + String requestingOrigin, int requestedPermissions, + CefMediaAccessCallback callback) { + return false; + } + + @Override + public boolean onShowPermissionPrompt(CefBrowser browser, long promptId, + String requestingOrigin, int requestedPermissions, + CefPermissionPromptCallback callback) { + return false; + } + + @Override + public void onDismissPermissionPrompt(CefBrowser browser, long promptId, int result) {} +} diff --git a/java/tests/junittests/CefClientTest.java b/java/tests/junittests/CefClientTest.java index 342c45b3..d9ea4db7 100644 --- a/java/tests/junittests/CefClientTest.java +++ b/java/tests/junittests/CefClientTest.java @@ -79,6 +79,9 @@ void addAndRemoveEveryHandlerType() { client.addLoadHandler(new CefLoadHandlerAdapter() {}); client.removeLoadHandler(); + client.addPermissionHandler(new org.cef.handler.CefPermissionHandlerAdapter() {}); + client.removePermissionHandler(); + client.addPrintHandler(new CefPrintHandlerAdapter() {}); client.removePrintHandler(); diff --git a/native/CMakeLists.txt b/native/CMakeLists.txt index 6054c8ed..c8c4bb2b 100644 --- a/native/CMakeLists.txt +++ b/native/CMakeLists.txt @@ -39,10 +39,14 @@ set(JCEF_SRCS CefTestHelper.cpp CefJSDialogCallback_N.h CefJSDialogCallback_N.cpp + CefMediaAccessCallback_N.cpp + CefMediaAccessCallback_N.h CefMenuModel_N.cpp CefMenuModel_N.h CefMessageRouter_N.cpp CefMessageRouter_N.h + CefPermissionPromptCallback_N.cpp + CefPermissionPromptCallback_N.h CefPostData_N.cpp CefPostData_N.h CefPostDataElement_N.cpp @@ -125,6 +129,8 @@ set(JCEF_SRCS message_router_handler.h pdf_print_callback.cpp pdf_print_callback.h + permission_handler.cpp + permission_handler.h print_handler.cpp print_handler.h render_handler.cpp diff --git a/native/CefClientHandler.cpp b/native/CefClientHandler.cpp index 2c56f483..4cc49dac 100644 --- a/native/CefClientHandler.cpp +++ b/native/CefClientHandler.cpp @@ -18,6 +18,7 @@ #include "life_span_handler.h" #include "load_handler.h" #include "message_router_handler.h" +#include "permission_handler.h" #include "print_handler.h" #include "render_handler.h" #include "request_handler.h" @@ -161,6 +162,15 @@ Java_org_cef_handler_CefClientHandler_N_1removeLoadHandler( "CefLoadHandler"); } +JNIEXPORT void JNICALL +Java_org_cef_handler_CefClientHandler_N_1removePermissionHandler( + JNIEnv* env, + jobject clientHandler, + jobject permissionHandler) { + SetCefForJNIObject_sync(env, permissionHandler, nullptr, + "CefPermissionHandler"); +} + JNIEXPORT void JNICALL Java_org_cef_handler_CefClientHandler_N_1removePrintHandler( JNIEnv* env, diff --git a/native/CefClientHandler.h b/native/CefClientHandler.h index 9b21fd2d..7cdb68f4 100644 --- a/native/CefClientHandler.h +++ b/native/CefClientHandler.h @@ -146,6 +146,16 @@ Java_org_cef_handler_CefClientHandler_N_1removeLoadHandler(JNIEnv*, jobject, jobject); +/* + * Class: org_cef_handler_CefClientHandler + * Method: N_removePermissionHandler + * Signature: (Lorg/cef/handler/CefPermissionHandler;)V + */ +JNIEXPORT void JNICALL +Java_org_cef_handler_CefClientHandler_N_1removePermissionHandler(JNIEnv*, + jobject, + jobject); + /* * Class: org_cef_handler_CefClientHandler * Method: N_removePrintHandler diff --git a/native/CefMediaAccessCallback_N.cpp b/native/CefMediaAccessCallback_N.cpp new file mode 100644 index 00000000..363f42de --- /dev/null +++ b/native/CefMediaAccessCallback_N.cpp @@ -0,0 +1,52 @@ +// Copyright (c) 2026 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. + +#include "CefMediaAccessCallback_N.h" +#include "include/cef_permission_handler.h" +#include "jni_scoped_helpers.h" +#include "jni_util.h" + +namespace { + +CefRefPtr GetSelf(jlong self) { + return reinterpret_cast(self); +} + +void ClearSelf(JNIEnv* env, jobject obj) { + // Clear the reference added in PermissionHandler::OnRequestMediaAccessPermission. + SetCefForJNIObject_sync(env, obj, nullptr, + "CefMediaAccessCallback"); +} + +} // namespace + +JNIEXPORT void JNICALL +Java_org_cef_callback_CefMediaAccessCallback_1N_N_1Continue( + JNIEnv* env, + jobject obj, + jlong self, + jint jallowedPermissions) { + // See jni_util.h's JNI_REQUIRE_CEF_ALIVE_OR_RETURN comment -- reachable + // from CefMediaAccessCallback_N.java's finalize(). + JNI_REQUIRE_CEF_ALIVE_OR_RETURN(); + CefRefPtr callback = GetSelf(self); + if (!callback) + return; + callback->Continue(static_cast(jallowedPermissions)); + ClearSelf(env, obj); +} + +JNIEXPORT void JNICALL +Java_org_cef_callback_CefMediaAccessCallback_1N_N_1Cancel(JNIEnv* env, + jobject obj, + jlong self) { + // See jni_util.h's JNI_REQUIRE_CEF_ALIVE_OR_RETURN comment -- reachable + // from CefMediaAccessCallback_N.java's finalize(). + JNI_REQUIRE_CEF_ALIVE_OR_RETURN(); + CefRefPtr callback = GetSelf(self); + if (!callback) + return; + callback->Cancel(); + ClearSelf(env, obj); +} diff --git a/native/CefMediaAccessCallback_N.h b/native/CefMediaAccessCallback_N.h new file mode 100644 index 00000000..9e5291c9 --- /dev/null +++ b/native/CefMediaAccessCallback_N.h @@ -0,0 +1,34 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class org_cef_callback_CefMediaAccessCallback_N */ + +#ifndef _Included_org_cef_callback_CefMediaAccessCallback_N +#define _Included_org_cef_callback_CefMediaAccessCallback_N +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: org_cef_callback_CefMediaAccessCallback_N + * Method: N_Continue + * Signature: (JI)V + */ +JNIEXPORT void JNICALL +Java_org_cef_callback_CefMediaAccessCallback_1N_N_1Continue(JNIEnv*, + jobject, + jlong, + jint); + +/* + * Class: org_cef_callback_CefMediaAccessCallback_N + * Method: N_Cancel + * Signature: (J)V + */ +JNIEXPORT void JNICALL +Java_org_cef_callback_CefMediaAccessCallback_1N_N_1Cancel(JNIEnv*, + jobject, + jlong); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/native/CefPermissionPromptCallback_N.cpp b/native/CefPermissionPromptCallback_N.cpp new file mode 100644 index 00000000..78481afd --- /dev/null +++ b/native/CefPermissionPromptCallback_N.cpp @@ -0,0 +1,41 @@ +// Copyright (c) 2026 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. + +#include "CefPermissionPromptCallback_N.h" +#include "include/cef_permission_handler.h" +#include "jni_scoped_helpers.h" +#include "jni_util.h" + +namespace { + +CefRefPtr GetSelf(jlong self) { + return reinterpret_cast(self); +} + +void ClearSelf(JNIEnv* env, jobject obj) { + // Clear the reference added in PermissionHandler::OnShowPermissionPrompt. + SetCefForJNIObject_sync( + env, obj, nullptr, "CefPermissionPromptCallback"); +} + +} // namespace + +JNIEXPORT void JNICALL +Java_org_cef_callback_CefPermissionPromptCallback_1N_N_1Continue( + JNIEnv* env, + jobject obj, + jlong self, + jint jresult) { + // See jni_util.h's JNI_REQUIRE_CEF_ALIVE_OR_RETURN comment -- reachable + // from CefPermissionPromptCallback_N.java's finalize(). + JNI_REQUIRE_CEF_ALIVE_OR_RETURN(); + CefRefPtr callback = GetSelf(self); + if (!callback) + return; + // jresult's values are defined in CefPermissionHandler. + // PermissionRequestResult to match cef_permission_request_result_t's + // declaration order (ACCEPT=0, DENY=1, DISMISS=2, IGNORE=3) exactly. + callback->Continue(static_cast(jresult)); + ClearSelf(env, obj); +} diff --git a/native/CefPermissionPromptCallback_N.h b/native/CefPermissionPromptCallback_N.h new file mode 100644 index 00000000..b665ea0d --- /dev/null +++ b/native/CefPermissionPromptCallback_N.h @@ -0,0 +1,24 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class org_cef_callback_CefPermissionPromptCallback_N */ + +#ifndef _Included_org_cef_callback_CefPermissionPromptCallback_N +#define _Included_org_cef_callback_CefPermissionPromptCallback_N +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: org_cef_callback_CefPermissionPromptCallback_N + * Method: N_Continue + * Signature: (JI)V + */ +JNIEXPORT void JNICALL +Java_org_cef_callback_CefPermissionPromptCallback_1N_N_1Continue(JNIEnv*, + jobject, + jlong, + jint); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/native/client_handler.cpp b/native/client_handler.cpp index 3c7d7d85..24f0a640 100644 --- a/native/client_handler.cpp +++ b/native/client_handler.cpp @@ -25,6 +25,7 @@ #include "life_span_handler.h" #include "load_handler.h" #include "message_router_handler.h" +#include "permission_handler.h" #include "print_handler.h" #include "render_handler.h" #include "request_handler.h" @@ -143,6 +144,10 @@ CefRefPtr ClientHandler::GetLoadHandler() { return GetHandler("LoadHandler"); } +CefRefPtr ClientHandler::GetPermissionHandler() { + return GetHandler("PermissionHandler"); +} + CefRefPtr ClientHandler::GetPrintHandler() { return GetHandler("PrintHandler"); } diff --git a/native/client_handler.h b/native/client_handler.h index 6d074110..8d301316 100644 --- a/native/client_handler.h +++ b/native/client_handler.h @@ -36,6 +36,7 @@ class ClientHandler : public CefClient { CefRefPtr GetKeyboardHandler() override; CefRefPtr GetLifeSpanHandler() override; CefRefPtr GetLoadHandler() override; + CefRefPtr GetPermissionHandler() override; CefRefPtr GetPrintHandler() override; CefRefPtr GetRenderHandler() override; CefRefPtr GetRequestHandler() override; diff --git a/native/permission_handler.cpp b/native/permission_handler.cpp new file mode 100644 index 00000000..2b99a65a --- /dev/null +++ b/native/permission_handler.cpp @@ -0,0 +1,123 @@ +// Copyright (c) 2026 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. + +#include "permission_handler.h" + +#include "client_handler.h" +#include "jni_util.h" +#include "util.h" + +namespace { + +// JNI CefMediaAccessCallback object. +class ScopedJNIMediaAccessCallback + : public ScopedJNIObject { + public: + ScopedJNIMediaAccessCallback(JNIEnv* env, CefRefPtr obj) + : ScopedJNIObject( + env, + obj, + "org/cef/callback/CefMediaAccessCallback_N", + "CefMediaAccessCallback") {} +}; + +// JNI CefPermissionPromptCallback object. +class ScopedJNIPermissionPromptCallback + : public ScopedJNIObject { + public: + ScopedJNIPermissionPromptCallback(JNIEnv* env, + CefRefPtr obj) + : ScopedJNIObject( + env, + obj, + "org/cef/callback/CefPermissionPromptCallback_N", + "CefPermissionPromptCallback") {} +}; + +} // namespace + +PermissionHandler::PermissionHandler(JNIEnv* env, jobject handler) + : handle_(env, handler) {} + +bool PermissionHandler::OnRequestMediaAccessPermission( + CefRefPtr browser, + CefRefPtr frame, + const CefString& requesting_origin, + uint32_t requested_permissions, + CefRefPtr callback) { + ScopedJNIEnv env; + if (!env) + return false; + + ScopedJNIBrowser jbrowser(env, browser); + ScopedJNIFrame jframe(env, frame); + jframe.SetTemporary(); + ScopedJNIString jrequestingOrigin(env, requesting_origin); + ScopedJNIMediaAccessCallback jcallback(env, callback); + + jboolean jresult = JNI_FALSE; + + JNI_CALL_METHOD(env, handle_, "onRequestMediaAccessPermission", + "(Lorg/cef/browser/CefBrowser;Lorg/cef/browser/CefFrame;" + "Ljava/lang/String;ILorg/cef/callback/" + "CefMediaAccessCallback;)Z", + Boolean, jresult, jbrowser.get(), jframe.get(), + jrequestingOrigin.get(), (jint)requested_permissions, + jcallback.get()); + + if (jresult == JNI_FALSE) { + // If the Java method returns "false" the callback won't be used and + // the reference can therefore be removed. + jcallback.SetTemporary(); + } + + return (jresult != JNI_FALSE); +} + +bool PermissionHandler::OnShowPermissionPrompt( + CefRefPtr browser, + uint64_t prompt_id, + const CefString& requesting_origin, + uint32_t requested_permissions, + CefRefPtr callback) { + ScopedJNIEnv env; + if (!env) + return false; + + ScopedJNIBrowser jbrowser(env, browser); + ScopedJNIString jrequestingOrigin(env, requesting_origin); + ScopedJNIPermissionPromptCallback jcallback(env, callback); + + jboolean jresult = JNI_FALSE; + + JNI_CALL_METHOD(env, handle_, "onShowPermissionPrompt", + "(Lorg/cef/browser/CefBrowser;JLjava/lang/String;ILorg/cef/" + "callback/CefPermissionPromptCallback;)Z", + Boolean, jresult, jbrowser.get(), (jlong)prompt_id, + jrequestingOrigin.get(), (jint)requested_permissions, + jcallback.get()); + + if (jresult == JNI_FALSE) { + // If the Java method returns "false" the callback won't be used and + // the reference can therefore be removed. + jcallback.SetTemporary(); + } + + return (jresult != JNI_FALSE); +} + +void PermissionHandler::OnDismissPermissionPrompt( + CefRefPtr browser, + uint64_t prompt_id, + cef_permission_request_result_t result) { + ScopedJNIEnv env; + if (!env) + return; + + ScopedJNIBrowser jbrowser(env, browser); + + JNI_CALL_VOID_METHOD(env, handle_, "onDismissPermissionPrompt", + "(Lorg/cef/browser/CefBrowser;JI)V", jbrowser.get(), + (jlong)prompt_id, (jint)result); +} diff --git a/native/permission_handler.h b/native/permission_handler.h new file mode 100644 index 00000000..054b94a7 --- /dev/null +++ b/native/permission_handler.h @@ -0,0 +1,46 @@ +// Copyright (c) 2026 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. + +#ifndef JCEF_NATIVE_PERMISSION_HANDLER_H_ +#define JCEF_NATIVE_PERMISSION_HANDLER_H_ +#pragma once + +#include +#include "include/cef_permission_handler.h" + +#include "jni_scoped_helpers.h" + +// PermissionHandler implementation. +class PermissionHandler : public CefPermissionHandler { + public: + PermissionHandler(JNIEnv* env, jobject handler); + + // CefPermissionHandler methods + virtual bool OnRequestMediaAccessPermission( + CefRefPtr browser, + CefRefPtr frame, + const CefString& requesting_origin, + uint32_t requested_permissions, + CefRefPtr callback) override; + + virtual bool OnShowPermissionPrompt( + CefRefPtr browser, + uint64_t prompt_id, + const CefString& requesting_origin, + uint32_t requested_permissions, + CefRefPtr callback) override; + + virtual void OnDismissPermissionPrompt( + CefRefPtr browser, + uint64_t prompt_id, + cef_permission_request_result_t result) override; + + protected: + ScopedJNIObjectGlobal handle_; + + // Include the default reference counting implementation. + IMPLEMENT_REFCOUNTING(PermissionHandler); +}; + +#endif // JCEF_NATIVE_PERMISSION_HANDLER_H_ diff --git a/tools/make_all_jni_headers.bat b/tools/make_all_jni_headers.bat index ecb1dee0..09e5cb6c 100644 --- a/tools/make_all_jni_headers.bat +++ b/tools/make_all_jni_headers.bat @@ -30,7 +30,9 @@ call make_jni_header.bat %1 org.cef.callback.CefDownloadItemCallback_N call make_jni_header.bat %1 org.cef.callback.CefDragData_N call make_jni_header.bat %1 org.cef.callback.CefFileDialogCallback_N call make_jni_header.bat %1 org.cef.callback.CefJSDialogCallback_N +call make_jni_header.bat %1 org.cef.callback.CefMediaAccessCallback_N call make_jni_header.bat %1 org.cef.callback.CefMenuModel_N +call make_jni_header.bat %1 org.cef.callback.CefPermissionPromptCallback_N call make_jni_header.bat %1 org.cef.callback.CefPrintDialogCallback_N call make_jni_header.bat %1 org.cef.callback.CefPrintJobCallback_N call make_jni_header.bat %1 org.cef.callback.CefQueryCallback_N diff --git a/tools/make_all_jni_headers.sh b/tools/make_all_jni_headers.sh index b4dd3122..12e9bb8b 100755 --- a/tools/make_all_jni_headers.sh +++ b/tools/make_all_jni_headers.sh @@ -22,7 +22,9 @@ else "${DIR}"/make_jni_header.sh $1 org.cef.callback.CefDragData_N "${DIR}"/make_jni_header.sh $1 org.cef.callback.CefFileDialogCallback_N "${DIR}"/make_jni_header.sh $1 org.cef.callback.CefJSDialogCallback_N + "${DIR}"/make_jni_header.sh $1 org.cef.callback.CefMediaAccessCallback_N "${DIR}"/make_jni_header.sh $1 org.cef.callback.CefMenuModel_N + "${DIR}"/make_jni_header.sh $1 org.cef.callback.CefPermissionPromptCallback_N "${DIR}"/make_jni_header.sh $1 org.cef.callback.CefPrintDialogCallback_N "${DIR}"/make_jni_header.sh $1 org.cef.callback.CefPrintJobCallback_N "${DIR}"/make_jni_header.sh $1 org.cef.callback.CefQueryCallback_N