diff --git a/tools/minibrowser/src/main/java/org/wpewebkit/tools/minibrowser/BrowserFragment.kt b/tools/minibrowser/src/main/java/org/wpewebkit/tools/minibrowser/BrowserFragment.kt index 17af08634..afd4af2cc 100644 --- a/tools/minibrowser/src/main/java/org/wpewebkit/tools/minibrowser/BrowserFragment.kt +++ b/tools/minibrowser/src/main/java/org/wpewebkit/tools/minibrowser/BrowserFragment.kt @@ -37,7 +37,7 @@ import org.wpewebkit.wpeview.WPEView import org.wpewebkit.wpeview.WPEViewClient -const val INITIAL_URL = "https://igalia.com" +const val INITIAL_URL = "https://davidwalsh.name/demo/fullscreen.php"///"https://igalia.com" const val SEARCH_URI_BASE = "https://duckduckgo.com/?q=" class BrowserFragment : Fragment(R.layout.fragment_browser) { @@ -163,20 +163,6 @@ class BrowserFragment : Fragment(R.layout.fragment_browser) { } } } - - if (selectedTab.webview.wpeViewClient == null) { - selectedTab.webview.wpeViewClient = object : WPEViewClient { - override fun onPageStarted(view: WPEView, url: String) { - // DO nothing for now - super.onPageStarted(view, url) - } - - override fun onPageFinished(view: WPEView, url: String) { - // DO nothing for now - super.onPageFinished(view, url) - } - } - } } override fun onStart() { diff --git a/wpe/src/main/cpp/Runtime/WKWebView.cpp b/wpe/src/main/cpp/Runtime/WKWebView.cpp index eacfedd83..2905717da 100644 --- a/wpe/src/main/cpp/Runtime/WKWebView.cpp +++ b/wpe/src/main/cpp/Runtime/WKWebView.cpp @@ -70,10 +70,10 @@ class JNIWKWebViewCache final : public JNI::TypedClass { getJNIPageCache().m_onLoadChanged, wkWebView->m_webViewJavaInstance.get(), static_cast(loadEvent)); } - static void onLoadProgress(WKWebView* wkWebView, GParamSpec* /*pspec*/, WebKitWebView* webView) noexcept + static void onEstimatedLoadProgress(WKWebView* wkWebView, GParamSpec* /*pspec*/, WebKitWebView* webView) noexcept { - Logging::logDebug("WKWebView::onLoadProgress() [tid %d]", gettid()); - callJavaMethod(getJNIPageCache().m_onLoadProgress, wkWebView->m_webViewJavaInstance.get(), + Logging::logDebug("WKWebView::onEstimatedLoadProgress() [tid %d]", gettid()); + callJavaMethod(getJNIPageCache().m_onEstimatedLoadProgress, wkWebView->m_webViewJavaInstance.get(), static_cast(webkit_web_view_get_estimated_load_progress(webView))); } @@ -226,7 +226,7 @@ class JNIWKWebViewCache final : public JNI::TypedClass { // NOLINTBEGIN(cppcoreguidelines-avoid-const-or-ref-data-members) const JNI::Method m_onClose; const JNI::Method m_onLoadChanged; - const JNI::Method m_onLoadProgress; + const JNI::Method m_onEstimatedLoadProgress; const JNI::Method m_onUriChanged; const JNI::Method m_onTitleChanged; const JNI::Method m_onScriptDialog; @@ -243,6 +243,7 @@ class JNIWKWebViewCache final : public JNI::TypedClass { static void nativeDestroy(JNIEnv* env, jobject obj, jlong wkWebViewPtr) noexcept; static void nativeLoadUrl(JNIEnv* env, jobject obj, jlong wkWebViewPtr, jstring url) noexcept; static void nativeLoadHtml(JNIEnv* env, jobject obj, jlong wkWebViewPtr, jstring content, jstring baseUri) noexcept; + static jdouble nativeGetEstimatedLoadProgress(JNIEnv* env, jobject obj, jlong wkWebViewPtr) noexcept; static void nativeGoBack(JNIEnv* env, jobject obj, jlong wkWebViewPtr) noexcept; static void nativeGoForward(JNIEnv* env, jobject obj, jlong wkWebViewPtr) noexcept; static void nativeStopLoading(JNIEnv* env, jobject obj, jlong wkWebViewPtr) noexcept; @@ -275,7 +276,7 @@ JNIWKWebViewCache::JNIWKWebViewCache() : JNI::TypedClass(true) , m_onClose(getMethod("onClose")) , m_onLoadChanged(getMethod("onLoadChanged")) - , m_onLoadProgress(getMethod("onLoadProgress")) + , m_onEstimatedLoadProgress(getMethod("onEstimatedLoadProgress")) , m_onUriChanged(getMethod("onUriChanged")) , m_onTitleChanged(getMethod("onTitleChanged")) , m_onScriptDialog(getMethod("onScriptDialog")) @@ -292,6 +293,8 @@ JNIWKWebViewCache::JNIWKWebViewCache() JNI::NativeMethod("nativeDestroy", JNIWKWebViewCache::nativeDestroy), JNI::NativeMethod("nativeLoadUrl", JNIWKWebViewCache::nativeLoadUrl), JNI::NativeMethod("nativeLoadHtml", JNIWKWebViewCache::nativeLoadHtml), + JNI::NativeMethod( + "nativeGetEstimatedLoadProgress", JNIWKWebViewCache::nativeGetEstimatedLoadProgress), JNI::NativeMethod("nativeGoBack", JNIWKWebViewCache::nativeGoBack), JNI::NativeMethod("nativeGoForward", JNIWKWebViewCache::nativeGoForward), JNI::NativeMethod("nativeStopLoading", JNIWKWebViewCache::nativeStopLoading), @@ -363,6 +366,15 @@ void JNIWKWebViewCache::nativeLoadHtml( } } +jdouble JNIWKWebViewCache::nativeGetEstimatedLoadProgress(JNIEnv* /*env*/, jobject /*obj*/, jlong wkWebViewPtr) noexcept +{ + auto* wkWebView = reinterpret_cast(wkWebViewPtr); // NOLINT(performance-no-int-to-ptr) + if ((wkWebView != nullptr) && (wkWebView->m_webView != nullptr)) { + return webkit_web_view_get_estimated_load_progress(wkWebView->m_webView); + } + return 0; +} + void JNIWKWebViewCache::nativeGoBack(JNIEnv* /*env*/, jobject /*obj*/, jlong wkWebViewPtr) noexcept { Logging::logDebug("WKWebView::nativeGoBack() [tid %d]", gettid()); @@ -584,7 +596,7 @@ WKWebView::WKWebView(JNIEnv* env, JNIWKWebView jniWKWebView, WKWebContext* wkWeb m_signalHandlers.push_back( g_signal_connect_swapped(m_webView, "load-changed", G_CALLBACK(JNIWKWebViewCache::onLoadChanged), this)); m_signalHandlers.push_back(g_signal_connect_swapped( - m_webView, "notify::estimated-load-progress", G_CALLBACK(JNIWKWebViewCache::onLoadProgress), this)); + m_webView, "notify::estimated-load-progress", G_CALLBACK(JNIWKWebViewCache::onEstimatedLoadProgress), this)); m_signalHandlers.push_back( g_signal_connect_swapped(m_webView, "notify::uri", G_CALLBACK(JNIWKWebViewCache::onUriChanged), this)); m_signalHandlers.push_back( diff --git a/wpe/src/main/java/org/wpewebkit/wpe/WKWebView.java b/wpe/src/main/java/org/wpewebkit/wpe/WKWebView.java index ce67f2150..b5fb17b88 100644 --- a/wpe/src/main/java/org/wpewebkit/wpe/WKWebView.java +++ b/wpe/src/main/java/org/wpewebkit/wpe/WKWebView.java @@ -41,6 +41,7 @@ import android.view.View; import android.view.inputmethod.InputMethodManager; import android.widget.EditText; +import android.widget.FrameLayout; import android.widget.TextView; import androidx.annotation.Keep; @@ -55,6 +56,7 @@ import org.wpewebkit.wpeview.WPEResourceRequest; import org.wpewebkit.wpeview.WPEResourceResponse; import org.wpewebkit.wpeview.WPEView; +import org.wpewebkit.wpeview.WPEViewClient; import java.lang.ref.WeakReference; import java.net.MalformedURLException; @@ -86,35 +88,22 @@ public final class WKWebView { protected long nativePtr = 0; public long getNativePtr() { return nativePtr; } - private native long nativeInit(long nativeContextPtr, int width, int height, float deviceScale, boolean headless); - private native void nativeClose(long nativePtr); - private native void nativeDestroy(long nativePtr); - private native void nativeLoadUrl(long nativePtr, @NonNull String url); - private native void nativeLoadHtml(long nativePtr, @NonNull String content, @Nullable String baseUri); - private native void nativeGoBack(long nativePtr); - private native void nativeGoForward(long nativePtr); - private native void nativeStopLoading(long nativePtr); - private native void nativeReload(long nativePtr); - protected native void nativeSurfaceCreated(long nativePtr, @NonNull Surface surface); - protected native void nativeSurfaceChanged(long nativePtr, int format, int width, int height); - protected native void nativeSurfaceRedrawNeeded(long nativePtr); - protected native void nativeSurfaceDestroyed(long nativePtr); - protected native void nativeSetZoomLevel(long nativePtr, double zoomLevel); - protected native void nativeOnTouchEvent(long nativePtr, long time, int type, float x, float y); - private native void nativeSetInputMethodContent(long nativePtr, int unicodeChar); - private native void nativeDeleteInputMethodContent(long nativePtr, int offset); - private native void nativeRequestExitFullscreenMode(long nativePtr); - private native void nativeEvaluateJavascript(long nativePtr, String script, WKCallback callback); - private native void nativeScriptDialogClose(long nativeDialogPtr); - private native void nativeScriptDialogConfirm(long nativeDialogPtr, boolean confirm, @Nullable String text); - private final WPEView wpeView; + private WPEViewClient wpeViewClient = new WPEViewClient(); + private WPEChromeClient wpeChromeClient = null; + private final PageSurfaceView surfaceView; protected final ScaleGestureDetector scaleDetector; private final WKSettings wkSettings; + private FrameLayout customView = null; + public @NonNull WKSettings getWKSettings() { return wkSettings; } + private String uri = "about:blank"; + private String originalUrl = uri; + private String title = uri; + private boolean isClosed = false; private boolean canGoBack = true; private boolean canGoForward = true; @@ -151,12 +140,22 @@ public WKWebView(@NonNull WPEView wpeView, @NonNull WKWebContext context, boolea } surfaceView.requestLayout(); + wkSettings = new WKSettings(this); scaleDetector = new ScaleGestureDetector(ctx, new PageScaleListener()); - wpeView.onPageSurfaceViewCreated(surfaceView); - wpeView.onPageSurfaceViewReady(surfaceView); + wpeView.post(() -> { + // Add the view during the next UI cycle + try { + wpeView.addView(surfaceView); + } catch (Exception e) { + Log.e(LOGTAG, "Error while adding the surface view", e); + } + }); - wkSettings = new WKSettings(this); + wpeView.post(() -> { + if (wpeViewClient != null) + wpeViewClient.onViewReady(wpeView); + }); } public void close() { @@ -168,6 +167,9 @@ public void close() { } public void destroy() { + // Make sure that we do not trigger any callbacks after destruction + wpeChromeClient = null; + wpeViewClient = null; if (nativePtr != 0) { close(); nativeDestroy(nativePtr); @@ -184,45 +186,143 @@ protected void finalize() throws Throwable { } } + public void setWPEViewClient(@NonNull WPEViewClient wpeViewClient) { this.wpeViewClient = wpeViewClient; } + + public @NonNull WPEViewClient getWPEViewClient() { return wpeViewClient; } + + public @Nullable WPEChromeClient getWPEChromeClient() { return wpeChromeClient; } + + public void setWPEChromeClient(@Nullable WPEChromeClient client) { wpeChromeClient = client; } + + public @Nullable String getTitle() { return title; } + + public @Nullable String getUrl() { return uri; } + + public @Nullable String getOriginalUrl() { return originalUrl; } + + public int getEstimatedLoadProgress() { return (int)Math.round(nativeGetEstimatedLoadProgress(nativePtr) * 100); } + public void loadUrl(@NonNull String url) { Log.d(LOGTAG, "loadUrl('" + url + "')"); + originalUrl = url; nativeLoadUrl(nativePtr, url); } public void loadHtml(@NonNull String content, @Nullable String baseUri) { Log.d(LOGTAG, "loadHtml(..., '" + baseUri + "')"); + originalUrl = baseUri; nativeLoadHtml(nativePtr, content, baseUri); } - @Keep - public void onLoadChanged(int loadEvent) { - wpeView.onLoadChanged(loadEvent); - if (loadEvent == WKWebView.LOAD_STARTED) { - onInputMethodContextOut(); - } - } + public void requestExitFullscreenMode() { nativeRequestExitFullscreenMode(nativePtr); } - @Keep - public void onClose() { - wpeView.onClose(); + public boolean canGoBack() { return canGoBack; } + + public boolean canGoForward() { return canGoForward; } + + public void goBack() { nativeGoBack(nativePtr); } + + public void goForward() { nativeGoForward(nativePtr); } + + public void stopLoading() { nativeStopLoading(nativePtr); } + + public void reload() { nativeReload(nativePtr); } + + public void setInputMethodContent(int unicodeChar) { nativeSetInputMethodContent(nativePtr, unicodeChar); } + + public void deleteInputMethodContent(int offset) { nativeDeleteInputMethodContent(nativePtr, offset); } + + public void evaluateJavascript(@NonNull String script, @Nullable WKCallback callback) { + nativeEvaluateJavascript(nativePtr, script, callback); } - @Keep - public void onLoadProgress(double progress) { - wpeView.onLoadProgress(progress); + + protected final class PageSurfaceHolderCallback implements SurfaceHolder.Callback2 { + @Override + public void surfaceCreated(SurfaceHolder holder) { + Log.d(LOGTAG, "PageSurfaceHolderCallback::surfaceCreated()"); + nativeSurfaceCreated(nativePtr, holder.getSurface()); + } + + @Override + public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { + Log.d(LOGTAG, "PageSurfaceHolderCallback::surfaceChanged() with format: " + format + " and size: " + width + + " x " + height); + nativeSurfaceChanged(nativePtr, format, width, height); + } + + @Override + public void surfaceRedrawNeeded(SurfaceHolder holder) { + Log.d(LOGTAG, "PageSurfaceHolderCallback::surfaceRedrawNeeded()"); + nativeSurfaceRedrawNeeded(nativePtr); + } + + @Override + public void surfaceDestroyed(SurfaceHolder holder) { + Log.d(LOGTAG, "PageSurfaceHolderCallback::surfaceDestroyed()"); + nativeSurfaceDestroyed(nativePtr); + } } - @Keep - public void onUriChanged(@NonNull String uri) { - wpeView.onUriChanged(uri); + protected final class PageScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener { + private float m_scaleFactor = 1.f; + + @Override + public boolean onScale(ScaleGestureDetector detector) { + Log.d(LOGTAG, "PageScaleListener::onScale()"); + + m_scaleFactor *= detector.getScaleFactor(); + m_scaleFactor = Math.max(0.1f, Math.min(m_scaleFactor, 5.0f)); + nativeSetZoomLevel(nativePtr, m_scaleFactor); + + ignoreTouchEvents = true; + return true; + } } - @Keep - public void onTitleChanged(@NonNull String title, boolean canGoBack, boolean canGoForward) { - this.canGoBack = canGoBack; - this.canGoForward = canGoForward; - wpeView.onTitleChanged(title); + private final class PageSurfaceView extends SurfaceView { + public PageSurfaceView(Context context) { super(context); } + + @Override + @SuppressLint("ClickableViewAccessibility") + public boolean onTouchEvent(MotionEvent event) { + int pointerCount = event.getPointerCount(); + if (pointerCount < 1) + return false; + + scaleDetector.onTouchEvent(event); + if (ignoreTouchEvents) + ignoreTouchEvents = false; + + int eventType; + int eventAction = event.getActionMasked(); + switch (eventAction) { + case MotionEvent.ACTION_DOWN: + eventType = 0; + break; + + case MotionEvent.ACTION_MOVE: + eventType = 1; + break; + + case MotionEvent.ACTION_UP: + eventType = 2; + break; + + default: + return false; + } + + nativeOnTouchEvent(nativePtr, event.getEventTime(), eventType, event.getX(0), event.getY(0)); + return true; + } } + /** + * -------------------------------------------------------------------------------------------- + * Methods called from native via JNI + * -------------------------------------------------------------------------------------------- + */ + private class ScriptDialogResult implements WPEJsPromptResult { private final long nativeScriptDialogPtr; @@ -291,10 +391,86 @@ public void onClick(DialogInterface dialogInterface, int which) { } } + private static class PageResourceRequest implements WPEResourceRequest { + + private final Uri uri; + private final String method; + private final HashMap requestHeaders = new HashMap<>(); + + PageResourceRequest(String uri, String method, String[] headers) { + this.uri = Uri.parse(uri); + this.method = method; + + int i = 0; + while (i < headers.length) { + requestHeaders.put(headers[i++], headers[i++]); + } + } + + @NonNull + @Override + public Uri getUrl() { + return uri; + } + + @NonNull + @Override + public String getMethod() { + return method; + } + + @NonNull + @Override + public Map getRequestHeaders() { + return requestHeaders; + } + } + + @Keep + private void onLoadChanged(int loadEvent) { + switch (loadEvent) { + case WKWebView.LOAD_STARTED: + if (wpeViewClient != null) + wpeViewClient.onPageStarted(wpeView, uri); + onInputMethodContextOut(); + break; + case WKWebView.LOAD_FINISHED: + if (wpeViewClient != null) + wpeViewClient.onPageFinished(wpeView, uri); + break; + } + } + + @Keep + private void onClose() { + if (wpeChromeClient != null) + wpeChromeClient.onCloseWindow(wpeView); + } + + @Keep + private void onEstimatedLoadProgress(double progress) { + if (wpeChromeClient != null) + wpeChromeClient.onProgressChanged(wpeView, (int)Math.round(progress * 100)); + } + + @Keep + private void onUriChanged(@NonNull String uri) { + this.uri = uri; + } + + @Keep + private void onTitleChanged(@NonNull String title, boolean canGoBack, boolean canGoForward) { + this.title = title; + this.canGoBack = canGoBack; + this.canGoForward = canGoForward; + if (wpeChromeClient != null) + wpeChromeClient.onReceivedTitle(wpeView, title); + } + @SuppressLint("StringFormatInvalid") @Keep - public boolean onScriptDialog(long nativeDialogPtr, int dialogType, @NonNull String url, @NonNull String message, - @NonNull String defaultText) { + private boolean onScriptDialog(long nativeDialogPtr, int dialogType, @NonNull String url, @NonNull String message, + @NonNull String defaultText) { WPEChromeClient client = wpeView.getWPEChromeClient(); if (client != null) { boolean clientHandledDialog = false; @@ -355,7 +531,7 @@ public boolean onScriptDialog(long nativeDialogPtr, int dialogType, @NonNull Str } @Keep - public void onInputMethodContextIn() { + private void onInputMethodContextIn() { WeakReference weakRefecence = new WeakReference<>(wpeView); Handler handler = new Handler(Looper.getMainLooper()); handler.post(() -> { @@ -371,7 +547,7 @@ public void onInputMethodContextIn() { } @Keep - public void onInputMethodContextOut() { + private void onInputMethodContextOut() { WeakReference weakRefecence = new WeakReference<>(wpeView); Handler handler = new Handler(Looper.getMainLooper()); handler.post(() -> { @@ -385,169 +561,75 @@ public void onInputMethodContextOut() { } @Keep - public void onEnterFullscreenMode() { + private void onEnterFullscreenMode() { Log.d(LOGTAG, "onEnterFullscreenMode()"); - wpeView.onEnterFullscreenMode(); + if ((surfaceView != null) && (wpeChromeClient != null)) { + wpeView.removeView(surfaceView); + + customView = new FrameLayout(wpeView.getContext()); + customView.addView(surfaceView); + customView.setFocusable(true); + customView.setFocusableInTouchMode(true); + + wpeChromeClient.onShowCustomView(customView, () -> { + if (customView != null) + requestExitFullscreenMode(); + }); + } } @Keep - public void onExitFullscreenMode() { + private void onExitFullscreenMode() { Log.d(LOGTAG, "onExitFullscreenMode()"); - wpeView.onExitFullscreenMode(); - } - - private static class PageResourceRequest implements WPEResourceRequest { - - private final Uri uri; - private final String method; - private final HashMap requestHeaders = new HashMap<>(); - - PageResourceRequest(String uri, String method, String[] headers) { - this.uri = Uri.parse(uri); - this.method = method; - - int i = 0; - while (i < headers.length) { - requestHeaders.put(headers[i++], headers[i++]); - } - } - - @NonNull - @Override - public Uri getUrl() { - return uri; - } - - @NonNull - @Override - public String getMethod() { - return method; - } - - @NonNull - @Override - public Map getRequestHeaders() { - return requestHeaders; + if ((customView != null) && (surfaceView != null) && (wpeChromeClient != null)) { + customView.removeView(surfaceView); + wpeView.addView(surfaceView); + customView = null; + wpeChromeClient.onHideCustomView(); } } @Keep - public void onReceivedHttpError( // WPEResourceRequest + private void onReceivedHttpError( // WPEResourceRequest @NonNull String requestUri, @NonNull String requestMethod, @NonNull String[] requestHeaders, // WPEResourceResponse @NonNull String responseMimeType, int responseStatusCode, @NonNull String[] responseHeaders) { - PageResourceRequest request = new PageResourceRequest(requestUri, requestMethod, requestHeaders); - - HashMap responseHeadersMap = new HashMap<>(); - int i = 0; - while (i < responseHeaders.length) { - responseHeadersMap.put(responseHeaders[i++], responseHeaders[i++]); - } - WPEResourceResponse response = - new WPEResourceResponse(responseMimeType, responseStatusCode, responseHeadersMap); - wpeView.onReceivedHttpError(request, response); - } - - public void requestExitFullscreenMode() { nativeRequestExitFullscreenMode(nativePtr); } - - public boolean canGoBack() { return canGoBack; } - - public boolean canGoForward() { return canGoForward; } - - public void goBack() { nativeGoBack(nativePtr); } - - public void goForward() { nativeGoForward(nativePtr); } - - public void stopLoading() { nativeStopLoading(nativePtr); } - - public void reload() { nativeReload(nativePtr); } - - public void setInputMethodContent(int unicodeChar) { nativeSetInputMethodContent(nativePtr, unicodeChar); } - - public void deleteInputMethodContent(int offset) { nativeDeleteInputMethodContent(nativePtr, offset); } - - public void evaluateJavascript(@NonNull String script, @Nullable WKCallback callback) { - nativeEvaluateJavascript(nativePtr, script, callback); - } - - protected final class PageSurfaceHolderCallback implements SurfaceHolder.Callback2 { - @Override - public void surfaceCreated(SurfaceHolder holder) { - Log.d(LOGTAG, "PageSurfaceHolderCallback::surfaceCreated()"); - nativeSurfaceCreated(nativePtr, holder.getSurface()); - } - - @Override - public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { - Log.d(LOGTAG, "PageSurfaceHolderCallback::surfaceChanged() with format: " + format + " and size: " + width + - " x " + height); - nativeSurfaceChanged(nativePtr, format, width, height); - } - - @Override - public void surfaceRedrawNeeded(SurfaceHolder holder) { - Log.d(LOGTAG, "PageSurfaceHolderCallback::surfaceRedrawNeeded()"); - nativeSurfaceRedrawNeeded(nativePtr); - } - - @Override - public void surfaceDestroyed(SurfaceHolder holder) { - Log.d(LOGTAG, "PageSurfaceHolderCallback::surfaceDestroyed()"); - nativeSurfaceDestroyed(nativePtr); - } - } - - protected final class PageScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener { - private float m_scaleFactor = 1.f; - - @Override - public boolean onScale(ScaleGestureDetector detector) { - Log.d(LOGTAG, "PageScaleListener::onScale()"); - - m_scaleFactor *= detector.getScaleFactor(); - m_scaleFactor = Math.max(0.1f, Math.min(m_scaleFactor, 5.0f)); - nativeSetZoomLevel(nativePtr, m_scaleFactor); - - ignoreTouchEvents = true; - return true; - } - } - - private final class PageSurfaceView extends SurfaceView { - public PageSurfaceView(Context context) { super(context); } - - @Override - @SuppressLint("ClickableViewAccessibility") - public boolean onTouchEvent(MotionEvent event) { - int pointerCount = event.getPointerCount(); - if (pointerCount < 1) - return false; - - scaleDetector.onTouchEvent(event); - if (ignoreTouchEvents) - ignoreTouchEvents = false; - - int eventType; - int eventAction = event.getActionMasked(); - switch (eventAction) { - case MotionEvent.ACTION_DOWN: - eventType = 0; - break; - case MotionEvent.ACTION_MOVE: - eventType = 1; - break; - - case MotionEvent.ACTION_UP: - eventType = 2; - break; + if (wpeViewClient != null) { + PageResourceRequest request = new PageResourceRequest(requestUri, requestMethod, requestHeaders); - default: - return false; + HashMap responseHeadersMap = new HashMap<>(); + int i = 0; + while (i < responseHeaders.length) { + responseHeadersMap.put(responseHeaders[i++], responseHeaders[i++]); } + WPEResourceResponse response = + new WPEResourceResponse(responseMimeType, responseStatusCode, responseHeadersMap); - nativeOnTouchEvent(nativePtr, event.getEventTime(), eventType, event.getX(0), event.getY(0)); - return true; + wpeViewClient.onReceivedHttpError(wpeView, request, response); } } + + private native long nativeInit(long nativeContextPtr, int width, int height, float deviceScale, boolean headless); + private native void nativeClose(long nativePtr); + private native void nativeDestroy(long nativePtr); + private native void nativeLoadUrl(long nativePtr, @NonNull String url); + private native void nativeLoadHtml(long nativePtr, @NonNull String content, @Nullable String baseUri); + private native double nativeGetEstimatedLoadProgress(long nativePtr); + private native void nativeGoBack(long nativePtr); + private native void nativeGoForward(long nativePtr); + private native void nativeStopLoading(long nativePtr); + private native void nativeReload(long nativePtr); + private native void nativeSurfaceCreated(long nativePtr, @NonNull Surface surface); + private native void nativeSurfaceChanged(long nativePtr, int format, int width, int height); + private native void nativeSurfaceRedrawNeeded(long nativePtr); + private native void nativeSurfaceDestroyed(long nativePtr); + private native void nativeSetZoomLevel(long nativePtr, double zoomLevel); + private native void nativeOnTouchEvent(long nativePtr, long time, int type, float x, float y); + private native void nativeSetInputMethodContent(long nativePtr, int unicodeChar); + private native void nativeDeleteInputMethodContent(long nativePtr, int offset); + private native void nativeRequestExitFullscreenMode(long nativePtr); + private native void nativeEvaluateJavascript(long nativePtr, String script, WKCallback callback); + private native void nativeScriptDialogClose(long nativeDialogPtr); + private native void nativeScriptDialogConfirm(long nativeDialogPtr, boolean confirm, @Nullable String text); } diff --git a/wpe/src/main/java/org/wpewebkit/wpeview/WPEView.java b/wpe/src/main/java/org/wpewebkit/wpeview/WPEView.java index d87d7dbce..156aee0ad 100644 --- a/wpe/src/main/java/org/wpewebkit/wpeview/WPEView.java +++ b/wpe/src/main/java/org/wpewebkit/wpeview/WPEView.java @@ -53,6 +53,7 @@ public class WPEView extends FrameLayout { private boolean ownsContext; private WKWebView wkWebView; + private SurfaceClient surfaceClient = null; public WPEView(@NonNull Context context) { super(context); @@ -82,120 +83,6 @@ private void init(@NonNull WPEContext context, boolean ownsContext, boolean head setDescendantFocusability(FOCUS_BLOCK_DESCENDANTS); } - private SurfaceView surfaceView = null; - private WPEViewClient wpeViewClient = null; - private WPEChromeClient wpeChromeClient = null; - private SurfaceClient surfaceClient = null; - private int currentLoadProgress = 0; - private String url = "about:blank"; - private String originalUrl = url; - private String title = url; - private FrameLayout customView = null; - - public void onPageSurfaceViewCreated(@NonNull SurfaceView view) { - Log.d(LOGTAG, - "onPageSurfaceViewCreated() for view: " + view + " (number of children: " + getChildCount() + ")"); - surfaceView = view; - - post(() -> { - // Add the view during the next UI cycle - try { - addView(view); - } catch (Exception e) { - Log.e(LOGTAG, "Error while adding the surface view", e); - } - }); - } - - public void onPageSurfaceViewReady(@NonNull SurfaceView view) { - Log.d(LOGTAG, "onPageSurfaceViewReady() for view: " + view + " (number of children: " + getChildCount() + ")"); - - // FIXME: Once PSON is enabled we may want to do something smarter here and not - // display the view until this point. - post(() -> { - if (wpeViewClient != null) - wpeViewClient.onViewReady(WPEView.this); - }); - } - - @Override - public boolean onKeyUp(int keyCode, @NonNull KeyEvent event) { - if (keyCode == KeyEvent.KEYCODE_DEL) { - wkWebView.deleteInputMethodContent(-1); - return true; - } - - KeyCharacterMap map = KeyCharacterMap.load(event.getDeviceId()); - wkWebView.setInputMethodContent(map.get(keyCode, event.getMetaState())); - return true; - } - - public void onLoadChanged(int loadEvent) { - switch (loadEvent) { - case WKWebView.LOAD_STARTED: - if (wpeViewClient != null) - wpeViewClient.onPageStarted(this, url); - break; - - case WKWebView.LOAD_FINISHED: - onLoadProgress(100); - if (wpeViewClient != null) - wpeViewClient.onPageFinished(this, url); - break; - } - } - - public void onClose() { - if (wpeChromeClient != null) - wpeChromeClient.onCloseWindow(this); - } - - public void onLoadProgress(double progress) { - currentLoadProgress = Math.max(0, Math.min(100, (int)Math.round(progress * 100))); - if (wpeChromeClient != null) - wpeChromeClient.onProgressChanged(this, currentLoadProgress); - } - - public void onUriChanged(@NonNull String uri) { url = uri; } - - public void onTitleChanged(@NonNull String title) { - this.title = title; - if (wpeChromeClient != null) - wpeChromeClient.onReceivedTitle(this, title); - } - - public void onEnterFullscreenMode() { - if ((surfaceView != null) && (wpeChromeClient != null)) { - removeView(surfaceView); - - customView = new FrameLayout(getContext()); - customView.addView(surfaceView); - customView.setFocusable(true); - customView.setFocusableInTouchMode(true); - - wpeChromeClient.onShowCustomView(customView, () -> { - if (customView != null) - wkWebView.requestExitFullscreenMode(); - }); - } - } - - public void onExitFullscreenMode() { - if ((customView != null) && (surfaceView != null) && (wpeChromeClient != null)) { - customView.removeView(surfaceView); - addView(surfaceView); - customView = null; - wpeChromeClient.onHideCustomView(); - } - } - - public void onReceivedHttpError(@NonNull WPEResourceRequest request, @NonNull WPEResourceResponse response) { - if (wpeViewClient != null) - wpeViewClient.onReceivedHttpError(this, request, response); - } - - /************** PUBLIC WPEView API *******************/ - /** * Destroys the internal state of this WebView. This method should be called * after this WebView has been removed from the view system. No other @@ -218,20 +105,14 @@ public void destroy() { * Loads the given URL. * @param url The URL of the resource to load. */ - public void loadUrl(@NonNull String url) { - originalUrl = url; - wkWebView.loadUrl(url); - } + public void loadUrl(@NonNull String url) { wkWebView.loadUrl(url); } /** * Loads an HTML page from its content. * @param content The HTML content to load. * @param baseUri The base URI for the content loaded. */ - public void loadHtml(@NonNull String content, @Nullable String baseUri) { - originalUrl = baseUri; - wkWebView.loadHtml(content, baseUri); - } + public void loadHtml(@NonNull String content, @Nullable String baseUri) { wkWebView.loadHtml(content, baseUri); } /** * Gets whether this WPEView has a back history item. @@ -269,38 +150,43 @@ public void loadHtml(@NonNull String content, @Nullable String baseUri) { * Gets loading progress for the current page. * @return the loading progress for the current page (between 0 and 100). */ - public int getProgress() { return currentLoadProgress; } + public int getProgress() { return wkWebView.getEstimatedLoadProgress(); } /** - * Gets current page title (until WebViewClient.onReceivedTitle is called). - * @return the title for the current page + * Gets the title for the current page. This is the title of the current page + * until WPEViewClient.onReceivedTitle is called. + * + * @return the title for the current page or {@code null} if no page has been loaded */ - public @NonNull String getTitle() { return title; } + public @Nullable String getTitle() { return wkWebView.getTitle(); } /** - * Get the url for the current page. This is not always the same as the url - * passed to WebViewClient.onPageStarted because although the load for - * that url has begun, the current page may not have changed. - * @return The url for the current page. + * Gets the URL for the current page. This is not always the same as the URL + * passed to WPEViewClient.onPageStarted because although the load for + * that URL has begun, the current page may not have changed. + * + * @return the URL for the current page or {@code null} if no page has been loaded */ - public @NonNull String getUrl() { return url; } + public @Nullable String getUrl() { return wkWebView.getUrl(); } /** - * Get the original url for the current page. This is not always the same - * as the url passed to WebViewClient.onPageStarted because although the - * load for that url has begun, the current page may not have changed. - * Also, there may have been redirects resulting in a different url to that + * Gets the original URL for the current page. This is not always the same + * as the URL passed to WPEViewClient.onPageStarted because although the + * load for that URL has begun, the current page may not have changed. + * Also, there may have been redirects resulting in a different URL to that * originally requested. - * @return The url that was originally requested for the current page. + * + * @return the URL that was originally requested for the current page or + * {@code null} if no page has been loaded */ - public @NonNull String getOriginalUrl() { return originalUrl; } + public @Nullable String getOriginalUrl() { return wkWebView.getOriginalUrl(); } /** * Gets the chrome handler. * @return the WPEChromeClient, or {@code null} if it has not been set yet. * @see #setWPEChromeClient */ - public @Nullable WPEChromeClient getWPEChromeClient() { return wpeChromeClient; } + public @Nullable WPEChromeClient getWPEChromeClient() { return wkWebView.getWPEChromeClient(); } /** * Sets the chrome handler. This is an implementation of WPEChromeClient for @@ -309,21 +195,24 @@ public void loadHtml(@NonNull String content, @Nullable String baseUri) { * @param client an implementation of WPEChromeClient * @see #getWPEChromeClient */ - public void setWPEChromeClient(@Nullable WPEChromeClient client) { wpeChromeClient = client; } + public void setWPEChromeClient(@Nullable WPEChromeClient client) { wkWebView.setWPEChromeClient(client); } /** * Gets the WPEViewClient. - * @return the WPEViewClient, or {@code null} if it has not been set yet. + * + * @return the WPEViewClient, or a default client if not yet set * @see #setWPEViewClient */ - public @Nullable WPEViewClient getWPEViewClient() { return wpeViewClient; } + public @NonNull WPEViewClient getWPEViewClient() { return wkWebView.getWPEViewClient(); } /** - * Set the WPEViewClient that will receive various notifications and + * Sets the WPEViewClient that will receive various notifications and * requests. This will replace the current handler. - * @param client An implementation of WPEViewClient. + * + * @param client an implementation of WPEViewClient + * @see #getWPEViewClient */ - public void setWPEViewClient(@Nullable WPEViewClient client) { wpeViewClient = client; } + public void setWPEViewClient(@NonNull WPEViewClient client) { wkWebView.setWPEViewClient(client); } /** * Gets the SurfaceClient. @@ -360,4 +249,16 @@ public void loadHtml(@NonNull String content, @Nullable String baseUri) { public void evaluateJavascript(@NonNull String script, @Nullable WPECallback resultCallback) { wkWebView.evaluateJavascript(script, WKCallback.fromWPECallback(resultCallback)); } + + @Override + public boolean onKeyUp(int keyCode, @NonNull KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_DEL) { + wkWebView.deleteInputMethodContent(-1); + return true; + } + + KeyCharacterMap map = KeyCharacterMap.load(event.getDeviceId()); + wkWebView.setInputMethodContent(map.get(keyCode, event.getMetaState())); + return true; + } } diff --git a/wpe/src/main/java/org/wpewebkit/wpeview/WPEViewClient.java b/wpe/src/main/java/org/wpewebkit/wpeview/WPEViewClient.java index 8e82071f1..663fa86c2 100644 --- a/wpe/src/main/java/org/wpewebkit/wpeview/WPEViewClient.java +++ b/wpe/src/main/java/org/wpewebkit/wpeview/WPEViewClient.java @@ -23,7 +23,7 @@ import androidx.annotation.NonNull; -public interface WPEViewClient { +public class WPEViewClient { /** * Notify the host application that a page has started loading. This method * is called once for each main frame load so a page with iframes or @@ -33,7 +33,7 @@ public interface WPEViewClient { * @param view The WPEView that is initiating the callback. * @param url The url to be loaded. */ - default void onPageStarted(@NonNull WPEView view, @NonNull String url) {} + public void onPageStarted(@NonNull WPEView view, @NonNull String url) {} /** * Notify the host application that a page has finished loading. This method @@ -41,13 +41,13 @@ default void onPageStarted(@NonNull WPEView view, @NonNull String url) {} * @param view The WPEView that is initiating the callback. * @param url The url of the page. */ - default void onPageFinished(@NonNull WPEView view, @NonNull String url) {} + public void onPageFinished(@NonNull WPEView view, @NonNull String url) {} /** * Notify the host application that the internal SurfaceView has been created * and it's ready to render to it's surface. */ - default void onViewReady(@NonNull WPEView view) {} + public void onViewReady(@NonNull WPEView view) {} /** * Notify the host application that an HTTP error has been received from the server while @@ -59,6 +59,6 @@ default void onViewReady(@NonNull WPEView view) {} * @param request The originating request. * @param errorResponse Information about the error occurred. */ - default void onReceivedHttpError(@NonNull WPEView view, @NonNull WPEResourceRequest request, - @NonNull WPEResourceResponse errorResponse) {} + public void onReceivedHttpError(@NonNull WPEView view, @NonNull WPEResourceRequest request, + @NonNull WPEResourceResponse errorResponse) {} }