From ca2794193c23e639be0b2e290b8524ed793244a9 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 19 Jul 2021 18:16:36 +0200 Subject: [PATCH 01/38] Typo --- .../features/home/room/list/GroupRoomListSectionBuilder.kt | 4 ++-- .../features/home/room/list/SpaceRoomListSectionBuilder.kt | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/GroupRoomListSectionBuilder.kt b/vector/src/main/java/im/vector/app/features/home/room/list/GroupRoomListSectionBuilder.kt index 106a02cd3c..4e6fe3ccee 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/GroupRoomListSectionBuilder.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/GroupRoomListSectionBuilder.kt @@ -42,7 +42,7 @@ class GroupRoomListSectionBuilder( val appStateHandler: AppStateHandler, private val autoAcceptInvites: AutoAcceptInvites, val onDisposable: (Disposable) -> Unit, - val onUdpatable: (UpdatableLivePageResult) -> Unit + val onUpdatable: (UpdatableLivePageResult) -> Unit ) : RoomListSectionBuilder { override fun buildSections(mode: RoomListDisplayMode): List { @@ -69,7 +69,7 @@ class GroupRoomListSectionBuilder( val name = stringProvider.getString(R.string.bottom_action_rooms) session.getFilteredPagedRoomSummariesLive(qpm) .let { updatableFilterLivePageResult -> - onUdpatable(updatableFilterLivePageResult) + onUpdatable(updatableFilterLivePageResult) sections.add(RoomsSection(name, updatableFilterLivePageResult.livePagedList)) } } diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/SpaceRoomListSectionBuilder.kt b/vector/src/main/java/im/vector/app/features/home/room/list/SpaceRoomListSectionBuilder.kt index 5a296ce7ed..a05e464ab1 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/SpaceRoomListSectionBuilder.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/SpaceRoomListSectionBuilder.kt @@ -54,7 +54,7 @@ class SpaceRoomListSectionBuilder( private val suggestedRoomJoiningState: LiveData>>, private val autoAcceptInvites: AutoAcceptInvites, val onDisposable: (Disposable) -> Unit, - val onUdpatable: (UpdatableLivePageResult) -> Unit, + val onUpdatable: (UpdatableLivePageResult) -> Unit, val onlyOrphansInHome: Boolean = false ) : RoomListSectionBuilder { @@ -84,7 +84,7 @@ class SpaceRoomListSectionBuilder( val name = stringProvider.getString(R.string.bottom_action_rooms) session.getFilteredPagedRoomSummariesLive(qpm) .let { updatableFilterLivePageResult -> - onUdpatable(updatableFilterLivePageResult) + onUpdatable(updatableFilterLivePageResult) sections.add(RoomsSection(name, updatableFilterLivePageResult.livePagedList)) } } From ac8303bb990347c7cf246d8b409611c5f7060fc6 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 19 Jul 2021 18:23:14 +0200 Subject: [PATCH 02/38] Add low priority section in DM tab #3463 --- changelog.d/3463.feature | 1 + .../room/list/GroupRoomListSectionBuilder.kt | 17 +++++++++++--- .../room/list/SpaceRoomListSectionBuilder.kt | 23 +++++++++++++++---- 3 files changed, 34 insertions(+), 7 deletions(-) create mode 100644 changelog.d/3463.feature diff --git a/changelog.d/3463.feature b/changelog.d/3463.feature new file mode 100644 index 0000000000..a0a5f85393 --- /dev/null +++ b/changelog.d/3463.feature @@ -0,0 +1 @@ +Add low priority section in DM tab \ No newline at end of file diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/GroupRoomListSectionBuilder.kt b/vector/src/main/java/im/vector/app/features/home/room/list/GroupRoomListSectionBuilder.kt index 4e6fe3ccee..e4bcc8ff0c 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/GroupRoomListSectionBuilder.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/GroupRoomListSectionBuilder.kt @@ -52,7 +52,7 @@ class GroupRoomListSectionBuilder( when (mode) { RoomListDisplayMode.PEOPLE -> { - // 3 sections Invites / Fav / Dms + // 4 sections Invites / Fav / Dms / Low Priority buildPeopleSections(sections, activeGroupAwareQueries, actualGroupId) } RoomListDisplayMode.ROOMS -> { @@ -218,7 +218,19 @@ class GroupRoomListSectionBuilder( ) { it.memberships = listOf(Membership.JOIN) it.roomCategoryFilter = RoomCategoryFilter.ONLY_DM - it.roomTagQueryFilter = RoomTagQueryFilter(false, null, null) + it.roomTagQueryFilter = RoomTagQueryFilter(false, false, null) + it.activeGroupId = actualGroupId + } + + addSection( + sections, + activeSpaceAwareQueries, + R.string.low_priority_header, + false + ) { + it.memberships = listOf(Membership.JOIN) + it.roomCategoryFilter = RoomCategoryFilter.ONLY_DM + it.roomTagQueryFilter = RoomTagQueryFilter(false, true, null) it.activeGroupId = actualGroupId } } @@ -231,7 +243,6 @@ class GroupRoomListSectionBuilder( withQueryParams( { query.invoke(it) }, { roomQueryParams -> - val name = stringProvider.getString(nameRes) session.getFilteredPagedRoomSummariesLive(roomQueryParams) .also { diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/SpaceRoomListSectionBuilder.kt b/vector/src/main/java/im/vector/app/features/home/room/list/SpaceRoomListSectionBuilder.kt index a05e464ab1..725a62e7d5 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/SpaceRoomListSectionBuilder.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/SpaceRoomListSectionBuilder.kt @@ -261,7 +261,8 @@ class SpaceRoomListSectionBuilder( private fun buildDmSections(sections: MutableList, activeSpaceAwareQueries: MutableList) { if (autoAcceptInvites.showInvites()) { - addSection(sections = sections, + addSection( + sections = sections, activeSpaceUpdaters = activeSpaceAwareQueries, nameRes = R.string.invitations_header, notifyOfLocalEcho = true, @@ -273,7 +274,8 @@ class SpaceRoomListSectionBuilder( } } - addSection(sections, + addSection( + sections, activeSpaceAwareQueries, R.string.bottom_action_favourites, false, @@ -284,7 +286,8 @@ class SpaceRoomListSectionBuilder( it.roomTagQueryFilter = RoomTagQueryFilter(true, null, null) } - addSection(sections, + addSection( + sections, activeSpaceAwareQueries, R.string.bottom_action_people_x, false, @@ -292,7 +295,19 @@ class SpaceRoomListSectionBuilder( ) { it.memberships = listOf(Membership.JOIN) it.roomCategoryFilter = RoomCategoryFilter.ONLY_DM - it.roomTagQueryFilter = RoomTagQueryFilter(false, null, null) + it.roomTagQueryFilter = RoomTagQueryFilter(false, false, null) + } + + addSection( + sections, + activeSpaceAwareQueries, + R.string.low_priority_header, + false, + RoomListViewModel.SpaceFilterStrategy.ALL_IF_SPACE_NULL + ) { + it.memberships = listOf(Membership.JOIN) + it.roomCategoryFilter = RoomCategoryFilter.ONLY_DM + it.roomTagQueryFilter = RoomTagQueryFilter(false, true, null) } } From 40907a71b6c0c24fa474cd2a837f644849df4f7a Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 19 Jul 2021 18:44:57 +0200 Subject: [PATCH 03/38] Cleanup --- .../api/session/room/RoomSummaryQueryParams.kt | 9 +-------- .../room/summary/RoomSummaryDataSource.kt | 18 +++++++++--------- 2 files changed, 10 insertions(+), 17 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomSummaryQueryParams.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomSummaryQueryParams.kt index 88ec2de768..b440857518 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomSummaryQueryParams.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/RoomSummaryQueryParams.kt @@ -39,12 +39,6 @@ fun spaceSummaryQueryParams(init: (RoomSummaryQueryParams.Builder.() -> Unit) = .build() } -enum class RoomCategoryFilter { - ONLY_DM, - ONLY_ROOMS, - ALL -} - /** * This class can be used to filter room summaries to use with: * [org.matrix.android.sdk.api.session.room.Room] and [org.matrix.android.sdk.api.session.room.RoomService] @@ -59,11 +53,10 @@ data class RoomSummaryQueryParams( val excludeType: List?, val includeType: List?, val activeSpaceFilter: ActiveSpaceFilter?, - var activeGroupId: String? = null + val activeGroupId: String? = null ) { class Builder { - var roomId: QueryStringValue = QueryStringValue.IsNotEmpty var displayName: QueryStringValue = QueryStringValue.IsNotEmpty var canonicalAlias: QueryStringValue = QueryStringValue.NoCondition diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryDataSource.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryDataSource.kt index bff1af60ca..0b8c6df806 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryDataSource.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/summary/RoomSummaryDataSource.kt @@ -247,10 +247,10 @@ internal class RoomSummaryDataSource @Inject constructor(@SessionDatabase privat queryParams.roomCategoryFilter?.let { when (it) { - RoomCategoryFilter.ONLY_DM -> query.equalTo(RoomSummaryEntityFields.IS_DIRECT, true) - RoomCategoryFilter.ONLY_ROOMS -> query.equalTo(RoomSummaryEntityFields.IS_DIRECT, false) + RoomCategoryFilter.ONLY_DM -> query.equalTo(RoomSummaryEntityFields.IS_DIRECT, true) + RoomCategoryFilter.ONLY_ROOMS -> query.equalTo(RoomSummaryEntityFields.IS_DIRECT, false) RoomCategoryFilter.ONLY_WITH_NOTIFICATIONS -> query.greaterThan(RoomSummaryEntityFields.NOTIFICATION_COUNT, 0) - RoomCategoryFilter.ALL -> { + RoomCategoryFilter.ALL -> { // nop } } @@ -274,15 +274,15 @@ internal class RoomSummaryDataSource @Inject constructor(@SessionDatabase privat query.equalTo(RoomSummaryEntityFields.ROOM_TYPE, it) } when (queryParams.roomCategoryFilter) { - RoomCategoryFilter.ONLY_DM -> query.equalTo(RoomSummaryEntityFields.IS_DIRECT, true) - RoomCategoryFilter.ONLY_ROOMS -> query.equalTo(RoomSummaryEntityFields.IS_DIRECT, false) + RoomCategoryFilter.ONLY_DM -> query.equalTo(RoomSummaryEntityFields.IS_DIRECT, true) + RoomCategoryFilter.ONLY_ROOMS -> query.equalTo(RoomSummaryEntityFields.IS_DIRECT, false) RoomCategoryFilter.ONLY_WITH_NOTIFICATIONS -> query.greaterThan(RoomSummaryEntityFields.NOTIFICATION_COUNT, 0) - RoomCategoryFilter.ALL -> Unit // nop + RoomCategoryFilter.ALL -> Unit // nop } // Timber.w("VAL: activeSpaceId : ${queryParams.activeSpaceId}") when (queryParams.activeSpaceFilter) { - is ActiveSpaceFilter.ActiveSpace -> { + is ActiveSpaceFilter.ActiveSpace -> { // It's annoying but for now realm java does not support querying in primitive list :/ // https://github.com/realm/realm-java/issues/5361 if (queryParams.activeSpaceFilter.currentSpaceId == null) { @@ -300,8 +300,8 @@ internal class RoomSummaryDataSource @Inject constructor(@SessionDatabase privat } } - if (queryParams.activeGroupId != null) { - query.contains(RoomSummaryEntityFields.GROUP_IDS, queryParams.activeGroupId!!) + queryParams.activeGroupId?.let { activeGroupId -> + query.contains(RoomSummaryEntityFields.GROUP_IDS, activeGroupId) } return query } From b8abe1b7adc6ea0e6c3ed7f9dc5d8062f7e68a73 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 19 Jul 2021 18:54:14 +0200 Subject: [PATCH 04/38] Rename class for code clarity --- ...omListSectionBuilder.kt => RoomListSectionBuilderGroup.kt} | 2 +- ...omListSectionBuilder.kt => RoomListSectionBuilderSpace.kt} | 2 +- .../vector/app/features/home/room/list/RoomListViewModel.kt | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) rename vector/src/main/java/im/vector/app/features/home/room/list/{GroupRoomListSectionBuilder.kt => RoomListSectionBuilderGroup.kt} (99%) rename vector/src/main/java/im/vector/app/features/home/room/list/{SpaceRoomListSectionBuilder.kt => RoomListSectionBuilderSpace.kt} (99%) diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/GroupRoomListSectionBuilder.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilderGroup.kt similarity index 99% rename from vector/src/main/java/im/vector/app/features/home/room/list/GroupRoomListSectionBuilder.kt rename to vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilderGroup.kt index e4bcc8ff0c..2ce18030e1 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/GroupRoomListSectionBuilder.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilderGroup.kt @@ -35,7 +35,7 @@ import org.matrix.android.sdk.api.session.room.UpdatableLivePageResult import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.rx.asObservable -class GroupRoomListSectionBuilder( +class RoomListSectionBuilderGroup( val session: Session, val stringProvider: StringProvider, val viewModelScope: CoroutineScope, diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/SpaceRoomListSectionBuilder.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilderSpace.kt similarity index 99% rename from vector/src/main/java/im/vector/app/features/home/room/list/SpaceRoomListSectionBuilder.kt rename to vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilderSpace.kt index 725a62e7d5..ff34f57c1e 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/SpaceRoomListSectionBuilder.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilderSpace.kt @@ -46,7 +46,7 @@ import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.api.session.room.summary.RoomAggregateNotificationCount import org.matrix.android.sdk.rx.asObservable -class SpaceRoomListSectionBuilder( +class RoomListSectionBuilderSpace( val session: Session, val stringProvider: StringProvider, val appStateHandler: AppStateHandler, diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewModel.kt index c5f166ea5b..0c4b9a9561 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewModel.kt @@ -122,7 +122,7 @@ class RoomListViewModel @Inject constructor( val sections: List by lazy { if (appStateHandler.getCurrentRoomGroupingMethod() is RoomGroupingMethod.BySpace) { - SpaceRoomListSectionBuilder( + RoomListSectionBuilderSpace( session, stringProvider, appStateHandler, @@ -138,7 +138,7 @@ class RoomListViewModel @Inject constructor( vectorPreferences.labsSpacesOnlyOrphansInHome() ).buildSections(initialState.displayMode) } else { - GroupRoomListSectionBuilder( + RoomListSectionBuilderGroup( session, stringProvider, viewModelScope, From 14b4bff4771cb7ba6db0b1dad5a9b4c130262079 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 19 Jul 2021 18:56:15 +0200 Subject: [PATCH 05/38] Use the interface power! --- .../vector/app/features/home/room/list/RoomListViewModel.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewModel.kt index 0c4b9a9561..f807b34889 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewModel.kt @@ -136,7 +136,7 @@ class RoomListViewModel @Inject constructor( updatableQuery = it }, vectorPreferences.labsSpacesOnlyOrphansInHome() - ).buildSections(initialState.displayMode) + ) } else { RoomListSectionBuilderGroup( session, @@ -150,8 +150,9 @@ class RoomListViewModel @Inject constructor( { updatableQuery = it } - ).buildSections(initialState.displayMode) + ) } + .buildSections(initialState.displayMode) } override fun handle(action: RoomListAction) { From 5990e5a52b9d4f6d0bc8e2b9193eda7785fe0a40 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 19 Jul 2021 18:59:27 +0200 Subject: [PATCH 06/38] Cleanup constructors --- .../room/list/RoomListSectionBuilderGroup.kt | 12 +++++------- .../room/list/RoomListSectionBuilderSpace.kt | 18 +++++++++--------- .../home/room/list/RoomListViewModel.kt | 10 ++++------ 3 files changed, 18 insertions(+), 22 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilderGroup.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilderGroup.kt index 2ce18030e1..e43370c1af 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilderGroup.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilderGroup.kt @@ -26,7 +26,6 @@ import im.vector.app.features.invite.AutoAcceptInvites import im.vector.app.features.invite.showInvites import io.reactivex.disposables.Disposable import io.reactivex.schedulers.Schedulers -import kotlinx.coroutines.CoroutineScope import org.matrix.android.sdk.api.query.RoomCategoryFilter import org.matrix.android.sdk.api.query.RoomTagQueryFilter import org.matrix.android.sdk.api.session.Session @@ -36,13 +35,12 @@ import org.matrix.android.sdk.api.session.room.model.Membership import org.matrix.android.sdk.rx.asObservable class RoomListSectionBuilderGroup( - val session: Session, - val stringProvider: StringProvider, - val viewModelScope: CoroutineScope, - val appStateHandler: AppStateHandler, + private val session: Session, + private val stringProvider: StringProvider, + private val appStateHandler: AppStateHandler, private val autoAcceptInvites: AutoAcceptInvites, - val onDisposable: (Disposable) -> Unit, - val onUpdatable: (UpdatableLivePageResult) -> Unit + private val onDisposable: (Disposable) -> Unit, + private val onUpdatable: (UpdatableLivePageResult) -> Unit ) : RoomListSectionBuilder { override fun buildSections(mode: RoomListDisplayMode): List { diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilderSpace.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilderSpace.kt index ff34f57c1e..1e1134c284 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilderSpace.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilderSpace.kt @@ -47,18 +47,18 @@ import org.matrix.android.sdk.api.session.room.summary.RoomAggregateNotification import org.matrix.android.sdk.rx.asObservable class RoomListSectionBuilderSpace( - val session: Session, - val stringProvider: StringProvider, - val appStateHandler: AppStateHandler, - val viewModelScope: CoroutineScope, - private val suggestedRoomJoiningState: LiveData>>, + private val session: Session, + private val stringProvider: StringProvider, + private val appStateHandler: AppStateHandler, + private val viewModelScope: CoroutineScope, private val autoAcceptInvites: AutoAcceptInvites, - val onDisposable: (Disposable) -> Unit, - val onUpdatable: (UpdatableLivePageResult) -> Unit, - val onlyOrphansInHome: Boolean = false + private val onDisposable: (Disposable) -> Unit, + private val onUpdatable: (UpdatableLivePageResult) -> Unit, + private val suggestedRoomJoiningState: LiveData>>, + private val onlyOrphansInHome: Boolean = false ) : RoomListSectionBuilder { - val pagedListConfig = PagedList.Config.Builder() + private val pagedListConfig = PagedList.Config.Builder() .setPageSize(10) .setInitialLoadSizeHint(20) .setEnablePlaceholders(true) diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewModel.kt index f807b34889..e8e46acc2d 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewModel.kt @@ -127,7 +127,6 @@ class RoomListViewModel @Inject constructor( stringProvider, appStateHandler, viewModelScope, - suggestedRoomJoiningState, autoAcceptInvites, { it.disposeOnClear() @@ -135,22 +134,21 @@ class RoomListViewModel @Inject constructor( { updatableQuery = it }, + suggestedRoomJoiningState, vectorPreferences.labsSpacesOnlyOrphansInHome() ) } else { RoomListSectionBuilderGroup( session, stringProvider, - viewModelScope, appStateHandler, autoAcceptInvites, { it.disposeOnClear() - }, - { - updatableQuery = it } - ) + ) { + updatableQuery = it + } } .buildSections(initialState.displayMode) } From ac2f1ee7fe20964509cd558f586a3b2d936ee599 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 19 Jul 2021 19:03:41 +0200 Subject: [PATCH 07/38] Cleanup and comment --- .../home/room/list/RoomListSectionBuilderGroup.kt | 3 +++ .../home/room/list/RoomListSectionBuilderSpace.kt | 11 +++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilderGroup.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilderGroup.kt index e43370c1af..1ca379882c 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilderGroup.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilderGroup.kt @@ -86,6 +86,7 @@ class RoomListSectionBuilderGroup( it.activeGroupId = actualGroupId } } + addSection( sections, activeGroupAwareQueries, @@ -111,6 +112,7 @@ class RoomListSectionBuilderGroup( }.also { onDisposable.invoke(it) } + return sections } @@ -257,6 +259,7 @@ class RoomListSectionBuilderGroup( }.also { onDisposable.invoke(it) } + sections.add( RoomsSection( sectionName = name, diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilderSpace.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilderSpace.kt index 1e1134c284..6edbb07992 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilderSpace.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilderSpace.kt @@ -70,12 +70,15 @@ class RoomListSectionBuilderSpace( val activeSpaceAwareQueries = mutableListOf() when (mode) { RoomListDisplayMode.PEOPLE -> { + // 4 sections Invites / Fav / Dms / Low Priority buildDmSections(sections, activeSpaceAwareQueries) } RoomListDisplayMode.ROOMS -> { + // 6 sections invites / Fav / Rooms / Low Priority / Server notice / Suggested rooms buildRoomsSections(sections, activeSpaceAwareQueries) } RoomListDisplayMode.FILTERED -> { + // Used when searching for rooms withQueryParams( { it.memberships = Membership.activeMemberships() @@ -140,7 +143,8 @@ class RoomListSectionBuilderSpace( return sections } - private fun buildRoomsSections(sections: MutableList, activeSpaceAwareQueries: MutableList) { + private fun buildRoomsSections(sections: MutableList, + activeSpaceAwareQueries: MutableList) { if (autoAcceptInvites.showInvites()) { addSection( sections = sections, @@ -259,7 +263,8 @@ class RoomListSectionBuilderSpace( ) } - private fun buildDmSections(sections: MutableList, activeSpaceAwareQueries: MutableList) { + private fun buildDmSections(sections: MutableList, + activeSpaceAwareQueries: MutableList) { if (autoAcceptInvites.showInvites()) { addSection( sections = sections, @@ -321,7 +326,6 @@ class RoomListSectionBuilderSpace( withQueryParams( { query.invoke(it) }, { roomQueryParams -> - val name = stringProvider.getString(nameRes) session.getFilteredPagedRoomSummariesLive( roomQueryParams.process(spaceFilterStrategy, appStateHandler.safeActiveSpaceId()), @@ -364,7 +368,6 @@ class RoomListSectionBuilderSpace( } }.livePagedList .let { livePagedList -> - // use it also as a source to update count livePagedList.asObservable() .observeOn(Schedulers.computation()) From 256df7e8699a84ee1973807d9d4de0fe0d9e9e1d Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 19 Jul 2021 19:18:49 +0200 Subject: [PATCH 08/38] Rework on how we dispose the subscriptions --- .../home/room/list/RoomListSectionBuilder.kt | 2 + .../room/list/RoomListSectionBuilderGroup.kt | 13 ++-- .../room/list/RoomListSectionBuilderSpace.kt | 15 +++-- .../home/room/list/RoomListViewModel.kt | 60 +++++++++---------- 4 files changed, 51 insertions(+), 39 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilder.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilder.kt index 5267158000..019a6ceddf 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilder.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilder.kt @@ -20,4 +20,6 @@ import im.vector.app.features.home.RoomListDisplayMode interface RoomListSectionBuilder { fun buildSections(mode: RoomListDisplayMode) : List + + fun dispose() } diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilderGroup.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilderGroup.kt index 1ca379882c..f101669af3 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilderGroup.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilderGroup.kt @@ -24,7 +24,7 @@ import im.vector.app.core.resources.StringProvider import im.vector.app.features.home.RoomListDisplayMode import im.vector.app.features.invite.AutoAcceptInvites import im.vector.app.features.invite.showInvites -import io.reactivex.disposables.Disposable +import io.reactivex.disposables.CompositeDisposable import io.reactivex.schedulers.Schedulers import org.matrix.android.sdk.api.query.RoomCategoryFilter import org.matrix.android.sdk.api.query.RoomTagQueryFilter @@ -39,10 +39,11 @@ class RoomListSectionBuilderGroup( private val stringProvider: StringProvider, private val appStateHandler: AppStateHandler, private val autoAcceptInvites: AutoAcceptInvites, - private val onDisposable: (Disposable) -> Unit, private val onUpdatable: (UpdatableLivePageResult) -> Unit ) : RoomListSectionBuilder { + private val disposables = CompositeDisposable() + override fun buildSections(mode: RoomListDisplayMode): List { val activeGroupAwareQueries = mutableListOf() val sections = mutableListOf() @@ -110,7 +111,7 @@ class RoomListSectionBuilderGroup( } } }.also { - onDisposable.invoke(it) + disposables.add(it) } return sections @@ -257,7 +258,7 @@ class RoomListSectionBuilderGroup( ?.notificationCount ?.postValue(session.getNotificationCountForRooms(roomQueryParams)) }.also { - onDisposable.invoke(it) + disposables.add(it) } sections.add( @@ -279,4 +280,8 @@ class RoomListSectionBuilderGroup( .build() .let { block(it) } } + + override fun dispose() { + disposables.dispose() + } } diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilderSpace.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilderSpace.kt index 6edbb07992..13a6fc0d2d 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilderSpace.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListSectionBuilderSpace.kt @@ -30,7 +30,7 @@ import im.vector.app.features.invite.AutoAcceptInvites import im.vector.app.features.invite.showInvites import im.vector.app.space import io.reactivex.Observable -import io.reactivex.disposables.Disposable +import io.reactivex.disposables.CompositeDisposable import io.reactivex.rxkotlin.Observables import io.reactivex.schedulers.Schedulers import kotlinx.coroutines.CoroutineScope @@ -52,12 +52,13 @@ class RoomListSectionBuilderSpace( private val appStateHandler: AppStateHandler, private val viewModelScope: CoroutineScope, private val autoAcceptInvites: AutoAcceptInvites, - private val onDisposable: (Disposable) -> Unit, private val onUpdatable: (UpdatableLivePageResult) -> Unit, private val suggestedRoomJoiningState: LiveData>>, private val onlyOrphansInHome: Boolean = false ) : RoomListSectionBuilder { + private val disposables = CompositeDisposable() + private val pagedListConfig = PagedList.Config.Builder() .setPageSize(10) .setInitialLoadSizeHint(20) @@ -137,7 +138,7 @@ class RoomListSectionBuilderSpace( updater.updateForSpaceId(selectedSpace?.roomId) } }.also { - onDisposable.invoke(it) + disposables.add(it) } return sections @@ -252,7 +253,7 @@ class RoomListSectionBuilderSpace( }.subscribe { liveSuggestedRooms.postValue(it) }.also { - onDisposable.invoke(it) + disposables.add(it) } sections.add( RoomsSection( @@ -384,7 +385,7 @@ class RoomListSectionBuilderSpace( } ) }.also { - onDisposable.invoke(it) + disposables.add(it) } sections.add( @@ -428,4 +429,8 @@ class RoomListSectionBuilderSpace( RoomListViewModel.SpaceFilterStrategy.NONE -> this } } + + override fun dispose() { + disposables.dispose() + } } diff --git a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewModel.kt b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewModel.kt index e8e46acc2d..845be0b18b 100644 --- a/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/home/room/list/RoomListViewModel.kt @@ -120,37 +120,32 @@ class RoomListViewModel @Inject constructor( } } - val sections: List by lazy { - if (appStateHandler.getCurrentRoomGroupingMethod() is RoomGroupingMethod.BySpace) { - RoomListSectionBuilderSpace( - session, - stringProvider, - appStateHandler, - viewModelScope, - autoAcceptInvites, - { - it.disposeOnClear() - }, - { - updatableQuery = it - }, - suggestedRoomJoiningState, - vectorPreferences.labsSpacesOnlyOrphansInHome() - ) - } else { - RoomListSectionBuilderGroup( - session, - stringProvider, - appStateHandler, - autoAcceptInvites, - { - it.disposeOnClear() - } - ) { - updatableQuery = it - } + private val roomListSectionBuilder = if (appStateHandler.getCurrentRoomGroupingMethod() is RoomGroupingMethod.BySpace) { + RoomListSectionBuilderSpace( + session, + stringProvider, + appStateHandler, + viewModelScope, + autoAcceptInvites, + { + updatableQuery = it + }, + suggestedRoomJoiningState, + vectorPreferences.labsSpacesOnlyOrphansInHome() + ) + } else { + RoomListSectionBuilderGroup( + session, + stringProvider, + appStateHandler, + autoAcceptInvites + ) { + updatableQuery = it } - .buildSections(initialState.displayMode) + } + + val sections: List by lazy { + roomListSectionBuilder.buildSections(initialState.displayMode) } override fun handle(action: RoomListAction) { @@ -340,4 +335,9 @@ class RoomListViewModel @Inject constructor( _viewEvents.post(value) } } + + override fun onCleared() { + super.onCleared() + roomListSectionBuilder.dispose() + } } From f7e2e741c0c9b36ff28d2df36fe3a8bbacd446b6 Mon Sep 17 00:00:00 2001 From: ganfra Date: Mon, 19 Jul 2021 20:25:09 +0200 Subject: [PATCH 09/38] Missed call: start showing notification when there is a missed call --- .../vector/app/core/services/CallService.kt | 75 +++++++++++++------ .../app/features/call/webrtc/WebRtcCall.kt | 5 +- .../features/call/webrtc/WebRtcCallManager.kt | 6 +- .../notifications/NotificationUtils.kt | 20 +++++ vector/src/main/res/values/strings.xml | 1 + 5 files changed, 80 insertions(+), 27 deletions(-) diff --git a/vector/src/main/java/im/vector/app/core/services/CallService.kt b/vector/src/main/java/im/vector/app/core/services/CallService.kt index 59eee14d37..7c7b51acc9 100644 --- a/vector/src/main/java/im/vector/app/core/services/CallService.kt +++ b/vector/src/main/java/im/vector/app/core/services/CallService.kt @@ -46,7 +46,8 @@ import timber.log.Timber class CallService : VectorService() { private val connections = mutableMapOf() - private val knownCalls = mutableSetOf() + private val knownCalls = mutableSetOf() + private val ongoingCallIds = mutableSetOf() private lateinit var notificationManager: NotificationManagerCompat private lateinit var notificationUtils: NotificationUtils @@ -115,19 +116,19 @@ class CallService : VectorService() { callRingPlayerOutgoing?.start() displayOutgoingRingingCallNotification(intent) } - ACTION_ONGOING_CALL -> { + ACTION_ONGOING_CALL -> { callRingPlayerIncoming?.stop() callRingPlayerOutgoing?.stop() displayCallInProgressNotification(intent) } - ACTION_CALL_CONNECTING -> { + ACTION_CALL_CONNECTING -> { // lower notification priority displayCallInProgressNotification(intent) // stop ringing callRingPlayerIncoming?.stop() callRingPlayerOutgoing?.stop() } - ACTION_CALL_TERMINATED -> { + ACTION_CALL_TERMINATED -> { handleCallTerminated(intent) } else -> { @@ -153,9 +154,9 @@ class CallService : VectorService() { val call = callManager.getCallById(callId) ?: return Unit.also { handleUnexpectedState(callId) } + val callInformation = call.toCallInformation() val isVideoCall = call.mxCall.isVideoCall val fromBg = intent.getBooleanExtra(EXTRA_IS_IN_BG, false) - val opponentMatrixItem = getOpponentMatrixItem(call) Timber.v("displayIncomingCallNotification : display the dedicated notification") val incomingCallAlert = IncomingCallAlert(callId, shouldBeDisplayedIn = { activity -> @@ -165,7 +166,7 @@ class CallService : VectorService() { } ).apply { viewBinder = IncomingCallAlert.ViewBinder( - matrixItem = opponentMatrixItem, + matrixItem = callInformation.matrixItem, avatarRenderer = avatarRenderer, isVideoCall = isVideoCall, onAccept = { showCallScreen(call, VectorCallActivity.INCOMING_ACCEPT) }, @@ -177,7 +178,7 @@ class CallService : VectorService() { alertManager.postVectorAlert(incomingCallAlert) val notification = notificationUtils.buildIncomingCallNotification( call = call, - title = opponentMatrixItem?.getBestName() ?: call.mxCall.opponentUserId, + title = callInformation.matrixItem?.getBestName() ?: callInformation.opponentUserId, fromBg = fromBg ) if (knownCalls.isEmpty()) { @@ -185,19 +186,33 @@ class CallService : VectorService() { } else { notificationManager.notify(callId.hashCode(), notification) } - knownCalls.add(callId) + knownCalls.add(callInformation) } private fun handleCallTerminated(intent: Intent) { val callId = intent.getStringExtra(EXTRA_CALL_ID) ?: "" + val isRejected = intent.getBooleanExtra(EXTRA_IS_REJECTED, false) alertManager.cancelAlert(callId) - if (!knownCalls.remove(callId)) { + val terminatedCall = knownCalls.firstOrNull { it.callId == callId } + if (terminatedCall == null) { Timber.v("Call terminated for unknown call $callId$") handleUnexpectedState(callId) return } - val notification = notificationUtils.buildCallEndedNotification() - notificationManager.notify(callId.hashCode(), notification) + knownCalls.remove(terminatedCall) + val wasOngoing = ongoingCallIds.remove(callId) + if (wasOngoing || isRejected) { + val notification = notificationUtils.buildCallEndedNotification() + notificationManager.notify(callId.hashCode(), notification) + } else { + val notification = notificationUtils.buildCallMissedNotification( + roomId = terminatedCall.nativeRoomId, + caller = terminatedCall.matrixItem?.getBestName() ?: terminatedCall.opponentUserId + ) + notificationManager.cancel(callId.hashCode()) + notificationManager.notify(MISSED_CALL_TAG, callId.hashCode(), notification) + } + if (knownCalls.isEmpty()) { mediaSession?.isActive = false myStopSelf() @@ -218,18 +233,18 @@ class CallService : VectorService() { val call = callManager.getCallById(callId) ?: return Unit.also { handleUnexpectedState(callId) } - val opponentMatrixItem = getOpponentMatrixItem(call) + val callInformation = call.toCallInformation() Timber.v("displayOutgoingCallNotification : display the dedicated notification") val notification = notificationUtils.buildOutgoingRingingCallNotification( call = call, - title = opponentMatrixItem?.getBestName() ?: call.mxCall.opponentUserId + title = callInformation.matrixItem?.getBestName() ?: callInformation.opponentUserId ) if (knownCalls.isEmpty()) { startForeground(callId.hashCode(), notification) } else { notificationManager.notify(callId.hashCode(), notification) } - knownCalls.add(callId) + knownCalls.add(callInformation) } /** @@ -238,21 +253,22 @@ class CallService : VectorService() { private fun displayCallInProgressNotification(intent: Intent) { Timber.v("## VOIP displayCallInProgressNotification") val callId = intent.getStringExtra(EXTRA_CALL_ID) ?: "" + ongoingCallIds.add(callId) val call = callManager.getCallById(callId) ?: return Unit.also { handleUnexpectedState(callId) } - val opponentMatrixItem = getOpponentMatrixItem(call) alertManager.cancelAlert(callId) + val callInformation = call.toCallInformation() val notification = notificationUtils.buildPendingCallNotification( call = call, - title = opponentMatrixItem?.getBestName() ?: call.mxCall.opponentUserId + title = callInformation.matrixItem?.getBestName() ?: callInformation.opponentUserId ) if (knownCalls.isEmpty()) { startForeground(callId.hashCode(), notification) } else { notificationManager.notify(callId.hashCode(), notification) } - knownCalls.add(callId) + knownCalls.add(callInformation) } private fun handleUnexpectedState(callId: String?) { @@ -274,14 +290,27 @@ class CallService : VectorService() { connections[callConnection.callId] = callConnection } - private fun getOpponentMatrixItem(call: WebRtcCall): MatrixItem? { - return vectorComponent().activeSessionHolder().getSafeActiveSession()?.let { - call.getOpponentAsMatrixItem(it) - } + private fun WebRtcCall.toCallInformation(): CallInformation{ + return CallInformation( + callId = this.callId, + nativeRoomId = this.nativeRoomId, + opponentUserId = this.mxCall.opponentUserId, + matrixItem = vectorComponent().activeSessionHolder().getSafeActiveSession()?.let { + this.getOpponentAsMatrixItem(it) + } + ) } + private data class CallInformation( + val callId: String, + val nativeRoomId: String, + val opponentUserId: String, + val matrixItem: MatrixItem? + ) + companion object { private const val DEFAULT_NOTIFICATION_ID = 6480 + private const val MISSED_CALL_TAG = "MISSED_CALL_TAG" private const val ACTION_INCOMING_RINGING_CALL = "im.vector.app.core.services.CallService.ACTION_INCOMING_RINGING_CALL" private const val ACTION_OUTGOING_RINGING_CALL = "im.vector.app.core.services.CallService.ACTION_OUTGOING_RINGING_CALL" @@ -294,6 +323,7 @@ class CallService : VectorService() { private const val EXTRA_CALL_ID = "EXTRA_CALL_ID" private const val EXTRA_IS_IN_BG = "EXTRA_IS_IN_BG" + private const val EXTRA_IS_REJECTED = "EXTRA_IS_REJECTED" fun onIncomingCallRinging(context: Context, callId: String, @@ -329,11 +359,12 @@ class CallService : VectorService() { ContextCompat.startForegroundService(context, intent) } - fun onCallTerminated(context: Context, callId: String) { + fun onCallTerminated(context: Context, callId: String, isRejected: Boolean) { val intent = Intent(context, CallService::class.java) .apply { action = ACTION_CALL_TERMINATED putExtra(EXTRA_CALL_ID, callId) + putExtra(EXTRA_IS_REJECTED, isRejected) } ContextCompat.startForegroundService(context, intent) } diff --git a/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCall.kt b/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCall.kt index 3259b0915f..086a3be9d3 100644 --- a/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCall.kt +++ b/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCall.kt @@ -99,7 +99,7 @@ class WebRtcCall( private val sessionProvider: Provider, private val peerConnectionFactoryProvider: Provider, private val onCallBecomeActive: (WebRtcCall) -> Unit, - private val onCallEnded: (String) -> Unit + private val onCallEnded: (String, Boolean) -> Unit ) : MxCall.StateListener { interface Listener : MxCall.StateListener { @@ -810,7 +810,8 @@ class WebRtcCall( val wasRinging = mxCall.state is CallState.LocalRinging mxCall.state = CallState.Terminated release() - onCallEnded(callId) + val isRejected = wasRinging && sendEndSignaling + onCallEnded(callId, isRejected) if (sendEndSignaling) { if (wasRinging) { mxCall.reject() diff --git a/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCallManager.kt b/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCallManager.kt index 25463428e9..d7628cef90 100644 --- a/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCallManager.kt +++ b/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCallManager.kt @@ -232,12 +232,12 @@ class WebRtcCallManager @Inject constructor( this.currentCall.setAndNotify(call) } - private fun onCallEnded(callId: String) { + private fun onCallEnded(callId: String, isRejected: Boolean) { Timber.v("## VOIP WebRtcPeerConnectionManager onCall ended: $callId") val webRtcCall = callsByCallId.remove(callId) ?: return Unit.also { Timber.v("On call ended for unknown call $callId") } - CallService.onCallTerminated(context, callId) + CallService.onCallTerminated(context, callId, isRejected) callsByRoomId[webRtcCall.signalingRoomId]?.remove(webRtcCall) callsByRoomId[webRtcCall.nativeRoomId]?.remove(webRtcCall) transferees.remove(callId) @@ -420,7 +420,7 @@ class WebRtcCallManager @Inject constructor( override fun onCallManagedByOtherSession(callId: String) { Timber.v("## VOIP onCallManagedByOtherSession: $callId") - onCallEnded(callId) + onCallEnded(callId, false) } override fun onCallAssertedIdentityReceived(callAssertedIdentityContent: CallAssertedIdentityContent) { diff --git a/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt b/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt index 439705c9d6..d6358fe710 100755 --- a/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt +++ b/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt @@ -459,6 +459,26 @@ class NotificationUtils @Inject constructor(private val context: Context, .build() } + /** + * Build notification for the CallService, when a call is missed + */ + fun buildCallMissedNotification(roomId: String, caller: String): Notification { + val builder = NotificationCompat.Builder(context, SILENT_NOTIFICATION_CHANNEL_ID) + .setContentTitle(caller) + .setContentText(stringProvider.getString(R.string.call_missed, caller)) + .setSmallIcon(R.drawable.ic_material_call_end_grey) + .setAutoCancel(true) + .setCategory(NotificationCompat.CATEGORY_CALL) + + val contentPendingIntent = TaskStackBuilder.create(context) + .addNextIntentWithParentStack(HomeActivity.newIntent(context)) + .addNextIntent(RoomDetailActivity.newIntent(context, RoomDetailArgs(roomId))) + .getPendingIntent(System.currentTimeMillis().toInt(), PendingIntent.FLAG_UPDATE_CURRENT) + + builder.setContentIntent(contentPendingIntent) + return builder.build() + } + fun buildDownloadFileNotification(uri: Uri, fileName: String, mimeType: String): Notification { return NotificationCompat.Builder(context, SILENT_NOTIFICATION_CHANNEL_ID) .setGroup(stringProvider.getString(R.string.app_name)) diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index ef25329eed..8ef366656e 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -727,6 +727,7 @@ Call connected Call connecting… Call ended + You missed a call from %s Calling… Incoming Call Incoming Video Call From c59967fb6cf88e7f7e93a952477a2185a41a20e6 Mon Sep 17 00:00:00 2001 From: ganfra Date: Tue, 20 Jul 2021 09:40:09 +0200 Subject: [PATCH 10/38] Missed call: make some changes on notification --- .../java/im/vector/app/core/services/CallService.kt | 13 ++++++------- .../app/features/notifications/NotificationUtils.kt | 8 ++++---- vector/src/main/res/values/strings.xml | 2 +- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/vector/src/main/java/im/vector/app/core/services/CallService.kt b/vector/src/main/java/im/vector/app/core/services/CallService.kt index 7c7b51acc9..7434f8a277 100644 --- a/vector/src/main/java/im/vector/app/core/services/CallService.kt +++ b/vector/src/main/java/im/vector/app/core/services/CallService.kt @@ -200,6 +200,10 @@ class CallService : VectorService() { return } knownCalls.remove(terminatedCall) + if (knownCalls.isEmpty()) { + mediaSession?.isActive = false + myStopSelf() + } val wasOngoing = ongoingCallIds.remove(callId) if (wasOngoing || isRejected) { val notification = notificationUtils.buildCallEndedNotification() @@ -207,15 +211,10 @@ class CallService : VectorService() { } else { val notification = notificationUtils.buildCallMissedNotification( roomId = terminatedCall.nativeRoomId, - caller = terminatedCall.matrixItem?.getBestName() ?: terminatedCall.opponentUserId + title = terminatedCall.matrixItem?.getBestName() ?: terminatedCall.opponentUserId ) notificationManager.cancel(callId.hashCode()) - notificationManager.notify(MISSED_CALL_TAG, callId.hashCode(), notification) - } - - if (knownCalls.isEmpty()) { - mediaSession?.isActive = false - myStopSelf() + notificationManager.notify(MISSED_CALL_TAG, terminatedCall.nativeRoomId.hashCode(), notification) } } diff --git a/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt b/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt index d6358fe710..27771ddb2b 100755 --- a/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt +++ b/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt @@ -462,10 +462,10 @@ class NotificationUtils @Inject constructor(private val context: Context, /** * Build notification for the CallService, when a call is missed */ - fun buildCallMissedNotification(roomId: String, caller: String): Notification { - val builder = NotificationCompat.Builder(context, SILENT_NOTIFICATION_CHANNEL_ID) - .setContentTitle(caller) - .setContentText(stringProvider.getString(R.string.call_missed, caller)) + fun buildCallMissedNotification(roomId: String, title: String): Notification { + val builder = NotificationCompat.Builder(context, NOISY_NOTIFICATION_CHANNEL_ID) + .setContentTitle(title) + .setContentText(stringProvider.getString(R.string.call_missed)) .setSmallIcon(R.drawable.ic_material_call_end_grey) .setAutoCancel(true) .setCategory(NotificationCompat.CATEGORY_CALL) diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index 8ef366656e..e9c8e5b43e 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -727,7 +727,7 @@ Call connected Call connecting… Call ended - You missed a call from %s + Missed call Calling… Incoming Call Incoming Video Call From 278bba3ada4fe312d526becf5a5a7e6c56e81938 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damir=20Jeli=C4=87?= Date: Tue, 20 Jul 2021 16:41:01 +0200 Subject: [PATCH 11/38] crypto: Don't use the transaction ID of the verification for the request Verification flows have something called a transaction id. This is a client-set custom ID that identifies the flow and is established by the first message that gets sent out. This transaction ID needs to be kept the same and be part of all events that are sent during the verification flow. To-device requests have something called a transaction id. This is a client-set custom ID that identifies a given request. It is used to ensure idempotency of requests, i.e. retrying to send a request won't result in two events being sent as long as the transaction id is kept the same. This patch removes usage of the first type of transaction ID for the second use-case. This closes: #3589. --- changelog.d/3589.bugfix | 1 + .../crypto/verification/VerificationTransportToDevice.kt | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) create mode 100644 changelog.d/3589.bugfix diff --git a/changelog.d/3589.bugfix b/changelog.d/3589.bugfix new file mode 100644 index 0000000000..2b9a04f6a2 --- /dev/null +++ b/changelog.d/3589.bugfix @@ -0,0 +1 @@ +Don't use the transaction ID of the verification for the request diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationTransportToDevice.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationTransportToDevice.kt index 0dbbe656c7..45f8143937 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationTransportToDevice.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/verification/VerificationTransportToDevice.kt @@ -68,7 +68,7 @@ internal class VerificationTransportToDevice( contentMap.setObject(otherUserId, it, keyReq) } sendToDeviceTask - .configureWith(SendToDeviceTask.Params(MessageType.MSGTYPE_VERIFICATION_REQUEST, contentMap, localId)) { + .configureWith(SendToDeviceTask.Params(MessageType.MSGTYPE_VERIFICATION_REQUEST, contentMap)) { this.callback = object : MatrixCallback { override fun onSuccess(data: Unit) { Timber.v("## verification [$tx.transactionId] send toDevice request success") @@ -124,7 +124,7 @@ internal class VerificationTransportToDevice( contentMap.setObject(tx.otherUserId, tx.otherDeviceId, toSendToDeviceObject) sendToDeviceTask - .configureWith(SendToDeviceTask.Params(type, contentMap, tx.transactionId)) { + .configureWith(SendToDeviceTask.Params(type, contentMap)) { this.callback = object : MatrixCallback { override fun onSuccess(data: Unit) { Timber.v("## SAS verification [$tx.transactionId] toDevice type '$type' success.") @@ -155,7 +155,7 @@ internal class VerificationTransportToDevice( val contentMap = MXUsersDevicesMap() contentMap.setObject(otherUserId, otherUserDeviceId, cancelMessage) sendToDeviceTask - .configureWith(SendToDeviceTask.Params(EventType.KEY_VERIFICATION_DONE, contentMap, transactionId)) { + .configureWith(SendToDeviceTask.Params(EventType.KEY_VERIFICATION_DONE, contentMap)) { this.callback = object : MatrixCallback { override fun onSuccess(data: Unit) { onDone?.invoke() @@ -176,7 +176,7 @@ internal class VerificationTransportToDevice( val contentMap = MXUsersDevicesMap() contentMap.setObject(otherUserId, otherUserDeviceId, cancelMessage) sendToDeviceTask - .configureWith(SendToDeviceTask.Params(EventType.KEY_VERIFICATION_CANCEL, contentMap, transactionId)) { + .configureWith(SendToDeviceTask.Params(EventType.KEY_VERIFICATION_CANCEL, contentMap)) { this.callback = object : MatrixCallback { override fun onSuccess(data: Unit) { Timber.v("## SAS verification [$transactionId] canceled for reason ${code.value}") From 88cc7471a8827fc9b807480ce44f0e0334c81441 Mon Sep 17 00:00:00 2001 From: ganfra Date: Tue, 20 Jul 2021 12:28:07 +0200 Subject: [PATCH 12/38] Call notification: add missed call icons. Also set tint. --- .../vector/app/core/services/CallService.kt | 28 ++++++----- .../notifications/NotificationUtils.kt | 50 ++++++++++++++----- .../res/drawable/ic_missed_video_call.xml | 10 ++++ .../drawable/ic_missed_video_call_small.xml | 4 ++ .../res/drawable/ic_missed_voice_call.xml | 12 +++++ .../drawable/ic_missed_voice_call_small.xml | 5 ++ vector/src/main/res/values/strings.xml | 3 +- 7 files changed, 85 insertions(+), 27 deletions(-) create mode 100644 vector/src/main/res/drawable/ic_missed_video_call.xml create mode 100644 vector/src/main/res/drawable/ic_missed_video_call_small.xml create mode 100644 vector/src/main/res/drawable/ic_missed_voice_call.xml create mode 100644 vector/src/main/res/drawable/ic_missed_voice_call_small.xml diff --git a/vector/src/main/java/im/vector/app/core/services/CallService.kt b/vector/src/main/java/im/vector/app/core/services/CallService.kt index 7434f8a277..b0766d1cdb 100644 --- a/vector/src/main/java/im/vector/app/core/services/CallService.kt +++ b/vector/src/main/java/im/vector/app/core/services/CallService.kt @@ -37,6 +37,7 @@ import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.notifications.NotificationUtils import im.vector.app.features.popup.IncomingCallAlert import im.vector.app.features.popup.PopupAlertManager +import org.matrix.android.sdk.api.session.content.ContentUrlResolver import org.matrix.android.sdk.api.util.MatrixItem import timber.log.Timber @@ -47,7 +48,7 @@ class CallService : VectorService() { private val connections = mutableMapOf() private val knownCalls = mutableSetOf() - private val ongoingCallIds = mutableSetOf() + private val connectedCallIds = mutableSetOf() private lateinit var notificationManager: NotificationManagerCompat private lateinit var notificationUtils: NotificationUtils @@ -204,15 +205,12 @@ class CallService : VectorService() { mediaSession?.isActive = false myStopSelf() } - val wasOngoing = ongoingCallIds.remove(callId) - if (wasOngoing || isRejected) { - val notification = notificationUtils.buildCallEndedNotification() + val wasConnected = connectedCallIds.remove(callId) + if (wasConnected || terminatedCall.isOutgoing || isRejected) { + val notification = notificationUtils.buildCallEndedNotification(terminatedCall.isVideoCall) notificationManager.notify(callId.hashCode(), notification) } else { - val notification = notificationUtils.buildCallMissedNotification( - roomId = terminatedCall.nativeRoomId, - title = terminatedCall.matrixItem?.getBestName() ?: terminatedCall.opponentUserId - ) + val notification = notificationUtils.buildCallMissedNotification(terminatedCall) notificationManager.cancel(callId.hashCode()) notificationManager.notify(MISSED_CALL_TAG, terminatedCall.nativeRoomId.hashCode(), notification) } @@ -252,7 +250,7 @@ class CallService : VectorService() { private fun displayCallInProgressNotification(intent: Intent) { Timber.v("## VOIP displayCallInProgressNotification") val callId = intent.getStringExtra(EXTRA_CALL_ID) ?: "" - ongoingCallIds.add(callId) + connectedCallIds.add(callId) val call = callManager.getCallById(callId) ?: return Unit.also { handleUnexpectedState(callId) } @@ -277,7 +275,7 @@ class CallService : VectorService() { if (callId != null) { notificationManager.cancel(callId.hashCode()) } - val notification = notificationUtils.buildCallEndedNotification() + val notification = notificationUtils.buildCallEndedNotification(false) startForeground(DEFAULT_NOTIFICATION_ID, notification) if (knownCalls.isEmpty()) { mediaSession?.isActive = false @@ -296,15 +294,19 @@ class CallService : VectorService() { opponentUserId = this.mxCall.opponentUserId, matrixItem = vectorComponent().activeSessionHolder().getSafeActiveSession()?.let { this.getOpponentAsMatrixItem(it) - } + }, + isVideoCall = this.mxCall.isVideoCall, + isOutgoing = this.mxCall.isOutgoing ) } - private data class CallInformation( + data class CallInformation( val callId: String, val nativeRoomId: String, val opponentUserId: String, - val matrixItem: MatrixItem? + val matrixItem: MatrixItem?, + val isVideoCall: Boolean, + val isOutgoing: Boolean, ) companion object { diff --git a/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt b/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt index 27771ddb2b..3c4af56b37 100755 --- a/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt +++ b/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt @@ -48,6 +48,7 @@ import androidx.fragment.app.Fragment import im.vector.app.BuildConfig import im.vector.app.R import im.vector.app.core.resources.StringProvider +import im.vector.app.core.services.CallService import im.vector.app.core.utils.startNotificationChannelSettingsIntent import im.vector.app.features.call.VectorCallActivity import im.vector.app.features.call.service.CallHeadsUpActionReceiver @@ -298,12 +299,14 @@ class NotificationUtils @Inject constructor(private val context: Context, .apply { if (call.mxCall.isVideoCall) { setContentText(stringProvider.getString(R.string.incoming_video_call)) + setSmallIcon(R.drawable.ic_call_answer_video) } else { setContentText(stringProvider.getString(R.string.incoming_voice_call)) + setSmallIcon(R.drawable.ic_call_answer) } } - .setSmallIcon(R.drawable.incoming_call_notification_transparent) .setCategory(NotificationCompat.CATEGORY_CALL) + .setColor(ThemeUtils.getColor(context, android.R.attr.colorPrimary)) .setLights(accentColor, 500, 500) .setOngoing(true) @@ -339,8 +342,6 @@ class NotificationUtils @Inject constructor(private val context: Context, builder.addAction( NotificationCompat.Action( R.drawable.ic_call_answer, - // IconCompat.createWithResource(applicationContext, R.drawable.ic_call) - // .setTint(ContextCompat.getColor(applicationContext, R.color.vctr_positive_accent)), getActionText(R.string.call_notification_answer, R.attr.colorPrimary), answerCallPendingIntent ) @@ -360,10 +361,15 @@ class NotificationUtils @Inject constructor(private val context: Context, .setContentTitle(ensureTitleNotEmpty(title)) .apply { setContentText(stringProvider.getString(R.string.call_ring)) + if (call.mxCall.isVideoCall) { + setSmallIcon(R.drawable.ic_call_answer_video) + } else { + setSmallIcon(R.drawable.ic_call_answer) + } } - .setSmallIcon(R.drawable.incoming_call_notification_transparent) .setCategory(NotificationCompat.CATEGORY_CALL) .setLights(accentColor, 500, 500) + .setColor(ThemeUtils.getColor(context, android.R.attr.colorPrimary)) .setOngoing(true) val contentIntent = VectorCallActivity.newIntent( @@ -407,11 +413,13 @@ class NotificationUtils @Inject constructor(private val context: Context, .apply { if (call.mxCall.isVideoCall) { setContentText(stringProvider.getString(R.string.video_call_in_progress)) + setSmallIcon(R.drawable.ic_call_answer_video) } else { setContentText(stringProvider.getString(R.string.call_in_progress)) + setSmallIcon(R.drawable.ic_call_answer) } } - .setSmallIcon(R.drawable.incoming_call_notification_transparent) + .setColor(ThemeUtils.getColor(context, android.R.attr.colorPrimary)) .setCategory(NotificationCompat.CATEGORY_CALL) val rejectCallPendingIntent = buildRejectCallPendingIntent(call.callId) @@ -450,11 +458,18 @@ class NotificationUtils @Inject constructor(private val context: Context, /** * Build a temporary (because service will be stopped just after) notification for the CallService, when a call is ended */ - fun buildCallEndedNotification(): Notification { + fun buildCallEndedNotification(isVideoCall: Boolean): Notification { return NotificationCompat.Builder(context, SILENT_NOTIFICATION_CHANNEL_ID) .setContentTitle(stringProvider.getString(R.string.call_ended)) + .apply { + if (isVideoCall) { + setSmallIcon(R.drawable.ic_call_answer_video) + } else { + setSmallIcon(R.drawable.ic_call_answer) + } + } .setTimeoutAfter(2000) - .setSmallIcon(R.drawable.ic_material_call_end_grey) + .setColor(ThemeUtils.getColor(context, android.R.attr.colorPrimary)) .setCategory(NotificationCompat.CATEGORY_CALL) .build() } @@ -462,17 +477,26 @@ class NotificationUtils @Inject constructor(private val context: Context, /** * Build notification for the CallService, when a call is missed */ - fun buildCallMissedNotification(roomId: String, title: String): Notification { - val builder = NotificationCompat.Builder(context, NOISY_NOTIFICATION_CHANNEL_ID) - .setContentTitle(title) - .setContentText(stringProvider.getString(R.string.call_missed)) - .setSmallIcon(R.drawable.ic_material_call_end_grey) + fun buildCallMissedNotification(callInformation: CallService.CallInformation): Notification { + val builder = NotificationCompat.Builder(context, SILENT_NOTIFICATION_CHANNEL_ID) + .setContentTitle(callInformation.matrixItem?.getBestName() ?: callInformation.opponentUserId) + .apply { + if (callInformation.isVideoCall) { + setContentText(stringProvider.getString(R.string.missed_video_call)) + setSmallIcon(R.drawable.ic_missed_video_call) + } else { + setContentText(stringProvider.getString(R.string.missed_audio_call)) + setSmallIcon(R.drawable.ic_missed_voice_call) + } + } + .setShowWhen(true) + .setColor(ThemeUtils.getColor(context, android.R.attr.colorPrimary)) .setAutoCancel(true) .setCategory(NotificationCompat.CATEGORY_CALL) val contentPendingIntent = TaskStackBuilder.create(context) .addNextIntentWithParentStack(HomeActivity.newIntent(context)) - .addNextIntent(RoomDetailActivity.newIntent(context, RoomDetailArgs(roomId))) + .addNextIntent(RoomDetailActivity.newIntent(context, RoomDetailArgs(callInformation.nativeRoomId))) .getPendingIntent(System.currentTimeMillis().toInt(), PendingIntent.FLAG_UPDATE_CURRENT) builder.setContentIntent(contentPendingIntent) diff --git a/vector/src/main/res/drawable/ic_missed_video_call.xml b/vector/src/main/res/drawable/ic_missed_video_call.xml new file mode 100644 index 0000000000..555e15a371 --- /dev/null +++ b/vector/src/main/res/drawable/ic_missed_video_call.xml @@ -0,0 +1,10 @@ + + + diff --git a/vector/src/main/res/drawable/ic_missed_video_call_small.xml b/vector/src/main/res/drawable/ic_missed_video_call_small.xml new file mode 100644 index 0000000000..c703f0cfca --- /dev/null +++ b/vector/src/main/res/drawable/ic_missed_video_call_small.xml @@ -0,0 +1,4 @@ + + + diff --git a/vector/src/main/res/drawable/ic_missed_voice_call.xml b/vector/src/main/res/drawable/ic_missed_voice_call.xml new file mode 100644 index 0000000000..dc869fa8bc --- /dev/null +++ b/vector/src/main/res/drawable/ic_missed_voice_call.xml @@ -0,0 +1,12 @@ + + + + diff --git a/vector/src/main/res/drawable/ic_missed_voice_call_small.xml b/vector/src/main/res/drawable/ic_missed_voice_call_small.xml new file mode 100644 index 0000000000..21d8b309c6 --- /dev/null +++ b/vector/src/main/res/drawable/ic_missed_voice_call_small.xml @@ -0,0 +1,5 @@ + + + + diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index e9c8e5b43e..f77c940cf9 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -727,7 +727,8 @@ Call connected Call connecting… Call ended - Missed call + Missed audio call + Missed video call Calling… Incoming Call Incoming Video Call From b809d4acf4b57534d9bea758145ff56c45618909 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 20 Jul 2021 23:06:30 +0000 Subject: [PATCH 13/38] Bump libphonenumber from 8.12.27 to 8.12.28 Bumps [libphonenumber](https://github.com/google/libphonenumber) from 8.12.27 to 8.12.28. - [Release notes](https://github.com/google/libphonenumber/releases) - [Changelog](https://github.com/google/libphonenumber/blob/master/making-metadata-changes.md) - [Commits](https://github.com/google/libphonenumber/compare/v8.12.27...v8.12.28) --- updated-dependencies: - dependency-name: com.googlecode.libphonenumber:libphonenumber dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- matrix-sdk-android/build.gradle | 2 +- vector/build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/matrix-sdk-android/build.gradle b/matrix-sdk-android/build.gradle index 484a2ddfe6..a9a2797da6 100644 --- a/matrix-sdk-android/build.gradle +++ b/matrix-sdk-android/build.gradle @@ -169,7 +169,7 @@ dependencies { implementation 'com.otaliastudios:transcoder:0.10.3' // Phone number https://github.com/google/libphonenumber - implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.27' + implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.28' testImplementation 'junit:junit:4.13.2' testImplementation 'org.robolectric:robolectric:4.5.1' diff --git a/vector/build.gradle b/vector/build.gradle index 29f517a7e0..a025e85151 100644 --- a/vector/build.gradle +++ b/vector/build.gradle @@ -360,7 +360,7 @@ dependencies { implementation 'com.facebook.stetho:stetho:1.6.0' // Phone number https://github.com/google/libphonenumber - implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.27' + implementation 'com.googlecode.libphonenumber:libphonenumber:8.12.28' // rx implementation 'io.reactivex.rxjava2:rxkotlin:2.4.0' From 89dc4bb13eed4449d6b19ffbd8f09c1ceeceaa70 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 20 Jul 2021 23:06:50 +0000 Subject: [PATCH 14/38] Bump daggerVersion from 2.37 to 2.38 Bumps `daggerVersion` from 2.37 to 2.38. Updates `dagger` from 2.37 to 2.38 - [Release notes](https://github.com/google/dagger/releases) - [Changelog](https://github.com/google/dagger/blob/master/CHANGELOG.md) - [Commits](https://github.com/google/dagger/compare/dagger-2.37...dagger-2.38) Updates `dagger-compiler` from 2.37 to 2.38 - [Release notes](https://github.com/google/dagger/releases) - [Changelog](https://github.com/google/dagger/blob/master/CHANGELOG.md) - [Commits](https://github.com/google/dagger/compare/dagger-2.37...dagger-2.38) --- updated-dependencies: - dependency-name: com.google.dagger:dagger dependency-type: direct:production update-type: version-update:semver-minor - dependency-name: com.google.dagger:dagger-compiler dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- matrix-sdk-android/build.gradle | 2 +- vector/build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/matrix-sdk-android/build.gradle b/matrix-sdk-android/build.gradle index 484a2ddfe6..68e120cdcc 100644 --- a/matrix-sdk-android/build.gradle +++ b/matrix-sdk-android/build.gradle @@ -112,7 +112,7 @@ dependencies { def lifecycle_version = '2.2.0' def arch_version = '2.1.0' def markwon_version = '3.1.0' - def daggerVersion = '2.37' + def daggerVersion = '2.38' def work_version = '2.5.0' def retrofit_version = '2.9.0' diff --git a/vector/build.gradle b/vector/build.gradle index 29f517a7e0..665ed27617 100644 --- a/vector/build.gradle +++ b/vector/build.gradle @@ -311,7 +311,7 @@ dependencies { def big_image_viewer_version = '1.8.0' def glide_version = '4.12.0' def moshi_version = '1.12.0' - def daggerVersion = '2.37' + def daggerVersion = '2.38' def autofill_version = "1.1.0" def work_version = '2.5.0' def arch_version = '2.1.0' From 5dda5a107a58c9494a459514cc40f408f3e42595 Mon Sep 17 00:00:00 2001 From: ganfra Date: Wed, 21 Jul 2021 12:28:14 +0200 Subject: [PATCH 15/38] Missed call notif: make some cleanup and minor changes --- changelog.d/3710.feature | 1 + .../android/sdk/api/session/call/CallState.kt | 6 +- .../android/sdk/api/session/call/MxCall.kt | 4 +- .../room/model/call/CallHangupContent.kt | 28 +------ .../room/model/call/CallRejectContent.kt | 7 +- .../session/room/model/call/EndCallReason.kt | 50 +++++++++++ .../session/call/CallSignalingHandler.kt | 2 +- .../internal/session/call/model/MxCallImpl.kt | 9 +- .../vector/app/core/services/CallService.kt | 25 +++--- .../app/features/call/CallControlsView.kt | 2 +- .../app/features/call/VectorCallActivity.kt | 6 +- .../call/transfer/CallTransferViewModel.kt | 2 +- .../app/features/call/webrtc/WebRtcCall.kt | 83 ++++++++++++------- .../features/call/webrtc/WebRtcCallManager.kt | 27 +++--- 14 files changed, 159 insertions(+), 93 deletions(-) create mode 100644 changelog.d/3710.feature create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/EndCallReason.kt diff --git a/changelog.d/3710.feature b/changelog.d/3710.feature new file mode 100644 index 0000000000..74134d7ee5 --- /dev/null +++ b/changelog.d/3710.feature @@ -0,0 +1 @@ +Show missed call notification. \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/CallState.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/CallState.kt index 2dbd1c9b01..47a63b4a25 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/CallState.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/CallState.kt @@ -16,6 +16,8 @@ package org.matrix.android.sdk.api.session.call +import org.matrix.android.sdk.api.session.room.model.call.EndCallReason + sealed class CallState { /** Idle, setting up objects */ @@ -42,6 +44,6 @@ sealed class CallState { * */ data class Connected(val iceConnectionState: MxPeerConnectionState) : CallState() - /** Terminated. Incoming/Outgoing call, the call is terminated */ - object Terminated : CallState() + /** Ended. Incoming/Outgoing call, the call is terminated */ + data class Ended(val reason: EndCallReason? = null) : CallState() } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/MxCall.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/MxCall.kt index fcc9f7072d..dd23e81cc6 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/MxCall.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/call/MxCall.kt @@ -18,7 +18,7 @@ package org.matrix.android.sdk.api.session.call import org.matrix.android.sdk.api.session.room.model.call.CallCandidate import org.matrix.android.sdk.api.session.room.model.call.CallCapabilities -import org.matrix.android.sdk.api.session.room.model.call.CallHangupContent +import org.matrix.android.sdk.api.session.room.model.call.EndCallReason import org.matrix.android.sdk.api.session.room.model.call.SdpType import org.matrix.android.sdk.api.util.Optional @@ -69,7 +69,7 @@ interface MxCall : MxCallDetail { /** * End the call */ - fun hangUp(reason: CallHangupContent.Reason? = null) + fun hangUp(reason: EndCallReason? = null) /** * Start a call diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallHangupContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallHangupContent.kt index 9d6e1a7eae..31f801dd6f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallHangupContent.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallHangupContent.kt @@ -43,29 +43,5 @@ data class CallHangupContent( * or `invite_timeout` for when the other party did not answer in time. * One of: ["ice_failed", "invite_timeout"] */ - @Json(name = "reason") val reason: Reason? = null -) : CallSignalingContent { - @JsonClass(generateAdapter = false) - enum class Reason { - @Json(name = "ice_failed") - ICE_FAILED, - - @Json(name = "ice_timeout") - ICE_TIMEOUT, - - @Json(name = "user_hangup") - USER_HANGUP, - - @Json(name = "replaced") - REPLACED, - - @Json(name = "user_media_failed") - USER_MEDIA_FAILED, - - @Json(name = "invite_timeout") - INVITE_TIMEOUT, - - @Json(name = "unknown_error") - UNKWOWN_ERROR - } -} + @Json(name = "reason") val reason: EndCallReason? = null +) : CallSignalingContent diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallRejectContent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallRejectContent.kt index ea412fbe3e..1b9a7186e2 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallRejectContent.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/CallRejectContent.kt @@ -36,5 +36,10 @@ data class CallRejectContent( /** * Required. The version of the VoIP specification this message adheres to. */ - @Json(name = "version") override val version: String? + @Json(name = "version") override val version: String?, + + /** + * Optional error reason for the reject. + */ + @Json(name = "reason") val reason: EndCallReason? = null ) : CallSignalingContent diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/EndCallReason.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/EndCallReason.kt new file mode 100644 index 0000000000..60e038b2f9 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/call/EndCallReason.kt @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2021 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.session.room.model.call + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +@JsonClass(generateAdapter = false) +enum class EndCallReason { + @Json(name = "ice_failed") + ICE_FAILED, + + @Json(name = "ice_timeout") + ICE_TIMEOUT, + + @Json(name = "user_hangup") + USER_HANGUP, + + @Json(name = "replaced") + REPLACED, + + @Json(name = "user_media_failed") + USER_MEDIA_FAILED, + + @Json(name = "invite_timeout") + INVITE_TIMEOUT, + + @Json(name = "unknown_error") + UNKWOWN_ERROR, + + @Json(name = "user_busy") + USER_BUSY, + + @Json(name = "answered_elsewhere") + ANSWERED_ELSEWHERE +} diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallSignalingHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallSignalingHandler.kt index b0901af719..6863f52435 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallSignalingHandler.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallSignalingHandler.kt @@ -166,7 +166,7 @@ internal class CallSignalingHandler @Inject constructor(private val activeCallHa Timber.v("Ignoring hangup from party ID ${content.partyId} we have chosen party ID ${call.opponentPartyId}") return } - if (call.state != CallState.Terminated) { + if (call.state !is CallState.Ended) { activeCallHandler.removeCall(content.callId) callListenersDispatcher.onCallHangupReceived(content) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/model/MxCallImpl.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/model/MxCallImpl.kt index f101685a4b..31f3e114e5 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/model/MxCallImpl.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/model/MxCallImpl.kt @@ -38,6 +38,7 @@ import org.matrix.android.sdk.api.session.room.model.call.CallRejectContent import org.matrix.android.sdk.api.session.room.model.call.CallReplacesContent import org.matrix.android.sdk.api.session.room.model.call.CallSelectAnswerContent import org.matrix.android.sdk.api.session.room.model.call.CallSignalingContent +import org.matrix.android.sdk.api.session.room.model.call.EndCallReason import org.matrix.android.sdk.api.session.room.model.call.SdpType import org.matrix.android.sdk.api.util.Optional import org.matrix.android.sdk.internal.session.call.DefaultCallSignalingService @@ -153,20 +154,20 @@ internal class MxCallImpl( ) .let { createEventAndLocalEcho(type = EventType.CALL_REJECT, roomId = roomId, content = it.toContent()) } .also { eventSenderProcessor.postEvent(it) } - state = CallState.Terminated + state = CallState.Ended(reason = EndCallReason.USER_HANGUP) } - override fun hangUp(reason: CallHangupContent.Reason?) { + override fun hangUp(reason: EndCallReason?) { Timber.v("## VOIP hangup $callId") CallHangupContent( callId = callId, partyId = ourPartyId, - reason = reason ?: CallHangupContent.Reason.USER_HANGUP, + reason = reason ?: EndCallReason.USER_HANGUP, version = MxCall.VOIP_PROTO_VERSION.toString() ) .let { createEventAndLocalEcho(type = EventType.CALL_HANGUP, roomId = roomId, content = it.toContent()) } .also { eventSenderProcessor.postEvent(it) } - state = CallState.Terminated + state = CallState.Ended(reason) } override fun accept(sdpString: String) { diff --git a/vector/src/main/java/im/vector/app/core/services/CallService.kt b/vector/src/main/java/im/vector/app/core/services/CallService.kt index b0766d1cdb..e5ba2ea10c 100644 --- a/vector/src/main/java/im/vector/app/core/services/CallService.kt +++ b/vector/src/main/java/im/vector/app/core/services/CallService.kt @@ -37,7 +37,7 @@ import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.notifications.NotificationUtils import im.vector.app.features.popup.IncomingCallAlert import im.vector.app.features.popup.PopupAlertManager -import org.matrix.android.sdk.api.session.content.ContentUrlResolver +import org.matrix.android.sdk.api.session.room.model.call.EndCallReason import org.matrix.android.sdk.api.util.MatrixItem import timber.log.Timber @@ -192,7 +192,8 @@ class CallService : VectorService() { private fun handleCallTerminated(intent: Intent) { val callId = intent.getStringExtra(EXTRA_CALL_ID) ?: "" - val isRejected = intent.getBooleanExtra(EXTRA_IS_REJECTED, false) + val endCallReason = intent.getSerializableExtra(EXTRA_END_CALL_REASON) as EndCallReason + val rejected = intent.getBooleanExtra(EXTRA_END_CALL_REJECTED, false) alertManager.cancelAlert(callId) val terminatedCall = knownCalls.firstOrNull { it.callId == callId } if (terminatedCall == null) { @@ -206,13 +207,13 @@ class CallService : VectorService() { myStopSelf() } val wasConnected = connectedCallIds.remove(callId) - if (wasConnected || terminatedCall.isOutgoing || isRejected) { - val notification = notificationUtils.buildCallEndedNotification(terminatedCall.isVideoCall) - notificationManager.notify(callId.hashCode(), notification) - } else { + if (!wasConnected && !terminatedCall.isOutgoing && !rejected && endCallReason != EndCallReason.ANSWERED_ELSEWHERE) { val notification = notificationUtils.buildCallMissedNotification(terminatedCall) notificationManager.cancel(callId.hashCode()) notificationManager.notify(MISSED_CALL_TAG, terminatedCall.nativeRoomId.hashCode(), notification) + } else { + val notification = notificationUtils.buildCallEndedNotification(terminatedCall.isVideoCall) + notificationManager.notify(callId.hashCode(), notification) } } @@ -287,7 +288,7 @@ class CallService : VectorService() { connections[callConnection.callId] = callConnection } - private fun WebRtcCall.toCallInformation(): CallInformation{ + private fun WebRtcCall.toCallInformation(): CallInformation { return CallInformation( callId = this.callId, nativeRoomId = this.nativeRoomId, @@ -306,7 +307,7 @@ class CallService : VectorService() { val opponentUserId: String, val matrixItem: MatrixItem?, val isVideoCall: Boolean, - val isOutgoing: Boolean, + val isOutgoing: Boolean ) companion object { @@ -324,7 +325,8 @@ class CallService : VectorService() { private const val EXTRA_CALL_ID = "EXTRA_CALL_ID" private const val EXTRA_IS_IN_BG = "EXTRA_IS_IN_BG" - private const val EXTRA_IS_REJECTED = "EXTRA_IS_REJECTED" + private const val EXTRA_END_CALL_REJECTED = "EXTRA_END_CALL_REJECTED" + private const val EXTRA_END_CALL_REASON = "EXTRA_END_CALL_REASON" fun onIncomingCallRinging(context: Context, callId: String, @@ -360,12 +362,13 @@ class CallService : VectorService() { ContextCompat.startForegroundService(context, intent) } - fun onCallTerminated(context: Context, callId: String, isRejected: Boolean) { + fun onCallTerminated(context: Context, callId: String, endCallReason: EndCallReason, rejected: Boolean) { val intent = Intent(context, CallService::class.java) .apply { action = ACTION_CALL_TERMINATED putExtra(EXTRA_CALL_ID, callId) - putExtra(EXTRA_IS_REJECTED, isRejected) + putExtra(EXTRA_END_CALL_REASON, endCallReason) + putExtra(EXTRA_END_CALL_REJECTED, rejected) } ContextCompat.startForegroundService(context, intent) } diff --git a/vector/src/main/java/im/vector/app/features/call/CallControlsView.kt b/vector/src/main/java/im/vector/app/features/call/CallControlsView.kt index 1a54551072..3742de6271 100644 --- a/vector/src/main/java/im/vector/app/features/call/CallControlsView.kt +++ b/vector/src/main/java/im/vector/app/features/call/CallControlsView.kt @@ -118,7 +118,7 @@ class CallControlsView @JvmOverloads constructor( views.connectedControls.isVisible = false } } - is CallState.Terminated, + is CallState.Ended, null -> { views.ringingControls.isVisible = false views.connectedControls.isVisible = false diff --git a/vector/src/main/java/im/vector/app/features/call/VectorCallActivity.kt b/vector/src/main/java/im/vector/app/features/call/VectorCallActivity.kt index 7e84811102..702f50af57 100644 --- a/vector/src/main/java/im/vector/app/features/call/VectorCallActivity.kt +++ b/vector/src/main/java/im/vector/app/features/call/VectorCallActivity.kt @@ -196,7 +196,7 @@ class VectorCallActivity : VectorBaseActivity(), CallContro views.callConnectingProgress.isVisible = true configureCallInfo(state) } - is CallState.Connected -> { + is CallState.Connected -> { if (callState.iceConnectionState == MxPeerConnectionState.CONNECTED) { if (state.isLocalOnHold || state.isRemoteOnHold) { views.smallIsHeldIcon.isVisible = true @@ -246,10 +246,10 @@ class VectorCallActivity : VectorBaseActivity(), CallContro views.callConnectingProgress.isVisible = true } } - is CallState.Terminated -> { + is CallState.Ended -> { finish() } - null -> { + null -> { } } } diff --git a/vector/src/main/java/im/vector/app/features/call/transfer/CallTransferViewModel.kt b/vector/src/main/java/im/vector/app/features/call/transfer/CallTransferViewModel.kt index 0f37ccaa29..0217551260 100644 --- a/vector/src/main/java/im/vector/app/features/call/transfer/CallTransferViewModel.kt +++ b/vector/src/main/java/im/vector/app/features/call/transfer/CallTransferViewModel.kt @@ -57,7 +57,7 @@ class CallTransferViewModel @AssistedInject constructor(@Assisted initialState: private val call = callManager.getCallById(initialState.callId) private val callListener = object : WebRtcCall.Listener { override fun onStateUpdate(call: MxCall) { - if (call.state == CallState.Terminated) { + if (call.state is CallState.Ended) { _viewEvents.post(CallTransferViewEvents.Dismiss) } } diff --git a/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCall.kt b/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCall.kt index 086a3be9d3..7ec6715b42 100644 --- a/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCall.kt +++ b/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCall.kt @@ -57,6 +57,9 @@ import org.matrix.android.sdk.api.session.room.model.call.CallCandidatesContent import org.matrix.android.sdk.api.session.room.model.call.CallHangupContent import org.matrix.android.sdk.api.session.room.model.call.CallInviteContent import org.matrix.android.sdk.api.session.room.model.call.CallNegotiateContent +import org.matrix.android.sdk.api.session.room.model.call.CallRejectContent +import org.matrix.android.sdk.api.session.room.model.call.CallSelectAnswerContent +import org.matrix.android.sdk.api.session.room.model.call.EndCallReason import org.matrix.android.sdk.api.session.room.model.call.SdpType import org.threeten.bp.Duration import org.webrtc.AudioSource @@ -99,7 +102,7 @@ class WebRtcCall( private val sessionProvider: Provider, private val peerConnectionFactoryProvider: Provider, private val onCallBecomeActive: (WebRtcCall) -> Unit, - private val onCallEnded: (String, Boolean) -> Unit + private val onCallEnded: (String, EndCallReason, Boolean) -> Unit ) : MxCall.StateListener { interface Listener : MxCall.StateListener { @@ -227,7 +230,7 @@ class WebRtcCall( // Allow a short time for initial candidates to be gathered delay(200) } - if (mxCall.state == CallState.Terminated) { + if (mxCall.state is CallState.Ended) { return@launch } if (mxCall.state == CallState.CreateOffer) { @@ -285,7 +288,7 @@ class WebRtcCall( createCallId = CallIdGenerator.generate(), awaitCallId = null ) - endCall(sendEndSignaling = false) + terminate(EndCallReason.REPLACED) } } @@ -307,8 +310,8 @@ class WebRtcCall( createCallId = newCallId, awaitCallId = null ) - endCall(sendEndSignaling = false) - transferTargetCall.endCall(sendEndSignaling = false) + terminate(EndCallReason.REPLACED) + transferTargetCall.terminate(EndCallReason.REPLACED) } } @@ -461,7 +464,7 @@ class WebRtcCall( peerConnection?.awaitSetRemoteDescription(offerSdp) } catch (failure: Throwable) { Timber.v("Failure putting remote description") - endCall(true, CallHangupContent.Reason.UNKWOWN_ERROR) + endCall(reason = EndCallReason.UNKWOWN_ERROR) return@withContext } // 2) Access camera + microphone, create local stream @@ -767,7 +770,7 @@ class WebRtcCall( if (stream.audioTracks.size > 1 || stream.videoTracks.size > 1) { Timber.e("## VOIP StreamObserver weird looking stream: $stream") // TODO maybe do something more?? - endCall(true) + endCall(EndCallReason.UNKWOWN_ERROR) return@launch } if (stream.audioTracks.size == 1) { @@ -795,33 +798,34 @@ class WebRtcCall( } } - fun endCall(sendEndSignaling: Boolean = true, reason: CallHangupContent.Reason? = null) { + fun endCall(reason: EndCallReason? = null) { sessionScope?.launch(dispatcher) { - if (mxCall.state == CallState.Terminated) { + if (mxCall.state is CallState.Ended) { return@launch } - // Close tracks ASAP - localVideoTrack?.setEnabled(false) - localVideoTrack?.setEnabled(false) - cameraAvailabilityCallback?.let { cameraAvailabilityCallback -> - val cameraManager = context.getSystemService()!! - cameraManager.unregisterAvailabilityCallback(cameraAvailabilityCallback) - } - val wasRinging = mxCall.state is CallState.LocalRinging - mxCall.state = CallState.Terminated - release() - val isRejected = wasRinging && sendEndSignaling - onCallEnded(callId, isRejected) - if (sendEndSignaling) { - if (wasRinging) { - mxCall.reject() - } else { - mxCall.hangUp(reason) - } + val reject = mxCall.state is CallState.LocalRinging + terminate(EndCallReason.USER_HANGUP, reject) + if (reject) { + mxCall.reject() + } else { + mxCall.hangUp(reason) } } } + private suspend fun terminate(reason: EndCallReason? = null, rejected: Boolean = false) = withContext(dispatcher) { + // Close tracks ASAP + localVideoTrack?.setEnabled(false) + localVideoTrack?.setEnabled(false) + cameraAvailabilityCallback?.let { cameraAvailabilityCallback -> + val cameraManager = context.getSystemService()!! + cameraManager.unregisterAvailabilityCallback(cameraAvailabilityCallback) + } + mxCall.state = CallState.Ended(reason ?: EndCallReason.USER_HANGUP) + release() + onCallEnded(callId, reason ?: EndCallReason.USER_HANGUP, rejected) + } + // Call listener fun onCallIceCandidateReceived(iceCandidatesContent: CallCandidatesContent) { @@ -844,7 +848,7 @@ class WebRtcCall( try { peerConnection?.awaitSetRemoteDescription(sdp) } catch (failure: Throwable) { - endCall(true, CallHangupContent.Reason.UNKWOWN_ERROR) + endCall(EndCallReason.UNKWOWN_ERROR) return@launch } if (mxCall.opponentPartyId?.hasValue().orFalse()) { @@ -905,6 +909,29 @@ class WebRtcCall( } } + fun onCallHangupReceived(callHangupContent: CallHangupContent) { + sessionScope?.launch(dispatcher) { + terminate(callHangupContent.reason) + } + } + + fun onCallRejectReceived(callRejectContent: CallRejectContent) { + sessionScope?.launch(dispatcher) { + terminate(callRejectContent.reason, true) + } + } + + fun onCallSelectedAnswerReceived(callSelectAnswerContent: CallSelectAnswerContent) { + sessionScope?.launch(dispatcher) { + val selectedPartyId = callSelectAnswerContent.selectedPartyId + if (selectedPartyId != mxCall.ourPartyId) { + Timber.i("Got select_answer for party ID $selectedPartyId: we are party ID ${mxCall.ourPartyId}.") + // The other party has picked somebody else's answer + terminate() + } + } + } + fun onCallAssertedIdentityReceived(callAssertedIdentityContent: CallAssertedIdentityContent) { sessionScope?.launch(dispatcher) { val session = sessionProvider.get() ?: return@launch diff --git a/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCallManager.kt b/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCallManager.kt index d7628cef90..24400afb42 100644 --- a/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCallManager.kt +++ b/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCallManager.kt @@ -29,7 +29,9 @@ import im.vector.app.features.call.lookup.CallProtocolsChecker import im.vector.app.features.call.lookup.CallUserMapper import im.vector.app.features.call.utils.EglUtils import im.vector.app.features.call.vectorCallService +import im.vector.app.features.session.coroutineScope import im.vector.app.push.fcm.FcmHelper +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.asCoroutineDispatcher import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.extensions.tryOrNull @@ -45,6 +47,7 @@ import org.matrix.android.sdk.api.session.room.model.call.CallInviteContent import org.matrix.android.sdk.api.session.room.model.call.CallNegotiateContent import org.matrix.android.sdk.api.session.room.model.call.CallRejectContent import org.matrix.android.sdk.api.session.room.model.call.CallSelectAnswerContent +import org.matrix.android.sdk.api.session.room.model.call.EndCallReason import org.webrtc.DefaultVideoDecoderFactory import org.webrtc.DefaultVideoEncoderFactory import org.webrtc.PeerConnectionFactory @@ -75,6 +78,9 @@ class WebRtcCallManager @Inject constructor( private val callUserMapper: CallUserMapper? get() = currentSession?.vectorCallService?.userMapper + private val sessionScope: CoroutineScope? + get() = currentSession?.coroutineScope + interface CurrentCallListener { fun onCurrentCallChange(call: WebRtcCall?) {} fun onAudioDevicesChange() {} @@ -232,12 +238,12 @@ class WebRtcCallManager @Inject constructor( this.currentCall.setAndNotify(call) } - private fun onCallEnded(callId: String, isRejected: Boolean) { + private fun onCallEnded(callId: String, endCallReason: EndCallReason, rejected: Boolean) { Timber.v("## VOIP WebRtcPeerConnectionManager onCall ended: $callId") val webRtcCall = callsByCallId.remove(callId) ?: return Unit.also { Timber.v("On call ended for unknown call $callId") } - CallService.onCallTerminated(context, callId, isRejected) + CallService.onCallTerminated(context, callId, endCallReason, rejected) callsByRoomId[webRtcCall.signalingRoomId]?.remove(webRtcCall) callsByRoomId[webRtcCall.nativeRoomId]?.remove(webRtcCall) transferees.remove(callId) @@ -329,8 +335,8 @@ class WebRtcCallManager @Inject constructor( return webRtcCall } - fun endCallForRoom(roomId: String, originatedByMe: Boolean = true) { - callsByRoomId[roomId]?.firstOrNull()?.endCall(originatedByMe) + fun endCallForRoom(roomId: String) { + callsByRoomId[roomId]?.firstOrNull()?.endCall() } override fun onCallInviteReceived(mxCall: MxCall, callInviteContent: CallInviteContent) { @@ -386,7 +392,7 @@ class WebRtcCallManager @Inject constructor( ?: return Unit.also { Timber.w("onCallHangupReceived for non active call? ${callHangupContent.callId}") } - call.endCall(false) + call.onCallHangupReceived(callHangupContent) } override fun onCallRejectReceived(callRejectContent: CallRejectContent) { @@ -394,7 +400,7 @@ class WebRtcCallManager @Inject constructor( ?: return Unit.also { Timber.w("onCallRejectReceived for non active call? ${callRejectContent.callId}") } - call.endCall(false) + call.onCallRejectReceived(callRejectContent) } override fun onCallSelectAnswerReceived(callSelectAnswerContent: CallSelectAnswerContent) { @@ -402,12 +408,7 @@ class WebRtcCallManager @Inject constructor( ?: return Unit.also { Timber.w("onCallSelectAnswerReceived for non active call? ${callSelectAnswerContent.callId}") } - val selectedPartyId = callSelectAnswerContent.selectedPartyId - if (selectedPartyId != call.mxCall.ourPartyId) { - Timber.i("Got select_answer for party ID $selectedPartyId: we are party ID ${call.mxCall.ourPartyId}.") - // The other party has picked somebody else's answer - call.endCall(false) - } + call.onCallSelectedAnswerReceived(callSelectAnswerContent) } override fun onCallNegotiateReceived(callNegotiateContent: CallNegotiateContent) { @@ -420,7 +421,7 @@ class WebRtcCallManager @Inject constructor( override fun onCallManagedByOtherSession(callId: String) { Timber.v("## VOIP onCallManagedByOtherSession: $callId") - onCallEnded(callId, false) + onCallEnded(callId, EndCallReason.ANSWERED_ELSEWHERE, false) } override fun onCallAssertedIdentityReceived(callAssertedIdentityContent: CallAssertedIdentityContent) { From 8955049110d5df2e3c8f51e9e2c5dc715d4a091c Mon Sep 17 00:00:00 2001 From: ganfra Date: Wed, 21 Jul 2021 17:35:08 +0200 Subject: [PATCH 16/38] Minor changes after benoits review --- .../sdk/internal/session/call/model/MxCallImpl.kt | 4 ++-- .../java/im/vector/app/core/services/CallService.kt | 12 ++++++------ .../im/vector/app/features/call/webrtc/WebRtcCall.kt | 2 +- .../vector/app/features/call/webrtc/WebRtcCallExt.kt | 9 +++++++-- .../app/features/notifications/NotificationUtils.kt | 6 +++--- vector/src/main/res/values/strings.xml | 10 ++++++++-- 6 files changed, 27 insertions(+), 16 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/model/MxCallImpl.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/model/MxCallImpl.kt index 31f3e114e5..2827b60b34 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/model/MxCallImpl.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/model/MxCallImpl.kt @@ -143,7 +143,7 @@ internal class MxCallImpl( override fun reject() { if (opponentVersion < 1) { Timber.v("Opponent version is less than 1 ($opponentVersion): sending hangup instead of reject") - hangUp() + hangUp(EndCallReason.USER_HANGUP) return } Timber.v("## VOIP reject $callId") @@ -162,7 +162,7 @@ internal class MxCallImpl( CallHangupContent( callId = callId, partyId = ourPartyId, - reason = reason ?: EndCallReason.USER_HANGUP, + reason = reason, version = MxCall.VOIP_PROTO_VERSION.toString() ) .let { createEventAndLocalEcho(type = EventType.CALL_HANGUP, roomId = roomId, content = it.toContent()) } diff --git a/vector/src/main/java/im/vector/app/core/services/CallService.kt b/vector/src/main/java/im/vector/app/core/services/CallService.kt index e5ba2ea10c..2cc33711ea 100644 --- a/vector/src/main/java/im/vector/app/core/services/CallService.kt +++ b/vector/src/main/java/im/vector/app/core/services/CallService.kt @@ -167,7 +167,7 @@ class CallService : VectorService() { } ).apply { viewBinder = IncomingCallAlert.ViewBinder( - matrixItem = callInformation.matrixItem, + matrixItem = callInformation.opponentMatrixItem, avatarRenderer = avatarRenderer, isVideoCall = isVideoCall, onAccept = { showCallScreen(call, VectorCallActivity.INCOMING_ACCEPT) }, @@ -179,7 +179,7 @@ class CallService : VectorService() { alertManager.postVectorAlert(incomingCallAlert) val notification = notificationUtils.buildIncomingCallNotification( call = call, - title = callInformation.matrixItem?.getBestName() ?: callInformation.opponentUserId, + title = callInformation.opponentMatrixItem?.getBestName() ?: callInformation.opponentUserId, fromBg = fromBg ) if (knownCalls.isEmpty()) { @@ -235,7 +235,7 @@ class CallService : VectorService() { Timber.v("displayOutgoingCallNotification : display the dedicated notification") val notification = notificationUtils.buildOutgoingRingingCallNotification( call = call, - title = callInformation.matrixItem?.getBestName() ?: callInformation.opponentUserId + title = callInformation.opponentMatrixItem?.getBestName() ?: callInformation.opponentUserId ) if (knownCalls.isEmpty()) { startForeground(callId.hashCode(), notification) @@ -259,7 +259,7 @@ class CallService : VectorService() { val callInformation = call.toCallInformation() val notification = notificationUtils.buildPendingCallNotification( call = call, - title = callInformation.matrixItem?.getBestName() ?: callInformation.opponentUserId + title = callInformation.opponentMatrixItem?.getBestName() ?: callInformation.opponentUserId ) if (knownCalls.isEmpty()) { startForeground(callId.hashCode(), notification) @@ -293,7 +293,7 @@ class CallService : VectorService() { callId = this.callId, nativeRoomId = this.nativeRoomId, opponentUserId = this.mxCall.opponentUserId, - matrixItem = vectorComponent().activeSessionHolder().getSafeActiveSession()?.let { + opponentMatrixItem = vectorComponent().activeSessionHolder().getSafeActiveSession()?.let { this.getOpponentAsMatrixItem(it) }, isVideoCall = this.mxCall.isVideoCall, @@ -305,7 +305,7 @@ class CallService : VectorService() { val callId: String, val nativeRoomId: String, val opponentUserId: String, - val matrixItem: MatrixItem?, + val opponentMatrixItem: MatrixItem?, val isVideoCall: Boolean, val isOutgoing: Boolean ) diff --git a/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCall.kt b/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCall.kt index 7ec6715b42..3be942d9c8 100644 --- a/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCall.kt +++ b/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCall.kt @@ -798,7 +798,7 @@ class WebRtcCall( } } - fun endCall(reason: EndCallReason? = null) { + fun endCall(reason: EndCallReason = EndCallReason.USER_HANGUP) { sessionScope?.launch(dispatcher) { if (mxCall.state is CallState.Ended) { return@launch diff --git a/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCallExt.kt b/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCallExt.kt index c99d097707..ef9ef3ef9a 100644 --- a/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCallExt.kt +++ b/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCallExt.kt @@ -21,7 +21,12 @@ import org.matrix.android.sdk.api.util.MatrixItem import org.matrix.android.sdk.api.util.toMatrixItem fun WebRtcCall.getOpponentAsMatrixItem(session: Session): MatrixItem? { - return session.getRoomSummary(nativeRoomId)?.otherMemberIds?.firstOrNull()?.let { - session.getUser(it)?.toMatrixItem() + return session.getRoomSummary(nativeRoomId)?.let { roomSummary -> + // Fallback to RoomSummary if there is no other member. + if (roomSummary.otherMemberIds.isEmpty()) { + roomSummary.toMatrixItem() + } else { + roomSummary.otherMemberIds.first().let { session.getUser(it)?.toMatrixItem() } + } } } diff --git a/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt b/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt index 3c4af56b37..24a64f3cdb 100755 --- a/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt +++ b/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt @@ -479,13 +479,13 @@ class NotificationUtils @Inject constructor(private val context: Context, */ fun buildCallMissedNotification(callInformation: CallService.CallInformation): Notification { val builder = NotificationCompat.Builder(context, SILENT_NOTIFICATION_CHANNEL_ID) - .setContentTitle(callInformation.matrixItem?.getBestName() ?: callInformation.opponentUserId) + .setContentTitle(callInformation.opponentMatrixItem?.getBestName() ?: callInformation.opponentUserId) .apply { if (callInformation.isVideoCall) { - setContentText(stringProvider.getString(R.string.missed_video_call)) + setContentText(stringProvider.getQuantityString(R.plurals.missed_video_call, 1, 1)) setSmallIcon(R.drawable.ic_missed_video_call) } else { - setContentText(stringProvider.getString(R.string.missed_audio_call)) + setContentText(stringProvider.getQuantityString(R.plurals.missed_audio_call, 1, 1)) setSmallIcon(R.drawable.ic_missed_voice_call) } } diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index f77c940cf9..4cd7f6f6c3 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -727,8 +727,14 @@ Call connected Call connecting… Call ended - Missed audio call - Missed video call + + Missed audio call + %d missed audio calls + + + Missed video call + %d missed video calls + Calling… Incoming Call Incoming Video Call From b862e5ccbf9c1a15a1bf637ebe8befbb92374363 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 21 Jul 2021 20:52:34 +0200 Subject: [PATCH 17/38] Add initialState support to CreateRoomParams (#3713) --- changelog.d/3713.removal | 1 + .../room/model/create/CreateRoomParams.kt | 8 ++++- .../room/model/create/CreateRoomStateEvent.kt | 36 +++++++++++++++++++ .../room/create/CreateRoomBodyBuilder.kt | 13 ++++++- 4 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 changelog.d/3713.removal create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/CreateRoomStateEvent.kt diff --git a/changelog.d/3713.removal b/changelog.d/3713.removal new file mode 100644 index 0000000000..e797a408e7 --- /dev/null +++ b/changelog.d/3713.removal @@ -0,0 +1 @@ +Add initialState support to CreateRoomParams (#3713) \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/CreateRoomParams.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/CreateRoomParams.kt index ca8c66bb3b..c46d7d0fd2 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/CreateRoomParams.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/CreateRoomParams.kt @@ -25,7 +25,6 @@ import org.matrix.android.sdk.api.session.room.model.RoomHistoryVisibility import org.matrix.android.sdk.api.session.room.model.RoomJoinRulesAllowEntry import org.matrix.android.sdk.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM -// TODO Give a way to include other initial states open class CreateRoomParams { /** * A public visibility indicates that the room will be shown in the published room list. @@ -103,6 +102,13 @@ open class CreateRoomParams { */ val creationContent = mutableMapOf() + /** + * A list of state events to set in the new room. This allows the user to override the default state events + * set in the new room. The expected format of the state events are an object with type, state_key and content keys set. + * Takes precedence over events set by preset, but gets overridden by name and topic keys. + */ + val initialStates = mutableListOf() + /** * Set to true to disable federation of this room. * Default: false diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/CreateRoomStateEvent.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/CreateRoomStateEvent.kt new file mode 100644 index 0000000000..fcfdc3e333 --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/session/room/model/create/CreateRoomStateEvent.kt @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2021 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.session.room.model.create + +import org.matrix.android.sdk.api.session.events.model.Content + +data class CreateRoomStateEvent( + /** + * Required. The type of event to send. + */ + val type: String, + + /** + * Required. The content of the event. + */ + val content: Content, + + /** + * The state_key of the state event. Defaults to an empty string. + */ + val stateKey: String = "" +) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBodyBuilder.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBodyBuilder.kt index 86d2b70da1..b5eae014e2 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBodyBuilder.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBodyBuilder.kt @@ -81,13 +81,14 @@ internal class CreateRoomBodyBuilder @Inject constructor( params.historyVisibility = params.historyVisibility ?: RoomHistoryVisibility.SHARED params.guestAccess = params.guestAccess ?: GuestAccess.Forbidden } - val initialStates = listOfNotNull( + val initialStates = (listOfNotNull( buildEncryptionWithAlgorithmEvent(params), buildHistoryVisibilityEvent(params), buildAvatarEvent(params), buildGuestAccess(params), buildJoinRulesRestricted(params) ) + + buildCustomInitialStates(params)) .takeIf { it.isNotEmpty() } return CreateRoomBody( @@ -107,6 +108,16 @@ internal class CreateRoomBodyBuilder @Inject constructor( ) } + private fun buildCustomInitialStates(params: CreateRoomParams): List { + return params.initialStates.map { + Event( + type = it.type, + stateKey = it.stateKey, + content = it.content + ) + } + } + private suspend fun buildAvatarEvent(params: CreateRoomParams): Event? { return params.avatarUri?.let { avatarUri -> // First upload the image, ignoring any error From 966a959e410c95878a97ef3e884442f248b380c2 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 21 Jul 2021 20:56:08 +0200 Subject: [PATCH 18/38] do not send empty invite list when creating a room --- .../sdk/internal/session/room/create/CreateRoomBodyBuilder.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBodyBuilder.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBodyBuilder.kt index b5eae014e2..2c04759b22 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBodyBuilder.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/room/create/CreateRoomBodyBuilder.kt @@ -96,7 +96,7 @@ internal class CreateRoomBodyBuilder @Inject constructor( roomAliasName = params.roomAliasName, name = params.name, topic = params.topic, - invitedUserIds = params.invitedUserIds.filter { it != userId }, + invitedUserIds = params.invitedUserIds.filter { it != userId }.takeIf { it.isNotEmpty() }, invite3pids = invite3pids, creationContent = params.creationContent.takeIf { it.isNotEmpty() }, initialStates = initialStates, @@ -104,7 +104,6 @@ internal class CreateRoomBodyBuilder @Inject constructor( isDirect = params.isDirect, powerLevelContentOverride = params.powerLevelContentOverride, roomVersion = params.roomVersion - ) } From b6e739afd37aef9208eab89573d40b1464b291c6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 21 Jul 2021 23:04:46 +0000 Subject: [PATCH 19/38] Bump media from 1.3.1 to 1.4.0 Bumps media from 1.3.1 to 1.4.0. --- updated-dependencies: - dependency-name: androidx.media:media dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- vector/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vector/build.gradle b/vector/build.gradle index 0f21723a87..aed5efe4d5 100644 --- a/vector/build.gradle +++ b/vector/build.gradle @@ -342,7 +342,7 @@ dependencies { implementation 'androidx.constraintlayout:constraintlayout:2.0.4' implementation "androidx.sharetarget:sharetarget:1.1.0" implementation 'androidx.core:core-ktx:1.6.0' - implementation "androidx.media:media:1.3.1" + implementation "androidx.media:media:1.4.0" implementation "androidx.transition:transition:1.4.1" implementation "org.threeten:threetenbp:1.4.0:no-tzdb" From 76f412ffe87901ab1cb8011f873f36f3ccc2ea05 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 21 Jul 2021 23:05:41 +0000 Subject: [PATCH 20/38] Bump fragment-ktx from 1.3.5 to 1.3.6 Bumps fragment-ktx from 1.3.5 to 1.3.6. --- updated-dependencies: - dependency-name: androidx.fragment:fragment-ktx dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- multipicker/build.gradle | 2 +- vector/build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/multipicker/build.gradle b/multipicker/build.gradle index a993c452b0..a8a46a86ba 100644 --- a/multipicker/build.gradle +++ b/multipicker/build.gradle @@ -43,7 +43,7 @@ android { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation 'androidx.appcompat:appcompat:1.3.0' - implementation "androidx.fragment:fragment-ktx:1.3.5" + implementation "androidx.fragment:fragment-ktx:1.3.6" implementation 'androidx.exifinterface:exifinterface:1.3.2' // Log diff --git a/vector/build.gradle b/vector/build.gradle index 0f21723a87..5f85dab612 100644 --- a/vector/build.gradle +++ b/vector/build.gradle @@ -305,7 +305,7 @@ android { dependencies { def epoxy_version = '4.6.2' - def fragment_version = '1.3.5' + def fragment_version = '1.3.6' def arrow_version = "0.8.2" def markwon_version = '4.1.2' def big_image_viewer_version = '1.8.0' From 115f00ff1a6e00f53a2753252530f78ccdfafa3f Mon Sep 17 00:00:00 2001 From: ganfra Date: Thu, 22 Jul 2021 10:12:46 +0200 Subject: [PATCH 21/38] Start experiment on log tags --- .../android/sdk/api/logger/LoggerTag.kt | 32 ++++++++ .../session/call/CallEventProcessor.kt | 11 +-- .../session/call/CallSignalingHandler.kt | 23 ++++-- .../vector/app/core/services/CallService.kt | 23 +++--- .../app/features/call/webrtc/WebRtcCall.kt | 81 ++++++++++--------- .../features/call/webrtc/WebRtcCallManager.kt | 53 ++++++------ 6 files changed, 135 insertions(+), 88 deletions(-) create mode 100644 matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/logger/LoggerTag.kt diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/logger/LoggerTag.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/logger/LoggerTag.kt new file mode 100644 index 0000000000..074bd5cf6c --- /dev/null +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/logger/LoggerTag.kt @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2021 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.logger + +/** + * Some tags used on Timber. + */ +open class LoggerTag(private val value: String, private val parentTag: LoggerTag? = null) { + + object VOIP : LoggerTag("VOIP", null) + + val computedValue: String + get() { + if (parentTag == null) return value + return "${parentTag.computedValue}/$value" + } +} + diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallEventProcessor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallEventProcessor.kt index 473adeb8d2..0fb7ce5307 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallEventProcessor.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallEventProcessor.kt @@ -20,11 +20,14 @@ import io.realm.Realm 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.internal.database.model.EventInsertType +import org.matrix.android.sdk.api.logger.LoggerTag import org.matrix.android.sdk.internal.session.EventInsertLiveProcessor import org.matrix.android.sdk.internal.session.SessionScope import timber.log.Timber import javax.inject.Inject +private val CallEventProcessorTag = LoggerTag("CallEventProcessor", LoggerTag.VOIP) + @SessionScope internal class CallEventProcessor @Inject constructor(private val callSignalingHandler: CallSignalingHandler) : EventInsertLiveProcessor { @@ -71,14 +74,8 @@ internal class CallEventProcessor @Inject constructor(private val callSignalingH } private fun dispatchToCallSignalingHandlerIfNeeded(event: Event) { - val now = System.currentTimeMillis() event.roomId ?: return Unit.also { - Timber.w("Event with no room id ${event.eventId}") - } - val age = now - (event.ageLocalTs ?: now) - if (age > 40_000) { - // Too old to ring? - return + Timber.tag(CallEventProcessorTag.computedValue).w("Event with no room id ${event.eventId}") } callSignalingHandler.onCallEvent(event) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallSignalingHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallSignalingHandler.kt index b0901af719..18abfef5f8 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallSignalingHandler.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallSignalingHandler.kt @@ -32,10 +32,13 @@ import org.matrix.android.sdk.api.session.room.model.call.CallRejectContent import org.matrix.android.sdk.api.session.room.model.call.CallSelectAnswerContent import org.matrix.android.sdk.api.session.room.model.call.CallSignalingContent import org.matrix.android.sdk.internal.di.UserId +import org.matrix.android.sdk.api.logger.LoggerTag import org.matrix.android.sdk.internal.session.SessionScope import timber.log.Timber import javax.inject.Inject +private val CallSignalingHandlerTag = LoggerTag("CallSignalingHandler", LoggerTag.VOIP) + @SessionScope internal class CallSignalingHandler @Inject constructor(private val activeCallHandler: ActiveCallHandler, private val mxCallFactory: MxCallFactory, @@ -111,12 +114,12 @@ internal class CallSignalingHandler @Inject constructor(private val activeCallHa return } if (call.isOutgoing) { - Timber.v("Got selectAnswer for an outbound call: ignoring") + Timber.tag(CallSignalingHandlerTag.computedValue).v("Got selectAnswer for an outbound call: ignoring") return } val selectedPartyId = content.selectedPartyId if (selectedPartyId == null) { - Timber.w("Got nonsensical select_answer with null selected_party_id: ignoring") + Timber.tag(CallSignalingHandlerTag.computedValue).w("Got nonsensical select_answer with null selected_party_id: ignoring") return } callListenersDispatcher.onCallSelectAnswerReceived(content) @@ -130,7 +133,7 @@ internal class CallSignalingHandler @Inject constructor(private val activeCallHa return } if (call.opponentPartyId != null && !call.partyIdsMatches(content)) { - Timber.v("Ignoring candidates from party ID ${content.partyId} we have chosen party ID ${call.opponentPartyId}") + Timber.tag(CallSignalingHandlerTag.computedValue).v("Ignoring candidates from party ID ${content.partyId} we have chosen party ID ${call.opponentPartyId}") return } callListenersDispatcher.onCallIceCandidateReceived(call, content) @@ -163,7 +166,7 @@ internal class CallSignalingHandler @Inject constructor(private val activeCallHa // party ID must match (our chosen partner hanging up the call) or be undefined (we haven't chosen // a partner yet but we're treating the hangup as a reject as per VoIP v0) if (call.opponentPartyId != null && !call.partyIdsMatches(content)) { - Timber.v("Ignoring hangup from party ID ${content.partyId} we have chosen party ID ${call.opponentPartyId}") + Timber.tag(CallSignalingHandlerTag.computedValue).v("Ignoring hangup from party ID ${content.partyId} we have chosen party ID ${call.opponentPartyId}") return } if (call.state != CallState.Terminated) { @@ -180,12 +183,18 @@ internal class CallSignalingHandler @Inject constructor(private val activeCallHa if (event.roomId == null || event.senderId == null) { return } + val now = System.currentTimeMillis() + val age = now - (event.ageLocalTs ?: now) + if (age > 40_000 && event.getClearType() == EventType.CALL_INVITE) { + Timber.tag(CallSignalingHandlerTag.computedValue).w("Call invite is too old to ring.") + return + } val content = event.getClearContent().toModel() ?: return content.callId ?: return if (invitedCallIds.contains(content.callId)) { // Call is already known, maybe due to fast lane. Ignore - Timber.d("Ignoring already known call invite") + Timber.tag(CallSignalingHandlerTag.computedValue).d("Ignoring already known call invite") return } val incomingCall = mxCallFactory.createIncomingCall( @@ -214,7 +223,7 @@ internal class CallSignalingHandler @Inject constructor(private val activeCallHa callListenersDispatcher.onCallManagedByOtherSession(content.callId) } else { if (call.opponentPartyId != null) { - Timber.v("Ignoring answer from party ID ${content.partyId} we already have an answer from ${call.opponentPartyId}") + Timber.tag(CallSignalingHandlerTag.computedValue).v("Ignoring answer from party ID ${content.partyId} we already have an answer from ${call.opponentPartyId}") return } mxCallFactory.updateOutgoingCallWithOpponentData(call, event.senderId, content, content.capabilities) @@ -231,7 +240,7 @@ internal class CallSignalingHandler @Inject constructor(private val activeCallHa activeCallHandler.getCallWithId(it) } if (currentCall == null) { - Timber.v("Call with id $callId is null") + Timber.tag(CallSignalingHandlerTag.computedValue).v("Call with id $callId is null") } return currentCall } diff --git a/vector/src/main/java/im/vector/app/core/services/CallService.kt b/vector/src/main/java/im/vector/app/core/services/CallService.kt index 59eee14d37..d83c3e47f5 100644 --- a/vector/src/main/java/im/vector/app/core/services/CallService.kt +++ b/vector/src/main/java/im/vector/app/core/services/CallService.kt @@ -37,9 +37,12 @@ import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.notifications.NotificationUtils import im.vector.app.features.popup.IncomingCallAlert import im.vector.app.features.popup.PopupAlertManager +import org.matrix.android.sdk.api.logger.LoggerTag import org.matrix.android.sdk.api.util.MatrixItem import timber.log.Timber +private val CallServiceTag = LoggerTag("CallService", LoggerTag.VOIP) + /** * Foreground service to manage calls */ @@ -91,7 +94,7 @@ class CallService : VectorService() { } override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { - Timber.v("## VOIP onStartCommand $intent") + Timber.tag(CallServiceTag.computedValue).v("onStartCommand $intent") if (mediaSession == null) { mediaSession = MediaSessionCompat(applicationContext, CallService::class.java.name).apply { setCallback(mediaSessionButtonCallback) @@ -115,19 +118,19 @@ class CallService : VectorService() { callRingPlayerOutgoing?.start() displayOutgoingRingingCallNotification(intent) } - ACTION_ONGOING_CALL -> { + ACTION_ONGOING_CALL -> { callRingPlayerIncoming?.stop() callRingPlayerOutgoing?.stop() displayCallInProgressNotification(intent) } - ACTION_CALL_CONNECTING -> { + ACTION_CALL_CONNECTING -> { // lower notification priority displayCallInProgressNotification(intent) // stop ringing callRingPlayerIncoming?.stop() callRingPlayerOutgoing?.stop() } - ACTION_CALL_TERMINATED -> { + ACTION_CALL_TERMINATED -> { handleCallTerminated(intent) } else -> { @@ -148,7 +151,7 @@ class CallService : VectorService() { * */ private fun displayIncomingCallNotification(intent: Intent) { - Timber.v("## VOIP displayIncomingCallNotification $intent") + Timber.tag(CallServiceTag.computedValue).v("displayIncomingCallNotification $intent") val callId = intent.getStringExtra(EXTRA_CALL_ID) ?: "" val call = callManager.getCallById(callId) ?: return Unit.also { handleUnexpectedState(callId) @@ -156,7 +159,7 @@ class CallService : VectorService() { val isVideoCall = call.mxCall.isVideoCall val fromBg = intent.getBooleanExtra(EXTRA_IS_IN_BG, false) val opponentMatrixItem = getOpponentMatrixItem(call) - Timber.v("displayIncomingCallNotification : display the dedicated notification") + Timber.tag(CallServiceTag.computedValue).v("displayIncomingCallNotification : display the dedicated notification") val incomingCallAlert = IncomingCallAlert(callId, shouldBeDisplayedIn = { activity -> if (activity is VectorCallActivity) { @@ -192,7 +195,7 @@ class CallService : VectorService() { val callId = intent.getStringExtra(EXTRA_CALL_ID) ?: "" alertManager.cancelAlert(callId) if (!knownCalls.remove(callId)) { - Timber.v("Call terminated for unknown call $callId$") + Timber.tag(CallServiceTag.computedValue).v("Call terminated for unknown call $callId$") handleUnexpectedState(callId) return } @@ -219,7 +222,7 @@ class CallService : VectorService() { handleUnexpectedState(callId) } val opponentMatrixItem = getOpponentMatrixItem(call) - Timber.v("displayOutgoingCallNotification : display the dedicated notification") + Timber.tag(CallServiceTag.computedValue).v("displayOutgoingCallNotification : display the dedicated notification") val notification = notificationUtils.buildOutgoingRingingCallNotification( call = call, title = opponentMatrixItem?.getBestName() ?: call.mxCall.opponentUserId @@ -236,7 +239,7 @@ class CallService : VectorService() { * Display a call in progress notification. */ private fun displayCallInProgressNotification(intent: Intent) { - Timber.v("## VOIP displayCallInProgressNotification") + Timber.tag(CallServiceTag.computedValue).v("displayCallInProgressNotification") val callId = intent.getStringExtra(EXTRA_CALL_ID) ?: "" val call = callManager.getCallById(callId) ?: return Unit.also { handleUnexpectedState(callId) @@ -256,7 +259,7 @@ class CallService : VectorService() { } private fun handleUnexpectedState(callId: String?) { - Timber.v("Fallback to clear everything") + Timber.tag(CallServiceTag.computedValue).v("Fallback to clear everything") callRingPlayerIncoming?.stop() callRingPlayerOutgoing?.stop() if (callId != null) { diff --git a/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCall.kt b/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCall.kt index 3259b0915f..9bcd442be6 100644 --- a/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCall.kt +++ b/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCall.kt @@ -45,6 +45,7 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.extensions.tryOrNull +import org.matrix.android.sdk.api.logger.LoggerTag import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.call.CallIdGenerator import org.matrix.android.sdk.api.session.call.CallState @@ -88,6 +89,8 @@ private const val AUDIO_TRACK_ID = "${STREAM_ID}a0" private const val VIDEO_TRACK_ID = "${STREAM_ID}v0" private val DEFAULT_AUDIO_CONSTRAINTS = MediaConstraints() +private val WebRtcCallTag = LoggerTag("WebRtcCall", LoggerTag.VOIP) + class WebRtcCall( val mxCall: MxCall, // This is where the call is placed from an ui perspective. @@ -192,7 +195,7 @@ class WebRtcCall( .subscribe { // omit empty :/ if (it.isNotEmpty()) { - Timber.v("## Sending local ice candidates to call") + Timber.tag(WebRtcCallTag.computedValue).v("Sending local ice candidates to call") // it.forEach { peerConnection?.addIceCandidate(it) } mxCall.sendLocalCallCandidates(it.mapToCallCandidate()) } @@ -210,7 +213,7 @@ class WebRtcCall( fun onRenegotiationNeeded(restartIce: Boolean) { sessionScope?.launch(dispatcher) { if (mxCall.state != CallState.CreateOffer && mxCall.opponentVersion == 0) { - Timber.v("Opponent does not support renegotiation: ignoring onRenegotiationNeeded event") + Timber.tag(WebRtcCallTag.computedValue).v("Opponent does not support renegotiation: ignoring onRenegotiationNeeded event") return@launch } val constraints = MediaConstraints() @@ -218,7 +221,7 @@ class WebRtcCall( constraints.mandatory.add(MediaConstraints.KeyValuePair("IceRestart", "true")) } val peerConnection = peerConnection ?: return@launch - Timber.v("## VOIP creating offer...") + Timber.tag(WebRtcCallTag.computedValue).v("creating offer...") makingOffer = true try { val sessionDescription = peerConnection.awaitCreateOffer(constraints) ?: return@launch @@ -238,7 +241,7 @@ class WebRtcCall( } } catch (failure: Throwable) { // Need to handle error properly. - Timber.v("Failure while creating offer") + Timber.tag(WebRtcCallTag.computedValue).v("Failure while creating offer") } finally { makingOffer = false } @@ -267,7 +270,7 @@ class WebRtcCall( } } } - Timber.v("## VOIP creating peer connection...with iceServers $iceServers ") + Timber.tag(WebRtcCallTag.computedValue).v("creating peer connection...with iceServers $iceServers ") val rtcConfig = PeerConnection.RTCConfiguration(iceServers).apply { sdpSemantics = PeerConnection.SdpSemantics.UNIFIED_PLAN } @@ -314,7 +317,7 @@ class WebRtcCall( fun acceptIncomingCall() { sessionScope?.launch { - Timber.v("## VOIP acceptIncomingCall from state ${mxCall.state}") + Timber.tag(WebRtcCallTag.computedValue).v("acceptIncomingCall from state ${mxCall.state}") if (mxCall.state == CallState.LocalRinging) { internalAcceptIncomingCall() } @@ -333,7 +336,7 @@ class WebRtcCall( sender.dtmf()?.insertDtmf(digit, 100, 70) return@launch } catch (failure: Throwable) { - Timber.v("Fail to send Dtmf digit") + Timber.tag(WebRtcCallTag.computedValue).v("Fail to send Dtmf digit") } } } @@ -342,7 +345,7 @@ class WebRtcCall( fun attachViewRenderers(localViewRenderer: SurfaceViewRenderer?, remoteViewRenderer: SurfaceViewRenderer, mode: String?) { sessionScope?.launch(dispatcher) { - Timber.v("## VOIP attachViewRenderers localRendeder $localViewRenderer / $remoteViewRenderer") + Timber.tag(WebRtcCallTag.computedValue).v("attachViewRenderers localRendeder $localViewRenderer / $remoteViewRenderer") localSurfaceRenderers.addIfNeeded(localViewRenderer) remoteSurfaceRenderers.addIfNeeded(remoteViewRenderer) when (mode) { @@ -389,7 +392,7 @@ class WebRtcCall( } private suspend fun detachRenderersInternal(renderers: List?) = withContext(dispatcher) { - Timber.v("## VOIP detachRenderers") + Timber.tag(WebRtcCallTag.computedValue).v("detachRenderers") if (renderers.isNullOrEmpty()) { // remove all sinks localSurfaceRenderers.forEach { @@ -422,12 +425,12 @@ class WebRtcCall( // 2. Access camera (if video call) + microphone, create local stream createLocalStream() attachViewRenderersInternal() - Timber.v("## VOIP remoteCandidateSource $remoteCandidateSource") + Timber.tag(WebRtcCallTag.computedValue).v("remoteCandidateSource $remoteCandidateSource") remoteIceCandidateDisposable = remoteCandidateSource.subscribe({ - Timber.v("## VOIP adding remote ice candidate $it") + Timber.tag(WebRtcCallTag.computedValue).v("adding remote ice candidate $it") peerConnection?.addIceCandidate(it) }, { - Timber.v("## VOIP failed to add remote ice candidate $it") + Timber.tag(WebRtcCallTag.computedValue).v("failed to add remote ice candidate $it") }) // Now we wait for negotiation callback } @@ -453,14 +456,14 @@ class WebRtcCall( SessionDescription(SessionDescription.Type.OFFER, it) } if (offerSdp == null) { - Timber.v("We don't have any offer to process") + Timber.tag(WebRtcCallTag.computedValue).v("We don't have any offer to process") return@withContext } - Timber.v("Offer sdp for invite: ${offerSdp.description}") + Timber.tag(WebRtcCallTag.computedValue).v("Offer sdp for invite: ${offerSdp.description}") try { peerConnection?.awaitSetRemoteDescription(offerSdp) } catch (failure: Throwable) { - Timber.v("Failure putting remote description") + Timber.tag(WebRtcCallTag.computedValue).v("Failure putting remote description") endCall(true, CallHangupContent.Reason.UNKWOWN_ERROR) return@withContext } @@ -472,12 +475,12 @@ class WebRtcCall( createAnswer()?.also { mxCall.accept(it.description) } - Timber.v("## VOIP remoteCandidateSource $remoteCandidateSource") + Timber.tag(WebRtcCallTag.computedValue).v("remoteCandidateSource $remoteCandidateSource") remoteIceCandidateDisposable = remoteCandidateSource.subscribe({ - Timber.v("## VOIP adding remote ice candidate $it") + Timber.tag(WebRtcCallTag.computedValue).v("adding remote ice candidate $it") peerConnection?.addIceCandidate(it) }, { - Timber.v("## VOIP failed to add remote ice candidate $it") + Timber.tag(WebRtcCallTag.computedValue).v("failed to add remote ice candidate $it") }) } @@ -489,7 +492,7 @@ class WebRtcCall( private fun createLocalStream() { val peerConnectionFactory = peerConnectionFactoryProvider.get() ?: return - Timber.v("Create local stream for call ${mxCall.callId}") + Timber.tag(WebRtcCallTag.computedValue).v("Create local stream for call ${mxCall.callId}") configureAudioTrack(peerConnectionFactory) // add video track if needed if (mxCall.isVideoCall) { @@ -502,7 +505,7 @@ class WebRtcCall( val audioSource = peerConnectionFactory.createAudioSource(DEFAULT_AUDIO_CONSTRAINTS) val audioTrack = peerConnectionFactory.createAudioTrack(AUDIO_TRACK_ID, audioSource) audioTrack.setEnabled(true) - Timber.v("Add audio track $AUDIO_TRACK_ID to call ${mxCall.callId}") + Timber.tag(WebRtcCallTag.computedValue).v("Add audio track $AUDIO_TRACK_ID to call ${mxCall.callId}") peerConnection?.addTrack(audioTrack, listOf(STREAM_ID)) localAudioSource = audioSource localAudioTrack = audioTrack @@ -544,7 +547,7 @@ class WebRtcCall( override fun onCameraClosed() { super.onCameraClosed() - Timber.v("onCameraClosed") + Timber.tag(WebRtcCallTag.computedValue).v("onCameraClosed") // This could happen if you open the camera app in chat // We then register in order to restart capture as soon as the camera is available again videoCapturerIsInError = true @@ -552,16 +555,16 @@ class WebRtcCall( cameraAvailabilityCallback = object : CameraManager.AvailabilityCallback() { override fun onCameraUnavailable(cameraId: String) { super.onCameraUnavailable(cameraId) - Timber.v("On camera unavailable: $cameraId") + Timber.tag(WebRtcCallTag.computedValue).v("On camera unavailable: $cameraId") } override fun onCameraAccessPrioritiesChanged() { super.onCameraAccessPrioritiesChanged() - Timber.v("onCameraAccessPrioritiesChanged") + Timber.tag(WebRtcCallTag.computedValue).v("onCameraAccessPrioritiesChanged") } override fun onCameraAvailable(cameraId: String) { - Timber.v("On camera available: $cameraId") + Timber.tag(WebRtcCallTag.computedValue).v("On camera available: $cameraId") if (cameraId == camera.name) { videoCapturer?.startCapture(currentCaptureFormat.width, currentCaptureFormat.height, currentCaptureFormat.fps) cameraManager?.unregisterAvailabilityCallback(this) @@ -574,7 +577,7 @@ class WebRtcCall( val videoSource = peerConnectionFactory.createVideoSource(videoCapturer.isScreencast) val surfaceTextureHelper = SurfaceTextureHelper.create("CaptureThread", rootEglBase!!.eglBaseContext) - Timber.v("## VOIP Local video source created") + Timber.tag(WebRtcCallTag.computedValue).v("Local video source created") videoCapturer.initialize(surfaceTextureHelper, context, videoSource.capturerObserver) // HD @@ -582,7 +585,7 @@ class WebRtcCall( this.videoCapturer = videoCapturer val videoTrack = peerConnectionFactory.createVideoTrack(VIDEO_TRACK_ID, videoSource) - Timber.v("Add video track $VIDEO_TRACK_ID to call ${mxCall.callId}") + Timber.tag(WebRtcCallTag.computedValue).v("Add video track $VIDEO_TRACK_ID to call ${mxCall.callId}") videoTrack.setEnabled(true) peerConnection?.addTrack(videoTrack, listOf(STREAM_ID)) localVideoSource = videoSource @@ -592,7 +595,7 @@ class WebRtcCall( fun setCaptureFormat(format: CaptureFormat) { sessionScope?.launch(dispatcher) { - Timber.v("## VOIP setCaptureFormat $format") + Timber.tag(WebRtcCallTag.computedValue).v("setCaptureFormat $format") videoCapturer?.changeCaptureFormat(format.width, format.height, format.fps) currentCaptureFormat = format } @@ -686,14 +689,14 @@ class WebRtcCall( fun switchCamera() { sessionScope?.launch(dispatcher) { - Timber.v("## VOIP switchCamera") + Timber.tag(WebRtcCallTag.computedValue).v("switchCamera") if (mxCall.state is CallState.Connected && mxCall.isVideoCall) { val oppositeCamera = getOppositeCameraIfAny() ?: return@launch videoCapturer?.switchCamera( object : CameraVideoCapturer.CameraSwitchHandler { // Invoked on success. |isFrontCamera| is true if the new camera is front facing. override fun onCameraSwitchDone(isFrontCamera: Boolean) { - Timber.v("## VOIP onCameraSwitchDone isFront $isFrontCamera") + Timber.tag(WebRtcCallTag.computedValue).v("onCameraSwitchDone isFront $isFrontCamera") cameraInUse = oppositeCamera localSurfaceRenderers.forEach { it.get()?.setMirror(isFrontCamera) @@ -704,7 +707,7 @@ class WebRtcCall( } override fun onCameraSwitchError(errorDescription: String?) { - Timber.v("## VOIP onCameraSwitchError isFront $errorDescription") + Timber.tag(WebRtcCallTag.computedValue).v("onCameraSwitchError isFront $errorDescription") } }, oppositeCamera.name ) @@ -713,7 +716,7 @@ class WebRtcCall( } private suspend fun createAnswer(): SessionDescription? { - Timber.w("## VOIP createAnswer") + Timber.tag(WebRtcCallTag.computedValue).w("createAnswer") val peerConnection = peerConnection ?: return null val constraints = MediaConstraints().apply { mandatory.add(MediaConstraints.KeyValuePair("OfferToReceiveAudio", "true")) @@ -724,7 +727,7 @@ class WebRtcCall( peerConnection.awaitSetLocalDescription(localDescription) localDescription } catch (failure: Throwable) { - Timber.v("Fail to create answer") + Timber.tag(WebRtcCallTag.computedValue).v("Fail to create answer") null } } @@ -765,7 +768,7 @@ class WebRtcCall( sessionScope?.launch(dispatcher) { // reportError("Weird-looking stream: " + stream); if (stream.audioTracks.size > 1 || stream.videoTracks.size > 1) { - Timber.e("## VOIP StreamObserver weird looking stream: $stream") + Timber.tag(WebRtcCallTag.computedValue).e("## VOIP StreamObserver weird looking stream: $stream") // TODO maybe do something more?? endCall(true) return@launch @@ -829,7 +832,7 @@ class WebRtcCall( if (it.sdpMid.isNullOrEmpty() || it.candidate.isNullOrEmpty()) { return@forEach } - Timber.v("## VOIP onCallIceCandidateReceived for call ${mxCall.callId} sdp: ${it.candidate}") + Timber.tag(WebRtcCallTag.computedValue).v("onCallIceCandidateReceived for call ${mxCall.callId} sdp: ${it.candidate}") val iceCandidate = IceCandidate(it.sdpMid, it.sdpMLineIndex, it.candidate) remoteCandidateSource.onNext(iceCandidate) } @@ -838,7 +841,7 @@ class WebRtcCall( fun onCallAnswerReceived(callAnswerContent: CallAnswerContent) { sessionScope?.launch(dispatcher) { - Timber.v("## VOIP onCallAnswerReceived ${callAnswerContent.callId}") + Timber.tag(WebRtcCallTag.computedValue).v("onCallAnswerReceived ${callAnswerContent.callId}") val sdp = SessionDescription(SessionDescription.Type.ANSWER, callAnswerContent.answer.sdp) try { peerConnection?.awaitSetRemoteDescription(sdp) @@ -858,7 +861,7 @@ class WebRtcCall( val type = description?.type val sdpText = description?.sdp if (type == null || sdpText == null) { - Timber.i("Ignoring invalid m.call.negotiate event") + Timber.tag(WebRtcCallTag.computedValue).i("Ignoring invalid m.call.negotiate event") return@launch } val peerConnection = peerConnection ?: return@launch @@ -873,7 +876,7 @@ class WebRtcCall( ignoreOffer = !polite && offerCollision if (ignoreOffer) { - Timber.i("Ignoring colliding negotiate event because we're impolite") + Timber.tag(WebRtcCallTag.computedValue).i("Ignoring colliding negotiate event because we're impolite") return@launch } val prevOnHold = computeIsLocalOnHold() @@ -886,7 +889,7 @@ class WebRtcCall( } } } catch (failure: Throwable) { - Timber.e(failure, "Failed to complete negotiation") + Timber.tag(WebRtcCallTag.computedValue).e(failure, "Failed to complete negotiation") } val nowOnHold = computeIsLocalOnHold() wasLocalOnHold = nowOnHold @@ -909,7 +912,7 @@ class WebRtcCall( val session = sessionProvider.get() ?: return@launch val newAssertedIdentity = callAssertedIdentityContent.assertedIdentity ?: return@launch if (newAssertedIdentity.id == null && newAssertedIdentity.displayName == null) { - Timber.v("Asserted identity received with no relevant information, skip") + Timber.tag(WebRtcCallTag.computedValue).v("Asserted identity received with no relevant information, skip") return@launch } remoteAssertedIdentity = newAssertedIdentity diff --git a/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCallManager.kt b/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCallManager.kt index 25463428e9..566ba7e81a 100644 --- a/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCallManager.kt +++ b/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCallManager.kt @@ -33,6 +33,7 @@ import im.vector.app.push.fcm.FcmHelper import kotlinx.coroutines.asCoroutineDispatcher import org.matrix.android.sdk.api.extensions.orFalse import org.matrix.android.sdk.api.extensions.tryOrNull +import org.matrix.android.sdk.api.logger.LoggerTag import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.call.CallListener import org.matrix.android.sdk.api.session.call.CallState @@ -60,6 +61,8 @@ import javax.inject.Singleton * Manage peerConnectionFactory & Peer connections outside of activity lifecycle to resist configuration changes * Use app context */ +private val WebRtcCallManagerTag = LoggerTag("WebRtcCallManager", LoggerTag.VOIP) + @Singleton class WebRtcCallManager @Inject constructor( private val context: Context, @@ -184,7 +187,7 @@ class WebRtcCallManager @Inject constructor( fun getAdvertisedCalls() = advertisedCalls fun headSetButtonTapped() { - Timber.v("## VOIP headSetButtonTapped") + Timber.tag(WebRtcCallManagerTag.computedValue).v("headSetButtonTapped") val call = getCurrentCall() ?: return if (call.mxCall.state is CallState.LocalRinging) { call.acceptIncomingCall() @@ -197,12 +200,12 @@ class WebRtcCallManager @Inject constructor( private fun createPeerConnectionFactoryIfNeeded() { if (peerConnectionFactory != null) return - Timber.v("## VOIP createPeerConnectionFactory") + Timber.tag(WebRtcCallManagerTag.computedValue).v("createPeerConnectionFactory") val eglBaseContext = rootEglBase?.eglBaseContext ?: return Unit.also { - Timber.e("## VOIP No EGL BASE") + Timber.tag(WebRtcCallManagerTag.computedValue).e("No EGL BASE") } - Timber.v("## VOIP PeerConnectionFactory.initialize") + Timber.tag(WebRtcCallManagerTag.computedValue).v("PeerConnectionFactory.initialize") PeerConnectionFactory.initialize(PeerConnectionFactory .InitializationOptions.builder(context.applicationContext) .createInitializationOptions() @@ -216,7 +219,7 @@ class WebRtcCallManager @Inject constructor( /* enableH264HighProfile */ true) val defaultVideoDecoderFactory = DefaultVideoDecoderFactory(eglBaseContext) - Timber.v("## VOIP PeerConnectionFactory.createPeerConnectionFactory ...") + Timber.tag(WebRtcCallManagerTag.computedValue).v("PeerConnectionFactory.createPeerConnectionFactory ...") peerConnectionFactory = PeerConnectionFactory.builder() .setOptions(options) .setVideoEncoderFactory(defaultVideoEncoderFactory) @@ -225,7 +228,7 @@ class WebRtcCallManager @Inject constructor( } private fun onCallActive(call: WebRtcCall) { - Timber.v("## VOIP WebRtcPeerConnectionManager onCall active: ${call.mxCall.callId}") + Timber.tag(WebRtcCallManagerTag.computedValue).v("WebRtcPeerConnectionManager onCall active: ${call.mxCall.callId}") val currentCall = getCurrentCall().takeIf { it != call } currentCall?.updateRemoteOnHold(onHold = true) audioManager.setMode(if (call.mxCall.isVideoCall) CallAudioManager.Mode.VIDEO_CALL else CallAudioManager.Mode.AUDIO_CALL) @@ -233,9 +236,9 @@ class WebRtcCallManager @Inject constructor( } private fun onCallEnded(callId: String) { - Timber.v("## VOIP WebRtcPeerConnectionManager onCall ended: $callId") + Timber.tag(WebRtcCallManagerTag.computedValue).v("WebRtcPeerConnectionManager onCall ended: $callId") val webRtcCall = callsByCallId.remove(callId) ?: return Unit.also { - Timber.v("On call ended for unknown call $callId") + Timber.tag(WebRtcCallManagerTag.computedValue).v("On call ended for unknown call $callId") } CallService.onCallTerminated(context, callId) callsByRoomId[webRtcCall.signalingRoomId]?.remove(webRtcCall) @@ -247,7 +250,7 @@ class WebRtcCallManager @Inject constructor( } // There is no active calls if (getCurrentCall() == null) { - Timber.v("## VOIP Dispose peerConnectionFactory as there is no need to keep one") + Timber.tag(WebRtcCallManagerTag.computedValue).v("Dispose peerConnectionFactory as there is no need to keep one") peerConnectionFactory?.dispose() peerConnectionFactory = null audioManager.setMode(CallAudioManager.Mode.DEFAULT) @@ -265,13 +268,13 @@ class WebRtcCallManager @Inject constructor( suspend fun startOutgoingCall(nativeRoomId: String, otherUserId: String, isVideoCall: Boolean, transferee: WebRtcCall? = null) { val signalingRoomId = callUserMapper?.getOrCreateVirtualRoomForRoom(nativeRoomId, otherUserId) ?: nativeRoomId - Timber.v("## VOIP startOutgoingCall in room $signalingRoomId to $otherUserId isVideo $isVideoCall") + Timber.tag(WebRtcCallManagerTag.computedValue).v("startOutgoingCall in room $signalingRoomId to $otherUserId isVideo $isVideoCall") if (getCallsByRoomId(nativeRoomId).isNotEmpty()) { - Timber.w("## VOIP you already have a call in this room") + Timber.tag(WebRtcCallManagerTag.computedValue).w("you already have a call in this room") return } if (getCurrentCall() != null && getCurrentCall()?.mxCall?.state !is CallState.Connected || getCalls().size >= 2) { - Timber.w("## VOIP cannot start outgoing call") + Timber.tag(WebRtcCallManagerTag.computedValue).w("cannot start outgoing call") // Just ignore, maybe we could answer from other session? return } @@ -294,10 +297,10 @@ class WebRtcCallManager @Inject constructor( } override fun onCallIceCandidateReceived(mxCall: MxCall, iceCandidatesContent: CallCandidatesContent) { - Timber.v("## VOIP onCallIceCandidateReceived for call ${mxCall.callId}") + Timber.tag(WebRtcCallManagerTag.computedValue).v("onCallIceCandidateReceived for call ${mxCall.callId}") val call = callsByCallId[iceCandidatesContent.callId] ?: return Unit.also { - Timber.w("onCallIceCandidateReceived for non active call? ${iceCandidatesContent.callId}") + Timber.tag(WebRtcCallManagerTag.computedValue).w("onCallIceCandidateReceived for non active call? ${iceCandidatesContent.callId}") } call.onCallIceCandidateReceived(iceCandidatesContent) } @@ -334,14 +337,14 @@ class WebRtcCallManager @Inject constructor( } override fun onCallInviteReceived(mxCall: MxCall, callInviteContent: CallInviteContent) { - Timber.v("## VOIP onCallInviteReceived callId ${mxCall.callId}") + Timber.tag(WebRtcCallManagerTag.computedValue).v("onCallInviteReceived callId ${mxCall.callId}") val nativeRoomId = callUserMapper?.nativeRoomForVirtualRoom(mxCall.roomId) ?: mxCall.roomId if (getCallsByRoomId(nativeRoomId).isNotEmpty()) { - Timber.w("## VOIP you already have a call in this room") + Timber.tag(WebRtcCallManagerTag.computedValue).w("you already have a call in this room") return } if ((getCurrentCall() != null && getCurrentCall()?.mxCall?.state !is CallState.Connected) || getCalls().size >= 2) { - Timber.w("## VOIP receiving incoming call but cannot handle it") + Timber.tag(WebRtcCallManagerTag.computedValue).w("receiving incoming call but cannot handle it") // Just ignore, maybe we could answer from other session? return } @@ -370,7 +373,7 @@ class WebRtcCallManager @Inject constructor( override fun onCallAnswerReceived(callAnswerContent: CallAnswerContent) { val call = callsByCallId[callAnswerContent.callId] ?: return Unit.also { - Timber.w("onCallAnswerReceived for non active call? ${callAnswerContent.callId}") + Timber.tag(WebRtcCallManagerTag.computedValue).w("onCallAnswerReceived for non active call? ${callAnswerContent.callId}") } val mxCall = call.mxCall // Update service state @@ -384,7 +387,7 @@ class WebRtcCallManager @Inject constructor( override fun onCallHangupReceived(callHangupContent: CallHangupContent) { val call = callsByCallId[callHangupContent.callId] ?: return Unit.also { - Timber.w("onCallHangupReceived for non active call? ${callHangupContent.callId}") + Timber.tag(WebRtcCallManagerTag.computedValue).w("onCallHangupReceived for non active call? ${callHangupContent.callId}") } call.endCall(false) } @@ -392,7 +395,7 @@ class WebRtcCallManager @Inject constructor( override fun onCallRejectReceived(callRejectContent: CallRejectContent) { val call = callsByCallId[callRejectContent.callId] ?: return Unit.also { - Timber.w("onCallRejectReceived for non active call? ${callRejectContent.callId}") + Timber.tag(WebRtcCallManagerTag.computedValue).w("onCallRejectReceived for non active call? ${callRejectContent.callId}") } call.endCall(false) } @@ -400,7 +403,7 @@ class WebRtcCallManager @Inject constructor( override fun onCallSelectAnswerReceived(callSelectAnswerContent: CallSelectAnswerContent) { val call = callsByCallId[callSelectAnswerContent.callId] ?: return Unit.also { - Timber.w("onCallSelectAnswerReceived for non active call? ${callSelectAnswerContent.callId}") + Timber.tag(WebRtcCallManagerTag.computedValue).w("onCallSelectAnswerReceived for non active call? ${callSelectAnswerContent.callId}") } val selectedPartyId = callSelectAnswerContent.selectedPartyId if (selectedPartyId != call.mxCall.ourPartyId) { @@ -413,13 +416,13 @@ class WebRtcCallManager @Inject constructor( override fun onCallNegotiateReceived(callNegotiateContent: CallNegotiateContent) { val call = callsByCallId[callNegotiateContent.callId] ?: return Unit.also { - Timber.w("onCallNegotiateReceived for non active call? ${callNegotiateContent.callId}") + Timber.tag(WebRtcCallManagerTag.computedValue).w("onCallNegotiateReceived for non active call? ${callNegotiateContent.callId}") } call.onCallNegotiateReceived(callNegotiateContent) } override fun onCallManagedByOtherSession(callId: String) { - Timber.v("## VOIP onCallManagedByOtherSession: $callId") + Timber.tag(WebRtcCallManagerTag.computedValue).v("onCallManagedByOtherSession: $callId") onCallEnded(callId) } @@ -429,8 +432,8 @@ class WebRtcCallManager @Inject constructor( } val call = callsByCallId[callAssertedIdentityContent.callId] ?: return Unit.also { - Timber.w("onCallAssertedIdentityReceived for non active call? ${callAssertedIdentityContent.callId}") + Timber.tag(WebRtcCallManagerTag.computedValue).w("onCallAssertedIdentityReceived for non active call? ${callAssertedIdentityContent.callId}") } - call.onCallAssertedIdentityReceived(callAssertedIdentityContent) + call.onCallAssertedIdentityReceived(callAssertedIdentityContent) } } From 4bbf1751878b441642f94df69678b57a96b4641f Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 22 Jul 2021 12:46:34 +0200 Subject: [PATCH 22/38] Fix a crash which can happen when user signs out. The crypto DB has been deleted, and the key download request is cancelled, but in the catch block we tried to write to the deleted DB --- changelog.d/3720.bugfix | 1 + .../android/sdk/internal/crypto/DeviceListManager.kt | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 changelog.d/3720.bugfix diff --git a/changelog.d/3720.bugfix b/changelog.d/3720.bugfix new file mode 100644 index 0000000000..18363b90e3 --- /dev/null +++ b/changelog.d/3720.bugfix @@ -0,0 +1 @@ +Fix a crash which can happen when user signs out \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DeviceListManager.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DeviceListManager.kt index 63f15aaf6e..79910c6de2 100755 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DeviceListManager.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DeviceListManager.kt @@ -16,6 +16,7 @@ package org.matrix.android.sdk.internal.crypto +import kotlinx.coroutines.CancellationException import kotlinx.coroutines.launch import org.matrix.android.sdk.api.MatrixPatterns import org.matrix.android.sdk.api.auth.data.Credentials @@ -336,7 +337,12 @@ internal class DeviceListManager @Inject constructor(private val cryptoStore: IM downloadKeysForUsersTask.execute(params) } catch (throwable: Throwable) { Timber.e(throwable, "## CRYPTO | doKeyDownloadForUsers(): error") - onKeysDownloadFailed(filteredUsers) + if (throwable is CancellationException) { + // the crypto module is getting closed, so we cannot access the DB anymore + Timber.w("The crypto module is closed, ignoring this error") + } else { + onKeysDownloadFailed(filteredUsers) + } throw throwable } Timber.v("## CRYPTO | doKeyDownloadForUsers() : Got keys for " + filteredUsers.size + " users") From 4dd5b2c884498a086d39423c03bb9d23089ff25d Mon Sep 17 00:00:00 2001 From: Andrew Morgan <1342360+anoadragon453@users.noreply.github.com> Date: Thu, 22 Jul 2021 11:58:32 +0100 Subject: [PATCH 23/38] grammar: Server matching ... -> Servers matching ... This commit uses the plural form of Server as each message is talking about *one or more* servers in the room. --- vector/src/main/res/values/strings.xml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index 4cd7f6f6c3..e3385765a8 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -74,19 +74,19 @@ You upgraded here. %s set the server ACLs for this room. You set the server ACLs for this room. - • Server matching %s are banned. - • Server matching %s are allowed. - • Server matching IP literals are allowed. - • Server matching IP literals are banned. + • Servers matching %s are banned. + • Servers matching %s are allowed. + • Servers matching IP literals are allowed. + • Servers matching IP literals are banned. %s changed the server ACLs for this room. You changed the server ACLs for this room. - • Server matching %s are now banned. - • Server matching %s were removed from the ban list. - • Server matching %s are now allowed. - • Server matching %s were removed from the allowed list. - • Server matching IP literals are now allowed. - • Server matching IP literals are now banned. + • Servers matching %s are now banned. + • Servers matching %s were removed from the ban list. + • Servers matching %s are now allowed. + • Servers matching %s were removed from the allowed list. + • Servers matching IP literals are now allowed. + • Servers matching IP literals are now banned. No change. 🎉 All servers are banned from participating! This room can no longer be used. From 74aea4611ac713c648b3e0ba0addd97ac30ebe2d Mon Sep 17 00:00:00 2001 From: Andrew Morgan Date: Thu, 22 Jul 2021 12:02:44 +0100 Subject: [PATCH 24/38] Changelog --- changelog.d/3721.misc | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/3721.misc diff --git a/changelog.d/3721.misc b/changelog.d/3721.misc new file mode 100644 index 0000000000..8c3424c6ed --- /dev/null +++ b/changelog.d/3721.misc @@ -0,0 +1 @@ +Apply grammatical fixes to the Server ACL timeline messages. From a75ceee03f3c04fdd52926c0a2aaa07b6efa85dc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 22 Jul 2021 12:13:24 +0000 Subject: [PATCH 25/38] Bump appcompat from 1.3.0 to 1.3.1 Bumps appcompat from 1.3.0 to 1.3.1. --- updated-dependencies: - dependency-name: androidx.appcompat:appcompat dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- attachment-viewer/build.gradle | 2 +- library/ui-styles/build.gradle | 2 +- matrix-sdk-android-rx/build.gradle | 2 +- matrix-sdk-android/build.gradle | 2 +- multipicker/build.gradle | 2 +- vector/build.gradle | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/attachment-viewer/build.gradle b/attachment-viewer/build.gradle index 0ed883cc95..c393c5f483 100644 --- a/attachment-viewer/build.gradle +++ b/attachment-viewer/build.gradle @@ -56,7 +56,7 @@ dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" implementation 'androidx.core:core-ktx:1.6.0' - implementation 'androidx.appcompat:appcompat:1.3.0' + implementation 'androidx.appcompat:appcompat:1.3.1' implementation "androidx.recyclerview:recyclerview:1.2.1" implementation 'com.google.android.material:material:1.4.0' diff --git a/library/ui-styles/build.gradle b/library/ui-styles/build.gradle index 40360bbbe1..4d34195962 100644 --- a/library/ui-styles/build.gradle +++ b/library/ui-styles/build.gradle @@ -52,7 +52,7 @@ android { } dependencies { - implementation 'androidx.appcompat:appcompat:1.3.0' + implementation 'androidx.appcompat:appcompat:1.3.1' implementation 'com.google.android.material:material:1.4.0' // Pref theme implementation 'androidx.preference:preference-ktx:1.1.1' diff --git a/matrix-sdk-android-rx/build.gradle b/matrix-sdk-android-rx/build.gradle index 0d4aa7fc84..899432b498 100644 --- a/matrix-sdk-android-rx/build.gradle +++ b/matrix-sdk-android-rx/build.gradle @@ -35,7 +35,7 @@ android { dependencies { implementation project(":matrix-sdk-android") - implementation 'androidx.appcompat:appcompat:1.3.0' + implementation 'androidx.appcompat:appcompat:1.3.1' implementation 'io.reactivex.rxjava2:rxkotlin:2.4.0' implementation 'io.reactivex.rxjava2:rxandroid:2.1.1' implementation "org.jetbrains.kotlinx:kotlinx-coroutines-rx2:$kotlin_coroutines_version" diff --git a/matrix-sdk-android/build.gradle b/matrix-sdk-android/build.gradle index b28f69b839..96c9fdb1e6 100644 --- a/matrix-sdk-android/build.gradle +++ b/matrix-sdk-android/build.gradle @@ -120,7 +120,7 @@ dependencies { implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlin_coroutines_version" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines_version" - implementation "androidx.appcompat:appcompat:1.3.0" + implementation "androidx.appcompat:appcompat:1.3.1" implementation "androidx.core:core-ktx:1.6.0" implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version" diff --git a/multipicker/build.gradle b/multipicker/build.gradle index a8a46a86ba..04ce8a2aec 100644 --- a/multipicker/build.gradle +++ b/multipicker/build.gradle @@ -42,7 +42,7 @@ android { dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" - implementation 'androidx.appcompat:appcompat:1.3.0' + implementation 'androidx.appcompat:appcompat:1.3.1' implementation "androidx.fragment:fragment-ktx:1.3.6" implementation 'androidx.exifinterface:exifinterface:1.3.2' diff --git a/vector/build.gradle b/vector/build.gradle index 8d5125a323..05dbec0e6f 100644 --- a/vector/build.gradle +++ b/vector/build.gradle @@ -337,7 +337,7 @@ dependencies { implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines_version" implementation "androidx.recyclerview:recyclerview:1.2.1" - implementation 'androidx.appcompat:appcompat:1.3.0' + implementation 'androidx.appcompat:appcompat:1.3.1' implementation "androidx.fragment:fragment-ktx:$fragment_version" implementation 'androidx.constraintlayout:constraintlayout:2.0.4' implementation "androidx.sharetarget:sharetarget:1.1.0" From 79c8ef7ebf0c7e16cc34036631c9172b4db16885 Mon Sep 17 00:00:00 2001 From: ganfra Date: Thu, 22 Jul 2021 15:22:15 +0200 Subject: [PATCH 26/38] LoggerTag: try new thing and branch more on VOIP --- .../android/sdk/api/logger/LoggerTag.kt | 17 ++-- .../session/call/CallEventProcessor.kt | 4 +- .../session/call/CallSignalingHandler.kt | 21 ++--- .../call/DefaultCallSignalingService.kt | 2 - .../internal/session/call/model/MxCallImpl.kt | 23 +++--- .../vector/app/core/services/CallService.kt | 16 ++-- .../app/features/call/VectorCallActivity.kt | 19 +++-- .../call/audio/API21AudioDeviceDetector.kt | 21 ++--- .../call/webrtc/PeerConnectionObserver.kt | 27 ++++--- .../webrtc/PeerConnectionObserverAdapter.kt | 70 ---------------- .../app/features/call/webrtc/WebRtcCall.kt | 80 +++++++++---------- .../features/call/webrtc/WebRtcCallManager.kt | 50 ++++++------ 12 files changed, 148 insertions(+), 202 deletions(-) delete mode 100644 vector/src/main/java/im/vector/app/features/call/webrtc/PeerConnectionObserverAdapter.kt diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/logger/LoggerTag.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/logger/LoggerTag.kt index 074bd5cf6c..9978ae32aa 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/logger/LoggerTag.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/logger/LoggerTag.kt @@ -17,16 +17,21 @@ package org.matrix.android.sdk.api.logger /** - * Some tags used on Timber. + * Parent class for custom logger tags. Can be used with Timber : + * + * val loggerTag = LoggerTag("MyTag", LoggerTag.VOIP) + * Timber.tag(loggerTag.value).v("My log message") */ -open class LoggerTag(private val value: String, private val parentTag: LoggerTag? = null) { +open class LoggerTag(private val _value: String, private val parentTag: LoggerTag? = null) { object VOIP : LoggerTag("VOIP", null) - val computedValue: String + val value: String get() { - if (parentTag == null) return value - return "${parentTag.computedValue}/$value" + return if (parentTag == null) { + _value + } else { + "${parentTag.value}/$_value" + } } } - diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallEventProcessor.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallEventProcessor.kt index 0fb7ce5307..bdc254fc99 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallEventProcessor.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallEventProcessor.kt @@ -26,7 +26,7 @@ import org.matrix.android.sdk.internal.session.SessionScope import timber.log.Timber import javax.inject.Inject -private val CallEventProcessorTag = LoggerTag("CallEventProcessor", LoggerTag.VOIP) +private val loggerTag = LoggerTag("CallEventProcessor", LoggerTag.VOIP) @SessionScope internal class CallEventProcessor @Inject constructor(private val callSignalingHandler: CallSignalingHandler) @@ -75,7 +75,7 @@ internal class CallEventProcessor @Inject constructor(private val callSignalingH private fun dispatchToCallSignalingHandlerIfNeeded(event: Event) { event.roomId ?: return Unit.also { - Timber.tag(CallEventProcessorTag.computedValue).w("Event with no room id ${event.eventId}") + Timber.tag(loggerTag.value).w("Event with no room id ${event.eventId}") } callSignalingHandler.onCallEvent(event) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallSignalingHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallSignalingHandler.kt index 18abfef5f8..17e9aa9b7f 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallSignalingHandler.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallSignalingHandler.kt @@ -16,6 +16,7 @@ package org.matrix.android.sdk.internal.session.call +import org.matrix.android.sdk.api.logger.LoggerTag import org.matrix.android.sdk.api.session.call.CallListener import org.matrix.android.sdk.api.session.call.CallState import org.matrix.android.sdk.api.session.call.MxCall @@ -32,12 +33,11 @@ import org.matrix.android.sdk.api.session.room.model.call.CallRejectContent import org.matrix.android.sdk.api.session.room.model.call.CallSelectAnswerContent import org.matrix.android.sdk.api.session.room.model.call.CallSignalingContent import org.matrix.android.sdk.internal.di.UserId -import org.matrix.android.sdk.api.logger.LoggerTag import org.matrix.android.sdk.internal.session.SessionScope import timber.log.Timber import javax.inject.Inject -private val CallSignalingHandlerTag = LoggerTag("CallSignalingHandler", LoggerTag.VOIP) +private val loggerTag = LoggerTag("CallSignalingHandler", LoggerTag.VOIP) @SessionScope internal class CallSignalingHandler @Inject constructor(private val activeCallHandler: ActiveCallHandler, @@ -114,12 +114,12 @@ internal class CallSignalingHandler @Inject constructor(private val activeCallHa return } if (call.isOutgoing) { - Timber.tag(CallSignalingHandlerTag.computedValue).v("Got selectAnswer for an outbound call: ignoring") + Timber.tag(loggerTag.value).v("Got selectAnswer for an outbound call: ignoring") return } val selectedPartyId = content.selectedPartyId if (selectedPartyId == null) { - Timber.tag(CallSignalingHandlerTag.computedValue).w("Got nonsensical select_answer with null selected_party_id: ignoring") + Timber.tag(loggerTag.value).w("Got nonsensical select_answer with null selected_party_id: ignoring") return } callListenersDispatcher.onCallSelectAnswerReceived(content) @@ -133,7 +133,7 @@ internal class CallSignalingHandler @Inject constructor(private val activeCallHa return } if (call.opponentPartyId != null && !call.partyIdsMatches(content)) { - Timber.tag(CallSignalingHandlerTag.computedValue).v("Ignoring candidates from party ID ${content.partyId} we have chosen party ID ${call.opponentPartyId}") + Timber.tag(loggerTag.value).v("Ignoring candidates from party ID ${content.partyId} we have chosen party ID ${call.opponentPartyId}") return } callListenersDispatcher.onCallIceCandidateReceived(call, content) @@ -166,7 +166,7 @@ internal class CallSignalingHandler @Inject constructor(private val activeCallHa // party ID must match (our chosen partner hanging up the call) or be undefined (we haven't chosen // a partner yet but we're treating the hangup as a reject as per VoIP v0) if (call.opponentPartyId != null && !call.partyIdsMatches(content)) { - Timber.tag(CallSignalingHandlerTag.computedValue).v("Ignoring hangup from party ID ${content.partyId} we have chosen party ID ${call.opponentPartyId}") + Timber.tag(loggerTag.value).v("Ignoring hangup from party ID ${content.partyId} we have chosen party ID ${call.opponentPartyId}") return } if (call.state != CallState.Terminated) { @@ -186,7 +186,7 @@ internal class CallSignalingHandler @Inject constructor(private val activeCallHa val now = System.currentTimeMillis() val age = now - (event.ageLocalTs ?: now) if (age > 40_000 && event.getClearType() == EventType.CALL_INVITE) { - Timber.tag(CallSignalingHandlerTag.computedValue).w("Call invite is too old to ring.") + Timber.tag(loggerTag.value).w("Call invite is too old to ring.") return } val content = event.getClearContent().toModel() ?: return @@ -194,7 +194,7 @@ internal class CallSignalingHandler @Inject constructor(private val activeCallHa content.callId ?: return if (invitedCallIds.contains(content.callId)) { // Call is already known, maybe due to fast lane. Ignore - Timber.tag(CallSignalingHandlerTag.computedValue).d("Ignoring already known call invite") + Timber.tag(loggerTag.value).d("Ignoring already known call invite") return } val incomingCall = mxCallFactory.createIncomingCall( @@ -223,7 +223,8 @@ internal class CallSignalingHandler @Inject constructor(private val activeCallHa callListenersDispatcher.onCallManagedByOtherSession(content.callId) } else { if (call.opponentPartyId != null) { - Timber.tag(CallSignalingHandlerTag.computedValue).v("Ignoring answer from party ID ${content.partyId} we already have an answer from ${call.opponentPartyId}") + Timber.tag(loggerTag.value) + .v("Ignoring answer from party ID ${content.partyId} we already have an answer from ${call.opponentPartyId}") return } mxCallFactory.updateOutgoingCallWithOpponentData(call, event.senderId, content, content.capabilities) @@ -240,7 +241,7 @@ internal class CallSignalingHandler @Inject constructor(private val activeCallHa activeCallHandler.getCallWithId(it) } if (currentCall == null) { - Timber.tag(CallSignalingHandlerTag.computedValue).v("Call with id $callId is null") + Timber.tag(loggerTag.value).v("Call with id $callId is null") } return currentCall } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/DefaultCallSignalingService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/DefaultCallSignalingService.kt index da1f84cc89..4a949e21a6 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/DefaultCallSignalingService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/DefaultCallSignalingService.kt @@ -21,7 +21,6 @@ import org.matrix.android.sdk.api.session.call.CallSignalingService import org.matrix.android.sdk.api.session.call.MxCall import org.matrix.android.sdk.api.session.call.TurnServerResponse import org.matrix.android.sdk.internal.session.SessionScope -import timber.log.Timber import javax.inject.Inject @SessionScope @@ -51,7 +50,6 @@ internal class DefaultCallSignalingService @Inject constructor( } override fun getCallWithId(callId: String): MxCall? { - Timber.v("## VOIP getCallWithId $callId all calls ${activeCallHandler.getActiveCallsLiveData().value?.map { it.callId }}") return activeCallHandler.getCallWithId(callId) } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/model/MxCallImpl.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/model/MxCallImpl.kt index f101685a4b..1d831afcae 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/model/MxCallImpl.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/model/MxCallImpl.kt @@ -17,6 +17,7 @@ package org.matrix.android.sdk.internal.session.call.model import org.matrix.android.sdk.api.MatrixConfiguration +import org.matrix.android.sdk.api.logger.LoggerTag import org.matrix.android.sdk.api.session.call.CallIdGenerator import org.matrix.android.sdk.api.session.call.CallState import org.matrix.android.sdk.api.session.call.MxCall @@ -47,6 +48,8 @@ import org.matrix.android.sdk.internal.session.room.send.queue.EventSenderProces import timber.log.Timber import java.math.BigDecimal +private val loggerTag = LoggerTag("MxCallImpl", LoggerTag.VOIP) + internal class MxCallImpl( override val callId: String, override val isOutgoing: Boolean, @@ -93,7 +96,7 @@ internal class MxCallImpl( try { it.onStateUpdate(this) } catch (failure: Throwable) { - Timber.d("dispatchStateChange failed for call $callId : ${failure.localizedMessage}") + Timber.tag(loggerTag.value).d("dispatchStateChange failed for call $callId : ${failure.localizedMessage}") } } } @@ -109,7 +112,7 @@ internal class MxCallImpl( override fun offerSdp(sdpString: String) { if (!isOutgoing) return - Timber.v("## VOIP offerSdp $callId") + Timber.tag(loggerTag.value).v("offerSdp $callId") state = CallState.Dialing CallInviteContent( callId = callId, @@ -124,7 +127,7 @@ internal class MxCallImpl( } override fun sendLocalCallCandidates(candidates: List) { - Timber.v("Send local call canditates $callId: $candidates") + Timber.tag(loggerTag.value).v("Send local call canditates $callId: $candidates") CallCandidatesContent( callId = callId, partyId = ourPartyId, @@ -141,11 +144,11 @@ internal class MxCallImpl( override fun reject() { if (opponentVersion < 1) { - Timber.v("Opponent version is less than 1 ($opponentVersion): sending hangup instead of reject") + Timber.tag(loggerTag.value).v("Opponent version is less than 1 ($opponentVersion): sending hangup instead of reject") hangUp() return } - Timber.v("## VOIP reject $callId") + Timber.tag(loggerTag.value).v("reject $callId") CallRejectContent( callId = callId, partyId = ourPartyId, @@ -157,7 +160,7 @@ internal class MxCallImpl( } override fun hangUp(reason: CallHangupContent.Reason?) { - Timber.v("## VOIP hangup $callId") + Timber.tag(loggerTag.value).v("hangup $callId") CallHangupContent( callId = callId, partyId = ourPartyId, @@ -170,7 +173,7 @@ internal class MxCallImpl( } override fun accept(sdpString: String) { - Timber.v("## VOIP accept $callId") + Timber.tag(loggerTag.value).v("accept $callId") if (isOutgoing) return state = CallState.Answering CallAnswerContent( @@ -185,7 +188,7 @@ internal class MxCallImpl( } override fun negotiate(sdpString: String, type: SdpType) { - Timber.v("## VOIP negotiate $callId") + Timber.tag(loggerTag.value).v("negotiate $callId") CallNegotiateContent( callId = callId, partyId = ourPartyId, @@ -198,7 +201,7 @@ internal class MxCallImpl( } override fun selectAnswer() { - Timber.v("## VOIP select answer $callId") + Timber.tag(loggerTag.value).v("select answer $callId") if (isOutgoing) return state = CallState.Answering CallSelectAnswerContent( @@ -219,7 +222,7 @@ internal class MxCallImpl( val profileInfo = try { getProfileInfoTask.execute(profileInfoParams) } catch (failure: Throwable) { - Timber.v("Fail fetching profile info of $targetUserId while transferring call") + Timber.tag(loggerTag.value).v("Fail fetching profile info of $targetUserId while transferring call") null } CallReplacesContent( diff --git a/vector/src/main/java/im/vector/app/core/services/CallService.kt b/vector/src/main/java/im/vector/app/core/services/CallService.kt index d83c3e47f5..23a57e459e 100644 --- a/vector/src/main/java/im/vector/app/core/services/CallService.kt +++ b/vector/src/main/java/im/vector/app/core/services/CallService.kt @@ -41,7 +41,7 @@ import org.matrix.android.sdk.api.logger.LoggerTag import org.matrix.android.sdk.api.util.MatrixItem import timber.log.Timber -private val CallServiceTag = LoggerTag("CallService", LoggerTag.VOIP) +private val loggerTag = LoggerTag("CallService", LoggerTag.VOIP) /** * Foreground service to manage calls @@ -94,7 +94,7 @@ class CallService : VectorService() { } override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { - Timber.tag(CallServiceTag.computedValue).v("onStartCommand $intent") + Timber.tag(loggerTag.value).v("onStartCommand $intent") if (mediaSession == null) { mediaSession = MediaSessionCompat(applicationContext, CallService::class.java.name).apply { setCallback(mediaSessionButtonCallback) @@ -151,7 +151,7 @@ class CallService : VectorService() { * */ private fun displayIncomingCallNotification(intent: Intent) { - Timber.tag(CallServiceTag.computedValue).v("displayIncomingCallNotification $intent") + Timber.tag(loggerTag.value).v("displayIncomingCallNotification $intent") val callId = intent.getStringExtra(EXTRA_CALL_ID) ?: "" val call = callManager.getCallById(callId) ?: return Unit.also { handleUnexpectedState(callId) @@ -159,7 +159,7 @@ class CallService : VectorService() { val isVideoCall = call.mxCall.isVideoCall val fromBg = intent.getBooleanExtra(EXTRA_IS_IN_BG, false) val opponentMatrixItem = getOpponentMatrixItem(call) - Timber.tag(CallServiceTag.computedValue).v("displayIncomingCallNotification : display the dedicated notification") + Timber.tag(loggerTag.value).v("displayIncomingCallNotification : display the dedicated notification") val incomingCallAlert = IncomingCallAlert(callId, shouldBeDisplayedIn = { activity -> if (activity is VectorCallActivity) { @@ -195,7 +195,7 @@ class CallService : VectorService() { val callId = intent.getStringExtra(EXTRA_CALL_ID) ?: "" alertManager.cancelAlert(callId) if (!knownCalls.remove(callId)) { - Timber.tag(CallServiceTag.computedValue).v("Call terminated for unknown call $callId$") + Timber.tag(loggerTag.value).v("Call terminated for unknown call $callId$") handleUnexpectedState(callId) return } @@ -222,7 +222,7 @@ class CallService : VectorService() { handleUnexpectedState(callId) } val opponentMatrixItem = getOpponentMatrixItem(call) - Timber.tag(CallServiceTag.computedValue).v("displayOutgoingCallNotification : display the dedicated notification") + Timber.tag(loggerTag.value).v("displayOutgoingCallNotification : display the dedicated notification") val notification = notificationUtils.buildOutgoingRingingCallNotification( call = call, title = opponentMatrixItem?.getBestName() ?: call.mxCall.opponentUserId @@ -239,7 +239,7 @@ class CallService : VectorService() { * Display a call in progress notification. */ private fun displayCallInProgressNotification(intent: Intent) { - Timber.tag(CallServiceTag.computedValue).v("displayCallInProgressNotification") + Timber.tag(loggerTag.value).v("displayCallInProgressNotification") val callId = intent.getStringExtra(EXTRA_CALL_ID) ?: "" val call = callManager.getCallById(callId) ?: return Unit.also { handleUnexpectedState(callId) @@ -259,7 +259,7 @@ class CallService : VectorService() { } private fun handleUnexpectedState(callId: String?) { - Timber.tag(CallServiceTag.computedValue).v("Fallback to clear everything") + Timber.tag(loggerTag.value).v("Fallback to clear everything") callRingPlayerIncoming?.stop() callRingPlayerOutgoing?.stop() if (callId != null) { diff --git a/vector/src/main/java/im/vector/app/features/call/VectorCallActivity.kt b/vector/src/main/java/im/vector/app/features/call/VectorCallActivity.kt index 7e84811102..7a22ac3b8e 100644 --- a/vector/src/main/java/im/vector/app/features/call/VectorCallActivity.kt +++ b/vector/src/main/java/im/vector/app/features/call/VectorCallActivity.kt @@ -54,6 +54,7 @@ import im.vector.app.features.home.room.detail.RoomDetailArgs import io.reactivex.android.schedulers.AndroidSchedulers import kotlinx.parcelize.Parcelize import org.matrix.android.sdk.api.extensions.orFalse +import org.matrix.android.sdk.api.logger.LoggerTag import org.matrix.android.sdk.api.session.call.CallState import org.matrix.android.sdk.api.session.call.MxPeerConnectionState import org.matrix.android.sdk.api.session.call.TurnServerResponse @@ -71,6 +72,8 @@ data class CallArgs( val isVideoCall: Boolean ) : Parcelable +private val loggerTag = LoggerTag("VectorCallActivity", LoggerTag.VOIP) + class VectorCallActivity : VectorBaseActivity(), CallControlsView.InteractionListener { override fun getBinding() = ActivityCallBinding.inflate(layoutInflater) @@ -113,11 +116,11 @@ class VectorCallActivity : VectorBaseActivity(), CallContro if (intent.hasExtra(MvRx.KEY_ARG)) { callArgs = intent.getParcelableExtra(MvRx.KEY_ARG)!! } else { - Timber.e("## VOIP missing callArgs for VectorCall Activity") + Timber.tag(loggerTag.value).e("missing callArgs for VectorCall Activity") finish() } - Timber.v("## VOIP EXTRA_MODE is ${intent.getStringExtra(EXTRA_MODE)}") + Timber.tag(loggerTag.value).v("EXTRA_MODE is ${intent.getStringExtra(EXTRA_MODE)}") if (intent.getStringExtra(EXTRA_MODE) == INCOMING_RINGING) { turnScreenOnAndKeyguardOff() } @@ -160,7 +163,7 @@ class VectorCallActivity : VectorBaseActivity(), CallContro } private fun renderState(state: VectorCallViewState) { - Timber.v("## VOIP renderState call $state") + Timber.tag(loggerTag.value).v("renderState call $state") if (state.callState is Fail) { finish() return @@ -309,7 +312,7 @@ class VectorCallActivity : VectorBaseActivity(), CallContro private fun start() { rootEglBase = EglUtils.rootEglBase ?: return Unit.also { - Timber.v("## VOIP rootEglBase is null") + Timber.tag(loggerTag.value).v("rootEglBase is null") finish() } @@ -335,7 +338,7 @@ class VectorCallActivity : VectorBaseActivity(), CallContro } private fun handleViewEvents(event: VectorCallViewEvents?) { - Timber.v("## VOIP handleViewEvents $event") + Timber.tag(loggerTag.value).v("handleViewEvents $event") when (event) { VectorCallViewEvents.DismissNoCall -> { finish() @@ -357,7 +360,7 @@ class VectorCallActivity : VectorBaseActivity(), CallContro } private fun onErrorTimoutConnect(turn: TurnServerResponse?) { - Timber.d("## VOIP onErrorTimoutConnect $turn") + Timber.tag(loggerTag.value).d("onErrorTimoutConnect $turn") // TODO ask to use default stun, etc... MaterialAlertDialogBuilder(this) .setTitle(R.string.call_failed_no_connection) @@ -437,7 +440,7 @@ class VectorCallActivity : VectorBaseActivity(), CallContro // Needed to let you answer call when phone is locked private fun turnScreenOnAndKeyguardOff() { - Timber.v("## VOIP turnScreenOnAndKeyguardOff") + Timber.tag(loggerTag.value).v("turnScreenOnAndKeyguardOff") if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) { setShowWhenLocked(true) setTurnScreenOn(true) @@ -458,7 +461,7 @@ class VectorCallActivity : VectorBaseActivity(), CallContro } private fun turnScreenOffAndKeyguardOn() { - Timber.v("## VOIP turnScreenOnAndKeyguardOn") + Timber.tag(loggerTag.value).v("turnScreenOnAndKeyguardOn") if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) { setShowWhenLocked(false) setTurnScreenOn(false) diff --git a/vector/src/main/java/im/vector/app/features/call/audio/API21AudioDeviceDetector.kt b/vector/src/main/java/im/vector/app/features/call/audio/API21AudioDeviceDetector.kt index 32b243aa2b..4f54f703b4 100644 --- a/vector/src/main/java/im/vector/app/features/call/audio/API21AudioDeviceDetector.kt +++ b/vector/src/main/java/im/vector/app/features/call/audio/API21AudioDeviceDetector.kt @@ -25,9 +25,12 @@ import android.media.AudioManager import androidx.core.content.getSystemService import im.vector.app.core.services.BluetoothHeadsetReceiver import im.vector.app.core.services.WiredHeadsetStateReceiver +import org.matrix.android.sdk.api.logger.LoggerTag import timber.log.Timber import java.util.HashSet +private val loggerTag = LoggerTag("API21AudioDeviceDetector", LoggerTag.VOIP) + internal class API21AudioDeviceDetector(private val context: Context, private val audioManager: AudioManager, private val callAudioManager: CallAudioManager @@ -62,17 +65,17 @@ internal class API21AudioDeviceDetector(private val context: Context, } private fun isBluetoothHeadsetOn(): Boolean { - Timber.v("## VOIP: AudioManager isBluetoothHeadsetOn") + Timber.tag(loggerTag.value).v("AudioManager isBluetoothHeadsetOn") try { if (connectedBlueToothHeadset == null) return false.also { - Timber.v("## VOIP: AudioManager no connected bluetooth headset") + Timber.tag(loggerTag.value).v("AudioManager no connected bluetooth headset") } if (!audioManager.isBluetoothScoAvailableOffCall) return false.also { - Timber.v("## VOIP: AudioManager isBluetoothScoAvailableOffCall false") + Timber.tag(loggerTag.value).v("AudioManager isBluetoothScoAvailableOffCall false") } return true } catch (failure: Throwable) { - Timber.e("## VOIP: AudioManager isBluetoothHeadsetOn failure ${failure.localizedMessage}") + Timber.e("AudioManager isBluetoothHeadsetOn failure ${failure.localizedMessage}") return false } } @@ -91,11 +94,11 @@ internal class API21AudioDeviceDetector(private val context: Context, bluetoothHeadsetStateReceiver = BluetoothHeadsetReceiver.createAndRegister(context, this) val bm: BluetoothManager? = context.getSystemService() val adapter = bm?.adapter - Timber.d("## VOIP Bluetooth adapter $adapter") + Timber.tag(loggerTag.value).d("Bluetooth adapter $adapter") bluetoothAdapter = adapter adapter?.getProfileProxy(context, object : BluetoothProfile.ServiceListener { override fun onServiceDisconnected(profile: Int) { - Timber.d("## VOIP onServiceDisconnected $profile") + Timber.tag(loggerTag.value).d("onServiceDisconnected $profile") if (profile == BluetoothProfile.HEADSET) { connectedBlueToothHeadset = null onAudioDeviceChange() @@ -103,7 +106,7 @@ internal class API21AudioDeviceDetector(private val context: Context, } override fun onServiceConnected(profile: Int, proxy: BluetoothProfile?) { - Timber.d("## VOIP onServiceConnected $profile , proxy:$proxy") + Timber.tag(loggerTag.value).d("onServiceConnected $profile , proxy:$proxy") if (profile == BluetoothProfile.HEADSET) { connectedBlueToothHeadset = proxy onAudioDeviceChange() @@ -122,12 +125,12 @@ internal class API21AudioDeviceDetector(private val context: Context, } override fun onHeadsetEvent(event: WiredHeadsetStateReceiver.HeadsetPlugEvent) { - Timber.v("onHeadsetEvent $event") + Timber.tag(loggerTag.value).v("onHeadsetEvent $event") onAudioDeviceChange() } override fun onBTHeadsetEvent(event: BluetoothHeadsetReceiver.BTHeadsetPlugEvent) { - Timber.v("onBTHeadsetEvent $event") + Timber.tag(loggerTag.value).v("onBTHeadsetEvent $event") onAudioDeviceChange() } } diff --git a/vector/src/main/java/im/vector/app/features/call/webrtc/PeerConnectionObserver.kt b/vector/src/main/java/im/vector/app/features/call/webrtc/PeerConnectionObserver.kt index f14bb2f849..99c26c5ebe 100644 --- a/vector/src/main/java/im/vector/app/features/call/webrtc/PeerConnectionObserver.kt +++ b/vector/src/main/java/im/vector/app/features/call/webrtc/PeerConnectionObserver.kt @@ -16,6 +16,7 @@ package im.vector.app.features.call.webrtc +import org.matrix.android.sdk.api.logger.LoggerTag import org.matrix.android.sdk.api.session.call.CallState import org.matrix.android.sdk.api.session.call.MxPeerConnectionState import org.webrtc.DataChannel @@ -25,10 +26,12 @@ import org.webrtc.PeerConnection import org.webrtc.RtpReceiver import timber.log.Timber +private val loggerTag = LoggerTag("PeerConnectionObserver", LoggerTag.VOIP) + class PeerConnectionObserver(private val webRtcCall: WebRtcCall) : PeerConnection.Observer { override fun onConnectionChange(newState: PeerConnection.PeerConnectionState?) { - Timber.v("## VOIP StreamObserver onConnectionChange: $newState") + Timber.tag(loggerTag.value).v("StreamObserver onConnectionChange: $newState") when (newState) { /** * Every ICE transport used by the connection is either in use (state "connected" or "completed") @@ -79,20 +82,20 @@ class PeerConnectionObserver(private val webRtcCall: WebRtcCall) : PeerConnectio } override fun onIceCandidate(iceCandidate: IceCandidate) { - Timber.v("## VOIP StreamObserver onIceCandidate: $iceCandidate") + Timber.tag(loggerTag.value).v("StreamObserver onIceCandidate: $iceCandidate") webRtcCall.onIceCandidate(iceCandidate) } override fun onDataChannel(dc: DataChannel) { - Timber.v("## VOIP StreamObserver onDataChannel: ${dc.state()}") + Timber.tag(loggerTag.value).v("StreamObserver onDataChannel: ${dc.state()}") } override fun onIceConnectionReceivingChange(receiving: Boolean) { - Timber.v("## VOIP StreamObserver onIceConnectionReceivingChange: $receiving") + Timber.tag(loggerTag.value).v("StreamObserver onIceConnectionReceivingChange: $receiving") } override fun onIceConnectionChange(newState: PeerConnection.IceConnectionState) { - Timber.v("## VOIP StreamObserver onIceConnectionChange IceConnectionState:$newState") + Timber.tag(loggerTag.value).v("StreamObserver onIceConnectionChange IceConnectionState:$newState") when (newState) { /** * the ICE agent is gathering addresses or is waiting to be given remote candidates through @@ -145,29 +148,29 @@ class PeerConnectionObserver(private val webRtcCall: WebRtcCall) : PeerConnectio } override fun onAddStream(stream: MediaStream) { - Timber.v("## VOIP StreamObserver onAddStream: $stream") + Timber.tag(loggerTag.value).v("StreamObserver onAddStream: $stream") webRtcCall.onAddStream(stream) } override fun onRemoveStream(stream: MediaStream) { - Timber.v("## VOIP StreamObserver onRemoveStream") + Timber.tag(loggerTag.value).v("StreamObserver onRemoveStream") webRtcCall.onRemoveStream() } override fun onIceGatheringChange(newState: PeerConnection.IceGatheringState) { - Timber.v("## VOIP StreamObserver onIceGatheringChange: $newState") + Timber.tag(loggerTag.value).v("StreamObserver onIceGatheringChange: $newState") } override fun onSignalingChange(newState: PeerConnection.SignalingState) { - Timber.v("## VOIP StreamObserver onSignalingChange: $newState") + Timber.tag(loggerTag.value).v("StreamObserver onSignalingChange: $newState") } override fun onIceCandidatesRemoved(candidates: Array) { - Timber.v("## VOIP StreamObserver onIceCandidatesRemoved: ${candidates.contentToString()}") + Timber.tag(loggerTag.value).v("StreamObserver onIceCandidatesRemoved: ${candidates.contentToString()}") } override fun onRenegotiationNeeded() { - Timber.v("## VOIP StreamObserver onRenegotiationNeeded") + Timber.tag(loggerTag.value).v("StreamObserver onRenegotiationNeeded") webRtcCall.onRenegotiationNeeded(restartIce = false) } @@ -178,6 +181,6 @@ class PeerConnectionObserver(private val webRtcCall: WebRtcCall) : PeerConnectio * gets a new set of tracks because the media element being captured loaded a new source. */ override fun onAddTrack(p0: RtpReceiver?, p1: Array?) { - Timber.v("## VOIP StreamObserver onAddTrack") + Timber.tag(loggerTag.value).v("StreamObserver onAddTrack") } } diff --git a/vector/src/main/java/im/vector/app/features/call/webrtc/PeerConnectionObserverAdapter.kt b/vector/src/main/java/im/vector/app/features/call/webrtc/PeerConnectionObserverAdapter.kt deleted file mode 100644 index 3d31f0e705..0000000000 --- a/vector/src/main/java/im/vector/app/features/call/webrtc/PeerConnectionObserverAdapter.kt +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2020 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.call.webrtc - -import org.webrtc.DataChannel -import org.webrtc.IceCandidate -import org.webrtc.MediaStream -import org.webrtc.PeerConnection -import org.webrtc.RtpReceiver -import timber.log.Timber - -abstract class PeerConnectionObserverAdapter : PeerConnection.Observer { - override fun onIceCandidate(p0: IceCandidate?) { - Timber.v("## VOIP onIceCandidate $p0") - } - - override fun onDataChannel(p0: DataChannel?) { - Timber.v("## VOIP onDataChannel $p0") - } - - override fun onIceConnectionReceivingChange(p0: Boolean) { - Timber.v("## VOIP onIceConnectionReceivingChange $p0") - } - - override fun onIceConnectionChange(p0: PeerConnection.IceConnectionState?) { - Timber.v("## VOIP onIceConnectionChange $p0") - } - - override fun onIceGatheringChange(p0: PeerConnection.IceGatheringState?) { - Timber.v("## VOIP onIceConnectionChange $p0") - } - - override fun onAddStream(mediaStream: MediaStream?) { - Timber.v("## VOIP onAddStream $mediaStream") - } - - override fun onSignalingChange(p0: PeerConnection.SignalingState?) { - Timber.v("## VOIP onSignalingChange $p0") - } - - override fun onIceCandidatesRemoved(p0: Array?) { - Timber.v("## VOIP onIceCandidatesRemoved $p0") - } - - override fun onRemoveStream(mediaStream: MediaStream?) { - Timber.v("## VOIP onRemoveStream $mediaStream") - } - - override fun onRenegotiationNeeded() { - Timber.v("## VOIP onRenegotiationNeeded") - } - - override fun onAddTrack(p0: RtpReceiver?, p1: Array?) { - Timber.v("## VOIP onAddTrack $p0 / out: $p1") - } -} diff --git a/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCall.kt b/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCall.kt index 9bcd442be6..6c55b9380d 100644 --- a/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCall.kt +++ b/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCall.kt @@ -89,7 +89,7 @@ private const val AUDIO_TRACK_ID = "${STREAM_ID}a0" private const val VIDEO_TRACK_ID = "${STREAM_ID}v0" private val DEFAULT_AUDIO_CONSTRAINTS = MediaConstraints() -private val WebRtcCallTag = LoggerTag("WebRtcCall", LoggerTag.VOIP) +private val loggerTag = LoggerTag("WebRtcCall", LoggerTag.VOIP) class WebRtcCall( val mxCall: MxCall, @@ -195,7 +195,7 @@ class WebRtcCall( .subscribe { // omit empty :/ if (it.isNotEmpty()) { - Timber.tag(WebRtcCallTag.computedValue).v("Sending local ice candidates to call") + Timber.tag(loggerTag.value).v("Sending local ice candidates to call") // it.forEach { peerConnection?.addIceCandidate(it) } mxCall.sendLocalCallCandidates(it.mapToCallCandidate()) } @@ -213,7 +213,7 @@ class WebRtcCall( fun onRenegotiationNeeded(restartIce: Boolean) { sessionScope?.launch(dispatcher) { if (mxCall.state != CallState.CreateOffer && mxCall.opponentVersion == 0) { - Timber.tag(WebRtcCallTag.computedValue).v("Opponent does not support renegotiation: ignoring onRenegotiationNeeded event") + Timber.tag(loggerTag.value).v("Opponent does not support renegotiation: ignoring onRenegotiationNeeded event") return@launch } val constraints = MediaConstraints() @@ -221,7 +221,7 @@ class WebRtcCall( constraints.mandatory.add(MediaConstraints.KeyValuePair("IceRestart", "true")) } val peerConnection = peerConnection ?: return@launch - Timber.tag(WebRtcCallTag.computedValue).v("creating offer...") + Timber.tag(loggerTag.value).v("creating offer...") makingOffer = true try { val sessionDescription = peerConnection.awaitCreateOffer(constraints) ?: return@launch @@ -241,7 +241,7 @@ class WebRtcCall( } } catch (failure: Throwable) { // Need to handle error properly. - Timber.tag(WebRtcCallTag.computedValue).v("Failure while creating offer") + Timber.tag(loggerTag.value).v("Failure while creating offer") } finally { makingOffer = false } @@ -270,7 +270,7 @@ class WebRtcCall( } } } - Timber.tag(WebRtcCallTag.computedValue).v("creating peer connection...with iceServers $iceServers ") + Timber.tag(loggerTag.value).v("creating peer connection...with iceServers $iceServers ") val rtcConfig = PeerConnection.RTCConfiguration(iceServers).apply { sdpSemantics = PeerConnection.SdpSemantics.UNIFIED_PLAN } @@ -317,7 +317,7 @@ class WebRtcCall( fun acceptIncomingCall() { sessionScope?.launch { - Timber.tag(WebRtcCallTag.computedValue).v("acceptIncomingCall from state ${mxCall.state}") + Timber.tag(loggerTag.value).v("acceptIncomingCall from state ${mxCall.state}") if (mxCall.state == CallState.LocalRinging) { internalAcceptIncomingCall() } @@ -336,7 +336,7 @@ class WebRtcCall( sender.dtmf()?.insertDtmf(digit, 100, 70) return@launch } catch (failure: Throwable) { - Timber.tag(WebRtcCallTag.computedValue).v("Fail to send Dtmf digit") + Timber.tag(loggerTag.value).v("Fail to send Dtmf digit") } } } @@ -345,7 +345,7 @@ class WebRtcCall( fun attachViewRenderers(localViewRenderer: SurfaceViewRenderer?, remoteViewRenderer: SurfaceViewRenderer, mode: String?) { sessionScope?.launch(dispatcher) { - Timber.tag(WebRtcCallTag.computedValue).v("attachViewRenderers localRendeder $localViewRenderer / $remoteViewRenderer") + Timber.tag(loggerTag.value).v("attachViewRenderers localRendeder $localViewRenderer / $remoteViewRenderer") localSurfaceRenderers.addIfNeeded(localViewRenderer) remoteSurfaceRenderers.addIfNeeded(remoteViewRenderer) when (mode) { @@ -392,7 +392,7 @@ class WebRtcCall( } private suspend fun detachRenderersInternal(renderers: List?) = withContext(dispatcher) { - Timber.tag(WebRtcCallTag.computedValue).v("detachRenderers") + Timber.tag(loggerTag.value).v("detachRenderers") if (renderers.isNullOrEmpty()) { // remove all sinks localSurfaceRenderers.forEach { @@ -425,12 +425,12 @@ class WebRtcCall( // 2. Access camera (if video call) + microphone, create local stream createLocalStream() attachViewRenderersInternal() - Timber.tag(WebRtcCallTag.computedValue).v("remoteCandidateSource $remoteCandidateSource") + Timber.tag(loggerTag.value).v("remoteCandidateSource $remoteCandidateSource") remoteIceCandidateDisposable = remoteCandidateSource.subscribe({ - Timber.tag(WebRtcCallTag.computedValue).v("adding remote ice candidate $it") + Timber.tag(loggerTag.value).v("adding remote ice candidate $it") peerConnection?.addIceCandidate(it) }, { - Timber.tag(WebRtcCallTag.computedValue).v("failed to add remote ice candidate $it") + Timber.tag(loggerTag.value).v("failed to add remote ice candidate $it") }) // Now we wait for negotiation callback } @@ -456,14 +456,14 @@ class WebRtcCall( SessionDescription(SessionDescription.Type.OFFER, it) } if (offerSdp == null) { - Timber.tag(WebRtcCallTag.computedValue).v("We don't have any offer to process") + Timber.tag(loggerTag.value).v("We don't have any offer to process") return@withContext } - Timber.tag(WebRtcCallTag.computedValue).v("Offer sdp for invite: ${offerSdp.description}") + Timber.tag(loggerTag.value).v("Offer sdp for invite: ${offerSdp.description}") try { peerConnection?.awaitSetRemoteDescription(offerSdp) } catch (failure: Throwable) { - Timber.tag(WebRtcCallTag.computedValue).v("Failure putting remote description") + Timber.tag(loggerTag.value).v("Failure putting remote description") endCall(true, CallHangupContent.Reason.UNKWOWN_ERROR) return@withContext } @@ -475,12 +475,12 @@ class WebRtcCall( createAnswer()?.also { mxCall.accept(it.description) } - Timber.tag(WebRtcCallTag.computedValue).v("remoteCandidateSource $remoteCandidateSource") + Timber.tag(loggerTag.value).v("remoteCandidateSource $remoteCandidateSource") remoteIceCandidateDisposable = remoteCandidateSource.subscribe({ - Timber.tag(WebRtcCallTag.computedValue).v("adding remote ice candidate $it") + Timber.tag(loggerTag.value).v("adding remote ice candidate $it") peerConnection?.addIceCandidate(it) }, { - Timber.tag(WebRtcCallTag.computedValue).v("failed to add remote ice candidate $it") + Timber.tag(loggerTag.value).v("failed to add remote ice candidate $it") }) } @@ -492,7 +492,7 @@ class WebRtcCall( private fun createLocalStream() { val peerConnectionFactory = peerConnectionFactoryProvider.get() ?: return - Timber.tag(WebRtcCallTag.computedValue).v("Create local stream for call ${mxCall.callId}") + Timber.tag(loggerTag.value).v("Create local stream for call ${mxCall.callId}") configureAudioTrack(peerConnectionFactory) // add video track if needed if (mxCall.isVideoCall) { @@ -505,7 +505,7 @@ class WebRtcCall( val audioSource = peerConnectionFactory.createAudioSource(DEFAULT_AUDIO_CONSTRAINTS) val audioTrack = peerConnectionFactory.createAudioTrack(AUDIO_TRACK_ID, audioSource) audioTrack.setEnabled(true) - Timber.tag(WebRtcCallTag.computedValue).v("Add audio track $AUDIO_TRACK_ID to call ${mxCall.callId}") + Timber.tag(loggerTag.value).v("Add audio track $AUDIO_TRACK_ID to call ${mxCall.callId}") peerConnection?.addTrack(audioTrack, listOf(STREAM_ID)) localAudioSource = audioSource localAudioTrack = audioTrack @@ -547,7 +547,7 @@ class WebRtcCall( override fun onCameraClosed() { super.onCameraClosed() - Timber.tag(WebRtcCallTag.computedValue).v("onCameraClosed") + Timber.tag(loggerTag.value).v("onCameraClosed") // This could happen if you open the camera app in chat // We then register in order to restart capture as soon as the camera is available again videoCapturerIsInError = true @@ -555,16 +555,16 @@ class WebRtcCall( cameraAvailabilityCallback = object : CameraManager.AvailabilityCallback() { override fun onCameraUnavailable(cameraId: String) { super.onCameraUnavailable(cameraId) - Timber.tag(WebRtcCallTag.computedValue).v("On camera unavailable: $cameraId") + Timber.tag(loggerTag.value).v("On camera unavailable: $cameraId") } override fun onCameraAccessPrioritiesChanged() { super.onCameraAccessPrioritiesChanged() - Timber.tag(WebRtcCallTag.computedValue).v("onCameraAccessPrioritiesChanged") + Timber.tag(loggerTag.value).v("onCameraAccessPrioritiesChanged") } override fun onCameraAvailable(cameraId: String) { - Timber.tag(WebRtcCallTag.computedValue).v("On camera available: $cameraId") + Timber.tag(loggerTag.value).v("On camera available: $cameraId") if (cameraId == camera.name) { videoCapturer?.startCapture(currentCaptureFormat.width, currentCaptureFormat.height, currentCaptureFormat.fps) cameraManager?.unregisterAvailabilityCallback(this) @@ -577,7 +577,7 @@ class WebRtcCall( val videoSource = peerConnectionFactory.createVideoSource(videoCapturer.isScreencast) val surfaceTextureHelper = SurfaceTextureHelper.create("CaptureThread", rootEglBase!!.eglBaseContext) - Timber.tag(WebRtcCallTag.computedValue).v("Local video source created") + Timber.tag(loggerTag.value).v("Local video source created") videoCapturer.initialize(surfaceTextureHelper, context, videoSource.capturerObserver) // HD @@ -585,7 +585,7 @@ class WebRtcCall( this.videoCapturer = videoCapturer val videoTrack = peerConnectionFactory.createVideoTrack(VIDEO_TRACK_ID, videoSource) - Timber.tag(WebRtcCallTag.computedValue).v("Add video track $VIDEO_TRACK_ID to call ${mxCall.callId}") + Timber.tag(loggerTag.value).v("Add video track $VIDEO_TRACK_ID to call ${mxCall.callId}") videoTrack.setEnabled(true) peerConnection?.addTrack(videoTrack, listOf(STREAM_ID)) localVideoSource = videoSource @@ -595,7 +595,7 @@ class WebRtcCall( fun setCaptureFormat(format: CaptureFormat) { sessionScope?.launch(dispatcher) { - Timber.tag(WebRtcCallTag.computedValue).v("setCaptureFormat $format") + Timber.tag(loggerTag.value).v("setCaptureFormat $format") videoCapturer?.changeCaptureFormat(format.width, format.height, format.fps) currentCaptureFormat = format } @@ -689,14 +689,14 @@ class WebRtcCall( fun switchCamera() { sessionScope?.launch(dispatcher) { - Timber.tag(WebRtcCallTag.computedValue).v("switchCamera") + Timber.tag(loggerTag.value).v("switchCamera") if (mxCall.state is CallState.Connected && mxCall.isVideoCall) { val oppositeCamera = getOppositeCameraIfAny() ?: return@launch videoCapturer?.switchCamera( object : CameraVideoCapturer.CameraSwitchHandler { // Invoked on success. |isFrontCamera| is true if the new camera is front facing. override fun onCameraSwitchDone(isFrontCamera: Boolean) { - Timber.tag(WebRtcCallTag.computedValue).v("onCameraSwitchDone isFront $isFrontCamera") + Timber.tag(loggerTag.value).v("onCameraSwitchDone isFront $isFrontCamera") cameraInUse = oppositeCamera localSurfaceRenderers.forEach { it.get()?.setMirror(isFrontCamera) @@ -707,7 +707,7 @@ class WebRtcCall( } override fun onCameraSwitchError(errorDescription: String?) { - Timber.tag(WebRtcCallTag.computedValue).v("onCameraSwitchError isFront $errorDescription") + Timber.tag(loggerTag.value).v("onCameraSwitchError isFront $errorDescription") } }, oppositeCamera.name ) @@ -716,7 +716,7 @@ class WebRtcCall( } private suspend fun createAnswer(): SessionDescription? { - Timber.tag(WebRtcCallTag.computedValue).w("createAnswer") + Timber.tag(loggerTag.value).w("createAnswer") val peerConnection = peerConnection ?: return null val constraints = MediaConstraints().apply { mandatory.add(MediaConstraints.KeyValuePair("OfferToReceiveAudio", "true")) @@ -727,7 +727,7 @@ class WebRtcCall( peerConnection.awaitSetLocalDescription(localDescription) localDescription } catch (failure: Throwable) { - Timber.tag(WebRtcCallTag.computedValue).v("Fail to create answer") + Timber.tag(loggerTag.value).v("Fail to create answer") null } } @@ -768,7 +768,7 @@ class WebRtcCall( sessionScope?.launch(dispatcher) { // reportError("Weird-looking stream: " + stream); if (stream.audioTracks.size > 1 || stream.videoTracks.size > 1) { - Timber.tag(WebRtcCallTag.computedValue).e("## VOIP StreamObserver weird looking stream: $stream") + Timber.tag(loggerTag.value).e("StreamObserver weird looking stream: $stream") // TODO maybe do something more?? endCall(true) return@launch @@ -832,7 +832,7 @@ class WebRtcCall( if (it.sdpMid.isNullOrEmpty() || it.candidate.isNullOrEmpty()) { return@forEach } - Timber.tag(WebRtcCallTag.computedValue).v("onCallIceCandidateReceived for call ${mxCall.callId} sdp: ${it.candidate}") + Timber.tag(loggerTag.value).v("onCallIceCandidateReceived for call ${mxCall.callId} sdp: ${it.candidate}") val iceCandidate = IceCandidate(it.sdpMid, it.sdpMLineIndex, it.candidate) remoteCandidateSource.onNext(iceCandidate) } @@ -841,7 +841,7 @@ class WebRtcCall( fun onCallAnswerReceived(callAnswerContent: CallAnswerContent) { sessionScope?.launch(dispatcher) { - Timber.tag(WebRtcCallTag.computedValue).v("onCallAnswerReceived ${callAnswerContent.callId}") + Timber.tag(loggerTag.value).v("onCallAnswerReceived ${callAnswerContent.callId}") val sdp = SessionDescription(SessionDescription.Type.ANSWER, callAnswerContent.answer.sdp) try { peerConnection?.awaitSetRemoteDescription(sdp) @@ -861,7 +861,7 @@ class WebRtcCall( val type = description?.type val sdpText = description?.sdp if (type == null || sdpText == null) { - Timber.tag(WebRtcCallTag.computedValue).i("Ignoring invalid m.call.negotiate event") + Timber.tag(loggerTag.value).i("Ignoring invalid m.call.negotiate event") return@launch } val peerConnection = peerConnection ?: return@launch @@ -876,7 +876,7 @@ class WebRtcCall( ignoreOffer = !polite && offerCollision if (ignoreOffer) { - Timber.tag(WebRtcCallTag.computedValue).i("Ignoring colliding negotiate event because we're impolite") + Timber.tag(loggerTag.value).i("Ignoring colliding negotiate event because we're impolite") return@launch } val prevOnHold = computeIsLocalOnHold() @@ -889,7 +889,7 @@ class WebRtcCall( } } } catch (failure: Throwable) { - Timber.tag(WebRtcCallTag.computedValue).e(failure, "Failed to complete negotiation") + Timber.tag(loggerTag.value).e(failure, "Failed to complete negotiation") } val nowOnHold = computeIsLocalOnHold() wasLocalOnHold = nowOnHold @@ -912,7 +912,7 @@ class WebRtcCall( val session = sessionProvider.get() ?: return@launch val newAssertedIdentity = callAssertedIdentityContent.assertedIdentity ?: return@launch if (newAssertedIdentity.id == null && newAssertedIdentity.displayName == null) { - Timber.tag(WebRtcCallTag.computedValue).v("Asserted identity received with no relevant information, skip") + Timber.tag(loggerTag.value).v("Asserted identity received with no relevant information, skip") return@launch } remoteAssertedIdentity = newAssertedIdentity diff --git a/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCallManager.kt b/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCallManager.kt index 566ba7e81a..1d09d30de2 100644 --- a/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCallManager.kt +++ b/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCallManager.kt @@ -61,7 +61,7 @@ import javax.inject.Singleton * Manage peerConnectionFactory & Peer connections outside of activity lifecycle to resist configuration changes * Use app context */ -private val WebRtcCallManagerTag = LoggerTag("WebRtcCallManager", LoggerTag.VOIP) +private val loggerTag = LoggerTag("WebRtcCallManager", LoggerTag.VOIP) @Singleton class WebRtcCallManager @Inject constructor( @@ -187,7 +187,7 @@ class WebRtcCallManager @Inject constructor( fun getAdvertisedCalls() = advertisedCalls fun headSetButtonTapped() { - Timber.tag(WebRtcCallManagerTag.computedValue).v("headSetButtonTapped") + Timber.tag(loggerTag.value).v("headSetButtonTapped") val call = getCurrentCall() ?: return if (call.mxCall.state is CallState.LocalRinging) { call.acceptIncomingCall() @@ -200,12 +200,12 @@ class WebRtcCallManager @Inject constructor( private fun createPeerConnectionFactoryIfNeeded() { if (peerConnectionFactory != null) return - Timber.tag(WebRtcCallManagerTag.computedValue).v("createPeerConnectionFactory") + Timber.tag(loggerTag.value).v("createPeerConnectionFactory") val eglBaseContext = rootEglBase?.eglBaseContext ?: return Unit.also { - Timber.tag(WebRtcCallManagerTag.computedValue).e("No EGL BASE") + Timber.tag(loggerTag.value).e("No EGL BASE") } - Timber.tag(WebRtcCallManagerTag.computedValue).v("PeerConnectionFactory.initialize") + Timber.tag(loggerTag.value).v("PeerConnectionFactory.initialize") PeerConnectionFactory.initialize(PeerConnectionFactory .InitializationOptions.builder(context.applicationContext) .createInitializationOptions() @@ -219,7 +219,7 @@ class WebRtcCallManager @Inject constructor( /* enableH264HighProfile */ true) val defaultVideoDecoderFactory = DefaultVideoDecoderFactory(eglBaseContext) - Timber.tag(WebRtcCallManagerTag.computedValue).v("PeerConnectionFactory.createPeerConnectionFactory ...") + Timber.tag(loggerTag.value).v("PeerConnectionFactory.createPeerConnectionFactory ...") peerConnectionFactory = PeerConnectionFactory.builder() .setOptions(options) .setVideoEncoderFactory(defaultVideoEncoderFactory) @@ -228,7 +228,7 @@ class WebRtcCallManager @Inject constructor( } private fun onCallActive(call: WebRtcCall) { - Timber.tag(WebRtcCallManagerTag.computedValue).v("WebRtcPeerConnectionManager onCall active: ${call.mxCall.callId}") + Timber.tag(loggerTag.value).v("WebRtcPeerConnectionManager onCall active: ${call.mxCall.callId}") val currentCall = getCurrentCall().takeIf { it != call } currentCall?.updateRemoteOnHold(onHold = true) audioManager.setMode(if (call.mxCall.isVideoCall) CallAudioManager.Mode.VIDEO_CALL else CallAudioManager.Mode.AUDIO_CALL) @@ -236,9 +236,9 @@ class WebRtcCallManager @Inject constructor( } private fun onCallEnded(callId: String) { - Timber.tag(WebRtcCallManagerTag.computedValue).v("WebRtcPeerConnectionManager onCall ended: $callId") + Timber.tag(loggerTag.value).v("WebRtcPeerConnectionManager onCall ended: $callId") val webRtcCall = callsByCallId.remove(callId) ?: return Unit.also { - Timber.tag(WebRtcCallManagerTag.computedValue).v("On call ended for unknown call $callId") + Timber.tag(loggerTag.value).v("On call ended for unknown call $callId") } CallService.onCallTerminated(context, callId) callsByRoomId[webRtcCall.signalingRoomId]?.remove(webRtcCall) @@ -250,7 +250,7 @@ class WebRtcCallManager @Inject constructor( } // There is no active calls if (getCurrentCall() == null) { - Timber.tag(WebRtcCallManagerTag.computedValue).v("Dispose peerConnectionFactory as there is no need to keep one") + Timber.tag(loggerTag.value).v("Dispose peerConnectionFactory as there is no need to keep one") peerConnectionFactory?.dispose() peerConnectionFactory = null audioManager.setMode(CallAudioManager.Mode.DEFAULT) @@ -268,13 +268,13 @@ class WebRtcCallManager @Inject constructor( suspend fun startOutgoingCall(nativeRoomId: String, otherUserId: String, isVideoCall: Boolean, transferee: WebRtcCall? = null) { val signalingRoomId = callUserMapper?.getOrCreateVirtualRoomForRoom(nativeRoomId, otherUserId) ?: nativeRoomId - Timber.tag(WebRtcCallManagerTag.computedValue).v("startOutgoingCall in room $signalingRoomId to $otherUserId isVideo $isVideoCall") + Timber.tag(loggerTag.value).v("startOutgoingCall in room $signalingRoomId to $otherUserId isVideo $isVideoCall") if (getCallsByRoomId(nativeRoomId).isNotEmpty()) { - Timber.tag(WebRtcCallManagerTag.computedValue).w("you already have a call in this room") + Timber.tag(loggerTag.value).w("you already have a call in this room") return } if (getCurrentCall() != null && getCurrentCall()?.mxCall?.state !is CallState.Connected || getCalls().size >= 2) { - Timber.tag(WebRtcCallManagerTag.computedValue).w("cannot start outgoing call") + Timber.tag(loggerTag.value).w("cannot start outgoing call") // Just ignore, maybe we could answer from other session? return } @@ -297,10 +297,10 @@ class WebRtcCallManager @Inject constructor( } override fun onCallIceCandidateReceived(mxCall: MxCall, iceCandidatesContent: CallCandidatesContent) { - Timber.tag(WebRtcCallManagerTag.computedValue).v("onCallIceCandidateReceived for call ${mxCall.callId}") + Timber.tag(loggerTag.value).v("onCallIceCandidateReceived for call ${mxCall.callId}") val call = callsByCallId[iceCandidatesContent.callId] ?: return Unit.also { - Timber.tag(WebRtcCallManagerTag.computedValue).w("onCallIceCandidateReceived for non active call? ${iceCandidatesContent.callId}") + Timber.tag(loggerTag.value).w("onCallIceCandidateReceived for non active call? ${iceCandidatesContent.callId}") } call.onCallIceCandidateReceived(iceCandidatesContent) } @@ -337,14 +337,14 @@ class WebRtcCallManager @Inject constructor( } override fun onCallInviteReceived(mxCall: MxCall, callInviteContent: CallInviteContent) { - Timber.tag(WebRtcCallManagerTag.computedValue).v("onCallInviteReceived callId ${mxCall.callId}") + Timber.tag(loggerTag.value).v("onCallInviteReceived callId ${mxCall.callId}") val nativeRoomId = callUserMapper?.nativeRoomForVirtualRoom(mxCall.roomId) ?: mxCall.roomId if (getCallsByRoomId(nativeRoomId).isNotEmpty()) { - Timber.tag(WebRtcCallManagerTag.computedValue).w("you already have a call in this room") + Timber.tag(loggerTag.value).w("you already have a call in this room") return } if ((getCurrentCall() != null && getCurrentCall()?.mxCall?.state !is CallState.Connected) || getCalls().size >= 2) { - Timber.tag(WebRtcCallManagerTag.computedValue).w("receiving incoming call but cannot handle it") + Timber.tag(loggerTag.value).w("receiving incoming call but cannot handle it") // Just ignore, maybe we could answer from other session? return } @@ -373,7 +373,7 @@ class WebRtcCallManager @Inject constructor( override fun onCallAnswerReceived(callAnswerContent: CallAnswerContent) { val call = callsByCallId[callAnswerContent.callId] ?: return Unit.also { - Timber.tag(WebRtcCallManagerTag.computedValue).w("onCallAnswerReceived for non active call? ${callAnswerContent.callId}") + Timber.tag(loggerTag.value).w("onCallAnswerReceived for non active call? ${callAnswerContent.callId}") } val mxCall = call.mxCall // Update service state @@ -387,7 +387,7 @@ class WebRtcCallManager @Inject constructor( override fun onCallHangupReceived(callHangupContent: CallHangupContent) { val call = callsByCallId[callHangupContent.callId] ?: return Unit.also { - Timber.tag(WebRtcCallManagerTag.computedValue).w("onCallHangupReceived for non active call? ${callHangupContent.callId}") + Timber.tag(loggerTag.value).w("onCallHangupReceived for non active call? ${callHangupContent.callId}") } call.endCall(false) } @@ -395,7 +395,7 @@ class WebRtcCallManager @Inject constructor( override fun onCallRejectReceived(callRejectContent: CallRejectContent) { val call = callsByCallId[callRejectContent.callId] ?: return Unit.also { - Timber.tag(WebRtcCallManagerTag.computedValue).w("onCallRejectReceived for non active call? ${callRejectContent.callId}") + Timber.tag(loggerTag.value).w("onCallRejectReceived for non active call? ${callRejectContent.callId}") } call.endCall(false) } @@ -403,7 +403,7 @@ class WebRtcCallManager @Inject constructor( override fun onCallSelectAnswerReceived(callSelectAnswerContent: CallSelectAnswerContent) { val call = callsByCallId[callSelectAnswerContent.callId] ?: return Unit.also { - Timber.tag(WebRtcCallManagerTag.computedValue).w("onCallSelectAnswerReceived for non active call? ${callSelectAnswerContent.callId}") + Timber.tag(loggerTag.value).w("onCallSelectAnswerReceived for non active call? ${callSelectAnswerContent.callId}") } val selectedPartyId = callSelectAnswerContent.selectedPartyId if (selectedPartyId != call.mxCall.ourPartyId) { @@ -416,13 +416,13 @@ class WebRtcCallManager @Inject constructor( override fun onCallNegotiateReceived(callNegotiateContent: CallNegotiateContent) { val call = callsByCallId[callNegotiateContent.callId] ?: return Unit.also { - Timber.tag(WebRtcCallManagerTag.computedValue).w("onCallNegotiateReceived for non active call? ${callNegotiateContent.callId}") + Timber.tag(loggerTag.value).w("onCallNegotiateReceived for non active call? ${callNegotiateContent.callId}") } call.onCallNegotiateReceived(callNegotiateContent) } override fun onCallManagedByOtherSession(callId: String) { - Timber.tag(WebRtcCallManagerTag.computedValue).v("onCallManagedByOtherSession: $callId") + Timber.tag(loggerTag.value).v("onCallManagedByOtherSession: $callId") onCallEnded(callId) } @@ -432,7 +432,7 @@ class WebRtcCallManager @Inject constructor( } val call = callsByCallId[callAssertedIdentityContent.callId] ?: return Unit.also { - Timber.tag(WebRtcCallManagerTag.computedValue).w("onCallAssertedIdentityReceived for non active call? ${callAssertedIdentityContent.callId}") + Timber.tag(loggerTag.value).w("onCallAssertedIdentityReceived for non active call? ${callAssertedIdentityContent.callId}") } call.onCallAssertedIdentityReceived(callAssertedIdentityContent) } From be488ae75ab7b44349eb2086c0a618a29fd30734 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 22 Jul 2021 15:24:05 +0200 Subject: [PATCH 27/38] Ensure OTK are uploaded when we upload the device keys The sync response can omit the field device_one_time_keys_count.signed_curve25519 and the SDK was waiting to know this value to upload the OTK. Now the SDK uploads the OTK when it uploads the device keys. --- .../android/sdk/internal/crypto/DefaultCryptoService.kt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt index d170ae3dd3..1ca08dbe65 100755 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt @@ -314,6 +314,12 @@ internal class DefaultCryptoService @Inject constructor( cryptoCoroutineScope.launchToCallback(coroutineDispatchers.crypto, NoOpMatrixCallback()) { // Open the store cryptoStore.open() + + if (!cryptoStore.getDeviceKeysUploaded()) { + // Schedule upload of OTK + oneTimeKeysUploader.updateOneTimeKeyCount(0) + } + // this can throw if no network tryOrNull { uploadDeviceKeys() From 7a7c292b3c8ad06cba782df43e259a2d10f725f1 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 22 Jul 2021 15:26:11 +0200 Subject: [PATCH 28/38] Rename store API --- .../android/sdk/internal/crypto/DefaultCryptoService.kt | 4 ++-- .../android/sdk/internal/crypto/store/IMXCryptoStore.kt | 2 +- .../android/sdk/internal/crypto/store/db/RealmCryptoStore.kt | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt index 1ca08dbe65..563c890950 100755 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/DefaultCryptoService.kt @@ -315,7 +315,7 @@ internal class DefaultCryptoService @Inject constructor( // Open the store cryptoStore.open() - if (!cryptoStore.getDeviceKeysUploaded()) { + if (!cryptoStore.areDeviceKeysUploaded()) { // Schedule upload of OTK oneTimeKeysUploader.updateOneTimeKeyCount(0) } @@ -911,7 +911,7 @@ internal class DefaultCryptoService @Inject constructor( * Upload my user's device keys. */ private suspend fun uploadDeviceKeys() { - if (cryptoStore.getDeviceKeysUploaded()) { + if (cryptoStore.areDeviceKeysUploaded()) { Timber.d("Keys already uploaded, nothing to do") return } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/IMXCryptoStore.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/IMXCryptoStore.kt index 181bd94cc7..3d12e74fcd 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/IMXCryptoStore.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/IMXCryptoStore.kt @@ -475,7 +475,7 @@ internal interface IMXCryptoStore { fun getGossipingEvents(): List fun setDeviceKeysUploaded(uploaded: Boolean) - fun getDeviceKeysUploaded(): Boolean + fun areDeviceKeysUploaded(): Boolean fun tidyUpDataBase() fun logDbUsageInfo() } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStore.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStore.kt index 9ae93d61eb..9266f8fe7d 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStore.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/store/db/RealmCryptoStore.kt @@ -937,7 +937,7 @@ internal class RealmCryptoStore @Inject constructor( } } - override fun getDeviceKeysUploaded(): Boolean { + override fun areDeviceKeysUploaded(): Boolean { return doWithRealm(realmConfiguration) { it.where().findFirst()?.deviceKeysSentToServer } ?: false From 952a0f7c07deccfe6e28b4de8b5e373dec6a9ab5 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 22 Jul 2021 15:33:05 +0200 Subject: [PATCH 29/38] change --- changelog.d/3724.bugfix | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/3724.bugfix diff --git a/changelog.d/3724.bugfix b/changelog.d/3724.bugfix new file mode 100644 index 0000000000..8397e687bb --- /dev/null +++ b/changelog.d/3724.bugfix @@ -0,0 +1 @@ +Ensure OTKs are uploaded when the session is created \ No newline at end of file From 05988107a7187851092bf106a12d370d22abb6e9 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 22 Jul 2021 15:59:37 +0200 Subject: [PATCH 30/38] Ask the number of OTK if unknown from the sync. --- .../sdk/internal/crypto/OneTimeKeysUploader.kt | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OneTimeKeysUploader.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OneTimeKeysUploader.kt index 6695234d62..e3f622cb64 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OneTimeKeysUploader.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OneTimeKeysUploader.kt @@ -16,6 +16,7 @@ package org.matrix.android.sdk.internal.crypto +import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.internal.crypto.model.MXKey import org.matrix.android.sdk.internal.crypto.model.rest.KeysUploadResponse import org.matrix.android.sdk.internal.crypto.tasks.UploadKeysTask @@ -77,6 +78,10 @@ internal class OneTimeKeysUploader @Inject constructor( // discard the oldest private keys first. This will eventually clean // out stale private keys that won't receive a message. val keyLimit = floor(maxOneTimeKeys / 2.0).toInt() + if (oneTimeKeyCount == null) { + // Ask the server how many otk he has + oneTimeKeyCount = fetchOtkNumber() + } val oneTimeKeyCountFromSync = oneTimeKeyCount if (oneTimeKeyCountFromSync != null) { // We need to keep a pool of one time public keys on the server so that @@ -103,6 +108,13 @@ internal class OneTimeKeysUploader @Inject constructor( } } + private suspend fun fetchOtkNumber(): Int? { + return tryOrNull { + val result = uploadKeysTask.execute(UploadKeysTask.Params(null, null)) + result.oneTimeKeyCountsForAlgorithm(MXKey.KEY_SIGNED_CURVE_25519_TYPE) + } + } + /** * Upload some the OTKs. * From 1d5ed46a49dc9dc0a70532dc8e87148cd8862889 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 22 Jul 2021 16:01:01 +0200 Subject: [PATCH 31/38] Small cleanup --- .../android/sdk/internal/crypto/OneTimeKeysUploader.kt | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OneTimeKeysUploader.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OneTimeKeysUploader.kt index e3f622cb64..d11943630e 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OneTimeKeysUploader.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OneTimeKeysUploader.kt @@ -95,17 +95,15 @@ internal class OneTimeKeysUploader @Inject constructor( // private keys clogging up our local storage. // So we need some kind of engineering compromise to balance all of // these factors. - try { + tryOrNull { val uploadedKeys = uploadOTK(oneTimeKeyCountFromSync, keyLimit) Timber.v("## uploadKeys() : success, $uploadedKeys key(s) sent") - } finally { - oneTimeKeyCheckInProgress = false } } else { Timber.w("maybeUploadOneTimeKeys: waiting to know the number of OTK from the sync") - oneTimeKeyCheckInProgress = false lastOneTimeKeyCheck = 0 } + oneTimeKeyCheckInProgress = false } private suspend fun fetchOtkNumber(): Int? { From ed0143c2402f6e46d90d7c4a1ecf62ef5b85cd22 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 22 Jul 2021 16:20:16 +0200 Subject: [PATCH 32/38] Log errors --- .../android/sdk/internal/crypto/OneTimeKeysUploader.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OneTimeKeysUploader.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OneTimeKeysUploader.kt index d11943630e..c4b62fe9fe 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OneTimeKeysUploader.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/crypto/OneTimeKeysUploader.kt @@ -80,7 +80,7 @@ internal class OneTimeKeysUploader @Inject constructor( val keyLimit = floor(maxOneTimeKeys / 2.0).toInt() if (oneTimeKeyCount == null) { // Ask the server how many otk he has - oneTimeKeyCount = fetchOtkNumber() + oneTimeKeyCount = fetchOtkCount() } val oneTimeKeyCountFromSync = oneTimeKeyCount if (oneTimeKeyCountFromSync != null) { @@ -95,7 +95,7 @@ internal class OneTimeKeysUploader @Inject constructor( // private keys clogging up our local storage. // So we need some kind of engineering compromise to balance all of // these factors. - tryOrNull { + tryOrNull("Unable to upload OTK") { val uploadedKeys = uploadOTK(oneTimeKeyCountFromSync, keyLimit) Timber.v("## uploadKeys() : success, $uploadedKeys key(s) sent") } @@ -106,8 +106,8 @@ internal class OneTimeKeysUploader @Inject constructor( oneTimeKeyCheckInProgress = false } - private suspend fun fetchOtkNumber(): Int? { - return tryOrNull { + private suspend fun fetchOtkCount(): Int? { + return tryOrNull("Unable to get OTK count") { val result = uploadKeysTask.execute(UploadKeysTask.Params(null, null)) result.oneTimeKeyCountsForAlgorithm(MXKey.KEY_SIGNED_CURVE_25519_TYPE) } From e3464f58fa467b00a9a2e4a57e3989b644e84686 Mon Sep 17 00:00:00 2001 From: ganfra Date: Thu, 22 Jul 2021 15:39:13 +0200 Subject: [PATCH 33/38] Call notif: make end call notif better --- .../java/im/vector/app/core/services/CallService.kt | 10 ++++------ .../app/features/notifications/NotificationUtils.kt | 3 ++- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/vector/src/main/java/im/vector/app/core/services/CallService.kt b/vector/src/main/java/im/vector/app/core/services/CallService.kt index 916dc66718..d8cf8cf6b8 100644 --- a/vector/src/main/java/im/vector/app/core/services/CallService.kt +++ b/vector/src/main/java/im/vector/app/core/services/CallService.kt @@ -210,13 +210,11 @@ class CallService : VectorService() { myStopSelf() } val wasConnected = connectedCallIds.remove(callId) + val notification = notificationUtils.buildCallEndedNotification(terminatedCall.isVideoCall) + notificationManager.notify(callId.hashCode(), notification) if (!wasConnected && !terminatedCall.isOutgoing && !rejected && endCallReason != EndCallReason.ANSWERED_ELSEWHERE) { - val notification = notificationUtils.buildCallMissedNotification(terminatedCall) - notificationManager.cancel(callId.hashCode()) - notificationManager.notify(MISSED_CALL_TAG, terminatedCall.nativeRoomId.hashCode(), notification) - } else { - val notification = notificationUtils.buildCallEndedNotification(terminatedCall.isVideoCall) - notificationManager.notify(callId.hashCode(), notification) + val missedCallNotification = notificationUtils.buildCallMissedNotification(terminatedCall) + notificationManager.notify(MISSED_CALL_TAG, terminatedCall.nativeRoomId.hashCode(), missedCallNotification) } } diff --git a/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt b/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt index 24a64f3cdb..cf13150e59 100755 --- a/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt +++ b/vector/src/main/java/im/vector/app/features/notifications/NotificationUtils.kt @@ -468,7 +468,8 @@ class NotificationUtils @Inject constructor(private val context: Context, setSmallIcon(R.drawable.ic_call_answer) } } - .setTimeoutAfter(2000) + // This is a trick to make the previous notification with same id disappear as cancel notification is not working with Foreground Service. + .setTimeoutAfter(1) .setColor(ThemeUtils.getColor(context, android.R.attr.colorPrimary)) .setCategory(NotificationCompat.CATEGORY_CALL) .build() From 45a51d138e88070360faa5d76f7c6a2b526e8563 Mon Sep 17 00:00:00 2001 From: ganfra Date: Fri, 23 Jul 2021 09:50:09 +0200 Subject: [PATCH 34/38] Voip log: clean after Benoit review --- .../matrix/android/sdk/api/logger/LoggerTag.kt | 15 ++++++--------- .../internal/session/call/CallSignalingHandler.kt | 3 ++- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/logger/LoggerTag.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/logger/LoggerTag.kt index 9978ae32aa..9e7ee297f1 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/logger/LoggerTag.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/logger/LoggerTag.kt @@ -22,16 +22,13 @@ package org.matrix.android.sdk.api.logger * val loggerTag = LoggerTag("MyTag", LoggerTag.VOIP) * Timber.tag(loggerTag.value).v("My log message") */ -open class LoggerTag(private val _value: String, private val parentTag: LoggerTag? = null) { +open class LoggerTag(_value: String, parentTag: LoggerTag? = null) { object VOIP : LoggerTag("VOIP", null) - val value: String - get() { - return if (parentTag == null) { - _value - } else { - "${parentTag.value}/$_value" - } - } + val value: String = if (parentTag == null) { + _value + } else { + "${parentTag.value}/$_value" + } } diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallSignalingHandler.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallSignalingHandler.kt index a71fdeae03..59058bf976 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallSignalingHandler.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/internal/session/call/CallSignalingHandler.kt @@ -38,6 +38,7 @@ import timber.log.Timber import javax.inject.Inject private val loggerTag = LoggerTag("CallSignalingHandler", LoggerTag.VOIP) +private const val MAX_AGE_TO_RING = 40_000 @SessionScope internal class CallSignalingHandler @Inject constructor(private val activeCallHandler: ActiveCallHandler, @@ -185,7 +186,7 @@ internal class CallSignalingHandler @Inject constructor(private val activeCallHa } val now = System.currentTimeMillis() val age = now - (event.ageLocalTs ?: now) - if (age > 40_000 && event.getClearType() == EventType.CALL_INVITE) { + if (age > MAX_AGE_TO_RING) { Timber.tag(loggerTag.value).w("Call invite is too old to ring.") return } From adabb3168844fcd5c2db04e6971719b6625f741f Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 23 Jul 2021 11:25:56 +0200 Subject: [PATCH 35/38] Changelog --- changelog.d/3723.misc | 1 + .../main/java/org/matrix/android/sdk/api/logger/LoggerTag.kt | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 changelog.d/3723.misc diff --git a/changelog.d/3723.misc b/changelog.d/3723.misc new file mode 100644 index 0000000000..d855c2f643 --- /dev/null +++ b/changelog.d/3723.misc @@ -0,0 +1 @@ +Add tags in the log, especially for VoIP, but can be used for other features in the future \ No newline at end of file diff --git a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/logger/LoggerTag.kt b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/logger/LoggerTag.kt index 9e7ee297f1..51f9b50699 100644 --- a/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/logger/LoggerTag.kt +++ b/matrix-sdk-android/src/main/java/org/matrix/android/sdk/api/logger/LoggerTag.kt @@ -24,7 +24,7 @@ package org.matrix.android.sdk.api.logger */ open class LoggerTag(_value: String, parentTag: LoggerTag? = null) { - object VOIP : LoggerTag("VOIP", null) + object VOIP : LoggerTag("VOIP") val value: String = if (parentTag == null) { _value From 9ad1ad2156efdf0e43a725873f750fb66c357c4a Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 23 Jul 2021 11:49:16 +0200 Subject: [PATCH 36/38] Changelog --- CHANGES.md | 25 +++++++++++++++++++++++++ changelog.d/3463.feature | 1 - changelog.d/3589.bugfix | 1 - changelog.d/3656.bugfix | 1 - changelog.d/3710.feature | 1 - changelog.d/3713.removal | 1 - changelog.d/3720.bugfix | 1 - changelog.d/3721.misc | 1 - changelog.d/3723.misc | 1 - changelog.d/3724.bugfix | 1 - 10 files changed, 25 insertions(+), 9 deletions(-) delete mode 100644 changelog.d/3463.feature delete mode 100644 changelog.d/3589.bugfix delete mode 100644 changelog.d/3656.bugfix delete mode 100644 changelog.d/3710.feature delete mode 100644 changelog.d/3713.removal delete mode 100644 changelog.d/3720.bugfix delete mode 100644 changelog.d/3721.misc delete mode 100644 changelog.d/3723.misc delete mode 100644 changelog.d/3724.bugfix diff --git a/CHANGES.md b/CHANGES.md index 79e1e07520..a5ef37fb55 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,28 @@ +Changes in Element 1.1.14 (2021-07-23) +====================================== + +Features ✨ +---------- + - Add low priority section in DM tab ([#3463](https://github.com/vector-im/element-android/issues/3463)) + - Show missed call notification. ([#3710](https://github.com/vector-im/element-android/issues/3710)) + +Bugfixes 🐛 +---------- + - Don't use the transaction ID of the verification for the request ([#3589](https://github.com/vector-im/element-android/issues/3589)) + - Avoid incomplete downloads in cache ([#3656](https://github.com/vector-im/element-android/issues/3656)) + - Fix a crash which can happen when user signs out ([#3720](https://github.com/vector-im/element-android/issues/3720)) + - Ensure OTKs are uploaded when the session is created ([#3724](https://github.com/vector-im/element-android/issues/3724)) + +SDK API changes ⚠️ +------------------ + - Add initialState support to CreateRoomParams (#3713) ([#3713](https://github.com/vector-im/element-android/issues/3713)) + +Other changes +------------- + - Apply grammatical fixes to the Server ACL timeline messages. ([#3721](https://github.com/vector-im/element-android/issues/3721)) + - Add tags in the log, especially for VoIP, but can be used for other features in the future ([#3723](https://github.com/vector-im/element-android/issues/3723)) + + Changes in Element v1.1.13 (2021-07-19) ======================================= diff --git a/changelog.d/3463.feature b/changelog.d/3463.feature deleted file mode 100644 index a0a5f85393..0000000000 --- a/changelog.d/3463.feature +++ /dev/null @@ -1 +0,0 @@ -Add low priority section in DM tab \ No newline at end of file diff --git a/changelog.d/3589.bugfix b/changelog.d/3589.bugfix deleted file mode 100644 index 2b9a04f6a2..0000000000 --- a/changelog.d/3589.bugfix +++ /dev/null @@ -1 +0,0 @@ -Don't use the transaction ID of the verification for the request diff --git a/changelog.d/3656.bugfix b/changelog.d/3656.bugfix deleted file mode 100644 index 30d451558f..0000000000 --- a/changelog.d/3656.bugfix +++ /dev/null @@ -1 +0,0 @@ -Avoid incomplete downloads in cache diff --git a/changelog.d/3710.feature b/changelog.d/3710.feature deleted file mode 100644 index 74134d7ee5..0000000000 --- a/changelog.d/3710.feature +++ /dev/null @@ -1 +0,0 @@ -Show missed call notification. \ No newline at end of file diff --git a/changelog.d/3713.removal b/changelog.d/3713.removal deleted file mode 100644 index e797a408e7..0000000000 --- a/changelog.d/3713.removal +++ /dev/null @@ -1 +0,0 @@ -Add initialState support to CreateRoomParams (#3713) \ No newline at end of file diff --git a/changelog.d/3720.bugfix b/changelog.d/3720.bugfix deleted file mode 100644 index 18363b90e3..0000000000 --- a/changelog.d/3720.bugfix +++ /dev/null @@ -1 +0,0 @@ -Fix a crash which can happen when user signs out \ No newline at end of file diff --git a/changelog.d/3721.misc b/changelog.d/3721.misc deleted file mode 100644 index 8c3424c6ed..0000000000 --- a/changelog.d/3721.misc +++ /dev/null @@ -1 +0,0 @@ -Apply grammatical fixes to the Server ACL timeline messages. diff --git a/changelog.d/3723.misc b/changelog.d/3723.misc deleted file mode 100644 index d855c2f643..0000000000 --- a/changelog.d/3723.misc +++ /dev/null @@ -1 +0,0 @@ -Add tags in the log, especially for VoIP, but can be used for other features in the future \ No newline at end of file diff --git a/changelog.d/3724.bugfix b/changelog.d/3724.bugfix deleted file mode 100644 index 8397e687bb..0000000000 --- a/changelog.d/3724.bugfix +++ /dev/null @@ -1 +0,0 @@ -Ensure OTKs are uploaded when the session is created \ No newline at end of file From ba7c5acd92502abea17bb91c5f7e9e65ce59342c Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 23 Jul 2021 11:50:46 +0200 Subject: [PATCH 37/38] fastlane change --- fastlane/metadata/android/en-US/changelogs/40101140.txt | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 fastlane/metadata/android/en-US/changelogs/40101140.txt diff --git a/fastlane/metadata/android/en-US/changelogs/40101140.txt b/fastlane/metadata/android/en-US/changelogs/40101140.txt new file mode 100644 index 0000000000..ee04069968 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/40101140.txt @@ -0,0 +1,2 @@ +Main changes in this version: fix an issue about encrypted messages. +Full changelog: https://github.com/vector-im/element-android/releases/tag/v1.1.14 \ No newline at end of file From bdbfbe61750fdd6fac624ed72cfeead87fd245b5 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Fri, 23 Jul 2021 11:53:21 +0200 Subject: [PATCH 38/38] Version++ --- vector/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vector/build.gradle b/vector/build.gradle index 05dbec0e6f..b57d7eef33 100644 --- a/vector/build.gradle +++ b/vector/build.gradle @@ -14,7 +14,7 @@ kapt { // Note: 2 digits max for each value ext.versionMajor = 1 ext.versionMinor = 1 -ext.versionPatch = 14 +ext.versionPatch = 15 static def getGitTimestamp() { def cmd = 'git show -s --format=%ct'