diff --git a/gearslip/src/main/java/app/seb3thehacker/gearslip/browser/adblock/AdBlockManager.kt b/gearslip/src/main/java/app/seb3thehacker/gearslip/browser/adblock/AdBlockManager.kt index 7ad7b02..4d35992 100644 --- a/gearslip/src/main/java/app/seb3thehacker/gearslip/browser/adblock/AdBlockManager.kt +++ b/gearslip/src/main/java/app/seb3thehacker/gearslip/browser/adblock/AdBlockManager.kt @@ -71,6 +71,11 @@ object AdBlockManager { private val refreshRunning = AtomicBoolean(false) private val autoUpdateAttempted = AtomicBoolean(false) private val blockedCount = AtomicLong(0) + // Time spent deciding requests since the last page load, for the log line that tells whether + // the blocker is what makes a page or a video slow to start. + private val checkedCount = AtomicLong(0) + private val checkedNanos = AtomicLong(0) + private val blockedSincePage = AtomicLong(0) val isEngineReady: Boolean get() = engine != null val blockedRequestCount: Long get() = blockedCount.get() @@ -275,6 +280,27 @@ object AdBlockManager { */ fun response(request: WebResourceRequest, pageUrl: String?): WebResourceResponse? { if (!enabled) return null + // A ranged request is a video or audio stream fetching its next piece: ads never come + // that way, and a stream makes hundreds of them, so they skip the lists entirely. + if (request.requestHeaders?.keys?.any { it.equals("Range", ignoreCase = true) } == true) return null + val started = System.nanoTime() + try { + return decide(request, pageUrl) + } finally { + checkedCount.incrementAndGet() + checkedNanos.addAndGet(System.nanoTime() - started) + } + } + + /** Logs what the blocker cost the page that just finished loading, and starts counting afresh. */ + fun logPageCost(url: String?) { + val count = checkedCount.getAndSet(0) + val ms = checkedNanos.getAndSet(0) / 1_000_000 + val blocked = blockedSincePage.getAndSet(0) + if (count > 0) GearslipLog.i("adblock: $count requests checked in ${ms}ms, $blocked blocked, for ${url?.substringBefore('?')}") + } + + private fun decide(request: WebResourceRequest, pageUrl: String?): WebResourceResponse? { val current = engine ?: return null // Never interfere with top-level navigation: a mistake there costs the whole page. @@ -296,6 +322,7 @@ object AdBlockManager { }.getOrNull() ?: return null blockedCount.incrementAndGet() + blockedSincePage.incrementAndGet() return blockedResponse(request, match.redirectResource) } diff --git a/gearslip/src/main/java/app/seb3thehacker/gearslip/car/WebApp.kt b/gearslip/src/main/java/app/seb3thehacker/gearslip/car/WebApp.kt index ccede5a..1120e23 100644 --- a/gearslip/src/main/java/app/seb3thehacker/gearslip/car/WebApp.kt +++ b/gearslip/src/main/java/app/seb3thehacker/gearslip/car/WebApp.kt @@ -192,6 +192,11 @@ fun WebApp(content: String) { settings.domStorageEnabled = true settings.loadWithOverviewMode = true settings.useWideViewPort = true + // A video starts when the page asks, as in a normal browser. Left at Android's + // default, YouTube's player waits for a second tap before it will play. + settings.mediaPlaybackRequiresUserGesture = false + // Draws the page before it's on screen, so the first frame is ready sooner. + settings.offscreenPreRaster = true webViewClient = LoggingClient(ring, documentUrl, onStarted = { pageUrl = it }) { view -> canGoForward = view.canGoForward() pageUrl = view.url @@ -339,6 +344,7 @@ private class LoggingClient( override fun onPageFinished(view: WebView?, url: String?) { documentUrl.set(url) GearslipLog.i("car web page loaded: $url") + AdBlockManager.logPageCost(url) view?.let(onLoaded) view?.evaluateJavascript(FOCUS_TRACKING_JS, null) view?.evaluateJavascript(focusRingJs(ring), null)