From 4fd915b005492fbb25c1c1965fd88541ed2be85d Mon Sep 17 00:00:00 2001 From: Andrew Kaster Date: Sat, 23 Sep 2023 23:05:15 -0600 Subject: [PATCH] Ladybird/Android: Add EditText for URL bar and attach to native WebView --- Ladybird/Android/src/main/cpp/JNIHelpers.cpp | 16 +++++++++++ Ladybird/Android/src/main/cpp/JNIHelpers.h | 3 +++ .../main/cpp/WebViewImplementationNative.cpp | 7 +++++ .../main/cpp/WebViewImplementationNative.h | 1 + .../cpp/WebViewImplementationNativeJNI.cpp | 6 +++++ .../serenityos/ladybird/LadybirdActivity.kt | 27 ++++++++++++++----- .../java/org/serenityos/ladybird/WebView.kt | 5 ++-- .../ladybird/WebViewImplementation.kt | 8 ++++-- .../src/main/res/layout/activity_main.xml | 15 ++++++++++- .../src/main/res/values-night/themes.xml | 1 + .../Android/src/main/res/values/colors.xml | 1 + .../Android/src/main/res/values/strings.xml | 1 + .../Android/src/main/res/values/themes.xml | 1 + Ladybird/CMakeLists.txt | 1 + Ladybird/WebContent/CMakeLists.txt | 1 + 15 files changed, 82 insertions(+), 12 deletions(-) create mode 100644 Ladybird/Android/src/main/cpp/JNIHelpers.cpp diff --git a/Ladybird/Android/src/main/cpp/JNIHelpers.cpp b/Ladybird/Android/src/main/cpp/JNIHelpers.cpp new file mode 100644 index 00000000000..939fe0d9310 --- /dev/null +++ b/Ladybird/Android/src/main/cpp/JNIHelpers.cpp @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2023, Andrew Kaster + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include "JNIHelpers.h" +#include + +namespace Ladybird { +jstring JavaEnvironment::jstring_from_ak_string(String const& str) +{ + auto as_utf16 = MUST(AK::utf8_to_utf16(str.code_points())); + return m_env->NewString(as_utf16.data(), as_utf16.size()); +} +} diff --git a/Ladybird/Android/src/main/cpp/JNIHelpers.h b/Ladybird/Android/src/main/cpp/JNIHelpers.h index 0db5254fb85..38f1b67d6f5 100644 --- a/Ladybird/Android/src/main/cpp/JNIHelpers.h +++ b/Ladybird/Android/src/main/cpp/JNIHelpers.h @@ -7,6 +7,7 @@ #pragma once #include +#include #include namespace Ladybird { @@ -37,6 +38,8 @@ public: JNIEnv* get() const { return m_env; } + jstring jstring_from_ak_string(String const& str); + private: JavaVM* m_vm = nullptr; JNIEnv* m_env = nullptr; diff --git a/Ladybird/Android/src/main/cpp/WebViewImplementationNative.cpp b/Ladybird/Android/src/main/cpp/WebViewImplementationNative.cpp index 90764a61533..f8acbc4befd 100644 --- a/Ladybird/Android/src/main/cpp/WebViewImplementationNative.cpp +++ b/Ladybird/Android/src/main/cpp/WebViewImplementationNative.cpp @@ -34,6 +34,13 @@ WebViewImplementationNative::WebViewImplementationNative(jobject thiz) JavaEnvironment env(global_vm); env.get()->CallVoidMethod(m_java_instance, invalidate_layout_method); }; + + on_load_start = [this](AK::URL const& url, bool is_redirect) { + JavaEnvironment env(global_vm); + auto url_string = env.jstring_from_ak_string(MUST(url.to_string())); + env.get()->CallVoidMethod(m_java_instance, on_load_start_method, url_string, is_redirect); + env.get()->DeleteLocalRef(url_string); + }; } void WebViewImplementationNative::create_client(WebView::EnableCallgrindProfiling) diff --git a/Ladybird/Android/src/main/cpp/WebViewImplementationNative.h b/Ladybird/Android/src/main/cpp/WebViewImplementationNative.h index dd75e36d3a8..55306fdec33 100644 --- a/Ladybird/Android/src/main/cpp/WebViewImplementationNative.h +++ b/Ladybird/Android/src/main/cpp/WebViewImplementationNative.h @@ -32,6 +32,7 @@ public: static jclass global_class_reference; static jmethodID bind_webcontent_method; static jmethodID invalidate_layout_method; + static jmethodID on_load_start_method; jobject java_instance() const { return m_java_instance; } diff --git a/Ladybird/Android/src/main/cpp/WebViewImplementationNativeJNI.cpp b/Ladybird/Android/src/main/cpp/WebViewImplementationNativeJNI.cpp index b02c172a3aa..f94248ba2e1 100644 --- a/Ladybird/Android/src/main/cpp/WebViewImplementationNativeJNI.cpp +++ b/Ladybird/Android/src/main/cpp/WebViewImplementationNativeJNI.cpp @@ -12,6 +12,7 @@ using namespace Ladybird; jclass WebViewImplementationNative::global_class_reference; jmethodID WebViewImplementationNative::bind_webcontent_method; jmethodID WebViewImplementationNative::invalidate_layout_method; +jmethodID WebViewImplementationNative::on_load_start_method; extern "C" JNIEXPORT void JNICALL Java_org_serenityos_ladybird_WebViewImplementation_00024Companion_nativeClassInit(JNIEnv* env, jobject /* thiz */) @@ -31,6 +32,11 @@ Java_org_serenityos_ladybird_WebViewImplementation_00024Companion_nativeClassIni if (!method) TODO(); WebViewImplementationNative::invalidate_layout_method = method; + + method = env->GetMethodID(WebViewImplementationNative::global_class_reference, "onLoadStart", "(Ljava/lang/String;Z)V"); + if (!method) + TODO(); + WebViewImplementationNative::on_load_start_method = method; } extern "C" JNIEXPORT jlong JNICALL diff --git a/Ladybird/Android/src/main/java/org/serenityos/ladybird/LadybirdActivity.kt b/Ladybird/Android/src/main/java/org/serenityos/ladybird/LadybirdActivity.kt index c228a8eb9be..95510e53900 100644 --- a/Ladybird/Android/src/main/java/org/serenityos/ladybird/LadybirdActivity.kt +++ b/Ladybird/Android/src/main/java/org/serenityos/ladybird/LadybirdActivity.kt @@ -8,15 +8,18 @@ package org.serenityos.ladybird import androidx.appcompat.app.AppCompatActivity import android.os.Bundle +import android.view.KeyEvent +import android.view.inputmethod.EditorInfo +import android.widget.EditText +import android.widget.TextView import org.serenityos.ladybird.databinding.ActivityMainBinding -import java.net.URL -import kotlin.io.path.Path class LadybirdActivity : AppCompatActivity() { private lateinit var binding: ActivityMainBinding private lateinit var resourceDir: String private lateinit var view: WebView + private lateinit var urlEditText: EditText private var timerService = TimerExecutorService() override fun onCreate(savedInstanceState: Bundle?) { @@ -28,16 +31,23 @@ class LadybirdActivity : AppCompatActivity() { binding = ActivityMainBinding.inflate(layoutInflater) setContentView(binding.root) setSupportActionBar(binding.toolbar) + urlEditText = binding.urlEditText view = binding.webView + view.onLoadStart = { url: String, _ -> + urlEditText.setText(url, TextView.BufferType.EDITABLE) + } + urlEditText.setOnEditorActionListener { textView: TextView, actionId: Int, _: KeyEvent? -> + when (actionId) { + EditorInfo.IME_ACTION_GO, EditorInfo.IME_ACTION_SEARCH -> view.loadURL(textView.text.toString()) + } + false + } view.initialize(resourceDir) + view.loadURL(intent.dataString ?: "https://ladybird.dev") } override fun onStart() { super.onStart() - - // FIXME: This is not the right place to load the homepage :^) - val initialURL = URL("https://ladybird.dev") - view.loadURL(initialURL) } override fun onDestroy() { @@ -52,7 +62,10 @@ class LadybirdActivity : AppCompatActivity() { } } - private external fun initNativeCode(resourceDir: String, tag: String, timerService: TimerExecutorService) + private external fun initNativeCode( + resourceDir: String, tag: String, timerService: TimerExecutorService + ) + private external fun disposeNativeCode() private external fun execMainEventLoop() diff --git a/Ladybird/Android/src/main/java/org/serenityos/ladybird/WebView.kt b/Ladybird/Android/src/main/java/org/serenityos/ladybird/WebView.kt index 02a2200d568..3adf963e8f9 100644 --- a/Ladybird/Android/src/main/java/org/serenityos/ladybird/WebView.kt +++ b/Ladybird/Android/src/main/java/org/serenityos/ladybird/WebView.kt @@ -11,12 +11,12 @@ import android.graphics.Bitmap import android.graphics.Canvas import android.util.AttributeSet import android.view.View -import java.net.URL // FIXME: This should (eventually) implement NestedScrollingChild3 and ScrollingView class WebView(context: Context, attributeSet: AttributeSet) : View(context, attributeSet) { private val viewImpl = WebViewImplementation(this) private lateinit var contentBitmap: Bitmap + var onLoadStart: (url: String, isRedirect: Boolean) -> Unit = { _, _ -> } fun initialize(resourceDir: String) { viewImpl.initialize(resourceDir) @@ -26,7 +26,7 @@ class WebView(context: Context, attributeSet: AttributeSet) : View(context, attr viewImpl.dispose() } - fun loadURL(url: URL) { + fun loadURL(url: String) { viewImpl.loadURL(url) } @@ -47,4 +47,5 @@ class WebView(context: Context, attributeSet: AttributeSet) : View(context, attr viewImpl.drawIntoBitmap(contentBitmap); canvas?.drawBitmap(contentBitmap, 0f, 0f, null) } + } diff --git a/Ladybird/Android/src/main/java/org/serenityos/ladybird/WebViewImplementation.kt b/Ladybird/Android/src/main/java/org/serenityos/ladybird/WebViewImplementation.kt index ab0eff9e0c0..9817d11869f 100644 --- a/Ladybird/Android/src/main/java/org/serenityos/ladybird/WebViewImplementation.kt +++ b/Ladybird/Android/src/main/java/org/serenityos/ladybird/WebViewImplementation.kt @@ -33,8 +33,8 @@ class WebViewImplementation(private val view: WebView) { nativeInstance = 0 } - fun loadURL(url: URL) { - nativeLoadURL(nativeInstance, url.toString()) + fun loadURL(url: String) { + nativeLoadURL(nativeInstance, url) } fun drawIntoBitmap(bitmap: Bitmap) { @@ -70,6 +70,10 @@ class WebViewImplementation(private val view: WebView) { view.invalidate() } + fun onLoadStart(url: String, isRedirect: Boolean) { + view.onLoadStart(url, isRedirect) + } + // Functions implemented in native code private external fun nativeObjectInit(): Long private external fun nativeObjectDispose(instance: Long) diff --git a/Ladybird/Android/src/main/res/layout/activity_main.xml b/Ladybird/Android/src/main/res/layout/activity_main.xml index c3a0cec9b19..a9d4dd57dd2 100644 --- a/Ladybird/Android/src/main/res/layout/activity_main.xml +++ b/Ladybird/Android/src/main/res/layout/activity_main.xml @@ -16,7 +16,20 @@ android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="match_parent" - app:layout_scrollFlags="scroll|snap|enterAlways"/> + app:layout_scrollFlags="scroll|snap|enterAlways"> + + + ?attr/colorPrimaryVariant + @color/grey false true diff --git a/Ladybird/Android/src/main/res/values/colors.xml b/Ladybird/Android/src/main/res/values/colors.xml index ca1931bca99..d9462c7ca96 100644 --- a/Ladybird/Android/src/main/res/values/colors.xml +++ b/Ladybird/Android/src/main/res/values/colors.xml @@ -7,4 +7,5 @@ #FF018786 #FF000000 #FFFFFFFF + #FF6B6B6B diff --git a/Ladybird/Android/src/main/res/values/strings.xml b/Ladybird/Android/src/main/res/values/strings.xml index f4749a649de..f5b02a618a2 100644 --- a/Ladybird/Android/src/main/res/values/strings.xml +++ b/Ladybird/Android/src/main/res/values/strings.xml @@ -1,3 +1,4 @@ Ladybird + Enter URL... diff --git a/Ladybird/Android/src/main/res/values/themes.xml b/Ladybird/Android/src/main/res/values/themes.xml index 5413fb17ef4..4d2d58af0ae 100644 --- a/Ladybird/Android/src/main/res/values/themes.xml +++ b/Ladybird/Android/src/main/res/values/themes.xml @@ -12,6 +12,7 @@ ?attr/colorPrimaryVariant + @color/white false true diff --git a/Ladybird/CMakeLists.txt b/Ladybird/CMakeLists.txt index 71b4a26e4e5..3bc35f5c0e4 100644 --- a/Ladybird/CMakeLists.txt +++ b/Ladybird/CMakeLists.txt @@ -161,6 +161,7 @@ elseif(ANDROID) Android/src/main/cpp/WebViewImplementationNativeJNI.cpp Android/src/main/cpp/ALooperEventLoopImplementation.cpp Android/src/main/cpp/TimerExecutorService.cpp + Android/src/main/cpp/JNIHelpers.cpp ) target_link_libraries(ladybird PRIVATE LibArchive jnigraphics android) else() diff --git a/Ladybird/WebContent/CMakeLists.txt b/Ladybird/WebContent/CMakeLists.txt index bc12a8ee108..6022763009a 100644 --- a/Ladybird/WebContent/CMakeLists.txt +++ b/Ladybird/WebContent/CMakeLists.txt @@ -57,6 +57,7 @@ else() ../Android/src/main/cpp/WebContentService.cpp ../Android/src/main/cpp/WebContentServiceJNI.cpp ../Android/src/main/cpp/LadybirdServiceBaseJNI.cpp + ../Android/src/main/cpp/JNIHelpers.cpp ) target_link_libraries(webcontent PRIVATE android) endif()