Merge branch 'develop' into develop

This commit is contained in:
Benoit Marty 2021-01-22 17:20:36 +01:00 committed by GitHub
commit 0a96841336
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 239 additions and 132 deletions

View file

@ -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. - 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) - 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) - 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 🗣: Translations 🗣:
- -
SDK API changes ⚠️: SDK API changes ⚠️:
- - Increase targetSdkVersion to 30 (#2600)
Build 🧱: Build 🧱:
- - Compile with Android SDK 30 (Android 11)
Test: Test:
- -

View file

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

View file

@ -18,15 +18,19 @@
package im.vector.lib.attachmentviewer package im.vector.lib.attachmentviewer
import android.graphics.Color import android.graphics.Color
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.view.GestureDetector import android.view.GestureDetector
import android.view.MotionEvent import android.view.MotionEvent
import android.view.ScaleGestureDetector import android.view.ScaleGestureDetector
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.WindowInsets
import android.view.WindowInsetsController
import android.view.WindowManager import android.view.WindowManager
import android.widget.ImageView import android.widget.ImageView
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.view.GestureDetectorCompat import androidx.core.view.GestureDetectorCompat
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
import androidx.core.view.isVisible import androidx.core.view.isVisible
@ -94,14 +98,7 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
// This is important for the dispatchTouchEvent, if not we must correct setDecorViewFullScreen()
// the touch coordinates
window.decorView.systemUiVisibility = (
View.SYSTEM_UI_FLAG_LAYOUT_STABLE
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
or View.SYSTEM_UI_FLAG_IMMERSIVE)
window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS, WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
window.setFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION, WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION)
views = ActivityAttachmentViewerBinding.inflate(layoutInflater) views = ActivityAttachmentViewerBinding.inflate(layoutInflater)
setContentView(views.root) setContentView(views.root)
@ -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) { fun onSelectedPositionChanged(position: Int) {
attachmentsAdapter.recyclerView?.findViewHolderForAdapterPosition(currentPosition)?.let { attachmentsAdapter.recyclerView?.findViewHolderForAdapterPosition(currentPosition)?.let {
(it as? BaseViewHolder)?.onSelected(false) (it as? BaseViewHolder)?.onSelected(false)
@ -313,11 +333,24 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi
?.handleCommand(commands) ?.handleCommand(commands)
} }
@Suppress("DEPRECATION")
private fun hideSystemUI() { private fun hideSystemUI() {
systemUiVisibility = false systemUiVisibility = false
// Enables regular immersive mode. // Enables regular immersive mode.
// For "lean back" mode, remove SYSTEM_UI_FLAG_IMMERSIVE. // For "lean back" mode, remove SYSTEM_UI_FLAG_IMMERSIVE.
// Or for "sticky immersive," replace it with SYSTEM_UI_FLAG_IMMERSIVE_STICKY // Or for "sticky immersive," replace it with SYSTEM_UI_FLAG_IMMERSIVE_STICKY
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 window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_IMMERSIVE
// Set the content to appear under the system bars so that the // Set the content to appear under the system bars so that the
// content doesn't resize when the system bars hide and show. // content doesn't resize when the system bars hide and show.
@ -328,13 +361,20 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi
or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
or View.SYSTEM_UI_FLAG_FULLSCREEN) or View.SYSTEM_UI_FLAG_FULLSCREEN)
} }
}
// Shows the system bars by removing all the flags // Shows the system bars by removing all the flags
// except for the ones that make the content appear under the system bars. // except for the ones that make the content appear under the system bars.
@Suppress("DEPRECATION")
private fun showSystemUI() { private fun showSystemUI() {
systemUiVisibility = true systemUiVisibility = true
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 window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)
} }
} }
}

View file

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

View file

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

View file

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

View file

