From 23623b8895958acfe9b8d6e8b5b674e7d012fe33 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Mon, 4 Jan 2021 17:12:49 +0300 Subject: [PATCH 1/5] Migrate to Android 11, API 30. --- CHANGES.md | 4 +- attachment-viewer/build.gradle | 4 +- .../AttachmentViewerActivity.kt | 69 ++- .../src/main/res/values/colors.xml | 6 + matrix-sdk-android-rx/build.gradle | 4 +- matrix-sdk-android/build.gradle | 4 +- .../session/content/ThumbnailExtractor.kt | 34 +- multipicker/build.gradle | 4 +- .../im/vector/lib/multipicker/AudioPicker.kt | 2 +- .../im/vector/lib/multipicker/VideoPicker.kt | 8 +- vector/build.gradle | 4 +- .../app/core/platform/VectorBaseActivity.kt | 22 +- .../preview/AttachmentsPreviewFragment.kt | 7 +- .../app/features/call/VectorCallActivity.kt | 41 +- .../crypto/recover/BootstrapBottomSheet.kt | 8 +- .../app/features/login/LoginWebFragment.kt | 9 +- .../app/features/popup/PopupAlertManager.kt | 9 +- .../app/features/rageshake/BugReporter.kt | 492 +++++++++--------- .../uploads/media/RoomUploadsMediaFragment.kt | 8 +- .../features/webview/VectorWebViewActivity.kt | 4 +- .../features/widgets/webview/WidgetWebView.kt | 3 +- 21 files changed, 424 insertions(+), 322 deletions(-) create mode 100644 attachment-viewer/src/main/res/values/colors.xml diff --git a/CHANGES.md b/CHANGES.md index 373c3aa985..f02c05672d 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -15,10 +15,10 @@ Translations 🗣: - SDK API changes ⚠️: - - + - Increase targetSdkVersion to 30 (#2600) Build 🧱: - - + - Compile with Android SDK 30 (Android 11) Test: - diff --git a/attachment-viewer/build.gradle b/attachment-viewer/build.gradle index d8cd7d0c98..5ce9f1eff6 100644 --- a/attachment-viewer/build.gradle +++ b/attachment-viewer/build.gradle @@ -32,11 +32,11 @@ buildscript { } android { - compileSdkVersion 29 + compileSdkVersion 30 defaultConfig { minSdkVersion 21 - targetSdkVersion 29 + targetSdkVersion 30 versionCode 1 versionName "1.0" } diff --git a/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/AttachmentViewerActivity.kt b/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/AttachmentViewerActivity.kt index ae095be41a..1d09e1ef0e 100644 --- a/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/AttachmentViewerActivity.kt +++ b/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/AttachmentViewerActivity.kt @@ -24,9 +24,12 @@ import android.view.MotionEvent import android.view.ScaleGestureDetector import android.view.View import android.view.ViewGroup +import android.view.WindowInsets +import android.view.WindowInsetsController import android.view.WindowManager import android.widget.ImageView import androidx.appcompat.app.AppCompatActivity +import androidx.core.content.ContextCompat import androidx.core.view.GestureDetectorCompat import androidx.core.view.ViewCompat import androidx.core.view.isVisible @@ -89,14 +92,7 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - // This is important for the dispatchTouchEvent, if not we must correct - // 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) + setDecorViewFullScreen() views = ActivityAttachmentViewerBinding.inflate(layoutInflater) 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) { attachmentsAdapter.recyclerView?.findViewHolderForAdapterPosition(currentPosition)?.let { (it as? BaseViewHolder)?.onSelected(false) @@ -311,28 +326,42 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi ?.handleCommand(commands) } + @Suppress("DEPRECATION") private fun hideSystemUI() { systemUiVisibility = false // Enables regular immersive mode. // For "lean back" mode, remove SYSTEM_UI_FLAG_IMMERSIVE. // Or for "sticky immersive," replace it with SYSTEM_UI_FLAG_IMMERSIVE_STICKY - window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_IMMERSIVE - // 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) + 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?.hide(WindowInsets.Type.navigationBars()) // new API instead of SYSTEM_UI_FLAG_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_IMMERSIVE + // 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 // except for the ones that make the content appear under the system bars. + @Suppress("DEPRECATION") private fun showSystemUI() { systemUiVisibility = true - window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE - or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION - or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) + 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 + } 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) + } } } diff --git a/attachment-viewer/src/main/res/values/colors.xml b/attachment-viewer/src/main/res/values/colors.xml new file mode 100644 index 0000000000..7ceef40881 --- /dev/null +++ b/attachment-viewer/src/main/res/values/colors.xml @@ -0,0 +1,6 @@ + + + + #80000000 + + \ No newline at end of file diff --git a/matrix-sdk-android-rx/build.gradle b/matrix-sdk-android-rx/build.gradle index a99b5856ba..0e899e21ff 100644 --- a/matrix-sdk-android-rx/build.gradle +++ b/matrix-sdk-android-rx/build.gradle @@ -3,11 +3,11 @@ apply plugin: 'kotlin-android' apply plugin: 'kotlin-kapt' android { - compileSdkVersion 29 + compileSdkVersion 30 defaultConfig { minSdkVersion 21 - targetSdkVersion 29 + targetSdkVersion 30 versionCode 1 versionName "1.0" diff --git a/matrix-sdk-android/build.gradle b/matrix-sdk-android/build.gradle index d72e5bda41..ad177db95c 100644 --- a/matrix-sdk-android/build.gradle +++ b/matrix-sdk-android/build.gradle @@ -14,12 +14,12 @@ buildscript { } android { - compileSdkVersion 29 + compileSdkVersion 30 testOptions.unitTests.includeAndroidResources = true defaultConfig { minSdkVersion 21 - targetSdkVersion 29 + targetSdkVersion 30 versionCode 1 versionName "0.0.1" // Multidex is useful for tests diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/ThumbnailExtractor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/ThumbnailExtractor.kt index 4b31db59b1..c28668a53e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/ThumbnailExtractor.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/content/ThumbnailExtractor.kt @@ -47,22 +47,24 @@ internal object ThumbnailExtractor { val mediaMetadataRetriever = MediaMetadataRetriever() try { mediaMetadataRetriever.setDataSource(context, attachment.queryUri) - val thumbnail = mediaMetadataRetriever.frameAtTime - - val outputStream = ByteArrayOutputStream() - thumbnail.compress(Bitmap.CompressFormat.JPEG, 100, outputStream) - val thumbnailWidth = thumbnail.width - val thumbnailHeight = thumbnail.height - val thumbnailSize = outputStream.size() - thumbnailData = ThumbnailData( - width = thumbnailWidth, - height = thumbnailHeight, - size = thumbnailSize.toLong(), - bytes = outputStream.toByteArray(), - mimeType = MimeTypes.Jpeg - ) - thumbnail.recycle() - outputStream.reset() + mediaMetadataRetriever.frameAtTime?.let { thumbnail -> + val outputStream = ByteArrayOutputStream() + thumbnail.compress(Bitmap.CompressFormat.JPEG, 100, outputStream) + val thumbnailWidth = thumbnail.width + val thumbnailHeight = thumbnail.height + val thumbnailSize = outputStream.size() + thumbnailData = ThumbnailData( + width = thumbnailWidth, + height = thumbnailHeight, + size = thumbnailSize.toLong(), + bytes = outputStream.toByteArray(), + mimeType = MimeTypes.Jpeg + ) + thumbnail.recycle() + outputStream.reset() + } ?: run { + Timber.e("Cannot extract video thumbnail at %s", attachment.queryUri.toString()) + } } catch (e: Exception) { Timber.e(e, "Cannot extract video thumbnail") } finally { diff --git a/multipicker/build.gradle b/multipicker/build.gradle index c58c4586b2..10dc18e488 100644 --- a/multipicker/build.gradle +++ b/multipicker/build.gradle @@ -19,11 +19,11 @@ apply plugin: 'kotlin-android' apply plugin: 'kotlin-parcelize' android { - compileSdkVersion 29 + compileSdkVersion 30 defaultConfig { minSdkVersion 19 - targetSdkVersion 29 + targetSdkVersion 30 versionCode 1 versionName "1.0" diff --git a/multipicker/src/main/java/im/vector/lib/multipicker/AudioPicker.kt b/multipicker/src/main/java/im/vector/lib/multipicker/AudioPicker.kt index 516022100d..e8970d72ef 100644 --- a/multipicker/src/main/java/im/vector/lib/multipicker/AudioPicker.kt +++ b/multipicker/src/main/java/im/vector/lib/multipicker/AudioPicker.kt @@ -58,7 +58,7 @@ class AudioPicker : Picker() { context.contentResolver.openFileDescriptor(selectedUri, "r")?.use { pfd -> val mediaMetadataRetriever = MediaMetadataRetriever() mediaMetadataRetriever.setDataSource(pfd.fileDescriptor) - duration = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION).toLong() + duration = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)?.toLong() ?: 0L } audioList.add( diff --git a/multipicker/src/main/java/im/vector/lib/multipicker/VideoPicker.kt b/multipicker/src/main/java/im/vector/lib/multipicker/VideoPicker.kt index c7c06f795f..dada9ac5bd 100644 --- a/multipicker/src/main/java/im/vector/lib/multipicker/VideoPicker.kt +++ b/multipicker/src/main/java/im/vector/lib/multipicker/VideoPicker.kt @@ -61,10 +61,10 @@ class VideoPicker : Picker() { context.contentResolver.openFileDescriptor(selectedUri, "r")?.use { pfd -> val mediaMetadataRetriever = MediaMetadataRetriever() mediaMetadataRetriever.setDataSource(pfd.fileDescriptor) - duration = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION).toLong() - width = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH).toInt() - height = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT).toInt() - orientation = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION).toInt() + duration = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION)?.toLong() ?: 0L + width = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH)?.toInt() ?: 0 + height = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT)?.toInt() ?: 0 + orientation = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_ROTATION)?.toInt() ?: 0 } videoList.add( diff --git a/vector/build.gradle b/vector/build.gradle index f6ba5d6e27..d75bf6c1fe 100644 --- a/vector/build.gradle +++ b/vector/build.gradle @@ -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 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 // Ref: https://issuetracker.google.com/issues/144111441 @@ -111,7 +111,7 @@ android { applicationId "im.vector.app" // Set to API 21: see #405 minSdkVersion 21 - targetSdkVersion 29 + targetSdkVersion 30 multiDexEnabled true // `develop` branch will have version code from timestamp, to ensure each build from CI has a incremented versionCode. diff --git a/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt b/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt index a585e8ea77..3ea995c418 100644 --- a/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt +++ b/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt @@ -23,6 +23,7 @@ import android.os.Bundle import android.view.Menu import android.view.MenuItem import android.view.View +import android.view.WindowInsetsController import android.view.WindowManager import android.widget.TextView import androidx.annotation.AttrRes @@ -33,6 +34,7 @@ import androidx.annotation.StringRes import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.widget.Toolbar import androidx.coordinatorlayout.widget.CoordinatorLayout +import androidx.core.content.ContextCompat import androidx.core.view.isVisible import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentFactory @@ -410,13 +412,21 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScr /** * Force to render the activity in fullscreen */ + @Suppress("DEPRECATION") private fun setFullScreen() { - 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) + 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, im.vector.lib.attachmentviewer.R.color.half_transparent_status_bar) // New API instead of FLAG_TRANSLUCENT_STATUS + window.navigationBarColor = ContextCompat.getColor(this, im.vector.lib.attachmentviewer.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_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) + } } /* ========================================================================================== diff --git a/vector/src/main/java/im/vector/app/features/attachments/preview/AttachmentsPreviewFragment.kt b/vector/src/main/java/im/vector/app/features/attachments/preview/AttachmentsPreviewFragment.kt index 407b51666b..147492fc46 100644 --- a/vector/src/main/java/im/vector/app/features/attachments/preview/AttachmentsPreviewFragment.kt +++ b/vector/src/main/java/im/vector/app/features/attachments/preview/AttachmentsPreviewFragment.kt @@ -153,8 +153,13 @@ class AttachmentsPreviewFragment @Inject constructor( ) } + @Suppress("DEPRECATION") 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 -> v.updatePadding(bottom = insets.systemWindowInsetBottom) insets diff --git a/vector/src/main/java/im/vector/app/features/call/VectorCallActivity.kt b/vector/src/main/java/im/vector/app/features/call/VectorCallActivity.kt index 41bf7bbeaf..ef96bc810a 100644 --- a/vector/src/main/java/im/vector/app/features/call/VectorCallActivity.kt +++ b/vector/src/main/java/im/vector/app/features/call/VectorCallActivity.kt @@ -25,8 +25,11 @@ import android.os.Bundle import android.os.Parcelable import android.view.View import android.view.Window +import android.view.WindowInsets +import android.view.WindowInsetsController import android.view.WindowManager import androidx.appcompat.app.AlertDialog +import androidx.core.content.ContextCompat import androidx.core.content.getSystemService import androidx.core.view.ViewCompat import androidx.core.view.isInvisible @@ -102,29 +105,43 @@ class VectorCallActivity : VectorBaseActivity(), CallContro setContentView(R.layout.activity_call) } + @Suppress("DEPRECATION") private fun hideSystemUI() { systemUiVisibility = false // Enables regular immersive mode. // For "lean back" mode, remove SYSTEM_UI_FLAG_IMMERSIVE. // Or for "sticky immersive," replace it with SYSTEM_UI_FLAG_IMMERSIVE_STICKY - window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_IMMERSIVE - // 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) + if (Build.VERSION.SDK_INT >= 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?.hide(WindowInsets.Type.navigationBars()) // new API instead of SYSTEM_UI_FLAG_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_IMMERSIVE + // 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 // except for the ones that make the content appear under the system bars. + @Suppress("DEPRECATION") private fun showSystemUI() { systemUiVisibility = true - window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE - or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION - or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + window.setDecorFitsSystemWindows(false) // New API instead of SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN and SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + } 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() { diff --git a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapBottomSheet.kt b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapBottomSheet.kt index f1ea50c9bf..149bd629e1 100644 --- a/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapBottomSheet.kt +++ b/vector/src/main/java/im/vector/app/features/crypto/recover/BootstrapBottomSheet.kt @@ -17,6 +17,7 @@ package im.vector.app.features.crypto.recover import android.app.Dialog +import android.os.Build import android.os.Bundle import android.os.Parcelable import android.view.KeyEvent @@ -102,7 +103,12 @@ class BootstrapBottomSheet : VectorBaseBottomSheetDialogFragment= Build.VERSION_CODES.R) { + dialog?.window?.setDecorFitsSystemWindows(false) + } else { + @Suppress("DEPRECATION") + dialog?.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE) + } return rootView } diff --git a/vector/src/main/java/im/vector/app/features/login/LoginWebFragment.kt b/vector/src/main/java/im/vector/app/features/login/LoginWebFragment.kt index 4b03c93321..9ea42308eb 100644 --- a/vector/src/main/java/im/vector/app/features/login/LoginWebFragment.kt +++ b/vector/src/main/java/im/vector/app/features/login/LoginWebFragment.kt @@ -155,18 +155,15 @@ class LoginWebFragment @Inject constructor( // avoid infinite onPageFinished call if (url.startsWith("http")) { // Generic method to make a bridge between JS and the UIWebView - val mxcJavascriptSendObjectMessage = assetReader.readAssetFile("sendObject.js") - view.loadUrl(mxcJavascriptSendObjectMessage) + assetReader.readAssetFile("sendObject.js")?.let { view.loadUrl(it) } if (state.signMode == SignMode.SignIn) { // The function the fallback page calls when the login is complete - val mxcJavascriptOnLogin = assetReader.readAssetFile("onLogin.js") - view.loadUrl(mxcJavascriptOnLogin) + assetReader.readAssetFile("onLogin.js")?.let { view.loadUrl(it) } } else { // MODE_REGISTER // The function the fallback page calls when the registration is complete - val mxcJavascriptOnRegistered = assetReader.readAssetFile("onRegistered.js") - view.loadUrl(mxcJavascriptOnRegistered) + assetReader.readAssetFile("onRegistered.js")?.let { view.loadUrl(it) } } } } diff --git a/vector/src/main/java/im/vector/app/features/popup/PopupAlertManager.kt b/vector/src/main/java/im/vector/app/features/popup/PopupAlertManager.kt index 24fb6159f8..28b2a8b4d5 100644 --- a/vector/src/main/java/im/vector/app/features/popup/PopupAlertManager.kt +++ b/vector/src/main/java/im/vector/app/features/popup/PopupAlertManager.kt @@ -21,6 +21,7 @@ import android.os.Build import android.os.Handler import android.os.Looper import android.view.View +import android.view.WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS import android.widget.ImageView import com.tapadoo.alerter.Alerter import com.tapadoo.alerter.OnHideAlertListener @@ -165,9 +166,7 @@ class PopupAlertManager @Inject constructor(private val avatarRenderer: Lazy - var flags = view.systemUiVisibility - flags = flags and View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR.inv() - view.systemUiVisibility = flags + view.windowInsetsController?.setSystemBarsAppearance(0, APPEARANCE_LIGHT_STATUS_BARS) } } @@ -179,9 +178,7 @@ class PopupAlertManager @Inject constructor(private val avatarRenderer: Lazy - var flags = view.systemUiVisibility - flags = flags or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR - view.systemUiVisibility = flags + view.windowInsetsController?.setSystemBarsAppearance(APPEARANCE_LIGHT_STATUS_BARS, APPEARANCE_LIGHT_STATUS_BARS) } } diff --git a/vector/src/main/java/im/vector/app/features/rageshake/BugReporter.kt b/vector/src/main/java/im/vector/app/features/rageshake/BugReporter.kt index 7be7624a48..fa037a5435 100755 --- a/vector/src/main/java/im/vector/app/features/rageshake/BugReporter.kt +++ b/vector/src/main/java/im/vector/app/features/rageshake/BugReporter.kt @@ -21,7 +21,6 @@ import android.content.Context import android.content.Intent import android.graphics.Bitmap import android.graphics.Canvas -import android.os.AsyncTask import android.os.Build import android.view.View 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.themes.ThemeUtils 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.MediaType.Companion.toMediaTypeOrNull import okhttp3.OkHttpClient @@ -98,6 +102,8 @@ class BugReporter @Inject constructor( var screenshot: Bitmap? = null private set + private val coroutineScope = CoroutineScope(SupervisorJob()) + private val LOGCAT_CMD_ERROR = arrayOf("logcat", // /< Run 'logcat' command "-d", // /< Dump the log rather than continue outputting it "-v", // formatting @@ -160,286 +166,287 @@ class BugReporter @Inject constructor( withScreenshot: Boolean, theBugDescription: String, listener: IMXBugReportListener?) { - object : AsyncTask() { - // enumerate files to delete - val mBugReportFiles: MutableList = ArrayList() + // enumerate files to delete + val mBugReportFiles: MutableList = ArrayList() - override fun doInBackground(vararg voids: Void?): String? { - var bugDescription = theBugDescription - var serverError: String? = null - val crashCallStack = getCrashDescription(context) + coroutineScope.executeAsyncTask( + onPreExecute = { + // NOOP + }, + doInBackground = { publishProgress: suspend (progress: Int) -> Unit -> + var bugDescription = theBugDescription + var serverError: String? = null + val crashCallStack = getCrashDescription(context) - if (null != crashCallStack) { - bugDescription += "\n\n\n\n--------------------------------- crash call stack ---------------------------------\n" - bugDescription += crashCallStack - } - - val gzippedFiles = ArrayList() - - if (withDevicesLogs) { - val files = vectorFileLogger.getLogFiles() - files.mapNotNullTo(gzippedFiles) { f -> - if (!mIsCancelled) { - compressFile(f) - } else { - null - } + if (null != crashCallStack) { + bugDescription += "\n\n\n\n--------------------------------- crash call stack ---------------------------------\n" + bugDescription += crashCallStack } - } - if (!mIsCancelled && (withCrashLogs || withDevicesLogs)) { - val gzippedLogcat = saveLogCat(context, false) + val gzippedFiles = ArrayList() - if (null != gzippedLogcat) { - if (gzippedFiles.size == 0) { - gzippedFiles.add(gzippedLogcat) - } else { - gzippedFiles.add(0, gzippedLogcat) + if (withDevicesLogs) { + val files = vectorFileLogger.getLogFiles() + files.mapNotNullTo(gzippedFiles) { f -> + if (!mIsCancelled) { + compressFile(f) + } else { + null + } } } - val crashDescription = getCrashFile(context) - if (crashDescription.exists()) { - val compressedCrashDescription = compressFile(crashDescription) + if (!mIsCancelled && (withCrashLogs || withDevicesLogs)) { + val gzippedLogcat = saveLogCat(context, false) - if (null != compressedCrashDescription) { + if (null != gzippedLogcat) { if (gzippedFiles.size == 0) { - gzippedFiles.add(compressedCrashDescription) + gzippedFiles.add(gzippedLogcat) } 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() - ?.takeIf { !mIsCancelled && withKeyRequestHistory } - ?.cryptoService() - ?.getGossipingEvents() - ?.let { GossipingEventsSerializer().serialize(it) } - ?.toByteArray() - ?.let { rawByteArray -> - File(context.cacheDir.absolutePath, KEY_REQUESTS_FILENAME) - .also { - it.outputStream() - .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() + activeSessionHolder.getSafeActiveSession() + ?.takeIf { !mIsCancelled && withKeyRequestHistory } + ?.cryptoService() + ?.getGossipingEvents() + ?.let { GossipingEventsSerializer().serialize(it) } + ?.toByteArray() + ?.let { rawByteArray -> + File(context.cacheDir.absolutePath, KEY_REQUESTS_FILENAME) + .also { + it.outputStream() + .use { os -> os.write(rawByteArray) } + } } + ?.let { compressFile(it) } + ?.let { gzippedFiles.add(it) } - try { - logCatScreenshotFile.outputStream().use { - bitmap.compress(Bitmap.CompressFormat.PNG, 100, 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() } - builder.addFormDataPart("file", - logCatScreenshotFile.name, logCatScreenshotFile.asRequestBody(MimeTypes.OctetStream.toMediaTypeOrNull())) - } catch (e: Exception) { - Timber.e(e, "## sendBugReport() : fail to write screenshot$e") + try { + logCatScreenshotFile.outputStream().use { + bitmap.compress(Bitmap.CompressFormat.PNG, 100, it) + } + + 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 - builder.addFormDataPart("label", BuildConfig.VERSION_NAME) - builder.addFormDataPart("label", BuildConfig.FLAVOR_DESCRIPTION) - builder.addFormDataPart("label", context.getString(R.string.git_branch_name)) + // add some github labels + builder.addFormDataPart("label", BuildConfig.VERSION_NAME) + builder.addFormDataPart("label", BuildConfig.FLAVOR_DESCRIPTION) + builder.addFormDataPart("label", context.getString(R.string.git_branch_name)) - // Special for RiotX - builder.addFormDataPart("label", "[Element]") + // Special for RiotX + builder.addFormDataPart("label", "[Element]") - // Suggestion - if (forSuggestion) { - builder.addFormDataPart("label", "[Suggestion]") - } + // Suggestion + if (forSuggestion) { + builder.addFormDataPart("label", "[Suggestion]") + } - if (getCrashFile(context).exists()) { - builder.addFormDataPart("label", "crash") - deleteCrashFile(context) - } + if (getCrashFile(context).exists()) { + builder.addFormDataPart("label", "crash") + deleteCrashFile(context) + } - val requestBody = builder.build() + val requestBody = builder.build() - // add a progress listener - requestBody.setWriteListener { totalWritten, contentLength -> - val percentage = if (-1L != contentLength) { - if (totalWritten > contentLength) { - 100 + // add a progress listener + requestBody.setWriteListener { totalWritten, contentLength -> + val percentage = if (-1L != contentLength) { + if (totalWritten > contentLength) { + 100 + } else { + (totalWritten * 100 / contentLength).toInt() + } } 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) { - mBugReportCall!!.cancel() + // build the request + 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%") - publishProgress(percentage) - } + // 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() - // build the request - 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 - } - - // 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() + serverError = inputStream.use { + buildString { + var ch = it.read() + while (ch != -1) { + append(ch.toChar()) + ch = it.read() + } } } - } - // check if the error message - try { - val responseJSON = JSONObject(serverError) - serverError = responseJSON.getString("error") - } catch (e: JSONException) { - Timber.e(e, "doInBackground ; Json conversion failed") - } + // check if the error message + try { + val responseJSON = JSONObject(serverError) + serverError = responseJSON.getString("error") + } catch (e: JSONException) { + Timber.e(e, "doInBackground ; Json conversion failed") + } - // should never happen - if (null == serverError) { - serverError = "Failed with error $responseCode" + // should never happen + if (null == serverError) { + 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 - } - - override fun onProgressUpdate(vararg progress: Int?) { - if (null != listener) { - try { - listener.onProgress(progress[0] ?: 0) - } catch (e: Exception) { - Timber.e(e, "## onProgress() : failed") - } - } - } - - override fun onPostExecute(reason: String?) { - mBugReportCall = null - - // delete when the bug report has been successfully sent - for (file in mBugReportFiles) { - file.delete() - } - - if (null != listener) { - try { - if (mIsCancelled) { - listener.onUploadCancelled() - } else if (null == reason) { - listener.onUploadSucceed() - } else { - listener.onUploadFailed(reason) + serverError + }, + onProgressUpdate = { progress -> + if (null != listener) { + try { + listener.onProgress(progress) + } catch (e: Exception) { + Timber.e(e, "## onProgress() : failed") + } + } + }, + onPostExecute = { reason: String? -> + mBugReportCall = null + + // delete when the bug report has been successfully sent + for (file in mBugReportFiles) { + file.delete() + } + + if (null != listener) { + try { + if (mIsCancelled) { + listener.onUploadCancelled() + } else if (null == reason) { + listener.onUploadSucceed() + } 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 } + + fun 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) + } } diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/uploads/media/RoomUploadsMediaFragment.kt b/vector/src/main/java/im/vector/app/features/roomprofile/uploads/media/RoomUploadsMediaFragment.kt index 84a419c6c6..fe6dc86165 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/uploads/media/RoomUploadsMediaFragment.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/uploads/media/RoomUploadsMediaFragment.kt @@ -16,6 +16,7 @@ package im.vector.app.features.roomprofile.uploads.media +import android.os.Build import android.os.Bundle import android.util.DisplayMetrics import android.view.LayoutInflater @@ -78,9 +79,14 @@ class RoomUploadsMediaFragment @Inject constructor( controller.listener = this } + @Suppress("DEPRECATION") private fun getNumberOfColumns(): Int { 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 } diff --git a/vector/src/main/java/im/vector/app/features/webview/VectorWebViewActivity.kt b/vector/src/main/java/im/vector/app/features/webview/VectorWebViewActivity.kt index 68c13c300e..e4d2571333 100644 --- a/vector/src/main/java/im/vector/app/features/webview/VectorWebViewActivity.kt +++ b/vector/src/main/java/im/vector/app/features/webview/VectorWebViewActivity.kt @@ -64,7 +64,9 @@ class VectorWebViewActivity : VectorBaseActivity() // Allow use of Local Storage domStorageEnabled = true + @Suppress("DEPRECATION") allowFileAccessFromFileURLs = true + @Suppress("DEPRECATION") allowUniversalAccessFromFileURLs = true displayZoomControls = false @@ -73,7 +75,7 @@ class VectorWebViewActivity : VectorBaseActivity() val cookieManager = android.webkit.CookieManager.getInstance() 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) if (title != USE_TITLE_FROM_WEB_PAGE) { setTitle(title) diff --git a/vector/src/main/java/im/vector/app/features/widgets/webview/WidgetWebView.kt b/vector/src/main/java/im/vector/app/features/widgets/webview/WidgetWebView.kt index 446bc1663f..d30baef55a 100644 --- a/vector/src/main/java/im/vector/app/features/widgets/webview/WidgetWebView.kt +++ b/vector/src/main/java/im/vector/app/features/widgets/webview/WidgetWebView.kt @@ -54,7 +54,9 @@ fun WebView.setupForWidget(webViewEventListener: WebViewEventListener) { // Allow use of Local Storage settings.domStorageEnabled = true + @Suppress("DEPRECATION") settings.allowFileAccessFromFileURLs = true + @Suppress("DEPRECATION") settings.allowUniversalAccessFromFileURLs = true settings.displayZoomControls = false @@ -75,7 +77,6 @@ fun WebView.clearAfterWidget() { // Make sure you remove the WebView from its parent view before doing anything. (parent as? ViewGroup)?.removeAllViews() webChromeClient = null - webViewClient = null clearHistory() // NOTE: clears RAM cache, if you pass true, it will also clear the disk cache. clearCache(true) From fa311f4ce28ba9e0a944d3dce02ec5910338eafd Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Tue, 5 Jan 2021 14:44:02 +0300 Subject: [PATCH 2/5] Fix bug reporter progress. --- .../app/features/rageshake/BugReporter.kt | 516 +++++++++--------- 1 file changed, 246 insertions(+), 270 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/rageshake/BugReporter.kt b/vector/src/main/java/im/vector/app/features/rageshake/BugReporter.kt index fa037a5435..1a03fc6c47 100755 --- a/vector/src/main/java/im/vector/app/features/rageshake/BugReporter.kt +++ b/vector/src/main/java/im/vector/app/features/rageshake/BugReporter.kt @@ -102,7 +102,7 @@ class BugReporter @Inject constructor( var screenshot: Bitmap? = null private set - private val coroutineScope = CoroutineScope(SupervisorJob()) + private val coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Main) private val LOGCAT_CMD_ERROR = arrayOf("logcat", // /< Run 'logcat' command "-d", // /< Dump the log rather than continue outputting it @@ -169,284 +169,277 @@ class BugReporter @Inject constructor( // enumerate files to delete val mBugReportFiles: MutableList = ArrayList() - coroutineScope.executeAsyncTask( - onPreExecute = { - // NOOP - }, - doInBackground = { publishProgress: suspend (progress: Int) -> Unit -> - var bugDescription = theBugDescription - var serverError: String? = null - val crashCallStack = getCrashDescription(context) + coroutineScope.launch { + var serverError: String? = null + withContext(Dispatchers.IO) { + var bugDescription = theBugDescription + val crashCallStack = getCrashDescription(context) - if (null != crashCallStack) { - bugDescription += "\n\n\n\n--------------------------------- crash call stack ---------------------------------\n" - bugDescription += crashCallStack + if (null != crashCallStack) { + bugDescription += "\n\n\n\n--------------------------------- crash call stack ---------------------------------\n" + bugDescription += crashCallStack + } + + val gzippedFiles = ArrayList() + + if (withDevicesLogs) { + val files = vectorFileLogger.getLogFiles() + files.mapNotNullTo(gzippedFiles) { f -> + if (!mIsCancelled) { + compressFile(f) + } else { + null + } } + } - val gzippedFiles = ArrayList() + if (!mIsCancelled && (withCrashLogs || withDevicesLogs)) { + val gzippedLogcat = saveLogCat(context, false) - if (withDevicesLogs) { - val files = vectorFileLogger.getLogFiles() - files.mapNotNullTo(gzippedFiles) { f -> - if (!mIsCancelled) { - compressFile(f) - } else { - null - } + if (null != gzippedLogcat) { + if (gzippedFiles.size == 0) { + gzippedFiles.add(gzippedLogcat) + } else { + gzippedFiles.add(0, gzippedLogcat) } } - if (!mIsCancelled && (withCrashLogs || withDevicesLogs)) { - val gzippedLogcat = saveLogCat(context, false) + val crashDescription = getCrashFile(context) + if (crashDescription.exists()) { + val compressedCrashDescription = compressFile(crashDescription) - if (null != gzippedLogcat) { + if (null != compressedCrashDescription) { if (gzippedFiles.size == 0) { - gzippedFiles.add(gzippedLogcat) + gzippedFiles.add(compressedCrashDescription) } else { - 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) - } + gzippedFiles.add(0, compressedCrashDescription) } } } + } - activeSessionHolder.getSafeActiveSession() - ?.takeIf { !mIsCancelled && withKeyRequestHistory } - ?.cryptoService() - ?.getGossipingEvents() - ?.let { GossipingEventsSerializer().serialize(it) } - ?.toByteArray() - ?.let { rawByteArray -> - File(context.cacheDir.absolutePath, KEY_REQUESTS_FILENAME) - .also { - it.outputStream() - .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() - } - - try { - logCatScreenshotFile.outputStream().use { - bitmap.compress(Bitmap.CompressFormat.PNG, 100, it) + activeSessionHolder.getSafeActiveSession() + ?.takeIf { !mIsCancelled && withKeyRequestHistory } + ?.cryptoService() + ?.getGossipingEvents() + ?.let { GossipingEventsSerializer().serialize(it) } + ?.toByteArray() + ?.let { rawByteArray -> + File(context.cacheDir.absolutePath, KEY_REQUESTS_FILENAME) + .also { + it.outputStream() + .use { os -> os.write(rawByteArray) } } - - builder.addFormDataPart("file", - logCatScreenshotFile.name, logCatScreenshotFile.asRequestBody(MimeTypes.OctetStream.toMediaTypeOrNull())) - } catch (e: Exception) { - Timber.e(e, "## sendBugReport() : fail to write screenshot$e") - } - } } + ?.let { compressFile(it) } + ?.let { gzippedFiles.add(it) } - screenshot = null + var deviceId = "undefined" + var userId = "undefined" + var olmVersion = "undefined" - // add some github labels - builder.addFormDataPart("label", BuildConfig.VERSION_NAME) - builder.addFormDataPart("label", BuildConfig.FLAVOR_DESCRIPTION) - builder.addFormDataPart("label", context.getString(R.string.git_branch_name)) + activeSessionHolder.getSafeActiveSession()?.let { session -> + userId = session.myUserId + deviceId = session.sessionParams.deviceId ?: "undefined" + olmVersion = session.cryptoService().getCryptoVersion(context, true) + } - // Special for RiotX - builder.addFormDataPart("label", "[Element]") - - // Suggestion - if (forSuggestion) { - builder.addFormDataPart("label", "[Suggestion]") - } - - if (getCrashFile(context).exists()) { - builder.addFormDataPart("label", "crash") - deleteCrashFile(context) - } - - val requestBody = builder.build() - - // add a progress listener - requestBody.setWriteListener { totalWritten, contentLength -> - val percentage = if (-1L != contentLength) { - if (totalWritten > contentLength) { - 100 - } else { - (totalWritten * 100 / contentLength).toInt() - } + if (!mIsCancelled) { + val text = "[Element] " + + if (forSuggestion) { + "[Suggestion] " } else { - 0 + "" + } + + 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() } - if (mIsCancelled && null != mBugReportCall) { - mBugReportCall!!.cancel() - } + try { + logCatScreenshotFile.outputStream().use { + bitmap.compress(Bitmap.CompressFormat.PNG, 100, it) + } - Timber.v("## onWrite() : $percentage%") - suspend { publishProgress(percentage) } + builder.addFormDataPart("file", + logCatScreenshotFile.name, logCatScreenshotFile.asRequestBody(MimeTypes.OctetStream.toMediaTypeOrNull())) + } catch (e: Exception) { + Timber.e(e, "## sendBugReport() : fail to write screenshot$e") + } + } + } + + screenshot = null + + // add some github labels + builder.addFormDataPart("label", BuildConfig.VERSION_NAME) + builder.addFormDataPart("label", BuildConfig.FLAVOR_DESCRIPTION) + builder.addFormDataPart("label", context.getString(R.string.git_branch_name)) + + // Special for RiotX + builder.addFormDataPart("label", "[Element]") + + // Suggestion + if (forSuggestion) { + builder.addFormDataPart("label", "[Suggestion]") + } + + if (getCrashFile(context).exists()) { + builder.addFormDataPart("label", "crash") + deleteCrashFile(context) + } + + val requestBody = builder.build() + + // add a progress listener + requestBody.setWriteListener { totalWritten, contentLength -> + val percentage = if (-1L != contentLength) { + if (totalWritten > contentLength) { + 100 + } else { + (totalWritten * 100 / contentLength).toInt() + } + } else { + 0 } - // build the request - val request = Request.Builder() - .url(context.getString(R.string.bug_report_url)) - .post(requestBody) - .build() + if (mIsCancelled && null != mBugReportCall) { + mBugReportCall!!.cancel() + } - var responseCode = HttpURLConnection.HTTP_INTERNAL_ERROR - var response: Response? = null - var errorMessage: String? = null - - // trigger the request + Timber.v("## onWrite() : $percentage%") 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 - try { - val responseJSON = JSONObject(serverError) - serverError = responseJSON.getString("error") - } catch (e: JSONException) { - Timber.e(e, "doInBackground ; Json conversion failed") - } - - // should never happen - if (null == serverError) { - serverError = "Failed with error $responseCode" - } - } catch (e: Exception) { - Timber.e(e, "## sendBugReport() : failed to parse error") - } - } - } - } - - serverError - }, - onProgressUpdate = { progress -> - if (null != listener) { - try { - listener.onProgress(progress) + listener?.onProgress(percentage) } catch (e: Exception) { Timber.e(e, "## onProgress() : failed") } } - }, - onPostExecute = { reason: String? -> - mBugReportCall = null - // delete when the bug report has been successfully sent - for (file in mBugReportFiles) { - file.delete() + // build the request + 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 } - if (null != listener) { - try { - if (mIsCancelled) { - listener.onUploadCancelled() - } else if (null == reason) { - listener.onUploadSucceed() - } else { - listener.onUploadFailed(reason) + // 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 + serverError?.let { + try { + val responseJSON = JSONObject(it) + serverError = responseJSON.getString("error") + } catch (e: JSONException) { + Timber.e(e, "doInBackground ; Json conversion failed") + } + } + + // should never happen + if (null == serverError) { + serverError = "Failed with error $responseCode" + } + } catch (e: Exception) { + Timber.e(e, "## sendBugReport() : failed to parse error") } - } catch (e: Exception) { - Timber.e(e, "## onPostExecute() : failed") } } } - ) + } + + withContext(Dispatchers.Main) { + mBugReportCall = null + + // delete when the bug report has been successfully sent + for (file in mBugReportFiles) { + file.delete() + } + + if (null != listener) { + try { + if (mIsCancelled) { + listener.onUploadCancelled() + } else if (null == serverError) { + listener.onUploadSucceed() + } else { + listener.onUploadFailed(serverError) + } + } catch (e: Exception) { + Timber.e(e, "## onPostExecute() : failed") + } + } + } + } } /** @@ -464,9 +457,9 @@ class BugReporter @Inject constructor( activity.startActivity(intent) } - // ============================================================================================================== - // crash report management - // ============================================================================================================== +// ============================================================================================================== +// crash report management +// ============================================================================================================== /** * Provides the crash file @@ -536,9 +529,9 @@ class BugReporter @Inject constructor( return null } - // ============================================================================================================== - // Screenshot management - // ============================================================================================================== +// ============================================================================================================== +// Screenshot management +// ============================================================================================================== /** * Take a screenshot of the display. @@ -605,9 +598,9 @@ class BugReporter @Inject constructor( } } - // ============================================================================================================== - // Logcat management - // ============================================================================================================== +// ============================================================================================================== +// Logcat management +// ============================================================================================================== /** * Save the logcat @@ -667,9 +660,9 @@ class BugReporter @Inject constructor( } } - // ============================================================================================================== - // File compression management - // ============================================================================================================== +// ============================================================================================================== +// File compression management +// ============================================================================================================== /** * GZip a file @@ -703,21 +696,4 @@ class BugReporter @Inject constructor( return null } - - fun 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) - } } From 869eb262f33ee87cdfeffcf128c166d4586e87df Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Wed, 6 Jan 2021 12:49:11 +0300 Subject: [PATCH 3/5] Lint fixes. --- .../AttachmentViewerActivity.kt | 37 ++++++++++++------- .../app/core/platform/VectorBaseActivity.kt | 15 +++++--- .../preview/AttachmentsPreviewFragment.kt | 3 +- .../app/features/call/VectorCallActivity.kt | 18 ++++++--- 4 files changed, 48 insertions(+), 25 deletions(-) diff --git a/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/AttachmentViewerActivity.kt b/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/AttachmentViewerActivity.kt index 1d09e1ef0e..88109e7ea0 100644 --- a/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/AttachmentViewerActivity.kt +++ b/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/AttachmentViewerActivity.kt @@ -18,6 +18,7 @@ package im.vector.lib.attachmentviewer import android.graphics.Color +import android.os.Build import android.os.Bundle import android.view.GestureDetector import android.view.MotionEvent @@ -132,11 +133,15 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi 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 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + // New API instead of SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN and SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + window.setDecorFitsSystemWindows(false) + // New API instead of SYSTEM_UI_FLAG_IMMERSIVE + window.decorView.windowInsetsController?.systemBarsBehavior = WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_SWIPE + // New API instead of FLAG_TRANSLUCENT_STATUS + window.statusBarColor = ContextCompat.getColor(this, R.color.half_transparent_status_bar) + // new API instead of FLAG_TRANSLUCENT_NAVIGATION + window.navigationBarColor = ContextCompat.getColor(this, R.color.half_transparent_status_bar) } else { window.decorView.systemUiVisibility = ( View.SYSTEM_UI_FLAG_LAYOUT_STABLE @@ -332,12 +337,17 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi // Enables regular immersive mode. // For "lean back" mode, remove SYSTEM_UI_FLAG_IMMERSIVE. // Or for "sticky immersive," replace it with SYSTEM_UI_FLAG_IMMERSIVE_STICKY - 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?.hide(WindowInsets.Type.navigationBars()) // new API instead of SYSTEM_UI_FLAG_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 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + // New API instead of SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN and SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + window.setDecorFitsSystemWindows(false) + // new API instead of SYSTEM_UI_FLAG_HIDE_NAVIGATION + window.decorView.windowInsetsController?.hide(WindowInsets.Type.navigationBars()) + // New API instead of SYSTEM_UI_FLAG_IMMERSIVE + window.decorView.windowInsetsController?.systemBarsBehavior = WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_SWIPE + // New API instead of FLAG_TRANSLUCENT_STATUS + window.statusBarColor = ContextCompat.getColor(this, R.color.half_transparent_status_bar) + // New API instead of FLAG_TRANSLUCENT_NAVIGATION + window.navigationBarColor = ContextCompat.getColor(this, R.color.half_transparent_status_bar) } else { window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_IMMERSIVE // Set the content to appear under the system bars so that the @@ -356,8 +366,9 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi @Suppress("DEPRECATION") private fun showSystemUI() { systemUiVisibility = true - 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 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + // New API instead of SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN and SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + window.setDecorFitsSystemWindows(false) } else { window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION diff --git a/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt b/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt index 3ea995c418..d8b61f3cba 100644 --- a/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt +++ b/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt @@ -19,6 +19,7 @@ package im.vector.app.core.platform import android.app.Activity import android.content.Context import android.content.res.Configuration +import android.os.Build import android.os.Bundle import android.view.Menu import android.view.MenuItem @@ -414,11 +415,15 @@ abstract class VectorBaseActivity : AppCompatActivity(), HasScr */ @Suppress("DEPRECATION") private fun setFullScreen() { - 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, im.vector.lib.attachmentviewer.R.color.half_transparent_status_bar) // New API instead of FLAG_TRANSLUCENT_STATUS - window.navigationBarColor = ContextCompat.getColor(this, im.vector.lib.attachmentviewer.R.color.half_transparent_status_bar) // new API instead of FLAG_TRANSLUCENT_NAVIGATION + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + // New API instead of SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN and SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + window.setDecorFitsSystemWindows(false) + // New API instead of SYSTEM_UI_FLAG_IMMERSIVE + window.decorView.windowInsetsController?.systemBarsBehavior = WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_SWIPE + // New API instead of FLAG_TRANSLUCENT_STATUS + window.statusBarColor = ContextCompat.getColor(this, im.vector.lib.attachmentviewer.R.color.half_transparent_status_bar) + // New API instead of FLAG_TRANSLUCENT_NAVIGATION + window.navigationBarColor = ContextCompat.getColor(this, im.vector.lib.attachmentviewer.R.color.half_transparent_status_bar) } else { window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION diff --git a/vector/src/main/java/im/vector/app/features/attachments/preview/AttachmentsPreviewFragment.kt b/vector/src/main/java/im/vector/app/features/attachments/preview/AttachmentsPreviewFragment.kt index 147492fc46..cdb015e4da 100644 --- a/vector/src/main/java/im/vector/app/features/attachments/preview/AttachmentsPreviewFragment.kt +++ b/vector/src/main/java/im/vector/app/features/attachments/preview/AttachmentsPreviewFragment.kt @@ -19,6 +19,7 @@ package im.vector.app.features.attachments.preview import android.app.Activity.RESULT_CANCELED import android.app.Activity.RESULT_OK +import android.os.Build import android.os.Bundle import android.os.Parcelable import android.view.LayoutInflater @@ -155,7 +156,7 @@ class AttachmentsPreviewFragment @Inject constructor( @Suppress("DEPRECATION") private fun applyInsets() { - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) { + if (Build.VERSION.SDK_INT >= 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 diff --git a/vector/src/main/java/im/vector/app/features/call/VectorCallActivity.kt b/vector/src/main/java/im/vector/app/features/call/VectorCallActivity.kt index ef96bc810a..6c49d4d3e2 100644 --- a/vector/src/main/java/im/vector/app/features/call/VectorCallActivity.kt +++ b/vector/src/main/java/im/vector/app/features/call/VectorCallActivity.kt @@ -112,11 +112,16 @@ class VectorCallActivity : VectorBaseActivity(), CallContro // For "lean back" mode, remove SYSTEM_UI_FLAG_IMMERSIVE. // Or for "sticky immersive," replace it with SYSTEM_UI_FLAG_IMMERSIVE_STICKY if (Build.VERSION.SDK_INT >= 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?.hide(WindowInsets.Type.navigationBars()) // new API instead of SYSTEM_UI_FLAG_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 + // New API instead of SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN and SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + window.setDecorFitsSystemWindows(false) + // New API instead of SYSTEM_UI_FLAG_HIDE_NAVIGATION + window.decorView.windowInsetsController?.hide(WindowInsets.Type.navigationBars()) + // New API instead of SYSTEM_UI_FLAG_IMMERSIVE + window.decorView.windowInsetsController?.systemBarsBehavior = WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_SWIPE + // New API instead of FLAG_TRANSLUCENT_STATUS + window.statusBarColor = ContextCompat.getColor(this, R.color.half_transparent_status_bar) + // New API instead of FLAG_TRANSLUCENT_NAVIGATION + window.navigationBarColor = ContextCompat.getColor(this, R.color.half_transparent_status_bar) } else { window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_IMMERSIVE // Set the content to appear under the system bars so that the @@ -136,7 +141,8 @@ class VectorCallActivity : VectorBaseActivity(), CallContro private fun showSystemUI() { systemUiVisibility = true if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { - window.setDecorFitsSystemWindows(false) // New API instead of SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN and SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + // New API instead of SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN and SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION + window.setDecorFitsSystemWindows(false) } else { window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION From e948e9d85ad3f4ba84b85bfe82337762c02bec88 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Wed, 6 Jan 2021 16:28:45 +0300 Subject: [PATCH 4/5] Lint fixes. --- .../main/java/im/vector/app/features/call/CallAudioManager.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vector/src/main/java/im/vector/app/features/call/CallAudioManager.kt b/vector/src/main/java/im/vector/app/features/call/CallAudioManager.kt index 3a24cf6d48..82bbaf1d54 100644 --- a/vector/src/main/java/im/vector/app/features/call/CallAudioManager.kt +++ b/vector/src/main/java/im/vector/app/features/call/CallAudioManager.kt @@ -48,7 +48,7 @@ class CallAudioManager( private var savedIsSpeakerPhoneOn = false private var savedIsMicrophoneMute = false - private var savedAudioMode = AudioManager.MODE_INVALID + private var savedAudioMode = AudioManager.MODE_NORMAL private var connectedBlueToothHeadset: BluetoothProfile? = null private var wantsBluetoothConnection = false From 883a7cecf0ab17a03d7b876995cc20b7c3013a07 Mon Sep 17 00:00:00 2001 From: Onuray Sahin Date: Fri, 22 Jan 2021 15:34:40 +0300 Subject: [PATCH 5/5] Fix viewbinding npe crashes. --- CHANGES.md | 1 + .../java/im/vector/app/ui/UiAllScreensSanityTest.kt | 2 ++ .../app/features/home/room/detail/RoomDetailFragment.kt | 5 ++++- .../app/features/home/room/detail/search/SearchFragment.kt | 4 ++-- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index b2483df78d..d6e3a9b21a 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -10,6 +10,7 @@ Improvements 🙌: Bugfix 🐛: - Fix clear cache issue: sometimes, after a clear cache, there is still a token, so the init sync service is not started. - Sidebar too large in horizontal orientation or tablets (#475) + - Crashes reported by PlayStore (new in 1.0.14) (#2707) Translations 🗣: - diff --git a/vector/src/androidTest/java/im/vector/app/ui/UiAllScreensSanityTest.kt b/vector/src/androidTest/java/im/vector/app/ui/UiAllScreensSanityTest.kt index 58b596b05f..2d0077fc55 100644 --- a/vector/src/androidTest/java/im/vector/app/ui/UiAllScreensSanityTest.kt +++ b/vector/src/androidTest/java/im/vector/app/ui/UiAllScreensSanityTest.kt @@ -196,6 +196,8 @@ class UiAllScreensSanityTest { pressBack() clickMenu(R.id.video_call) pressBack() + clickMenu(R.id.search) + pressBack() pressBack() } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt index e134230c61..2d2059377c 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailFragment.kt @@ -297,6 +297,8 @@ class RoomDetailFragment @Inject constructor( private var lockSendButton = false private val activeCallViewHolder = ActiveCallViewHolder() + private lateinit var emojiPopup: EmojiPopup + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) sharedActionViewModel = activityViewModelProvider.get(MessageSharedActionViewModel::class.java) @@ -512,7 +514,7 @@ class RoomDetailFragment @Inject constructor( } private fun setupEmojiPopup() { - val emojiPopup = EmojiPopup + emojiPopup = EmojiPopup .Builder .fromRootView(views.rootConstraintLayout) .setKeyboardAnimationStyle(R.style.emoji_fade_animation_style) @@ -591,6 +593,7 @@ class RoomDetailFragment @Inject constructor( autoCompleter.clear() debouncer.cancelAll() views.timelineRecyclerView.cleanup() + emojiPopup.dismiss() super.onDestroyView() } diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchFragment.kt index 8a8701e45f..9a57d9480c 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchFragment.kt @@ -76,10 +76,10 @@ class SearchFragment @Inject constructor( controller.listener = this } - override fun onDestroy() { - super.onDestroy() + override fun onDestroyView() { views.searchResultRecycler.cleanup() controller.listener = null + super.onDestroyView() } override fun invalidate() = withState(searchViewModel) { state ->