package com.example.privateamazon import android.net.http.SslError import android.os.Bundle import android.view.View import android.webkit.CookieManager import android.webkit.SslErrorHandler import android.webkit.WebResourceRequest import android.webkit.WebResourceResponse import android.webkit.WebSettings import android.webkit.WebStorage import android.webkit.WebView import android.webkit.WebViewClient import androidx.activity.ComponentActivity import androidx.activity.OnBackPressedCallback import androidx.core.view.ViewCompat import androidx.core.view.WindowInsetsCompat import androidx.webkit.WebSettingsCompat import androidx.webkit.WebViewCompat import androidx.webkit.WebViewFeature import java.io.ByteArrayInputStream class MainActivity : ComponentActivity() { private lateinit var webView: WebView private val blockPatterns = mutableListOf() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 1. Fix Status Bar Overlay (Push app below the clock/battery) val mainContainer = findViewById(R.id.main_container) ViewCompat.setOnApplyWindowInsetsListener(mainContainer) { v, insets -> val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars()) v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom) insets } webView = findViewById(R.id.webview) // 2. Configure WebSettings val webSettings: WebSettings = webView.settings webSettings.javaScriptEnabled = true webSettings.domStorageEnabled = true webSettings.cacheMode = WebSettings.LOAD_DEFAULT webSettings.mixedContentMode = WebSettings.MIXED_CONTENT_NEVER_ALLOW // Privacy Hardening webSettings.allowFileAccess = false webSettings.allowContentAccess = false webSettings.setGeolocationEnabled(false) webSettings.userAgentString = "Mozilla/5.0 (Linux; Android 10; Mobile) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114 Mobile Safari/537.36" // 3. Feature Checks (Safe Browsing & Dark Mode) if (WebViewFeature.isFeatureSupported(WebViewFeature.START_SAFE_BROWSING)) { WebViewCompat.startSafeBrowsing(this) { } } if (WebViewFeature.isFeatureSupported(WebViewFeature.FORCE_DARK)) { WebSettingsCompat.setForceDark(webSettings, WebSettingsCompat.FORCE_DARK_ON) } // 4. --- COOKIE CONFIGURATION (STAY LOGGED IN) --- val cookieManager = CookieManager.getInstance() cookieManager.setAcceptCookie(true) cookieManager.setAcceptThirdPartyCookies(webView, false) // Block trackers, allow Amazon // ------------------------------------------------ // 5. Handle Back Button onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) { override fun handleOnBackPressed() { if (webView.canGoBack()) webView.goBack() else finish() } }) loadFilterList() // 6. Set up the WebView Client webView.webViewClient = object : WebViewClient() { override fun shouldInterceptRequest(view: WebView?, request: WebResourceRequest?): WebResourceResponse? { val req = request ?: return null val urlStr = req.url.toString().lowercase() // Block Trackers from filters.txt for (pattern in blockPatterns) { if (pattern.containsMatchIn(urlStr)) { return WebResourceResponse("text/plain", "utf-8", ByteArrayInputStream("".toByteArray())) } } // Block cleartext (Force HTTPS) if (urlStr.startsWith("http://")) { return WebResourceResponse("text/plain", "utf-8", ByteArrayInputStream("".toByteArray())) } return null } override fun onReceivedSslError(view: WebView?, handler: SslErrorHandler?, error: SslError?) { handler?.cancel() // Security: Don't allow bad SSL } override fun onPageFinished(view: WebView?, url: String?) { super.onPageFinished(view, url) // Save cookies to disk immediately after page loads CookieManager.getInstance().flush() injectPrivacyScript() } } // 7. Load Amazon with a custom header to hide the "App" identity val extraHeaders = mapOf("X-Requested-With" to "") webView.loadUrl("https://www.amazon.co.uk", extraHeaders) } private fun loadFilterList() { try { assets.open("filters.txt").bufferedReader().useLines { lines -> lines.map { it.trim() } .filter { it.isNotEmpty() && !it.startsWith("#") } .forEach { rule -> val escaped = rule.replace(".", "\\.").replace("*", ".*") blockPatterns.add(Regex(escaped, RegexOption.IGNORE_CASE)) } } } catch (_: Exception) {} } private fun injectPrivacyScript() { val js = """ (function() { try { navigator.sendBeacon = function(){ return true; }; window.RTCPeerConnection = null; window.webkitRTCPeerConnection = null; const getContext = HTMLCanvasElement.prototype.getContext; HTMLCanvasElement.prototype.getContext = function(type) { if (type.includes('webgl')) return null; return getContext.apply(this, arguments); }; } catch(_){} })(); """.trimIndent() webView.evaluateJavascript(js, null) } override fun onPause() { super.onPause() // Save cookies to disk when app goes to background CookieManager.getInstance().flush() } }