diff --git a/dependencies.gradle b/dependencies.gradle index a0ac311963f..0fd445b543b 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -1,13 +1,13 @@ ext.versions = [ 'minSdk' : 21, - 'compileSdk' : 34, - 'targetSdk' : 34, + 'compileSdk' : 35, + 'targetSdk' : 35, 'sourceCompat' : JavaVersion.VERSION_21, 'targetCompat' : JavaVersion.VERSION_21, 'jvmTarget' : "21", ] -def gradle = "8.4.2" +def gradle = "8.11.0" // Ref: https://kotlinlang.org/releases.html def kotlin = "1.9.24" def kotlinCoroutines = "1.8.1" diff --git a/gradle.properties b/gradle.properties index 8cde2fc6875..2433ae78cbd 100644 --- a/gradle.properties +++ b/gradle.properties @@ -42,4 +42,4 @@ signing.element.nightly.keyPassword=Secret # Customise the Lint version to use a more recent version than the one bundled with AGP # https://googlesamples.github.io/android-custom-lint-rules/usage/newer-lint.md.html -android.experimental.lint.version=8.6.0-alpha08 +android.experimental.lint.version=8.12.0-alpha08 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index e6441136f3d..1b33c55baab 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 515ab9d5f18..78cb6e16a49 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionSha256Sum=f8b4f4772d302c8ff580bc40d0f56e715de69b163546944f787c87abf209c961 -distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-all.zip +distributionSha256Sum=bd71102213493060956ec229d946beee57158dbd89d0e62b91bca0fa2c5f3531 +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.3-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index 65dcd68d65c..23d15a93670 100755 --- a/gradlew +++ b/gradlew @@ -15,6 +15,8 @@ # See the License for the specific language governing permissions and # limitations under the License. # +# SPDX-License-Identifier: Apache-2.0 +# ############################################################################## # @@ -55,7 +57,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -83,10 +85,8 @@ done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -114,7 +114,7 @@ case "$( uname )" in #( NONSTOP* ) nonstop=true ;; esac -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar +CLASSPATH="\\\"\\\"" # Determine the Java command to use to start the JVM. @@ -133,10 +133,13 @@ location of your Java installation." fi else JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. @@ -144,7 +147,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac @@ -152,7 +155,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -197,16 +200,20 @@ if "$cygwin" || "$msys" ; then done fi -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ "$@" # Stop when "xargs" is not available. diff --git a/gradlew.bat b/gradlew.bat index 6689b85beec..5eed7ee8452 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -13,6 +13,8 @@ @rem See the License for the specific language governing permissions and @rem limitations under the License. @rem +@rem SPDX-License-Identifier: Apache-2.0 +@rem @if "%DEBUG%"=="" @echo off @rem ########################################################################## @@ -43,11 +45,11 @@ set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -57,22 +59,22 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail :execute @rem Setup the command line -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar +set CLASSPATH= @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* :end @rem End local scope for the variables with windows NT shell diff --git a/library/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/AttachmentViewerActivity.kt b/library/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/AttachmentViewerActivity.kt index 09785e50e79..55a3b5d511b 100644 --- a/library/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/AttachmentViewerActivity.kt +++ b/library/attachment-viewer/src/main/java/im/vector/lib/attachmentviewer/AttachmentViewerActivity.kt @@ -131,12 +131,15 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi // 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 + @Suppress("DEPRECATION") window.setDecorFitsSystemWindows(false) // New API instead of SYSTEM_UI_FLAG_IMMERSIVE window.decorView.windowInsetsController?.systemBarsBehavior = WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE // New API instead of FLAG_TRANSLUCENT_STATUS + @Suppress("DEPRECATION") window.statusBarColor = ContextCompat.getColor(this, R.color.half_transparent_status_bar) // new API instead of FLAG_TRANSLUCENT_NAVIGATION + @Suppress("DEPRECATION") window.navigationBarColor = ContextCompat.getColor(this, R.color.half_transparent_status_bar) } else { @Suppress("DEPRECATION") @@ -318,6 +321,7 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi protected open fun shouldAnimateDismiss(): Boolean = true protected open fun animateClose() { + @Suppress("DEPRECATION") window.statusBarColor = Color.TRANSPARENT finish() } @@ -334,14 +338,17 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi // 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 + @Suppress("DEPRECATION") 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_TRANSIENT_BARS_BY_SWIPE // New API instead of FLAG_TRANSLUCENT_STATUS + @Suppress("DEPRECATION") window.statusBarColor = ContextCompat.getColor(this, R.color.half_transparent_status_bar) // New API instead of FLAG_TRANSLUCENT_NAVIGATION + @Suppress("DEPRECATION") window.navigationBarColor = ContextCompat.getColor(this, R.color.half_transparent_status_bar) } else { @Suppress("DEPRECATION") @@ -363,6 +370,7 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi 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 + @Suppress("DEPRECATION") window.setDecorFitsSystemWindows(false) } else { @Suppress("DEPRECATION") diff --git a/library/ui-styles/src/main/res/values/theme_light.xml b/library/ui-styles/src/main/res/values/theme_light.xml index bd397d1bc68..68a0e8a5feb 100644 --- a/library/ui-styles/src/main/res/values/theme_light.xml +++ b/library/ui-styles/src/main/res/values/theme_light.xml @@ -64,6 +64,9 @@ @color/element_accent_light + + + ?vctr_toolbar_background @color/element_accent_light @android:color/white @color/element_accent_light diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/interceptors/FormattedJsonHttpLogger.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/interceptors/FormattedJsonHttpLogger.kt index 334a8c50766..f11b8a031c9 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/interceptors/FormattedJsonHttpLogger.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/network/interceptors/FormattedJsonHttpLogger.kt @@ -38,7 +38,8 @@ internal class FormattedJsonHttpLogger( */ @Synchronized override fun log(message: String) { - Timber.v(message) + Timber.v(message.take(20_000)) + if (message.length > 20_000) return // Try to log formatted Json only if there is a chance that [message] contains Json. // It can be only the case if we log the bodies of Http requests. diff --git a/vector-app/src/debug/java/im/vector/app/features/debug/DebugMenuActivity.kt b/vector-app/src/debug/java/im/vector/app/features/debug/DebugMenuActivity.kt index 288b7a89bd8..876baf69d95 100644 --- a/vector-app/src/debug/java/im/vector/app/features/debug/DebugMenuActivity.kt +++ b/vector-app/src/debug/java/im/vector/app/features/debug/DebugMenuActivity.kt @@ -12,6 +12,7 @@ import android.app.NotificationChannel import android.app.NotificationManager import android.content.Intent import android.os.Build +import android.view.View import androidx.core.app.NotificationCompat import androidx.core.app.Person import androidx.core.content.getSystemService @@ -49,7 +50,9 @@ import javax.inject.Inject class DebugMenuActivity : VectorBaseActivity() { override fun getBinding() = ActivityDebugMenuBinding.inflate(layoutInflater) - + override fun getCoordinatorLayout() = views.coordinatorLayout + override val rootView: View + get() = views.coordinatorLayout @Inject lateinit var clock: Clock private lateinit var buffer: ByteArray diff --git a/vector-app/src/debug/java/im/vector/app/features/debug/DebugPermissionActivity.kt b/vector-app/src/debug/java/im/vector/app/features/debug/DebugPermissionActivity.kt index cae9f63b225..9f5622713ba 100644 --- a/vector-app/src/debug/java/im/vector/app/features/debug/DebugPermissionActivity.kt +++ b/vector-app/src/debug/java/im/vector/app/features/debug/DebugPermissionActivity.kt @@ -10,6 +10,7 @@ package im.vector.app.features.debug import android.Manifest import android.content.pm.PackageManager import android.os.Build +import android.view.View import android.widget.Toast import androidx.core.app.ActivityCompat import androidx.core.content.ContextCompat @@ -32,6 +33,9 @@ class DebugPermissionActivity : VectorBaseActivity() { override fun getBinding() = ActivitySimpleBinding.inflate(layoutInflater) + override fun getCoordinatorLayout() = views.coordinatorLayout + override val rootView: View + get() = views.coordinatorLayout + override fun initUiAndData() { if (isFirstCreation()) { addFragment( diff --git a/vector-app/src/debug/java/im/vector/app/features/debug/features/DebugFeaturesSettingsActivity.kt b/vector-app/src/debug/java/im/vector/app/features/debug/features/DebugFeaturesSettingsActivity.kt index 2f7ff692af0..b4a77939629 100644 --- a/vector-app/src/debug/java/im/vector/app/features/debug/features/DebugFeaturesSettingsActivity.kt +++ b/vector-app/src/debug/java/im/vector/app/features/debug/features/DebugFeaturesSettingsActivity.kt @@ -8,6 +8,7 @@ package im.vector.app.features.debug.features import android.os.Bundle +import android.view.View import dagger.hilt.android.AndroidEntryPoint import im.vector.app.core.extensions.cleanup import im.vector.app.core.extensions.configureWith @@ -24,6 +25,9 @@ class DebugFeaturesSettingsActivity : VectorBaseActivity() { override fun getBinding() = ActivityDebugJitsiBinding.inflate(layoutInflater) override fun getCoordinatorLayout() = views.coordinatorLayout + override val rootView: View + get() = views.coordinatorLayout @SuppressLint("SetTextI18n") override fun initUiAndData() { diff --git a/vector-app/src/debug/java/im/vector/app/features/debug/leak/DebugMemoryLeaksActivity.kt b/vector-app/src/debug/java/im/vector/app/features/debug/leak/DebugMemoryLeaksActivity.kt index f942fc342d4..7eb9ea99d62 100644 --- a/vector-app/src/debug/java/im/vector/app/features/debug/leak/DebugMemoryLeaksActivity.kt +++ b/vector-app/src/debug/java/im/vector/app/features/debug/leak/DebugMemoryLeaksActivity.kt @@ -7,6 +7,7 @@ package im.vector.app.features.debug.leak +import android.view.View import dagger.hilt.android.AndroidEntryPoint import im.vector.app.core.extensions.addFragment import im.vector.app.core.platform.VectorBaseActivity @@ -17,6 +18,10 @@ class DebugMemoryLeaksActivity : VectorBaseActivity() { override fun getBinding() = ActivitySimpleBinding.inflate(layoutInflater) + override fun getCoordinatorLayout() = views.coordinatorLayout + override val rootView: View + get() = views.coordinatorLayout + override fun initUiAndData() { if (isFirstCreation()) { addFragment( diff --git a/vector-app/src/debug/java/im/vector/app/features/debug/settings/DebugPrivateSettingsActivity.kt b/vector-app/src/debug/java/im/vector/app/features/debug/settings/DebugPrivateSettingsActivity.kt index 017bde5eb79..2a539a21ca4 100644 --- a/vector-app/src/debug/java/im/vector/app/features/debug/settings/DebugPrivateSettingsActivity.kt +++ b/vector-app/src/debug/java/im/vector/app/features/debug/settings/DebugPrivateSettingsActivity.kt @@ -7,6 +7,7 @@ package im.vector.app.features.debug.settings +import android.view.View import dagger.hilt.android.AndroidEntryPoint import im.vector.app.core.extensions.addFragment import im.vector.app.core.platform.VectorBaseActivity @@ -17,6 +18,10 @@ class DebugPrivateSettingsActivity : VectorBaseActivity() override fun getBinding() = ActivitySimpleBinding.inflate(layoutInflater) + override fun getCoordinatorLayout() = views.coordinatorLayout + override val rootView: View + get() = views.coordinatorLayout + override fun initUiAndData() { if (isFirstCreation()) { addFragment( diff --git a/vector/src/main/AndroidManifest.xml b/vector/src/main/AndroidManifest.xml index fab5be1257d..7455c0847f4 100644 --- a/vector/src/main/AndroidManifest.xml +++ b/vector/src/main/AndroidManifest.xml @@ -167,8 +167,7 @@ + android:parentActivityName=".features.home.HomeActivity"> @@ -369,8 +368,8 @@ + android:exported="false" + android:foregroundServiceType="phoneCall"> @@ -387,7 +386,8 @@ + android:permission="android.permission.BIND_TELECOM_CONNECTION_SERVICE" + tools:targetApi="M"> @@ -413,8 +413,7 @@ android:name=".features.call.audio.MicrophoneAccessService" android:exported="false" android:foregroundServiceType="microphone" - android:permission="android.permission.FOREGROUND_SERVICE_MICROPHONE"> - + android:permission="android.permission.FOREGROUND_SERVICE_MICROPHONE" /> diff --git a/vector/src/main/java/im/vector/app/SpaceStateHandlerImpl.kt b/vector/src/main/java/im/vector/app/SpaceStateHandlerImpl.kt index 97b6eb6209b..06abc16cbfe 100644 --- a/vector/src/main/java/im/vector/app/SpaceStateHandlerImpl.kt +++ b/vector/src/main/java/im/vector/app/SpaceStateHandlerImpl.kt @@ -137,7 +137,7 @@ class SpaceStateHandlerImpl @Inject constructor( override fun popSpaceBackstack(): String? { vectorPreferences.getSpaceBackstack().toMutableList().apply { - val poppedSpaceId = removeLast() + val poppedSpaceId = removeAt(lastIndex) vectorPreferences.setSpaceBackstack(this) return poppedSpaceId } diff --git a/vector/src/main/java/im/vector/app/core/platform/SimpleFragmentActivity.kt b/vector/src/main/java/im/vector/app/core/platform/SimpleFragmentActivity.kt index 06eecf1d41e..12ed8418bc3 100644 --- a/vector/src/main/java/im/vector/app/core/platform/SimpleFragmentActivity.kt +++ b/vector/src/main/java/im/vector/app/core/platform/SimpleFragmentActivity.kt @@ -6,6 +6,7 @@ */ package im.vector.app.core.platform +import android.view.View import androidx.core.view.isGone import androidx.core.view.isVisible import im.vector.app.core.extensions.hideKeyboard @@ -20,6 +21,9 @@ abstract class SimpleFragmentActivity : VectorBaseActivity() { final override fun getCoordinatorLayout() = views.coordinatorLayout + override val rootView: View + get() = views.coordinatorLayout + override fun initUiAndData() { setupToolbar(views.toolbar) .allowBack(true) 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 355a164ab07..a6b9d779307 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 @@ -10,25 +10,26 @@ package im.vector.app.core.platform import android.annotation.SuppressLint import android.app.Activity import android.content.Context -import android.os.Build import android.os.Bundle import android.view.Menu import android.view.MenuInflater import android.view.MenuItem import android.view.View -import android.view.WindowInsetsController import android.view.WindowManager import android.widget.TextView +import androidx.activity.enableEdgeToEdge import androidx.annotation.CallSuper import androidx.annotation.MainThread import androidx.annotation.StringRes import androidx.appcompat.app.AppCompatActivity import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.core.app.MultiWindowModeChangedInfo -import androidx.core.content.ContextCompat import androidx.core.util.Consumer import androidx.core.view.MenuProvider +import androidx.core.view.ViewCompat +import androidx.core.view.WindowInsetsCompat import androidx.core.view.isVisible +import androidx.core.view.updatePadding import androidx.fragment.app.FragmentManager import androidx.lifecycle.Lifecycle import androidx.lifecycle.ViewModelProvider @@ -208,6 +209,7 @@ abstract class VectorBaseActivity : AppCompatActivity(), Maver val activityEntryPoint = EntryPointAccessors.fromActivity(this, ActivityEntryPoint::class.java) ThemeUtils.setActivityTheme(this, getOtherThemes()) viewModelFactory = activityEntryPoint.viewModelFactory() + enableEdgeToEdge() super.onCreate(savedInstanceState) addOnMultiWindowModeChangedListener(onMultiWindowModeChangedListener) setupMenu() @@ -247,7 +249,9 @@ abstract class VectorBaseActivity : AppCompatActivity(), Maver if (vectorPreferences.isNewAppLayoutEnabled()) { tryOrNull { // Add to XML theme when feature flag is removed val toolbarBackground = MaterialColors.getColor(views.root, im.vector.lib.ui.styles.R.attr.vctr_toolbar_background) + @Suppress("DEPRECATION") window.statusBarColor = toolbarBackground + @Suppress("DEPRECATION") window.navigationBarColor = toolbarBackground } } @@ -334,7 +338,8 @@ abstract class VectorBaseActivity : AppCompatActivity(), Maver private fun handleCertificateError(certificateError: GlobalError.CertificateError) { singletonEntryPoint() .unrecognizedCertificateDialog() - .show(this, + .show( + this, certificateError.fingerprint, object : UnrecognizedCertificateDialog.Callback { override fun onAccept() { @@ -411,6 +416,20 @@ abstract class VectorBaseActivity : AppCompatActivity(), Maver // Just log that a change occurred. Timber.w("MDM data has been updated") } + ViewCompat.setOnApplyWindowInsetsListener(rootView) { v, insets -> + val systemBars = insets.getInsets( + WindowInsetsCompat.Type.systemBars() or + WindowInsetsCompat.Type.displayCutout() or + WindowInsetsCompat.Type.ime() + ) + v.updatePadding( + systemBars.left, + systemBars.top, + systemBars.right, + systemBars.bottom, + ) + insets + } } private val postResumeScheduledActions = mutableListOf<() -> Unit>() @@ -444,14 +463,6 @@ abstract class VectorBaseActivity : AppCompatActivity(), Maver mdmService.unregisterListener(this) } - override fun onWindowFocusChanged(hasFocus: Boolean) { - super.onWindowFocusChanged(hasFocus) - - if (hasFocus && displayInFullscreen()) { - setFullScreen() - } - } - private val onMultiWindowModeChangedListener = Consumer { Timber.w("onMultiWindowModeChanged. isInMultiWindowMode: ${it.isInMultiWindowMode}") bugReporter.inMultiWindowMode = it.isInMultiWindowMode @@ -461,30 +472,6 @@ abstract class VectorBaseActivity : AppCompatActivity(), Maver * PRIVATE METHODS * ========================================================================================== */ - /** - * Force to render the activity in fullscreen. - */ - 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_TRANSIENT_BARS_BY_SWIPE - // New API instead of FLAG_TRANSLUCENT_STATUS - window.statusBarColor = ContextCompat.getColor(this, im.vector.lib.ui.styles.R.color.half_transparent_status_bar) - // New API instead of FLAG_TRANSLUCENT_NAVIGATION - window.navigationBarColor = ContextCompat.getColor(this, im.vector.lib.ui.styles.R.color.half_transparent_status_bar) - } else { - @Suppress("DEPRECATION") - 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) - } - } - private fun handleMenuItemHome(item: MenuItem): Boolean { return when (item.itemId) { android.R.id.home -> { @@ -586,8 +573,6 @@ abstract class VectorBaseActivity : AppCompatActivity(), Maver abstract fun getBinding(): VB - open fun displayInFullscreen() = false - open fun doBeforeSetContentView() = Unit open fun initUiAndData() = Unit @@ -626,6 +611,8 @@ abstract class VectorBaseActivity : AppCompatActivity(), Maver open fun getCoordinatorLayout(): CoordinatorLayout? = null + abstract val rootView: View + /* ========================================================================================== * User Consent * ========================================================================================== */ diff --git a/vector/src/main/java/im/vector/app/core/services/BluetoothHeadsetReceiver.kt b/vector/src/main/java/im/vector/app/core/services/BluetoothHeadsetReceiver.kt index dd04e5664e5..031ea2268de 100644 --- a/vector/src/main/java/im/vector/app/core/services/BluetoothHeadsetReceiver.kt +++ b/vector/src/main/java/im/vector/app/core/services/BluetoothHeadsetReceiver.kt @@ -18,6 +18,10 @@ import androidx.core.content.ContextCompat import im.vector.lib.core.utils.compat.getParcelableExtraCompat import java.lang.ref.WeakReference +/** + * It's only used in API 21 and 22 so we will not have security exception on these OS, + * so it's safe to use @Suppress("MissingPermission"). + */ class BluetoothHeadsetReceiver : BroadcastReceiver() { interface EventListener { @@ -53,12 +57,15 @@ class BluetoothHeadsetReceiver : BroadcastReceiver() { } val device = intent.getParcelableExtraCompat(BluetoothDevice.EXTRA_DEVICE) + @Suppress("MissingPermission") val deviceName = device?.name + @Suppress("MissingPermission") when (device?.bluetoothClass?.deviceClass) { BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE, BluetoothClass.Device.AUDIO_VIDEO_CAR_AUDIO, BluetoothClass.Device.AUDIO_VIDEO_WEARABLE_HEADSET -> { // filter only device that we care about for + @Suppress("MissingPermission") delegate?.get()?.onBTHeadsetEvent( BTHeadsetPlugEvent( plugged = headsetConnected, diff --git a/vector/src/main/java/im/vector/app/core/services/CallAndroidService.kt b/vector/src/main/java/im/vector/app/core/services/CallAndroidService.kt index f818ab412eb..9e0a718b156 100644 --- a/vector/src/main/java/im/vector/app/core/services/CallAndroidService.kt +++ b/vector/src/main/java/im/vector/app/core/services/CallAndroidService.kt @@ -8,11 +8,14 @@ package im.vector.app.core.services +import android.Manifest import android.content.Context import android.content.Intent +import android.content.pm.PackageManager import android.os.Binder import android.support.v4.media.session.MediaSessionCompat import android.view.KeyEvent +import androidx.core.app.ActivityCompat import androidx.core.app.NotificationManagerCompat import androidx.core.content.ContextCompat import androidx.media.session.MediaButtonReceiver @@ -150,7 +153,8 @@ class CallAndroidService : VectorAndroidService() { val isVideoCall = call.mxCall.isVideoCall val fromBg = intent.getBooleanExtra(EXTRA_IS_IN_BG, false) Timber.tag(loggerTag.value).v("displayIncomingCallNotification : display the dedicated notification") - val incomingCallAlert = IncomingCallAlert(callId, + val incomingCallAlert = IncomingCallAlert( + callId, shouldBeDisplayedIn = { activity -> if (activity is VectorCallActivity) { activity.intent.getParcelableExtraCompat(Mavericks.KEY_ARG)?.callId != call.callId @@ -176,7 +180,11 @@ class CallAndroidService : VectorAndroidService() { if (knownCalls.isEmpty()) { startForegroundCompat(callId.hashCode(), notification) } else { - notificationManager.notify(callId.hashCode(), notification) + if (ActivityCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) { + Timber.w("Not allowed to notify.") + } else { + notificationManager.notify(callId.hashCode(), notification) + } } knownCalls[callId] = callInformation } @@ -234,7 +242,11 @@ class CallAndroidService : VectorAndroidService() { if (knownCalls.isEmpty()) { startForegroundCompat(callId.hashCode(), notification) } else { - notificationManager.notify(callId.hashCode(), notification) + if (ActivityCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) { + Timber.w("Not allowed to notify.") + } else { + notificationManager.notify(callId.hashCode(), notification) + } } knownCalls[callId] = callInformation } @@ -258,7 +270,11 @@ class CallAndroidService : VectorAndroidService() { if (knownCalls.isEmpty()) { startForegroundCompat(callId.hashCode(), notification) } else { - notificationManager.notify(callId.hashCode(), notification) + if (ActivityCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) { + Timber.w("Not allowed to notify.") + } else { + notificationManager.notify(callId.hashCode(), notification) + } } knownCalls[callId] = callInformation } diff --git a/vector/src/main/java/im/vector/app/core/utils/ExpandingBottomSheetBehavior.kt b/vector/src/main/java/im/vector/app/core/utils/ExpandingBottomSheetBehavior.kt index 7834d6a0142..5b84579b2b1 100644 --- a/vector/src/main/java/im/vector/app/core/utils/ExpandingBottomSheetBehavior.kt +++ b/vector/src/main/java/im/vector/app/core/utils/ExpandingBottomSheetBehavior.kt @@ -658,7 +658,8 @@ class ExpandingBottomSheetBehavior : CoordinatorLayout.Behavior { val insetsType = WindowInsetsCompat.Type.systemBars() or WindowInsetsCompat.Type.ime() val imeInsets = insets.getInsets(insetsType) insetTop = imeInsets.top - insetBottom = imeInsets.bottom + // Now that edgeToEdge is enabled, disable the bottom padding. + insetBottom = 0 insetLeft = imeInsets.left insetRight = imeInsets.right diff --git a/vector/src/main/java/im/vector/app/core/utils/PermissionChecker.kt b/vector/src/main/java/im/vector/app/core/utils/PermissionChecker.kt new file mode 100644 index 00000000000..3840e028c0a --- /dev/null +++ b/vector/src/main/java/im/vector/app/core/utils/PermissionChecker.kt @@ -0,0 +1,23 @@ +/* + * Copyright 2025 New Vector Ltd. + * + * SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial + * Please see LICENSE files in the repository root for full details. + */ + +package im.vector.app.core.utils + +import android.content.Context +import android.content.pm.PackageManager +import androidx.core.app.ActivityCompat +import javax.inject.Inject + +class PermissionChecker @Inject constructor( + private val applicationContext: Context, +) { + fun checkPermission(vararg permissions: String): Boolean { + return permissions.any { permission -> + ActivityCompat.checkSelfPermission(applicationContext, permission) != PackageManager.PERMISSION_GRANTED + } + } +} diff --git a/vector/src/main/java/im/vector/app/features/MainActivity.kt b/vector/src/main/java/im/vector/app/features/MainActivity.kt index 6b16c2deb80..9c95a5d835b 100644 --- a/vector/src/main/java/im/vector/app/features/MainActivity.kt +++ b/vector/src/main/java/im/vector/app/features/MainActivity.kt @@ -12,6 +12,7 @@ import android.content.Context import android.content.Intent import android.os.Bundle import android.os.Parcelable +import android.view.View import androidx.core.content.ContextCompat import androidx.core.view.isVisible import androidx.lifecycle.Lifecycle @@ -392,4 +393,7 @@ class MainActivity : VectorBaseActivity(), UnlockedActivity val className = componentName.className return packageName == buildMeta.applicationId && className in allowList } + + override val rootView: View + get() = views.mainRoot } diff --git a/vector/src/main/java/im/vector/app/features/analytics/ui/consent/AnalyticsOptInActivity.kt b/vector/src/main/java/im/vector/app/features/analytics/ui/consent/AnalyticsOptInActivity.kt index e3cf06bd87f..42598f43561 100644 --- a/vector/src/main/java/im/vector/app/features/analytics/ui/consent/AnalyticsOptInActivity.kt +++ b/vector/src/main/java/im/vector/app/features/analytics/ui/consent/AnalyticsOptInActivity.kt @@ -7,6 +7,7 @@ package im.vector.app.features.analytics.ui.consent +import android.view.View import com.airbnb.mvrx.viewModel import dagger.hilt.android.AndroidEntryPoint import im.vector.app.core.extensions.addFragment @@ -29,6 +30,9 @@ class AnalyticsOptInActivity : VectorBaseActivity() { override fun getCoordinatorLayout() = views.coordinatorLayout + override val rootView: View + get() = views.coordinatorLayout + override fun initUiAndData() { orientationLocker.lockPhonesToPortrait(this) if (isFirstCreation()) { diff --git a/vector/src/main/java/im/vector/app/features/attachments/preview/AttachmentsPreviewActivity.kt b/vector/src/main/java/im/vector/app/features/attachments/preview/AttachmentsPreviewActivity.kt index 487e116fb5d..5382d546705 100644 --- a/vector/src/main/java/im/vector/app/features/attachments/preview/AttachmentsPreviewActivity.kt +++ b/vector/src/main/java/im/vector/app/features/attachments/preview/AttachmentsPreviewActivity.kt @@ -9,6 +9,7 @@ package im.vector.app.features.attachments.preview import android.content.Context import android.content.Intent +import android.view.View import dagger.hilt.android.AndroidEntryPoint import im.vector.app.core.extensions.addFragment import im.vector.app.core.platform.VectorBaseActivity @@ -47,6 +48,9 @@ class AttachmentsPreviewActivity : VectorBaseActivity() { override fun getCoordinatorLayout() = views.coordinatorLayout + override val rootView: View + get() = views.coordinatorLayout + override fun initUiAndData() { if (isFirstCreation()) { val fragmentArgs: AttachmentsPreviewArgs = intent?.extras?.getParcelableCompat(EXTRA_FRAGMENT_ARGS) ?: return 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 999b76295d4..a4f1dafda18 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 @@ -163,6 +163,7 @@ class AttachmentsPreviewFragment : private fun applyInsets() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { + @Suppress("DEPRECATION") activity?.window?.setDecorFitsSystemWindows(false) } else { @Suppress("DEPRECATION") 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 47db3dccc7e..03a3aaf8c98 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 @@ -128,7 +128,9 @@ class VectorCallActivity : window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN) window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON) + @Suppress("DEPRECATION") window.statusBarColor = Color.TRANSPARENT + @Suppress("DEPRECATION") window.navigationBarColor = Color.BLACK super.onCreate(savedInstanceState) addOnPictureInPictureModeChangedListener(pictureInPictureModeChangedInfoConsumer) @@ -185,6 +187,9 @@ class VectorCallActivity : override fun getMenuRes() = R.menu.vector_call + override val rootView: View + get() = views.constraintLayout + override fun onUserLeaveHint() { super.onUserLeaveHint() enterPictureInPictureIfRequired() diff --git a/vector/src/main/java/im/vector/app/features/call/audio/API21AudioDeviceDetector.kt b/vector/src/main/java/im/vector/app/features/call/audio/API21AudioDeviceDetector.kt index 30d65073800..69adc08c637 100644 --- a/vector/src/main/java/im/vector/app/features/call/audio/API21AudioDeviceDetector.kt +++ b/vector/src/main/java/im/vector/app/features/call/audio/API21AudioDeviceDetector.kt @@ -43,6 +43,11 @@ internal class API21AudioDeviceDetector( return HashSet().apply { if (isBluetoothHeadsetOn()) { connectedBlueToothHeadset?.connectedDevices?.forEach { + // Call requires permission which may be rejected by user: code should explicitly + // check to see if permission is available (with checkPermission) or explicitly + // handle a potential SecurityException + // But it should not happen on API 21/22. + @Suppress("MissingPermission") add(CallAudioManager.Device.WirelessHeadset(it.name)) } } diff --git a/vector/src/main/java/im/vector/app/features/call/conference/VectorJitsiActivity.kt b/vector/src/main/java/im/vector/app/features/call/conference/VectorJitsiActivity.kt index 4a0ccf28e3e..a86b5e34c93 100644 --- a/vector/src/main/java/im/vector/app/features/call/conference/VectorJitsiActivity.kt +++ b/vector/src/main/java/im/vector/app/features/call/conference/VectorJitsiActivity.kt @@ -15,6 +15,7 @@ import android.content.res.Configuration import android.os.Build import android.os.Bundle import android.os.Parcelable +import android.view.View import android.widget.FrameLayout import android.widget.Toast import androidx.core.app.PictureInPictureModeChangedInfo @@ -58,6 +59,9 @@ class VectorJitsiActivity : VectorBaseActivity(), JitsiMee override fun getBinding() = ActivityJitsiBinding.inflate(layoutInflater) + override val rootView: View + get() = views.jitsiLayout + private var jitsiMeetView: JitsiMeetView? = null private val jitsiViewModel: JitsiCallViewModel by viewModel() diff --git a/vector/src/main/java/im/vector/app/features/call/dialpad/DialPadFragment.kt b/vector/src/main/java/im/vector/app/features/call/dialpad/DialPadFragment.kt index 7efe7b8df9d..5bb1b5d0dd1 100644 --- a/vector/src/main/java/im/vector/app/features/call/dialpad/DialPadFragment.kt +++ b/vector/src/main/java/im/vector/app/features/call/dialpad/DialPadFragment.kt @@ -12,7 +12,6 @@ import android.content.ClipboardManager import android.content.Context import android.content.res.ColorStateList import android.os.Bundle -import android.telephony.PhoneNumberFormattingTextWatcher import android.telephony.PhoneNumberUtils import android.text.Editable import android.text.InputType @@ -78,7 +77,8 @@ class DialPadFragment : Fragment(), TextWatcher { digits.inputType = InputType.TYPE_CLASS_PHONE digits.keyListener = DialerKeyListener.getInstance() digits.setTextColor(ThemeUtils.getColor(requireContext(), im.vector.lib.ui.styles.R.attr.vctr_content_primary)) - digits.addTextChangedListener(PhoneNumberFormattingTextWatcher(if (formatAsYouType) regionCode else "")) + @Suppress("DEPRECATION") + digits.addTextChangedListener(android.telephony.PhoneNumberFormattingTextWatcher(if (formatAsYouType) regionCode else "")) digits.addTextChangedListener(this) dialpadView.findViewById(R.id.zero).setOnClickListener { keyPressed(KeyEvent.KEYCODE_0, "0") } dialpadView.findViewById(R.id.one).setOnClickListener { keyPressed(KeyEvent.KEYCODE_1, "1") } diff --git a/vector/src/main/java/im/vector/app/features/call/transfer/CallTransferActivity.kt b/vector/src/main/java/im/vector/app/features/call/transfer/CallTransferActivity.kt index 6a647bd5018..1925ce854e6 100644 --- a/vector/src/main/java/im/vector/app/features/call/transfer/CallTransferActivity.kt +++ b/vector/src/main/java/im/vector/app/features/call/transfer/CallTransferActivity.kt @@ -11,6 +11,7 @@ import android.content.Context import android.content.Intent import android.os.Bundle import android.os.Parcelable +import android.view.View import com.airbnb.mvrx.Mavericks import com.airbnb.mvrx.viewModel import com.google.android.material.tabs.TabLayoutMediator @@ -37,6 +38,9 @@ class CallTransferActivity : VectorBaseActivity() { override fun getCoordinatorLayout() = views.vectorCoordinatorLayout + override val rootView: View + get() = views.vectorCoordinatorLayout + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) waitingView = views.waitingView.waitingView 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 b1072576bc7..8a29bdd9e8e 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 @@ -122,6 +122,7 @@ class BootstrapBottomSheet : VectorBaseBottomSheetDialogFragment= Build.VERSION_CODES.R) { + @Suppress("DEPRECATION") dialog?.window?.setDecorFitsSystemWindows(false) } else { @Suppress("DEPRECATION") diff --git a/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt b/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt index d22ea908564..bea9d1303ba 100644 --- a/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt +++ b/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt @@ -192,6 +192,9 @@ class HomeActivity : override fun getCoordinatorLayout() = views.coordinatorLayout + override val rootView: View + get() = views.coordinatorLayout + override fun getBinding() = ActivityHomeBinding.inflate(layoutInflater) override fun onCreate(savedInstanceState: Bundle?) { diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailActivity.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailActivity.kt index e65e6c17f08..e5d785af639 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailActivity.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/RoomDetailActivity.kt @@ -14,7 +14,6 @@ import android.os.Bundle import android.view.View import android.widget.Toast import androidx.core.view.GravityCompat -import androidx.core.view.WindowCompat import androidx.drawerlayout.widget.DrawerLayout import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager @@ -82,6 +81,9 @@ class RoomDetailActivity : override fun getCoordinatorLayout() = views.coordinatorLayout + override val rootView: View + get() = views.coordinatorLayout + @Inject lateinit var playbackTracker: AudioMessagePlaybackTracker private lateinit var sharedActionViewModel: RoomDetailSharedActionViewModel private val requireActiveMembershipViewModel: RequireActiveMembershipViewModel by viewModel() @@ -93,7 +95,7 @@ class RoomDetailActivity : super.onCreate(savedInstanceState) // For dealing with insets and status bar background color - WindowCompat.setDecorFitsSystemWindows(window, false) + @Suppress("DEPRECATION") window.statusBarColor = Color.TRANSPARENT supportFragmentManager.registerFragmentLifecycleCallbacks(fragmentLifecycleCallbacks, false) diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt index 8e7b9ca951c..01be29d84ff 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/TimelineFragment.kt @@ -32,11 +32,9 @@ import androidx.core.net.toUri import androidx.core.text.toSpannable import androidx.core.util.Pair import androidx.core.view.ViewCompat -import androidx.core.view.WindowInsetsCompat import androidx.core.view.forEach import androidx.core.view.isInvisible import androidx.core.view.isVisible -import androidx.core.view.updatePadding import androidx.fragment.app.setFragmentResultListener import androidx.lifecycle.lifecycleScope import androidx.lifecycle.withResumed @@ -409,13 +407,6 @@ class TimelineFragment : is RoomDetailViewEvents.RevokeFilePermission -> revokeFilePermission(it) } } - - ViewCompat.setOnApplyWindowInsetsListener(views.coordinatorLayout) { _, insets -> - val imeInsets = insets.getInsets(WindowInsetsCompat.Type.ime() or WindowInsetsCompat.Type.systemBars()) - views.appBarLayout.updatePadding(top = imeInsets.top) - views.voiceMessageRecorderContainer.updatePadding(bottom = imeInsets.bottom) - insets - } } private fun setupBackPressHandling() { diff --git a/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchActivity.kt b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchActivity.kt index 0d674174c82..f262f5b044b 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchActivity.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/detail/search/SearchActivity.kt @@ -10,6 +10,7 @@ package im.vector.app.features.home.room.detail.search import android.content.Context import android.content.Intent import android.os.Bundle +import android.view.View import androidx.appcompat.widget.SearchView import com.airbnb.mvrx.Mavericks import dagger.hilt.android.AndroidEntryPoint @@ -30,6 +31,9 @@ class SearchActivity : VectorBaseActivity() { override fun getCoordinatorLayout() = views.coordinatorLayout + override val rootView: View + get() = views.coordinatorLayout + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setupToolbar(views.searchToolbar) diff --git a/vector/src/main/java/im/vector/app/features/home/room/filtered/FilteredRoomsActivity.kt b/vector/src/main/java/im/vector/app/features/home/room/filtered/FilteredRoomsActivity.kt index b2402ee4390..7e10e697974 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/filtered/FilteredRoomsActivity.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/filtered/FilteredRoomsActivity.kt @@ -10,6 +10,7 @@ package im.vector.app.features.home.room.filtered import android.content.Context import android.content.Intent import android.os.Bundle +import android.view.View import androidx.appcompat.widget.SearchView import dagger.hilt.android.AndroidEntryPoint import im.vector.app.core.extensions.replaceFragment @@ -32,6 +33,9 @@ class FilteredRoomsActivity : VectorBaseActivity() override fun getCoordinatorLayout() = views.coordinatorLayout + override val rootView: View + get() = views.coordinatorLayout + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) analyticsScreenName = MobileScreen.ScreenName.RoomFilter diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesActivity.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesActivity.kt index f2a19545fe2..8976e580c5a 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesActivity.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/invites/InvitesActivity.kt @@ -7,6 +7,7 @@ package im.vector.app.features.home.room.list.home.invites +import android.view.View import dagger.hilt.android.AndroidEntryPoint import im.vector.app.core.extensions.addFragment import im.vector.app.core.platform.VectorBaseActivity @@ -22,4 +23,8 @@ class InvitesActivity : VectorBaseActivity() { addFragment(views.simpleFragmentContainer, InvitesFragment::class.java) } } + + override fun getCoordinatorLayout() = views.coordinatorLayout + override val rootView: View + get() = views.coordinatorLayout } diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/home/release/ReleaseNotesActivity.kt b/vector/src/main/java/im/vector/app/features/home/room/list/home/release/ReleaseNotesActivity.kt index 0a3fa4393af..e7c104ff050 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/home/release/ReleaseNotesActivity.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/home/release/ReleaseNotesActivity.kt @@ -7,6 +7,7 @@ package im.vector.app.features.home.room.list.home.release +import android.view.View import androidx.lifecycle.lifecycleScope import dagger.hilt.android.AndroidEntryPoint import im.vector.app.core.extensions.addFragment @@ -26,6 +27,9 @@ class ReleaseNotesActivity : VectorBaseActivity() { override fun getCoordinatorLayout() = views.coordinatorLayout + override val rootView: View + get() = views.coordinatorLayout + override fun initUiAndData() { orientationLocker.lockPhonesToPortrait(this) if (isFirstCreation()) { diff --git a/vector/src/main/java/im/vector/app/features/home/room/threads/ThreadsActivity.kt b/vector/src/main/java/im/vector/app/features/home/room/threads/ThreadsActivity.kt index e0b773c2b6c..9174f60e5b9 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/threads/ThreadsActivity.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/threads/ThreadsActivity.kt @@ -10,6 +10,7 @@ package im.vector.app.features.home.room.threads import android.content.Context import android.content.Intent import android.os.Bundle +import android.view.View import androidx.fragment.app.FragmentTransaction import dagger.hilt.android.AndroidEntryPoint import im.vector.app.core.extensions.addFragmentToBackstack @@ -42,6 +43,9 @@ class ThreadsActivity : VectorBaseActivity() { override fun getCoordinatorLayout() = views.coordinatorLayout + override val rootView: View + get() = views.coordinatorLayout + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) initFragment() diff --git a/vector/src/main/java/im/vector/app/features/lifecycle/VectorActivityLifecycleCallbacks.kt b/vector/src/main/java/im/vector/app/features/lifecycle/VectorActivityLifecycleCallbacks.kt index fcb0dc22a81..968c422f433 100644 --- a/vector/src/main/java/im/vector/app/features/lifecycle/VectorActivityLifecycleCallbacks.kt +++ b/vector/src/main/java/im/vector/app/features/lifecycle/VectorActivityLifecycleCallbacks.kt @@ -32,7 +32,7 @@ class VectorActivityLifecycleCallbacks constructor(private val popupAlertManager /** * The activities information collected from the app manifest. */ - private var activitiesInfo: Array = emptyArray() + private var activitiesInfo: List? = null private val coroutineScope = CoroutineScope(SupervisorJob()) @@ -51,24 +51,32 @@ class VectorActivityLifecycleCallbacks constructor(private val popupAlertManager override fun onActivityStopped(activity: Activity) {} override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) { - if (activitiesInfo.isEmpty()) { + if (activitiesInfo == null) { val context = activity.applicationContext val packageManager: PackageManager = context.packageManager // Get all activities from element android - activitiesInfo = packageManager.getPackageInfoCompat(context.packageName, PackageManager.GET_ACTIVITIES).activities - + val activities = packageManager + .getPackageInfoCompat(context.packageName, PackageManager.GET_ACTIVITIES) + .activities + .orEmpty() + .toList() // Get all activities from PermissionController module // See https://source.android.com/docs/core/architecture/modular-system/permissioncontroller#package-format - if (Build.VERSION.SDK_INT > Build.VERSION_CODES.S_V2) { - activitiesInfo += tryOrNull { + val otherActivities = if (Build.VERSION.SDK_INT > Build.VERSION_CODES.S_V2) { + (tryOrNull { packageManager.getPackageInfoCompat("com.google.android.permissioncontroller", PackageManager.GET_ACTIVITIES).activities } ?: tryOrNull { packageManager.getModuleInfo("com.google.android.permission", 1).packageName?.let { packageManager.getPackageInfoCompat(it, PackageManager.GET_ACTIVITIES or PackageManager.MATCH_APEX).activities } - }.orEmpty() + }) + .orEmpty() + .toList() + } else { + emptyList() } + activitiesInfo = activities + otherActivities } // restart the app if the task contains an unknown activity @@ -144,5 +152,5 @@ class VectorActivityLifecycleCallbacks constructor(private val popupAlertManager * @param activity the activity of the task * @return true if the activity is potentially malicious */ - private fun isPotentialMaliciousActivity(activity: ComponentName): Boolean = activitiesInfo.none { it.name == activity.className } + private fun isPotentialMaliciousActivity(activity: ComponentName): Boolean = activitiesInfo.orEmpty().none { it.name == activity.className } } diff --git a/vector/src/main/java/im/vector/app/features/link/LinkHandlerActivity.kt b/vector/src/main/java/im/vector/app/features/link/LinkHandlerActivity.kt index 5c3ba3fbc36..f8c90575710 100644 --- a/vector/src/main/java/im/vector/app/features/link/LinkHandlerActivity.kt +++ b/vector/src/main/java/im/vector/app/features/link/LinkHandlerActivity.kt @@ -10,6 +10,7 @@ package im.vector.app.features.link import android.content.Intent import android.net.Uri import android.os.Bundle +import android.view.View import androidx.lifecycle.lifecycleScope import com.airbnb.mvrx.viewModel import com.google.android.material.dialog.MaterialAlertDialogBuilder @@ -41,6 +42,9 @@ class LinkHandlerActivity : VectorBaseActivity() { override fun getBinding() = ActivityProgressBinding.inflate(layoutInflater) + override val rootView: View + get() = views.mainRoot + override fun initUiAndData() { handleIntent() } diff --git a/vector/src/main/java/im/vector/app/features/location/LocationSharingActivity.kt b/vector/src/main/java/im/vector/app/features/location/LocationSharingActivity.kt index d9d3ee0731b..70ef34d03b1 100644 --- a/vector/src/main/java/im/vector/app/features/location/LocationSharingActivity.kt +++ b/vector/src/main/java/im/vector/app/features/location/LocationSharingActivity.kt @@ -10,6 +10,7 @@ package im.vector.app.features.location import android.content.Context import android.content.Intent import android.os.Parcelable +import android.view.View import dagger.hilt.android.AndroidEntryPoint import im.vector.app.core.extensions.addFragment import im.vector.app.core.platform.VectorBaseActivity @@ -31,6 +32,9 @@ class LocationSharingActivity : VectorBaseActivity(initialState), LocationTracker.Callback { private val room = session.getRoom(initialState.roomId)!! @@ -88,7 +91,15 @@ class LocationSharingViewModel @AssistedInject constructor( locationTracker.locations .onEach(::onLocationUpdate) .launchIn(viewModelScope) - locationTracker.start() + if (permissionChecker.checkPermission( + Manifest.permission.ACCESS_COARSE_LOCATION, + Manifest.permission.ACCESS_FINE_LOCATION, + ) + ) { + locationTracker.start() + } else { + Timber.w("Not allowed to use location api.") + } } private fun setUserItem() { diff --git a/vector/src/main/java/im/vector/app/features/location/LocationTracker.kt b/vector/src/main/java/im/vector/app/features/location/LocationTracker.kt index 70e909de27c..1baebec6175 100644 --- a/vector/src/main/java/im/vector/app/features/location/LocationTracker.kt +++ b/vector/src/main/java/im/vector/app/features/location/LocationTracker.kt @@ -17,6 +17,7 @@ import androidx.core.content.getSystemService import androidx.core.location.LocationListenerCompat import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.resources.BuildMeta +import im.vector.app.core.utils.PermissionChecker import im.vector.app.features.session.coroutineScope import kotlinx.coroutines.flow.MutableSharedFlow import kotlinx.coroutines.flow.asSharedFlow @@ -37,6 +38,7 @@ class LocationTracker @Inject constructor( context: Context, private val activeSessionHolder: ActiveSessionHolder, private val buildMeta: BuildMeta, + private val permissionChecker: PermissionChecker, ) : LocationListenerCompat { private val locationManager = context.getSystemService() @@ -173,7 +175,15 @@ class LocationTracker @Inject constructor( fun removeCallback(callback: Callback) { callbacks.remove(callback) if (callbacks.size == 0) { - stop() + if (permissionChecker.checkPermission( + Manifest.permission.ACCESS_COARSE_LOCATION, + Manifest.permission.ACCESS_FINE_LOCATION, + ) + ) { + stop() + } else { + Timber.w("Not allowed to use location api.") + } } } diff --git a/vector/src/main/java/im/vector/app/features/location/live/map/LiveLocationMapViewActivity.kt b/vector/src/main/java/im/vector/app/features/location/live/map/LiveLocationMapViewActivity.kt index 21e8f2ba029..2564d5a3959 100644 --- a/vector/src/main/java/im/vector/app/features/location/live/map/LiveLocationMapViewActivity.kt +++ b/vector/src/main/java/im/vector/app/features/location/live/map/LiveLocationMapViewActivity.kt @@ -10,6 +10,7 @@ package im.vector.app.features.location.live.map import android.content.Context import android.content.Intent import android.os.Parcelable +import android.view.View import dagger.hilt.android.AndroidEntryPoint import im.vector.app.core.extensions.addFragment import im.vector.app.core.platform.VectorBaseActivity @@ -29,6 +30,9 @@ class LiveLocationMapViewActivity : VectorBaseActivity(initialState), LocationSharingServiceConnection.Callback, @@ -123,7 +127,15 @@ class LiveLocationMapViewModel @AssistedInject constructor( copy(isLoadingUserLocation = true) } viewModelScope.launch(session.coroutineDispatchers.main) { - locationTracker.start() + if (permissionChecker.checkPermission( + Manifest.permission.ACCESS_COARSE_LOCATION, + Manifest.permission.ACCESS_FINE_LOCATION, + ) + ) { + locationTracker.start() + } else { + Timber.w("Not allowed to use location api.") + } locationTracker.requestLastKnownLocation() } } diff --git a/vector/src/main/java/im/vector/app/features/location/live/tracking/LocationSharingAndroidService.kt b/vector/src/main/java/im/vector/app/features/location/live/tracking/LocationSharingAndroidService.kt index 315a555703b..76205f98cfe 100644 --- a/vector/src/main/java/im/vector/app/features/location/live/tracking/LocationSharingAndroidService.kt +++ b/vector/src/main/java/im/vector/app/features/location/live/tracking/LocationSharingAndroidService.kt @@ -7,14 +7,18 @@ package im.vector.app.features.location.live.tracking +import android.Manifest import android.content.Intent +import android.content.pm.PackageManager import android.os.IBinder import android.os.Parcelable +import androidx.core.app.ActivityCompat import androidx.core.app.NotificationManagerCompat import dagger.hilt.android.AndroidEntryPoint import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.extensions.startForegroundCompat import im.vector.app.core.services.VectorAndroidService +import im.vector.app.core.utils.PermissionChecker import im.vector.app.features.location.LocationData import im.vector.app.features.location.LocationTracker import im.vector.app.features.location.live.GetLiveLocationShareSummaryUseCase @@ -52,6 +56,7 @@ class LocationSharingAndroidService : VectorAndroidService(), LocationTracker.Ca @Inject lateinit var activeSessionHolder: ActiveSessionHolder @Inject lateinit var getLiveLocationShareSummaryUseCase: GetLiveLocationShareSummaryUseCase @Inject lateinit var checkIfEventIsRedactedUseCase: CheckIfEventIsRedactedUseCase + @Inject lateinit var permissionChecker: PermissionChecker private var binder: LocationSharingAndroidServiceBinder? = null @@ -74,7 +79,15 @@ class LocationSharingAndroidService : VectorAndroidService(), LocationTracker.Ca private fun initLocationTracking() { // Start tracking location locationTracker.addCallback(this) - locationTracker.start() + if (permissionChecker.checkPermission( + Manifest.permission.ACCESS_COARSE_LOCATION, + Manifest.permission.ACCESS_FINE_LOCATION, + ) + ) { + locationTracker.start() + } else { + Timber.w("Not allowed to use location api.") + } launchWithActiveSession { session -> val job = locationTracker.locations @@ -95,7 +108,11 @@ class LocationSharingAndroidService : VectorAndroidService(), LocationTracker.Ca // Show a sticky notification val notification = liveLocationNotificationBuilder.buildLiveLocationSharingNotification(roomArgs.roomId) if (foregroundModeStarted) { - NotificationManagerCompat.from(this).notify(FOREGROUND_SERVICE_NOTIFICATION_ID, notification) + if (ActivityCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) { + Timber.w("Not allowed to notify.") + } else { + NotificationManagerCompat.from(this).notify(FOREGROUND_SERVICE_NOTIFICATION_ID, notification) + } } else { startForegroundCompat(FOREGROUND_SERVICE_NOTIFICATION_ID, notification) foregroundModeStarted = true @@ -146,10 +163,14 @@ class LocationSharingAndroidService : VectorAndroidService(), LocationTracker.Ca } private fun updateNotification() { - if (liveInfoSet.isNotEmpty()) { - val roomId = liveInfoSet.last().roomArgs.roomId - val notification = liveLocationNotificationBuilder.buildLiveLocationSharingNotification(roomId) - NotificationManagerCompat.from(this).notify(FOREGROUND_SERVICE_NOTIFICATION_ID, notification) + if (ActivityCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) { + Timber.w("Not allowed to notify.") + } else { + if (liveInfoSet.isNotEmpty()) { + val roomId = liveInfoSet.last().roomArgs.roomId + val notification = liveLocationNotificationBuilder.buildLiveLocationSharingNotification(roomId) + NotificationManagerCompat.from(this).notify(FOREGROUND_SERVICE_NOTIFICATION_ID, notification) + } } } diff --git a/vector/src/main/java/im/vector/app/features/location/preview/LocationPreviewViewModel.kt b/vector/src/main/java/im/vector/app/features/location/preview/LocationPreviewViewModel.kt index aacff1f745f..ae091adaae1 100644 --- a/vector/src/main/java/im/vector/app/features/location/preview/LocationPreviewViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/location/preview/LocationPreviewViewModel.kt @@ -7,6 +7,7 @@ package im.vector.app.features.location.preview +import android.Manifest import com.airbnb.mvrx.MavericksViewModelFactory import dagger.assisted.Assisted import dagger.assisted.AssistedFactory @@ -14,6 +15,7 @@ import dagger.assisted.AssistedInject import im.vector.app.core.di.MavericksAssistedViewModelFactory import im.vector.app.core.di.hiltMavericksViewModelFactory import im.vector.app.core.platform.VectorViewModel +import im.vector.app.core.utils.PermissionChecker import im.vector.app.features.home.room.detail.timeline.helper.LocationPinProvider import im.vector.app.features.location.LocationData import im.vector.app.features.location.LocationTracker @@ -23,12 +25,14 @@ import kotlinx.coroutines.launch import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.util.MatrixItem import org.matrix.android.sdk.api.util.toMatrixItem +import timber.log.Timber class LocationPreviewViewModel @AssistedInject constructor( @Assisted private val initialState: LocationPreviewViewState, private val session: Session, private val locationPinProvider: LocationPinProvider, private val locationTracker: LocationTracker, + private val permissionChecker: PermissionChecker, ) : VectorViewModel(initialState), LocationTracker.Callback { @AssistedFactory @@ -89,7 +93,15 @@ class LocationPreviewViewModel @AssistedInject constructor( copy(isLoadingUserLocation = true) } viewModelScope.launch(session.coroutineDispatchers.main) { - locationTracker.start() + if (permissionChecker.checkPermission( + Manifest.permission.ACCESS_COARSE_LOCATION, + Manifest.permission.ACCESS_FINE_LOCATION, + ) + ) { + locationTracker.start() + } else { + Timber.w("Not allowed to use location api.") + } locationTracker.requestLastKnownLocation() } } diff --git a/vector/src/main/java/im/vector/app/features/login/LoginActivity.kt b/vector/src/main/java/im/vector/app/features/login/LoginActivity.kt index cbf13acc986..2419ba7bfc1 100644 --- a/vector/src/main/java/im/vector/app/features/login/LoginActivity.kt +++ b/vector/src/main/java/im/vector/app/features/login/LoginActivity.kt @@ -76,6 +76,9 @@ open class LoginActivity : VectorBaseActivity(), UnlockedA override fun getCoordinatorLayout() = views.coordinatorLayout + override val rootView: View + get() = views.coordinatorLayout + override fun initUiAndData() { analyticsScreenName = MobileScreen.ScreenName.Login diff --git a/vector/src/main/java/im/vector/app/features/media/BigImageViewerActivity.kt b/vector/src/main/java/im/vector/app/features/media/BigImageViewerActivity.kt index 05c331d1d04..57d631b5be7 100644 --- a/vector/src/main/java/im/vector/app/features/media/BigImageViewerActivity.kt +++ b/vector/src/main/java/im/vector/app/features/media/BigImageViewerActivity.kt @@ -10,6 +10,7 @@ package im.vector.app.features.media import android.content.Context import android.content.Intent import android.os.Bundle +import android.view.View import androidx.core.net.toUri import dagger.hilt.android.AndroidEntryPoint import im.vector.app.core.di.ActiveSessionHolder @@ -26,6 +27,9 @@ class BigImageViewerActivity : VectorBaseActivity override fun getBinding() = ActivityBigImageViewerBinding.inflate(layoutInflater) + override val rootView: View + get() = views.mainRoot + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) diff --git a/vector/src/main/java/im/vector/app/features/media/VectorAttachmentViewerActivity.kt b/vector/src/main/java/im/vector/app/features/media/VectorAttachmentViewerActivity.kt index 058372feffd..e6e2209e421 100644 --- a/vector/src/main/java/im/vector/app/features/media/VectorAttachmentViewerActivity.kt +++ b/vector/src/main/java/im/vector/app/features/media/VectorAttachmentViewerActivity.kt @@ -138,7 +138,9 @@ class VectorAttachmentViewerActivity : AttachmentViewerActivity(), AttachmentInt } } + @Suppress("DEPRECATION") window.statusBarColor = ContextCompat.getColor(this, im.vector.lib.ui.styles.R.color.black_alpha) + @Suppress("DEPRECATION") window.navigationBarColor = ContextCompat.getColor(this, im.vector.lib.ui.styles.R.color.black_alpha) observeViewEvents() diff --git a/vector/src/main/java/im/vector/app/features/notifications/NotificationDisplayer.kt b/vector/src/main/java/im/vector/app/features/notifications/NotificationDisplayer.kt index 5106eb1dfcd..29eeb04f9d3 100644 --- a/vector/src/main/java/im/vector/app/features/notifications/NotificationDisplayer.kt +++ b/vector/src/main/java/im/vector/app/features/notifications/NotificationDisplayer.kt @@ -7,18 +7,27 @@ package im.vector.app.features.notifications +import android.Manifest import android.app.Notification import android.content.Context +import android.content.pm.PackageManager +import androidx.core.app.ActivityCompat import androidx.core.app.NotificationManagerCompat import timber.log.Timber import javax.inject.Inject -class NotificationDisplayer @Inject constructor(context: Context) { +class NotificationDisplayer @Inject constructor( + private val context: Context, +) { private val notificationManager = NotificationManagerCompat.from(context) fun showNotificationMessage(tag: String?, id: Int, notification: Notification) { - notificationManager.notify(tag, id, notification) + if (ActivityCompat.checkSelfPermission(context, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) { + Timber.w("Not allowed to notify.") + } else { + notificationManager.notify(tag, id, notification) + } } fun cancelNotificationMessage(tag: String?, id: Int) { diff --git a/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt b/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt index 985d35961f5..aa6010c31ed 100755 --- a/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt +++ b/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt @@ -9,6 +9,7 @@ package im.vector.app.features.notifications +import android.Manifest import android.annotation.SuppressLint import android.app.Notification import android.app.NotificationChannel @@ -16,6 +17,7 @@ import android.app.NotificationManager import android.app.PendingIntent import android.content.Context import android.content.Intent +import android.content.pm.PackageManager import android.graphics.Bitmap import android.graphics.Canvas import android.net.Uri @@ -27,6 +29,7 @@ import androidx.annotation.AttrRes import androidx.annotation.ChecksSdkIntAtLeast import androidx.annotation.DrawableRes import androidx.annotation.StringRes +import androidx.core.app.ActivityCompat import androidx.core.app.NotificationCompat import androidx.core.app.NotificationManagerCompat import androidx.core.app.RemoteInput @@ -153,55 +156,59 @@ class NotificationUtils @Inject constructor( * Default notification importance: shows everywhere, makes noise, but does not visually * intrude. */ - notificationManager.createNotificationChannel(NotificationChannel( - NOISY_NOTIFICATION_CHANNEL_ID, - stringProvider.getString(CommonStrings.notification_noisy_notifications).ifEmpty { "Noisy notifications" }, - NotificationManager.IMPORTANCE_DEFAULT - ) - .apply { - description = stringProvider.getString(CommonStrings.notification_noisy_notifications) - enableVibration(true) - enableLights(true) - lightColor = accentColor - }) + notificationManager.createNotificationChannel( + NotificationChannel( + NOISY_NOTIFICATION_CHANNEL_ID, + stringProvider.getString(CommonStrings.notification_noisy_notifications).ifEmpty { "Noisy notifications" }, + NotificationManager.IMPORTANCE_DEFAULT + ) + .apply { + description = stringProvider.getString(CommonStrings.notification_noisy_notifications) + enableVibration(true) + enableLights(true) + lightColor = accentColor + }) /** * Low notification importance: shows everywhere, but is not intrusive. */ - notificationManager.createNotificationChannel(NotificationChannel( - SILENT_NOTIFICATION_CHANNEL_ID, - stringProvider.getString(CommonStrings.notification_silent_notifications).ifEmpty { "Silent notifications" }, - NotificationManager.IMPORTANCE_LOW - ) - .apply { - description = stringProvider.getString(CommonStrings.notification_silent_notifications) - setSound(null, null) - enableLights(true) - lightColor = accentColor - }) - - notificationManager.createNotificationChannel(NotificationChannel( - LISTENING_FOR_EVENTS_NOTIFICATION_CHANNEL_ID, - stringProvider.getString(CommonStrings.notification_listening_for_events).ifEmpty { "Listening for events" }, - NotificationManager.IMPORTANCE_MIN - ) - .apply { - description = stringProvider.getString(CommonStrings.notification_listening_for_events) - setSound(null, null) - setShowBadge(false) - }) - - notificationManager.createNotificationChannel(NotificationChannel( - CALL_NOTIFICATION_CHANNEL_ID, - stringProvider.getString(CommonStrings.call).ifEmpty { "Call" }, - NotificationManager.IMPORTANCE_HIGH - ) - .apply { - description = stringProvider.getString(CommonStrings.call) - setSound(null, null) - enableLights(true) - lightColor = accentColor - }) + notificationManager.createNotificationChannel( + NotificationChannel( + SILENT_NOTIFICATION_CHANNEL_ID, + stringProvider.getString(CommonStrings.notification_silent_notifications).ifEmpty { "Silent notifications" }, + NotificationManager.IMPORTANCE_LOW + ) + .apply { + description = stringProvider.getString(CommonStrings.notification_silent_notifications) + setSound(null, null) + enableLights(true) + lightColor = accentColor + }) + + notificationManager.createNotificationChannel( + NotificationChannel( + LISTENING_FOR_EVENTS_NOTIFICATION_CHANNEL_ID, + stringProvider.getString(CommonStrings.notification_listening_for_events).ifEmpty { "Listening for events" }, + NotificationManager.IMPORTANCE_MIN + ) + .apply { + description = stringProvider.getString(CommonStrings.notification_listening_for_events) + setSound(null, null) + setShowBadge(false) + }) + + notificationManager.createNotificationChannel( + NotificationChannel( + CALL_NOTIFICATION_CHANNEL_ID, + stringProvider.getString(CommonStrings.call).ifEmpty { "Call" }, + NotificationManager.IMPORTANCE_HIGH + ) + .apply { + description = stringProvider.getString(CommonStrings.call) + setSound(null, null) + enableLights(true) + lightColor = accentColor + }) } fun getChannel(channelId: String): NotificationChannel? { @@ -997,7 +1004,11 @@ class NotificationUtils @Inject constructor( } fun showNotificationMessage(tag: String?, id: Int, notification: Notification) { - notificationManager.notify(tag, id, notification) + if (ActivityCompat.checkSelfPermission(context, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) { + Timber.w("Not allowed to notify.") + } else { + notificationManager.notify(tag, id, notification) + } } fun cancelNotificationMessage(tag: String?, id: Int) { @@ -1025,30 +1036,34 @@ class NotificationUtils @Inject constructor( @SuppressLint("LaunchActivityFromNotification") fun displayDiagnosticNotification() { - val testActionIntent = Intent(context, TestNotificationReceiver::class.java) - testActionIntent.action = actionIds.diagnostic - val testPendingIntent = PendingIntent.getBroadcast( - context, - 0, - testActionIntent, - PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE - ) + if (ActivityCompat.checkSelfPermission(context, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) { + Timber.w("Not allowed to notify.") + } else { + val testActionIntent = Intent(context, TestNotificationReceiver::class.java) + testActionIntent.action = actionIds.diagnostic + val testPendingIntent = PendingIntent.getBroadcast( + context, + 0, + testActionIntent, + PendingIntent.FLAG_UPDATE_CURRENT or PendingIntentCompat.FLAG_IMMUTABLE + ) - notificationManager.notify( - "DIAGNOSTIC", - 888, - NotificationCompat.Builder(context, NOISY_NOTIFICATION_CHANNEL_ID) - .setContentTitle(buildMeta.applicationName) - .setContentText(stringProvider.getString(CommonStrings.settings_troubleshoot_test_push_notification_content)) - .setSmallIcon(R.drawable.ic_notification) - .setLargeIcon(getBitmap(context, im.vector.lib.ui.styles.R.drawable.element_logo_green)) - .setColor(ContextCompat.getColor(context, im.vector.lib.ui.styles.R.color.notification_accent_color)) - .setPriority(NotificationCompat.PRIORITY_MAX) - .setCategory(NotificationCompat.CATEGORY_STATUS) - .setAutoCancel(true) - .setContentIntent(testPendingIntent) - .build() - ) + notificationManager.notify( + "DIAGNOSTIC", + 888, + NotificationCompat.Builder(context, NOISY_NOTIFICATION_CHANNEL_ID) + .setContentTitle(buildMeta.applicationName) + .setContentText(stringProvider.getString(CommonStrings.settings_troubleshoot_test_push_notification_content)) + .setSmallIcon(R.drawable.ic_notification) + .setLargeIcon(getBitmap(context, im.vector.lib.ui.styles.R.drawable.element_logo_green)) + .setColor(ContextCompat.getColor(context, im.vector.lib.ui.styles.R.color.notification_accent_color)) + .setPriority(NotificationCompat.PRIORITY_MAX) + .setCategory(NotificationCompat.CATEGORY_STATUS) + .setAutoCancel(true) + .setContentIntent(testPendingIntent) + .build() + ) + } } private fun getBitmap(context: Context, @DrawableRes drawableRes: Int): Bitmap? { diff --git a/vector/src/main/java/im/vector/app/features/onboarding/OnboardingActivity.kt b/vector/src/main/java/im/vector/app/features/onboarding/OnboardingActivity.kt index f62989fec61..dd8d287bad1 100644 --- a/vector/src/main/java/im/vector/app/features/onboarding/OnboardingActivity.kt +++ b/vector/src/main/java/im/vector/app/features/onboarding/OnboardingActivity.kt @@ -10,6 +10,7 @@ package im.vector.app.features.onboarding import android.content.Context import android.content.Intent import android.net.Uri +import android.view.View import dagger.hilt.android.AndroidEntryPoint import im.vector.app.core.extensions.lazyViewModel import im.vector.app.core.extensions.validateBackPressed @@ -33,6 +34,9 @@ class OnboardingActivity : VectorBaseActivity(), UnlockedA override fun getCoordinatorLayout() = views.coordinatorLayout + override val rootView: View + get() = views.coordinatorLayout + override fun onNewIntent(intent: Intent) { super.onNewIntent(intent) onboardingVariant.onNewIntent(intent) diff --git a/vector/src/main/java/im/vector/app/features/pin/PinActivity.kt b/vector/src/main/java/im/vector/app/features/pin/PinActivity.kt index a002bc0329a..b5c70fddd94 100644 --- a/vector/src/main/java/im/vector/app/features/pin/PinActivity.kt +++ b/vector/src/main/java/im/vector/app/features/pin/PinActivity.kt @@ -9,6 +9,7 @@ package im.vector.app.features.pin import android.content.Context import android.content.Intent +import android.view.View import com.airbnb.mvrx.Mavericks import dagger.hilt.android.AndroidEntryPoint import im.vector.app.core.extensions.addFragment @@ -31,6 +32,9 @@ class PinActivity : VectorBaseActivity(), UnlockedActivit override fun getCoordinatorLayout() = views.coordinatorLayout + override val rootView: View + get() = views.coordinatorLayout + override fun initUiAndData() { if (isFirstCreation()) { val fragmentArgs: PinArgs = intent?.extras?.getParcelableCompat(Mavericks.KEY_ARG) ?: return diff --git a/vector/src/main/java/im/vector/app/features/pin/lockscreen/views/LockScreenCodeView.kt b/vector/src/main/java/im/vector/app/features/pin/lockscreen/views/LockScreenCodeView.kt index 5187b8ba738..6efe59b09ad 100644 --- a/vector/src/main/java/im/vector/app/features/pin/lockscreen/views/LockScreenCodeView.kt +++ b/vector/src/main/java/im/vector/app/features/pin/lockscreen/views/LockScreenCodeView.kt @@ -92,7 +92,7 @@ class LockScreenCodeView @JvmOverloads constructor( */ fun deleteLast(): Int { if (code.size == 0) return code.size - code.removeLast() + code.removeAt(code.lastIndex) getCodeView(code.size)?.toggle() return code.size } diff --git a/vector/src/main/java/im/vector/app/features/qrcode/QrCodeScannerActivity.kt b/vector/src/main/java/im/vector/app/features/qrcode/QrCodeScannerActivity.kt index d2f8016bda8..5325a3f0435 100644 --- a/vector/src/main/java/im/vector/app/features/qrcode/QrCodeScannerActivity.kt +++ b/vector/src/main/java/im/vector/app/features/qrcode/QrCodeScannerActivity.kt @@ -10,6 +10,7 @@ package im.vector.app.features.qrcode import android.app.Activity import android.content.Intent import android.os.Bundle +import android.view.View import android.widget.Toast import androidx.activity.result.ActivityResultLauncher import com.airbnb.mvrx.viewModel @@ -26,6 +27,9 @@ class QrCodeScannerActivity : VectorBaseActivity() { override fun getCoordinatorLayout() = views.coordinatorLayout + override val rootView: View + get() = views.coordinatorLayout + private val qrViewModel: QrCodeScannerViewModel by viewModel() override fun onCreate(savedInstanceState: Bundle?) { diff --git a/vector/src/main/java/im/vector/app/features/rageshake/BugReportActivity.kt b/vector/src/main/java/im/vector/app/features/rageshake/BugReportActivity.kt index 71b58955739..b4024fa1242 100755 --- a/vector/src/main/java/im/vector/app/features/rageshake/BugReportActivity.kt +++ b/vector/src/main/java/im/vector/app/features/rageshake/BugReportActivity.kt @@ -11,6 +11,7 @@ import android.content.Context import android.content.Intent import android.view.Menu import android.view.MenuItem +import android.view.View import android.widget.Toast import androidx.core.view.isVisible import androidx.core.widget.doOnTextChanged @@ -37,6 +38,9 @@ class BugReportActivity : private val viewModel: BugReportViewModel by viewModel() + override val rootView: View + get() = views.mainRoot + private var reportType: ReportType = ReportType.BUG_REPORT override fun initUiAndData() { diff --git a/vector/src/main/java/im/vector/app/features/reactions/EmojiReactionPickerActivity.kt b/vector/src/main/java/im/vector/app/features/reactions/EmojiReactionPickerActivity.kt index 7cd7b79b112..774b41245ce 100644 --- a/vector/src/main/java/im/vector/app/features/reactions/EmojiReactionPickerActivity.kt +++ b/vector/src/main/java/im/vector/app/features/reactions/EmojiReactionPickerActivity.kt @@ -13,6 +13,7 @@ import android.graphics.Typeface import android.util.TypedValue import android.view.Menu import android.view.MenuItem +import android.view.View import android.widget.SearchView import androidx.core.view.isVisible import androidx.lifecycle.lifecycleScope @@ -55,6 +56,9 @@ class EmojiReactionPickerActivity : override fun getCoordinatorLayout() = views.coordinatorLayout + override val rootView: View + get() = views.coordinatorLayout + override fun getTitleRes() = CommonStrings.title_activity_emoji_reaction_picker @Inject lateinit var emojiCompatFontProvider: EmojiCompatFontProvider diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryActivity.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryActivity.kt index 3940404af96..8a1c75ad61b 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryActivity.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/RoomDirectoryActivity.kt @@ -10,6 +10,7 @@ package im.vector.app.features.roomdirectory import android.content.Context import android.content.Intent import android.os.Bundle +import android.view.View import androidx.lifecycle.lifecycleScope import com.airbnb.mvrx.viewModel import com.airbnb.mvrx.withState @@ -41,6 +42,9 @@ class RoomDirectoryActivity : VectorBaseActivity(), Matri override fun getCoordinatorLayout() = views.coordinatorLayout + override val rootView: View + get() = views.coordinatorLayout + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) analyticsScreenName = MobileScreen.ScreenName.RoomDirectory diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomActivity.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomActivity.kt index c3ba0e70413..90be84d8480 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomActivity.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/createroom/CreateRoomActivity.kt @@ -11,6 +11,7 @@ import android.app.Activity import android.content.Context import android.content.Intent import android.os.Bundle +import android.view.View import androidx.lifecycle.lifecycleScope import com.airbnb.mvrx.Mavericks import dagger.hilt.android.AndroidEntryPoint @@ -36,6 +37,9 @@ class CreateRoomActivity : VectorBaseActivity() { override fun getCoordinatorLayout() = views.coordinatorLayout + override val rootView: View + get() = views.coordinatorLayout + override fun initUiAndData() { if (isFirstCreation()) { val fragmentArgs: CreateRoomArgs = intent?.extras?.getParcelableCompat(Mavericks.KEY_ARG) ?: return diff --git a/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewActivity.kt b/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewActivity.kt index 77bac7dfa18..b6859f36dff 100644 --- a/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewActivity.kt +++ b/vector/src/main/java/im/vector/app/features/roomdirectory/roompreview/RoomPreviewActivity.kt @@ -10,6 +10,7 @@ package im.vector.app.features.roomdirectory.roompreview import android.content.Context import android.content.Intent import android.os.Parcelable +import android.view.View import dagger.hilt.android.AndroidEntryPoint import im.vector.app.core.extensions.addFragment import im.vector.app.core.platform.VectorBaseActivity @@ -73,6 +74,9 @@ class RoomPreviewActivity : VectorBaseActivity() { override fun getCoordinatorLayout() = views.coordinatorLayout + override val rootView: View + get() = views.simpleFragmentContainer + override fun initUiAndData() { if (isFirstCreation()) { val args = intent.getParcelableExtraCompat(ARG) diff --git a/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileActivity.kt b/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileActivity.kt index cf593c039e9..43ee03fd589 100644 --- a/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileActivity.kt +++ b/vector/src/main/java/im/vector/app/features/roommemberprofile/RoomMemberProfileActivity.kt @@ -9,6 +9,7 @@ package im.vector.app.features.roommemberprofile import android.content.Context import android.content.Intent +import android.view.View import android.widget.Toast import com.airbnb.mvrx.Mavericks import com.airbnb.mvrx.viewModel @@ -37,6 +38,11 @@ class RoomMemberProfileActivity : VectorBaseActivity() { return ActivitySimpleBinding.inflate(layoutInflater) } + override fun getCoordinatorLayout() = views.coordinatorLayout + + override val rootView: View + get() = views.coordinatorLayout + override fun initUiAndData() { if (isFirstCreation()) { val fragmentArgs: RoomMemberProfileArgs = intent?.extras?.getParcelableCompat(Mavericks.KEY_ARG) ?: return diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileActivity.kt b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileActivity.kt index 5bbfab6e18d..db5cd3b9cb1 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileActivity.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/RoomProfileActivity.kt @@ -9,6 +9,7 @@ package im.vector.app.features.roomprofile import android.content.Context import android.content.Intent +import android.view.View import android.widget.Toast import androidx.lifecycle.lifecycleScope import com.airbnb.mvrx.Mavericks @@ -68,6 +69,9 @@ class RoomProfileActivity : override fun getCoordinatorLayout() = views.coordinatorLayout + override val rootView: View + get() = views.coordinatorLayout + override fun initUiAndData() { sharedActionViewModel = viewModelProvider.get(RoomProfileSharedActionViewModel::class.java) roomProfileArgs = intent?.extras?.getParcelableCompat(Mavericks.KEY_ARG) ?: return diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/polls/detail/ui/RoomPollDetailActivity.kt b/vector/src/main/java/im/vector/app/features/roomprofile/polls/detail/ui/RoomPollDetailActivity.kt index dc3db0401e6..a8a1c318627 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/polls/detail/ui/RoomPollDetailActivity.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/polls/detail/ui/RoomPollDetailActivity.kt @@ -10,6 +10,7 @@ package im.vector.app.features.roomprofile.polls.detail.ui import android.content.Context import android.content.Intent import android.os.Bundle +import android.view.View import com.airbnb.mvrx.Mavericks import dagger.hilt.android.AndroidEntryPoint import im.vector.app.core.extensions.addFragment @@ -25,6 +26,11 @@ class RoomPollDetailActivity : VectorBaseActivity() { override fun getBinding() = ActivitySimpleBinding.inflate(layoutInflater) + override fun getCoordinatorLayout() = views.coordinatorLayout + + override val rootView: View + get() = views.coordinatorLayout + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) diff --git a/vector/src/main/java/im/vector/app/features/roomprofile/settings/joinrule/RoomJoinRuleActivity.kt b/vector/src/main/java/im/vector/app/features/roomprofile/settings/joinrule/RoomJoinRuleActivity.kt index 30d2e688b66..868564737fb 100644 --- a/vector/src/main/java/im/vector/app/features/roomprofile/settings/joinrule/RoomJoinRuleActivity.kt +++ b/vector/src/main/java/im/vector/app/features/roomprofile/settings/joinrule/RoomJoinRuleActivity.kt @@ -10,6 +10,7 @@ package im.vector.app.features.roomprofile.settings.joinrule import android.content.Context import android.content.Intent import android.os.Bundle +import android.view.View import androidx.core.view.isVisible import com.airbnb.mvrx.Fail import com.airbnb.mvrx.Loading @@ -40,6 +41,11 @@ class RoomJoinRuleActivity : VectorBaseActivity() { override fun getBinding() = ActivitySimpleBinding.inflate(layoutInflater) + override fun getCoordinatorLayout() = views.coordinatorLayout + + override val rootView: View + get() = views.coordinatorLayout + private lateinit var roomProfileArgs: RoomProfileArgs val viewModel: RoomJoinRuleChooseRestrictedViewModel by viewModel() diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsActivity.kt b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsActivity.kt index 62d09174906..c942d8f06ad 100755 --- a/vector/src/main/java/im/vector/app/features/settings/VectorSettingsActivity.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorSettingsActivity.kt @@ -11,6 +11,7 @@ import android.content.Context import android.content.Intent import android.os.Bundle import android.os.Parcelable +import android.view.View import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager import androidx.preference.Preference @@ -47,6 +48,9 @@ class VectorSettingsActivity : VectorBaseActivity override fun getCoordinatorLayout() = views.coordinatorLayout + override val rootView: View + get() = views.coordinatorLayout + override fun getTitleRes() = CommonStrings.title_activity_settings private var keyToHighlight: String? = null diff --git a/vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionActivity.kt b/vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionActivity.kt index 3625dee311d..7a556e18ebc 100644 --- a/vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionActivity.kt +++ b/vector/src/main/java/im/vector/app/features/settings/devices/v2/rename/RenameSessionActivity.kt @@ -10,6 +10,7 @@ package im.vector.app.features.settings.devices.v2.rename import android.content.Context import android.content.Intent import android.os.Bundle +import android.view.View import android.view.WindowManager import com.airbnb.mvrx.Mavericks import dagger.hilt.android.AndroidEntryPoint @@ -26,6 +27,11 @@ class RenameSessionActivity : VectorBaseActivity() { override fun getBinding() = ActivitySimpleBinding.inflate(layoutInflater) + override fun getCoordinatorLayout() = views.coordinatorLayout + + override val rootView: View + get() = views.coordinatorLayout + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) diff --git a/vector/src/main/java/im/vector/app/features/settings/font/FontScaleSettingActivity.kt b/vector/src/main/java/im/vector/app/features/settings/font/FontScaleSettingActivity.kt index d2e8ffccbfa..1ffb93d840b 100644 --- a/vector/src/main/java/im/vector/app/features/settings/font/FontScaleSettingActivity.kt +++ b/vector/src/main/java/im/vector/app/features/settings/font/FontScaleSettingActivity.kt @@ -7,6 +7,7 @@ package im.vector.app.features.settings.font +import android.view.View import dagger.hilt.android.AndroidEntryPoint import im.vector.app.core.extensions.addFragment import im.vector.app.core.platform.VectorBaseActivity @@ -17,6 +18,11 @@ class FontScaleSettingActivity : VectorBaseActivity() { override fun getBinding() = ActivitySimpleBinding.inflate(layoutInflater) + override fun getCoordinatorLayout() = views.coordinatorLayout + + override val rootView: View + get() = views.coordinatorLayout + override fun initUiAndData() { if (isFirstCreation()) { addFragment(views.simpleFragmentContainer, FontScaleSettingFragment::class.java) diff --git a/vector/src/main/java/im/vector/app/features/share/IncomingShareActivity.kt b/vector/src/main/java/im/vector/app/features/share/IncomingShareActivity.kt index e2a00c516fe..3d89a6ebc9c 100644 --- a/vector/src/main/java/im/vector/app/features/share/IncomingShareActivity.kt +++ b/vector/src/main/java/im/vector/app/features/share/IncomingShareActivity.kt @@ -9,6 +9,7 @@ package im.vector.app.features.share import android.content.Intent import android.os.Bundle +import android.view.View import com.airbnb.mvrx.viewModel import dagger.hilt.android.AndroidEntryPoint import im.vector.app.core.extensions.addFragment @@ -46,6 +47,9 @@ class IncomingShareActivity : VectorBaseActivity() { override fun getCoordinatorLayout() = views.coordinatorLayout + override val rootView: View + get() = views.coordinatorLayout + private fun handleAppStarted() { // If we are not logged in, stop the sharing process and open login screen. // In the future, we might want to relaunch the sharing process after login. diff --git a/vector/src/main/java/im/vector/app/features/signout/hard/SignedOutActivity.kt b/vector/src/main/java/im/vector/app/features/signout/hard/SignedOutActivity.kt index c94d9ab7b92..e6b3b817ea7 100644 --- a/vector/src/main/java/im/vector/app/features/signout/hard/SignedOutActivity.kt +++ b/vector/src/main/java/im/vector/app/features/signout/hard/SignedOutActivity.kt @@ -10,6 +10,7 @@ package im.vector.app.features.signout.hard import android.content.Context import android.content.Intent import android.os.Bundle +import android.view.View import dagger.hilt.android.AndroidEntryPoint import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.databinding.ActivitySignedOutBinding @@ -26,6 +27,9 @@ class SignedOutActivity : VectorBaseActivity() { override fun getBinding() = ActivitySignedOutBinding.inflate(layoutInflater) + override val rootView: View + get() = views.signedOut + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) diff --git a/vector/src/main/java/im/vector/app/features/spaces/SpaceExploreActivity.kt b/vector/src/main/java/im/vector/app/features/spaces/SpaceExploreActivity.kt index 5f060adeb9d..7e5d776ca2d 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/SpaceExploreActivity.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/SpaceExploreActivity.kt @@ -11,6 +11,7 @@ import android.app.Activity import android.content.Context import android.content.Intent import android.os.Bundle +import android.view.View import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager import com.airbnb.mvrx.Mavericks @@ -38,6 +39,11 @@ class SpaceExploreActivity : VectorBaseActivity(), Matrix override fun getBinding(): ActivitySimpleBinding = ActivitySimpleBinding.inflate(layoutInflater) + override fun getCoordinatorLayout() = views.coordinatorLayout + + override val rootView: View + get() = views.coordinatorLayout + override fun getTitleRes(): Int = CommonStrings.space_explore_activity_title val sharedViewModel: SpaceDirectoryViewModel by viewModel() diff --git a/vector/src/main/java/im/vector/app/features/spaces/SpacePreviewActivity.kt b/vector/src/main/java/im/vector/app/features/spaces/SpacePreviewActivity.kt index d698f2ed358..6b60253b4a1 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/SpacePreviewActivity.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/SpacePreviewActivity.kt @@ -10,6 +10,7 @@ package im.vector.app.features.spaces import android.content.Context import android.content.Intent import android.os.Bundle +import android.view.View import androidx.lifecycle.lifecycleScope import com.airbnb.mvrx.Mavericks import dagger.hilt.android.AndroidEntryPoint @@ -29,6 +30,11 @@ class SpacePreviewActivity : VectorBaseActivity() { override fun getBinding(): ActivitySimpleBinding = ActivitySimpleBinding.inflate(layoutInflater) + override fun getCoordinatorLayout() = views.coordinatorLayout + + override val rootView: View + get() = views.coordinatorLayout + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) sharedActionViewModel = viewModelProvider.get(SpacePreviewSharedActionViewModel::class.java) diff --git a/vector/src/main/java/im/vector/app/features/spaces/leave/SpaceLeaveAdvancedActivity.kt b/vector/src/main/java/im/vector/app/features/spaces/leave/SpaceLeaveAdvancedActivity.kt index cf7b706adfd..84c3c78b2ae 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/leave/SpaceLeaveAdvancedActivity.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/leave/SpaceLeaveAdvancedActivity.kt @@ -10,6 +10,7 @@ package im.vector.app.features.spaces.leave import android.content.Context import android.content.Intent import android.os.Bundle +import android.view.View import androidx.core.view.isGone import androidx.core.view.isVisible import com.airbnb.mvrx.Fail @@ -33,6 +34,11 @@ class SpaceLeaveAdvancedActivity : VectorBaseActivity() { override fun getBinding(): ActivitySimpleLoadingBinding = ActivitySimpleLoadingBinding.inflate(layoutInflater) + override fun getCoordinatorLayout() = views.coordinatorLayout + + override val rootView: View + get() = views.coordinatorLayout + override fun getTitleRes(): Int = CommonStrings.space_add_existing_rooms val sharedViewModel: SpaceManageSharedViewModel by viewModel() diff --git a/vector/src/main/java/im/vector/app/features/spaces/people/SpacePeopleActivity.kt b/vector/src/main/java/im/vector/app/features/spaces/people/SpacePeopleActivity.kt index 7a12dedd56e..4bb2f0c44a8 100644 --- a/vector/src/main/java/im/vector/app/features/spaces/people/SpacePeopleActivity.kt +++ b/vector/src/main/java/im/vector/app/features/spaces/people/SpacePeopleActivity.kt @@ -10,6 +10,7 @@ package im.vector.app.features.spaces.people import android.content.Context import android.content.Intent import android.os.Bundle +import android.view.View import androidx.core.view.isGone import androidx.core.view.isVisible import androidx.lifecycle.lifecycleScope @@ -32,6 +33,11 @@ class SpacePeopleActivity : VectorBaseActivity() { override fun getBinding() = ActivitySimpleLoadingBinding.inflate(layoutInflater) + override fun getCoordinatorLayout() = views.coordinatorLayout + + override val rootView: View + get() = views.coordinatorLayout + private lateinit var sharedActionViewModel: SpacePeopleSharedActionViewModel override fun initUiAndData() { diff --git a/vector/src/main/java/im/vector/app/features/usercode/UserCodeActivity.kt b/vector/src/main/java/im/vector/app/features/usercode/UserCodeActivity.kt index 06fc143e21c..7b27ffdd1ee 100644 --- a/vector/src/main/java/im/vector/app/features/usercode/UserCodeActivity.kt +++ b/vector/src/main/java/im/vector/app/features/usercode/UserCodeActivity.kt @@ -11,6 +11,7 @@ import android.content.Context import android.content.Intent import android.os.Bundle import android.os.Parcelable +import android.view.View import android.widget.Toast import androidx.core.app.ActivityCompat import androidx.core.view.isVisible @@ -51,6 +52,9 @@ class UserCodeActivity : VectorBaseActivity(), override fun getCoordinatorLayout() = views.coordinatorLayout + override val rootView: View + get() = views.coordinatorLayout + private val fragmentLifecycleCallbacks = object : FragmentManager.FragmentLifecycleCallbacks() { override fun onFragmentResumed(fm: FragmentManager, f: Fragment) { if (f is MatrixToBottomSheet) { diff --git a/vector/src/main/java/im/vector/app/features/voice/VoiceRecorderL.kt b/vector/src/main/java/im/vector/app/features/voice/VoiceRecorderL.kt index f53571e753f..b905ff4447a 100644 --- a/vector/src/main/java/im/vector/app/features/voice/VoiceRecorderL.kt +++ b/vector/src/main/java/im/vector/app/features/voice/VoiceRecorderL.kt @@ -7,6 +7,7 @@ package im.vector.app.features.voice +import android.Manifest import android.content.Context import android.media.AudioFormat import android.media.AudioRecord @@ -15,6 +16,7 @@ import android.media.audiofx.AutomaticGainControl import android.media.audiofx.NoiseSuppressor import android.os.Build import android.widget.Toast +import im.vector.app.core.utils.PermissionChecker import io.element.android.opusencoder.OggOpusEncoder import io.element.android.opusencoder.configuration.SampleRate import kotlinx.coroutines.CoroutineScope @@ -22,6 +24,7 @@ import kotlinx.coroutines.Job import kotlinx.coroutines.isActive import kotlinx.coroutines.launch import org.matrix.android.sdk.api.extensions.tryOrNull +import timber.log.Timber import kotlin.coroutines.CoroutineContext /** @@ -31,6 +34,7 @@ class VoiceRecorderL( private val context: Context, coroutineContext: CoroutineContext, private val codec: OggOpusEncoder, + private val permissionChecker: PermissionChecker, ) : AbstractVoiceRecorder(context) { companion object { @@ -127,7 +131,11 @@ class VoiceRecorderL( bufferSizeInShorts = AudioRecord.getMinBufferSize(SAMPLE_RATE.value, channelConfig, format) // Buffer is created as a ShortArray, but AudioRecord needs the size in bytes val bufferSizeInBytes = bufferSizeInShorts * 2 - audioRecorder = AudioRecord(MediaRecorder.AudioSource.MIC, SAMPLE_RATE.value, channelConfig, format, bufferSizeInBytes) + if (permissionChecker.checkPermission(Manifest.permission.RECORD_AUDIO)) { + audioRecorder = AudioRecord(MediaRecorder.AudioSource.MIC, SAMPLE_RATE.value, channelConfig, format, bufferSizeInBytes) + } else { + Timber.w("Not allowed to record audio.") + } } private fun calculateMaxAmplitude(buffer: ShortArray) { diff --git a/vector/src/main/java/im/vector/app/features/voice/VoiceRecorderProvider.kt b/vector/src/main/java/im/vector/app/features/voice/VoiceRecorderProvider.kt index 0b971907a2e..62309aa59b1 100644 --- a/vector/src/main/java/im/vector/app/features/voice/VoiceRecorderProvider.kt +++ b/vector/src/main/java/im/vector/app/features/voice/VoiceRecorderProvider.kt @@ -13,6 +13,7 @@ import android.media.MediaFormat import android.os.Build import androidx.annotation.ChecksSdkIntAtLeast import androidx.annotation.VisibleForTesting +import im.vector.app.core.utils.PermissionChecker import im.vector.app.features.VectorFeatures import io.element.android.opusencoder.OggOpusEncoder import kotlinx.coroutines.Dispatchers @@ -23,12 +24,13 @@ class VoiceRecorderProvider @Inject constructor( private val context: Context, private val vectorFeatures: VectorFeatures, private val buildVersionSdkIntProvider: BuildVersionSdkIntProvider, + private val permissionChecker: PermissionChecker, ) { fun provideVoiceRecorder(): VoiceRecorder { return if (useNativeRecorder()) { VoiceRecorderQ(context) } else { - VoiceRecorderL(context, Dispatchers.IO, OggOpusEncoder.create()) + VoiceRecorderL(context, Dispatchers.IO, OggOpusEncoder.create(), permissionChecker) } } 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 7af0dc62dc8..6e7cb9e4684 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 @@ -9,6 +9,7 @@ package im.vector.app.features.webview import android.content.Context import android.content.Intent +import android.view.View import android.webkit.WebChromeClient import android.webkit.WebView import dagger.hilt.android.AndroidEntryPoint @@ -28,6 +29,9 @@ class VectorWebViewActivity : VectorBaseActivity() override fun getBinding() = ActivityVectorWebViewBinding.inflate(layoutInflater) + override val rootView: View + get() = views.mainRoot + val session: Session by lazy { activeSessionHolder.getActiveSession() } diff --git a/vector/src/main/java/im/vector/app/features/widgets/WidgetActivity.kt b/vector/src/main/java/im/vector/app/features/widgets/WidgetActivity.kt index 099f39f67a7..917fc02440b 100644 --- a/vector/src/main/java/im/vector/app/features/widgets/WidgetActivity.kt +++ b/vector/src/main/java/im/vector/app/features/widgets/WidgetActivity.kt @@ -20,6 +20,7 @@ import android.content.IntentFilter import android.graphics.drawable.Icon import android.os.Build import android.util.Rational +import android.view.View import androidx.annotation.RequiresApi import androidx.core.app.PictureInPictureModeChangedInfo import androidx.core.content.ContextCompat @@ -77,6 +78,9 @@ class WidgetActivity : VectorBaseActivity() { override fun getBinding() = ActivityWidgetBinding.inflate(layoutInflater) + override val rootView: View + get() = views.mainRoot + override fun getTitleRes() = CommonStrings.room_widget_activity_title override fun initUiAndData() { diff --git a/vector/src/main/res/layout/activity_big_image_viewer.xml b/vector/src/main/res/layout/activity_big_image_viewer.xml index 8f1cf88affa..cd254db50db 100644 --- a/vector/src/main/res/layout/activity_big_image_viewer.xml +++ b/vector/src/main/res/layout/activity_big_image_viewer.xml @@ -1,6 +1,7 @@ @@ -28,4 +29,4 @@ app:layout_constraintTop_toBottomOf="@id/appBarLayout" app:optimizeDisplay="true" /> - \ No newline at end of file + diff --git a/vector/src/main/res/layout/activity_bug_report.xml b/vector/src/main/res/layout/activity_bug_report.xml index 1c019c858d5..799ab2fb5f5 100644 --- a/vector/src/main/res/layout/activity_bug_report.xml +++ b/vector/src/main/res/layout/activity_bug_report.xml @@ -2,6 +2,7 @@ diff --git a/vector/src/main/res/layout/activity_call.xml b/vector/src/main/res/layout/activity_call.xml index 5734e5f92ab..02c90f8e547 100644 --- a/vector/src/main/res/layout/activity_call.xml +++ b/vector/src/main/res/layout/activity_call.xml @@ -97,7 +97,6 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@android:color/transparent" - android:fitsSystemWindows="true" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" diff --git a/vector/src/main/res/layout/activity_location_sharing.xml b/vector/src/main/res/layout/activity_location_sharing.xml index bbb46de8c76..9e44c72c831 100755 --- a/vector/src/main/res/layout/activity_location_sharing.xml +++ b/vector/src/main/res/layout/activity_location_sharing.xml @@ -1,5 +1,6 @@ @@ -21,4 +22,4 @@ android:layout_width="match_parent" android:layout_height="match_parent" /> - \ No newline at end of file + diff --git a/vector/src/main/res/layout/activity_main.xml b/vector/src/main/res/layout/activity_main.xml index ba5925f000d..626eb100d4f 100644 --- a/vector/src/main/res/layout/activity_main.xml +++ b/vector/src/main/res/layout/activity_main.xml @@ -3,6 +3,7 @@ diff --git a/vector/src/main/res/layout/activity_widget.xml b/vector/src/main/res/layout/activity_widget.xml index b278bb5a1aa..f1222d11df1 100755 --- a/vector/src/main/res/layout/activity_widget.xml +++ b/vector/src/main/res/layout/activity_widget.xml @@ -1,6 +1,7 @@ @@ -23,4 +24,4 @@ android:layout_width="match_parent" android:layout_height="match_parent" /> - \ No newline at end of file + diff --git a/vector/src/main/res/layout/fragment_generic_recycler.xml b/vector/src/main/res/layout/fragment_generic_recycler.xml index 472f05092e7..1c2eb2fc40f 100644 --- a/vector/src/main/res/layout/fragment_generic_recycler.xml +++ b/vector/src/main/res/layout/fragment_generic_recycler.xml @@ -2,6 +2,7 @@ diff --git a/vector/src/main/res/layout/fragment_new_home_detail.xml b/vector/src/main/res/layout/fragment_new_home_detail.xml index d20223a3823..32d1dfc5d21 100644 --- a/vector/src/main/res/layout/fragment_new_home_detail.xml +++ b/vector/src/main/res/layout/fragment_new_home_detail.xml @@ -45,7 +45,6 @@ android:id="@+id/appBarLayout" android:layout_width="match_parent" android:layout_height="wrap_content" - android:fitsSystemWindows="true" app:layout_constraintTop_toBottomOf="@id/syncStateView">