mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2025-02-08 16:18:53 +01:00
Migrate to Android 11, API 30.
This commit is contained in:
parent
f1f1613f00
commit
23623b8895
@ -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:
|
||||||
-
|
-
|
||||||
|
@ -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"
|
||||||
}
|
}
|
||||||
|
@ -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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
6
attachment-viewer/src/main/res/values/colors.xml
Normal file
6
attachment-viewer/src/main/res/values/colors.xml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<resources>
|
||||||
|
|
||||||
|
<color name="half_transparent_status_bar">#80000000</color>
|
||||||
|
|
||||||
|
</resources>
|
@ -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"
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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 {
|
||||||
|
@ -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"
|
||||||
|
|
||||||
|
@ -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(
|
||||||
|
@ -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(
|
||||||
|
@ -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.
|
||||||
|
@ -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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ==========================================================================================
|
/* ==========================================================================================
|
||||||
|
@ -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
|
||||||
|
@ -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() {
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user