From d90cb9b61cd2e033b46f4780ad1340c5f35b7751 Mon Sep 17 00:00:00 2001 From: Allan Wang Date: Sun, 16 Jul 2017 17:26:58 -0700 Subject: Add image viewing and downloading (#63) * Commence aggressive image caching * Add glide toggle and css url parsing * Add image hook and refractor activities * Update version analytics * Implemented imageactivity but glide will not load * Create working image loader * Finalize image view * Finalize image view logic * Remove custom cache experiment --- .../com/pitchedapps/frost/web/BaseWebViewClient.kt | 16 ++++++ .../com/pitchedapps/frost/web/FrostChromeClient.kt | 16 ++++-- .../kotlin/com/pitchedapps/frost/web/FrostJSI.kt | 31 +++++++--- .../frost/web/FrostRequestInterceptor.kt | 67 ++++++++++++++++++++++ .../com/pitchedapps/frost/web/FrostWebView.kt | 2 +- .../pitchedapps/frost/web/FrostWebViewClient.kt | 21 +++---- .../com/pitchedapps/frost/web/FrostWebViewCore.kt | 13 +++-- .../pitchedapps/frost/web/FrostWebViewSearch.kt | 18 ++++-- .../com/pitchedapps/frost/web/LoginWebView.kt | 4 +- 9 files changed, 148 insertions(+), 40 deletions(-) create mode 100644 app/src/main/kotlin/com/pitchedapps/frost/web/BaseWebViewClient.kt create mode 100644 app/src/main/kotlin/com/pitchedapps/frost/web/FrostRequestInterceptor.kt (limited to 'app/src/main/kotlin/com/pitchedapps/frost/web') diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/BaseWebViewClient.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/BaseWebViewClient.kt new file mode 100644 index 00000000..09241254 --- /dev/null +++ b/app/src/main/kotlin/com/pitchedapps/frost/web/BaseWebViewClient.kt @@ -0,0 +1,16 @@ +package com.pitchedapps.frost.web + +import android.webkit.WebResourceRequest +import android.webkit.WebResourceResponse +import android.webkit.WebView +import android.webkit.WebViewClient + +/** + * Created by Allan Wang on 2017-07-13. + */ +open class BaseWebViewClient : WebViewClient() { + + override fun shouldInterceptRequest(view: WebView, request: WebResourceRequest): WebResourceResponse? + = shouldFrostInterceptRequest(view, request) + +} \ No newline at end of file diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostChromeClient.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostChromeClient.kt index aab3a165..4df6d6a7 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostChromeClient.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostChromeClient.kt @@ -1,9 +1,10 @@ package com.pitchedapps.frost.web import android.net.Uri -import android.os.Message -import android.view.View -import android.webkit.* +import android.webkit.ConsoleMessage +import android.webkit.ValueCallback +import android.webkit.WebChromeClient +import android.webkit.WebView import ca.allanwang.kau.utils.snackbar import com.pitchedapps.frost.contracts.ActivityWebContract import com.pitchedapps.frost.utils.L @@ -20,9 +21,16 @@ class FrostChromeClient(webCore: FrostWebViewCore) : WebChromeClient() { val titleObservable: BehaviorSubject = webCore.titleObservable val activityContract = (webCore.context as? ActivityWebContract) + companion object { + val consoleBlacklist = setOf( + "edge-chat" + ) + } + override fun onConsoleMessage(consoleMessage: ConsoleMessage): Boolean { + if (consoleBlacklist.any { consoleMessage.message().contains(it) }) return true L.i("Chrome Console ${consoleMessage.lineNumber()}: ${consoleMessage.message()}") - return super.onConsoleMessage(consoleMessage) + return true } override fun onReceivedTitle(view: WebView, title: String) { diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostJSI.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostJSI.kt index 3340e7d2..3f976fb8 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostJSI.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostJSI.kt @@ -2,8 +2,9 @@ package com.pitchedapps.frost.web import android.content.Context import android.webkit.JavascriptInterface -import ca.allanwang.kau.logging.KL -import com.pitchedapps.frost.MainActivity +import ca.allanwang.kau.utils.startActivity +import com.pitchedapps.frost.activities.ImageActivity +import com.pitchedapps.frost.activities.MainActivity import com.pitchedapps.frost.dbflow.CookieModel import com.pitchedapps.frost.facebook.formattedFbUrl import com.pitchedapps.frost.utils.* @@ -13,12 +14,18 @@ import io.reactivex.subjects.Subject /** * Created by Allan Wang on 2017-06-01. */ -class FrostJSI(val context: Context, val webView: FrostWebViewCore) { +class FrostJSI(val webView: FrostWebViewCore) { - val headerObservable: Subject? = (context as? MainActivity)?.headerBadgeObservable + val context: Context + get() = webView.context + + val activity: MainActivity? + get() = (context as? MainActivity) + + val headerObservable: Subject? = activity?.headerBadgeObservable val cookies: ArrayList - get() = (context as? MainActivity)?.cookies() ?: arrayListOf() + get() = activity?.cookies() ?: arrayListOf() @JavascriptInterface fun loadUrl(url: String) { @@ -35,8 +42,8 @@ class FrostJSI(val context: Context, val webView: FrostWebViewCore) { } @JavascriptInterface - fun contextMenu(url: String, text: String) { - webView.post { webView.context.showWebContextMenu(WebContext(url.formattedFbUrl, text)) } + fun contextMenu(url: String, text: String?) { + webView.post { context.showWebContextMenu(WebContext(url.formattedFbUrl, text)) } } /** @@ -45,7 +52,7 @@ class FrostJSI(val context: Context, val webView: FrostWebViewCore) { */ @JavascriptInterface fun longClick(start: Boolean) { - (webView.context as? MainActivity)?.viewPager?.enableSwipe = !start + activity?.viewPager?.enableSwipe = !start } @JavascriptInterface @@ -53,6 +60,14 @@ class FrostJSI(val context: Context, val webView: FrostWebViewCore) { context.launchLogin(cookies, true) } + /** + * Launch image overlay + */ + @JavascriptInterface + fun loadImage(imageUrl: String, text: String?) { + context.launchImageActivity(imageUrl, text) + } + @JavascriptInterface fun emit(flag: Int) { webView.post { webView.frostWebClient.emit(flag) } diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostRequestInterceptor.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostRequestInterceptor.kt new file mode 100644 index 00000000..45dc83aa --- /dev/null +++ b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostRequestInterceptor.kt @@ -0,0 +1,67 @@ +package com.pitchedapps.frost.web + +import android.graphics.Bitmap.CompressFormat +import android.webkit.WebResourceRequest +import android.webkit.WebResourceResponse +import android.webkit.WebView +import ca.allanwang.kau.utils.use +import com.pitchedapps.frost.utils.GlideApp +import com.pitchedapps.frost.utils.L +import com.pitchedapps.frost.utils.Prefs +import okhttp3.HttpUrl +import java.io.ByteArrayInputStream +import java.io.ByteArrayOutputStream +import java.io.InputStream + + +/** + * Created by Allan Wang on 2017-07-13. + * + * Handler to decide when a request should be done by us + * This is the crux of Frost's optimizations for the web browser + */ +val blankResource: WebResourceResponse by lazy { WebResourceResponse("text/plain", "utf-8", ByteArrayInputStream("".toByteArray())) } + +//these hosts will redirect to a blank resource +val blacklistHost: Set by lazy { + setOf( + "edge-chat.facebook.com" + ) +} + +//these hosts will return null and skip logging +val whitelistHost: Set by lazy { + setOf( + "static.xx.fbcdn.net", + "m.facebook.com", + "touch.facebook.com" + ) +} + +//these hosts will skip ad inspection +//this list does not have to include anything from the two above +val adWhitelistHost: Set by lazy { + setOf( + "scontent-sea1-1.xx.fbcdn.net" + ) +} + +var adblock: Set? = null + +fun shouldFrostInterceptRequest(view: WebView, request: WebResourceRequest): WebResourceResponse? { + val httpUrl = HttpUrl.parse(request.url?.toString() ?: return null) ?: return null + val host = httpUrl.host() + val url = httpUrl.toString() + if (blacklistHost.contains(host)) return blankResource + if (whitelistHost.contains(host)) return null + if (!adWhitelistHost.contains(host)) { + if (adblock == null) adblock = view.context.assets.open("adblock.txt").bufferedReader().use { it.readLines().toSet() } + if (adblock?.any { url.contains(it) } ?: false) return blankResource + } + L.v("Intercept Request ${host} ${url}") + return null +} + +fun WebResourceResponse?.filterCss(request: WebResourceRequest): WebResourceResponse? + = this ?: if (request.url.path.endsWith(".css")) blankResource else null + diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebView.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebView.kt index 7c0a6597..e7dae22a 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebView.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebView.kt @@ -69,7 +69,7 @@ class FrostWebView @JvmOverloads constructor( frostWebClient = baseEnum?.webClient?.invoke(this) ?: FrostWebViewClient(this) webViewClient = frostWebClient webChromeClient = FrostChromeClient(this) - addJavascriptInterface(FrostJSI(context, this), "Frost") + addJavascriptInterface(FrostJSI(this), "Frost") setBackgroundColor(Color.TRANSPARENT) } } diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClient.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClient.kt index 5e5dc597..5b2b4bfd 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClient.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewClient.kt @@ -4,10 +4,9 @@ import android.content.Context import android.graphics.Bitmap import android.webkit.WebResourceRequest import android.webkit.WebView -import android.webkit.WebViewClient -import com.pitchedapps.frost.LoginActivity -import com.pitchedapps.frost.MainActivity -import com.pitchedapps.frost.SelectorActivity +import com.pitchedapps.frost.activities.LoginActivity +import com.pitchedapps.frost.activities.MainActivity +import com.pitchedapps.frost.activities.SelectorActivity import com.pitchedapps.frost.facebook.FACEBOOK_COM import com.pitchedapps.frost.facebook.FbCookie import com.pitchedapps.frost.injectors.* @@ -17,7 +16,7 @@ import io.reactivex.subjects.Subject /** * Created by Allan Wang on 2017-05-31. */ -open class FrostWebViewClient(val webCore: FrostWebViewCore) : WebViewClient() { +open class FrostWebViewClient(val webCore: FrostWebViewCore) : BaseWebViewClient() { val refreshObservable: Subject = webCore.refreshObservable @@ -97,15 +96,9 @@ open class FrostWebViewClient(val webCore: FrostWebViewCore) : WebViewClient() { return super.shouldOverrideUrlLoading(view, request) } - override fun onPageCommitVisible(view: WebView?, url: String?) { - L.d("ASDF PCV") - super.onPageCommitVisible(view, url) - } - -// override fun onLoadResource(view: WebView, url: String) { -// L.v("Load resource $url") -// super.onLoadResource(view, url) +// override fun onPageCommitVisible(view: WebView?, url: String?) { +// L.d("ASDF PCV") +// super.onPageCommitVisible(view, url) // } - } \ No newline at end of file diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewCore.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewCore.kt index 1e023dca..d96fba55 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewCore.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewCore.kt @@ -72,7 +72,7 @@ class FrostWebViewCore @JvmOverloads constructor( dispose = refreshObservable.subscribeOn(AndroidSchedulers.mainThread()).subscribe { if (it) { loading = true - if (isVisible()) fadeOut(duration = 200L) + if (isVisible) fadeOut(duration = 200L) } else if (loading) { dispose?.dispose() if (animate && Prefs.animate) circularReveal(offset = 150L) @@ -148,11 +148,12 @@ class FrostWebViewCore @JvmOverloads constructor( if (scrollY > 10000) { scrollTo(0, 0) } else { - val animator = ValueAnimator.ofInt(scrollY, 0) - animator.duration = Math.min(scrollY, 500).toLong() - animator.interpolator = DecelerateInterpolator() - animator.addUpdateListener { scrollY = it.animatedValue as Int } - animator.start() + ValueAnimator.ofInt(scrollY, 0).apply { + duration = Math.min(scrollY, 500).toLong() + interpolator = DecelerateInterpolator() + addUpdateListener { scrollY = it.animatedValue as Int } + start() + } } } diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewSearch.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewSearch.kt index b3b1cfe5..bcadf32a 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewSearch.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/web/FrostWebViewSearch.kt @@ -3,9 +3,7 @@ package com.pitchedapps.frost.web import android.annotation.SuppressLint import android.content.Context import android.view.View -import android.webkit.JavascriptInterface -import android.webkit.WebView -import android.webkit.WebViewClient +import android.webkit.* import ca.allanwang.kau.searchview.SearchItem import ca.allanwang.kau.utils.gone import com.pitchedapps.frost.facebook.FbTab @@ -56,7 +54,8 @@ class FrostWebViewSearch(context: Context, val contract: SearchContract) : WebVi settings.javaScriptEnabled = true settings.userAgentString = USER_AGENT_BASIC setLayerType(View.LAYER_TYPE_HARDWARE, null) - webViewClient = FrostWebViewClientSearch() + webViewClient = SearchWebViewClient() + webChromeClient = SearchChromeClient() addJavascriptInterface(SearchJSI(), "Frost") searchSubject.debounce(300, TimeUnit.MILLISECONDS).subscribeOn(Schedulers.newThread()) .map { @@ -111,13 +110,22 @@ class FrostWebViewSearch(context: Context, val contract: SearchContract) : WebVi * * Barebones client that does what [FrostWebViewSearch] needs */ - inner class FrostWebViewClientSearch : WebViewClient() { + inner class SearchWebViewClient : BaseWebViewClient() { override fun onPageFinished(view: WebView, url: String) { super.onPageFinished(view, url) L.i("Search Page finished $url") view.jsInject(JsAssets.SEARCH) } + + override fun shouldInterceptRequest(view: WebView, request: WebResourceRequest): WebResourceResponse? + = super.shouldInterceptRequest(view, request).filterCss(request) + } + + class SearchChromeClient : WebChromeClient() { + + //mute console + override fun onConsoleMessage(consoleMessage: ConsoleMessage) = true } inner class SearchJSI { diff --git a/app/src/main/kotlin/com/pitchedapps/frost/web/LoginWebView.kt b/app/src/main/kotlin/com/pitchedapps/frost/web/LoginWebView.kt index 38d4ad8c..d7a2db0a 100644 --- a/app/src/main/kotlin/com/pitchedapps/frost/web/LoginWebView.kt +++ b/app/src/main/kotlin/com/pitchedapps/frost/web/LoginWebView.kt @@ -66,7 +66,7 @@ class LoginWebView @JvmOverloads constructor( } - inner class LoginClient : WebViewClient() { + inner class LoginClient : BaseWebViewClient() { override fun onPageFinished(view: WebView, url: String) { super.onPageFinished(view, url) @@ -88,7 +88,7 @@ class LoginWebView @JvmOverloads constructor( inner class LoginChromeClient : WebChromeClient() { override fun onConsoleMessage(consoleMessage: ConsoleMessage): Boolean { L.d("Login Console ${consoleMessage.lineNumber()}: ${consoleMessage.message()}") - return super.onConsoleMessage(consoleMessage) + return true } override fun onProgressChanged(view: WebView, newProgress: Int) { -- cgit v1.2.3