diff --git a/CHANGES.md b/CHANGES.md index a8aabb213d..501940dd18 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -11,15 +11,16 @@ 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) - When receiving a new pepper from identity server, use it on the next hash lookup (#2708) + - Crashes reported by PlayStore (new in 1.0.14) (#2707) 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 9b1345cd39..418b5b5cbb 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,15 +18,19 @@ 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 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 @@ -94,14 +98,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) @@ -134,6 +131,29 @@ 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 (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 + 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) @@ -313,28 +333,48 @@ 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 (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 + // 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) { + // 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 + 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 7d5432ebb8..836b49b3f2 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 71cbe532c3..ced0899cf9 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/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/core/platform/VectorBaseActivity.kt b/vector/src/main/java/im/vector/app/core/platform/VectorBaseActivity.kt index a585e8ea77..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,10 +19,12 @@ 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 import android.view.View +import android.view.WindowInsetsController import android.view.WindowManager import android.widget.TextView import androidx.annotation.AttrRes @@ -33,6 +35,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 +413,25 @@ 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 (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 + 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..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 @@ -153,8 +154,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 (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 + } ViewCompat.setOnApplyWindowInsetsListener(views.attachmentPreviewerBottomContainer) { v, insets -> v.updatePadding(bottom = insets.systemWindowInsetBottom) insets 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 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..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 @@ -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,49 @@ 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) { + // 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 + // 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) { + // 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 + 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/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 -> 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..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 @@ -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() + Dispatchers.Main) + private val LOGCAT_CMD_ERROR = arrayOf("logcat", // /< Run 'logcat' command "-d", // /< Dump the log rather than continue outputting it "-v", // formatting @@ -160,13 +166,13 @@ 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? { + coroutineScope.launch { + var serverError: String? = null + withContext(Dispatchers.IO) { var bugDescription = theBugDescription - var serverError: String? = null val crashCallStack = getCrashDescription(context) if (null != crashCallStack) { @@ -342,7 +348,11 @@ class BugReporter @Inject constructor( } Timber.v("## onWrite() : $percentage%") - publishProgress(percentage) + try { + listener?.onProgress(percentage) + } catch (e: Exception) { + Timber.e(e, "## onProgress() : failed") + } } // build the request @@ -386,11 +396,13 @@ class BugReporter @Inject constructor( } // check if the error message - try { - val responseJSON = JSONObject(serverError) - serverError = responseJSON.getString("error") - } catch (e: JSONException) { - Timber.e(e, "doInBackground ; Json conversion failed") + serverError?.let { + try { + val responseJSON = JSONObject(it) + serverError = responseJSON.getString("error") + } catch (e: JSONException) { + Timber.e(e, "doInBackground ; Json conversion failed") + } } // should never happen @@ -403,21 +415,9 @@ class BugReporter @Inject constructor( } } } - - 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?) { + withContext(Dispatchers.Main) { mBugReportCall = null // delete when the bug report has been successfully sent @@ -429,17 +429,17 @@ class BugReporter @Inject constructor( try { if (mIsCancelled) { listener.onUploadCancelled() - } else if (null == reason) { + } else if (null == serverError) { listener.onUploadSucceed() } else { - listener.onUploadFailed(reason) + listener.onUploadFailed(serverError) } } catch (e: Exception) { Timber.e(e, "## onPostExecute() : failed") } } } - }.execute() + } } /** @@ -457,9 +457,9 @@ class BugReporter @Inject constructor( activity.startActivity(intent) } - // ============================================================================================================== - // crash report management - // ============================================================================================================== +// ============================================================================================================== +// crash report management +// ============================================================================================================== /** * Provides the crash file @@ -529,9 +529,9 @@ class BugReporter @Inject constructor( return null } - // ============================================================================================================== - // Screenshot management - // ============================================================================================================== +// ============================================================================================================== +// Screenshot management +// ============================================================================================================== /** * Take a screenshot of the display. @@ -598,9 +598,9 @@ class BugReporter @Inject constructor( } } - // ============================================================================================================== - // Logcat management - // ============================================================================================================== +// ============================================================================================================== +// Logcat management +// ============================================================================================================== /** * Save the logcat @@ -660,9 +660,9 @@ class BugReporter @Inject constructor( } } - // ============================================================================================================== - // File compression management - // ============================================================================================================== +// ============================================================================================================== +// File compression management +// ============================================================================================================== /** * GZip a file 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)