From 1edf177eb00c7535c7b22b98d917ce9277ea024c Mon Sep 17 00:00:00 2001 From: luisguzman-adfa Date: Wed, 24 Jun 2026 00:28:34 +0000 Subject: [PATCH 1/2] feat(portal): clean-arch slice for the WebView portal + GestureWebView MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit New org.iiab.controller.portal slice (no behavior change until wired): - domain: NavigationPolicy (internal vs external host) + PortalUrlResolver (target URL with local fallback). Pure JVM, unit-tested. - data: WebViewProxyConfigurator (SOCKS proxy override adapter). - presentation: PortalUiState + PortalViewModel (load state survives rotation), and GestureWebView — a WebView that guarantees multi-finger delivery (requestDisallowInterceptTouchEvent on 2+ pointers) for map tilt, with optional gesture logging for diagnostics. --- .../portal/data/WebViewProxyConfigurator.java | 38 ++++++++++++ .../portal/domain/NavigationPolicy.java | 31 ++++++++++ .../portal/domain/PortalUrlResolver.java | 26 +++++++++ .../portal/presentation/GestureWebView.java | 58 +++++++++++++++++++ .../portal/presentation/PortalUiState.java | 22 +++++++ .../portal/presentation/PortalViewModel.java | 41 +++++++++++++ .../portal/domain/NavigationPolicyTest.java | 23 ++++++++ .../portal/domain/PortalUrlResolverTest.java | 19 ++++++ 8 files changed, 258 insertions(+) create mode 100644 controller/app/src/main/java/org/iiab/controller/portal/data/WebViewProxyConfigurator.java create mode 100644 controller/app/src/main/java/org/iiab/controller/portal/domain/NavigationPolicy.java create mode 100644 controller/app/src/main/java/org/iiab/controller/portal/domain/PortalUrlResolver.java create mode 100644 controller/app/src/main/java/org/iiab/controller/portal/presentation/GestureWebView.java create mode 100644 controller/app/src/main/java/org/iiab/controller/portal/presentation/PortalUiState.java create mode 100644 controller/app/src/main/java/org/iiab/controller/portal/presentation/PortalViewModel.java create mode 100644 controller/app/src/test/java/org/iiab/controller/portal/domain/NavigationPolicyTest.java create mode 100644 controller/app/src/test/java/org/iiab/controller/portal/domain/PortalUrlResolverTest.java diff --git a/controller/app/src/main/java/org/iiab/controller/portal/data/WebViewProxyConfigurator.java b/controller/app/src/main/java/org/iiab/controller/portal/data/WebViewProxyConfigurator.java new file mode 100644 index 0000000..4c876bf --- /dev/null +++ b/controller/app/src/main/java/org/iiab/controller/portal/data/WebViewProxyConfigurator.java @@ -0,0 +1,38 @@ +/* + * ============================================================================ + * Name : WebViewProxyConfigurator.java + * Author : AppDevForAll + * Copyright : Copyright (c) 2026 AppDevForAll + * Description : Wraps WebView SOCKS proxy override (VPN) behind a small adapter. + * ============================================================================ + */ +package org.iiab.controller.portal.data; + +import androidx.webkit.ProxyConfig; +import androidx.webkit.ProxyController; +import androidx.webkit.WebViewFeature; + +import java.util.concurrent.Executor; + +/** Thin adapter over androidx ProxyController for the portal's SOCKS proxy. */ +public final class WebViewProxyConfigurator { + + private WebViewProxyConfigurator() {} + + public static boolean isSupported() { + return WebViewFeature.isFeatureSupported(WebViewFeature.PROXY_OVERRIDE); + } + + /** Route WebView traffic through socks5://127.0.0.1:{port}; runs {@code onReady} when applied. */ + public static void applySocks(int port, Executor executor, Runnable onReady) { + ProxyConfig config = new ProxyConfig.Builder() + .addProxyRule("socks5://127.0.0.1:" + port) + .build(); + ProxyController.getInstance().setProxyOverride(config, executor, onReady); + } + + /** Remove any proxy override (call on teardown). */ + public static void clear(Runnable onCleared) { + ProxyController.getInstance().clearProxyOverride(Runnable::run, onCleared); + } +} diff --git a/controller/app/src/main/java/org/iiab/controller/portal/domain/NavigationPolicy.java b/controller/app/src/main/java/org/iiab/controller/portal/domain/NavigationPolicy.java new file mode 100644 index 0000000..4d9e49a --- /dev/null +++ b/controller/app/src/main/java/org/iiab/controller/portal/domain/NavigationPolicy.java @@ -0,0 +1,31 @@ +/* + * ============================================================================ + * Name : NavigationPolicy.java + * Author : AppDevForAll + * Copyright : Copyright (c) 2026 AppDevForAll + * Description : Decides whether a URL stays in the WebView (local IIAB server) or opens externally. + * ============================================================================ + */ +package org.iiab.controller.portal.domain; + +/** + * Pure navigation policy for the portal WebView. Hosts served by the on-device + * IIAB server are kept inside the WebView; everything else is "external" and + * should be handed to the system browser. + */ +public final class NavigationPolicy { + + private NavigationPolicy() {} + + /** True if {@code host} is served by the local IIAB server (stay in WebView). */ + public static boolean isInternalHost(String host) { + if (host == null) return false; + String h = host.trim().toLowerCase(); + return h.equals("box") || h.equals("localhost") || h.equals("127.0.0.1"); + } + + /** Inverse of {@link #isInternalHost(String)} — should open in an external app. */ + public static boolean isExternalHost(String host) { + return !isInternalHost(host); + } +} diff --git a/controller/app/src/main/java/org/iiab/controller/portal/domain/PortalUrlResolver.java b/controller/app/src/main/java/org/iiab/controller/portal/domain/PortalUrlResolver.java new file mode 100644 index 0000000..353e153 --- /dev/null +++ b/controller/app/src/main/java/org/iiab/controller/portal/domain/PortalUrlResolver.java @@ -0,0 +1,26 @@ +/* + * ============================================================================ + * Name : PortalUrlResolver.java + * Author : AppDevForAll + * Copyright : Copyright (c) 2026 AppDevForAll + * Description : Resolves the portal target URL, falling back to the local home page. + * ============================================================================ + */ +package org.iiab.controller.portal.domain; + +/** Resolves the URL the portal should open, with a safe local fallback. */ +public final class PortalUrlResolver { + + /** Local IIAB home, used when no target URL is supplied. */ + public static final String DEFAULT_URL = "http://localhost:8085/home"; + + private PortalUrlResolver() {} + + /** Returns {@code rawUrl} when usable, otherwise {@link #DEFAULT_URL}. */ + public static String resolve(String rawUrl) { + if (rawUrl == null || rawUrl.trim().isEmpty()) { + return DEFAULT_URL; + } + return rawUrl; + } +} diff --git a/controller/app/src/main/java/org/iiab/controller/portal/presentation/GestureWebView.java b/controller/app/src/main/java/org/iiab/controller/portal/presentation/GestureWebView.java new file mode 100644 index 0000000..cb43b0c --- /dev/null +++ b/controller/app/src/main/java/org/iiab/controller/portal/presentation/GestureWebView.java @@ -0,0 +1,58 @@ +/* + * ============================================================================ + * Name : GestureWebView.java + * Author : AppDevForAll + * Copyright : Copyright (c) 2026 AppDevForAll + * Description : WebView subclass that guarantees multi-touch delivery (map tilt) + optional gesture logging. + * ============================================================================ + */ +package org.iiab.controller.portal.presentation; + +import android.content.Context; +import android.util.AttributeSet; +import android.util.Log; +import android.view.MotionEvent; +import android.view.ViewParent; +import android.webkit.WebView; + +/** + * WebView that ensures multi-finger gestures (e.g. two-finger drag = map tilt in + * MapLibre) reach the web content: + * - while 2+ pointers are down it asks ancestors NOT to intercept the gesture, + * so no parent scroll/swipe steals it; + * - optional debug logging reports pointer counts to logcat (TAG below), which — + * together with the page's console touch logging — pinpoints where a gesture is lost. + */ +public class GestureWebView extends WebView { + + public static final String TAG = "IIAB-GestureWV"; + + private boolean gestureLogging = false; + + public GestureWebView(Context context) { super(context); } + public GestureWebView(Context context, AttributeSet attrs) { super(context, attrs); } + public GestureWebView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } + + /** Enable verbose touch logging (debug builds only). */ + public void setGestureLogging(boolean enabled) { this.gestureLogging = enabled; } + + @Override + public boolean onTouchEvent(MotionEvent event) { + final int pointers = event.getPointerCount(); + + // Two or more fingers: keep the gesture for the web content (the map), + // so an ancestor (pager/scroll) can't hijack a tilt/rotate/pinch. + if (pointers >= 2) { + ViewParent parent = getParent(); + if (parent != null) { + parent.requestDisallowInterceptTouchEvent(true); + } + } + + if (gestureLogging) { + Log.d(TAG, "onTouchEvent action=" + event.getActionMasked() + " pointers=" + pointers); + } + + return super.onTouchEvent(event); + } +} diff --git a/controller/app/src/main/java/org/iiab/controller/portal/presentation/PortalUiState.java b/controller/app/src/main/java/org/iiab/controller/portal/presentation/PortalUiState.java new file mode 100644 index 0000000..24ef378 --- /dev/null +++ b/controller/app/src/main/java/org/iiab/controller/portal/presentation/PortalUiState.java @@ -0,0 +1,22 @@ +/* + * ============================================================================ + * Name : PortalUiState.java + * Author : AppDevForAll + * Copyright : Copyright (c) 2026 AppDevForAll + * Description : Immutable UI state for the portal screen (page load status). + * ============================================================================ + */ +package org.iiab.controller.portal.presentation; + +/** Minimal portal UI state: whether the WebView is currently loading a page. */ +public final class PortalUiState { + + public final boolean loading; + + public PortalUiState(boolean loading) { + this.loading = loading; + } + + public static PortalUiState idle() { return new PortalUiState(false); } + public static PortalUiState loading() { return new PortalUiState(true); } +} diff --git a/controller/app/src/main/java/org/iiab/controller/portal/presentation/PortalViewModel.java b/controller/app/src/main/java/org/iiab/controller/portal/presentation/PortalViewModel.java new file mode 100644 index 0000000..ec6f221 --- /dev/null +++ b/controller/app/src/main/java/org/iiab/controller/portal/presentation/PortalViewModel.java @@ -0,0 +1,41 @@ +/* + * ============================================================================ + * Name : PortalViewModel.java + * Author : AppDevForAll + * Copyright : Copyright (c) 2026 AppDevForAll + * Description : Holds portal load state + resolved target URL across configuration changes. + * ============================================================================ + */ +package org.iiab.controller.portal.presentation; + +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; +import androidx.lifecycle.ViewModel; + +import org.iiab.controller.portal.domain.PortalUrlResolver; + +/** Survives rotation: keeps the resolved target URL and the page-load state. */ +public class PortalViewModel extends ViewModel { + + private final MutableLiveData state = new MutableLiveData<>(PortalUiState.idle()); + private String targetUrl; + + public LiveData state() { return state; } + + public boolean isLoading() { + PortalUiState s = state.getValue(); + return s != null && s.loading; + } + + public void setLoading(boolean loading) { + state.setValue(loading ? PortalUiState.loading() : PortalUiState.idle()); + } + + /** Resolve once and remember; subsequent calls keep the first resolved value. */ + public String targetUrl(String rawUrl) { + if (targetUrl == null) { + targetUrl = PortalUrlResolver.resolve(rawUrl); + } + return targetUrl; + } +} diff --git a/controller/app/src/test/java/org/iiab/controller/portal/domain/NavigationPolicyTest.java b/controller/app/src/test/java/org/iiab/controller/portal/domain/NavigationPolicyTest.java new file mode 100644 index 0000000..aedb51d --- /dev/null +++ b/controller/app/src/test/java/org/iiab/controller/portal/domain/NavigationPolicyTest.java @@ -0,0 +1,23 @@ +package org.iiab.controller.portal.domain; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +/** Pure-JVM tests for the portal navigation policy. */ +public class NavigationPolicyTest { + + @Test public void localHostsAreInternal() { + assertTrue(NavigationPolicy.isInternalHost("box")); + assertTrue(NavigationPolicy.isInternalHost("localhost")); + assertTrue(NavigationPolicy.isInternalHost("127.0.0.1")); + assertTrue(NavigationPolicy.isInternalHost("LocalHost")); // case-insensitive + } + + @Test public void remoteHostsAreExternal() { + assertTrue(NavigationPolicy.isExternalHost("youtube.com")); + assertTrue(NavigationPolicy.isExternalHost("example.org")); + assertFalse(NavigationPolicy.isInternalHost(null)); + } +} diff --git a/controller/app/src/test/java/org/iiab/controller/portal/domain/PortalUrlResolverTest.java b/controller/app/src/test/java/org/iiab/controller/portal/domain/PortalUrlResolverTest.java new file mode 100644 index 0000000..cdc6bc1 --- /dev/null +++ b/controller/app/src/test/java/org/iiab/controller/portal/domain/PortalUrlResolverTest.java @@ -0,0 +1,19 @@ +package org.iiab.controller.portal.domain; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +/** Pure-JVM tests for portal URL resolution. */ +public class PortalUrlResolverTest { + + @Test public void blankFallsBackToDefault() { + assertEquals(PortalUrlResolver.DEFAULT_URL, PortalUrlResolver.resolve(null)); + assertEquals(PortalUrlResolver.DEFAULT_URL, PortalUrlResolver.resolve("")); + assertEquals(PortalUrlResolver.DEFAULT_URL, PortalUrlResolver.resolve(" ")); + } + + @Test public void validUrlIsKept() { + assertEquals("http://box/maps/", PortalUrlResolver.resolve("http://box/maps/")); + } +} From 5370d816174b3bcfeb031263482107d507af10b1 Mon Sep 17 00:00:00 2001 From: luisguzman-adfa Date: Wed, 24 Jun 2026 00:28:34 +0000 Subject: [PATCH 2/2] refactor(portal): wire PortalActivity to the slice + two-finger gesture support - layout uses GestureWebView; PortalActivity slims down onto the slice (NavigationPolicy, PortalUrlResolver, WebViewProxyConfigurator, PortalViewModel). - two-finger gestures (map tilt) now reach the map; debug gesture logging on. - inject a touch probe on page load: logs touch-point counts via onConsoleMessage (-> logcat) to diagnose lost gestures, and best-effort enables MapLibre pitch. --- .../org/iiab/controller/PortalActivity.java | 131 +++++++++--------- .../src/main/res/layout/activity_portal.xml | 2 +- 2 files changed, 65 insertions(+), 68 deletions(-) diff --git a/controller/app/src/main/java/org/iiab/controller/PortalActivity.java b/controller/app/src/main/java/org/iiab/controller/PortalActivity.java index 6f88f1e..90b6d6c 100644 --- a/controller/app/src/main/java/org/iiab/controller/PortalActivity.java +++ b/controller/app/src/main/java/org/iiab/controller/PortalActivity.java @@ -15,9 +15,7 @@ import androidx.appcompat.app.AppCompatActivity; import androidx.core.content.ContextCompat; -import androidx.webkit.ProxyConfig; -import androidx.webkit.ProxyController; -import androidx.webkit.WebViewFeature; +import androidx.lifecycle.ViewModelProvider; import java.util.concurrent.Executor; @@ -29,10 +27,33 @@ import android.os.Handler; import android.os.Looper; +import org.iiab.controller.portal.data.WebViewProxyConfigurator; +import org.iiab.controller.portal.domain.NavigationPolicy; +import org.iiab.controller.portal.presentation.GestureWebView; +import org.iiab.controller.portal.presentation.PortalViewModel; + public class PortalActivity extends AppCompatActivity { private static final String TAG = "IIAB-Portal"; - private WebView webView; - private boolean isPageLoading = false; + + /** + * Injected after each page load. (1) logs touch-point counts the web content + * receives (captured via onConsoleMessage -> logcat) so a lost multi-finger + * gesture can be diagnosed; (2) best-effort enables MapLibre two-finger pitch + * if a map instance is exposed on the page. + */ + private static final String TOUCH_PROBE_JS = + "(function(){if(window.__iiabTouchProbe)return;window.__iiabTouchProbe=true;" + + "['touchstart','touchmove'].forEach(function(t){document.addEventListener(t,function(e){" + + "try{console.log('IIAB-TOUCH '+t+' touches='+(e.touches?e.touches.length:0));}catch(_){}}," + + "{passive:true,capture:true});});" + + "try{var m=window.map||window.__map||(window.maplibregl&&window.maplibregl.__map);" + + "if(m&&m.touchPitch&&m.touchPitch.enable){m.touchPitch.enable();" + + "if(m.touchZoomRotate&&m.touchZoomRotate.enable){m.touchZoomRotate.enable();}" + + "console.log('IIAB-TOUCH pitch-enabled');}else{console.log('IIAB-TOUCH no-map-instance');}}" + + "catch(err){console.log('IIAB-TOUCH pitch-error '+err);}})();"; + + private GestureWebView webView; + private PortalViewModel vm; private android.webkit.ValueCallback filePathCallback; private final static int FILECHOOSER_RESULTCODE = 100; @@ -41,8 +62,11 @@ protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_portal); + vm = new ViewModelProvider(this).get(PortalViewModel.class); + // 1. Basic WebView configuration webView = findViewById(R.id.myWebView); + webView.setGestureLogging(BuildConfig.DEBUG); LinearLayout bottomNav = findViewById(R.id.bottomNav); Button btnHandle = findViewById(R.id.btnHandle); // The new handle @@ -55,39 +79,32 @@ protected void onCreate(Bundle savedInstanceState) { Button btnForward = findViewById(R.id.btnForward); // --- PREPARE HIDDEN BAR --- - // Wait for Android to draw the screen to determine bar height - // and hide it exactly below the bottom edge. bottomNav.post(() -> { bottomNav.setTranslationY(bottomNav.getHeight()); // Move outside the screen - bottomNav.setVisibility(View.VISIBLE); // Remove invisibility + bottomNav.setVisibility(View.VISIBLE); }); // --- AUTO-HIDE TIMER --- Handler hideHandler = new Handler(Looper.getMainLooper()); - // This is the hiding action packaged for later use Runnable hideRunnable = () -> { bottomNav.animate().translationY(bottomNav.getHeight()).setDuration(250); btnHandle.setVisibility(View.VISIBLE); btnHandle.animate().alpha(1f).setDuration(150); }; - // --- Restart timer --- Runnable resetTimer = () -> { hideHandler.removeCallbacks(hideRunnable); - hideHandler.postDelayed(hideRunnable, 5000); // Restarts new 5 sec + hideHandler.postDelayed(hideRunnable, 5000); }; // --- HANDLE LOGIC (Show Bar) --- btnHandle.setOnClickListener(v -> { - // 1. Animate entry btnHandle.animate().alpha(0f).setDuration(150).withEndAction(() -> btnHandle.setVisibility(View.GONE)); bottomNav.animate().translationY(0).setDuration(250); - - // 2. Starts countdown resetTimer.run(); }); - // Button actions + btnBack.setOnClickListener(v -> { if (webView.canGoBack()) webView.goBack(); resetTimer.run(); @@ -101,15 +118,8 @@ protected void onCreate(Bundle savedInstanceState) { Preferences prefs = new Preferences(this); boolean isVpnActive = prefs.getEnable(); - String rawUrl = getIntent().getStringExtra("TARGET_URL"); - - // If for some strange reason the URL arrives empty, we use the security fallback - if (rawUrl == null || rawUrl.isEmpty()) { - rawUrl = "http://localhost:8085/home"; - } - - // We are giving the URL secure global reach for all lambdas from now on - final String finalTargetUrl = rawUrl; + // Resolve the target URL once (domain), surviving rotation via the ViewModel. + final String finalTargetUrl = vm.targetUrl(getIntent().getStringExtra("TARGET_URL")); btnHome.setOnClickListener(v -> { webView.loadUrl(finalTargetUrl); @@ -118,63 +128,57 @@ protected void onCreate(Bundle savedInstanceState) { // Dual logic: Forced reload or Stop btnReload.setOnClickListener(v -> { - if (isPageLoading) { + if (vm.isLoading()) { webView.stopLoading(); } else { - // Disable cache temporarily webView.getSettings().setCacheMode(android.webkit.WebSettings.LOAD_NO_CACHE); - // Force download from scratch webView.clearCache(true); webView.reload(); } resetTimer.run(); }); - // --- NEW: DETECT LOADING TO CHANGE BUTTON TO 'X' --- webView.setWebViewClient(new WebViewClient() { @Override public boolean shouldOverrideUrlLoading(WebView view, android.webkit.WebResourceRequest request) { String url = request.getUrl().toString(); String host = request.getUrl().getHost(); - // Internal server link (Box) - if (host != null && (host.equals("box") || host.equals("127.0.0.1") || host.equals("localhost"))) { - return false; // Remains in our app and travels through the proxy + // Internal server link stays in the WebView (and travels through the proxy). + if (NavigationPolicy.isInternalHost(host)) { + return false; } - // External link (Real Internet) + // External link: hand to the system browser / appropriate app. try { - // Tell Android to find the correct app to open this (Chrome, YouTube, etc.) - Intent intent = new Intent(Intent.ACTION_VIEW, request.getUrl()); - startActivity(intent); + startActivity(new Intent(Intent.ACTION_VIEW, request.getUrl())); } catch (Exception e) { Log.e(TAG, "No app installed to open: " + url); } - - return true; // return true means: "WebView, I'll handle it, you ignore this click" + return true; } @Override public void onPageStarted(WebView view, String url, Bitmap favicon) { super.onPageStarted(view, url, favicon); - isPageLoading = true; + vm.setLoading(true); btnReload.setText("✕"); // Change to Stop } @Override public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); - isPageLoading = false; + vm.setLoading(false); btnReload.setText("↻"); // Back to Reload - - // Restore cache for normal browsing speed view.getSettings().setCacheMode(android.webkit.WebSettings.LOAD_DEFAULT); + + // Touch diagnostics + best-effort MapLibre pitch enablement. + view.evaluateJavascript(TOUCH_PROBE_JS, null); } @Override public void onReceivedError(WebView view, android.webkit.WebResourceRequest request, android.webkit.WebResourceError error) { super.onReceivedError(view, request, error); - if (request.isForMainFrame()) { String customErrorHtml = "" + "

⚠️ Connection Failed

" @@ -182,7 +186,7 @@ public void onReceivedError(WebView view, android.webkit.WebResourceRequest requ + "

Error: " + error.getDescription() + "

" + ""; view.loadData(customErrorHtml, "text/html", "UTF-8"); - isPageLoading = false; + vm.setLoading(false); btnReload.setText("↻"); } } @@ -190,12 +194,12 @@ public void onReceivedError(WebView view, android.webkit.WebResourceRequest requ // --- MANUALLY CLOSE BAR LOGIC --- btnHideNav.setOnClickListener(v -> { - hideHandler.removeCallbacks(hideRunnable); // Cancel the timer so it doesn't conflict - hideRunnable.run(); // Execute hiding action immediately + hideHandler.removeCallbacks(hideRunnable); + hideRunnable.run(); }); - // <-- EXIT ACTION --> btnExit.setOnClickListener(v -> finish()); + webView.getSettings().setJavaScriptEnabled(true); webView.getSettings().setDomStorageEnabled(true); webView.setWebChromeClient(new android.webkit.WebChromeClient() { @@ -215,48 +219,43 @@ public boolean onShowFileChooser(WebView webView, android.webkit.ValueCallback { + WebViewProxyConfigurator.applySocks(finalProxyPort, executor, () -> { Log.d(TAG, "Proxy configured on port: " + finalProxyPort); - // Load HTML only when proxy is ready - webView.loadUrl(finalTargetUrl); + webView.loadUrl(finalTargetUrl); // load only when proxy is ready }); } else { - // Fallback for older devices Log.w(TAG, "Proxy Override not supported"); webView.loadUrl(finalTargetUrl); } } else { - // VPN is OFF. Do NOT use proxy. Just load localhost directly. + // VPN is OFF. Load localhost directly. webView.loadUrl(finalTargetUrl); } } - // Cleanup (Important to not leave the proxy active) @Override protected void onDestroy() { super.onDestroy(); - if (WebViewFeature.isFeatureSupported(WebViewFeature.PROXY_OVERRIDE)) { - ProxyController.getInstance().clearProxyOverride(Runnable::run, () -> { - Log.d(TAG, "WebView proxy released"); - }); + if (WebViewProxyConfigurator.isSupported()) { + WebViewProxyConfigurator.clear(() -> Log.d(TAG, "WebView proxy released")); } } @@ -275,7 +274,6 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (filePathCallback == null) return; android.net.Uri[] results = null; - if (resultCode == RESULT_OK && data != null) { String dataString = data.getDataString(); if (dataString != null) { @@ -288,7 +286,6 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) { } } } - filePathCallback.onReceiveValue(results); filePathCallback = null; } else { diff --git a/controller/app/src/main/res/layout/activity_portal.xml b/controller/app/src/main/res/layout/activity_portal.xml index d14c60e..cd88157 100644 --- a/controller/app/src/main/res/layout/activity_portal.xml +++ b/controller/app/src/main/res/layout/activity_portal.xml @@ -6,7 +6,7 @@ -