Migrate to Android 11, API 30.

This commit is contained in:
Onuray Sahin 2021-01-04 17:12:49 +03:00
parent f1f1613f00
commit 23623b8895
21 changed files with 424 additions and 322 deletions

View File

@ -15,10 +15,10 @@ Translations 🗣:
- -
SDK API changes ⚠️: SDK API changes ⚠️:
- - Increase targetSdkVersion to 30 (#2600)
Build 🧱: Build 🧱:
- - Compile with Android SDK 30 (Android 11)
Test: Test:
- -

View File

@ -32,11 +32,11 @@ buildscript {
} }
android { android {
compileSdkVersion 29 compileSdkVersion 30
defaultConfig { defaultConfig {
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 29 targetSdkVersion 30
versionCode 1 versionCode 1
versionName "1.0" versionName "1.0"
} }

View File

@ -24,9 +24,12 @@ import android.view.MotionEvent
import android.view.ScaleGestureDetector import android.view.ScaleGestureDetector
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.WindowInsets
import android.view.WindowInsetsController
import android.view.WindowManager import android.view.WindowManager
import android.widget.ImageView import android.widget.ImageView
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.view.GestureDetectorCompat import androidx.core.view.GestureDetectorCompat
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
import androidx.core.view.isVisible import androidx.core.view.isVisible
@ -89,14 +92,7 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
// This is important for the dispatchTouchEvent, if not we must correct setDecorViewFullScreen()
// the touch coordinates
window.decorView.systemUiVisibility = (
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
or View.SYSTEM_UI_FLAG_IMMERSIVE)
window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION, WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION)
views = ActivityAttachmentViewerBinding.inflate(layoutInflater) views = ActivityAttachmentViewerBinding.inflate(layoutInflater)
setContentView(views.root) setContentView(views.root)
@ -132,6 +128,25 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi
} }
} }
@Suppress("DEPRECATION")
private fun setDecorViewFullScreen() {
// This is important for the dispatchTouchEvent, if not we must correct
// the touch coordinates
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) {
window.setDecorFitsSystemWindows(false) // New API instead of SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN and SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
window.decorView.windowInsetsController?.systemBarsBehavior = WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_SWIPE // New API instead of SYSTEM_UI_FLAG_IMMERSIVE
window.statusBarColor = ContextCompat.getColor(this, R.color.half_transparent_status_bar) // New API instead of FLAG_TRANSLUCENT_STATUS
window.navigationBarColor = ContextCompat.getColor(this, R.color.half_transparent_status_bar) // new API instead of FLAG_TRANSLUCENT_NAVIGATION
} else {
window.decorView.systemUiVisibility = (
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
or View.SYSTEM_UI_FLAG_IMMERSIVE)
window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION, WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION)
}
}
fun onSelectedPositionChanged(position: Int) { fun onSelectedPositionChanged(position: Int) {
attachmentsAdapter.recyclerView?.findViewHolderForAdapterPosition(currentPosition)?.let { attachmentsAdapter.recyclerView?.findViewHolderForAdapterPosition(currentPosition)?.let {
(it as? BaseViewHolder)?.onSelected(false) (it as? BaseViewHolder)?.onSelected(false)
@ -311,28 +326,42 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi
?.handleCommand(commands) ?.handleCommand(commands)
} }
@Suppress("DEPRECATION")
private fun hideSystemUI() { private fun hideSystemUI() {
systemUiVisibility = false systemUiVisibility = false
// Enables regular immersive mode. // Enables regular immersive mode.
// For "lean back" mode, remove SYSTEM_UI_FLAG_IMMERSIVE. // For "lean back" mode, remove SYSTEM_UI_FLAG_IMMERSIVE.
// Or for "sticky immersive," replace it with SYSTEM_UI_FLAG_IMMERSIVE_STICKY // Or for "sticky immersive," replace it with SYSTEM_UI_FLAG_IMMERSIVE_STICKY
window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_IMMERSIVE if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) {
// Set the content to appear under the system bars so that the window.setDecorFitsSystemWindows(false) // New API instead of SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN and SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
// content doesn't resize when the system bars hide and show. window.decorView.windowInsetsController?.hide(WindowInsets.Type.navigationBars()) // new API instead of SYSTEM_UI_FLAG_HIDE_NAVIGATION
or View.SYSTEM_UI_FLAG_LAYOUT_STABLE window.decorView.windowInsetsController?.systemBarsBehavior = WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_SWIPE // New API instead of SYSTEM_UI_FLAG_IMMERSIVE
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION window.statusBarColor = ContextCompat.getColor(this, R.color.half_transparent_status_bar) // New API instead of FLAG_TRANSLUCENT_STATUS
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN window.navigationBarColor = ContextCompat.getColor(this, R.color.half_transparent_status_bar) // new API instead of FLAG_TRANSLUCENT_NAVIGATION
// Hide the nav bar and status bar } else {
or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_IMMERSIVE
or View.SYSTEM_UI_FLAG_FULLSCREEN) // Set the content to appear under the system bars so that the
// content doesn't resize when the system bars hide and show.
or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
// Hide the nav bar and status bar
or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
or View.SYSTEM_UI_FLAG_FULLSCREEN)
}
} }
// Shows the system bars by removing all the flags // Shows the system bars by removing all the flags
// except for the ones that make the content appear under the system bars. // except for the ones that make the content appear under the system bars.
@Suppress("DEPRECATION")
private fun showSystemUI() { private fun showSystemUI() {
systemUiVisibility = true systemUiVisibility = true
window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) {
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION window.setDecorFitsSystemWindows(false) // New API instead of SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN and SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) } else {
window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)
}
} }
} }

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<resources>
<color name="half_transparent_status_bar">#80000000</color>
</resources>

