Merge branch 'develop' into feature/ons/qr_code_login_ui
# Conflicts: # library/ui-strings/src/main/res/values/strings.xml # matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/auth/AuthenticationService.kt # matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/auth/DefaultAuthenticationService.kt # matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/database/migration/MigrateSessionTo038.kt # vector-app/src/debug/java/im/vector/app/features/debug/features/DebugFeaturesStateFactory.kt # vector-app/src/debug/java/im/vector/app/features/debug/features/DebugVectorFeatures.kt # vector/src/main/java/im/vector/app/features/VectorFeatures.kt
This commit is contained in:
commit
5953346b3d
2
.github/ISSUE_TEMPLATE/enhancement.yml
vendored
2
.github/ISSUE_TEMPLATE/enhancement.yml
vendored
@ -5,7 +5,7 @@ body:
|
|||||||
- type: markdown
|
- type: markdown
|
||||||
attributes:
|
attributes:
|
||||||
value: |
|
value: |
|
||||||
Thank you for taking the time to propose a new feature or make a suggestion.
|
Thank you for taking the time to propose an enhancement to an existing feature. If you would like to propose a new feature or a major cross-platform change, please [start a discussion here](https://github.com/vector-im/element-meta/discussions/new?category=ideas).
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: usecase
|
id: usecase
|
||||||
attributes:
|
attributes:
|
||||||
|
@ -30,10 +30,10 @@ buildscript {
|
|||||||
classpath 'com.google.android.gms:oss-licenses-plugin:0.10.5'
|
classpath 'com.google.android.gms:oss-licenses-plugin:0.10.5'
|
||||||
classpath "com.likethesalad.android:stem-plugin:2.2.2"
|
classpath "com.likethesalad.android:stem-plugin:2.2.2"
|
||||||
classpath 'org.owasp:dependency-check-gradle:7.2.1'
|
classpath 'org.owasp:dependency-check-gradle:7.2.1'
|
||||||
classpath "org.jetbrains.dokka:dokka-gradle-plugin:1.7.10"
|
classpath "org.jetbrains.dokka:dokka-gradle-plugin:1.7.20"
|
||||||
classpath "org.jetbrains.kotlinx:kotlinx-knit:0.4.0"
|
classpath "org.jetbrains.kotlinx:kotlinx-knit:0.4.0"
|
||||||
classpath 'com.jakewharton:butterknife-gradle-plugin:10.2.3'
|
classpath 'com.jakewharton:butterknife-gradle-plugin:10.2.3'
|
||||||
classpath 'app.cash.paparazzi:paparazzi-gradle-plugin:1.0.0'
|
classpath 'app.cash.paparazzi:paparazzi-gradle-plugin:1.1.0'
|
||||||
// NOTE: Do not place your application dependencies here; they belong
|
// NOTE: Do not place your application dependencies here; they belong
|
||||||
// in the individual module build.gradle files
|
// in the individual module build.gradle files
|
||||||
}
|
}
|
||||||
|
1
changelog.d/5968.bugfix
Normal file
1
changelog.d/5968.bugfix
Normal file
@ -0,0 +1 @@
|
|||||||
|
Fix wrong mic button direction to cancel on RTL languages
|
1
changelog.d/7257.wip
Normal file
1
changelog.d/7257.wip
Normal file
@ -0,0 +1 @@
|
|||||||
|
[Device Management] Save "matrix_client_information" events on login/registration
|
1
changelog.d/7281.wip
Normal file
1
changelog.d/7281.wip
Normal file
@ -0,0 +1 @@
|
|||||||
|
Links "Enable Notifications for this session" setting to enabled value in pusher
|
1
changelog.d/7294.wip
Normal file
1
changelog.d/7294.wip
Normal file
@ -0,0 +1 @@
|
|||||||
|
[Device Management] Render extended device info
|
1
changelog.d/7300.wip
Normal file
1
changelog.d/7300.wip
Normal file
@ -0,0 +1 @@
|
|||||||
|
Implements client-side of local notification settings event
|
1
changelog.d/7321.wip
Normal file
1
changelog.d/7321.wip
Normal file
@ -0,0 +1 @@
|
|||||||
|
[Device management] Improve the parsing for OS of Desktop/Web sessions
|
1
changelog.d/7324.wip
Normal file
1
changelog.d/7324.wip
Normal file
@ -0,0 +1 @@
|
|||||||
|
[Device management] Hide the IP address and last activity date on current session
|
1
changelog.d/7335.misc
Normal file
1
changelog.d/7335.misc
Normal file
@ -0,0 +1 @@
|
|||||||
|
Dependency to arrow has been removed. Please use `org.matrix.android.sdk.api.util.Optional` instead.
|
1
changelog.d/7336.feature
Normal file
1
changelog.d/7336.feature
Normal file
@ -0,0 +1 @@
|
|||||||
|
[Device management] Add lab flag for the feature
|
1
changelog.d/7354.misc
Normal file
1
changelog.d/7354.misc
Normal file
@ -0,0 +1 @@
|
|||||||
|
Update WYSIWYG editor designs.
|
1
changelog.d/7358.sdk
Normal file
1
changelog.d/7358.sdk
Normal file
@ -0,0 +1 @@
|
|||||||
|
Add support for `m.login.token` auth during QR code based sign in
|
@ -1,8 +1,8 @@
|
|||||||
ext.versions = [
|
ext.versions = [
|
||||||
|
|
||||||
'minSdk' : 21,
|
'minSdk' : 21,
|
||||||
'compileSdk' : 32,
|
'compileSdk' : 33,
|
||||||
'targetSdk' : 32,
|
'targetSdk' : 33,
|
||||||
'sourceCompat' : JavaVersion.VERSION_11,
|
'sourceCompat' : JavaVersion.VERSION_11,
|
||||||
'targetCompat' : JavaVersion.VERSION_11,
|
'targetCompat' : JavaVersion.VERSION_11,
|
||||||
]
|
]
|
||||||
@ -14,12 +14,11 @@ def kotlinCoroutines = "1.6.4"
|
|||||||
def dagger = "2.44"
|
def dagger = "2.44"
|
||||||
def appDistribution = "16.0.0-beta04"
|
def appDistribution = "16.0.0-beta04"
|
||||||
def retrofit = "2.9.0"
|
def retrofit = "2.9.0"
|
||||||
def arrow = "0.8.2"
|
|
||||||
def markwon = "4.6.2"
|
def markwon = "4.6.2"
|
||||||
def moshi = "1.14.0"
|
def moshi = "1.14.0"
|
||||||
def lifecycle = "2.5.1"
|
def lifecycle = "2.5.1"
|
||||||
def flowBinding = "1.2.0"
|
def flowBinding = "1.2.0"
|
||||||
def flipper = "0.169.0"
|
def flipper = "0.170.0"
|
||||||
def epoxy = "5.0.0"
|
def epoxy = "5.0.0"
|
||||||
def mavericks = "3.0.1"
|
def mavericks = "3.0.1"
|
||||||
def glide = "4.14.2"
|
def glide = "4.14.2"
|
||||||
@ -51,10 +50,10 @@ ext.libs = [
|
|||||||
'coroutinesTest' : "org.jetbrains.kotlinx:kotlinx-coroutines-test:$kotlinCoroutines"
|
'coroutinesTest' : "org.jetbrains.kotlinx:kotlinx-coroutines-test:$kotlinCoroutines"
|
||||||
],
|
],
|
||||||
androidx : [
|
androidx : [
|
||||||
'activity' : "androidx.activity:activity:1.5.1",
|
'activity' : "androidx.activity:activity-ktx:1.6.0",
|
||||||
'appCompat' : "androidx.appcompat:appcompat:1.5.1",
|
'appCompat' : "androidx.appcompat:appcompat:1.5.1",
|
||||||
'biometric' : "androidx.biometric:biometric:1.1.0",
|
'biometric' : "androidx.biometric:biometric:1.1.0",
|
||||||
'core' : "androidx.core:core-ktx:1.8.0",
|
'core' : "androidx.core:core-ktx:1.9.0",
|
||||||
'recyclerview' : "androidx.recyclerview:recyclerview:1.2.1",
|
'recyclerview' : "androidx.recyclerview:recyclerview:1.2.1",
|
||||||
'exifinterface' : "androidx.exifinterface:exifinterface:1.3.4",
|
'exifinterface' : "androidx.exifinterface:exifinterface:1.3.4",
|
||||||
'fragmentKtx' : "androidx.fragment:fragment-ktx:$fragment",
|
'fragmentKtx' : "androidx.fragment:fragment-ktx:$fragment",
|
||||||
@ -115,10 +114,6 @@ ext.libs = [
|
|||||||
rx : [
|
rx : [
|
||||||
'rxKotlin' : "io.reactivex.rxjava2:rxkotlin:2.4.0"
|
'rxKotlin' : "io.reactivex.rxjava2:rxkotlin:2.4.0"
|
||||||
],
|
],
|
||||||
arrow : [
|
|
||||||
'core' : "io.arrow-kt:arrow-core:$arrow",
|
|
||||||
'instances' : "io.arrow-kt:arrow-instances-core:$arrow"
|
|
||||||
],
|
|
||||||
markwon : [
|
markwon : [
|
||||||
'core' : "io.noties.markwon:core:$markwon",
|
'core' : "io.noties.markwon:core:$markwon",
|
||||||
'extLatex' : "io.noties.markwon:ext-latex:$markwon",
|
'extLatex' : "io.noties.markwon:ext-latex:$markwon",
|
||||||
|
@ -134,7 +134,6 @@ ext.groups = [
|
|||||||
'commons-io',
|
'commons-io',
|
||||||
'commons-logging',
|
'commons-logging',
|
||||||
'info.picocli',
|
'info.picocli',
|
||||||
'io.arrow-kt',
|
|
||||||
'io.element.android',
|
'io.element.android',
|
||||||
'io.github.davidburstrom.contester',
|
'io.github.davidburstrom.contester',
|
||||||
'io.github.detekt.sarif4k',
|
'io.github.detekt.sarif4k',
|
||||||
|
@ -316,10 +316,6 @@ abstract class AttachmentViewerActivity : AppCompatActivity(), AttachmentEventLi
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDoubleTap(e: MotionEvent?): Boolean {
|
|
||||||
return super.onDoubleTap(e)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
override fun onEvent(event: AttachmentEvents) {
|
override fun onEvent(event: AttachmentEvents) {
|
||||||
|
@ -96,31 +96,27 @@ class SwipeToDismissHandler(
|
|||||||
.setDuration(ANIMATION_DURATION)
|
.setDuration(ANIMATION_DURATION)
|
||||||
.setInterpolator(AccelerateInterpolator())
|
.setInterpolator(AccelerateInterpolator())
|
||||||
.setUpdateListener { onSwipeViewMove(swipeView.translationY, translationLimit) }
|
.setUpdateListener { onSwipeViewMove(swipeView.translationY, translationLimit) }
|
||||||
.setAnimatorListener(onAnimationEnd = {
|
.setAnimatorEndListener {
|
||||||
if (translationTo != 0f) {
|
if (translationTo != 0f) {
|
||||||
onDismiss()
|
onDismiss()
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove the update listener, otherwise it will be saved on the next animation execution:
|
// remove the update listener, otherwise it will be saved on the next animation execution:
|
||||||
swipeView.animate().setUpdateListener(null)
|
swipeView.animate().setUpdateListener(null)
|
||||||
})
|
}
|
||||||
.start()
|
.start()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun ViewPropertyAnimator.setAnimatorListener(
|
private fun ViewPropertyAnimator.setAnimatorEndListener(
|
||||||
onAnimationEnd: ((Animator?) -> Unit)? = null,
|
onAnimationEnd: () -> Unit,
|
||||||
onAnimationStart: ((Animator?) -> Unit)? = null
|
) = setListener(
|
||||||
) = this.setListener(
|
|
||||||
object : AnimatorListenerAdapter() {
|
object : AnimatorListenerAdapter() {
|
||||||
override fun onAnimationEnd(animation: Animator?) {
|
override fun onAnimationEnd(animation: Animator) {
|
||||||
onAnimationEnd?.invoke(animation)
|
onAnimationEnd()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
override fun onAnimationStart(animation: Animator?) {
|
private val View.hitRect: Rect
|
||||||
onAnimationStart?.invoke(animation)
|
get() = Rect().also { getHitRect(it) }
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
internal val View?.hitRect: Rect
|
|
||||||
get() = Rect().also { this?.getHitRect(it) }
|
|
||||||
|
@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package im.vector.lib.core.utils.compat
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import android.content.pm.ResolveInfo
|
||||||
|
import android.os.Build
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.os.Parcelable
|
||||||
|
import java.io.Serializable
|
||||||
|
|
||||||
|
inline fun <reified T> Intent.getParcelableExtraCompat(key: String): T? = when {
|
||||||
|
Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU -> getParcelableExtra(key, T::class.java)
|
||||||
|
else -> @Suppress("DEPRECATION") getParcelableExtra(key) as? T?
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified T : Parcelable> Intent.getParcelableArrayListExtraCompat(key: String): ArrayList<T>? = when {
|
||||||
|
Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU -> getParcelableArrayListExtra(key, T::class.java)
|
||||||
|
else -> @Suppress("DEPRECATION") getParcelableArrayListExtra<T>(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified T> Bundle.getParcelableCompat(key: String): T? = when {
|
||||||
|
Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU -> getParcelable(key, T::class.java)
|
||||||
|
else -> @Suppress("DEPRECATION") getParcelable(key) as? T?
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified T : Serializable> Bundle.getSerializableCompat(key: String): T? = when {
|
||||||
|
Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU -> getSerializable(key, T::class.java)
|
||||||
|
else -> @Suppress("DEPRECATION") getSerializable(key) as? T?
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified T : Serializable> Intent.getSerializableExtraCompat(key: String): T? = when {
|
||||||
|
Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU -> getSerializableExtra(key, T::class.java)
|
||||||
|
else -> @Suppress("DEPRECATION") getSerializableExtra(key) as? T?
|
||||||
|
}
|
||||||
|
|
||||||
|
fun PackageManager.queryIntentActivitiesCompat(data: Intent, flags: Int): List<ResolveInfo> {
|
||||||
|
return when {
|
||||||
|
Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU -> queryIntentActivities(
|
||||||
|
data,
|
||||||
|
PackageManager.ResolveInfoFlags.of(flags.toLong())
|
||||||
|
)
|
||||||
|
else -> @Suppress("DEPRECATION") queryIntentActivities(data, flags)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun PackageManager.resolveActivityCompat(data: Intent, flags: Int): ResolveInfo? {
|
||||||
|
return when {
|
||||||
|
Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU -> resolveActivity(
|
||||||
|
data,
|
||||||
|
PackageManager.ResolveInfoFlags.of(flags.toLong())
|
||||||
|
)
|
||||||
|
else -> @Suppress("DEPRECATION") resolveActivity(data, flags)
|
||||||
|
}
|
||||||
|
}
|
@ -103,6 +103,7 @@ public class DialpadView extends LinearLayout {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onFinishInflate() {
|
protected void onFinishInflate() {
|
||||||
|
super.onFinishInflate();
|
||||||
setupKeypad();
|
setupKeypad();
|
||||||
mDigits = (EditText) findViewById(R.id.digits);
|
mDigits = (EditText) findViewById(R.id.digits);
|
||||||
mDelete = (ImageButton) findViewById(R.id.deleteButton);
|
mDelete = (ImageButton) findViewById(R.id.deleteButton);
|
||||||
@ -201,14 +202,6 @@ public class DialpadView extends LinearLayout {
|
|||||||
zero.setLongHoverContentDescription(resources.getText(R.string.description_image_button_plus));
|
zero.setLongHoverContentDescription(resources.getText(R.string.description_image_button_plus));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Drawable getDrawableCompat(Context context, int id) {
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
|
||||||
return context.getDrawable(id);
|
|
||||||
} else {
|
|
||||||
return context.getResources().getDrawable(id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setShowVoicemailButton(boolean show) {
|
public void setShowVoicemailButton(boolean show) {
|
||||||
View view = findViewById(R.id.dialpad_key_voicemail);
|
View view = findViewById(R.id.dialpad_key_voicemail);
|
||||||
if (view != null) {
|
if (view != null) {
|
||||||
|
@ -23,6 +23,7 @@ import android.view.ViewGroup
|
|||||||
import android.view.WindowManager
|
import android.view.WindowManager
|
||||||
import androidx.fragment.app.DialogFragment
|
import androidx.fragment.app.DialogFragment
|
||||||
import com.airbnb.mvrx.Mavericks
|
import com.airbnb.mvrx.Mavericks
|
||||||
|
import im.vector.lib.core.utils.compat.getParcelableCompat
|
||||||
|
|
||||||
class JSonViewerDialog : DialogFragment() {
|
class JSonViewerDialog : DialogFragment() {
|
||||||
|
|
||||||
@ -36,16 +37,17 @@ class JSonViewerDialog : DialogFragment() {
|
|||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
val args: JSonViewerFragmentArgs = arguments?.getParcelable(Mavericks.KEY_ARG) ?: return
|
val args: JSonViewerFragmentArgs = arguments?.getParcelableCompat(Mavericks.KEY_ARG) ?: return
|
||||||
if (savedInstanceState == null) {
|
if (savedInstanceState == null) {
|
||||||
childFragmentManager.beginTransaction()
|
childFragmentManager.beginTransaction()
|
||||||
.replace(
|
.replace(
|
||||||
R.id.fragmentContainer, JSonViewerFragment.newInstance(
|
R.id.fragmentContainer,
|
||||||
args.jsonString,
|
JSonViewerFragment.newInstance(
|
||||||
args.defaultOpenDepth,
|
args.jsonString,
|
||||||
true,
|
args.defaultOpenDepth,
|
||||||
args.styleProvider
|
true,
|
||||||
)
|
args.styleProvider
|
||||||
|
)
|
||||||
)
|
)
|
||||||
.commitNow()
|
.commitNow()
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,7 @@ import com.airbnb.mvrx.Mavericks
|
|||||||
import com.airbnb.mvrx.MavericksView
|
import com.airbnb.mvrx.MavericksView
|
||||||
import com.airbnb.mvrx.fragmentViewModel
|
import com.airbnb.mvrx.fragmentViewModel
|
||||||
import com.airbnb.mvrx.withState
|
import com.airbnb.mvrx.withState
|
||||||
|
import im.vector.lib.core.utils.compat.getParcelableCompat
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
@Parcelize
|
@Parcelize
|
||||||
@ -53,7 +54,7 @@ class JSonViewerFragment : Fragment(), MavericksView {
|
|||||||
container: ViewGroup?,
|
container: ViewGroup?,
|
||||||
savedInstanceState: Bundle?
|
savedInstanceState: Bundle?
|
||||||
): View? {
|
): View? {
|
||||||
val args: JSonViewerFragmentArgs? = arguments?.getParcelable(Mavericks.KEY_ARG)
|
val args: JSonViewerFragmentArgs? = arguments?.getParcelableCompat(Mavericks.KEY_ARG)
|
||||||
val inflate =
|
val inflate =
|
||||||
if (args?.wrap == true) {
|
if (args?.wrap == true) {
|
||||||
inflater.inflate(R.layout.fragment_jv_recycler_view_wrap, container, false)
|
inflater.inflate(R.layout.fragment_jv_recycler_view_wrap, container, false)
|
||||||
|
@ -35,9 +35,19 @@ android {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
compileOptions {
|
||||||
|
sourceCompatibility versions.sourceCompat
|
||||||
|
targetCompatibility versions.targetCompat
|
||||||
|
}
|
||||||
|
|
||||||
|
kotlinOptions {
|
||||||
|
jvmTarget = "11"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
implementation project(":library:core-utils")
|
||||||
|
|
||||||
api libs.androidx.activity
|
api libs.androidx.activity
|
||||||
implementation libs.androidx.exifinterface
|
implementation libs.androidx.exifinterface
|
||||||
implementation libs.androidx.core
|
implementation libs.androidx.core
|
||||||
|
@ -22,6 +22,9 @@ import android.content.pm.PackageManager
|
|||||||
import android.content.pm.ResolveInfo
|
import android.content.pm.ResolveInfo
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import androidx.activity.result.ActivityResultLauncher
|
import androidx.activity.result.ActivityResultLauncher
|
||||||
|
import im.vector.lib.core.utils.compat.getParcelableArrayListExtraCompat
|
||||||
|
import im.vector.lib.core.utils.compat.getParcelableExtraCompat
|
||||||
|
import im.vector.lib.core.utils.compat.queryIntentActivitiesCompat
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Abstract class to provide all types of Pickers.
|
* Abstract class to provide all types of Pickers.
|
||||||
@ -45,13 +48,13 @@ abstract class Picker<T> {
|
|||||||
|
|
||||||
val uriList = mutableListOf<Uri>()
|
val uriList = mutableListOf<Uri>()
|
||||||
if (data.action == Intent.ACTION_SEND) {
|
if (data.action == Intent.ACTION_SEND) {
|
||||||
(data.getParcelableExtra(Intent.EXTRA_STREAM) as? Uri)?.let { uriList.add(it) }
|
data.getParcelableExtraCompat<Uri>(Intent.EXTRA_STREAM)?.let { uriList.add(it) }
|
||||||
} else if (data.action == Intent.ACTION_SEND_MULTIPLE) {
|
} else if (data.action == Intent.ACTION_SEND_MULTIPLE) {
|
||||||
val extraUriList: List<Uri>? = data.getParcelableArrayListExtra(Intent.EXTRA_STREAM)
|
val extraUriList: List<Uri>? = data.getParcelableArrayListExtraCompat(Intent.EXTRA_STREAM)
|
||||||
extraUriList?.let { uriList.addAll(it) }
|
extraUriList?.let { uriList.addAll(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
val resInfoList: List<ResolveInfo> = context.packageManager.queryIntentActivities(data, PackageManager.MATCH_DEFAULT_ONLY)
|
val resInfoList: List<ResolveInfo> = context.packageManager.queryIntentActivitiesCompat(data, PackageManager.MATCH_DEFAULT_ONLY)
|
||||||
uriList.forEach {
|
uriList.forEach {
|
||||||
for (resolveInfo in resInfoList) {
|
for (resolveInfo in resInfoList) {
|
||||||
val packageName: String = resolveInfo.activityInfo.packageName
|
val packageName: String = resolveInfo.activityInfo.packageName
|
||||||
@ -91,6 +94,7 @@ abstract class Picker<T> {
|
|||||||
} else if (dataUri != null) {
|
} else if (dataUri != null) {
|
||||||
selectedUriList.add(dataUri)
|
selectedUriList.add(dataUri)
|
||||||
} else {
|
} else {
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
data?.extras?.get(Intent.EXTRA_STREAM)?.let {
|
data?.extras?.get(Intent.EXTRA_STREAM)?.let {
|
||||||
(it as? List<*>)?.filterIsInstance<Uri>()?.let { uriList ->
|
(it as? List<*>)?.filterIsInstance<Uri>()?.let { uriList ->
|
||||||
selectedUriList.addAll(uriList)
|
selectedUriList.addAll(uriList)
|
||||||
|
@ -447,7 +447,7 @@
|
|||||||
<string name="labs_enable_deferred_dm_summary">Create DM only on first message</string>
|
<string name="labs_enable_deferred_dm_summary">Create DM only on first message</string>
|
||||||
|
|
||||||
<string name="labs_enable_rich_text_editor_title">Enable rich text editor</string>
|
<string name="labs_enable_rich_text_editor_title">Enable rich text editor</string>
|
||||||
<string name="labs_enable_rich_text_editor_summary">Use a rich text editor to send formatted messages</string>
|
<string name="labs_enable_rich_text_editor_summary">Try out the rich text editor (plain text mode coming soon)</string>
|
||||||
|
|
||||||
<!-- Home fragment -->
|
<!-- Home fragment -->
|
||||||
<string name="invitations_header">Invites</string>
|
<string name="invitations_header">Invites</string>
|
||||||
@ -638,6 +638,8 @@
|
|||||||
<string name="permissions_rationale_msg_record_audio">${app_name} needs permission to access your microphone to perform audio calls.</string>
|
<string name="permissions_rationale_msg_record_audio">${app_name} needs permission to access your microphone to perform audio calls.</string>
|
||||||
<!-- Note to translators: the translation MUST contain the string "${app_name}", which will be replaced by the application name -->
|
<!-- Note to translators: the translation MUST contain the string "${app_name}", which will be replaced by the application name -->
|
||||||
<string name="permissions_rationale_msg_camera_and_audio">${app_name} needs permission to access your camera and your microphone to perform video calls.\n\nPlease allow access on the next pop-ups to be able to make the call.</string>
|
<string name="permissions_rationale_msg_camera_and_audio">${app_name} needs permission to access your camera and your microphone to perform video calls.\n\nPlease allow access on the next pop-ups to be able to make the call.</string>
|
||||||
|
<!-- Note to translators: the translation MUST contain the string "${app_name}", which will be replaced by the application name -->
|
||||||
|
<string name="permissions_rationale_msg_notification">${app_name} needs permission to display notifications. Notifications can display your messages, your invitations, etc.\n\nPlease allow access on the next pop-ups to be able to view notification.</string>
|
||||||
|
|
||||||
<string name="permissions_denied_qr_code">To scan a QR code, you need to allow camera access.</string>
|
<string name="permissions_denied_qr_code">To scan a QR code, you need to allow camera access.</string>
|
||||||
<string name="permissions_denied_add_contact">Allow permission to access your contacts.</string>
|
<string name="permissions_denied_add_contact">Allow permission to access your contacts.</string>
|
||||||
@ -857,7 +859,9 @@
|
|||||||
<string name="settings_troubleshoot_test_system_settings_title">System Settings.</string>
|
<string name="settings_troubleshoot_test_system_settings_title">System Settings.</string>
|
||||||
<string name="settings_troubleshoot_test_system_settings_success">Notifications are enabled in the system settings.</string>
|
<string name="settings_troubleshoot_test_system_settings_success">Notifications are enabled in the system settings.</string>
|
||||||
<string name="settings_troubleshoot_test_system_settings_failed">Notifications are disabled in the system settings.\nPlease check system settings.</string>
|
<string name="settings_troubleshoot_test_system_settings_failed">Notifications are disabled in the system settings.\nPlease check system settings.</string>
|
||||||
|
<string name="settings_troubleshoot_test_system_settings_permission_failed">${app_name} needs the permission to show notifications.\nPlease grant the permission.</string>
|
||||||
<string name="open_settings">Open Settings</string>
|
<string name="open_settings">Open Settings</string>
|
||||||
|
<string name="grant_permission">Grant Permission</string>
|
||||||
|
|
||||||
<string name="settings_troubleshoot_test_account_settings_title">Account Settings.</string>
|
<string name="settings_troubleshoot_test_account_settings_title">Account Settings.</string>
|
||||||
<string name="settings_troubleshoot_test_account_settings_success">Notifications are enabled for your account.</string>
|
<string name="settings_troubleshoot_test_account_settings_success">Notifications are enabled for your account.</string>
|
||||||
@ -1666,6 +1670,7 @@
|
|||||||
<string name="create_new_room">Create New Room</string>
|
<string name="create_new_room">Create New Room</string>
|
||||||
<string name="create_new_space">Create New Space</string>
|
<string name="create_new_space">Create New Space</string>
|
||||||
<string name="error_no_network">No network. Please check your Internet connection.</string>
|
<string name="error_no_network">No network. Please check your Internet connection.</string>
|
||||||
|
<string name="error_check_network">Something went wrong. Please check your network connection and try again.</string>
|
||||||
<string name="change_room_directory_network">"Change network"</string>
|
<string name="change_room_directory_network">"Change network"</string>
|
||||||
<string name="please_wait">"Please wait…"</string>
|
<string name="please_wait">"Please wait…"</string>
|
||||||
<string name="updating_your_data">Updating your data…</string>
|
<string name="updating_your_data">Updating your data…</string>
|
||||||
@ -3240,7 +3245,8 @@
|
|||||||
<string name="labs_enable_element_call_permission_shortcuts_summary">Auto-approve Element Call widgets and grant camera / mic access</string>
|
<string name="labs_enable_element_call_permission_shortcuts_summary">Auto-approve Element Call widgets and grant camera / mic access</string>
|
||||||
|
|
||||||
<!-- Device Manager -->
|
<!-- Device Manager -->
|
||||||
<string name="device_manager_settings_active_sessions_show_all">Show All Sessions (V2, WIP)</string>
|
<!-- TODO remove this key -->
|
||||||
|
<string name="device_manager_settings_active_sessions_show_all" tools:ignore="UnusedResources">Show All Sessions (V2, WIP)</string>
|
||||||
<string name="device_manager_sessions_other_title">Other sessions</string>
|
<string name="device_manager_sessions_other_title">Other sessions</string>
|
||||||
<string name="device_manager_sessions_other_description">For best security, verify your sessions and sign out from any session that you don’t recognize or use anymore.</string>
|
<string name="device_manager_sessions_other_description">For best security, verify your sessions and sign out from any session that you don’t recognize or use anymore.</string>
|
||||||
<string name="a11y_device_manager_device_type_mobile">Mobile</string>
|
<string name="a11y_device_manager_device_type_mobile">Mobile</string>
|
||||||
@ -3313,6 +3319,13 @@
|
|||||||
<string name="device_manager_session_details_session_name">Session name</string>
|
<string name="device_manager_session_details_session_name">Session name</string>
|
||||||
<string name="device_manager_session_details_session_id">Session ID</string>
|
<string name="device_manager_session_details_session_id">Session ID</string>
|
||||||
<string name="device_manager_session_details_session_last_activity">Last activity</string>
|
<string name="device_manager_session_details_session_last_activity">Last activity</string>
|
||||||
|
<string name="device_manager_session_details_application">Application</string>
|
||||||
|
<string name="device_manager_session_details_application_name">Name</string>
|
||||||
|
<string name="device_manager_session_details_application_version">Version</string>
|
||||||
|
<string name="device_manager_session_details_application_url">URL</string>
|
||||||
|
<string name="device_manager_session_details_device_browser">Browser</string>
|
||||||
|
<string name="device_manager_session_details_device_model">Model</string>
|
||||||
|
<string name="device_manager_session_details_device_operating_system">Operating system</string>
|
||||||
<string name="device_manager_session_details_device_ip_address">IP address</string>
|
<string name="device_manager_session_details_device_ip_address">IP address</string>
|
||||||
<string name="device_manager_session_rename">Rename session</string>
|
<string name="device_manager_session_rename">Rename session</string>
|
||||||
<string name="device_manager_session_rename_edit_hint">Session name</string>
|
<string name="device_manager_session_rename_edit_hint">Session name</string>
|
||||||
@ -3329,6 +3342,8 @@
|
|||||||
<string name="device_manager_learn_more_sessions_verified">Verified sessions have logged in with your credentials and then been verified, either using your secure passphrase or by cross-verifying.\n\nThis means they hold encryption keys for your previous messages, and confirm to other users you are communicating with that these sessions are really you.</string>
|
<string name="device_manager_learn_more_sessions_verified">Verified sessions have logged in with your credentials and then been verified, either using your secure passphrase or by cross-verifying.\n\nThis means they hold encryption keys for your previous messages, and confirm to other users you are communicating with that these sessions are really you.</string>
|
||||||
<string name="device_manager_learn_more_session_rename_title">Renaming sessions</string>
|
<string name="device_manager_learn_more_session_rename_title">Renaming sessions</string>
|
||||||
<string name="device_manager_learn_more_session_rename">Other users in direct messages and rooms that you join are able to view a full list of your sessions.\n\nThis provides them with confidence that they are really speaking to you, but it also means they can see the session name you enter here.</string>
|
<string name="device_manager_learn_more_session_rename">Other users in direct messages and rooms that you join are able to view a full list of your sessions.\n\nThis provides them with confidence that they are really speaking to you, but it also means they can see the session name you enter here.</string>
|
||||||
|
<string name="labs_enable_session_manager_title">Enable new session manager</string>
|
||||||
|
<string name="labs_enable_session_manager_summary">Have greater visibility and control over all your sessions.</string>
|
||||||
|
|
||||||
<!-- Note to translators: %s will be replaces with selected space name -->
|
<!-- Note to translators: %s will be replaces with selected space name -->
|
||||||
<string name="home_empty_space_no_rooms_title">%s\nis looking a little empty.</string>
|
<string name="home_empty_space_no_rooms_title">%s\nis looking a little empty.</string>
|
||||||
@ -3385,4 +3400,10 @@
|
|||||||
<string name="qr_code_login_confirm_security_code">Confirm</string>
|
<string name="qr_code_login_confirm_security_code">Confirm</string>
|
||||||
<string name="qr_code_login_confirm_security_code_description">Please ensure that you know the origin of this code. By linking devices, you will provide someone with full access to your account.</string>
|
<string name="qr_code_login_confirm_security_code_description">Please ensure that you know the origin of this code. By linking devices, you will provide someone with full access to your account.</string>
|
||||||
|
|
||||||
|
<!-- WYSIWYG Composer -->
|
||||||
|
<string name="rich_text_editor_format_bold">Apply bold format</string>
|
||||||
|
<string name="rich_text_editor_format_italic">Apply italic format</string>
|
||||||
|
<string name="rich_text_editor_format_strikethrough">Apply strikethrough format</string>
|
||||||
|
<string name="rich_text_editor_format_underline">Apply underline format</string>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -152,4 +152,9 @@
|
|||||||
<color name="vctr_badge_color_border_light">@color/palette_white</color>
|
<color name="vctr_badge_color_border_light">@color/palette_white</color>
|
||||||
<color name="vctr_badge_color_border_dark">@color/palette_black_950</color>
|
<color name="vctr_badge_color_border_dark">@color/palette_black_950</color>
|
||||||
|
|
||||||
|
<!-- WYSIWYG Colors -->
|
||||||
|
<attr name="vctr_rich_text_editor_menu_button_background" format="color" />
|
||||||
|
<color name="vctr_rich_text_editor_menu_button_background_light">#EEF8F4</color>
|
||||||
|
<color name="vctr_rich_text_editor_menu_button_background_dark">#1D292A</color>
|
||||||
|
|
||||||
</resources>
|
</resources>
|
||||||
|
@ -47,7 +47,8 @@
|
|||||||
<dimen name="composer_min_height">56dp</dimen>
|
<dimen name="composer_min_height">56dp</dimen>
|
||||||
<dimen name="composer_attachment_size">52dp</dimen>
|
<dimen name="composer_attachment_size">52dp</dimen>
|
||||||
<dimen name="composer_attachment_margin">1dp</dimen>
|
<dimen name="composer_attachment_margin">1dp</dimen>
|
||||||
|
<dimen name="rich_text_composer_corner_radius_single_line">28dp</dimen>
|
||||||
|
<dimen name="rich_text_composer_corner_radius_expanded">14dp</dimen>
|
||||||
|
|
||||||
<dimen name="chat_bubble_margin_start">28dp</dimen>
|
<dimen name="chat_bubble_margin_start">28dp</dimen>
|
||||||
<dimen name="chat_bubble_margin_end">6dp</dimen>
|
<dimen name="chat_bubble_margin_end">6dp</dimen>
|
||||||
|
@ -11,4 +11,14 @@
|
|||||||
<item name="android:textColor">?vctr_message_text_color</item>
|
<item name="android:textColor">?vctr_message_text_color</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
</resources>
|
<style name="Widget.Vector.EditText.RichTextComposer" parent="Widget.AppCompat.EditText">
|
||||||
|
<item name="android:background">@android:color/transparent</item>
|
||||||
|
<item name="android:inputType">textCapSentences|textMultiLine</item>
|
||||||
|
<item name="android:maxLines">12</item>
|
||||||
|
<item name="android:minHeight">20dp</item>
|
||||||
|
<item name="android:padding">0dp</item>
|
||||||
|
<item name="android:textSize">15sp</item>
|
||||||
|
<item name="android:textColor">?vctr_message_text_color</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
</resources>
|
||||||
|
@ -152,6 +152,9 @@
|
|||||||
|
|
||||||
<!-- Material 3 -->
|
<!-- Material 3 -->
|
||||||
<item name="collapsingToolbarLayoutMediumSize">@dimen/collapsing_toolbar_layout_medium_size</item>
|
<item name="collapsingToolbarLayoutMediumSize">@dimen/collapsing_toolbar_layout_medium_size</item>
|
||||||
|
|
||||||
|
<!-- WYSIWYG Editor -->
|
||||||
|
<item name="vctr_rich_text_editor_menu_button_background">@color/vctr_rich_text_editor_menu_button_background_dark</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="Theme.Vector.Dark" parent="Base.Theme.Vector.Dark" />
|
<style name="Theme.Vector.Dark" parent="Base.Theme.Vector.Dark" />
|
||||||
|
@ -153,6 +153,9 @@
|
|||||||
|
|
||||||
<!-- Material 3 -->
|
<!-- Material 3 -->
|
||||||
<item name="collapsingToolbarLayoutMediumSize">@dimen/collapsing_toolbar_layout_medium_size</item>
|
<item name="collapsingToolbarLayoutMediumSize">@dimen/collapsing_toolbar_layout_medium_size</item>
|
||||||
|
|
||||||
|
<!-- WYSIWYG Editor -->
|
||||||
|
<item name="vctr_rich_text_editor_menu_button_background">@color/vctr_rich_text_editor_menu_button_background_light</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="Theme.Vector.Light" parent="Base.Theme.Vector.Light" />
|
<style name="Theme.Vector.Light" parent="Base.Theme.Vector.Light" />
|
||||||
|
@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.matrix.android.sdk.api.account
|
||||||
|
|
||||||
|
import com.squareup.moshi.Json
|
||||||
|
import com.squareup.moshi.JsonClass
|
||||||
|
|
||||||
|
@JsonClass(generateAdapter = true)
|
||||||
|
data class LocalNotificationSettingsContent(
|
||||||
|
@Json(name = "is_silenced") val isSilenced: Boolean = false
|
||||||
|
)
|
@ -130,4 +130,18 @@ interface AuthenticationService {
|
|||||||
* Return true if qr code login is supported by the server, false otherwise.
|
* Return true if qr code login is supported by the server, false otherwise.
|
||||||
*/
|
*/
|
||||||
suspend fun isQrLoginSupported(homeServerConnectionConfig: HomeServerConnectionConfig): Boolean
|
suspend fun isQrLoginSupported(homeServerConnectionConfig: HomeServerConnectionConfig): Boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Authenticate using m.login.token method during sign in with QR code.
|
||||||
|
* @param homeServerConnectionConfig the information about the homeserver and other configuration
|
||||||
|
* @param loginToken the m.login.token
|
||||||
|
* @param initialDeviceName the initial device name
|
||||||
|
* @param deviceId the device id, optional. If not provided or null, the server will generate one.
|
||||||
|
*/
|
||||||
|
suspend fun loginUsingQrLoginToken(
|
||||||
|
homeServerConnectionConfig: HomeServerConnectionConfig,
|
||||||
|
loginToken: String,
|
||||||
|
initialDeviceName: String? = null,
|
||||||
|
deviceId: String? = null
|
||||||
|
): Session
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,8 @@ enum class LoginType {
|
|||||||
UNSUPPORTED,
|
UNSUPPORTED,
|
||||||
CUSTOM,
|
CUSTOM,
|
||||||
DIRECT,
|
DIRECT,
|
||||||
UNKNOWN;
|
UNKNOWN,
|
||||||
|
QR;
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
@ -32,6 +33,7 @@ enum class LoginType {
|
|||||||
UNSUPPORTED.name -> UNSUPPORTED
|
UNSUPPORTED.name -> UNSUPPORTED
|
||||||
CUSTOM.name -> CUSTOM
|
CUSTOM.name -> CUSTOM
|
||||||
DIRECT.name -> DIRECT
|
DIRECT.name -> DIRECT
|
||||||
|
QR.name -> QR
|
||||||
else -> UNKNOWN
|
else -> UNKNOWN
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,4 +28,5 @@ object UserAccountDataTypes {
|
|||||||
const val TYPE_IDENTITY_SERVER = "m.identity_server"
|
const val TYPE_IDENTITY_SERVER = "m.identity_server"
|
||||||
const val TYPE_ACCEPTED_TERMS = "m.accepted_terms"
|
const val TYPE_ACCEPTED_TERMS = "m.accepted_terms"
|
||||||
const val TYPE_OVERRIDE_COLORS = "im.vector.setting.override_colors"
|
const val TYPE_OVERRIDE_COLORS = "im.vector.setting.override_colors"
|
||||||
|
const val TYPE_LOCAL_NOTIFICATION_SETTINGS = "org.matrix.msc3890.local_notification_settings."
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022 The Matrix.org Foundation C.I.C.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.matrix.android.sdk.api.util
|
||||||
|
|
||||||
|
import android.content.pm.ApplicationInfo
|
||||||
|
import android.content.pm.PackageInfo
|
||||||
|
import android.content.pm.PackageManager
|
||||||
|
import android.os.Build
|
||||||
|
|
||||||
|
fun PackageManager.getApplicationInfoCompat(packageName: String, flags: Int): ApplicationInfo {
|
||||||
|
return when {
|
||||||
|
Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU -> getApplicationInfo(
|
||||||
|
packageName,
|
||||||
|
PackageManager.ApplicationInfoFlags.of(flags.toLong())
|
||||||
|
)
|
||||||
|
else -> @Suppress("DEPRECATION") getApplicationInfo(packageName, flags)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun PackageManager.getPackageInfoCompat(packageName: String, flags: Int): PackageInfo {
|
||||||
|
return when {
|
||||||
|
Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU -> getPackageInfo(
|
||||||
|
packageName,
|
||||||
|
PackageManager.PackageInfoFlags.of(flags.toLong())
|
||||||
|
)
|
||||||
|
else -> @Suppress("DEPRECATION") getPackageInfo(packageName, flags)
|
||||||
|
}
|
||||||
|
}
|
@ -15,15 +15,13 @@
|
|||||||
*/
|
*/
|
||||||
package org.matrix.android.sdk.api.util
|
package org.matrix.android.sdk.api.util
|
||||||
|
|
||||||
data class Optional<T : Any> constructor(private val value: T?) {
|
data class Optional<T : Any>(private val value: T?) {
|
||||||
|
|
||||||
fun get(): T {
|
fun get(): T = value!!
|
||||||
return value!!
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getOrNull(): T? {
|
fun orNull(): T? = value
|
||||||
return value
|
|
||||||
}
|
fun getOrNull(): T? = value
|
||||||
|
|
||||||
fun <U : Any> map(fn: (T) -> U?): Optional<U> {
|
fun <U : Any> map(fn: (T) -> U?): Optional<U> {
|
||||||
return if (value == null) {
|
return if (value == null) {
|
||||||
@ -33,23 +31,19 @@ data class Optional<T : Any> constructor(private val value: T?) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getOrElse(fn: () -> T): T {
|
fun orElse(fn: () -> T): T {
|
||||||
return value ?: fn()
|
return value ?: fn()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun hasValue(): Boolean {
|
fun hasValue(): Boolean = value != null
|
||||||
return value != null
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun <T : Any> from(value: T?): Optional<T> {
|
fun <T : Any> from(value: T?): Optional<T> = Optional(value)
|
||||||
return Optional(value)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <T : Any> empty(): Optional<T> {
|
fun <T : Any> empty(): Optional<T> = Optional(null)
|
||||||
return Optional(null)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun <T : Any> T?.toOption() = Optional(this)
|
||||||
|
|
||||||
fun <T : Any> T?.toOptional() = Optional(this)
|
fun <T : Any> T?.toOptional() = Optional(this)
|
||||||
|
@ -29,7 +29,9 @@ import org.matrix.android.sdk.internal.auth.db.AuthRealmModule
|
|||||||
import org.matrix.android.sdk.internal.auth.db.RealmPendingSessionStore
|
import org.matrix.android.sdk.internal.auth.db.RealmPendingSessionStore
|
||||||
import org.matrix.android.sdk.internal.auth.db.RealmSessionParamsStore
|
import org.matrix.android.sdk.internal.auth.db.RealmSessionParamsStore
|
||||||
import org.matrix.android.sdk.internal.auth.login.DefaultDirectLoginTask
|
import org.matrix.android.sdk.internal.auth.login.DefaultDirectLoginTask
|
||||||
|
import org.matrix.android.sdk.internal.auth.login.DefaultQrLoginTokenTask
|
||||||
import org.matrix.android.sdk.internal.auth.login.DirectLoginTask
|
import org.matrix.android.sdk.internal.auth.login.DirectLoginTask
|
||||||
|
import org.matrix.android.sdk.internal.auth.login.QrLoginTokenTask
|
||||||
import org.matrix.android.sdk.internal.database.RealmKeysUtils
|
import org.matrix.android.sdk.internal.database.RealmKeysUtils
|
||||||
import org.matrix.android.sdk.internal.di.AuthDatabase
|
import org.matrix.android.sdk.internal.di.AuthDatabase
|
||||||
import org.matrix.android.sdk.internal.legacy.DefaultLegacySessionImporter
|
import org.matrix.android.sdk.internal.legacy.DefaultLegacySessionImporter
|
||||||
@ -94,4 +96,7 @@ internal abstract class AuthModule {
|
|||||||
|
|
||||||
@Binds
|
@Binds
|
||||||
abstract fun bindHomeServerHistoryService(service: DefaultHomeServerHistoryService): HomeServerHistoryService
|
abstract fun bindHomeServerHistoryService(service: DefaultHomeServerHistoryService): HomeServerHistoryService
|
||||||
|
|
||||||
|
@Binds
|
||||||
|
abstract fun bindQrLoginTokenTask(task: DefaultQrLoginTokenTask): QrLoginTokenTask
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,7 @@ import org.matrix.android.sdk.internal.auth.data.WebClientConfig
|
|||||||
import org.matrix.android.sdk.internal.auth.db.PendingSessionData
|
import org.matrix.android.sdk.internal.auth.db.PendingSessionData
|
||||||
import org.matrix.android.sdk.internal.auth.login.DefaultLoginWizard
|
import org.matrix.android.sdk.internal.auth.login.DefaultLoginWizard
|
||||||
import org.matrix.android.sdk.internal.auth.login.DirectLoginTask
|
import org.matrix.android.sdk.internal.auth.login.DirectLoginTask
|
||||||
|
import org.matrix.android.sdk.internal.auth.login.QrLoginTokenTask
|
||||||
import org.matrix.android.sdk.internal.auth.registration.DefaultRegistrationWizard
|
import org.matrix.android.sdk.internal.auth.registration.DefaultRegistrationWizard
|
||||||
import org.matrix.android.sdk.internal.auth.version.Versions
|
import org.matrix.android.sdk.internal.auth.version.Versions
|
||||||
import org.matrix.android.sdk.internal.auth.version.doesServerSupportLogoutDevices
|
import org.matrix.android.sdk.internal.auth.version.doesServerSupportLogoutDevices
|
||||||
@ -64,7 +65,8 @@ internal class DefaultAuthenticationService @Inject constructor(
|
|||||||
private val sessionCreator: SessionCreator,
|
private val sessionCreator: SessionCreator,
|
||||||
private val pendingSessionStore: PendingSessionStore,
|
private val pendingSessionStore: PendingSessionStore,
|
||||||
private val getWellknownTask: GetWellknownTask,
|
private val getWellknownTask: GetWellknownTask,
|
||||||
private val directLoginTask: DirectLoginTask
|
private val directLoginTask: DirectLoginTask,
|
||||||
|
private val qrLoginTokenTask: QrLoginTokenTask
|
||||||
) : AuthenticationService {
|
) : AuthenticationService {
|
||||||
|
|
||||||
private var pendingSessionData: PendingSessionData? = pendingSessionStore.getPendingSessionData()
|
private var pendingSessionData: PendingSessionData? = pendingSessionStore.getPendingSessionData()
|
||||||
@ -420,6 +422,22 @@ internal class DefaultAuthenticationService @Inject constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun loginUsingQrLoginToken(
|
||||||
|
homeServerConnectionConfig: HomeServerConnectionConfig,
|
||||||
|
loginToken: String,
|
||||||
|
initialDeviceName: String?,
|
||||||
|
deviceId: String?,
|
||||||
|
): Session {
|
||||||
|
return qrLoginTokenTask.execute(
|
||||||
|
QrLoginTokenTask.Params(
|
||||||
|
homeServerConnectionConfig = homeServerConnectionConfig,
|
||||||
|
loginToken = loginToken,
|
||||||
|
deviceName = initialDeviceName,
|
||||||
|
deviceId = deviceId
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private fun buildAuthAPI(homeServerConnectionConfig: HomeServerConnectionConfig): AuthAPI {
|
private fun buildAuthAPI(homeServerConnectionConfig: HomeServerConnectionConfig): AuthAPI {
|
||||||
val retrofit = retrofitFactory.create(buildClient(homeServerConnectionConfig), homeServerConnectionConfig.homeServerUriBase.toString())
|
val retrofit = retrofitFactory.create(buildClient(homeServerConnectionConfig), homeServerConnectionConfig.homeServerUriBase.toString())
|
||||||
return retrofit.create(AuthAPI::class.java)
|
return retrofit.create(AuthAPI::class.java)
|
||||||
|
@ -18,4 +18,6 @@ package org.matrix.android.sdk.internal.auth.data
|
|||||||
|
|
||||||
internal interface LoginParams {
|
internal interface LoginParams {
|
||||||
val type: String
|
val type: String
|
||||||
|
val deviceDisplayName: String?
|
||||||
|
val deviceId: String?
|
||||||
}
|
}
|
||||||
|
@ -30,8 +30,8 @@ internal data class PasswordLoginParams(
|
|||||||
@Json(name = "identifier") val identifier: Map<String, String>,
|
@Json(name = "identifier") val identifier: Map<String, String>,
|
||||||
@Json(name = "password") val password: String,
|
@Json(name = "password") val password: String,
|
||||||
@Json(name = "type") override val type: String,
|
@Json(name = "type") override val type: String,
|
||||||
@Json(name = "initial_device_display_name") val deviceDisplayName: String?,
|
@Json(name = "initial_device_display_name") override val deviceDisplayName: String?,
|
||||||
@Json(name = "device_id") val deviceId: String?
|
@Json(name = "device_id") override val deviceId: String?
|
||||||
) : LoginParams {
|
) : LoginParams {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -23,5 +23,7 @@ import org.matrix.android.sdk.api.auth.data.LoginFlowTypes
|
|||||||
@JsonClass(generateAdapter = true)
|
@JsonClass(generateAdapter = true)
|
||||||
internal data class TokenLoginParams(
|
internal data class TokenLoginParams(
|
||||||
@Json(name = "type") override val type: String = LoginFlowTypes.TOKEN,
|
@Json(name = "type") override val type: String = LoginFlowTypes.TOKEN,
|
||||||
@Json(name = "token") val token: String
|
@Json(name = "token") val token: String,
|
||||||
|
@Json(name = "initial_device_display_name") override val deviceDisplayName: String? = null,
|
||||||
|
@Json(name = "device_id") override val deviceId: String? = null
|
||||||
) : LoginParams
|
) : LoginParams
|
||||||
|
@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.matrix.android.sdk.internal.auth.login
|
||||||
|
|
||||||
|
import dagger.Lazy
|
||||||
|
import okhttp3.OkHttpClient
|
||||||
|
import org.matrix.android.sdk.api.auth.LoginType
|
||||||
|
import org.matrix.android.sdk.api.auth.data.HomeServerConnectionConfig
|
||||||
|
import org.matrix.android.sdk.api.failure.Failure
|
||||||
|
import org.matrix.android.sdk.api.session.Session
|
||||||
|
import org.matrix.android.sdk.internal.auth.AuthAPI
|
||||||
|
import org.matrix.android.sdk.internal.auth.SessionCreator
|
||||||
|
import org.matrix.android.sdk.internal.auth.data.TokenLoginParams
|
||||||
|
import org.matrix.android.sdk.internal.di.Unauthenticated
|
||||||
|
import org.matrix.android.sdk.internal.network.RetrofitFactory
|
||||||
|
import org.matrix.android.sdk.internal.network.executeRequest
|
||||||
|
import org.matrix.android.sdk.internal.network.httpclient.addSocketFactory
|
||||||
|
import org.matrix.android.sdk.internal.network.ssl.UnrecognizedCertificateException
|
||||||
|
import org.matrix.android.sdk.internal.task.Task
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
internal interface QrLoginTokenTask : Task<QrLoginTokenTask.Params, Session> {
|
||||||
|
data class Params(
|
||||||
|
val homeServerConnectionConfig: HomeServerConnectionConfig,
|
||||||
|
val loginToken: String,
|
||||||
|
val deviceName: String?,
|
||||||
|
val deviceId: String?
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class DefaultQrLoginTokenTask @Inject constructor(
|
||||||
|
@Unauthenticated
|
||||||
|
private val okHttpClient: Lazy<OkHttpClient>,
|
||||||
|
private val retrofitFactory: RetrofitFactory,
|
||||||
|
private val sessionCreator: SessionCreator,
|
||||||
|
) : QrLoginTokenTask {
|
||||||
|
|
||||||
|
override suspend fun execute(params: QrLoginTokenTask.Params): Session {
|
||||||
|
val client = buildClient(params.homeServerConnectionConfig)
|
||||||
|
val homeServerUrl = params.homeServerConnectionConfig.homeServerUriBase.toString()
|
||||||
|
|
||||||
|
val authAPI = retrofitFactory.create(client, homeServerUrl)
|
||||||
|
.create(AuthAPI::class.java)
|
||||||
|
|
||||||
|
val loginParams = TokenLoginParams(
|
||||||
|
token = params.loginToken,
|
||||||
|
deviceDisplayName = params.deviceName,
|
||||||
|
deviceId = params.deviceId
|
||||||
|
)
|
||||||
|
|
||||||
|
val credentials = try {
|
||||||
|
executeRequest(null) {
|
||||||
|
authAPI.login(loginParams)
|
||||||
|
}
|
||||||
|
} catch (throwable: Throwable) {
|
||||||
|
throw when (throwable) {
|
||||||
|
is UnrecognizedCertificateException -> Failure.UnrecognizedCertificateFailure(
|
||||||
|
homeServerUrl,
|
||||||
|
throwable.fingerprint
|
||||||
|
)
|
||||||
|
else -> throwable
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sessionCreator.createSession(credentials, params.homeServerConnectionConfig, LoginType.QR)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun buildClient(homeServerConnectionConfig: HomeServerConnectionConfig): OkHttpClient {
|
||||||
|
return okHttpClient.get()
|
||||||
|
.newBuilder()
|
||||||
|
.addSocketFactory(homeServerConnectionConfig)
|
||||||
|
.build()
|
||||||
|
}
|
||||||
|
}
|
@ -17,18 +17,15 @@
|
|||||||
package org.matrix.android.sdk.internal.database.migration
|
package org.matrix.android.sdk.internal.database.migration
|
||||||
|
|
||||||
import io.realm.DynamicRealm
|
import io.realm.DynamicRealm
|
||||||
import org.matrix.android.sdk.internal.database.model.HomeServerCapabilitiesEntityFields
|
import org.matrix.android.sdk.internal.database.model.PusherEntityFields
|
||||||
import org.matrix.android.sdk.internal.extensions.forceRefreshOfHomeServerCapabilities
|
|
||||||
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||||
|
|
||||||
internal class MigrateSessionTo038(realm: DynamicRealm) : RealmMigrator(realm, 38) {
|
internal class MigrateSessionTo038(realm: DynamicRealm) : RealmMigrator(realm, 38) {
|
||||||
|
|
||||||
override fun doMigrate(realm: DynamicRealm) {
|
override fun doMigrate(realm: DynamicRealm) {
|
||||||
realm.schema.get("HomeServerCapabilitiesEntity")
|
realm.schema.get("PusherEntity")
|
||||||
?.addField(HomeServerCapabilitiesEntityFields.CAN_LOGIN_WITH_QR_CODE, Boolean::class.java)
|
?.addField(PusherEntityFields.ENABLED, Boolean::class.java)
|
||||||
?.transform { obj ->
|
?.addField(PusherEntityFields.DEVICE_ID, String::class.java)
|
||||||
obj.set(HomeServerCapabilitiesEntityFields.CAN_LOGIN_WITH_QR_CODE, false)
|
?.transform { obj -> obj.set(PusherEntityFields.ENABLED, true) }
|
||||||
}
|
|
||||||
?.forceRefreshOfHomeServerCapabilities()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022 The Matrix.org Foundation C.I.C.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.matrix.android.sdk.internal.database.migration
|
||||||
|
|
||||||
|
import io.realm.DynamicRealm
|
||||||
|
import org.matrix.android.sdk.internal.database.model.HomeServerCapabilitiesEntityFields
|
||||||
|
import org.matrix.android.sdk.internal.extensions.forceRefreshOfHomeServerCapabilities
|
||||||
|
import org.matrix.android.sdk.internal.util.database.RealmMigrator
|
||||||
|
|
||||||
|
internal class MigrateSessionTo039(realm: DynamicRealm) : RealmMigrator(realm, 39) {
|
||||||
|
|
||||||
|
override fun doMigrate(realm: DynamicRealm) {
|
||||||
|
realm.schema.get("HomeServerCapabilitiesEntity")
|
||||||
|
?.addField(HomeServerCapabilitiesEntityFields.CAN_LOGIN_WITH_QR_CODE, Boolean::class.java)
|
||||||
|
?.transform { obj ->
|
||||||
|
obj.set(HomeServerCapabilitiesEntityFields.CAN_LOGIN_WITH_QR_CODE, false)
|
||||||
|
}
|
||||||
|
?.forceRefreshOfHomeServerCapabilities()
|
||||||
|
}
|
||||||
|
}
|
@ -20,6 +20,8 @@ import android.content.Context
|
|||||||
import android.os.Build
|
import android.os.Build
|
||||||
import org.matrix.android.sdk.BuildConfig
|
import org.matrix.android.sdk.BuildConfig
|
||||||
import org.matrix.android.sdk.api.extensions.tryOrNull
|
import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||||
|
import org.matrix.android.sdk.api.util.getApplicationInfoCompat
|
||||||
|
import org.matrix.android.sdk.api.util.getPackageInfoCompat
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class ComputeUserAgentUseCase @Inject constructor(
|
class ComputeUserAgentUseCase @Inject constructor(
|
||||||
@ -36,7 +38,7 @@ class ComputeUserAgentUseCase @Inject constructor(
|
|||||||
val appPackageName = context.applicationContext.packageName
|
val appPackageName = context.applicationContext.packageName
|
||||||
val pm = context.packageManager
|
val pm = context.packageManager
|
||||||
|
|
||||||
val appName = tryOrNull { pm.getApplicationLabel(pm.getApplicationInfo(appPackageName, 0)).toString() }
|
val appName = tryOrNull { pm.getApplicationLabel(pm.getApplicationInfoCompat(appPackageName, 0)).toString() }
|
||||||
?.takeIf {
|
?.takeIf {
|
||||||
it.matches("\\A\\p{ASCII}*\\z".toRegex())
|
it.matches("\\A\\p{ASCII}*\\z".toRegex())
|
||||||
}
|
}
|
||||||
@ -44,7 +46,7 @@ class ComputeUserAgentUseCase @Inject constructor(
|
|||||||
// Use appPackageName instead of appName if appName is null or contains any non-ASCII character
|
// Use appPackageName instead of appName if appName is null or contains any non-ASCII character
|
||||||
appPackageName
|
appPackageName
|
||||||
}
|
}
|
||||||
val appVersion = tryOrNull { pm.getPackageInfo(context.applicationContext.packageName, 0).versionName } ?: FALLBACK_APP_VERSION
|
val appVersion = tryOrNull { pm.getPackageInfoCompat(context.applicationContext.packageName, 0).versionName } ?: FALLBACK_APP_VERSION
|
||||||
|
|
||||||
val deviceManufacturer = Build.MANUFACTURER
|
val deviceManufacturer = Build.MANUFACTURER
|
||||||
val deviceModel = Build.MODEL
|
val deviceModel = Build.MODEL
|
||||||
|
@ -66,7 +66,7 @@ internal class DefaultSessionAccountDataService @Inject constructor(
|
|||||||
|
|
||||||
override suspend fun updateUserAccountData(type: String, content: Content) {
|
override suspend fun updateUserAccountData(type: String, content: Content) {
|
||||||
val params = UpdateUserAccountDataTask.AnyParams(type = type, any = content)
|
val params = UpdateUserAccountDataTask.AnyParams(type = type, any = content)
|
||||||
awaitCallback<Unit> { callback ->
|
awaitCallback { callback ->
|
||||||
updateUserAccountDataTask.configureWith(params) {
|
updateUserAccountDataTask.configureWith(params) {
|
||||||
this.retryCount = 5 // TODO Need to refactor retrying out into a helper method.
|
this.retryCount = 5 // TODO Need to refactor retrying out into a helper method.
|
||||||
this.callback = callback
|
this.callback = callback
|
||||||
|
@ -27,6 +27,8 @@ import org.amshove.kluent.shouldBeEqualTo
|
|||||||
import org.junit.Before
|
import org.junit.Before
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import org.matrix.android.sdk.BuildConfig
|
import org.matrix.android.sdk.BuildConfig
|
||||||
|
import org.matrix.android.sdk.api.util.getApplicationInfoCompat
|
||||||
|
import org.matrix.android.sdk.api.util.getPackageInfoCompat
|
||||||
import java.lang.Exception
|
import java.lang.Exception
|
||||||
|
|
||||||
private const val A_PACKAGE_NAME = "org.matrix.sdk"
|
private const val A_PACKAGE_NAME = "org.matrix.sdk"
|
||||||
@ -49,8 +51,8 @@ class ComputeUserAgentUseCaseTest {
|
|||||||
every { context.applicationContext } returns context
|
every { context.applicationContext } returns context
|
||||||
every { context.packageName } returns A_PACKAGE_NAME
|
every { context.packageName } returns A_PACKAGE_NAME
|
||||||
every { context.packageManager } returns packageManager
|
every { context.packageManager } returns packageManager
|
||||||
every { packageManager.getApplicationInfo(any(), any()) } returns applicationInfo
|
every { packageManager.getApplicationInfoCompat(any(), any()) } returns applicationInfo
|
||||||
every { packageManager.getPackageInfo(any<String>(), any()) } returns packageInfo
|
every { packageManager.getPackageInfoCompat(any(), any()) } returns packageInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
25
tools/adb/notification.sh
Executable file
25
tools/adb/notification.sh
Executable file
@ -0,0 +1,25 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
## From https://developer.android.com/develop/ui/views/notifications/notification-permission#test
|
||||||
|
|
||||||
|
PACKAGE_NAME=im.vector.app.debug
|
||||||
|
|
||||||
|
# App is newly installed on a device that runs Android 13 or higher:
|
||||||
|
|
||||||
|
adb shell pm revoke ${PACKAGE_NAME} android.permission.POST_NOTIFICATIONS
|
||||||
|
adb shell pm clear-permission-flags ${PACKAGE_NAME} android.permission.POST_NOTIFICATIONS user-set
|
||||||
|
adb shell pm clear-permission-flags ${PACKAGE_NAME} android.permission.POST_NOTIFICATIONS user-fixed
|
||||||
|
|
||||||
|
# The user keeps notifications enabled when the app is installed on a device that runs 12L or lower,
|
||||||
|
# then the device upgrades to Android 13 or higher:
|
||||||
|
|
||||||
|
# adb shell pm grant ${PACKAGE_NAME} android.permission.POST_NOTIFICATIONS
|
||||||
|
# adb shell pm set-permission-flags ${PACKAGE_NAME} android.permission.POST_NOTIFICATIONS user-set
|
||||||
|
# adb shell pm clear-permission-flags ${PACKAGE_NAME} android.permission.POST_NOTIFICATIONS user-fixed
|
||||||
|
|
||||||
|
# The user manually disables notifications when the app is installed on a device that runs 12L or lower,
|
||||||
|
# then the device upgrades to Android 13 or higher:
|
||||||
|
|
||||||
|
# adb shell pm revoke ${PACKAGE_NAME} android.permission.POST_NOTIFICATIONS
|
||||||
|
# adb shell pm set-permission-flags ${PACKAGE_NAME} android.permission.POST_NOTIFICATIONS user-set
|
||||||
|
# adb shell pm clear-permission-flags ${PACKAGE_NAME} android.permission.POST_NOTIFICATIONS user-fixed
|
@ -68,15 +68,14 @@ ${searchForbiddenStringsScript} ./tools/check/forbidden_strings_in_code.txt \
|
|||||||
./matrix-sdk-android/src/main/java \
|
./matrix-sdk-android/src/main/java \
|
||||||
./matrix-sdk-android-flow/src/main/java \
|
./matrix-sdk-android-flow/src/main/java \
|
||||||
./library/core-utils/src/main/java \
|
./library/core-utils/src/main/java \
|
||||||
./library/jsonviewer/src/main/java \
|
./library/external/jsonviewer/src/main/java \
|
||||||
./library/ui-styles/src/main/java \
|
./library/ui-styles/src/main/java \
|
||||||
./vector/src/main/java \
|
./vector/src/main/java \
|
||||||
./vector/src/debug/java \
|
./vector-app/src/debug/java \
|
||||||
./vector/src/release/java \
|
./vector-app/src/fdroid/java \
|
||||||
./vector/src/fdroid/java \
|
|
||||||
./vector/src/gplay/java \
|
|
||||||
./vector-app/src/gplay/java \
|
./vector-app/src/gplay/java \
|
||||||
./vector-app/src/main/java
|
./vector-app/src/main/java \
|
||||||
|
./vector-app/src/release/java
|
||||||
|
|
||||||
resultForbiddenStringInCode=$?
|
resultForbiddenStringInCode=$?
|
||||||
|
|
||||||
@ -93,13 +92,15 @@ echo
|
|||||||
echo "Search for forbidden patterns specific for App code..."
|
echo "Search for forbidden patterns specific for App code..."
|
||||||
|
|
||||||
${searchForbiddenStringsScript} ./tools/check/forbidden_strings_in_code_app.txt \
|
${searchForbiddenStringsScript} ./tools/check/forbidden_strings_in_code_app.txt \
|
||||||
|
./library/core-utils/src/main/java \
|
||||||
|
./library/external/jsonviewer/src/main/java \
|
||||||
|
./library/ui-styles/src/main/java \
|
||||||
./vector/src/main/java \
|
./vector/src/main/java \
|
||||||
./vector/src/debug/java \
|
./vector-app/src/debug/java \
|
||||||
./vector/src/release/java \
|
./vector-app/src/fdroid/java \
|
||||||
./vector/src/fdroid/java \
|
|
||||||
./vector/src/gplay/java \
|
|
||||||
./vector-app/src/gplay/java \
|
./vector-app/src/gplay/java \
|
||||||
./vector-app/src/main/java
|
./vector-app/src/main/java \
|
||||||
|
./vector-app/src/release/java
|
||||||
|
|
||||||
resultForbiddenStringInCodeApp=$?
|
resultForbiddenStringInCodeApp=$?
|
||||||
|
|
||||||
@ -120,8 +121,7 @@ echo
|
|||||||
echo "Search for forbidden patterns in layouts..."
|
echo "Search for forbidden patterns in layouts..."
|
||||||
|
|
||||||
${searchForbiddenStringsScript} ./tools/check/forbidden_strings_in_layout.txt \
|
${searchForbiddenStringsScript} ./tools/check/forbidden_strings_in_layout.txt \
|
||||||
./vector/src/main/res/layout \
|
./vector/src/main/res/layout
|
||||||
./vector-app/src/main/res/layout
|
|
||||||
|
|
||||||
resultForbiddenStringInLayout=$?
|
resultForbiddenStringInLayout=$?
|
||||||
|
|
||||||
@ -154,17 +154,19 @@ echo "Search for kotlin files with more than ${maxLines} lines..."
|
|||||||
${checkLongFilesScript} ${maxLines} \
|
${checkLongFilesScript} ${maxLines} \
|
||||||
./matrix-sdk-android/src/main/java \
|
./matrix-sdk-android/src/main/java \
|
||||||
./matrix-sdk-android-flow/src/main/java \
|
./matrix-sdk-android-flow/src/main/java \
|
||||||
|
./library/core-utils/src/main/java \
|
||||||
|
./library/external/jsonviewer/src/main/java \
|
||||||
|
./library/ui-styles/src/main/java \
|
||||||
./vector/src/androidTest/java \
|
./vector/src/androidTest/java \
|
||||||
./vector/src/debug/java \
|
|
||||||
./vector/src/fdroid/java \
|
|
||||||
./vector/src/gplay/java \
|
|
||||||
./vector/src/main/java \
|
./vector/src/main/java \
|
||||||
./vector/src/release/java \
|
|
||||||
./vector/src/sharedTest/java \
|
./vector/src/sharedTest/java \
|
||||||
./vector/src/test/java \
|
./vector/src/test/java \
|
||||||
./vector/src/androidTest/java \
|
./vector-app/src/androidTest/java \
|
||||||
./vector/src/gplay/java \
|
./vector-app/src/debug/java \
|
||||||
./vector/src/main/java
|
./vector-app/src/fdroid/java \
|
||||||
|
./vector-app/src/gplay/java \
|
||||||
|
./vector-app/src/main/java \
|
||||||
|
./vector-app/src/release/java
|
||||||
|
|
||||||
|
|
||||||
resultLongFiles=$?
|
resultLongFiles=$?
|
||||||
@ -179,8 +181,11 @@ echo "Search for png files in /drawable..."
|
|||||||
ls -1U ./vector/src/main/res/drawable/*.png
|
ls -1U ./vector/src/main/res/drawable/*.png
|
||||||
resultTmp=$?
|
resultTmp=$?
|
||||||
|
|
||||||
|
ls -1U ./vector-app/src/main/res/drawable/*.png
|
||||||
|
resultTmp2=$?
|
||||||
|
|
||||||
# Inverse the result, cause no file found is an error for ls but this is what we want!
|
# Inverse the result, cause no file found is an error for ls but this is what we want!
|
||||||
if [[ ${resultTmp} -eq 0 ]]; then
|
if [[ ${resultTmp} -eq 0 ]] || [[ ${resultTmp2} -eq 0 ]]; then
|
||||||
echo "ERROR, png files detected in /drawable"
|
echo "ERROR, png files detected in /drawable"
|
||||||
resultPngInDrawable=1
|
resultPngInDrawable=1
|
||||||
else
|
else
|
||||||
|
6
vector-app/proguard-rules.pro
vendored
6
vector-app/proguard-rules.pro
vendored
@ -75,4 +75,8 @@
|
|||||||
|
|
||||||
-keep class org.bouncycastle.** { *; }
|
-keep class org.bouncycastle.** { *; }
|
||||||
-keepnames class org.bouncycastle.** { *; }
|
-keepnames class org.bouncycastle.** { *; }
|
||||||
-dontwarn org.bouncycastle.**
|
-dontwarn org.bouncycastle.**
|
||||||
|
|
||||||
|
# JNA
|
||||||
|
-keep class com.sun.jna.** { *; }
|
||||||
|
-keep class * implements com.sun.jna.** { *; }
|
||||||
|
@ -22,6 +22,7 @@ import android.os.Build
|
|||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.core.app.ActivityCompat
|
import androidx.core.app.ActivityCompat
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.core.view.isVisible
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
import im.vector.app.core.platform.VectorBaseActivity
|
import im.vector.app.core.platform.VectorBaseActivity
|
||||||
import im.vector.app.core.utils.checkPermissions
|
import im.vector.app.core.utils.checkPermissions
|
||||||
@ -46,7 +47,15 @@ class DebugPermissionActivity : VectorBaseActivity<ActivityDebugPermissionBindin
|
|||||||
Manifest.permission.WRITE_EXTERNAL_STORAGE,
|
Manifest.permission.WRITE_EXTERNAL_STORAGE,
|
||||||
Manifest.permission.READ_EXTERNAL_STORAGE,
|
Manifest.permission.READ_EXTERNAL_STORAGE,
|
||||||
Manifest.permission.READ_CONTACTS
|
Manifest.permission.READ_CONTACTS
|
||||||
)
|
) + getAndroid13Permissions()
|
||||||
|
|
||||||
|
private fun getAndroid13Permissions(): List<String> {
|
||||||
|
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||||
|
listOf(Manifest.permission.POST_NOTIFICATIONS)
|
||||||
|
} else {
|
||||||
|
emptyList()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private var lastPermissions = emptyList<String>()
|
private var lastPermissions = emptyList<String>()
|
||||||
|
|
||||||
@ -77,6 +86,14 @@ class DebugPermissionActivity : VectorBaseActivity<ActivityDebugPermissionBindin
|
|||||||
lastPermissions = listOf(Manifest.permission.READ_CONTACTS)
|
lastPermissions = listOf(Manifest.permission.READ_CONTACTS)
|
||||||
checkPerm()
|
checkPerm()
|
||||||
}
|
}
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||||
|
views.notification.setOnClickListener {
|
||||||
|
lastPermissions = listOf(Manifest.permission.POST_NOTIFICATIONS)
|
||||||
|
checkPerm()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
views.notification.isVisible = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkPerm() {
|
private fun checkPerm() {
|
||||||
|
@ -85,11 +85,6 @@ class DebugFeaturesStateFactory @Inject constructor(
|
|||||||
key = DebugFeatureKeys.newAppLayoutEnabled,
|
key = DebugFeatureKeys.newAppLayoutEnabled,
|
||||||
factory = VectorFeatures::isNewAppLayoutFeatureEnabled
|
factory = VectorFeatures::isNewAppLayoutFeatureEnabled
|
||||||
),
|
),
|
||||||
createBooleanFeature(
|
|
||||||
label = "Enable New Device Management",
|
|
||||||
key = DebugFeatureKeys.newDeviceManagementEnabled,
|
|
||||||
factory = VectorFeatures::isNewDeviceManagementEnabled
|
|
||||||
),
|
|
||||||
createBooleanFeature(
|
createBooleanFeature(
|
||||||
label = "Enable QR Code Login",
|
label = "Enable QR Code Login",
|
||||||
key = DebugFeatureKeys.qrCodeLoginEnabled,
|
key = DebugFeatureKeys.qrCodeLoginEnabled,
|
||||||
|
@ -76,9 +76,6 @@ class DebugVectorFeatures(
|
|||||||
override fun isNewAppLayoutFeatureEnabled(): Boolean = read(DebugFeatureKeys.newAppLayoutEnabled)
|
override fun isNewAppLayoutFeatureEnabled(): Boolean = read(DebugFeatureKeys.newAppLayoutEnabled)
|
||||||
?: vectorFeatures.isNewAppLayoutFeatureEnabled()
|
?: vectorFeatures.isNewAppLayoutFeatureEnabled()
|
||||||
|
|
||||||
override fun isNewDeviceManagementEnabled(): Boolean = read(DebugFeatureKeys.newDeviceManagementEnabled)
|
|
||||||
?: vectorFeatures.isNewDeviceManagementEnabled()
|
|
||||||
|
|
||||||
override fun isQrCodeLoginEnabled() = read(DebugFeatureKeys.qrCodeLoginEnabled)
|
override fun isQrCodeLoginEnabled() = read(DebugFeatureKeys.qrCodeLoginEnabled)
|
||||||
?: vectorFeatures.isQrCodeLoginEnabled()
|
?: vectorFeatures.isQrCodeLoginEnabled()
|
||||||
|
|
||||||
@ -149,9 +146,7 @@ object DebugFeatureKeys {
|
|||||||
val liveLocationSharing = booleanPreferencesKey("live-location-sharing")
|
val liveLocationSharing = booleanPreferencesKey("live-location-sharing")
|
||||||
val screenSharing = booleanPreferencesKey("screen-sharing")
|
val screenSharing = booleanPreferencesKey("screen-sharing")
|
||||||
val forceUsageOfOpusEncoder = booleanPreferencesKey("force-usage-of-opus-encoder")
|
val forceUsageOfOpusEncoder = booleanPreferencesKey("force-usage-of-opus-encoder")
|
||||||
val startDmOnFirstMsg = booleanPreferencesKey("start-dm-on-first-msg")
|
|
||||||
val newAppLayoutEnabled = booleanPreferencesKey("new-app-layout-enabled")
|
val newAppLayoutEnabled = booleanPreferencesKey("new-app-layout-enabled")
|
||||||
val newDeviceManagementEnabled = booleanPreferencesKey("new-device-management-enabled")
|
|
||||||
val qrCodeLoginEnabled = booleanPreferencesKey("qr-code-login-enabled")
|
val qrCodeLoginEnabled = booleanPreferencesKey("qr-code-login-enabled")
|
||||||
val allowQrCodeLoginForAllServers = booleanPreferencesKey("allow-qr-code-login-for-all-servers")
|
val allowQrCodeLoginForAllServers = booleanPreferencesKey("allow-qr-code-login-for-all-servers")
|
||||||
val allowReciprocateQrCodeLogin = booleanPreferencesKey("allow-reciprocate-qr-code-login")
|
val allowReciprocateQrCodeLogin = booleanPreferencesKey("allow-reciprocate-qr-code-login")
|
||||||
|
@ -30,43 +30,43 @@
|
|||||||
android:id="@+id/camera"
|
android:id="@+id/camera"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="CAMERA"
|
android:text="CAMERA" />
|
||||||
android:textAllCaps="false" />
|
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/audio"
|
android:id="@+id/audio"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="RECORD_AUDIO"
|
android:text="RECORD_AUDIO" />
|
||||||
android:textAllCaps="false" />
|
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/camera_audio"
|
android:id="@+id/camera_audio"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="CAMERA + RECORD_AUDIO"
|
android:text="CAMERA + RECORD_AUDIO" />
|
||||||
android:textAllCaps="false" />
|
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/write"
|
android:id="@+id/write"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="WRITE_EXTERNAL_STORAGE"
|
android:text="WRITE_EXTERNAL_STORAGE" />
|
||||||
android:textAllCaps="false" />
|
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/read"
|
android:id="@+id/read"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="READ_EXTERNAL_STORAGE"
|
android:text="READ_EXTERNAL_STORAGE" />
|
||||||
android:textAllCaps="false" />
|
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
android:id="@+id/contact"
|
android:id="@+id/contact"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="READ_CONTACTS"
|
android:text="READ_CONTACTS" />
|
||||||
android:textAllCaps="false" />
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/notification"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="POST_NOTIFICATIONS" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
@ -15,8 +15,6 @@
|
|||||||
*/
|
*/
|
||||||
package im.vector.app.fdroid.features.settings.troubleshoot
|
package im.vector.app.fdroid.features.settings.troubleshoot
|
||||||
|
|
||||||
import android.content.Intent
|
|
||||||
import androidx.activity.result.ActivityResultLauncher
|
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.resources.StringProvider
|
import im.vector.app.core.resources.StringProvider
|
||||||
import im.vector.app.features.settings.VectorPreferences
|
import im.vector.app.features.settings.VectorPreferences
|
||||||
@ -32,7 +30,7 @@ class TestAutoStartBoot @Inject constructor(
|
|||||||
) :
|
) :
|
||||||
TroubleshootTest(R.string.settings_troubleshoot_test_service_boot_title) {
|
TroubleshootTest(R.string.settings_troubleshoot_test_service_boot_title) {
|
||||||
|
|
||||||
override fun perform(activityResultLauncher: ActivityResultLauncher<Intent>) {
|
override fun perform(testParameters: TestParameters) {
|
||||||
if (vectorPreferences.autoStartOnBoot()) {
|
if (vectorPreferences.autoStartOnBoot()) {
|
||||||
description = stringProvider.getString(R.string.settings_troubleshoot_test_service_boot_success)
|
description = stringProvider.getString(R.string.settings_troubleshoot_test_service_boot_success)
|
||||||
status = TestStatus.SUCCESS
|
status = TestStatus.SUCCESS
|
||||||
@ -42,7 +40,7 @@ class TestAutoStartBoot @Inject constructor(
|
|||||||
quickFix = object : TroubleshootQuickFix(R.string.settings_troubleshoot_test_service_boot_quickfix) {
|
quickFix = object : TroubleshootQuickFix(R.string.settings_troubleshoot_test_service_boot_quickfix) {
|
||||||
override fun doFix() {
|
override fun doFix() {
|
||||||
vectorPreferences.setAutoStartOnBoot(true)
|
vectorPreferences.setAutoStartOnBoot(true)
|
||||||
manager?.retry(activityResultLauncher)
|
manager?.retry(testParameters)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
status = TestStatus.FAILED
|
status = TestStatus.FAILED
|
||||||
|
@ -15,9 +15,7 @@
|
|||||||
*/
|
*/
|
||||||
package im.vector.app.fdroid.features.settings.troubleshoot
|
package im.vector.app.fdroid.features.settings.troubleshoot
|
||||||
|
|
||||||
import android.content.Intent
|
|
||||||
import android.net.ConnectivityManager
|
import android.net.ConnectivityManager
|
||||||
import androidx.activity.result.ActivityResultLauncher
|
|
||||||
import androidx.core.content.getSystemService
|
import androidx.core.content.getSystemService
|
||||||
import androidx.core.net.ConnectivityManagerCompat
|
import androidx.core.net.ConnectivityManagerCompat
|
||||||
import androidx.fragment.app.FragmentActivity
|
import androidx.fragment.app.FragmentActivity
|
||||||
@ -32,7 +30,7 @@ class TestBackgroundRestrictions @Inject constructor(
|
|||||||
) :
|
) :
|
||||||
TroubleshootTest(R.string.settings_troubleshoot_test_bg_restricted_title) {
|
TroubleshootTest(R.string.settings_troubleshoot_test_bg_restricted_title) {
|
||||||
|
|
||||||
override fun perform(activityResultLauncher: ActivityResultLauncher<Intent>) {
|
override fun perform(testParameters: TestParameters) {
|
||||||
context.getSystemService<ConnectivityManager>()!!.apply {
|
context.getSystemService<ConnectivityManager>()!!.apply {
|
||||||
// Checks if the device is on a metered network
|
// Checks if the device is on a metered network
|
||||||
if (isActiveNetworkMetered) {
|
if (isActiveNetworkMetered) {
|
||||||
|
@ -15,8 +15,6 @@
|
|||||||
*/
|
*/
|
||||||
package im.vector.app.fdroid.features.settings.troubleshoot
|
package im.vector.app.fdroid.features.settings.troubleshoot
|
||||||
|
|
||||||
import android.content.Intent
|
|
||||||
import androidx.activity.result.ActivityResultLauncher
|
|
||||||
import androidx.fragment.app.FragmentActivity
|
import androidx.fragment.app.FragmentActivity
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.resources.StringProvider
|
import im.vector.app.core.resources.StringProvider
|
||||||
@ -30,7 +28,7 @@ class TestBatteryOptimization @Inject constructor(
|
|||||||
private val stringProvider: StringProvider
|
private val stringProvider: StringProvider
|
||||||
) : TroubleshootTest(R.string.settings_troubleshoot_test_battery_title) {
|
) : TroubleshootTest(R.string.settings_troubleshoot_test_battery_title) {
|
||||||
|
|
||||||
override fun perform(activityResultLauncher: ActivityResultLauncher<Intent>) {
|
override fun perform(testParameters: TestParameters) {
|
||||||
if (context.isIgnoringBatteryOptimizations()) {
|
if (context.isIgnoringBatteryOptimizations()) {
|
||||||
description = stringProvider.getString(R.string.settings_troubleshoot_test_battery_success)
|
description = stringProvider.getString(R.string.settings_troubleshoot_test_battery_success)
|
||||||
status = TestStatus.SUCCESS
|
status = TestStatus.SUCCESS
|
||||||
@ -39,7 +37,7 @@ class TestBatteryOptimization @Inject constructor(
|
|||||||
description = stringProvider.getString(R.string.settings_troubleshoot_test_battery_failed)
|
description = stringProvider.getString(R.string.settings_troubleshoot_test_battery_failed)
|
||||||
quickFix = object : TroubleshootQuickFix(R.string.settings_troubleshoot_test_battery_quickfix) {
|
quickFix = object : TroubleshootQuickFix(R.string.settings_troubleshoot_test_battery_quickfix) {
|
||||||
override fun doFix() {
|
override fun doFix() {
|
||||||
requestDisablingBatteryOptimization(context, activityResultLauncher)
|
requestDisablingBatteryOptimization(context, testParameters.activityResultLauncher)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
status = TestStatus.FAILED
|
status = TestStatus.FAILED
|
||||||
|
@ -15,8 +15,6 @@
|
|||||||
*/
|
*/
|
||||||
package im.vector.app.gplay.features.settings.troubleshoot
|
package im.vector.app.gplay.features.settings.troubleshoot
|
||||||
|
|
||||||
import android.content.Intent
|
|
||||||
import androidx.activity.result.ActivityResultLauncher
|
|
||||||
import androidx.fragment.app.FragmentActivity
|
import androidx.fragment.app.FragmentActivity
|
||||||
import com.google.firebase.messaging.FirebaseMessaging
|
import com.google.firebase.messaging.FirebaseMessaging
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
@ -36,7 +34,7 @@ class TestFirebaseToken @Inject constructor(
|
|||||||
private val fcmHelper: FcmHelper,
|
private val fcmHelper: FcmHelper,
|
||||||
) : TroubleshootTest(R.string.settings_troubleshoot_test_fcm_title) {
|
) : TroubleshootTest(R.string.settings_troubleshoot_test_fcm_title) {
|
||||||
|
|
||||||
override fun perform(activityResultLauncher: ActivityResultLauncher<Intent>) {
|
override fun perform(testParameters: TestParameters) {
|
||||||
status = TestStatus.RUNNING
|
status = TestStatus.RUNNING
|
||||||
try {
|
try {
|
||||||
FirebaseMessaging.getInstance().token
|
FirebaseMessaging.getInstance().token
|
||||||
@ -53,7 +51,7 @@ class TestFirebaseToken @Inject constructor(
|
|||||||
"ACCOUNT_MISSING" -> {
|
"ACCOUNT_MISSING" -> {
|
||||||
quickFix = object : TroubleshootQuickFix(R.string.settings_troubleshoot_test_fcm_failed_account_missing_quick_fix) {
|
quickFix = object : TroubleshootQuickFix(R.string.settings_troubleshoot_test_fcm_failed_account_missing_quick_fix) {
|
||||||
override fun doFix() {
|
override fun doFix() {
|
||||||
startAddGoogleAccountIntent(context, activityResultLauncher)
|
startAddGoogleAccountIntent(context, testParameters.activityResultLauncher)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stringProvider.getString(R.string.settings_troubleshoot_test_fcm_failed_account_missing, errorMsg)
|
stringProvider.getString(R.string.settings_troubleshoot_test_fcm_failed_account_missing, errorMsg)
|
||||||
|
@ -15,8 +15,6 @@
|
|||||||
*/
|
*/
|
||||||
package im.vector.app.gplay.features.settings.troubleshoot
|
package im.vector.app.gplay.features.settings.troubleshoot
|
||||||
|
|
||||||
import android.content.Intent
|
|
||||||
import androidx.activity.result.ActivityResultLauncher
|
|
||||||
import androidx.fragment.app.FragmentActivity
|
import androidx.fragment.app.FragmentActivity
|
||||||
import com.google.android.gms.common.ConnectionResult
|
import com.google.android.gms.common.ConnectionResult
|
||||||
import com.google.android.gms.common.GoogleApiAvailability
|
import com.google.android.gms.common.GoogleApiAvailability
|
||||||
@ -35,7 +33,7 @@ class TestPlayServices @Inject constructor(
|
|||||||
) :
|
) :
|
||||||
TroubleshootTest(R.string.settings_troubleshoot_test_play_services_title) {
|
TroubleshootTest(R.string.settings_troubleshoot_test_play_services_title) {
|
||||||
|
|
||||||
override fun perform(activityResultLauncher: ActivityResultLauncher<Intent>) {
|
override fun perform(testParameters: TestParameters) {
|
||||||
val apiAvailability = GoogleApiAvailability.getInstance()
|
val apiAvailability = GoogleApiAvailability.getInstance()
|
||||||
val resultCode = apiAvailability.isGooglePlayServicesAvailable(context)
|
val resultCode = apiAvailability.isGooglePlayServicesAvailable(context)
|
||||||
if (resultCode == ConnectionResult.SUCCESS) {
|
if (resultCode == ConnectionResult.SUCCESS) {
|
||||||
|
@ -15,8 +15,6 @@
|
|||||||
*/
|
*/
|
||||||
package im.vector.app.gplay.features.settings.troubleshoot
|
package im.vector.app.gplay.features.settings.troubleshoot
|
||||||
|
|
||||||
import android.content.Intent
|
|
||||||
import androidx.activity.result.ActivityResultLauncher
|
|
||||||
import androidx.fragment.app.FragmentActivity
|
import androidx.fragment.app.FragmentActivity
|
||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
import androidx.work.WorkInfo
|
import androidx.work.WorkInfo
|
||||||
@ -42,7 +40,7 @@ class TestTokenRegistration @Inject constructor(
|
|||||||
) :
|
) :
|
||||||
TroubleshootTest(R.string.settings_troubleshoot_test_token_registration_title) {
|
TroubleshootTest(R.string.settings_troubleshoot_test_token_registration_title) {
|
||||||
|
|
||||||
override fun perform(activityResultLauncher: ActivityResultLauncher<Intent>) {
|
override fun perform(testParameters: TestParameters) {
|
||||||
// Check if we have a registered pusher for this token
|
// Check if we have a registered pusher for this token
|
||||||
val fcmToken = fcmHelper.getFcmToken() ?: run {
|
val fcmToken = fcmHelper.getFcmToken() ?: run {
|
||||||
status = TestStatus.FAILED
|
status = TestStatus.FAILED
|
||||||
@ -66,9 +64,9 @@ class TestTokenRegistration @Inject constructor(
|
|||||||
WorkManager.getInstance(context).getWorkInfoByIdLiveData(workId).observe(context, Observer { workInfo ->
|
WorkManager.getInstance(context).getWorkInfoByIdLiveData(workId).observe(context, Observer { workInfo ->
|
||||||
if (workInfo != null) {
|
if (workInfo != null) {
|
||||||
if (workInfo.state == WorkInfo.State.SUCCEEDED) {
|
if (workInfo.state == WorkInfo.State.SUCCEEDED) {
|
||||||
manager?.retry(activityResultLauncher)
|
manager?.retry(testParameters)
|
||||||
} else if (workInfo.state == WorkInfo.State.FAILED) {
|
} else if (workInfo.state == WorkInfo.State.FAILED) {
|
||||||
manager?.retry(activityResultLauncher)
|
manager?.retry(testParameters)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -41,6 +41,7 @@
|
|||||||
<bool name="settings_labs_deferred_dm_default">true</bool>
|
<bool name="settings_labs_deferred_dm_default">true</bool>
|
||||||
<bool name="settings_labs_thread_messages_default">false</bool>
|
<bool name="settings_labs_thread_messages_default">false</bool>
|
||||||
<bool name="settings_labs_new_app_layout_default">true</bool>
|
<bool name="settings_labs_new_app_layout_default">true</bool>
|
||||||
|
<bool name="settings_labs_new_session_manager_default">false</bool>
|
||||||
<bool name="settings_timeline_show_live_sender_info_visible">true</bool>
|
<bool name="settings_timeline_show_live_sender_info_visible">true</bool>
|
||||||
<bool name="settings_timeline_show_live_sender_info_default">false</bool>
|
<bool name="settings_timeline_show_live_sender_info_default">false</bool>
|
||||||
<bool name="settings_labs_rich_text_editor_visible">true</bool>
|
<bool name="settings_labs_rich_text_editor_visible">true</bool>
|
||||||
|
@ -174,9 +174,6 @@ dependencies {
|
|||||||
// Paging
|
// Paging
|
||||||
implementation libs.androidx.pagingRuntimeKtx
|
implementation libs.androidx.pagingRuntimeKtx
|
||||||
|
|
||||||
// Functional Programming
|
|
||||||
implementation libs.arrow.core
|
|
||||||
|
|
||||||
// Pref
|
// Pref
|
||||||
api libs.androidx.preferenceKtx
|
api libs.androidx.preferenceKtx
|
||||||
|
|
||||||
|
@ -17,6 +17,9 @@
|
|||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||||
|
|
||||||
|
<!-- https://developer.android.com/develop/ui/views/notifications/notification-permission#exemptions -->
|
||||||
|
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||||
|
|
||||||
<!-- Call feature -->
|
<!-- Call feature -->
|
||||||
<uses-permission android:name="android.permission.MANAGE_OWN_CALLS" />
|
<uses-permission android:name="android.permission.MANAGE_OWN_CALLS" />
|
||||||
<!-- Commented because Google PlayStore does not like we add permission if we are not requiring it. And it was added for future use -->
|
<!-- Commented because Google PlayStore does not like we add permission if we are not requiring it. And it was added for future use -->
|
||||||
|
@ -17,11 +17,11 @@
|
|||||||
|
|
||||||
package im.vector.app
|
package im.vector.app
|
||||||
|
|
||||||
import arrow.core.Option
|
|
||||||
import im.vector.app.core.utils.BehaviorDataSource
|
import im.vector.app.core.utils.BehaviorDataSource
|
||||||
import org.matrix.android.sdk.api.session.Session
|
import org.matrix.android.sdk.api.session.Session
|
||||||
|
import org.matrix.android.sdk.api.util.Optional
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@Singleton
|
@Singleton
|
||||||
class ActiveSessionDataSource @Inject constructor() : BehaviorDataSource<Option<Session>>()
|
class ActiveSessionDataSource @Inject constructor() : BehaviorDataSource<Optional<Session>>()
|
||||||
|
@ -17,10 +17,10 @@
|
|||||||
package im.vector.app
|
package im.vector.app
|
||||||
|
|
||||||
import androidx.lifecycle.DefaultLifecycleObserver
|
import androidx.lifecycle.DefaultLifecycleObserver
|
||||||
import arrow.core.Option
|
|
||||||
import kotlinx.coroutines.flow.Flow
|
import kotlinx.coroutines.flow.Flow
|
||||||
import org.matrix.android.sdk.api.session.Session
|
import org.matrix.android.sdk.api.session.Session
|
||||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||||
|
import org.matrix.android.sdk.api.util.Optional
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets info about the current space the user has navigated to, any space backstack they may have
|
* Gets info about the current space the user has navigated to, any space backstack they may have
|
||||||
@ -62,7 +62,7 @@ interface SpaceStateHandler : DefaultLifecycleObserver {
|
|||||||
/**
|
/**
|
||||||
* Gets a flow of the selected space for clients to react immediately to space changes.
|
* Gets a flow of the selected space for clients to react immediately to space changes.
|
||||||
*/
|
*/
|
||||||
fun getSelectedSpaceFlow(): Flow<Option<RoomSummary>>
|
fun getSelectedSpaceFlow(): Flow<Optional<RoomSummary>>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the id of the active space, or null if there is none.
|
* Gets the id of the active space, or null if there is none.
|
||||||
|
@ -17,7 +17,6 @@
|
|||||||
package im.vector.app
|
package im.vector.app
|
||||||
|
|
||||||
import androidx.lifecycle.LifecycleOwner
|
import androidx.lifecycle.LifecycleOwner
|
||||||
import arrow.core.Option
|
|
||||||
import im.vector.app.core.di.ActiveSessionHolder
|
import im.vector.app.core.di.ActiveSessionHolder
|
||||||
import im.vector.app.core.utils.BehaviorDataSource
|
import im.vector.app.core.utils.BehaviorDataSource
|
||||||
import im.vector.app.features.analytics.AnalyticsTracker
|
import im.vector.app.features.analytics.AnalyticsTracker
|
||||||
@ -42,6 +41,8 @@ import org.matrix.android.sdk.api.session.getRoom
|
|||||||
import org.matrix.android.sdk.api.session.getRoomSummary
|
import org.matrix.android.sdk.api.session.getRoomSummary
|
||||||
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
import org.matrix.android.sdk.api.session.room.model.RoomSummary
|
||||||
import org.matrix.android.sdk.api.session.sync.SyncRequestState
|
import org.matrix.android.sdk.api.session.sync.SyncRequestState
|
||||||
|
import org.matrix.android.sdk.api.util.Optional
|
||||||
|
import org.matrix.android.sdk.api.util.toOption
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@ -59,7 +60,7 @@ class SpaceStateHandlerImpl @Inject constructor(
|
|||||||
) : SpaceStateHandler {
|
) : SpaceStateHandler {
|
||||||
|
|
||||||
private val coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
|
private val coroutineScope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
|
||||||
private val selectedSpaceDataSource = BehaviorDataSource<Option<RoomSummary>>(Option.empty())
|
private val selectedSpaceDataSource = BehaviorDataSource<Optional<RoomSummary>>(Optional.empty())
|
||||||
private val selectedSpaceFlow = selectedSpaceDataSource.stream()
|
private val selectedSpaceFlow = selectedSpaceDataSource.stream()
|
||||||
|
|
||||||
override fun getCurrentSpace(): RoomSummary? {
|
override fun getCurrentSpace(): RoomSummary? {
|
||||||
@ -98,11 +99,7 @@ class SpaceStateHandlerImpl @Inject constructor(
|
|||||||
uiStateRepository.storeSelectedSpace(spaceToSet?.roomId, activeSession.sessionId)
|
uiStateRepository.storeSelectedSpace(spaceToSet?.roomId, activeSession.sessionId)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (spaceToSet == null) {
|
selectedSpaceDataSource.post(spaceToSet.toOption())
|
||||||
selectedSpaceDataSource.post(Option.empty())
|
|
||||||
} else {
|
|
||||||
selectedSpaceDataSource.post(Option.just(spaceToSet))
|
|
||||||
}
|
|
||||||
|
|
||||||
if (spaceId != null) {
|
if (spaceId != null) {
|
||||||
activeSession.coroutineScope.launch(Dispatchers.IO) {
|
activeSession.coroutineScope.launch(Dispatchers.IO) {
|
||||||
|
@ -19,19 +19,19 @@ package im.vector.app.core.animations
|
|||||||
import android.animation.Animator
|
import android.animation.Animator
|
||||||
|
|
||||||
open class SimpleAnimatorListener : Animator.AnimatorListener {
|
open class SimpleAnimatorListener : Animator.AnimatorListener {
|
||||||
override fun onAnimationRepeat(animation: Animator?) {
|
override fun onAnimationRepeat(animation: Animator) {
|
||||||
// No op
|
// No op
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onAnimationEnd(animation: Animator?) {
|
override fun onAnimationEnd(animation: Animator) {
|
||||||
// No op
|
// No op
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onAnimationCancel(animation: Animator?) {
|
override fun onAnimationCancel(animation: Animator) {
|
||||||
// No op
|
// No op
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onAnimationStart(animation: Animator?) {
|
override fun onAnimationStart(animation: Animator) {
|
||||||
// No op
|
// No op
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,12 +17,11 @@
|
|||||||
package im.vector.app.core.di
|
package im.vector.app.core.di
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import arrow.core.Option
|
|
||||||
import im.vector.app.ActiveSessionDataSource
|
import im.vector.app.ActiveSessionDataSource
|
||||||
import im.vector.app.core.extensions.configureAndStart
|
|
||||||
import im.vector.app.core.extensions.startSyncing
|
import im.vector.app.core.extensions.startSyncing
|
||||||
import im.vector.app.core.pushers.UnifiedPushHelper
|
import im.vector.app.core.pushers.UnifiedPushHelper
|
||||||
import im.vector.app.core.services.GuardServiceStarter
|
import im.vector.app.core.services.GuardServiceStarter
|
||||||
|
import im.vector.app.core.session.ConfigureAndStartSessionUseCase
|
||||||
import im.vector.app.features.call.webrtc.WebRtcCallManager
|
import im.vector.app.features.call.webrtc.WebRtcCallManager
|
||||||
import im.vector.app.features.crypto.keysrequest.KeyRequestHandler
|
import im.vector.app.features.crypto.keysrequest.KeyRequestHandler
|
||||||
import im.vector.app.features.crypto.verification.IncomingVerificationRequestHandler
|
import im.vector.app.features.crypto.verification.IncomingVerificationRequestHandler
|
||||||
@ -31,6 +30,8 @@ import im.vector.app.features.session.SessionListener
|
|||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import org.matrix.android.sdk.api.auth.AuthenticationService
|
import org.matrix.android.sdk.api.auth.AuthenticationService
|
||||||
import org.matrix.android.sdk.api.session.Session
|
import org.matrix.android.sdk.api.session.Session
|
||||||
|
import org.matrix.android.sdk.api.util.Optional
|
||||||
|
import org.matrix.android.sdk.api.util.toOption
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.util.concurrent.atomic.AtomicReference
|
import java.util.concurrent.atomic.AtomicReference
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
@ -50,6 +51,7 @@ class ActiveSessionHolder @Inject constructor(
|
|||||||
private val sessionInitializer: SessionInitializer,
|
private val sessionInitializer: SessionInitializer,
|
||||||
private val applicationContext: Context,
|
private val applicationContext: Context,
|
||||||
private val authenticationService: AuthenticationService,
|
private val authenticationService: AuthenticationService,
|
||||||
|
private val configureAndStartSessionUseCase: ConfigureAndStartSessionUseCase,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
private var activeSessionReference: AtomicReference<Session?> = AtomicReference()
|
private var activeSessionReference: AtomicReference<Session?> = AtomicReference()
|
||||||
@ -57,7 +59,7 @@ class ActiveSessionHolder @Inject constructor(
|
|||||||
fun setActiveSession(session: Session) {
|
fun setActiveSession(session: Session) {
|
||||||
Timber.w("setActiveSession of ${session.myUserId}")
|
Timber.w("setActiveSession of ${session.myUserId}")
|
||||||
activeSessionReference.set(session)
|
activeSessionReference.set(session)
|
||||||
activeSessionDataSource.post(Option.just(session))
|
activeSessionDataSource.post(session.toOption())
|
||||||
|
|
||||||
keyRequestHandler.start(session)
|
keyRequestHandler.start(session)
|
||||||
incomingVerificationRequestHandler.start(session)
|
incomingVerificationRequestHandler.start(session)
|
||||||
@ -77,7 +79,7 @@ class ActiveSessionHolder @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
activeSessionReference.set(null)
|
activeSessionReference.set(null)
|
||||||
activeSessionDataSource.post(Option.empty())
|
activeSessionDataSource.post(Optional.empty())
|
||||||
|
|
||||||
keyRequestHandler.stop()
|
keyRequestHandler.stop()
|
||||||
incomingVerificationRequestHandler.stop()
|
incomingVerificationRequestHandler.stop()
|
||||||
@ -109,7 +111,9 @@ class ActiveSessionHolder @Inject constructor(
|
|||||||
}
|
}
|
||||||
?: sessionInitializer.tryInitialize(readCurrentSession = { activeSessionReference.get() }) { session ->
|
?: sessionInitializer.tryInitialize(readCurrentSession = { activeSessionReference.get() }) { session ->
|
||||||
setActiveSession(session)
|
setActiveSession(session)
|
||||||
session.configureAndStart(applicationContext, startSyncing = startSync)
|
runBlocking {
|
||||||
|
configureAndStartSessionUseCase.execute(session, startSyncing = startSync)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@ import android.os.Parcelable
|
|||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import im.vector.app.core.platform.DefaultListUpdateCallback
|
import im.vector.app.core.platform.DefaultListUpdateCallback
|
||||||
import im.vector.app.core.platform.Restorable
|
import im.vector.app.core.platform.Restorable
|
||||||
|
import im.vector.lib.core.utils.compat.getParcelableCompat
|
||||||
import java.util.concurrent.atomic.AtomicReference
|
import java.util.concurrent.atomic.AtomicReference
|
||||||
|
|
||||||
private const val LAYOUT_MANAGER_STATE = "LAYOUT_MANAGER_STATE"
|
private const val LAYOUT_MANAGER_STATE = "LAYOUT_MANAGER_STATE"
|
||||||
@ -44,7 +45,7 @@ class LayoutManagerStateRestorer(layoutManager: RecyclerView.LayoutManager) : Re
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onRestoreInstanceState(savedInstanceState: Bundle?) {
|
override fun onRestoreInstanceState(savedInstanceState: Bundle?) {
|
||||||
val parcelable = savedInstanceState?.getParcelable<Parcelable>(LAYOUT_MANAGER_STATE)
|
val parcelable = savedInstanceState?.getParcelableCompat<Parcelable>(LAYOUT_MANAGER_STATE)
|
||||||
layoutManagerState.set(parcelable)
|
layoutManagerState.set(parcelable)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@ import com.airbnb.mvrx.MavericksViewModelProvider
|
|||||||
|
|
||||||
inline fun <reified VM : MavericksViewModel<S>, reified S : MavericksState> ComponentActivity.lazyViewModel(): Lazy<VM> {
|
inline fun <reified VM : MavericksViewModel<S>, reified S : MavericksState> ComponentActivity.lazyViewModel(): Lazy<VM> {
|
||||||
return lazy(mode = LazyThreadSafetyMode.NONE) {
|
return lazy(mode = LazyThreadSafetyMode.NONE) {
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
MavericksViewModelProvider.get(
|
MavericksViewModelProvider.get(
|
||||||
viewModelClass = VM::class.java,
|
viewModelClass = VM::class.java,
|
||||||
stateClass = S::class.java,
|
stateClass = S::class.java,
|
||||||
|
@ -24,20 +24,8 @@ import im.vector.app.core.services.VectorSyncAndroidService
|
|||||||
import im.vector.app.features.session.VectorSessionStore
|
import im.vector.app.features.session.VectorSessionStore
|
||||||
import org.matrix.android.sdk.api.session.Session
|
import org.matrix.android.sdk.api.session.Session
|
||||||
import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupState
|
import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupState
|
||||||
import org.matrix.android.sdk.api.session.sync.FilterService
|
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
fun Session.configureAndStart(context: Context, startSyncing: Boolean = true) {
|
|
||||||
Timber.i("Configure and start session for $myUserId. startSyncing: $startSyncing")
|
|
||||||
open()
|
|
||||||
filterService().setFilter(FilterService.FilterPreset.ElementFilter)
|
|
||||||
if (startSyncing) {
|
|
||||||
startSyncing(context)
|
|
||||||
}
|
|
||||||
pushersService().refreshPushers()
|
|
||||||
context.singletonEntryPoint().webRtcCallManager().checkForProtocolsSupportIfNeeded()
|
|
||||||
}
|
|
||||||
|
|
||||||
fun Session.startSyncing(context: Context) {
|
fun Session.startSyncing(context: Context) {
|
||||||
val applicationContext = context.applicationContext
|
val applicationContext = context.applicationContext
|
||||||
if (!syncService().hasAlreadySynced()) {
|
if (!syncService().hasAlreadySynced()) {
|
||||||
|
@ -22,6 +22,7 @@ import android.animation.ValueAnimator
|
|||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.animation.AccelerateDecelerateInterpolator
|
import android.view.animation.AccelerateDecelerateInterpolator
|
||||||
import androidx.viewpager2.widget.ViewPager2
|
import androidx.viewpager2.widget.ViewPager2
|
||||||
|
import im.vector.app.core.animations.SimpleAnimatorListener
|
||||||
|
|
||||||
fun ViewPager2.setCurrentItem(
|
fun ViewPager2.setCurrentItem(
|
||||||
item: Int,
|
item: Int,
|
||||||
@ -45,19 +46,16 @@ fun ViewPager2.setCurrentItem(
|
|||||||
previousValue = currentValue
|
previousValue = currentValue
|
||||||
}.onFailure { animator.cancel() }
|
}.onFailure { animator.cancel() }
|
||||||
}
|
}
|
||||||
animator.addListener(object : Animator.AnimatorListener {
|
animator.addListener(object : SimpleAnimatorListener() {
|
||||||
override fun onAnimationStart(animation: Animator?) {
|
override fun onAnimationStart(animation: Animator) {
|
||||||
isUserInputEnabled = false
|
isUserInputEnabled = false
|
||||||
beginFakeDrag()
|
beginFakeDrag()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onAnimationEnd(animation: Animator?) {
|
override fun onAnimationEnd(animation: Animator) {
|
||||||
isUserInputEnabled = true
|
isUserInputEnabled = true
|
||||||
endFakeDrag()
|
endFakeDrag()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onAnimationCancel(animation: Animator?) = Unit
|
|
||||||
override fun onAnimationRepeat(animation: Animator?) = Unit
|
|
||||||
})
|
})
|
||||||
animator.interpolator = interpolator
|
animator.interpolator = interpolator
|
||||||
animator.duration = duration
|
animator.duration = duration
|
||||||
|
@ -24,7 +24,6 @@ import android.os.Build
|
|||||||
import android.provider.MediaStore
|
import android.provider.MediaStore
|
||||||
import androidx.annotation.WorkerThread
|
import androidx.annotation.WorkerThread
|
||||||
import androidx.core.content.getSystemService
|
import androidx.core.content.getSystemService
|
||||||
import arrow.core.Try
|
|
||||||
import okio.buffer
|
import okio.buffer
|
||||||
import okio.sink
|
import okio.sink
|
||||||
import okio.source
|
import okio.source
|
||||||
@ -35,11 +34,10 @@ import java.io.File
|
|||||||
* Save a string to a file with Okio.
|
* Save a string to a file with Okio.
|
||||||
*/
|
*/
|
||||||
@WorkerThread
|
@WorkerThread
|
||||||
fun writeToFile(str: String, file: File): Try<Unit> {
|
@Throws
|
||||||
return Try<Unit> {
|
fun writeToFile(str: String, file: File) {
|
||||||
file.sink().buffer().use {
|
file.sink().buffer().use {
|
||||||
it.writeString(str, Charsets.UTF_8)
|
it.writeString(str, Charsets.UTF_8)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,11 +45,10 @@ fun writeToFile(str: String, file: File): Try<Unit> {
|
|||||||
* Save a byte array to a file with Okio.
|
* Save a byte array to a file with Okio.
|
||||||
*/
|
*/
|
||||||
@WorkerThread
|
@WorkerThread
|
||||||
fun writeToFile(data: ByteArray, file: File): Try<Unit> {
|
@Throws
|
||||||
return Try<Unit> {
|
fun writeToFile(data: ByteArray, file: File) {
|
||||||
file.sink().buffer().use {
|
file.sink().buffer().use {
|
||||||
it.write(data)
|
it.write(data)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,6 +83,7 @@ abstract class SimpleFragmentActivity : VectorBaseActivity<ActivityBinding>() {
|
|||||||
// ignore
|
// ignore
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
super.onBackPressed()
|
super.onBackPressed()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -505,6 +505,7 @@ abstract class VectorBaseActivity<VB : ViewBinding> : AppCompatActivity(), Maver
|
|||||||
private fun onBackPressed(fromToolbar: Boolean) {
|
private fun onBackPressed(fromToolbar: Boolean) {
|
||||||
val handled = recursivelyDispatchOnBackPressed(supportFragmentManager, fromToolbar)
|
val handled = recursivelyDispatchOnBackPressed(supportFragmentManager, fromToolbar)
|
||||||
if (!handled) {
|
if (!handled) {
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
super.onBackPressed()
|
super.onBackPressed()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ import im.vector.app.core.resources.AppNameProvider
|
|||||||
import im.vector.app.core.resources.LocaleProvider
|
import im.vector.app.core.resources.LocaleProvider
|
||||||
import im.vector.app.core.resources.StringProvider
|
import im.vector.app.core.resources.StringProvider
|
||||||
import org.matrix.android.sdk.api.session.pushers.HttpPusher
|
import org.matrix.android.sdk.api.session.pushers.HttpPusher
|
||||||
|
import org.matrix.android.sdk.api.session.pushers.Pusher
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
import kotlin.math.abs
|
import kotlin.math.abs
|
||||||
@ -90,6 +91,18 @@ class PushersManager @Inject constructor(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getPusherForCurrentSession(): Pusher? {
|
||||||
|
val session = activeSessionHolder.getSafeActiveSession() ?: return null
|
||||||
|
val deviceId = session.sessionParams.deviceId
|
||||||
|
return session.pushersService().getPushers().firstOrNull { it.deviceId == deviceId }
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun togglePusherForCurrentSession(enable: Boolean) {
|
||||||
|
val session = activeSessionHolder.getSafeActiveSession() ?: return
|
||||||
|
val pusher = getPusherForCurrentSession() ?: return
|
||||||
|
session.pushersService().togglePusher(pusher, enable)
|
||||||
|
}
|
||||||
|
|
||||||
suspend fun unregisterEmailPusher(email: String) {
|
suspend fun unregisterEmailPusher(email: String) {
|
||||||
val currentSession = activeSessionHolder.getSafeActiveSession() ?: return
|
val currentSession = activeSessionHolder.getSafeActiveSession() ?: return
|
||||||
currentSession.pushersService().removeEmailPusher(email)
|
currentSession.pushersService().removeEmailPusher(email)
|
||||||
|
@ -19,6 +19,7 @@ package im.vector.app.core.resources
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import androidx.annotation.NonNull
|
import androidx.annotation.NonNull
|
||||||
|
import org.matrix.android.sdk.api.util.getPackageInfoCompat
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class VersionCodeProvider @Inject constructor(private val context: Context) {
|
class VersionCodeProvider @Inject constructor(private val context: Context) {
|
||||||
@ -28,7 +29,7 @@ class VersionCodeProvider @Inject constructor(private val context: Context) {
|
|||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
fun getVersionCode(): Long {
|
fun getVersionCode(): Long {
|
||||||
val packageInfo = context.packageManager.getPackageInfo(context.packageName, 0)
|
val packageInfo = context.packageManager.getPackageInfoCompat(context.packageName, 0)
|
||||||
|
|
||||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||||
packageInfo.longVersionCode
|
packageInfo.longVersionCode
|
||||||
|
@ -23,6 +23,7 @@ import android.content.BroadcastReceiver
|
|||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.content.IntentFilter
|
import android.content.IntentFilter
|
||||||
|
import im.vector.lib.core.utils.compat.getParcelableExtraCompat
|
||||||
import java.lang.ref.WeakReference
|
import java.lang.ref.WeakReference
|
||||||
|
|
||||||
class BluetoothHeadsetReceiver : BroadcastReceiver() {
|
class BluetoothHeadsetReceiver : BroadcastReceiver() {
|
||||||
@ -59,7 +60,7 @@ class BluetoothHeadsetReceiver : BroadcastReceiver() {
|
|||||||
else -> return // ignore intermediate states
|
else -> return // ignore intermediate states
|
||||||
}
|
}
|
||||||
|
|
||||||
val device = intent.getParcelableExtra<BluetoothDevice>(BluetoothDevice.EXTRA_DEVICE)
|
val device = intent.getParcelableExtraCompat<BluetoothDevice>(BluetoothDevice.EXTRA_DEVICE)
|
||||||
val deviceName = device?.name
|
val deviceName = device?.name
|
||||||
when (device?.bluetoothClass?.deviceClass) {
|
when (device?.bluetoothClass?.deviceClass) {
|
||||||
BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE,
|
BluetoothClass.Device.AUDIO_VIDEO_HANDSFREE,
|
||||||
|
@ -39,6 +39,8 @@ import im.vector.app.features.home.AvatarRenderer
|
|||||||
import im.vector.app.features.notifications.NotificationUtils
|
import im.vector.app.features.notifications.NotificationUtils
|
||||||
import im.vector.app.features.popup.IncomingCallAlert
|
import im.vector.app.features.popup.IncomingCallAlert
|
||||||
import im.vector.app.features.popup.PopupAlertManager
|
import im.vector.app.features.popup.PopupAlertManager
|
||||||
|
import im.vector.lib.core.utils.compat.getParcelableExtraCompat
|
||||||
|
import im.vector.lib.core.utils.compat.getSerializableExtraCompat
|
||||||
import org.matrix.android.sdk.api.logger.LoggerTag
|
import org.matrix.android.sdk.api.logger.LoggerTag
|
||||||
import org.matrix.android.sdk.api.session.room.model.call.EndCallReason
|
import org.matrix.android.sdk.api.session.room.model.call.EndCallReason
|
||||||
import org.matrix.android.sdk.api.util.MatrixItem
|
import org.matrix.android.sdk.api.util.MatrixItem
|
||||||
@ -71,7 +73,7 @@ class CallAndroidService : VectorAndroidService() {
|
|||||||
private var mediaSession: MediaSessionCompat? = null
|
private var mediaSession: MediaSessionCompat? = null
|
||||||
private val mediaSessionButtonCallback = object : MediaSessionCompat.Callback() {
|
private val mediaSessionButtonCallback = object : MediaSessionCompat.Callback() {
|
||||||
override fun onMediaButtonEvent(mediaButtonEvent: Intent?): Boolean {
|
override fun onMediaButtonEvent(mediaButtonEvent: Intent?): Boolean {
|
||||||
val keyEvent = mediaButtonEvent?.getParcelableExtra<KeyEvent>(Intent.EXTRA_KEY_EVENT) ?: return false
|
val keyEvent = mediaButtonEvent?.getParcelableExtraCompat<KeyEvent>(Intent.EXTRA_KEY_EVENT) ?: return false
|
||||||
if (keyEvent.keyCode == KeyEvent.KEYCODE_HEADSETHOOK) {
|
if (keyEvent.keyCode == KeyEvent.KEYCODE_HEADSETHOOK) {
|
||||||
callManager.headSetButtonTapped()
|
callManager.headSetButtonTapped()
|
||||||
return true
|
return true
|
||||||
@ -158,7 +160,7 @@ class CallAndroidService : VectorAndroidService() {
|
|||||||
val incomingCallAlert = IncomingCallAlert(callId,
|
val incomingCallAlert = IncomingCallAlert(callId,
|
||||||
shouldBeDisplayedIn = { activity ->
|
shouldBeDisplayedIn = { activity ->
|
||||||
if (activity is VectorCallActivity) {
|
if (activity is VectorCallActivity) {
|
||||||
activity.intent.getParcelableExtra<CallArgs>(Mavericks.KEY_ARG)?.callId != call.callId
|
activity.intent.getParcelableExtraCompat<CallArgs>(Mavericks.KEY_ARG)?.callId != call.callId
|
||||||
} else true
|
} else true
|
||||||
}
|
}
|
||||||
).apply {
|
).apply {
|
||||||
@ -188,7 +190,7 @@ class CallAndroidService : VectorAndroidService() {
|
|||||||
|
|
||||||
private fun handleCallTerminated(intent: Intent) {
|
private fun handleCallTerminated(intent: Intent) {
|
||||||
val callId = intent.getStringExtra(EXTRA_CALL_ID) ?: ""
|
val callId = intent.getStringExtra(EXTRA_CALL_ID) ?: ""
|
||||||
val endCallReason = intent.getSerializableExtra(EXTRA_END_CALL_REASON) as EndCallReason
|
val endCallReason = intent.getSerializableExtraCompat<EndCallReason>(EXTRA_END_CALL_REASON)
|
||||||
val rejected = intent.getBooleanExtra(EXTRA_END_CALL_REJECTED, false)
|
val rejected = intent.getBooleanExtra(EXTRA_END_CALL_REJECTED, false)
|
||||||
alertManager.cancelAlert(callId)
|
alertManager.cancelAlert(callId)
|
||||||
val terminatedCall = knownCalls.remove(callId)
|
val terminatedCall = knownCalls.remove(callId)
|
||||||
@ -202,7 +204,7 @@ class CallAndroidService : VectorAndroidService() {
|
|||||||
startForeground(notificationId, notification)
|
startForeground(notificationId, notification)
|
||||||
if (knownCalls.isEmpty()) {
|
if (knownCalls.isEmpty()) {
|
||||||
Timber.tag(loggerTag.value).v("No more call, stop the service")
|
Timber.tag(loggerTag.value).v("No more call, stop the service")
|
||||||
stopForeground(true)
|
stopForegroundCompat()
|
||||||
mediaSession?.isActive = false
|
mediaSession?.isActive = false
|
||||||
myStopSelf()
|
myStopSelf()
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,7 @@ package im.vector.app.core.services
|
|||||||
|
|
||||||
import android.app.Service
|
import android.app.Service
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
|
import android.os.Build
|
||||||
import android.os.IBinder
|
import android.os.IBinder
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
@ -55,4 +56,13 @@ abstract class VectorAndroidService : Service() {
|
|||||||
override fun onBind(intent: Intent?): IBinder? {
|
override fun onBind(intent: Intent?): IBinder? {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected fun stopForegroundCompat() {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||||
|
stopForeground(STOP_FOREGROUND_REMOVE)
|
||||||
|
} else {
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
stopForeground(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package im.vector.app.core.session
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
|
import im.vector.app.core.extensions.startSyncing
|
||||||
|
import im.vector.app.core.session.clientinfo.UpdateMatrixClientInfoUseCase
|
||||||
|
import im.vector.app.features.call.webrtc.WebRtcCallManager
|
||||||
|
import org.matrix.android.sdk.api.session.Session
|
||||||
|
import org.matrix.android.sdk.api.session.sync.FilterService
|
||||||
|
import timber.log.Timber
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
class ConfigureAndStartSessionUseCase @Inject constructor(
|
||||||
|
@ApplicationContext private val context: Context,
|
||||||
|
private val webRtcCallManager: WebRtcCallManager,
|
||||||
|
private val updateMatrixClientInfoUseCase: UpdateMatrixClientInfoUseCase,
|
||||||
|
) {
|
||||||
|
|
||||||
|
suspend fun execute(session: Session, startSyncing: Boolean = true) {
|
||||||
|
Timber.i("Configure and start session for ${session.myUserId}. startSyncing: $startSyncing")
|
||||||
|
session.open()
|
||||||
|
session.filterService().setFilter(FilterService.FilterPreset.ElementFilter)
|
||||||
|
if (startSyncing) {
|
||||||
|
session.startSyncing(context)
|
||||||
|
}
|
||||||
|
session.pushersService().refreshPushers()
|
||||||
|
webRtcCallManager.checkForProtocolsSupportIfNeeded()
|
||||||
|
updateMatrixClientInfoUseCase.execute(session)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package im.vector.app.core.session.clientinfo
|
||||||
|
|
||||||
|
import org.matrix.android.sdk.api.session.Session
|
||||||
|
import org.matrix.android.sdk.api.session.events.model.toModel
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This use case retrieves the current account data event containing extended client info
|
||||||
|
* for a given deviceId.
|
||||||
|
*/
|
||||||
|
class GetMatrixClientInfoUseCase @Inject constructor() {
|
||||||
|
|
||||||
|
fun execute(session: Session, deviceId: String): MatrixClientInfoContent? {
|
||||||
|
val type = MATRIX_CLIENT_INFO_KEY_PREFIX + deviceId
|
||||||
|
val content = session.accountDataService().getUserAccountDataEvent(type)?.content
|
||||||
|
return content.toModel()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package im.vector.app.core.session.clientinfo
|
||||||
|
|
||||||
|
import com.squareup.moshi.Json
|
||||||
|
import com.squareup.moshi.JsonClass
|
||||||
|
|
||||||
|
@JsonClass(generateAdapter = true)
|
||||||
|
data class MatrixClientInfoContent(
|
||||||
|
// app name
|
||||||
|
@Json(name = "name")
|
||||||
|
val name: String? = null,
|
||||||
|
// app version
|
||||||
|
@Json(name = "version")
|
||||||
|
val version: String? = null,
|
||||||
|
// app url (optional, applicable only for web)
|
||||||
|
@Json(name = "url")
|
||||||
|
val url: String? = null,
|
||||||
|
)
|
@ -0,0 +1,19 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package im.vector.app.core.session.clientinfo
|
||||||
|
|
||||||
|
class NoDeviceIdError : IllegalStateException("device id is empty")
|
@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package im.vector.app.core.session.clientinfo
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prefix for the key account data event which holds client info.
|
||||||
|
*/
|
||||||
|
internal const val MATRIX_CLIENT_INFO_KEY_PREFIX = "io.element.matrix_client_information."
|
@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package im.vector.app.core.session.clientinfo
|
||||||
|
|
||||||
|
import org.matrix.android.sdk.api.session.Session
|
||||||
|
import org.matrix.android.sdk.api.session.events.model.toContent
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This use case sets the account data event containing extended client info.
|
||||||
|
*/
|
||||||
|
class SetMatrixClientInfoUseCase @Inject constructor() {
|
||||||
|
|
||||||
|
suspend fun execute(session: Session, clientInfo: MatrixClientInfoContent): Result<Unit> = runCatching {
|
||||||
|
val deviceId = session.sessionParams.deviceId.orEmpty()
|
||||||
|
if (deviceId.isNotEmpty()) {
|
||||||
|
val type = MATRIX_CLIENT_INFO_KEY_PREFIX + deviceId
|
||||||
|
session.accountDataService()
|
||||||
|
.updateUserAccountData(type, clientInfo.toContent())
|
||||||
|
} else {
|
||||||
|
throw NoDeviceIdError()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package im.vector.app.core.session.clientinfo
|
||||||
|
|
||||||
|
import im.vector.app.core.resources.AppNameProvider
|
||||||
|
import im.vector.app.core.resources.BuildMeta
|
||||||
|
import org.matrix.android.sdk.api.session.Session
|
||||||
|
import timber.log.Timber
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This use case updates if needed the account data event containing extended client info.
|
||||||
|
*/
|
||||||
|
class UpdateMatrixClientInfoUseCase @Inject constructor(
|
||||||
|
private val appNameProvider: AppNameProvider,
|
||||||
|
private val buildMeta: BuildMeta,
|
||||||
|
private val getMatrixClientInfoUseCase: GetMatrixClientInfoUseCase,
|
||||||
|
private val setMatrixClientInfoUseCase: SetMatrixClientInfoUseCase,
|
||||||
|
) {
|
||||||
|
|
||||||
|
suspend fun execute(session: Session) = runCatching {
|
||||||
|
val clientInfo = MatrixClientInfoContent(
|
||||||
|
name = appNameProvider.getAppName(),
|
||||||
|
version = buildMeta.versionName
|
||||||
|
)
|
||||||
|
val deviceId = session.sessionParams.deviceId.orEmpty()
|
||||||
|
if (deviceId.isNotEmpty()) {
|
||||||
|
val storedClientInfo = getMatrixClientInfoUseCase.execute(session, deviceId)
|
||||||
|
Timber.d("storedClientInfo=$storedClientInfo, current client info=$clientInfo")
|
||||||
|
if (clientInfo != storedClientInfo) {
|
||||||
|
Timber.d("client info need to be updated")
|
||||||
|
return setMatrixClientInfoUseCase.execute(session, clientInfo)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw NoDeviceIdError()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -34,6 +34,7 @@ import androidx.core.content.getSystemService
|
|||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.features.notifications.NotificationUtils
|
import im.vector.app.features.notifications.NotificationUtils
|
||||||
|
import org.matrix.android.sdk.api.util.getApplicationInfoCompat
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tells if the application ignores battery optimizations.
|
* Tells if the application ignores battery optimizations.
|
||||||
@ -63,7 +64,7 @@ fun Context.isAnimationEnabled(): Boolean {
|
|||||||
*/
|
*/
|
||||||
fun Context.getApplicationLabel(packageName: String): String {
|
fun Context.getApplicationLabel(packageName: String): String {
|
||||||
return try {
|
return try {
|
||||||
val ai = packageManager.getApplicationInfo(packageName, 0)
|
val ai = packageManager.getApplicationInfoCompat(packageName, 0)
|
||||||
packageManager.getApplicationLabel(ai).toString()
|
packageManager.getApplicationLabel(ai).toString()
|
||||||
} catch (e: PackageManager.NameNotFoundException) {
|
} catch (e: PackageManager.NameNotFoundException) {
|
||||||
packageName
|
packageName
|
||||||
|
@ -57,6 +57,7 @@ import im.vector.app.features.start.StartAppViewModel
|
|||||||
import im.vector.app.features.start.StartAppViewState
|
import im.vector.app.features.start.StartAppViewState
|
||||||
import im.vector.app.features.themes.ActivityOtherThemes
|
import im.vector.app.features.themes.ActivityOtherThemes
|
||||||
import im.vector.app.features.ui.UiStateRepository
|
import im.vector.app.features.ui.UiStateRepository
|
||||||
|
import im.vector.lib.core.utils.compat.getParcelableExtraCompat
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
@ -181,7 +182,7 @@ class MainActivity : VectorBaseActivity<ActivityMainBinding>(), UnlockedActivity
|
|||||||
private fun handleAppStarted() {
|
private fun handleAppStarted() {
|
||||||
if (intent.hasExtra(EXTRA_NEXT_INTENT)) {
|
if (intent.hasExtra(EXTRA_NEXT_INTENT)) {
|
||||||
// Start the next Activity
|
// Start the next Activity
|
||||||
val nextIntent = intent.getParcelableExtra<Intent>(EXTRA_NEXT_INTENT)
|
val nextIntent = intent.getParcelableExtraCompat<Intent>(EXTRA_NEXT_INTENT)
|
||||||
startIntentAndFinish(nextIntent)
|
startIntentAndFinish(nextIntent)
|
||||||
} else if (intent.hasExtra(EXTRA_INIT_SESSION)) {
|
} else if (intent.hasExtra(EXTRA_INIT_SESSION)) {
|
||||||
setResult(RESULT_OK)
|
setResult(RESULT_OK)
|
||||||
@ -218,7 +219,7 @@ class MainActivity : VectorBaseActivity<ActivityMainBinding>(), UnlockedActivity
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun parseArgs(): MainActivityArgs {
|
private fun parseArgs(): MainActivityArgs {
|
||||||
val argsFromIntent: MainActivityArgs? = intent.getParcelableExtra(EXTRA_ARGS)
|
val argsFromIntent: MainActivityArgs? = intent.getParcelableExtraCompat(EXTRA_ARGS)
|
||||||
Timber.w("Starting MainActivity with $argsFromIntent")
|
Timber.w("Starting MainActivity with $argsFromIntent")
|
||||||
|
|
||||||
return MainActivityArgs(
|
return MainActivityArgs(
|
||||||
|
@ -40,7 +40,6 @@ interface VectorFeatures {
|
|||||||
* use [VectorPreferences.isNewAppLayoutEnabled] instead.
|
* use [VectorPreferences.isNewAppLayoutEnabled] instead.
|
||||||
*/
|
*/
|
||||||
fun isNewAppLayoutFeatureEnabled(): Boolean
|
fun isNewAppLayoutFeatureEnabled(): Boolean
|
||||||
fun isNewDeviceManagementEnabled(): Boolean
|
|
||||||
fun isQrCodeLoginEnabled(): Boolean
|
fun isQrCodeLoginEnabled(): Boolean
|
||||||
fun allowQrCodeLoginForAllServers(): Boolean
|
fun allowQrCodeLoginForAllServers(): Boolean
|
||||||
fun allowReciprocateQrCodeLogin(): Boolean
|
fun allowReciprocateQrCodeLogin(): Boolean
|
||||||
@ -60,7 +59,6 @@ class DefaultVectorFeatures : VectorFeatures {
|
|||||||
override fun isLocationSharingEnabled() = Config.ENABLE_LOCATION_SHARING
|
override fun isLocationSharingEnabled() = Config.ENABLE_LOCATION_SHARING
|
||||||
override fun forceUsageOfOpusEncoder(): Boolean = false
|
override fun forceUsageOfOpusEncoder(): Boolean = false
|
||||||
override fun isNewAppLayoutFeatureEnabled(): Boolean = true
|
override fun isNewAppLayoutFeatureEnabled(): Boolean = true
|
||||||
override fun isNewDeviceManagementEnabled(): Boolean = false
|
|
||||||
override fun isQrCodeLoginEnabled(): Boolean = false
|
override fun isQrCodeLoginEnabled(): Boolean = false
|
||||||
override fun allowQrCodeLoginForAllServers(): Boolean = false
|
override fun allowQrCodeLoginForAllServers(): Boolean = false
|
||||||
override fun allowReciprocateQrCodeLogin(): Boolean = false
|
override fun allowReciprocateQrCodeLogin(): Boolean = false
|
||||||
|
@ -26,6 +26,8 @@ import im.vector.app.core.dialogs.PhotoOrVideoDialog
|
|||||||
import im.vector.app.core.platform.Restorable
|
import im.vector.app.core.platform.Restorable
|
||||||
import im.vector.app.core.resources.BuildMeta
|
import im.vector.app.core.resources.BuildMeta
|
||||||
import im.vector.app.features.settings.VectorPreferences
|
import im.vector.app.features.settings.VectorPreferences
|
||||||
|
import im.vector.lib.core.utils.compat.getParcelableCompat
|
||||||
|
import im.vector.lib.core.utils.compat.getSerializableCompat
|
||||||
import im.vector.lib.multipicker.MultiPicker
|
import im.vector.lib.multipicker.MultiPicker
|
||||||
import org.matrix.android.sdk.api.session.content.ContentAttachmentData
|
import org.matrix.android.sdk.api.session.content.ContentAttachmentData
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
@ -66,8 +68,8 @@ class AttachmentsHelper(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onRestoreInstanceState(savedInstanceState: Bundle?) {
|
override fun onRestoreInstanceState(savedInstanceState: Bundle?) {
|
||||||
captureUri = savedInstanceState?.getParcelable(CAPTURE_PATH_KEY) as? Uri
|
captureUri = savedInstanceState?.getParcelableCompat(CAPTURE_PATH_KEY)
|
||||||
pendingType = savedInstanceState?.getSerializable(PENDING_TYPE_KEY) as? AttachmentTypeSelectorView.Type
|
pendingType = savedInstanceState?.getSerializableCompat(PENDING_TYPE_KEY)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Public Methods
|
// Public Methods
|
||||||
|
@ -24,6 +24,8 @@ import im.vector.app.core.extensions.addFragment
|
|||||||
import im.vector.app.core.platform.VectorBaseActivity
|
import im.vector.app.core.platform.VectorBaseActivity
|
||||||
import im.vector.app.databinding.ActivitySimpleBinding
|
import im.vector.app.databinding.ActivitySimpleBinding
|
||||||
import im.vector.app.features.themes.ActivityOtherThemes
|
import im.vector.app.features.themes.ActivityOtherThemes
|
||||||
|
import im.vector.lib.core.utils.compat.getParcelableArrayListExtraCompat
|
||||||
|
import im.vector.lib.core.utils.compat.getParcelableCompat
|
||||||
import org.matrix.android.sdk.api.session.content.ContentAttachmentData
|
import org.matrix.android.sdk.api.session.content.ContentAttachmentData
|
||||||
|
|
||||||
@AndroidEntryPoint
|
@AndroidEntryPoint
|
||||||
@ -41,7 +43,7 @@ class AttachmentsPreviewActivity : VectorBaseActivity<ActivitySimpleBinding>() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getOutput(intent: Intent): List<ContentAttachmentData> {
|
fun getOutput(intent: Intent): List<ContentAttachmentData> {
|
||||||
return intent.getParcelableArrayListExtra<ContentAttachmentData>(ATTACHMENTS_PREVIEW_RESULT).orEmpty()
|
return intent.getParcelableArrayListExtraCompat<ContentAttachmentData>(ATTACHMENTS_PREVIEW_RESULT).orEmpty()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getKeepOriginalSize(intent: Intent): Boolean {
|
fun getKeepOriginalSize(intent: Intent): Boolean {
|
||||||
@ -57,7 +59,7 @@ class AttachmentsPreviewActivity : VectorBaseActivity<ActivitySimpleBinding>() {
|
|||||||
|
|
||||||
override fun initUiAndData() {
|
override fun initUiAndData() {
|
||||||
if (isFirstCreation()) {
|
if (isFirstCreation()) {
|
||||||
val fragmentArgs: AttachmentsPreviewArgs = intent?.extras?.getParcelable(EXTRA_FRAGMENT_ARGS) ?: return
|
val fragmentArgs: AttachmentsPreviewArgs = intent?.extras?.getParcelableCompat(EXTRA_FRAGMENT_ARGS) ?: return
|
||||||
addFragment(views.simpleFragmentContainer, AttachmentsPreviewFragment::class.java, fragmentArgs)
|
addFragment(views.simpleFragmentContainer, AttachmentsPreviewFragment::class.java, fragmentArgs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -69,6 +69,7 @@ import im.vector.app.features.displayname.getBestName
|
|||||||
import im.vector.app.features.home.AvatarRenderer
|
import im.vector.app.features.home.AvatarRenderer
|
||||||
import im.vector.app.features.home.room.detail.RoomDetailActivity
|
import im.vector.app.features.home.room.detail.RoomDetailActivity
|
||||||
import im.vector.app.features.home.room.detail.arguments.TimelineArgs
|
import im.vector.app.features.home.room.detail.arguments.TimelineArgs
|
||||||
|
import im.vector.lib.core.utils.compat.getParcelableExtraCompat
|
||||||
import io.github.hyuwah.draggableviewlib.DraggableView
|
import io.github.hyuwah.draggableviewlib.DraggableView
|
||||||
import io.github.hyuwah.draggableviewlib.setupDraggable
|
import io.github.hyuwah.draggableviewlib.setupDraggable
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
@ -178,7 +179,7 @@ class VectorCallActivity :
|
|||||||
override fun onNewIntent(intent: Intent?) {
|
override fun onNewIntent(intent: Intent?) {
|
||||||
super.onNewIntent(intent)
|
super.onNewIntent(intent)
|
||||||
intent?.takeIf { it.hasExtra(Mavericks.KEY_ARG) }
|
intent?.takeIf { it.hasExtra(Mavericks.KEY_ARG) }
|
||||||
?.let { intent.getParcelableExtra<CallArgs>(Mavericks.KEY_ARG) }
|
?.let { intent.getParcelableExtraCompat<CallArgs>(Mavericks.KEY_ARG) }
|
||||||
?.let {
|
?.let {
|
||||||
callViewModel.handle(VectorCallViewActions.SwitchCall(it))
|
callViewModel.handle(VectorCallViewActions.SwitchCall(it))
|
||||||
}
|
}
|
||||||
@ -193,6 +194,7 @@ class VectorCallActivity :
|
|||||||
|
|
||||||
override fun onBackPressed() {
|
override fun onBackPressed() {
|
||||||
if (!enterPictureInPictureIfRequired()) {
|
if (!enterPictureInPictureIfRequired()) {
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
super.onBackPressed()
|
super.onBackPressed()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -230,6 +232,7 @@ class VectorCallActivity :
|
|||||||
}
|
}
|
||||||
android.R.id.home -> {
|
android.R.id.home -> {
|
||||||
// We check here as we want PiP in some cases
|
// We check here as we want PiP in some cases
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
onBackPressed()
|
onBackPressed()
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
@ -38,6 +38,7 @@ import dagger.hilt.android.AndroidEntryPoint
|
|||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.platform.VectorBaseActivity
|
import im.vector.app.core.platform.VectorBaseActivity
|
||||||
import im.vector.app.databinding.ActivityJitsiBinding
|
import im.vector.app.databinding.ActivityJitsiBinding
|
||||||
|
import im.vector.lib.core.utils.compat.getParcelableExtraCompat
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
import org.jitsi.meet.sdk.JitsiMeet
|
import org.jitsi.meet.sdk.JitsiMeet
|
||||||
import org.jitsi.meet.sdk.JitsiMeetActivityDelegate
|
import org.jitsi.meet.sdk.JitsiMeetActivityDelegate
|
||||||
@ -200,7 +201,7 @@ class VectorJitsiActivity : VectorBaseActivity<ActivityJitsiBinding>(), JitsiMee
|
|||||||
|
|
||||||
// Is it a switch to another conf?
|
// Is it a switch to another conf?
|
||||||
intent?.takeIf { it.hasExtra(Mavericks.KEY_ARG) }
|
intent?.takeIf { it.hasExtra(Mavericks.KEY_ARG) }
|
||||||
?.let { intent.getParcelableExtra<Args>(Mavericks.KEY_ARG) }
|
?.let { intent.getParcelableExtraCompat<Args>(Mavericks.KEY_ARG) }
|
||||||
?.let {
|
?.let {
|
||||||
jitsiViewModel.handle(JitsiCallViewActions.SwitchTo(it, true))
|
jitsiViewModel.handle(JitsiCallViewActions.SwitchTo(it, true))
|
||||||
}
|
}
|
||||||
|
@ -28,6 +28,7 @@ import im.vector.app.R
|
|||||||
import im.vector.app.core.error.ErrorFormatter
|
import im.vector.app.core.error.ErrorFormatter
|
||||||
import im.vector.app.core.platform.VectorBaseActivity
|
import im.vector.app.core.platform.VectorBaseActivity
|
||||||
import im.vector.app.databinding.ActivityCallTransferBinding
|
import im.vector.app.databinding.ActivityCallTransferBinding
|
||||||
|
import im.vector.lib.core.utils.compat.getParcelableCompat
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@ -112,7 +113,7 @@ class CallTransferActivity : VectorBaseActivity<ActivityCallTransferBinding>() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getCallTransferResult(intent: Intent?): CallTransferResult? {
|
fun getCallTransferResult(intent: Intent?): CallTransferResult? {
|
||||||
return intent?.extras?.getParcelable(EXTRA_TRANSFER_RESULT)
|
return intent?.extras?.getParcelableCompat(EXTRA_TRANSFER_RESULT)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -78,6 +78,7 @@ class CreateDirectRoomActivity : SimpleFragmentActivity() {
|
|||||||
sharedActionViewModel
|
sharedActionViewModel
|
||||||
.stream()
|
.stream()
|
||||||
.onEach { action ->
|
.onEach { action ->
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
when (action) {
|
when (action) {
|
||||||
UserListSharedAction.Close -> finish()
|
UserListSharedAction.Close -> finish()
|
||||||
UserListSharedAction.GoBack -> onBackPressed()
|
UserListSharedAction.GoBack -> onBackPressed()
|
||||||
|
@ -52,6 +52,7 @@ class KeysBackupRestoreActivity : SimpleFragmentActivity() {
|
|||||||
|
|
||||||
override fun onBackPressed() {
|
override fun onBackPressed() {
|
||||||
hideWaitingView()
|
hideWaitingView()
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
super.onBackPressed()
|
super.onBackPressed()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,6 +114,7 @@ class KeysBackupManageActivity : SimpleFragmentActivity() {
|
|||||||
finish()
|
finish()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
super.onBackPressed()
|
super.onBackPressed()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -183,6 +183,7 @@ class KeysBackupSetupActivity : SimpleFragmentActivity() {
|
|||||||
}
|
}
|
||||||
.show()
|
.show()
|
||||||
} else {
|
} else {
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
super.onBackPressed()
|
super.onBackPressed()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,6 @@ import android.widget.TextView
|
|||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import arrow.core.Try
|
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
@ -167,7 +166,7 @@ class KeysBackupSetupStep3Fragment :
|
|||||||
|
|
||||||
private fun exportRecoveryKeyToFile(uri: Uri, data: String) {
|
private fun exportRecoveryKeyToFile(uri: Uri, data: String) {
|
||||||
lifecycleScope.launch(Dispatchers.Main) {
|
lifecycleScope.launch(Dispatchers.Main) {
|
||||||
Try {
|
try {
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
requireContext().safeOpenOutputStream(uri)
|
requireContext().safeOpenOutputStream(uri)
|
||||||
?.use { os ->
|
?.use { os ->
|
||||||
@ -176,24 +175,19 @@ class KeysBackupSetupStep3Fragment :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
?: throw IOException("Unable to write the file")
|
?: throw IOException("Unable to write the file")
|
||||||
|
viewModel.copyHasBeenMade = true
|
||||||
|
activity?.let {
|
||||||
|
MaterialAlertDialogBuilder(it)
|
||||||
|
.setTitle(R.string.dialog_title_success)
|
||||||
|
.setMessage(R.string.recovery_key_export_saved)
|
||||||
|
}
|
||||||
|
} catch (throwable: Throwable) {
|
||||||
|
activity?.let {
|
||||||
|
MaterialAlertDialogBuilder(it)
|
||||||
|
.setTitle(R.string.dialog_title_error)
|
||||||
|
.setMessage(errorFormatter.toHumanReadable(throwable))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.fold(
|
|
||||||
{ throwable ->
|
|
||||||
activity?.let {
|
|
||||||
MaterialAlertDialogBuilder(it)
|
|
||||||
.setTitle(R.string.dialog_title_error)
|
|
||||||
.setMessage(errorFormatter.toHumanReadable(throwable))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
viewModel.copyHasBeenMade = true
|
|
||||||
activity?.let {
|
|
||||||
MaterialAlertDialogBuilder(it)
|
|
||||||
.setTitle(R.string.dialog_title_success)
|
|
||||||
.setMessage(R.string.recovery_key_export_saved)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
?.setCancelable(false)
|
?.setCancelable(false)
|
||||||
?.setPositiveButton(R.string.ok, null)
|
?.setPositiveButton(R.string.ok, null)
|
||||||
?.show()
|
?.show()
|
||||||
|
@ -26,6 +26,7 @@ import im.vector.app.features.home.room.detail.RoomDetailActivity
|
|||||||
import im.vector.app.features.home.room.detail.arguments.TimelineArgs
|
import im.vector.app.features.home.room.detail.arguments.TimelineArgs
|
||||||
import im.vector.app.features.popup.PopupAlertManager
|
import im.vector.app.features.popup.PopupAlertManager
|
||||||
import im.vector.app.features.popup.VerificationVectorAlert
|
import im.vector.app.features.popup.VerificationVectorAlert
|
||||||
|
import im.vector.lib.core.utils.compat.getParcelableCompat
|
||||||
import org.matrix.android.sdk.api.session.Session
|
import org.matrix.android.sdk.api.session.Session
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.PendingVerificationRequest
|
import org.matrix.android.sdk.api.session.crypto.verification.PendingVerificationRequest
|
||||||
import org.matrix.android.sdk.api.session.crypto.verification.VerificationService
|
import org.matrix.android.sdk.api.session.crypto.verification.VerificationService
|
||||||
@ -147,7 +148,7 @@ class IncomingVerificationRequestHandler @Inject constructor(
|
|||||||
R.drawable.ic_shield_black,
|
R.drawable.ic_shield_black,
|
||||||
shouldBeDisplayedIn = { activity ->
|
shouldBeDisplayedIn = { activity ->
|
||||||
if (activity is RoomDetailActivity) {
|
if (activity is RoomDetailActivity) {
|
||||||
activity.intent?.extras?.getParcelable<TimelineArgs>(RoomDetailActivity.EXTRA_ROOM_DETAIL_ARGS)?.let {
|
activity.intent?.extras?.getParcelableCompat<TimelineArgs>(RoomDetailActivity.EXTRA_ROOM_DETAIL_ARGS)?.let {
|
||||||
it.roomId != pr.roomId
|
it.roomId != pr.roomId
|
||||||
} ?: true
|
} ?: true
|
||||||
} else true
|
} else true
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user