Skip to content

Commit

Permalink
[wpe] Introduce WPEContext and fix WPECookieManager API
Browse files Browse the repository at this point in the history
Introduce WPEContext to get better control over automation
and also fix WPECookieManager API to better match WebKit
  • Loading branch information
zhani committed Mar 10, 2024
1 parent 81b7094 commit e2b89f2
Show file tree
Hide file tree
Showing 24 changed files with 781 additions and 291 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,11 @@ import androidx.appcompat.app.AlertDialog
import androidx.appcompat.widget.Toolbar
import androidx.core.content.res.ResourcesCompat
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.lifecycle.lifecycleScope
import androidx.navigation.fragment.findNavController
import com.google.android.material.snackbar.Snackbar
import com.wpe.tools.minibrowser.BrowserViewModel
import com.wpe.tools.minibrowser.R
import com.wpe.tools.minibrowser.databinding.FragmentClearBrowsingDataBinding
import com.wpe.wpeview.WPECookieManager
Expand All @@ -39,6 +41,8 @@ class ClearBrowsingDataFragment : Fragment(R.layout.fragment_clear_browsing_data

private lateinit var binding: FragmentClearBrowsingDataBinding

private val browserViewModel by activityViewModels<BrowserViewModel>()

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

Expand Down Expand Up @@ -88,7 +92,9 @@ class ClearBrowsingDataFragment : Fragment(R.layout.fragment_clear_browsing_data

private fun clearSelected() {
if (binding.cookiesItem.isChecked) {
WPECookieManager.getInstance().removeAllCookies {
val selectedTabId = browserViewModel.browserState.value.selectedTabId
val wpeView = browserViewModel.findTab(selectedTabId!!).webview
wpeView.cookieManager.removeAllCookies {
Snackbar.make(
requireView(),
R.string.preferences_clear_browsing_data_snackbar,
Expand Down
2 changes: 2 additions & 0 deletions tools/webdriver/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

<uses-permission android:name="android.permission.INTERNET" />

<application
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,22 @@ import android.content.Intent
import android.os.Bundle
import android.os.ParcelFileDescriptor
import android.util.Log
import android.view.ViewGroup
import androidx.appcompat.app.AppCompatActivity
import com.wpe.wpe.Browser
import com.wpe.wpe.ProcessType
import com.wpe.wpe.services.WPEServiceConnection
import com.wpe.wpe.services.WPEServiceConnectionListener
import com.wpe.wpeview.WPEChromeClient
import com.wpe.wpeview.WPEContext
import com.wpe.wpeview.WPEView

class WebDriverActivity : AppCompatActivity() {

private val LOGTAG = "WebDriver"

private lateinit var wpeView: WPEView
private lateinit var wpeContext: WPEContext
private var wpeView: WPEView? = null

private val serviceConnectionDelegate: WPEServiceConnectionListener = object : WPEServiceConnectionListener {
override fun onCleanExit(connection: WPEServiceConnection) {
Expand All @@ -32,22 +35,31 @@ class WebDriverActivity : AppCompatActivity() {

private val wpeChromeClient: WPEChromeClient = object : WPEChromeClient {
override fun onCloseWindow(window: WPEView) {
Log.d(LOGTAG, "onCloseWindow")
setContentView(null)
wpeView.destroy()
wpeView?.let {
it.parent?.let {p ->
(p as ViewGroup).removeView(it)
}
it.destroy()
}
wpeView = null
}
}

private val wpeContextClient: WPEContext.Client = object : WPEContext.Client {
override fun createWPEViewForAutomation(): WPEView? {
return wpeView ?: run {
wpeView = createWPEView()
wpeView
}
}
}

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

Browser.getInstance().isAutomationMode = true

wpeView = WPEView(applicationContext)
wpeView.wpeChromeClient = wpeChromeClient
setContentView(wpeView)

wpeView.loadUrl("about:blank")
wpeContext = WPEContext(applicationContext, true)
wpeContext.setClient(wpeContextClient)
wpeView = createWPEView()

try {
val processType = ProcessType.WebDriverProcess
Expand All @@ -65,4 +77,14 @@ class WebDriverActivity : AppCompatActivity() {
Log.e(LOGTAG, "Cannot launch webdriver process", e)
}
}

private fun createWPEView() : WPEView? {
val view = WPEView(wpeContext)
view.wpeChromeClient = wpeChromeClient
setContentView(view)

view.loadUrl("about:blank")

return view
}
}
32 changes: 6 additions & 26 deletions wpe/src/main/cpp/Browser/Browser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include "LooperThread.h"

#include <string>
#include <wpe/webkit.h>

/***********************************************************************************************************************
* JNI mapping with Java Browser class
Expand Down Expand Up @@ -89,13 +90,12 @@ JNIBrowserCache::JNIBrowserCache()
Logging::pipeStdoutToLogcat();
Environment::configureEnvironment(envStringsArray);
}),
JNI::NativeMethod<void(jboolean, jstring, jstring)>(
JNI::NativeMethod<void()>(
"nativeInit",
+[](JNIEnv* env, jobject obj, jboolean automationMode, jstring dataDir, jstring cacheDir) {
+[](JNIEnv* env, jobject obj) {
getJNIBrowserCache().m_browserJavaInstance
= JNI::createTypedProtectedRef(env, reinterpret_cast<JNIBrowser>(obj), true);
Browser::instance().jniInit(automationMode != 0U, JNI::String(dataDir).getContent().get(),
JNI::String(cacheDir).getContent().get());
Browser::instance().jniInit();
}),
JNI::NativeMethod<void()>(
"nativeShut", +[](JNIEnv*, jobject) {
Expand Down Expand Up @@ -152,32 +152,17 @@ void Browser::configureJNIMappings()
wpe_process_provider_register_interface(&s_processProviderInterface);
}

void Browser::jniInit(bool automationMode, const char* dataDir, const char* cacheDir)
void Browser::jniInit()
{
Logging::logDebug("Browser::jniInit('%d', '%s', '%s') [tid %d]", automationMode, dataDir, cacheDir, gettid());
m_automationMode = automationMode;
Logging::logDebug("Browser::jniInit() [tid %d]", gettid());
m_messagePump = std::make_unique<MessagePump>();
if (automationMode) {
g_setenv("WEBKIT_INSPECTOR_SERVER", "127.0.0.1:8889", 1);
m_websiteDataManager = {webkit_website_data_manager_new_ephemeral(), [](auto* ptr) { g_object_unref(ptr); }};
} else {
m_websiteDataManager = {
webkit_website_data_manager_new("base-data-directory", dataDir, "base-cache-directory", cacheDir, nullptr),
[](auto* ptr) { g_object_unref(ptr); }};
}
m_webContext = {webkit_web_context_new_with_website_data_manager(m_websiteDataManager.get()),
[](auto* ptr) { g_object_unref(ptr); }};

webkit_cookie_manager_set_accept_policy(cookieManager(), WEBKIT_COOKIE_POLICY_ACCEPT_NO_THIRD_PARTY);
}

void Browser::jniShut() noexcept
{
try {
Logging::logDebug("Browser::jniShut() [tid %d]", gettid());
m_messagePump = nullptr;
m_websiteDataManager = nullptr;
m_webContext = nullptr;
} catch (...) {
}
}
Expand All @@ -186,8 +171,3 @@ void Browser::invokeOnUiThread(void (*onExec)(void*), void (*onDestroy)(void*),
{
m_messagePump->invoke(onExec, onDestroy, userData);
}

WebKitCookieManager* Browser::cookieManager() const noexcept
{
return webkit_website_data_manager_get_cookie_manager(m_websiteDataManager.get());
}
15 changes: 1 addition & 14 deletions wpe/src/main/cpp/Browser/Browser.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@

#include "MessagePump.h"

#include <wpe/webkit.h>

class Browser final {
public:
static void configureJNIMappings();
Expand All @@ -43,25 +41,14 @@ class Browser final {

~Browser() { jniShut(); }

bool automationMode() const noexcept { return m_automationMode; }

WebKitWebContext* webContext() const noexcept { return m_webContext.get(); }
WebKitWebsiteDataManager* websiteDataManager() const noexcept { return m_websiteDataManager.get(); }
WebKitCookieManager* cookieManager() const noexcept;

void invokeOnUiThread(void (*onExec)(void*), void (*onDestroy)(void*), void* userData) const noexcept;

private:
Browser() = default;

friend class JNIBrowserCache;
void jniInit(bool automationMode, const char* dataDir, const char* cacheDir);
void jniInit();
void jniShut() noexcept;

template <typename T> using ProtectedUniquePointer = std::unique_ptr<T, std::function<void(T*)>>;

bool m_automationMode = false;
std::unique_ptr<MessagePump> m_messagePump {};
ProtectedUniquePointer<WebKitWebsiteDataManager> m_websiteDataManager {};
ProtectedUniquePointer<WebKitWebContext> m_webContext {};
};
8 changes: 6 additions & 2 deletions wpe/src/main/cpp/Browser/EntryPoint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,19 @@
#include "Browser.h"
#include "Page.h"
#include "PageSettings.h"
#include "WPECookieManager.h"
#include "WKCookieManager.h"
#include "WKWebContext.h"
#include "WKWebsiteDataManager.h"

extern "C" JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* javaVM, void* /*reserved*/)
{
try {
JNI::initVM(javaVM);

Browser::configureJNIMappings();
WPECookieManager::configureJNIMappings();
WKCookieManager::configureJNIMappings();
WKWebContext::configureJNIMappings();
WKWebsiteDataManager::configureJNIMappings();
Page::configureJNIMappings();
PageSettings::configureJNIMappings();

Expand Down
39 changes: 9 additions & 30 deletions wpe/src/main/cpp/Browser/Page.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "Browser.h"
#include "Logging.h"
#include "RendererSurfaceControl.h"
#include "WKWebContext.h"

#include <android/native_window_jni.h>
#include <unistd.h>
Expand All @@ -38,22 +39,6 @@ void handleCommitBuffer(void* context, WPEAndroidBuffer* buffer, int fenceID)
page->commitBuffer(buffer, fenceID);
}

WebKitWebView* createWebViewForAutomationCallback(WebKitAutomationSession* /*session*/, WebKitWebView* view)
{
return view;
}

void automationStartedCallback(WebKitWebContext* /*context*/, WebKitAutomationSession* session, WebKitWebView* view)
{
auto* info = webkit_application_info_new();
webkit_application_info_set_name(info, "MiniBrowser");
webkit_application_info_set_version(info, WEBKIT_MAJOR_VERSION, WEBKIT_MINOR_VERSION, WEBKIT_MICRO_VERSION);
webkit_automation_session_set_application_info(session, info);
webkit_application_info_unref(info);

g_signal_connect(session, "create-web-view", G_CALLBACK(createWebViewForAutomationCallback), view);
}

} // namespace

/***********************************************************************************************************************
Expand Down Expand Up @@ -140,7 +125,7 @@ class JNIPageCache final : public JNI::TypedClass<JNIPage> {
const JNI::Method<void()> m_onEnterFullscreenMode;
const JNI::Method<void()> m_onExitFullscreenMode;

static jlong nativeInit(JNIEnv* env, jobject obj, jint width, jint height);
static jlong nativeInit(JNIEnv* env, jobject obj, jlong wkWebContextPtr, jint width, jint height);
static void nativeClose(JNIEnv* env, jobject obj, jlong pagePtr) noexcept;
static void nativeDestroy(JNIEnv* env, jobject obj, jlong pagePtr) noexcept;
static void nativeLoadUrl(JNIEnv* env, jobject obj, jlong pagePtr, jstring url) noexcept;
Expand Down Expand Up @@ -180,7 +165,7 @@ JNIPageCache::JNIPageCache()
, m_onEnterFullscreenMode(getMethod<void()>("onEnterFullscreenMode"))
, m_onExitFullscreenMode(getMethod<void()>("onExitFullscreenMode"))
{
registerNativeMethods(JNI::NativeMethod<jlong(jint, jint)>("nativeInit", JNIPageCache::nativeInit),
registerNativeMethods(JNI::NativeMethod<jlong(jlong, jint, jint)>("nativeInit", JNIPageCache::nativeInit),
JNI::NativeMethod<void(jlong)>("nativeClose", JNIPageCache::nativeClose),
JNI::NativeMethod<void(jlong)>("nativeDestroy", JNIPageCache::nativeDestroy),
JNI::NativeMethod<void(jlong, jstring)>("nativeLoadUrl", JNIPageCache::nativeLoadUrl),
Expand All @@ -203,11 +188,12 @@ JNIPageCache::JNIPageCache()
"nativeRequestExitFullscreenMode", JNIPageCache::nativeRequestExitFullscreenMode));
}

jlong JNIPageCache::nativeInit(JNIEnv* env, jobject obj, jint width, jint height)
jlong JNIPageCache::nativeInit(JNIEnv* env, jobject obj, jlong wkWebContextPtr, jint width, jint height)
{
Logging::logDebug("Page::nativeInit(%p, %d, %d) [tid %d]", obj, width, height, gettid());
auto* wkWebContext = reinterpret_cast<WKWebContext*>(wkWebContextPtr); // NOLINT(performance-no-int-to-ptr)
// NOLINTNEXTLINE(cppcoreguidelines-owning-memory)
Page* page = new Page(env, reinterpret_cast<JNIPage>(obj), width, height);
Page* page = new Page(env, reinterpret_cast<JNIPage>(obj), wkWebContext, width, height);
return reinterpret_cast<jlong>(page);
}

Expand Down Expand Up @@ -400,7 +386,7 @@ void JNIPageCache::nativeRequestExitFullscreenMode(JNIEnv* /*env*/, jobject /*ob

void Page::configureJNIMappings() { getJNIPageCache(); }

Page::Page(JNIEnv* env, JNIPage jniPage, int width, int height)
Page::Page(JNIEnv* env, JNIPage jniPage, WKWebContext* wkWebContext, int width, int height)
: m_pageJavaInstance(JNI::createTypedProtectedRef(env, jniPage, true))
, m_inputMethodContext(this)
{
Expand All @@ -414,13 +400,11 @@ Page::Page(JNIEnv* env, JNIPage jniPage, int width, int height)
WebKitWebViewBackend* viewBackend = webkit_web_view_backend_new(
wpeBackend, reinterpret_cast<GDestroyNotify>(WPEAndroidViewBackend_destroy), m_viewBackend);

gboolean const automationMode = Browser::instance().automationMode() ? TRUE : FALSE;
gboolean const automationMode = wkWebContext->automationMode() ? TRUE : FALSE;

// m_webView = webkit_web_view_new_with_context(viewBackend, Browser::instance().webContext());
m_webView = WEBKIT_WEB_VIEW(g_object_new(WEBKIT_TYPE_WEB_VIEW, "backend", viewBackend, "web-context",
Browser::instance().webContext(), "is-controlled-by-automation", automationMode, nullptr));
wkWebContext->webContext(), "is-controlled-by-automation", automationMode, nullptr));
webkit_web_view_set_input_method_context(m_webView, m_inputMethodContext.webKitInputMethodContext());
webkit_web_context_set_automation_allowed(Browser::instance().webContext(), automationMode);

m_signalHandlers.push_back(g_signal_connect_swapped(m_webView, "close", G_CALLBACK(JNIPageCache::onClose), this));
m_signalHandlers.push_back(
Expand All @@ -436,11 +420,6 @@ Page::Page(JNIEnv* env, JNIPage jniPage, int width, int height)
wpeBackend, reinterpret_cast<wpe_view_backend_fullscreen_handler>(JNIPageCache::onFullscreenRequest), this);

WPEAndroidViewBackend_setCommitBufferHandler(m_viewBackend, this, handleCommitBuffer);

if (Browser::instance().automationMode()) {
g_signal_connect(
Browser::instance().webContext(), "automation-started", G_CALLBACK(automationStartedCallback), m_webView);
}
}

void Page::close() noexcept
Expand Down
3 changes: 2 additions & 1 deletion wpe/src/main/cpp/Browser/Page.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
DECLARE_JNI_CLASS_SIGNATURE(JNIPage, "com/wpe/wpe/Page");

struct WPEAndroidViewBackend;
class WKWebContext;

class Page final : public InputMethodContextObserver {
public:
Expand All @@ -55,7 +56,7 @@ class Page final : public InputMethodContextObserver {
private:
friend class JNIPageCache;

Page(JNIEnv* env, JNIPage jniPage, int width, int height);
Page(JNIEnv* env, JNIPage jniPage, WKWebContext* wkWebContext, int width, int height);

JNI::ProtectedType<JNIPage> m_pageJavaInstance;
InputMethodContext m_inputMethodContext;
Expand Down
Loading

0 comments on commit e2b89f2

Please sign in to comment.