View File

@ -3,11 +3,11 @@ apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt' apply plugin: 'kotlin-kapt'
android { android {
compileSdkVersion 29 compileSdkVersion 30
defaultConfig { defaultConfig {
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 29 targetSdkVersion 30
versionCode 1 versionCode 1
versionName "1.0" versionName "1.0"

View File

@ -14,12 +14,12 @@ buildscript {
} }
android { android {
compileSdkVersion 29 compileSdkVersion 30
testOptions.unitTests.includeAndroidResources = true testOptions.unitTests.includeAndroidResources = true
defaultConfig { defaultConfig {
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 29 targetSdkVersion 30
versionCode 1 versionCode 1
versionName "0.0.1" versionName "0.0.1"
// Multidex is useful for tests // Multidex is useful for tests

View File

@ -47,22 +47,24 @@ internal object ThumbnailExtractor {
val mediaMetadataRetriever = MediaMetadataRetriever() val mediaMetadataRetriever = MediaMetadataRetriever()
try { try {
mediaMetadataRetriever.setDataSource(context, attachment.queryUri) mediaMetadataRetriever.setDataSource(context, attachment.queryUri)
val thumbnail = mediaMetadataRetriever.frameAtTime mediaMetadataRetriever.frameAtTime?.let { thumbnail ->
val outputStream = ByteArrayOutputStream()
val outputStream = ByteArrayOutputStream() thumbnail.compress(Bitmap.CompressFormat.JPEG, 100, outputStream)
thumbnail.compress(Bitmap.CompressFormat.JPEG, 100, outputStream) val thumbnailWidth = thumbnail.width
val thumbnailWidth = thumbnail.width val thumbnailHeight = thumbnail.height
val thumbnailHeight = thumbnail.height val thumbnailSize = outputStream.size()
val thumbnailSize = outputStream.size() thumbnailData = ThumbnailData(
thumbnailData = ThumbnailData( width = thumbnailWidth,
width = thumbnailWidth, height = thumbnailHeight,
height = thumbnailHeight, size = thumbnailSize.toLong(),
size = thumbnailSize.toLong(), bytes = outputStream.toByteArray(),
bytes = outputStream.toByteArray(), mimeType = MimeTypes.Jpeg
mimeType = MimeTypes.Jpeg )
) thumbnail.recycle()
thumbnail.recycle() outputStream.reset()
outputStream.reset() } ?: run {
Timber.e("Cannot extract video thumbnail at %s", attachment.queryUri.toString())
}
} catch (e: Exception) { } catch (e: Exception) {
Timber.e(e, "Cannot extract video thumbnail") Timber.e(e, "Cannot extract video thumbnail")
} finally { } finally {

View File

@ -19,11 +19,11 @@ apply plugin: 'kotlin-android'
apply plugin: 'kotlin-parcelize' apply plugin: 'kotlin-parcelize'
android { android {
compileSdkVersion 29 compileSdkVersion 30
defaultConfig { defaultConfig {
minSdkVersion 19 minSdkVersion 19
targetSdkVersion 29 targetSdkVersion 30
versionCode 1 versionCode 1
versionName "1.0" versionName "1.0"

View File

@ -58,7 +58,7 @@ class AudioPicker : Picker<MultiPickerAudioType>() {
context.contentResolver.openFileDescriptor(selectedUri, "r")?.use { pfd -> context.contentResolver.openFileDescriptor(selectedUri, "r")?.use { pfd ->
val mediaMetadataRetriever = MediaMetadataRetriever() val mediaMetadataRetriever = MediaMetadataRetriever()
mediaMetadataRetriever.setDataSource(pfd.fileDescriptor) mediaMetadataRetriever.setDataSource(pfd.fileDescriptor)
duration = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION).toLong() duration = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)?.toLong() ?: 0L
} }
audioList.add( audioList.add(

View File

@ -61,10 +61,10 @@ class VideoPicker : Picker<MultiPickerVideoType>() {
context.contentResolver.openFileDescriptor(selectedUri, "r")?.use { pfd -> context.contentResolver.openFileDescriptor(selectedUri, "r")?.use { pfd ->
val mediaMetadataRetriever = MediaMetadataRetriever() val mediaMetadataRetriever = MediaMetadataRetriever()
mediaMetadataRetriever.setDataSource(pfd.fileDescriptor) mediaMetadataRetriever.setDataSource(pfd.fileDescriptor)
duration = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION).toLong() duration = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)?.toLong() ?: 0L
width = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH).toInt() width = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH)?.toInt() ?: 0
height = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT).toInt() height = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT)?.toInt() ?: 0
orientation = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION).toInt() orientation = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION)?.toInt() ?: 0
} }
videoList.add( videoList.add(

View File

@ -101,7 +101,7 @@ ext.abiVersionCodes = ["armeabi-v7a": 1, "arm64-v8a": 2, "x86": 3, "x86_64": 4].
def buildNumber = System.env.BUILDKITE_BUILD_NUMBER as Integer ?: 0 def buildNumber = System.env.BUILDKITE_BUILD_NUMBER as Integer ?: 0
android { android {
compileSdkVersion 29 compileSdkVersion 30
// Due to a bug introduced in Android gradle plugin 3.6.0, we have to specify the ndk version to use // Due to a bug introduced in Android gradle plugin 3.6.0, we have to specify the ndk version to use
// Ref: https://issuetracker.google.com/issues/144111441 // Ref: https://issuetracker.google.com/issues/144111441
@ -111,7 +111,7 @@ android {
applicationId "im.vector.app" applicationId "im.vector.app"
// Set to API 21: see #405 // Set to API 21: see #405
minSdkVersion 21 minSdkVersion 21
targetSdkVersion 29 targetSdkVersion 30
multiDexEnabled true multiDexEnabled true
// `develop` branch will have version code from timestamp, to ensure each build from CI has a incremented versionCode. // `develop` branch will have version code from timestamp, to ensure each build from CI has a incremented versionCode.

View File

@ -23,6 +23,7 @@ import android.os.Bundle
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import android.view.WindowInsetsController
import android.view.WindowManager import android.view.WindowManager
import android.widget.TextView import android.widget.TextView
import androidx.annotation.AttrRes import androidx.annotation.AttrRes
@ -33,6 +34,7 @@ import androidx.annotation.StringRes
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar import androidx.appcompat.widget.Toolbar
import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.content.ContextCompat
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentFactory import androidx.fragment.app.FragmentFactory
@ -410,13 +412,21 @@ abstract class VectorBaseActivity<VB: ViewBinding> : AppCompatActivity(), HasScr
/** /**
* Force to render the activity in fullscreen * Force to render the activity in fullscreen
*/ */
@Suppress("DEPRECATION")
private fun setFullScreen() { private fun setFullScreen() {
window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) {
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION window.setDecorFitsSystemWindows(false) // New API instead of SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN and SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN window.decorView.windowInsetsController?.systemBarsBehavior = WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_SWIPE // New API instead of SYSTEM_UI_FLAG_IMMERSIVE
or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION window.statusBarColor = ContextCompat.getColor(this, im.vector.lib.attachmentviewer.R.color.half_transparent_status_bar) // New API instead of FLAG_TRANSLUCENT_STATUS
or View.SYSTEM_UI_FLAG_FULLSCREEN window.navigationBarColor = ContextCompat.getColor(this, im.vector.lib.attachmentviewer.R.color.half_transparent_status_bar) // new API instead of FLAG_TRANSLUCENT_NAVIGATION
or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) } else {
window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
or View.SYSTEM_UI_FLAG_FULLSCREEN
or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY)
}
} }
/* ========================================================================================== /* ==========================================================================================

View File

@ -153,8 +153,13 @@ class AttachmentsPreviewFragment @Inject constructor(
) )
} }
@Suppress("DEPRECATION")
private fun applyInsets() { private fun applyInsets() {
view?.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) {
activity?.window?.setDecorFitsSystemWindows(false)
} else {
view?.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
}
ViewCompat.setOnApplyWindowInsetsListener(views.attachmentPreviewerBottomContainer) { v, insets -> ViewCompat.setOnApplyWindowInsetsListener(views.attachmentPreviewerBottomContainer) { v, insets ->
v.updatePadding(bottom = insets.systemWindowInsetBottom) v.updatePadding(bottom = insets.systemWindowInsetBottom)
insets insets

View File

@ -25,8 +25,11 @@ import android.os.Bundle
import android.os.Parcelable import android.os.Parcelable
import android.view.View import android.view.View
import android.view.Window import android.view.Window
import android.view.WindowInsets
import android.view.WindowInsetsController
import android.view.WindowManager import android.view.WindowManager
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.core.content.ContextCompat
import androidx.core.content.getSystemService import androidx.core.content.getSystemService
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
import androidx.core.view.isInvisible import androidx.core.view.isInvisible
@ -102,29 +105,43 @@ class VectorCallActivity : VectorBaseActivity<ActivityCallBinding>(), CallContro
setContentView(R.layout.activity_call) setContentView(R.layout.activity_call)
} }
@Suppress("DEPRECATION")
private fun hideSystemUI() { private fun hideSystemUI() {
systemUiVisibility = false systemUiVisibility = false
// Enables regular immersive mode. // Enables regular immersive mode.
// For "lean back" mode, remove SYSTEM_UI_FLAG_IMMERSIVE. // For "lean back" mode, remove SYSTEM_UI_FLAG_IMMERSIVE.
// Or for "sticky immersive," replace it with SYSTEM_UI_FLAG_IMMERSIVE_STICKY // Or for "sticky immersive," replace it with SYSTEM_UI_FLAG_IMMERSIVE_STICKY
window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_IMMERSIVE if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
// Set the content to appear under the system bars so that the window.setDecorFitsSystemWindows(false) // New API instead of SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN and SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
// content doesn't resize when the system bars hide and show. window.decorView.windowInsetsController?.hide(WindowInsets.Type.navigationBars()) // new API instead of SYSTEM_UI_FLAG_HIDE_NAVIGATION
or View.SYSTEM_UI_FLAG_LAYOUT_STABLE window.decorView.windowInsetsController?.systemBarsBehavior = WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_SWIPE // New API instead of SYSTEM_UI_FLAG_IMMERSIVE
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION window.statusBarColor = ContextCompat.getColor(this, R.color.half_transparent_status_bar) // New API instead of FLAG_TRANSLUCENT_STATUS
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN window.navigationBarColor = ContextCompat.getColor(this, R.color.half_transparent_status_bar) // new API instead of FLAG_TRANSLUCENT_NAVIGATION
// Hide the nav bar and status bar } else {
or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_IMMERSIVE
or View.SYSTEM_UI_FLAG_FULLSCREEN) // Set the content to appear under the system bars so that the
// content doesn't resize when the system bars hide and show.
or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
// Hide the nav bar and status bar
or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
or View.SYSTEM_UI_FLAG_FULLSCREEN)
}
} }
// Shows the system bars by removing all the flags // Shows the system bars by removing all the flags
// except for the ones that make the content appear under the system bars. // except for the ones that make the content appear under the system bars.
@Suppress("DEPRECATION")
private fun showSystemUI() { private fun showSystemUI() {
systemUiVisibility = true systemUiVisibility = true
window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION window.setDecorFitsSystemWindows(false) // New API instead of SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN and SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) } else {
window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)
}
} }
private fun toggleUiSystemVisibility() { private fun toggleUiSystemVisibility() {

View File

@ -17,6 +17,7 @@
package im.vector.app.features.crypto.recover package im.vector.app.features.crypto.recover
import android.app.Dialog import android.app.Dialog
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.os.Parcelable import android.os.Parcelable
import android.view.KeyEvent import android.view.KeyEvent
@ -102,7 +103,12 @@ class BootstrapBottomSheet : VectorBaseBottomSheetDialogFragment<BottomSheetBoot
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val rootView = super.onCreateView(inflater, container, savedInstanceState) val rootView = super.onCreateView(inflater, container, savedInstanceState)
dialog?.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
dialog?.window?.setDecorFitsSystemWindows(false)
} else {
@Suppress("DEPRECATION")
dialog?.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE)
}
return rootView return rootView
} }

View File

@ -155,18 +155,15 @@ class LoginWebFragment @Inject constructor(
// avoid infinite onPageFinished call // avoid infinite onPageFinished call
if (url.startsWith("http")) { if (url.startsWith("http")) {
// Generic method to make a bridge between JS and the UIWebView // Generic method to make a bridge between JS and the UIWebView
val mxcJavascriptSendObjectMessage = assetReader.readAssetFile("sendObject.js") assetReader.readAssetFile("sendObject.js")?.let { view.loadUrl(it) }
view.loadUrl(mxcJavascriptSendObjectMessage)
if (state.signMode == SignMode.SignIn) { if (state.signMode == SignMode.SignIn) {
// The function the fallback page calls when the login is complete // The function the fallback page calls when the login is complete
val mxcJavascriptOnLogin = assetReader.readAssetFile("onLogin.js") assetReader.readAssetFile("onLogin.js")?.let { view.loadUrl(it) }
view.loadUrl(mxcJavascriptOnLogin)
} else { } else {
// MODE_REGISTER // MODE_REGISTER
// The function the fallback page calls when the registration is complete // The function the fallback page calls when the registration is complete
val mxcJavascriptOnRegistered = assetReader.readAssetFile("onRegistered.js") assetReader.readAssetFile("onRegistered.js")?.let { view.loadUrl(it) }
view.loadUrl(mxcJavascriptOnRegistered)
} }
} }
} }

View File

@ -21,6 +21,7 @@ import android.os.Build
import android.os.Handler import android.os.Handler
import android.os.Looper import android.os.Looper
import android.view.View import android.view.View
import android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS
import android.widget.ImageView import android.widget.ImageView
import com.tapadoo.alerter.Alerter import com.tapadoo.alerter.Alerter
import com.tapadoo.alerter.OnHideAlertListener import com.tapadoo.alerter.OnHideAlertListener
@ -165,9 +166,7 @@ class PopupAlertManager @Inject constructor(private val avatarRenderer: Lazy<Ava
?.takeIf { ThemeUtils.isLightTheme(it) } ?.takeIf { ThemeUtils.isLightTheme(it) }
?.let { it.window?.decorView } ?.let { it.window?.decorView }
?.let { view -> ?.let { view ->
var flags = view.systemUiVisibility view.windowInsetsController?.setSystemBarsAppearance(0, APPEARANCE_LIGHT_STATUS_BARS)
flags = flags and View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.inv()
view.systemUiVisibility = flags
} }
} }
@ -179,9 +178,7 @@ class PopupAlertManager @Inject constructor(private val avatarRenderer: Lazy<Ava
?.takeIf { ThemeUtils.isLightTheme(it) } ?.takeIf { ThemeUtils.isLightTheme(it) }
?.let { it.window?.decorView } ?.let { it.window?.decorView }
?.let { view -> ?.let { view ->
var flags = view.systemUiVisibility view.windowInsetsController?.setSystemBarsAppearance(APPEARANCE_LIGHT_STATUS_BARS, APPEARANCE_LIGHT_STATUS_BARS)
flags = flags or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
view.systemUiVisibility = flags
} }
} }

View File

@ -21,7 +21,6 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import android.graphics.Bitmap import android.graphics.Bitmap
import android.graphics.Canvas import android.graphics.Canvas
import android.os.AsyncTask
import android.os.Build import android.os.Build
import android.view.View import android.view.View
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
@ -37,6 +36,11 @@ import im.vector.app.features.settings.devtools.GossipingEventsSerializer
import im.vector.app.features.settings.locale.SystemLocaleProvider import im.vector.app.features.settings.locale.SystemLocaleProvider
import im.vector.app.features.themes.ThemeUtils import im.vector.app.features.themes.ThemeUtils
import im.vector.app.features.version.VersionProvider import im.vector.app.features.version.VersionProvider
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import okhttp3.Call import okhttp3.Call
import okhttp3.MediaType.Companion.toMediaTypeOrNull import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
@ -98,6 +102,8 @@ class BugReporter @Inject constructor(
var screenshot: Bitmap? = null var screenshot: Bitmap? = null
private set private set
private val coroutineScope = CoroutineScope(SupervisorJob())
private val LOGCAT_CMD_ERROR = arrayOf("logcat", // /< Run 'logcat' command private val LOGCAT_CMD_ERROR = arrayOf("logcat", // /< Run 'logcat' command
"-d", // /< Dump the log rather than continue outputting it "-d", // /< Dump the log rather than continue outputting it
"-v", // formatting "-v", // formatting
@ -160,286 +166,287 @@ class BugReporter @Inject constructor(
withScreenshot: Boolean, withScreenshot: Boolean,
theBugDescription: String, theBugDescription: String,
listener: IMXBugReportListener?) { listener: IMXBugReportListener?) {
object : AsyncTask<Void, Int, String>() { // enumerate files to delete
// enumerate files to delete val mBugReportFiles: MutableList<File> = ArrayList()
val mBugReportFiles: MutableList<File> = ArrayList()
override fun doInBackground(vararg voids: Void?): String? { coroutineScope.executeAsyncTask(
var bugDescription = theBugDescription onPreExecute = {
var serverError: String? = null // NOOP
val crashCallStack = getCrashDescription(context) },
doInBackground = { publishProgress: suspend (progress: Int) -> Unit ->
var bugDescription = theBugDescription
var serverError: String? = null
val crashCallStack = getCrashDescription(context)
if (null != crashCallStack) { if (null != crashCallStack) {
bugDescription += "\n\n\n\n--------------------------------- crash call stack ---------------------------------\n" bugDescription += "\n\n\n\n--------------------------------- crash call stack ---------------------------------\n"
bugDescription += crashCallStack bugDescription += crashCallStack
}
val gzippedFiles = ArrayList<File>()
if (withDevicesLogs) {
val files = vectorFileLogger.getLogFiles()
files.mapNotNullTo(gzippedFiles) { f ->
if (!mIsCancelled) {
compressFile(f)
} else {
null
}
} }
}
if (!mIsCancelled && (withCrashLogs || withDevicesLogs)) { val gzippedFiles = ArrayList<File>()
val gzippedLogcat = saveLogCat(context, false)
if (null != gzippedLogcat) { if (withDevicesLogs) {
if (gzippedFiles.size == 0) { val files = vectorFileLogger.getLogFiles()
gzippedFiles.add(gzippedLogcat) files.mapNotNullTo(gzippedFiles) { f ->
} else { if (!mIsCancelled) {
gzippedFiles.add(0, gzippedLogcat) compressFile(f)
} else {
null
}
} }
} }
val crashDescription = getCrashFile(context) if (!mIsCancelled && (withCrashLogs || withDevicesLogs)) {
if (crashDescription.exists()) { val gzippedLogcat = saveLogCat(context, false)
val compressedCrashDescription = compressFile(crashDescription)
if (null != compressedCrashDescription) { if (null != gzippedLogcat) {
if (gzippedFiles.size == 0) { if (gzippedFiles.size == 0) {
gzippedFiles.add(compressedCrashDescription) gzippedFiles.add(gzippedLogcat)
} else { } else {
gzippedFiles.add(0, compressedCrashDescription) gzippedFiles.add(0, gzippedLogcat)
}
}
val crashDescription = getCrashFile(context)
if (crashDescription.exists()) {
val compressedCrashDescription = compressFile(crashDescription)
if (null != compressedCrashDescription) {
if (gzippedFiles.size == 0) {
gzippedFiles.add(compressedCrashDescription)
} else {
gzippedFiles.add(0, compressedCrashDescription)
}
} }
} }
} }
}
activeSessionHolder.getSafeActiveSession() activeSessionHolder.getSafeActiveSession()
?.takeIf { !mIsCancelled && withKeyRequestHistory } ?.takeIf { !mIsCancelled && withKeyRequestHistory }
?.cryptoService() ?.cryptoService()
?.getGossipingEvents() ?.getGossipingEvents()
?.let { GossipingEventsSerializer().serialize(it) } ?.let { GossipingEventsSerializer().serialize(it) }
?.toByteArray() ?.toByteArray()
?.let { rawByteArray -> ?.let { rawByteArray ->
File(context.cacheDir.absolutePath, KEY_REQUESTS_FILENAME) File(context.cacheDir.absolutePath, KEY_REQUESTS_FILENAME)
.also { .also {
it.outputStream() it.outputStream()
.use { os -> os.write(rawByteArray) } .use { os -> os.write(rawByteArray) }
} }
}
?.let { compressFile(it) }
?.let { gzippedFiles.add(it) }
var deviceId = "undefined"
var userId = "undefined"
var olmVersion = "undefined"
activeSessionHolder.getSafeActiveSession()?.let { session ->
userId = session.myUserId
deviceId = session.sessionParams.deviceId ?: "undefined"
olmVersion = session.cryptoService().getCryptoVersion(context, true)
}
if (!mIsCancelled) {
val text = "[Element] " +
if (forSuggestion) {
"[Suggestion] "
} else {
""
} +
bugDescription
// build the multi part request
val builder = BugReporterMultipartBody.Builder()
.addFormDataPart("text", text)
.addFormDataPart("app", "riot-android")
.addFormDataPart("user_agent", Matrix.getInstance(context).getUserAgent())
.addFormDataPart("user_id", userId)
.addFormDataPart("device_id", deviceId)
.addFormDataPart("version", versionProvider.getVersion(longFormat = true, useBuildNumber = false))
.addFormDataPart("branch_name", context.getString(R.string.git_branch_name))
.addFormDataPart("matrix_sdk_version", Matrix.getSdkVersion())
.addFormDataPart("olm_version", olmVersion)
.addFormDataPart("device", Build.MODEL.trim())
.addFormDataPart("verbose_log", vectorPreferences.labAllowedExtendedLogging().toOnOff())
.addFormDataPart("multi_window", inMultiWindowMode.toOnOff())
.addFormDataPart("os", Build.VERSION.RELEASE + " (API " + Build.VERSION.SDK_INT + ") "
+ Build.VERSION.INCREMENTAL + "-" + Build.VERSION.CODENAME)
.addFormDataPart("locale", Locale.getDefault().toString())
.addFormDataPart("app_language", VectorLocale.applicationLocale.toString())
.addFormDataPart("default_app_language", systemLocaleProvider.getSystemLocale().toString())
.addFormDataPart("theme", ThemeUtils.getApplicationTheme(context))
val buildNumber = context.getString(R.string.build_number)
if (buildNumber.isNotEmpty() && buildNumber != "0") {
builder.addFormDataPart("build_number", buildNumber)
}
// add the gzipped files
for (file in gzippedFiles) {
builder.addFormDataPart("compressed-log", file.name, file.asRequestBody(MimeTypes.OctetStream.toMediaTypeOrNull()))
}
mBugReportFiles.addAll(gzippedFiles)
if (withScreenshot) {
val bitmap = screenshot
if (null != bitmap) {
val logCatScreenshotFile = File(context.cacheDir.absolutePath, LOG_CAT_SCREENSHOT_FILENAME)
if (logCatScreenshotFile.exists()) {
logCatScreenshotFile.delete()
} }
?.let { compressFile(it) }
?.let { gzippedFiles.add(it) }
try { var deviceId = "undefined"
logCatScreenshotFile.outputStream().use { var userId = "undefined"
bitmap.compress(Bitmap.CompressFormat.PNG, 100, it) var olmVersion = "undefined"
activeSessionHolder.getSafeActiveSession()?.let { session ->
userId = session.myUserId
deviceId = session.sessionParams.deviceId ?: "undefined"
olmVersion = session.cryptoService().getCryptoVersion(context, true)
}
if (!mIsCancelled) {
val text = "[Element] " +
if (forSuggestion) {
"[Suggestion] "
} else {
""
} +
bugDescription
// build the multi part request
val builder = BugReporterMultipartBody.Builder()
.addFormDataPart("text", text)
.addFormDataPart("app", "riot-android")
.addFormDataPart("user_agent", Matrix.getInstance(context).getUserAgent())
.addFormDataPart("user_id", userId)
.addFormDataPart("device_id", deviceId)
.addFormDataPart("version", versionProvider.getVersion(longFormat = true, useBuildNumber = false))
.addFormDataPart("branch_name", context.getString(R.string.git_branch_name))
.addFormDataPart("matrix_sdk_version", Matrix.getSdkVersion())
.addFormDataPart("olm_version", olmVersion)
.addFormDataPart("device", Build.MODEL.trim())
.addFormDataPart("verbose_log", vectorPreferences.labAllowedExtendedLogging().toOnOff())
.addFormDataPart("multi_window", inMultiWindowMode.toOnOff())
.addFormDataPart("os", Build.VERSION.RELEASE + " (API " + Build.VERSION.SDK_INT + ") "
+ Build.VERSION.INCREMENTAL + "-" + Build.VERSION.CODENAME)
.addFormDataPart("locale", Locale.getDefault().toString())
.addFormDataPart("app_language", VectorLocale.applicationLocale.toString())
.addFormDataPart("default_app_language", systemLocaleProvider.getSystemLocale().toString())
.addFormDataPart("theme", ThemeUtils.getApplicationTheme(context))
val buildNumber = context.getString(R.string.build_number)
if (buildNumber.isNotEmpty() && buildNumber != "0") {
builder.addFormDataPart("build_number", buildNumber)
}
// add the gzipped files
for (file in gzippedFiles) {
builder.addFormDataPart("compressed-log", file.name, file.asRequestBody(MimeTypes.OctetStream.toMediaTypeOrNull()))
}
mBugReportFiles.addAll(gzippedFiles)
if (withScreenshot) {
val bitmap = screenshot
if (null != bitmap) {
val logCatScreenshotFile = File(context.cacheDir.absolutePath, LOG_CAT_SCREENSHOT_FILENAME)
if (logCatScreenshotFile.exists()) {
logCatScreenshotFile.delete()
} }
builder.addFormDataPart("file", try {
logCatScreenshotFile.name, logCatScreenshotFile.asRequestBody(MimeTypes.OctetStream.toMediaTypeOrNull())) logCatScreenshotFile.outputStream().use {
} catch (e: Exception) { bitmap.compress(Bitmap.CompressFormat.PNG, 100, it)
Timber.e(e, "## sendBugReport() : fail to write screenshot$e") }
builder.addFormDataPart("file",
logCatScreenshotFile.name, logCatScreenshotFile.asRequestBody(MimeTypes.OctetStream.toMediaTypeOrNull()))
} catch (e: Exception) {
Timber.e(e, "## sendBugReport() : fail to write screenshot$e")
}
} }
} }
}
screenshot = null screenshot = null
// add some github labels // add some github labels
builder.addFormDataPart("label", BuildConfig.VERSION_NAME) builder.addFormDataPart("label", BuildConfig.VERSION_NAME)
builder.addFormDataPart("label", BuildConfig.FLAVOR_DESCRIPTION) builder.addFormDataPart("label", BuildConfig.FLAVOR_DESCRIPTION)
builder.addFormDataPart("label", context.getString(R.string.git_branch_name)) builder.addFormDataPart("label", context.getString(R.string.git_branch_name))
// Special for RiotX // Special for RiotX
builder.addFormDataPart("label", "[Element]") builder.addFormDataPart("label", "[Element]")
// Suggestion // Suggestion
if (forSuggestion) { if (forSuggestion) {
builder.addFormDataPart("label", "[Suggestion]") builder.addFormDataPart("label", "[Suggestion]")
} }
if (getCrashFile(context).exists()) { if (getCrashFile(context).exists()) {
builder.addFormDataPart("label", "crash") builder.addFormDataPart("label", "crash")
deleteCrashFile(context) deleteCrashFile(context)
} }
val requestBody = builder.build() val requestBody = builder.build()
// add a progress listener // add a progress listener
requestBody.setWriteListener { totalWritten, contentLength -> requestBody.setWriteListener { totalWritten, contentLength ->
val percentage = if (-1L != contentLength) { val percentage = if (-1L != contentLength) {
if (totalWritten > contentLength) { if (totalWritten > contentLength) {
100 100
} else {
(totalWritten * 100 / contentLength).toInt()
}
} else { } else {
(totalWritten * 100 / contentLength).toInt() 0
} }
} else {
0 if (mIsCancelled && null != mBugReportCall) {
mBugReportCall!!.cancel()
}
Timber.v("## onWrite() : $percentage%")
suspend { publishProgress(percentage) }
} }
if (mIsCancelled && null != mBugReportCall) { // build the request
mBugReportCall!!.cancel() val request = Request.Builder()
.url(context.getString(R.string.bug_report_url))
.post(requestBody)
.build()
var responseCode = HttpURLConnection.HTTP_INTERNAL_ERROR
var response: Response? = null
var errorMessage: String? = null
// trigger the request
try {
mBugReportCall = mOkHttpClient.newCall(request)
response = mBugReportCall!!.execute()
responseCode = response.code
} catch (e: Exception) {
Timber.e(e, "response")
errorMessage = e.localizedMessage
} }
Timber.v("## onWrite() : $percentage%") // if the upload failed, try to retrieve the reason
publishProgress(percentage) if (responseCode != HttpURLConnection.HTTP_OK) {
} if (null != errorMessage) {
serverError = "Failed with error $errorMessage"
} else if (null == response || null == response.body) {
serverError = "Failed with error $responseCode"
} else {
try {
val inputStream = response.body!!.byteStream()
// build the request serverError = inputStream.use {
val request = Request.Builder() buildString {
.url(context.getString(R.string.bug_report_url)) var ch = it.read()
.post(requestBody) while (ch != -1) {
.build() append(ch.toChar())
ch = it.read()
var responseCode = HttpURLConnection.HTTP_INTERNAL_ERROR }
var response: Response? = null
var errorMessage: String? = null
// trigger the request
try {
mBugReportCall = mOkHttpClient.newCall(request)
response = mBugReportCall!!.execute()
responseCode = response.code
} catch (e: Exception) {
Timber.e(e, "response")
errorMessage = e.localizedMessage
}
// if the upload failed, try to retrieve the reason
if (responseCode != HttpURLConnection.HTTP_OK) {
if (null != errorMessage) {
serverError = "Failed with error $errorMessage"
} else if (null == response || null == response.body) {
serverError = "Failed with error $responseCode"
} else {
try {
val inputStream = response.body!!.byteStream()
serverError = inputStream.use {
buildString {
var ch = it.read()
while (ch != -1) {
append(ch.toChar())
ch = it.read()
} }
} }
}
// check if the error message // check if the error message
try { try {
val responseJSON = JSONObject(serverError) val responseJSON = JSONObject(serverError)
serverError = responseJSON.getString("error") serverError = responseJSON.getString("error")
} catch (e: JSONException) { } catch (e: JSONException) {
Timber.e(e, "doInBackground ; Json conversion failed") Timber.e(e, "doInBackground ; Json conversion failed")
} }
// should never happen // should never happen
if (null == serverError) { if (null == serverError) {
serverError = "Failed with error $responseCode" serverError = "Failed with error $responseCode"
}
} catch (e: Exception) {
Timber.e(e, "## sendBugReport() : failed to parse error")
} }
} catch (e: Exception) {
Timber.e(e, "## sendBugReport() : failed to parse error")
} }
} }
} }
}
return serverError serverError
} },
onProgressUpdate = { progress ->
override fun onProgressUpdate(vararg progress: Int?) { if (null != listener) {
if (null != listener) { try {
try { listener.onProgress(progress)
listener.onProgress(progress[0] ?: 0) } catch (e: Exception) {
} catch (e: Exception) { Timber.e(e, "## onProgress() : failed")
Timber.e(e, "## onProgress() : failed") }
} }
} },
} onPostExecute = { reason: String? ->
mBugReportCall = null
override fun onPostExecute(reason: String?) {
mBugReportCall = null // delete when the bug report has been successfully sent
for (file in mBugReportFiles) {
// delete when the bug report has been successfully sent file.delete()
for (file in mBugReportFiles) { }
file.delete()
} if (null != listener) {
try {
if (null != listener) { if (mIsCancelled) {
try { listener.onUploadCancelled()
if (mIsCancelled) { } else if (null == reason) {
listener.onUploadCancelled() listener.onUploadSucceed()
} else if (null == reason) { } else {
listener.onUploadSucceed() listener.onUploadFailed(reason)
} else { }
listener.onUploadFailed(reason) } catch (e: Exception) {
Timber.e(e, "## onPostExecute() : failed")
} }
} catch (e: Exception) {
Timber.e(e, "## onPostExecute() : failed")
} }
} }
} )
}.execute()
} }
/** /**
@ -696,4 +703,21 @@ class BugReporter @Inject constructor(
return null return null
} }
fun <P, R> CoroutineScope.executeAsyncTask(
onPreExecute: () -> Unit,
doInBackground: suspend (suspend (P) -> Unit) -> R,
onPostExecute: (R) -> Unit,
onProgressUpdate: (P) -> Unit
) = launch {
onPreExecute()
val result = withContext(Dispatchers.IO) {
doInBackground {
withContext(Dispatchers.Main) { onProgressUpdate(it) }
}
}
onPostExecute(result)
}
} }

View File

@ -16,6 +16,7 @@
package im.vector.app.features.roomprofile.uploads.media package im.vector.app.features.roomprofile.uploads.media
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.util.DisplayMetrics import android.util.DisplayMetrics
import android.view.LayoutInflater import android.view.LayoutInflater
@ -78,9 +79,14 @@ class RoomUploadsMediaFragment @Inject constructor(
controller.listener = this controller.listener = this
} }
@Suppress("DEPRECATION")
private fun getNumberOfColumns(): Int { private fun getNumberOfColumns(): Int {
val displayMetrics = DisplayMetrics() val displayMetrics = DisplayMetrics()
requireActivity().windowManager.defaultDisplay.getMetrics(displayMetrics) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
requireContext().display?.getMetrics(displayMetrics)
} else {
requireActivity().windowManager.defaultDisplay.getMetrics(displayMetrics)
}
return dimensionConverter.pxToDp(displayMetrics.widthPixels) / IMAGE_SIZE_DP return dimensionConverter.pxToDp(displayMetrics.widthPixels) / IMAGE_SIZE_DP
} }

View File

@ -64,7 +64,9 @@ class VectorWebViewActivity : VectorBaseActivity<ActivityVectorWebViewBinding>()
// Allow use of Local Storage // Allow use of Local Storage
domStorageEnabled = true domStorageEnabled = true
@Suppress("DEPRECATION")
allowFileAccessFromFileURLs = true allowFileAccessFromFileURLs = true
@Suppress("DEPRECATION")
allowUniversalAccessFromFileURLs = true allowUniversalAccessFromFileURLs = true
displayZoomControls = false displayZoomControls = false
@ -73,7 +75,7 @@ class VectorWebViewActivity : VectorBaseActivity<ActivityVectorWebViewBinding>()
val cookieManager = android.webkit.CookieManager.getInstance() val cookieManager = android.webkit.CookieManager.getInstance()
cookieManager.setAcceptThirdPartyCookies(views.simpleWebview, true) cookieManager.setAcceptThirdPartyCookies(views.simpleWebview, true)
val url = intent.extras?.getString(EXTRA_URL) val url = intent.extras?.getString(EXTRA_URL) ?: return
val title = intent.extras?.getString(EXTRA_TITLE, USE_TITLE_FROM_WEB_PAGE) val title = intent.extras?.getString(EXTRA_TITLE, USE_TITLE_FROM_WEB_PAGE)
if (title != USE_TITLE_FROM_WEB_PAGE) { if (title != USE_TITLE_FROM_WEB_PAGE) {
setTitle(title) setTitle(title)

View File

@ -54,7 +54,9 @@ fun WebView.setupForWidget(webViewEventListener: WebViewEventListener) {
// Allow use of Local Storage // Allow use of Local Storage
settings.domStorageEnabled = true settings.domStorageEnabled = true
@Suppress("DEPRECATION")
settings.allowFileAccessFromFileURLs = true settings.allowFileAccessFromFileURLs = true
@Suppress("DEPRECATION")
settings.allowUniversalAccessFromFileURLs = true settings.allowUniversalAccessFromFileURLs = true
settings.displayZoomControls = false settings.displayZoomControls = false
@ -75,7 +77,6 @@ fun WebView.clearAfterWidget() {
// Make sure you remove the WebView from its parent view before doing anything. // Make sure you remove the WebView from its parent view before doing anything.
(parent as? ViewGroup)?.removeAllViews() (parent as? ViewGroup)?.removeAllViews()
webChromeClient = null webChromeClient = null
webViewClient = null
clearHistory() clearHistory()
// NOTE: clears RAM cache, if you pass true, it will also clear the disk cache. // NOTE: clears RAM cache, if you pass true, it will also clear the disk cache.
clearCache(true) clearCache(true)