@ -47,8 +47,7 @@ internal object ThumbnailExtractor {
val mediaMetadataRetriever = MediaMetadataRetriever() val mediaMetadataRetriever = MediaMetadataRetriever()
try { try {
mediaMetadataRetriever.setDataSource(context, attachment.queryUri) mediaMetadataRetriever.setDataSource(context, attachment.queryUri)
val thumbnail = mediaMetadataRetriever.frameAtTime mediaMetadataRetriever.frameAtTime?.let { thumbnail ->
val outputStream = ByteArrayOutputStream() val outputStream = ByteArrayOutputStream()
thumbnail.compress(Bitmap.CompressFormat.JPEG, 100, outputStream) thumbnail.compress(Bitmap.CompressFormat.JPEG, 100, outputStream)
val thumbnailWidth = thumbnail.width val thumbnailWidth = thumbnail.width
@ -63,6 +62,9 @@ internal object ThumbnailExtractor {
) )
thumbnail.recycle() thumbnail.recycle()
outputStream.reset() outputStream.reset()
} ?: run {
Timber.e("Cannot extract video thumbnail at %s", attachment.queryUri.toString())
}
} catch (e: Exception) { } catch (e: Exception) {
Timber.e(e, "Cannot extract video thumbnail") Timber.e(e, "Cannot extract video thumbnail")
} finally { } finally {

View file

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

View file

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

View file

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

View file

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

View file

@ -196,6 +196,8 @@ class UiAllScreensSanityTest {
pressBack() pressBack()
clickMenu(R.id.video_call) clickMenu(R.id.video_call)
pressBack() pressBack()
clickMenu(R.id.search)
pressBack()
pressBack() pressBack()
} }

View file

@ -19,10 +19,12 @@ package im.vector.app.core.platform
import android.app.Activity import android.app.Activity
import android.content.Context import android.content.Context
import android.content.res.Configuration import android.content.res.Configuration
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.view.Menu import android.view.Menu
import android.view.MenuItem import android.view.MenuItem
import android.view.View import android.view.View
import android.view.WindowInsetsController
import android.view.WindowManager import android.view.WindowManager
import android.widget.TextView import android.widget.TextView
import androidx.annotation.AttrRes import androidx.annotation.AttrRes
@ -33,6 +35,7 @@ import androidx.annotation.StringRes
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.Toolbar import androidx.appcompat.widget.Toolbar
import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.content.ContextCompat
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentFactory import androidx.fragment.app.FragmentFactory
@ -410,7 +413,18 @@ abstract class VectorBaseActivity<VB: ViewBinding> : AppCompatActivity(), HasScr
/** /**
* Force to render the activity in fullscreen * Force to render the activity in fullscreen
*/ */
@Suppress("DEPRECATION")
private fun setFullScreen() { private fun setFullScreen() {
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 window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
@ -418,6 +432,7 @@ abstract class VectorBaseActivity<VB: ViewBinding> : AppCompatActivity(), HasScr
or View.SYSTEM_UI_FLAG_FULLSCREEN or View.SYSTEM_UI_FLAG_FULLSCREEN
or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY) or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY)
} }
}
/* ========================================================================================== /* ==========================================================================================
* MENU MANAGEMENT * MENU MANAGEMENT

View file

@ -19,6 +19,7 @@ package im.vector.app.features.attachments.preview
import android.app.Activity.RESULT_CANCELED import android.app.Activity.RESULT_CANCELED
import android.app.Activity.RESULT_OK import android.app.Activity.RESULT_OK
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.os.Parcelable import android.os.Parcelable
import android.view.LayoutInflater import android.view.LayoutInflater
@ -153,8 +154,13 @@ class AttachmentsPreviewFragment @Inject constructor(
) )
} }
@Suppress("DEPRECATION")
private fun applyInsets() { private fun applyInsets() {
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 view?.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
}
ViewCompat.setOnApplyWindowInsetsListener(views.attachmentPreviewerBottomContainer) { v, insets -> ViewCompat.setOnApplyWindowInsetsListener(views.attachmentPreviewerBottomContainer) { v, insets ->
v.updatePadding(bottom = insets.systemWindowInsetBottom) v.updatePadding(bottom = insets.systemWindowInsetBottom)
insets insets

View file

@ -48,7 +48,7 @@ class CallAudioManager(
private var savedIsSpeakerPhoneOn = false private var savedIsSpeakerPhoneOn = false
private var savedIsMicrophoneMute = false private var savedIsMicrophoneMute = false
private var savedAudioMode = AudioManager.MODE_INVALID private var savedAudioMode = AudioManager.MODE_NORMAL
private var connectedBlueToothHeadset: BluetoothProfile? = null private var connectedBlueToothHeadset: BluetoothProfile? = null
private var wantsBluetoothConnection = false private var wantsBluetoothConnection = false

View file

@ -25,8 +25,11 @@ import android.os.Bundle
import android.os.Parcelable import android.os.Parcelable
import android.view.View import android.view.View
import android.view.Window import android.view.Window
import android.view.WindowInsets
import android.view.WindowInsetsController
import android.view.WindowManager import android.view.WindowManager
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.core.content.ContextCompat
import androidx.core.content.getSystemService import androidx.core.content.getSystemService
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
import androidx.core.view.isInvisible import androidx.core.view.isInvisible
@ -102,11 +105,24 @@ class VectorCallActivity : VectorBaseActivity<ActivityCallBinding>(), CallContro
setContentView(R.layout.activity_call) setContentView(R.layout.activity_call)
} }
@Suppress("DEPRECATION")
private fun hideSystemUI() { private fun hideSystemUI() {
systemUiVisibility = false systemUiVisibility = false
// Enables regular immersive mode. // Enables regular immersive mode.
// For "lean back" mode, remove SYSTEM_UI_FLAG_IMMERSIVE. // For "lean back" mode, remove SYSTEM_UI_FLAG_IMMERSIVE.
// Or for "sticky immersive," replace it with SYSTEM_UI_FLAG_IMMERSIVE_STICKY // Or for "sticky immersive," replace it with SYSTEM_UI_FLAG_IMMERSIVE_STICKY
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 window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_IMMERSIVE
// Set the content to appear under the system bars so that the // Set the content to appear under the system bars so that the
// content doesn't resize when the system bars hide and show. // content doesn't resize when the system bars hide and show.
@ -117,15 +133,22 @@ class VectorCallActivity : VectorBaseActivity<ActivityCallBinding>(), CallContro
or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
or View.SYSTEM_UI_FLAG_FULLSCREEN) or View.SYSTEM_UI_FLAG_FULLSCREEN)
} }
}
// Shows the system bars by removing all the flags // Shows the system bars by removing all the flags
// except for the ones that make the content appear under the system bars. // except for the ones that make the content appear under the system bars.
@Suppress("DEPRECATION")
private fun showSystemUI() { private fun showSystemUI() {
systemUiVisibility = true systemUiVisibility = true
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 window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE
or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)
} }
}
private fun toggleUiSystemVisibility() { private fun toggleUiSystemVisibility() {
if (systemUiVisibility) { if (systemUiVisibility) {

View file

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

View file

@ -297,6 +297,8 @@ class RoomDetailFragment @Inject constructor(
private var lockSendButton = false private var lockSendButton = false
private val activeCallViewHolder = ActiveCallViewHolder() private val activeCallViewHolder = ActiveCallViewHolder()
private lateinit var emojiPopup: EmojiPopup
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
sharedActionViewModel = activityViewModelProvider.get(MessageSharedActionViewModel::class.java) sharedActionViewModel = activityViewModelProvider.get(MessageSharedActionViewModel::class.java)
@ -512,7 +514,7 @@ class RoomDetailFragment @Inject constructor(
} }
private fun setupEmojiPopup() { private fun setupEmojiPopup() {
val emojiPopup = EmojiPopup emojiPopup = EmojiPopup
.Builder .Builder
.fromRootView(views.rootConstraintLayout) .fromRootView(views.rootConstraintLayout)
.setKeyboardAnimationStyle(R.style.emoji_fade_animation_style) .setKeyboardAnimationStyle(R.style.emoji_fade_animation_style)
@ -591,6 +593,7 @@ class RoomDetailFragment @Inject constructor(
autoCompleter.clear() autoCompleter.clear()
debouncer.cancelAll() debouncer.cancelAll()
views.timelineRecyclerView.cleanup() views.timelineRecyclerView.cleanup()
emojiPopup.dismiss()
super.onDestroyView() super.onDestroyView()
} }

View file

@ -76,10 +76,10 @@ class SearchFragment @Inject constructor(
controller.listener = this controller.listener = this
} }
override fun onDestroy() { override fun onDestroyView() {
super.onDestroy()
views.searchResultRecycler.cleanup() views.searchResultRecycler.cleanup()
controller.listener = null controller.listener = null
super.onDestroyView()
} }
override fun invalidate() = withState(searchViewModel) { state -> override fun invalidate() = withState(searchViewModel) { state ->

View file

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

View file

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

View file

@ -21,7 +21,6 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import android.graphics.Bitmap import android.graphics.Bitmap
import android.graphics.Canvas import android.graphics.Canvas
import android.os.AsyncTask
import android.os.Build import android.os.Build
import android.view.View import android.view.View
import androidx.fragment.app.DialogFragment import androidx.fragment.app.DialogFragment
@ -37,6 +36,11 @@ import im.vector.app.features.settings.devtools.GossipingEventsSerializer
import im.vector.app.features.settings.locale.SystemLocaleProvider import im.vector.app.features.settings.locale.SystemLocaleProvider
import im.vector.app.features.themes.ThemeUtils import im.vector.app.features.themes.ThemeUtils
import im.vector.app.features.version.VersionProvider import im.vector.app.features.version.VersionProvider
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import okhttp3.Call import okhttp3.Call
import okhttp3.MediaType.Companion.toMediaTypeOrNull import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
@ -98,6 +102,8 @@ class BugReporter @Inject constructor(
var screenshot: Bitmap? = null var screenshot: Bitmap? = null
private set private set
private val coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
private val LOGCAT_CMD_ERROR = arrayOf("logcat", // /< Run 'logcat' command private val LOGCAT_CMD_ERROR = arrayOf("logcat", // /< Run 'logcat' command
"-d", // /< Dump the log rather than continue outputting it "-d", // /< Dump the log rather than continue outputting it
"-v", // formatting "-v", // formatting
@ -160,13 +166,13 @@ class BugReporter @Inject constructor(
withScreenshot: Boolean, withScreenshot: Boolean,
theBugDescription: String, theBugDescription: String,
listener: IMXBugReportListener?) { listener: IMXBugReportListener?) {
object : AsyncTask<Void, Int, String>() {
// enumerate files to delete // enumerate files to delete
val mBugReportFiles: MutableList<File> = ArrayList() val mBugReportFiles: MutableList<File> = ArrayList()
override fun doInBackground(vararg voids: Void?): String? { coroutineScope.launch {
var bugDescription = theBugDescription
var serverError: String? = null var serverError: String? = null
withContext(Dispatchers.IO) {
var bugDescription = theBugDescription
val crashCallStack = getCrashDescription(context) val crashCallStack = getCrashDescription(context)
if (null != crashCallStack) { if (null != crashCallStack) {
@ -342,7 +348,11 @@ class BugReporter @Inject constructor(
} }
Timber.v("## onWrite() : $percentage%") Timber.v("## onWrite() : $percentage%")
publishProgress(percentage) try {
listener?.onProgress(percentage)
} catch (e: Exception) {
Timber.e(e, "## onProgress() : failed")
}
} }
// build the request // build the request
@ -386,12 +396,14 @@ class BugReporter @Inject constructor(
} }
// check if the error message // check if the error message
serverError?.let {
try { try {
val responseJSON = JSONObject(serverError) val responseJSON = JSONObject(it)
serverError = responseJSON.getString("error") serverError = responseJSON.getString("error")
} catch (e: JSONException) { } catch (e: JSONException) {
Timber.e(e, "doInBackground ; Json conversion failed") Timber.e(e, "doInBackground ; Json conversion failed")
} }
}
// should never happen // should never happen
if (null == serverError) { if (null == serverError) {
@ -403,21 +415,9 @@ class BugReporter @Inject constructor(
} }
} }
} }
return serverError
} }
override fun onProgressUpdate(vararg progress: Int?) { withContext(Dispatchers.Main) {
if (null != listener) {
try {
listener.onProgress(progress[0] ?: 0)
} catch (e: Exception) {
Timber.e(e, "## onProgress() : failed")
}
}
}
override fun onPostExecute(reason: String?) {
mBugReportCall = null mBugReportCall = null
// delete when the bug report has been successfully sent // delete when the bug report has been successfully sent
@ -429,17 +429,17 @@ class BugReporter @Inject constructor(
try { try {
if (mIsCancelled) { if (mIsCancelled) {
listener.onUploadCancelled() listener.onUploadCancelled()
} else if (null == reason) { } else if (null == serverError) {
listener.onUploadSucceed() listener.onUploadSucceed()
} else { } else {
listener.onUploadFailed(reason) listener.onUploadFailed(serverError)
} }
} catch (e: Exception) { } catch (e: Exception) {
Timber.e(e, "## onPostExecute() : failed") Timber.e(e, "## onPostExecute() : failed")
} }
} }
} }
}.execute() }
} }
/** /**

View file

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

View file

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

View file

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