Merge branch 'feature/eric/new-layout-navigation' into feature/eric/new-layout-debug

This commit is contained in:
ericdecanini 2022-08-18 17:37:16 +02:00
commit 88fc0afea5
254 changed files with 3092 additions and 7169 deletions

View file

@ -16,3 +16,5 @@ jobs:
args: "--dangerfile tools/danger/dangerfile.js"
env:
DANGER_GITHUB_API_TOKEN: ${{ secrets.DANGER_GITHUB_API_TOKEN }}
# Fallback for forks
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View file

@ -71,6 +71,8 @@ jobs:
args: "--dangerfile tools/danger/dangerfile-lint.js"
env:
DANGER_GITHUB_API_TOKEN: ${{ secrets.DANGER_GITHUB_API_TOKEN }}
# Fallback for forks
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# Gradle dependency analysis using https://github.com/autonomousapps/dependency-analysis-android-gradle-plugin
dependency-analysis:

View file

@ -1,3 +1,38 @@
Changes in Element v1.4.32 (2022-08-10)
=======================================
Features ✨
----------
- [Location Share] Render fallback UI when map fails to load ([#6711](https://github.com/vector-im/element-android/issues/6711))
Bugfixes 🐛
----------
- Fix message content sometimes appearing in the log ([#6706](https://github.com/vector-im/element-android/issues/6706))
- Disable 'Enable biometrics' option if there are not biometric authenticators enrolled. ([#6713](https://github.com/vector-im/element-android/issues/6713))
- Fix crash when biometric key is used when coming back to foreground and KeyStore reports that the device is still locked. ([#6768](https://github.com/vector-im/element-android/issues/6768))
- Catch all exceptions on lockscreen system key migrations. ([#6769](https://github.com/vector-im/element-android/issues/6769))
- Fixes crash when entering non ascii characters during account creation ([#6735](https://github.com/vector-im/element-android/issues/6735))
- Fixes onboarding login/account creation errors showing after navigation ([#6737](https://github.com/vector-im/element-android/issues/6737))
- [Location sharing] Invisible text on map symbol ([#6687](https://github.com/vector-im/element-android/issues/6687))
In development 🚧
----------------
- Adds new app layout toolbar ([#6655](https://github.com/vector-im/element-android/issues/6655))
Other changes
-------------
- [Modularization] Provides abstraction to avoid direct usages of BuildConfig ([#6406](https://github.com/vector-im/element-android/issues/6406))
- Refactors SpaceStateHandler (previously AppStateHandler) and adds unit tests for it ([#6598](https://github.com/vector-im/element-android/issues/6598))
- Setup Danger to the project ([#6637](https://github.com/vector-im/element-android/issues/6637))
- [Location Share] Open maximized map on tapping on live sharing notification ([#6642](https://github.com/vector-im/element-android/issues/6642))
- [Location sharing] Align naming of components for live location feature ([#6647](https://github.com/vector-im/element-android/issues/6647))
- [Location share] Update minimum sending period to 5 seconds for a live ([#6653](https://github.com/vector-im/element-android/issues/6653))
- [Location sharing] - Fix the memory leaks ([#6674](https://github.com/vector-im/element-android/issues/6674))
- [Timeline] Memory leak in audio message playback tracker ([#6678](https://github.com/vector-im/element-android/issues/6678))
- [FTUE] Memory leak on FtueAuthSplashCarouselFragment ([#6680](https://github.com/vector-im/element-android/issues/6680))
- Link directly to DCO docs from danger message. ([#6739](https://github.com/vector-im/element-android/issues/6739))
Changes in Element v1.4.31 (2022-08-01)
=======================================

View file

@ -24,7 +24,7 @@ buildscript {
classpath libs.gradle.gradlePlugin
classpath libs.gradle.kotlinPlugin
classpath libs.gradle.hiltPlugin
classpath 'com.google.firebase:firebase-appdistribution-gradle:3.0.2'
classpath 'com.google.firebase:firebase-appdistribution-gradle:3.0.3'
classpath 'com.google.gms:google-services:4.3.13'
classpath 'org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:3.4.0.2513'
classpath 'com.google.android.gms:oss-licenses-plugin:0.10.5'
@ -44,7 +44,7 @@ plugins {
id "io.gitlab.arturbosch.detekt" version "1.21.0"
// Dependency Analysis
id 'com.autonomousapps.dependency-analysis' version "1.11.2"
id 'com.autonomousapps.dependency-analysis' version "1.12.0"
}
// https://github.com/jeremylong/DependencyCheck
@ -151,6 +151,8 @@ allprojects {
"experimental:comment-wrapping",
// - A KDoc comment after any other element on the same line must be separated by a new line
"experimental:kdoc-wrapping",
// Ignore error "Redundant curly braces", since we use it to fix false positives, for instance in "elementLogs.${i}.txt"
"string-template",
]
}

1
changelog.d/5525.wip Normal file
View file

@ -0,0 +1 @@
Create DM room only on first message - Trigger the flow when the "Direct Message" action is selected from the room member details screen

1
changelog.d/5974.misc Normal file
View file

@ -0,0 +1 @@
Removes the Login2 proof of concept - replaced by the FTUE changes

View file

@ -1 +0,0 @@
[Modularization] Provides abstraction to avoids direct usages of BuildConfig

1
changelog.d/6505.wip Normal file
View file

@ -0,0 +1 @@
added filter tabs for new App layout's Home screen

View file

@ -1 +0,0 @@
Refactors SpaceStateHandler (previously AppStateHandler) and adds unit tests for it

View file

@ -1 +0,0 @@
Setup Danger to the project

View file

@ -1 +0,0 @@
[Location Share] Open maximized map on tapping on live sharing notification

1
changelog.d/6645.misc Normal file
View file

@ -0,0 +1 @@
Enable auto-capitalization for Room creation Title field

View file

@ -1 +0,0 @@
[Location sharing] Align naming of components for live location feature

View file

@ -1 +0,0 @@
[Location share] Update minimum sending period to 5 seconds for a live

View file

@ -1 +0,0 @@
Adds new app layout toolbar (feature flagged)

View file

@ -1 +0,0 @@
[Location sharing] - Fix the memory leaks

View file

@ -1 +0,0 @@
[Timeline] Memory leak in audio message playback tracker

View file

@ -1 +0,0 @@
[FTUE] Memory leak on FtueAuthSplashCarouselFragment

View file

@ -1 +0,0 @@
[Location sharing] Invisible text on map symbol

View file

@ -1 +0,0 @@
Fix message content sometimes appearing in the log

View file

@ -1 +0,0 @@
[Location Share] Render fallback UI when map fails to load

View file

@ -1 +0,0 @@
Disable 'Enable biometrics' option if there are not biometric authenticators enrolled.

View file

@ -1 +0,0 @@
Fixes onboarding login/account creation errors showing after navigation

View file

@ -1 +0,0 @@
Link directly to DCO docs from danger message.

1
changelog.d/6746.feature Normal file
View file

@ -0,0 +1 @@
[Notification] - Handle creation of notification for live location and poll start

1
changelog.d/6783.misc Normal file
View file

@ -0,0 +1 @@
Decouples the variant logic from the vector module

1
changelog.d/6786.misc Normal file
View file

@ -0,0 +1 @@
Add a developer setting to enable LeakCanary at runtime

1
changelog.d/6798.wip Normal file
View file

@ -0,0 +1 @@
[Devices management] Add a feature flag and empty screen for future new layout

1
changelog.d/6799.misc Normal file
View file

@ -0,0 +1 @@
[Create Room] Reduce some boilerplate with room state event contents

1
changelog.d/6806.wip Normal file
View file

@ -0,0 +1 @@
[Devices management] Other sessions section in new layout

1
changelog.d/6808.misc Normal file
View file

@ -0,0 +1 @@
[Call] Memory leak after a call

1
changelog.d/6843.misc Normal file
View file

@ -0,0 +1 @@
Fix some string template

1
changelog.d/6877.wip Normal file
View file

@ -0,0 +1 @@
[New Layout] Adds space backstack for back navigation and space sheet header

View file

@ -22,7 +22,7 @@ def markwon = "4.6.2"
def moshi = "1.13.0"
def lifecycle = "2.5.1"
def flowBinding = "1.2.0"
def flipper = "0.156.0"
def flipper = "0.157.0"
def epoxy = "4.6.2"
def mavericks = "2.7.0"
def glide = "4.13.2"
@ -30,7 +30,7 @@ def bigImageViewer = "1.8.1"
def jjwt = "0.11.5"
def vanniktechEmoji = "0.15.0"
def fragment = "1.5.1"
def fragment = "1.5.2"
// Testing
def mockk = "1.12.3" // We need to use 1.12.3 to have mocking in androidTest until a new version is released: https://github.com/mockk/mockk/issues/819

View file

@ -74,6 +74,7 @@ ext.groups = [
'com.github.javaparser',
'com.github.piasy',
'com.github.shyiko.klob',
'com.github.rubensousa',
'com.google',
'com.google.android',
'com.google.api.grpc',
@ -106,7 +107,9 @@ ext.groups = [
'com.pinterest.ktlint',
'com.posthog.android',
'com.squareup',
'com.squareup.curtains',
'com.squareup.duktape',
'com.squareup.leakcanary',
'com.squareup.moshi',
'com.squareup.okhttp3',
'com.squareup.okio',

View file

@ -23,6 +23,7 @@ Here are the checks that Danger does so far:
- PR description is not empty
- Big PR got a warning to recommend to split
- PR contains a file for towncrier and extension is checked
- PR does not modify frozen classes
- PR contains a Sign-Off, with exception for Element employee contributors
- PR with change on layout should include screenshot in the description
- PR which adds png file warn about the usage of vector drawables
@ -84,6 +85,8 @@ To let Danger check all the PRs, including PRs form forks, a GitHub account have
- password: Stored on Passbolt
- GitHub token: A token with limited access has been created and added to the repository https://github.com/vector-im/element-android as secret DANGER_GITHUB_API_TOKEN. This token is not saved anywhere else. In case of problem, just delete it and create a new one, then update the secret.
PRs from forks do not always have access to the secret `secrets.DANGER_GITHUB_API_TOKEN`, so `secrets.GITHUB_TOKEN` is also provided to the job environment. If `secrets.DANGER_GITHUB_API_TOKEN` is available, it will be used, so user `ElementBot` will comment the PR. Else `secrets.GITHUB_TOKEN` will be used, and bot `github-actions` will comment the PR.
## Useful links
- https://danger.systems/

View file

@ -0,0 +1,2 @@
Main changes in this version: Various bug fixes and stability improvements.
Full changelog: https://github.com/vector-im/element-android/releases

View file

@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionSha256Sum=97a52d145762adc241bad7fd18289bf7f6801e08ece6badf80402fe2b9f250b1
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip
distributionSha256Sum=db9c8211ed63f61f60292c69e80d89196f9eb36665e369e7f00ac4cc841c2219
distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View file

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="DevicesListHeaderView">
<attr name="devicesListHeaderTitle" format="string" />
<attr name="devicesListHeaderDescription" format="string" />
</declare-styleable>
</resources>

View file

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="TextAppearance.Vector.Subtitle.Medium.DevicesManagement">
<item name="android:textColor">?vctr_content_primary</item>
</style>
<style name="TextAppearance.Vector.Body.DevicesManagement">
<item name="android:textColor">?vctr_content_secondary</item>
</style>
</resources>

View file

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Widget.Vector.TabLayout" parent="Widget.MaterialComponents.TabLayout">
<item name="materialThemeOverlay">@style/ThemeOverlay.Vector.HomeFilterTabLayout</item>
<item name="tabTextAppearance">@style/TextAppearance.Vector.FilterTabTextAppearance</item>
</style>
<style name="TextAppearance.Vector.FilterTabTextAppearance" parent="TextAppearance.Vector.Subtitle">
<item name="textAllCaps">false</item>
</style>
<style name="ThemeOverlay.Vector.HomeFilterTabLayout" parent="Theme.Vector.Launcher">
<item name="colorSurface">?vctr_toolbar_background</item>
<item name="colorOnSurface">?vctr_content_secondary</item>
</style>
</resources>

View file

@ -17,7 +17,7 @@ buildscript {
}
}
dependencies {
classpath "io.realm:realm-gradle-plugin:10.11.0"
classpath "io.realm:realm-gradle-plugin:10.11.1"
}
}
@ -60,7 +60,7 @@ android {
// that the app's state is completely cleared between tests.
testInstrumentationRunnerArguments clearPackageData: 'true'
buildConfigField "String", "SDK_VERSION", "\"1.4.32\""
buildConfigField "String", "SDK_VERSION", "\"1.4.34\""
buildConfigField "String", "GIT_SDK_REVISION", "\"${gitRevision()}\""
buildConfigField "String", "GIT_SDK_REVISION_UNIX_DATE", "\"${gitRevisionUnixDate()}\""

View file

@ -62,7 +62,10 @@ fun Throwable.isUsernameInUse() = this is Failure.ServerError &&
error.code == MatrixError.M_USER_IN_USE
fun Throwable.isInvalidUsername() = this is Failure.ServerError &&
error.code == MatrixError.M_INVALID_USERNAME
(error.code == MatrixError.M_INVALID_USERNAME || usernameContainsNonAsciiCharacters())
private fun Failure.ServerError.usernameContainsNonAsciiCharacters() = error.code == MatrixError.M_UNKNOWN &&
error.message == "Query parameter \'username\' must be ascii"
fun Throwable.isInvalidPassword() = this is Failure.ServerError &&
error.code == MatrixError.M_FORBIDDEN &&

View file

@ -29,14 +29,12 @@ data class RoomGuestAccessContent(
// Required. Whether guests can join the room. One of: ["can_join", "forbidden"]
@Json(name = "guest_access") val guestAccessStr: String? = null
) {
val guestAccess: GuestAccess? = when (guestAccessStr) {
"can_join" -> GuestAccess.CanJoin
"forbidden" -> GuestAccess.Forbidden
else -> {
Timber.w("Invalid value for GuestAccess: `$guestAccessStr`")
null
}
}
val guestAccess: GuestAccess? = GuestAccess.values()
.find { it.value == guestAccessStr }
?: run {
Timber.w("Invalid value for GuestAccess: `$guestAccessStr`")
null
}
}
@JsonClass(generateAdapter = false)

View file

@ -23,30 +23,30 @@ import com.squareup.moshi.JsonClass
* Ref: https://matrix.org/docs/spec/client_server/latest#room-history-visibility
*/
@JsonClass(generateAdapter = false)
enum class RoomHistoryVisibility {
enum class RoomHistoryVisibility(val value: String) {
/**
* All events while this is the m.room.history_visibility value may be shared by any
* participating homeserver with anyone, regardless of whether they have ever joined the room.
*/
@Json(name = "world_readable") WORLD_READABLE,
@Json(name = "world_readable") WORLD_READABLE("world_readable"),
/**
* Previous events are always accessible to newly joined members. All events in the
* room are accessible, even those sent when the member was not a part of the room.
*/
@Json(name = "shared") SHARED,
@Json(name = "shared") SHARED("shared"),
/**
* Events are accessible to newly joined members from the point they were invited onwards.
* Events stop being accessible when the member's state changes to something other than invite or join.
*/
@Json(name = "invited") INVITED,
@Json(name = "invited") INVITED("invited"),
/**
* Events are accessible to newly joined members from the point they joined the room onwards.
* Events stop being accessible when the member's state changes to something other than join.
*/
@Json(name = "joined") JOINED
@Json(name = "joined") JOINED("joined")
}
/**

View file

@ -24,14 +24,10 @@ import timber.log.Timber
data class RoomHistoryVisibilityContent(
@Json(name = "history_visibility") val historyVisibilityStr: String? = null
) {
val historyVisibility: RoomHistoryVisibility? = when (historyVisibilityStr) {
"world_readable" -> RoomHistoryVisibility.WORLD_READABLE
"shared" -> RoomHistoryVisibility.SHARED
"invited" -> RoomHistoryVisibility.INVITED
"joined" -> RoomHistoryVisibility.JOINED
else -> {
Timber.w("Invalid value for RoomHistoryVisibility: `$historyVisibilityStr`")
null
}
}
val historyVisibility: RoomHistoryVisibility? = RoomHistoryVisibility.values()
.find { it.value == historyVisibilityStr }
?: run {
Timber.w("Invalid value for RoomHistoryVisibility: `$historyVisibilityStr`")
null
}
}

View file

@ -16,7 +16,6 @@
package org.matrix.android.sdk.api.session.room.model.create
import org.matrix.android.sdk.api.session.events.model.Event
import org.matrix.android.sdk.api.session.events.model.EventType
import org.matrix.android.sdk.api.session.events.model.toContent
import org.matrix.android.sdk.api.session.homeserver.HomeServerCapabilities
@ -30,7 +29,7 @@ interface RoomFeaturePreset {
fun updateRoomParams(params: CreateRoomParams)
fun setupInitialStates(): List<Event>?
fun setupInitialStates(): List<CreateRoomStateEvent>?
}
class RestrictedRoomPreset(val homeServerCapabilities: HomeServerCapabilities, val restrictedList: List<RoomJoinRulesAllowEntry>) : RoomFeaturePreset {
@ -41,9 +40,9 @@ class RestrictedRoomPreset(val homeServerCapabilities: HomeServerCapabilities, v
params.roomVersion = homeServerCapabilities.versionOverrideForFeature(HomeServerCapabilities.ROOM_CAP_RESTRICTED)
}
override fun setupInitialStates(): List<Event>? {
override fun setupInitialStates(): List<CreateRoomStateEvent> {
return listOf(
Event(
CreateRoomStateEvent(
type = EventType.STATE_ROOM_JOIN_RULES,
stateKey = "",
content = RoomJoinRulesContent(

View file

@ -22,7 +22,7 @@ import org.matrix.android.sdk.api.session.events.model.Content
import org.matrix.android.sdk.api.session.room.model.relation.RelationDefaultContent
/**
* Content of the state event of type
* Content of the event of type
* [EventType.BEACON_LOCATION_DATA][org.matrix.android.sdk.api.session.events.model.EventType.BEACON_LOCATION_DATA]
*
* It contains location data related to a live location share.

View file

@ -76,12 +76,12 @@ internal class VerificationTransportToDevice(
.configureWith(SendToDeviceTask.Params(MessageType.MSGTYPE_VERIFICATION_REQUEST, contentMap)) {
this.callback = object : MatrixCallback<Unit> {
override fun onSuccess(data: Unit) {
Timber.v("## verification [$tx.transactionId] send toDevice request success")
Timber.v("## verification [${tx?.transactionId}] send toDevice request success")
callback.invoke(localId, validKeyReq)
}
override fun onFailure(failure: Throwable) {
Timber.e("## verification [$tx.transactionId] failed to send toDevice request")
Timber.e("## verification [${tx?.transactionId}] failed to send toDevice request")
}
}
}
@ -103,12 +103,12 @@ internal class VerificationTransportToDevice(
.configureWith(SendToDeviceTask.Params(EventType.KEY_VERIFICATION_READY, contentMap)) {
this.callback = object : MatrixCallback<Unit> {
override fun onSuccess(data: Unit) {
Timber.v("## verification [$tx.transactionId] send toDevice request success")
Timber.v("## verification [${tx?.transactionId}] send toDevice request success")
callback?.invoke()
}
override fun onFailure(failure: Throwable) {
Timber.e("## verification [$tx.transactionId] failed to send toDevice request")
Timber.e("## verification [${tx?.transactionId}] failed to send toDevice request")
}
}
}
@ -136,7 +136,7 @@ internal class VerificationTransportToDevice(
.configureWith(SendToDeviceTask.Params(type, contentMap)) {
this.callback = object : MatrixCallback<Unit> {
override fun onSuccess(data: Unit) {
Timber.v("## SAS verification [$tx.transactionId] toDevice type '$type' success.")
Timber.v("## SAS verification [${tx.transactionId}] toDevice type '$type' success.")
if (onDone != null) {
onDone()
} else {
@ -149,7 +149,7 @@ internal class VerificationTransportToDevice(
}
override fun onFailure(failure: Throwable) {
Timber.e("## SAS verification [$tx.transactionId] failed to send toDevice in state : $tx.state")
Timber.e("## SAS verification [${tx.transactionId}] failed to send toDevice in state : ${tx.state}")
tx.cancel(onErrorReason)
}
}

View file

@ -93,7 +93,7 @@ internal class SessionRealmConfigurationFactory @Inject constructor(
return
}
listOf(REALM_NAME, "$REALM_NAME.lock", "$REALM_NAME.note", "$REALM_NAME.management").forEach { file ->
listOf(REALM_NAME, "${REALM_NAME}.lock", "${REALM_NAME}.note", "${REALM_NAME}.management").forEach { file ->
try {
File(directory, file).deleteRecursively()
} catch (e: Exception) {

View file

@ -20,8 +20,13 @@ import org.matrix.android.sdk.api.crypto.MXCRYPTO_ALGORITHM_MEGOLM
import org.matrix.android.sdk.api.extensions.tryOrNull
import org.matrix.android.sdk.api.session.events.model.Event
import org.matrix.android.sdk.api.session.events.model.EventType
import org.matrix.android.sdk.api.session.events.model.content.EncryptionEventContent
import org.matrix.android.sdk.api.session.events.model.toContent
import org.matrix.android.sdk.api.session.identity.IdentityServiceError
import org.matrix.android.sdk.api.session.identity.toMedium
import org.matrix.android.sdk.api.session.room.model.RoomAvatarContent
import org.matrix.android.sdk.api.session.room.model.RoomGuestAccessContent
import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibilityContent
import org.matrix.android.sdk.api.session.room.model.create.CreateRoomParams
import org.matrix.android.sdk.api.util.MimeTypes
import org.matrix.android.sdk.internal.crypto.DeviceListManager
@ -78,7 +83,7 @@ internal class CreateRoomBodyBuilder @Inject constructor(
buildAvatarEvent(params),
buildGuestAccess(params)
) +
params.featurePreset?.setupInitialStates().orEmpty() +
buildFeaturePresetInitialStates(params) +
buildCustomInitialStates(params)
)
.takeIf { it.isNotEmpty() }
@ -99,6 +104,16 @@ internal class CreateRoomBodyBuilder @Inject constructor(
)
}
private fun buildFeaturePresetInitialStates(params: CreateRoomParams): List<Event> {
return params.featurePreset?.setupInitialStates().orEmpty().map {
Event(
type = it.type,
stateKey = it.stateKey,
content = it.content
)
}
}
private fun buildCustomInitialStates(params: CreateRoomParams): List<Event> {
return params.initialStates.map {
Event(
@ -123,7 +138,7 @@ internal class CreateRoomBodyBuilder @Inject constructor(
Event(
type = EventType.STATE_ROOM_AVATAR,
stateKey = "",
content = mapOf("url" to response.contentUri)
content = RoomAvatarContent(response.contentUri).toContent()
)
}
}
@ -134,7 +149,7 @@ internal class CreateRoomBodyBuilder @Inject constructor(
Event(
type = EventType.STATE_ROOM_HISTORY_VISIBILITY,
stateKey = "",
content = mapOf("history_visibility" to it)
content = RoomHistoryVisibilityContent(it.value).toContent()
)
}
}
@ -145,7 +160,7 @@ internal class CreateRoomBodyBuilder @Inject constructor(
Event(
type = EventType.STATE_ROOM_GUEST_ACCESS,
stateKey = "",
content = mapOf("guest_access" to it.value)
content = RoomGuestAccessContent(it.value).toContent()
)
}
}
@ -167,7 +182,7 @@ internal class CreateRoomBodyBuilder @Inject constructor(
Event(
type = EventType.STATE_ROOM_ENCRYPTION,
stateKey = "",
content = mapOf("algorithm" to it)
content = EncryptionEventContent(it).toContent()
)
}
}

View file

@ -16,21 +16,6 @@
# limitations under the License.
#
#######################################################################################################################
# Check frozen class modification
#######################################################################################################################
echo "Check if frozen class modified"
git diff "HEAD@{1}" --name-only | grep -e OlmInboundGroupSessionWrapper.kt -e OlmInboundGroupSessionWrapper2.kt
FROZEN_CHANGED=$?
if [ ${FROZEN_CHANGED} -eq 0 ]; then
echo "❌ FROZEN CLASS CHANGED ERROR"
exit 1
else
echo "Frozen check OK"
fi
#######################################################################################################################
# Check drawable quantity
#######################################################################################################################

View file

@ -185,3 +185,6 @@ System\.currentTimeMillis\(\)===2
onCreateOptionsMenu
onOptionsItemSelected
onPrepareOptionsMenu
### Suspicious String template. Please check that the string template will behave as expected, i.e. the class field and not the whole object will be used. For instance `Timber.d("$event.type")` is not correct, you should write `Timber.d("${event.type}")`. In the former the whole event content will be logged, since it's a data class. If this is expected (i.e. to fix false positive), please add explicit curly braces (`{` and `}`) around the variable, for instance `"elementLogs.${i}.txt"`
\$[a-zA-Z_]\w*\??\.[a-zA-Z_]

View file

@ -52,6 +52,19 @@ if (requiresChangelog) {
}
}
// check that frozen classes have not been modified
const frozenClasses = [
"OlmInboundGroupSessionWrapper.kt",
"OlmInboundGroupSessionWrapper2.kt",
]
frozenClasses.forEach(frozen => {
if (editedFiles.some(file => file.endsWith(frozen))) {
fail("Frozen class `" + frozen + "` has been modified. Please do not modify frozen class.")
}
}
)
// Check for a sign-off
const signOff = "Signed-off-by:"

View file

@ -2634,7 +2634,8 @@
"mask",
"sick",
"ill",
"disease"
"disease",
"covid"
]
},
"face-with-thermometer": {
@ -2647,7 +2648,8 @@
"thermometer",
"temperature",
"cold",
"fever"
"fever",
"covid"
]
},
"face-with-headbandage": {
@ -4481,7 +4483,9 @@
"hope",
"wish",
"namaste",
"highfive"
"highfive",
"thank you",
"appreciate"
]
},
"writing-hand": {
@ -9581,7 +9585,8 @@
"amoeba",
"bacteria",
"virus",
"germs"
"germs",
"covid"
]
},
"bouquet": {
@ -10260,7 +10265,9 @@
"baguette",
"bread",
"food",
"french"
"french",
"france",
"bakery"
]
},
"flatbread": {
@ -10272,7 +10279,8 @@
"naan",
"pita",
"flour",
"food"
"food",
"bakery"
]
},
"pretzel": {
@ -10282,7 +10290,9 @@
"twisted",
"convoluted",
"food",
"bread"
"bread",
"germany",
"bakery"
]
},
"bagel": {
@ -10293,7 +10303,8 @@
"breakfast",
"schmear",
"food",
"bread"
"bread",
"jewish"
]
},
"pancakes": {
@ -10306,7 +10317,8 @@
"hotcake",
"pancake",
"flapjacks",
"hotcakes"
"hotcakes",
"brunch"
]
},
"waffle": {
@ -10316,7 +10328,8 @@
"breakfast",
"indecisive",
"iron",
"food"
"food",
"brunch"
]
},
"cheese-wedge": {
@ -10325,7 +10338,8 @@
"j": [
"cheese",
"food",
"chadder"
"chadder",
"swiss"
]
},
"meat-on-bone": {
@ -10376,7 +10390,8 @@
"food",
"meat",
"pork",
"pig"
"pig",
"brunch"
]
},
"hamburger": {
@ -10400,7 +10415,8 @@
"fries",
"chips",
"snack",
"fast food"
"fast food",
"potato"
]
},
"pizza": {
@ -10410,7 +10426,8 @@
"cheese",
"slice",
"food",
"party"
"party",
"italy"
]
},
"hot-dog": {
@ -10420,7 +10437,8 @@
"frankfurter",
"hotdog",
"sausage",
"food"
"food",
"america"
]
},
"sandwich": {
@ -10429,7 +10447,9 @@
"j": [
"bread",
"food",
"lunch"
"lunch",
"toast",
"bakery"
]
},
"taco": {
@ -10468,7 +10488,8 @@
"food",
"gyro",
"kebab",
"stuffed"
"stuffed",
"mediterranean"
]
},
"falafel": {
@ -10477,7 +10498,8 @@
"j": [
"chickpea",
"meatball",
"food"
"food",
"mediterranean"
]
},
"egg": {
@ -10498,7 +10520,8 @@
"frying",
"pan",
"food",
"kitchen"
"kitchen",
"skillet"
]
},
"shallow-pan-of-food": {
@ -10510,7 +10533,8 @@
"paella",
"pan",
"shallow",
"cooking"
"cooking",
"skillet"
]
},
"pot-of-food": {
@ -10521,7 +10545,8 @@
"stew",
"food",
"meat",
"soup"
"soup",
"hot pot"
]
},
"fondue": {
@ -10556,7 +10581,8 @@
"green",
"salad",
"healthy",
"lettuce"
"lettuce",
"vegetable"
]
},
"popcorn": {
@ -10566,7 +10592,8 @@
"food",
"movie theater",
"films",
"snack"
"snack",
"drama"
]
},
"butter": {
@ -10592,7 +10619,8 @@
"j": [
"can",
"food",
"soup"
"soup",
"tomatoes"
]
},
"bento-box": {
@ -10602,7 +10630,8 @@
"bento",
"box",
"food",
"japanese"
"japanese",
"lunch"
]
},
"rice-cracker": {
@ -10612,7 +10641,8 @@
"cracker",
"rice",
"food",
"japanese"
"japanese",
"snack"
]
},
"rice-ball": {
@ -10633,7 +10663,6 @@
"cooked",
"rice",
"food",
"china",
"asian"
]
},
@ -10680,7 +10709,8 @@
"roasted",
"sweet",
"food",
"nature"
"nature",
"plant"
]
},
"oden": {
@ -10745,7 +10775,8 @@
"autumn",
"festival",
"yuèbǐng",
"food"
"food",
"dessert"
]
},
"dango": {
@ -10772,7 +10803,8 @@
"jiaozi",
"pierogi",
"potsticker",
"food"
"food",
"gyoza"
]
},
"fortune-cookie": {
@ -10780,7 +10812,8 @@
"b": "1F960",
"j": [
"prophecy",
"food"
"food",
"dessert"
]
},
"takeout-box": {
@ -22169,7 +22202,9 @@
"nation",
"country",
"banner",
"japan"
"japan",
"jp",
"ja"
]
},
"flag-kenya": {

View file

@ -28,6 +28,7 @@ mv ./fastlane/metadata/android/fy ./fastlane_tmp
mv ./fastlane/metadata/android/ga ./fastlane_tmp
mv ./fastlane/metadata/android/kab ./fastlane_tmp
mv ./fastlane/metadata/android/nb ./fastlane_tmp
mv ./fastlane/metadata/android/gl ./fastlane_tmp
# Fastlane / PlayStore require longDescription and shortDescription file to be set, so copy the default
# one for languages where they are missing

View file

@ -18,6 +18,5 @@ package im.vector.app.config
enum class OnboardingVariant {
LEGACY,
LOGIN_2,
FTUE_AUTH
}

View file

@ -37,7 +37,7 @@ ext.versionMinor = 4
// Note: even values are reserved for regular release, odd values for hotfix release.
// When creating a hotfix, you should decrease the value, since the current value
// is the value for the next regular release.
ext.versionPatch = 32
ext.versionPatch = 34
static def getGitTimestamp() {
def cmd = 'git show -s --format=%ct'
@ -307,7 +307,6 @@ android {
isDefault = true
versionName "${versionMajor}.${versionMinor}.${versionPatch}${getGplayVersionSuffix()}"
resValue "bool", "isGplay", "true"
buildConfigField "String", "SHORT_FLAVOR_DESCRIPTION", "\"G\""
buildConfigField "String", "FLAVOR_DESCRIPTION", "\"GooglePlay\""
}
@ -317,7 +316,6 @@ android {
versionName "${versionMajor}.${versionMinor}.${versionPatch}${getFdroidVersionSuffix()}"
resValue "bool", "isGplay", "false"
buildConfigField "String", "SHORT_FLAVOR_DESCRIPTION", "\"F\""
buildConfigField "String", "FLAVOR_DESCRIPTION", "\"FDroid\""
}
@ -393,7 +391,7 @@ dependencies {
implementation libs.androidx.biometric
implementation "org.threeten:threetenbp:1.4.0:no-tzdb"
implementation "com.gabrielittner.threetenbp:lazythreetenbp:0.10.0"
implementation "com.gabrielittner.threetenbp:lazythreetenbp:0.11.0"
implementation libs.squareup.moshi
kapt libs.squareup.moshiKotlin
@ -427,6 +425,9 @@ dependencies {
implementation libs.airbnb.epoxyPaging
implementation libs.airbnb.mavericks
// Snap Helper https://github.com/rubensousa/GravitySnapHelper
implementation 'com.github.rubensousa:gravitysnaphelper:2.2.2'
// Nightly
// API-only library
gplayImplementation libs.google.appdistributionApi
@ -499,7 +500,7 @@ dependencies {
implementation 'com.posthog.android:posthog:1.1.2'
// UnifiedPush
implementation 'com.github.UnifiedPush:android-connector:2.0.0'
implementation 'com.github.UnifiedPush:android-connector:2.0.1'
// UnifiedPush gplay flavor only
gplayImplementation('com.github.UnifiedPush:android-embedded_fcm_distributor:2.1.1') {
exclude group: 'com.google.firebase', module: 'firebase-core'
@ -575,7 +576,7 @@ dependencies {
debugImplementation "com.kgurgul.flipper:flipper-realm-android:2.2.0"
// Activate when you want to check for leaks, from time to time.
//debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.3'
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.9.1'
androidTestImplementation libs.androidx.testCore
androidTestImplementation libs.androidx.testRunner

View file

@ -83,7 +83,7 @@ private fun useMediaStoreScreenshotStorage(
screenshotLocation: String,
bitmap: Bitmap
) {
contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, "$screenshotName.jpeg")
contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, "${screenshotName}.jpeg")
contentValues.put(MediaStore.Images.Media.RELATIVE_PATH, screenshotLocation)
val uri: Uri? = contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
if (uri != null) {
@ -104,7 +104,7 @@ private fun usePublicExternalScreenshotStorage(
if (!directory.exists()) {
directory.mkdirs()
}
val file = File(directory, "$screenshotName.jpeg")
val file = File(directory, "${screenshotName}.jpeg")
saveScreenshotToStream(bitmap, FileOutputStream(file))
contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues)
}

View file

@ -31,7 +31,6 @@ import androidx.test.filters.SdkSuppress
import androidx.test.platform.app.InstrumentationRegistry
import im.vector.app.TestBuildVersionSdkIntProvider
import im.vector.app.features.pin.lockscreen.configuration.LockScreenConfiguration
import im.vector.app.features.pin.lockscreen.configuration.LockScreenConfiguratorProvider
import im.vector.app.features.pin.lockscreen.configuration.LockScreenMode
import im.vector.app.features.pin.lockscreen.crypto.LockScreenCryptoConstants
import im.vector.app.features.pin.lockscreen.crypto.LockScreenKeyRepository
@ -40,6 +39,7 @@ import im.vector.app.features.pin.lockscreen.ui.fallbackprompt.FallbackBiometric
import im.vector.app.features.pin.lockscreen.utils.DevicePromptCheck
import io.mockk.clearAllMocks
import io.mockk.every
import io.mockk.justRun
import io.mockk.mockk
import io.mockk.mockkObject
import io.mockk.mockkStatic
@ -54,8 +54,10 @@ import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.launch
import kotlinx.coroutines.test.runTest
import org.amshove.kluent.coInvoking
import org.amshove.kluent.shouldBeFalse
import org.amshove.kluent.shouldBeTrue
import org.amshove.kluent.shouldThrow
import org.junit.Before
import org.junit.Ignore
import org.junit.Test
@ -239,36 +241,35 @@ class BiometricHelperTests {
@Test
@SdkSuppress(minSdkVersion = Build.VERSION_CODES.R) // Due to some issues with mockk and CryptoObject initialization
fun authenticateCreatesSystemKeyIfNeededOnSuccessOnAndroidM() = runTest {
fun enableAuthenticationDeletesSystemKeyOnFailure() = runTest {
buildVersionSdkIntProvider.value = Build.VERSION_CODES.M
every { lockScreenKeyRepository.isSystemKeyValid() } returns true
val mockAuthChannel = Channel<Boolean>(capacity = 1)
val biometricUtils = spyk(createBiometricHelper(createDefaultConfiguration(isBiometricsEnabled = true))) {
every { createAuthChannel() } returns mockAuthChannel
every { authenticateWithPromptInternal(any(), any(), any()) } returns mockk()
}
justRun { lockScreenKeyRepository.deleteSystemKey() }
val latch = CountDownLatch(1)
val intent = Intent(InstrumentationRegistry.getInstrumentation().targetContext, LockScreenTestActivity::class.java)
ActivityScenario.launch<LockScreenTestActivity>(intent).onActivity { activity ->
activity.lifecycleScope.launch {
val exception = IllegalStateException("Some error")
launch {
mockAuthChannel.send(true)
mockAuthChannel.close()
mockAuthChannel.close(exception)
}
biometricUtils.authenticate(activity).collect()
coInvoking { biometricUtils.enableAuthentication(activity).collect() } shouldThrow exception
latch.countDown()
}
}
latch.await(1, TimeUnit.SECONDS)
verify { lockScreenKeyRepository.ensureSystemKey() }
verify { lockScreenKeyRepository.deleteSystemKey() }
}
private fun createBiometricHelper(configuration: LockScreenConfiguration): BiometricHelper {
val context = InstrumentationRegistry.getInstrumentation().targetContext
val configProvider = LockScreenConfiguratorProvider(configuration)
return BiometricHelper(context, lockScreenKeyRepository, configProvider, biometricManager, buildVersionSdkIntProvider)
return BiometricHelper(configuration, context, lockScreenKeyRepository, biometricManager, buildVersionSdkIntProvider)
}
private fun createDefaultConfiguration(

View file

@ -17,8 +17,6 @@
package im.vector.app.features.pin.lockscreen.crypto
import androidx.test.platform.app.InstrumentationRegistry
import im.vector.app.features.pin.lockscreen.crypto.migrations.LegacyPinCodeMigrator
import im.vector.app.features.settings.VectorPreferences
import io.mockk.clearAllMocks
import io.mockk.every
import io.mockk.mockk
@ -44,8 +42,6 @@ class LockScreenKeyRepositoryTests {
}
private lateinit var lockScreenKeyRepository: LockScreenKeyRepository
private val legacyPinCodeMigrator: LegacyPinCodeMigrator = mockk(relaxed = true)
private val vectorPreferences: VectorPreferences = mockk(relaxed = true)
private val keyStore: KeyStore by lazy {
KeyStore.getInstance(LockScreenCryptoConstants.ANDROID_KEY_STORE).also { it.load(null) }

View file

@ -76,7 +76,7 @@ class EmojiDataSourceTest : InstrumentedTest {
fun searchTestOneResult() {
val emojiDataSource = createEmojiDataSource()
val result = runBlocking {
emojiDataSource.filterWith("france")
emojiDataSource.filterWith("flag-france")
}
assertEquals("Should have 1 result", 1, result.size)
}

View file

@ -9,6 +9,8 @@
<activity android:name=".features.debug.settings.DebugPrivateSettingsActivity" />
<activity android:name=".features.debug.sas.DebugSasEmojiActivity" />
<activity android:name=".features.debug.features.DebugFeaturesSettingsActivity" />
<activity android:name=".features.debug.DebugMenuActivity" />
<activity android:name=".features.debug.leak.DebugMemoryLeaksActivity" />
<activity
android:name="com.facebook.flipper.android.diagnostics.FlipperDiagnosticActivity"

View file

@ -37,6 +37,7 @@ import im.vector.app.core.utils.toast
import im.vector.app.databinding.ActivityDebugMenuBinding
import im.vector.app.features.debug.analytics.DebugAnalyticsActivity
import im.vector.app.features.debug.features.DebugFeaturesSettingsActivity
import im.vector.app.features.debug.leak.DebugMemoryLeaksActivity
import im.vector.app.features.debug.sas.DebugSasEmojiActivity
import im.vector.app.features.debug.settings.DebugPrivateSettingsActivity
import im.vector.app.features.qrcode.QrCodeScannerActivity
@ -86,6 +87,7 @@ class DebugMenuActivity : VectorBaseActivity<ActivityDebugMenuBinding>() {
views.debugAnalytics.setOnClickListener {
startActivity(Intent(this, DebugAnalyticsActivity::class.java))
}
views.debugMemoryLeaks.setOnClickListener { openMemoryLeaksSettings() }
views.debugTestTextViewLink.setOnClickListener { testTextViewLink() }
views.debugOpenButtonStylesLight.setOnClickListener {
startActivity(Intent(this, DebugVectorButtonStylesLightActivity::class.java))
@ -130,6 +132,10 @@ class DebugMenuActivity : VectorBaseActivity<ActivityDebugMenuBinding>() {
startActivity(Intent(this, DebugPrivateSettingsActivity::class.java))
}
private fun openMemoryLeaksSettings() {
startActivity(Intent(this, DebugMemoryLeaksActivity::class.java))
}
private fun renderQrCode(text: String) {
views.debugQrCode.setData(text)
}

View file

@ -0,0 +1,57 @@
/*
* 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.features.debug.di
import android.content.Context
import android.content.Intent
import dagger.Binds
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import im.vector.app.core.debug.DebugNavigator
import im.vector.app.core.debug.DebugReceiver
import im.vector.app.core.debug.FlipperProxy
import im.vector.app.core.debug.LeakDetector
import im.vector.app.features.debug.DebugMenuActivity
import im.vector.app.flipper.VectorFlipperProxy
import im.vector.app.leakcanary.LeakCanaryLeakDetector
import im.vector.app.receivers.VectorDebugReceiver
@InstallIn(SingletonComponent::class)
@Module
abstract class DebugModule {
companion object {
@Provides
fun providesDebugNavigator() = object : DebugNavigator {
override fun openDebugMenu(context: Context) {
context.startActivity(Intent(context, DebugMenuActivity::class.java))
}
}
}
@Binds
abstract fun bindsDebugReceiver(receiver: VectorDebugReceiver): DebugReceiver
@Binds
abstract fun bindsFlipperProxy(flipperProxy: VectorFlipperProxy): FlipperProxy
@Binds
abstract fun bindsLeakDetector(leakDetector: LeakCanaryLeakDetector): LeakDetector
}

View file

@ -24,6 +24,7 @@ import im.vector.app.core.di.MavericksAssistedViewModelFactory
import im.vector.app.core.di.MavericksViewModelComponent
import im.vector.app.core.di.MavericksViewModelKey
import im.vector.app.features.debug.analytics.DebugAnalyticsViewModel
import im.vector.app.features.debug.leak.DebugMemoryLeaksViewModel
import im.vector.app.features.debug.settings.DebugPrivateSettingsViewModel
@InstallIn(MavericksViewModelComponent::class)
@ -39,4 +40,9 @@ interface MavericksViewModelDebugModule {
@IntoMap
@MavericksViewModelKey(DebugPrivateSettingsViewModel::class)
fun debugPrivateSettingsViewModelFactory(factory: DebugPrivateSettingsViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
@Binds
@IntoMap
@MavericksViewModelKey(DebugMemoryLeaksViewModel::class)
fun debugMemoryLeaksViewModelFactory(factory: DebugMemoryLeaksViewModel.Factory): MavericksAssistedViewModelFactory<*, *>
}

View file

@ -90,6 +90,11 @@ class DebugFeaturesStateFactory @Inject constructor(
key = DebugFeatureKeys.newAppLayoutEnabled,
factory = VectorFeatures::isNewAppLayoutEnabled
),
createBooleanFeature(
label = "Enable New Device Management",
key = DebugFeatureKeys.newDeviceManagementEnabled,
factory = VectorFeatures::isNewDeviceManagementEnabled
),
)
)
}

View file

@ -79,6 +79,9 @@ class DebugVectorFeatures(
override fun isNewAppLayoutEnabled(): Boolean = read(DebugFeatureKeys.newAppLayoutEnabled)
?: vectorFeatures.isNewAppLayoutEnabled()
override fun isNewDeviceManagementEnabled(): Boolean = read(DebugFeatureKeys.newDeviceManagementEnabled)
?: vectorFeatures.isNewDeviceManagementEnabled()
fun <T> override(value: T?, key: Preferences.Key<T>) = updatePreferences {
if (value == null) {
it.remove(key)
@ -139,4 +142,5 @@ object DebugFeatureKeys {
val forceUsageOfOpusEncoder = booleanPreferencesKey("force-usage-of-opus-encoder")
val startDmOnFirstMsg = booleanPreferencesKey("start-dm-on-first-msg")
val newAppLayoutEnabled = booleanPreferencesKey("new-app-layout-enabled")
val newDeviceManagementEnabled = booleanPreferencesKey("new-device-management-enabled")
}

View file

@ -0,0 +1,37 @@
/*
* 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.features.debug.leak
import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.core.extensions.addFragment
import im.vector.app.core.platform.VectorBaseActivity
import im.vector.app.databinding.ActivitySimpleBinding
@AndroidEntryPoint
class DebugMemoryLeaksActivity : VectorBaseActivity<ActivitySimpleBinding>() {
override fun getBinding() = ActivitySimpleBinding.inflate(layoutInflater)
override fun initUiAndData() {
if (isFirstCreation()) {
addFragment(
views.simpleFragmentContainer,
DebugMemoryLeaksFragment::class.java
)
}
}
}

View file

@ -0,0 +1,54 @@
/*
* 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.features.debug.leak
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState
import dagger.hilt.android.AndroidEntryPoint
import im.vector.app.core.epoxy.onClick
import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.databinding.FragmentDebugMemoryLeaksBinding
@AndroidEntryPoint
class DebugMemoryLeaksFragment : VectorBaseFragment<FragmentDebugMemoryLeaksBinding>() {
private val viewModel: DebugMemoryLeaksViewModel by fragmentViewModel()
override fun getBinding(inflater: LayoutInflater, container: ViewGroup?): FragmentDebugMemoryLeaksBinding {
return FragmentDebugMemoryLeaksBinding.inflate(inflater, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setViewListeners()
}
private fun setViewListeners() {
views.enableMemoryLeakAnalysis.onClick {
viewModel.handle(DebugMemoryLeaksViewActions.EnableMemoryLeaksAnalysis(views.enableMemoryLeakAnalysis.isChecked))
}
}
override fun invalidate() = withState(viewModel) { viewState ->
views.enableMemoryLeakAnalysis.isChecked = viewState.isMemoryLeaksAnalysisEnabled
}
}

View file

@ -0,0 +1,23 @@
/*
* 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.features.debug.leak
import im.vector.app.core.platform.VectorViewModelAction
sealed interface DebugMemoryLeaksViewActions : VectorViewModelAction {
data class EnableMemoryLeaksAnalysis(val isEnabled: Boolean) : DebugMemoryLeaksViewActions
}

View file

@ -0,0 +1,67 @@
/*
* Copyright (c) 2021 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.features.debug.leak
import com.airbnb.mvrx.MavericksViewModelFactory
import dagger.assisted.Assisted
import dagger.assisted.AssistedFactory
import dagger.assisted.AssistedInject
import im.vector.app.core.debug.LeakDetector
import im.vector.app.core.di.MavericksAssistedViewModelFactory
import im.vector.app.core.di.hiltMavericksViewModelFactory
import im.vector.app.core.platform.EmptyViewEvents
import im.vector.app.core.platform.VectorViewModel
import im.vector.app.features.settings.VectorPreferences
import kotlinx.coroutines.launch
class DebugMemoryLeaksViewModel @AssistedInject constructor(
@Assisted initialState: DebugMemoryLeaksViewState,
private val vectorPreferences: VectorPreferences,
private val leakDetector: LeakDetector,
) : VectorViewModel<DebugMemoryLeaksViewState, DebugMemoryLeaksViewActions, EmptyViewEvents>(initialState) {
@AssistedFactory
interface Factory : MavericksAssistedViewModelFactory<DebugMemoryLeaksViewModel, DebugMemoryLeaksViewState> {
override fun create(initialState: DebugMemoryLeaksViewState): DebugMemoryLeaksViewModel
}
companion object : MavericksViewModelFactory<DebugMemoryLeaksViewModel, DebugMemoryLeaksViewState> by hiltMavericksViewModelFactory()
init {
viewModelScope.launch {
refreshStateFromPreferences()
}
}
override fun handle(action: DebugMemoryLeaksViewActions) {
when (action) {
is DebugMemoryLeaksViewActions.EnableMemoryLeaksAnalysis -> handleEnableMemoryLeaksAnalysis(action)
}
}
private fun handleEnableMemoryLeaksAnalysis(action: DebugMemoryLeaksViewActions.EnableMemoryLeaksAnalysis) {
viewModelScope.launch {
vectorPreferences.enableMemoryLeakAnalysis(action.isEnabled)
leakDetector.enable(action.isEnabled)
refreshStateFromPreferences()
}
}
private fun refreshStateFromPreferences() {
setState { copy(isMemoryLeaksAnalysisEnabled = vectorPreferences.isMemoryLeakAnalysisEnabled()) }
}
}

View file

@ -0,0 +1,23 @@
/*
* 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.features.debug.leak
import com.airbnb.mvrx.MavericksState
data class DebugMemoryLeaksViewState(
val isMemoryLeaksAnalysisEnabled: Boolean = false
) : MavericksState

View file

@ -29,19 +29,19 @@ import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPl
import com.facebook.soloader.SoLoader
import com.kgurgul.flipper.RealmDatabaseDriver
import com.kgurgul.flipper.RealmDatabaseProvider
import im.vector.app.core.debug.FlipperProxy
import io.realm.RealmConfiguration
import okhttp3.Interceptor
import org.matrix.android.sdk.api.Matrix
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
class FlipperProxy @Inject constructor(
class VectorFlipperProxy @Inject constructor(
private val context: Context,
) {
) : FlipperProxy {
private val networkFlipperPlugin = NetworkFlipperPlugin()
fun init(matrix: Matrix) {
override fun init(matrix: Matrix) {
SoLoader.init(context, false)
if (FlipperUtils.shouldEnableFlipper(context)) {
@ -65,8 +65,5 @@ class FlipperProxy @Inject constructor(
}
}
@Suppress("RedundantNullableReturnType")
fun getNetworkInterceptor(): Interceptor? {
return FlipperOkhttpInterceptor(networkFlipperPlugin)
}
override fun networkInterceptor() = FlipperOkhttpInterceptor(networkFlipperPlugin)
}

View file

@ -0,0 +1,27 @@
/*
* 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.leakcanary
import im.vector.app.core.debug.LeakDetector
import leakcanary.LeakCanary
import javax.inject.Inject
class LeakCanaryLeakDetector @Inject constructor() : LeakDetector {
override fun enable(enable: Boolean) {
LeakCanary.config = LeakCanary.config.copy(dumpHeap = enable)
}
}

View file

@ -22,14 +22,24 @@ import android.content.Intent
import android.content.IntentFilter
import android.content.SharedPreferences
import androidx.core.content.edit
import im.vector.app.core.debug.DebugReceiver
import im.vector.app.core.di.DefaultSharedPreferences
import im.vector.app.core.utils.lsFiles
import timber.log.Timber
import javax.inject.Inject
/**
* Receiver to handle some command from ADB
*/
class DebugReceiver : BroadcastReceiver() {
class VectorDebugReceiver @Inject constructor() : BroadcastReceiver(), DebugReceiver {
override fun register(context: Context) {
context.registerReceiver(this, getIntentFilter(context))
}
override fun unregister(context: Context) {
context.unregisterReceiver(this)
}
override fun onReceive(context: Context, intent: Intent) {
Timber.v("Received debug action: ${intent.action}")

View file

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/coordinatorLayout"
android:layout_width="match_parent"
@ -8,8 +9,11 @@
tools:ignore="HardcodedText">
<ScrollView
android:id="@+id/scrollView2"
android:layout_width="match_parent"
android:layout_height="wrap_content">
android:layout_height="wrap_content"
app:layout_anchor="@+id/scrollView2"
app:layout_anchorGravity="center">
<LinearLayout
android:layout_width="match_parent"
@ -38,6 +42,12 @@
android:layout_height="wrap_content"
android:text="Analytics" />
<Button
android:id="@+id/debug_memory_leaks"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Memory leaks" />
<Button
android:id="@+id/debug_test_text_view_link"
android:layout_width="wrap_content"

View file

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/coordinatorLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".features.debug.settings.DebugPrivateSettingsActivity"
tools:ignore="HardcodedText">
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:divider="@drawable/linear_divider"
android:orientation="vertical"
android:padding="@dimen/layout_horizontal_margin"
android:showDividers="middle">
<CheckBox
android:id="@+id/enableMemoryLeakAnalysis"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Enable memory leak analysis" />
</LinearLayout>
</ScrollView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View file

@ -17,20 +17,46 @@
package im.vector.app.di
import android.content.Context
import dagger.Binds
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import im.vector.app.core.pushers.FcmHelper
import im.vector.app.core.services.GuardServiceStarter
import im.vector.app.fdroid.service.FDroidGuardServiceStarter
import im.vector.app.features.home.NightlyProxy
import im.vector.app.features.settings.VectorPreferences
import im.vector.app.features.settings.legals.FlavorLegals
import im.vector.app.push.fcm.FdroidFcmHelper
@InstallIn(SingletonComponent::class)
@Module
object FlavorModule {
abstract class FlavorModule {
@Provides
fun provideGuardServiceStarter(preferences: VectorPreferences, appContext: Context): GuardServiceStarter {
return FDroidGuardServiceStarter(preferences, appContext)
companion object {
@Provides
fun provideGuardServiceStarter(preferences: VectorPreferences, appContext: Context): GuardServiceStarter {
return FDroidGuardServiceStarter(preferences, appContext)
}
@Provides
fun provideNightlyProxy() = object : NightlyProxy {
override fun onHomeResumed() {
// no op
}
}
@Provides
fun providesFlavorLegals() = object : FlavorLegals {
override fun hasThirdPartyNotices() = false
override fun navigateToThirdPartyNotices(context: Context) {
// no op
}
}
}
@Binds
abstract fun bindsFcmHelper(fcmHelper: FdroidFcmHelper): FcmHelper
}

View file

@ -0,0 +1,31 @@
/*
* 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.di
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.android.components.ActivityComponent
import im.vector.app.features.push.NotificationTroubleshootTestManagerFactory
import im.vector.app.push.fcm.FdroidNotificationTroubleshootTestManagerFactory
@InstallIn(ActivityComponent::class)
@Module
abstract class NotificationTestModule {
@Binds
abstract fun bindsNotificationTestFactory(factory: FdroidNotificationTroubleshootTestManagerFactory): NotificationTroubleshootTestManagerFactory
}

View file

@ -20,6 +20,7 @@ package im.vector.app.push.fcm
import android.app.Activity
import android.content.Context
import im.vector.app.core.di.ActiveSessionHolder
import im.vector.app.core.pushers.FcmHelper
import im.vector.app.core.pushers.PushersManager
import im.vector.app.fdroid.BackgroundSyncStarter
import im.vector.app.fdroid.receiver.AlarmSyncBroadcastReceiver
@ -28,47 +29,32 @@ import javax.inject.Inject
/**
* This class has an alter ego in the gplay variant.
*/
class FcmHelper @Inject constructor(
class FdroidFcmHelper @Inject constructor(
private val context: Context,
private val backgroundSyncStarter: BackgroundSyncStarter,
) {
) : FcmHelper {
fun isFirebaseAvailable(): Boolean = false
override fun isFirebaseAvailable(): Boolean = false
/**
* Retrieves the FCM registration token.
*
* @return the FCM token or null if not received from FCM
*/
fun getFcmToken(): String? {
override fun getFcmToken(): String? {
return null
}
/**
* Store FCM token to the SharedPrefs
*
* @param token the token to store
*/
fun storeFcmToken(token: String?) {
override fun storeFcmToken(token: String?) {
// No op
}
/**
* onNewToken may not be called on application upgrade, so ensure my shared pref is set
*
* @param activity the first launch Activity
*/
fun ensureFcmTokenIsRetrieved(activity: Activity, pushersManager: PushersManager, registerPusher: Boolean) {
override fun ensureFcmTokenIsRetrieved(activity: Activity, pushersManager: PushersManager, registerPusher: Boolean) {
// No op
}
fun onEnterForeground(activeSessionHolder: ActiveSessionHolder) {
override fun onEnterForeground(activeSessionHolder: ActiveSessionHolder) {
// try to stop all regardless of background mode
activeSessionHolder.getSafeActiveSession()?.syncService()?.stopAnyBackgroundSync()
AlarmSyncBroadcastReceiver.cancelAlarm(context)
}
fun onEnterBackground(activeSessionHolder: ActiveSessionHolder) {
override fun onEnterBackground(activeSessionHolder: ActiveSessionHolder) {
backgroundSyncStarter.start(activeSessionHolder)
}
}

View file

@ -21,6 +21,7 @@ import im.vector.app.fdroid.features.settings.troubleshoot.TestAutoStartBoot
import im.vector.app.fdroid.features.settings.troubleshoot.TestBackgroundRestrictions
import im.vector.app.fdroid.features.settings.troubleshoot.TestBatteryOptimization
import im.vector.app.features.VectorFeatures
import im.vector.app.features.push.NotificationTroubleshootTestManagerFactory
import im.vector.app.features.settings.troubleshoot.NotificationTroubleshootTestManager
import im.vector.app.features.settings.troubleshoot.TestAccountSettings
import im.vector.app.features.settings.troubleshoot.TestAvailableUnifiedPushDistributors
@ -35,7 +36,7 @@ import im.vector.app.features.settings.troubleshoot.TestUnifiedPushEndpoint
import im.vector.app.features.settings.troubleshoot.TestUnifiedPushGateway
import javax.inject.Inject
class NotificationTroubleshootTestManagerFactory @Inject constructor(
class FdroidNotificationTroubleshootTestManagerFactory @Inject constructor(
private val unifiedPushHelper: UnifiedPushHelper,
private val testSystemSettings: TestSystemSettings,
private val testAccountSettings: TestAccountSettings,
@ -52,9 +53,9 @@ class NotificationTroubleshootTestManagerFactory @Inject constructor(
private val testBatteryOptimization: TestBatteryOptimization,
private val testNotification: TestNotification,
private val vectorFeatures: VectorFeatures,
) {
) : NotificationTroubleshootTestManagerFactory {
fun create(fragment: Fragment): NotificationTroubleshootTestManager {
override fun create(fragment: Fragment): NotificationTroubleshootTestManager {
val mgr = NotificationTroubleshootTestManager(fragment)
mgr.addTest(testSystemSettings)
mgr.addTest(testAccountSettings)

View file

@ -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
import android.content.Context
import android.content.Intent
import com.google.android.gms.oss.licenses.OssLicensesMenuActivity
import im.vector.app.features.settings.legals.FlavorLegals
import javax.inject.Inject
class GoogleFlavorLegals @Inject constructor() : FlavorLegals {
override fun hasThirdPartyNotices() = true
override fun navigateToThirdPartyNotices(context: Context) {
// See https://developers.google.com/android/guides/opensource
context.startActivity(Intent(context, OssLicensesMenuActivity::class.java))
}
}

View file

@ -16,18 +16,36 @@
package im.vector.app.di
import dagger.Binds
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import im.vector.app.GoogleFlavorLegals
import im.vector.app.core.pushers.FcmHelper
import im.vector.app.core.services.GuardServiceStarter
import im.vector.app.features.home.NightlyProxy
import im.vector.app.features.settings.legals.FlavorLegals
import im.vector.app.nightly.FirebaseNightlyProxy
import im.vector.app.push.fcm.GoogleFcmHelper
@InstallIn(SingletonComponent::class)
@Module
object FlavorModule {
abstract class FlavorModule {
@Provides
fun provideGuardServiceStarter(): GuardServiceStarter {
return object : GuardServiceStarter {}
companion object {
@Provides
fun provideGuardServiceStarter(): GuardServiceStarter {
return object : GuardServiceStarter {}
}
}
@Binds
abstract fun bindsNightlyProxy(nightlyProxy: FirebaseNightlyProxy): NightlyProxy
@Binds
abstract fun bindsFcmHelper(fcmHelper: GoogleFcmHelper): FcmHelper
@Binds
abstract fun bindsFlavorLegals(legals: GoogleFlavorLegals): FlavorLegals
}

View file

@ -0,0 +1,31 @@
/*
* 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.di
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.android.components.ActivityComponent
import im.vector.app.features.push.NotificationTroubleshootTestManagerFactory
import im.vector.app.push.fcm.GoogleNotificationTroubleshootTestManagerFactory
@InstallIn(ActivityComponent::class)
@Module
abstract class NotificationTestModule {
@Binds
abstract fun bindsNotificationTestFactory(factory: GoogleNotificationTroubleshootTestManagerFactory): NotificationTroubleshootTestManagerFactory
}

View file

@ -20,10 +20,10 @@ import androidx.activity.result.ActivityResultLauncher
import androidx.fragment.app.FragmentActivity
import com.google.firebase.messaging.FirebaseMessaging
import im.vector.app.R
import im.vector.app.core.pushers.FcmHelper
import im.vector.app.core.resources.StringProvider
import im.vector.app.core.utils.startAddGoogleAccountIntent
import im.vector.app.features.settings.troubleshoot.TroubleshootTest
import im.vector.app.push.fcm.FcmHelper
import timber.log.Timber
import javax.inject.Inject

View file

@ -23,10 +23,10 @@ import androidx.work.WorkInfo
import androidx.work.WorkManager
import im.vector.app.R
import im.vector.app.core.di.ActiveSessionHolder
import im.vector.app.core.pushers.FcmHelper
import im.vector.app.core.pushers.PushersManager
import im.vector.app.core.resources.StringProvider
import im.vector.app.features.settings.troubleshoot.TroubleshootTest
import im.vector.app.push.fcm.FcmHelper
import org.matrix.android.sdk.api.session.pushers.PusherState
import javax.inject.Inject

View file

@ -23,15 +23,17 @@ import com.google.firebase.appdistribution.FirebaseAppDistributionException
import im.vector.app.BuildConfig
import im.vector.app.core.di.DefaultPreferences
import im.vector.app.core.time.Clock
import im.vector.app.features.home.NightlyProxy
import timber.log.Timber
import javax.inject.Inject
class NightlyProxy @Inject constructor(
class FirebaseNightlyProxy @Inject constructor(
private val clock: Clock,
@DefaultPreferences
private val sharedPreferences: SharedPreferences,
) {
fun onHomeResumed() {
) : NightlyProxy {
override fun onHomeResumed() {
if (!canDisplayPopup()) return
val firebaseAppDistribution = FirebaseAppDistribution.getInstance()
firebaseAppDistribution.updateIfNewReleaseAvailable()

View file

@ -25,6 +25,7 @@ import com.google.firebase.messaging.FirebaseMessaging
import im.vector.app.R
import im.vector.app.core.di.ActiveSessionHolder
import im.vector.app.core.di.DefaultSharedPreferences
import im.vector.app.core.pushers.FcmHelper
import im.vector.app.core.pushers.PushersManager
import timber.log.Timber
import javax.inject.Inject
@ -33,44 +34,29 @@ import javax.inject.Inject
* This class store the FCM token in SharedPrefs and ensure this token is retrieved.
* It has an alter ego in the fdroid variant.
*/
class FcmHelper @Inject constructor(
class GoogleFcmHelper @Inject constructor(
context: Context,
) {
) : FcmHelper {
companion object {
private const val PREFS_KEY_FCM_TOKEN = "FCM_TOKEN"
}
private val sharedPrefs = DefaultSharedPreferences.getInstance(context)
fun isFirebaseAvailable(): Boolean = true
override fun isFirebaseAvailable(): Boolean = true
/**
* Retrieves the FCM registration token.
*
* @return the FCM token or null if not received from FCM
*/
fun getFcmToken(): String? {
override fun getFcmToken(): String? {
return sharedPrefs.getString(PREFS_KEY_FCM_TOKEN, null)
}
/**
* Store FCM token to the SharedPrefs
* TODO Store in realm
*
* @param token the token to store
*/
fun storeFcmToken(token: String?) {
override fun storeFcmToken(token: String?) {
// TODO Store in realm
sharedPrefs.edit {
putString(PREFS_KEY_FCM_TOKEN, token)
}
}
/**
* onNewToken may not be called on application upgrade, so ensure my shared pref is set
*
* @param activity the first launch Activity
*/
fun ensureFcmTokenIsRetrieved(activity: Activity, pushersManager: PushersManager, registerPusher: Boolean) {
override fun ensureFcmTokenIsRetrieved(activity: Activity, pushersManager: PushersManager, registerPusher: Boolean) {
// if (TextUtils.isEmpty(getFcmToken(activity))) {
// 'app should always check the device for a compatible Google Play services APK before accessing Google Play services features'
if (checkPlayServices(activity)) {
@ -105,13 +91,11 @@ class FcmHelper @Inject constructor(
return resultCode == ConnectionResult.SUCCESS
}
@Suppress("UNUSED_PARAMETER")
fun onEnterForeground(activeSessionHolder: ActiveSessionHolder) {
override fun onEnterForeground(activeSessionHolder: ActiveSessionHolder) {
// No op
}
@Suppress("UNUSED_PARAMETER")
fun onEnterBackground(activeSessionHolder: ActiveSessionHolder) {
override fun onEnterBackground(activeSessionHolder: ActiveSessionHolder) {
// No op
}
}

View file

@ -18,6 +18,7 @@ package im.vector.app.push.fcm
import androidx.fragment.app.Fragment
import im.vector.app.core.pushers.UnifiedPushHelper
import im.vector.app.features.VectorFeatures
import im.vector.app.features.push.NotificationTroubleshootTestManagerFactory
import im.vector.app.features.settings.troubleshoot.NotificationTroubleshootTestManager
import im.vector.app.features.settings.troubleshoot.TestAccountSettings
import im.vector.app.features.settings.troubleshoot.TestAvailableUnifiedPushDistributors
@ -35,7 +36,7 @@ import im.vector.app.gplay.features.settings.troubleshoot.TestPlayServices
import im.vector.app.gplay.features.settings.troubleshoot.TestTokenRegistration
import javax.inject.Inject
class NotificationTroubleshootTestManagerFactory @Inject constructor(
class GoogleNotificationTroubleshootTestManagerFactory @Inject constructor(
private val unifiedPushHelper: UnifiedPushHelper,
private val testSystemSettings: TestSystemSettings,
private val testAccountSettings: TestAccountSettings,
@ -52,9 +53,9 @@ class NotificationTroubleshootTestManagerFactory @Inject constructor(
private val testPushFromPushGateway: TestPushFromPushGateway,
private val testNotification: TestNotification,
private val vectorFeatures: VectorFeatures,
) {
) : NotificationTroubleshootTestManagerFactory {
fun create(fragment: Fragment): NotificationTroubleshootTestManager {
override fun create(fragment: Fragment): NotificationTroubleshootTestManager {
val mgr = NotificationTroubleshootTestManager(fragment)
mgr.addTest(testSystemSettings)
mgr.addTest(testAccountSettings)

View file

@ -187,7 +187,6 @@
android:name="android.support.PARENT_ACTIVITY"
android:value=".features.home.HomeActivity" />
</activity>
<activity android:name=".features.debug.DebugMenuActivity" />
<activity android:name=".features.createdirect.CreateDirectRoomActivity" />
<activity android:name=".features.invite.InviteUsersToRoomActivity" />
<activity android:name=".features.webview.VectorWebViewActivity" />

View file

@ -42,12 +42,14 @@ interface SpaceStateHandler : DefaultLifecycleObserver {
* @param session the current active session
* @param persistNow if true, the current space will immediately be persisted in shared prefs
* @param isForwardNavigation whether this navigation is a forward action to properly handle backstack
* @param overriddenSpaceName overrides the display name of the space being set
*/
fun setCurrentSpace(
spaceId: String?,
session: Session? = null,
persistNow: Boolean = false,
isForwardNavigation: Boolean = true,
overriddenSpaceName: String? = null,
)
/**
@ -57,7 +59,7 @@ interface SpaceStateHandler : DefaultLifecycleObserver {
*/
fun popSpaceBackstack(): String?
fun getPersistedSpaceBackstack(): List<String?>
fun getSpaceBackstack(): List<String?>
/**
* Gets a flow of the selected space for clients to react immediately to space changes.

View file

@ -72,10 +72,13 @@ class SpaceStateHandlerImpl @Inject constructor(
session: Session?,
persistNow: Boolean,
isForwardNavigation: Boolean,
overriddenSpaceName: String?,
) {
val activeSession = session ?: activeSessionHolder.getSafeActiveSession() ?: return
val spaceToLeave = selectedSpaceDataSource.currentValue?.orNull()
val spaceToSet = spaceId?.let { activeSession.getRoomSummary(spaceId) }
val spaceToSet = spaceId?.let { activeSession.getRoomSummary(spaceId) }?.let {
if (overriddenSpaceName != null) it.copy(displayName = overriddenSpaceName) else it
}
val sameSpaceSelected = spaceId == spaceToLeave?.roomId
if (sameSpaceSelected) {
@ -106,13 +109,13 @@ class SpaceStateHandlerImpl @Inject constructor(
}
private fun addToBackstack(spaceToLeave: RoomSummary?, spaceToSet: RoomSummary?) {
// Only add to the persisted backstack if the space to set is not All Chats, else reset the persisted stack
// Only add to the backstack if the space to set is not All Chats, else clear the backstack
if (spaceToSet != null) {
val currentPersistedBackstack = vectorPreferences.getPersistedSpaceBackstack().toMutableList()
val currentPersistedBackstack = vectorPreferences.getSpaceBackstack().toMutableList()
currentPersistedBackstack.add(spaceToLeave?.roomId)
vectorPreferences.setPersistedSpaceBackstack(currentPersistedBackstack)
vectorPreferences.setSpaceBackstack(currentPersistedBackstack)
} else {
vectorPreferences.setPersistedSpaceBackstack(emptyList())
vectorPreferences.setSpaceBackstack(emptyList())
}
}
@ -140,14 +143,14 @@ class SpaceStateHandlerImpl @Inject constructor(
}
override fun popSpaceBackstack(): String? {
vectorPreferences.getPersistedSpaceBackstack().toMutableList().apply {
vectorPreferences.getSpaceBackstack().toMutableList().apply {
val poppedSpaceId = removeLast()
vectorPreferences.setPersistedSpaceBackstack(this)
vectorPreferences.setSpaceBackstack(this)
return poppedSpaceId
}
}
override fun getPersistedSpaceBackstack() = vectorPreferences.getPersistedSpaceBackstack()
override fun getSpaceBackstack() = vectorPreferences.getSpaceBackstack()
override fun getSelectedSpaceFlow() = selectedSpaceFlow

View file

@ -25,23 +25,30 @@ import android.content.res.Configuration
import android.os.Handler
import android.os.HandlerThread
import android.os.StrictMode
import android.view.Gravity
import androidx.core.provider.FontRequest
import androidx.core.provider.FontsContractCompat
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.ProcessLifecycleOwner
import androidx.multidex.MultiDex
import androidx.recyclerview.widget.SnapHelper
import com.airbnb.epoxy.Carousel
import com.airbnb.epoxy.EpoxyAsyncUtil
import com.airbnb.epoxy.EpoxyController
import com.airbnb.mvrx.Mavericks
import com.facebook.stetho.Stetho
import com.gabrielittner.threetenbp.LazyThreeTen
import com.github.rubensousa.gravitysnaphelper.GravitySnapHelper
import com.mapbox.mapboxsdk.Mapbox
import com.vanniktech.emoji.EmojiManager
import com.vanniktech.emoji.google.GoogleEmojiProvider
import dagger.hilt.android.HiltAndroidApp
import im.vector.app.config.Config
import im.vector.app.core.debug.FlipperProxy
import im.vector.app.core.debug.LeakDetector
import im.vector.app.core.di.ActiveSessionHolder
import im.vector.app.core.pushers.FcmHelper
import im.vector.app.core.resources.BuildMeta
import im.vector.app.features.analytics.VectorAnalytics
import im.vector.app.features.call.webrtc.WebRtcCallManager
@ -59,8 +66,6 @@ import im.vector.app.features.settings.VectorLocale
import im.vector.app.features.settings.VectorPreferences
import im.vector.app.features.themes.ThemeUtils
import im.vector.app.features.version.VersionProvider
import im.vector.app.flipper.FlipperProxy
import im.vector.app.push.fcm.FcmHelper
import org.jitsi.meet.sdk.log.JitsiMeetDefaultLogHandler
import org.matrix.android.sdk.api.Matrix
import org.matrix.android.sdk.api.auth.AuthenticationService
@ -102,6 +107,7 @@ class VectorApplication :
@Inject lateinit var matrix: Matrix
@Inject lateinit var fcmHelper: FcmHelper
@Inject lateinit var buildMeta: BuildMeta
@Inject lateinit var leakDetector: LeakDetector
// font thread handler
private var fontThreadHandler: Handler? = null
@ -141,8 +147,9 @@ class VectorApplication :
logInfo()
LazyThreeTen.init(this)
Mavericks.initialize(debugMode = false)
EpoxyController.defaultDiffingHandler = EpoxyAsyncUtil.getAsyncBackgroundHandler()
EpoxyController.defaultModelBuildingHandler = EpoxyAsyncUtil.getAsyncBackgroundHandler()
configureEpoxy()
registerActivityLifecycleCallbacks(VectorActivityLifecycleCallbacks(popupAlertManager))
val fontRequest = FontRequest(
"com.google.android.gms.fonts",
@ -196,6 +203,18 @@ class VectorApplication :
// Initialize Mapbox before inflating mapViews
Mapbox.getInstance(this)
initMemoryLeakAnalysis()
}
private fun configureEpoxy() {
EpoxyController.defaultDiffingHandler = EpoxyAsyncUtil.getAsyncBackgroundHandler()
EpoxyController.defaultModelBuildingHandler = EpoxyAsyncUtil.getAsyncBackgroundHandler()
Carousel.setDefaultGlobalSnapHelperFactory(object : Carousel.SnapHelperFactory() {
override fun buildSnapHelper(context: Context?): SnapHelper {
return GravitySnapHelper(Gravity.START)
}
})
}
private fun enableStrictModeIfNeeded() {
@ -251,4 +270,8 @@ class VectorApplication :
handlerThread.start()
return Handler(handlerThread.looper)
}
private fun initMemoryLeakAnalysis() {
leakDetector.enable(vectorPreferences.isMemoryLeakAnalysisEnabled())
}
}

View file

@ -14,10 +14,10 @@
* limitations under the License.
*/
package im.vector.app.nightly
package im.vector.app.core.debug
import javax.inject.Inject
import android.content.Context
class NightlyProxy @Inject constructor() {
fun onHomeResumed() = Unit
interface DebugNavigator {
fun openDebugMenu(context: Context)
}

View file

@ -1,5 +1,5 @@
/*
* Copyright 2020 New Vector Ltd
* 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.
@ -14,9 +14,11 @@
* limitations under the License.
*/
package im.vector.app
package im.vector.app.core.debug
import android.content.Context
// No op
fun openOssLicensesMenuActivity(@Suppress("UNUSED_PARAMETER") context: Context) = Unit
interface DebugReceiver {
fun register(context: Context)
fun unregister(context: Context)
}

View file

@ -14,18 +14,12 @@
* limitations under the License.
*/
package im.vector.app.flipper
package im.vector.app.core.debug
import okhttp3.Interceptor
import org.matrix.android.sdk.api.Matrix
import javax.inject.Inject
/**
* No op version.
*/
@Suppress("UNUSED_PARAMETER")
class FlipperProxy @Inject constructor() {
fun init(matrix: Matrix) {}
fun getNetworkInterceptor(): Interceptor? = null
interface FlipperProxy {
fun init(matrix: Matrix)
fun networkInterceptor(): Interceptor?
}

View file

@ -1,5 +1,5 @@
/*
* Copyright 2019 New Vector Ltd
* 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.
@ -14,9 +14,11 @@
* limitations under the License.
*/
package im.vector.app.features.debug
package im.vector.app.core.debug
import androidx.appcompat.app.AppCompatActivity
// This activity is not accessible
class DebugMenuActivity : AppCompatActivity()
/**
* Used for memory leak analysis control.
*/
interface LeakDetector {
fun enable(enable: Boolean)
}

View file

@ -79,24 +79,6 @@ import im.vector.app.features.login.LoginSplashFragment
import im.vector.app.features.login.LoginWaitForEmailFragment
import im.vector.app.features.login.LoginWebFragment
import im.vector.app.features.login.terms.LoginTermsFragment
import im.vector.app.features.login2.LoginCaptchaFragment2
import im.vector.app.features.login2.LoginFragmentSigninPassword2
import im.vector.app.features.login2.LoginFragmentSigninUsername2
import im.vector.app.features.login2.LoginFragmentSignupPassword2
import im.vector.app.features.login2.LoginFragmentSignupUsername2
import im.vector.app.features.login2.LoginFragmentToAny2
import im.vector.app.features.login2.LoginGenericTextInputFormFragment2
import im.vector.app.features.login2.LoginResetPasswordFragment2
import im.vector.app.features.login2.LoginResetPasswordMailConfirmationFragment2
import im.vector.app.features.login2.LoginResetPasswordSuccessFragment2
import im.vector.app.features.login2.LoginServerSelectionFragment2
import im.vector.app.features.login2.LoginServerUrlFormFragment2
import im.vector.app.features.login2.LoginSplashSignUpSignInSelectionFragment2
import im.vector.app.features.login2.LoginSsoOnlyFragment2
import im.vector.app.features.login2.LoginWaitForEmailFragment2
import im.vector.app.features.login2.LoginWebFragment2
import im.vector.app.features.login2.created.AccountCreatedFragment
import im.vector.app.features.login2.terms.LoginTermsFragment2
import im.vector.app.features.matrixto.MatrixToRoomSpaceFragment
import im.vector.app.features.matrixto.MatrixToUserFragment
import im.vector.app.features.onboarding.ftueauth.FtueAuthAccountCreatedFragment
@ -334,96 +316,6 @@ interface FragmentModule {
@FragmentKey(LoginWaitForEmailFragment::class)
fun bindLoginWaitForEmailFragment(fragment: LoginWaitForEmailFragment): Fragment
@Binds
@IntoMap
@FragmentKey(LoginFragmentSigninUsername2::class)
fun bindLoginFragmentSigninUsername2(fragment: LoginFragmentSigninUsername2): Fragment
@Binds
@IntoMap
@FragmentKey(AccountCreatedFragment::class)
fun bindAccountCreatedFragment(fragment: AccountCreatedFragment): Fragment
@Binds
@IntoMap
@FragmentKey(LoginFragmentSignupUsername2::class)
fun bindLoginFragmentSignupUsername2(fragment: LoginFragmentSignupUsername2): Fragment
@Binds
@IntoMap
@FragmentKey(LoginFragmentSigninPassword2::class)
fun bindLoginFragmentSigninPassword2(fragment: LoginFragmentSigninPassword2): Fragment
@Binds
@IntoMap
@FragmentKey(LoginFragmentSignupPassword2::class)
fun bindLoginFragmentSignupPassword2(fragment: LoginFragmentSignupPassword2): Fragment
@Binds
@IntoMap
@FragmentKey(LoginCaptchaFragment2::class)
fun bindLoginCaptchaFragment2(fragment: LoginCaptchaFragment2): Fragment
@Binds
@IntoMap
@FragmentKey(LoginFragmentToAny2::class)
fun bindLoginFragmentToAny2(fragment: LoginFragmentToAny2): Fragment
@Binds
@IntoMap
@FragmentKey(LoginTermsFragment2::class)
fun bindLoginTermsFragment2(fragment: LoginTermsFragment2): Fragment
@Binds
@IntoMap
@FragmentKey(LoginServerUrlFormFragment2::class)
fun bindLoginServerUrlFormFragment2(fragment: LoginServerUrlFormFragment2): Fragment
@Binds
@IntoMap
@FragmentKey(LoginResetPasswordMailConfirmationFragment2::class)
fun bindLoginResetPasswordMailConfirmationFragment2(fragment: LoginResetPasswordMailConfirmationFragment2): Fragment
@Binds
@IntoMap
@FragmentKey(LoginResetPasswordFragment2::class)
fun bindLoginResetPasswordFragment2(fragment: LoginResetPasswordFragment2): Fragment
@Binds
@IntoMap
@FragmentKey(LoginResetPasswordSuccessFragment2::class)
fun bindLoginResetPasswordSuccessFragment2(fragment: LoginResetPasswordSuccessFragment2): Fragment
@Binds
@IntoMap
@FragmentKey(LoginServerSelectionFragment2::class)
fun bindLoginServerSelectionFragment2(fragment: LoginServerSelectionFragment2): Fragment
@Binds
@IntoMap
@FragmentKey(LoginSsoOnlyFragment2::class)
fun bindLoginSsoOnlyFragment2(fragment: LoginSsoOnlyFragment2): Fragment
@Binds
@IntoMap
@FragmentKey(LoginSplashSignUpSignInSelectionFragment2::class)
fun bindLoginSplashSignUpSignInSelectionFragment2(fragment: LoginSplashSignUpSignInSelectionFragment2): Fragment
@Binds
@IntoMap
@FragmentKey(LoginWebFragment2::class)
fun bindLoginWebFragment2(fragment: LoginWebFragment2): Fragment
@Binds
@IntoMap
@FragmentKey(LoginGenericTextInputFormFragment2::class)
fun bindLoginGenericTextInputFormFragment2(fragment: LoginGenericTextInputFormFragment2): Fragment
@Binds
@IntoMap
@FragmentKey(LoginWaitForEmailFragment2::class)
fun bindLoginWaitForEmailFragment2(fragment: LoginWaitForEmailFragment2): Fragment
@Binds
@IntoMap
@FragmentKey(FtueAuthLegacyStyleCaptchaFragment::class)

Some files were not shown because too many files have changed in this diff Show more