123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180 |
- /*
- * Nextcloud Android client application
- *
- * @author Alper Ozturk
- * Copyright (C) 2023 Alper Ozturk
- * Copyright (C) 2023 Nextcloud GmbH
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- */
- package com.owncloud.android.utils
- import android.annotation.SuppressLint
- import android.content.Context
- import android.content.Intent
- import android.content.pm.PackageManager
- import android.net.Proxy
- import android.net.Uri
- import android.text.TextUtils
- import android.util.ArrayMap
- import android.util.Log
- import android.webkit.WebView
- import com.google.android.material.dialog.MaterialAlertDialogBuilder
- import com.owncloud.android.R
- import com.owncloud.android.lib.common.OwnCloudClientManagerFactory
- import java.io.PrintWriter
- import java.io.StringWriter
- class WebViewUtil(private val context: Context) {
- private val packageName = "com.google.android.webview"
- fun checkWebViewVersion() {
- if (!isWebViewVersionValid()) {
- showUpdateDialog()
- }
- }
- private fun isWebViewVersionValid(): Boolean {
- val currentWebViewVersion = getCurrentWebViewMajorVersion() ?: return true
- val minSupportedWebViewVersion: String = getMinimumSupportedMajorWebViewVersion()
- return currentWebViewVersion.toInt() >= minSupportedWebViewVersion.toInt()
- }
- private fun showUpdateDialog() {
- val builder = MaterialAlertDialogBuilder(context)
- .setTitle(context.getString(R.string.webview_version_check_alert_dialog_title))
- .setMessage(context.getString(R.string.webview_version_check_alert_dialog_message))
- .setCancelable(false)
- .setPositiveButton(
- context.getString(R.string.webview_version_check_alert_dialog_positive_button_title)
- ) { _, _ ->
- redirectToAndroidSystemWebViewStorePage()
- }
- val dialog = builder.create()
- dialog.show()
- }
- private fun redirectToAndroidSystemWebViewStorePage() {
- val uri = Uri.parse("market://details?id=$packageName")
- val intent = Intent(Intent.ACTION_VIEW, uri)
- intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
- try {
- context.startActivity(intent)
- } catch (e: android.content.ActivityNotFoundException) {
- redirectToPlayStoreWebsiteForAndroidSystemWebView()
- }
- }
- private fun redirectToPlayStoreWebsiteForAndroidSystemWebView() {
- val playStoreWebUri = Uri.parse("https://play.google.com/store/apps/details?id=$packageName")
- val webIntent = Intent(Intent.ACTION_VIEW, playStoreWebUri)
- context.startActivity(webIntent)
- }
- private fun getCurrentWebViewMajorVersion(): String? {
- val pm: PackageManager = context.packageManager
- return try {
- val pi = pm.getPackageInfo("com.google.android.webview", 0)
- val fullVersion = pi.versionName
- // Split the version string by "." and get the first part
- val versionParts = fullVersion.split("\\.".toRegex()).dropLastWhile { it.isEmpty() }
- .toTypedArray()
- if (versionParts.isNotEmpty()) {
- versionParts[0]
- } else {
- null
- }
- } catch (e: PackageManager.NameNotFoundException) {
- null
- }
- }
- /**
- * Ideally we should fetch from database, reading actual value
- * from PlayStore not feasible due to frequently api changes made by
- * Google
- *
- */
- private fun getMinimumSupportedMajorWebViewVersion(): String {
- return "118"
- }
- /**
- * From https://stackoverflow.com/a/18453384
- *
- * @return
- */
- @SuppressLint("PrivateApi", "DiscouragedPrivateApi")
- @Suppress("TooGenericExceptionCaught")
- fun setProxyKKPlus(webView: WebView) {
- val proxyHost = OwnCloudClientManagerFactory.getProxyHost()
- val proxyPort = OwnCloudClientManagerFactory.getProxyPort()
- if (TextUtils.isEmpty(proxyHost) || proxyPort <= 0) {
- return
- }
- val applicationClassName = "android.app.Application"
- Log.d(PROXY_TAG, "Setting proxy with >= 4.4 API.")
- val appContext = webView.context.applicationContext
- System.setProperty("http.proxyHost", proxyHost)
- System.setProperty("http.proxyPort", proxyPort.toString())
- System.setProperty("https.proxyHost", proxyHost)
- System.setProperty("https.proxyPort", proxyPort.toString())
- try {
- val applicationClass = Class.forName(applicationClassName)
- val loadedApkField = applicationClass.getField("mLoadedApk")
- loadedApkField.isAccessible = true
- val loadedApk = loadedApkField[appContext]
- val loadedApkCls = Class.forName("android.app.LoadedApk")
- val receiversField = loadedApkCls.getDeclaredField("mReceivers")
- receiversField.isAccessible = true
- val receivers = receiversField[loadedApk] as ArrayMap<*, *>
- for (receiverMap in receivers.values) {
- for (rec in (receiverMap as ArrayMap<*, *>).keys) {
- val clazz: Class<*> = rec.javaClass
- if (clazz.name.contains("ProxyChangeListener")) {
- val onReceiveMethod = clazz.getDeclaredMethod(
- "onReceive",
- Context::class.java,
- Intent::class.java
- )
- val intent = Intent(Proxy.PROXY_CHANGE_ACTION)
- onReceiveMethod.invoke(rec, appContext, intent)
- }
- }
- }
- Log.d(PROXY_TAG, "Setting proxy with >= 4.4 API successful!")
- } catch (e: Exception) {
- val sw = StringWriter()
- e.printStackTrace(PrintWriter(sw))
- val exceptionAsString = sw.toString()
- e.message?.let { Log.v(PROXY_TAG, it) }
- Log.v(PROXY_TAG, exceptionAsString)
- }
- }
- companion object {
- private const val PROXY_TAG = "PROXY"
- }
- }
|